diff --git a/.travis.yml b/.travis.yml index e32e9dbf..b1bcc67d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ install: - sudo apt-get update -qq - sudo apt-get install -qq $LLVM_PACKAGE libconfig++8-dev env: - - DVER=1 LLVM_PACKAGE=llvm-3.1 LLVM_VERSION=3.1 - DVER=2 LLVM_PACKAGE=llvm-3.0-dev LLVM_VERSION=3.0 TESTSUITE_FILTER=debug - DVER=2 LLVM_PACKAGE=llvm-3.0-dev LLVM_VERSION=3.0 TESTSUITE_FILTER=release - DVER=2 LLVM_PACKAGE=llvm-3.1 LLVM_VERSION=3.1 TESTSUITE_FILTER=debug diff --git a/CMakeLists.txt b/CMakeLists.txt index afb801e4..03b9cf64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,11 +50,8 @@ option(USE_METADATA "use metadata and related custom optimization passes" ON) mark_as_advanced(USE_BOEHM_GC GENERATE_OFFTI USE_METADATA) if(D_VERSION EQUAL 1) - set(DMDFE_PATH dmd) - set(LDC_EXE ldc) - set(LDMD_EXE ldmd) - set(RUNTIME runtime) - add_definitions(-DDMDV1) + message(FATAL_ERROR "D version 1 is no longer supported. +Please consider using D version 2 or checkout the 'd1' git branch for the last version supporting D version 1.") elseif(D_VERSION EQUAL 2) set(DMDFE_PATH dmd2) set(LDC_EXE ldc2) diff --git a/dmd/access.c b/dmd/access.c deleted file mode 100644 index fae07af9..00000000 --- a/dmd/access.c +++ /dev/null @@ -1,418 +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 && getModule() == cd->getModule()) - { -#if LOG - printf("\tin same module\n"); -#endif - return 1; - } - -#if LOG - printf("\tnot friend\n"); -#endif - return 0; -} - -/**************************************** - * Determine if scope sc has package level access to s. - */ - -int hasPackageAccess(Scope *sc, Dsymbol *s) -{ -#if LOG - printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc); -#endif - - for (; s; s = s->parent) - { - if (s->isPackage() && !s->isModule()) - break; - } -#if LOG - if (s) - printf("\tthis is in package '%s'\n", s->toChars()); -#endif - - if (s && s == sc->module->parent) - { -#if LOG - printf("\ts is in same package as sc\n"); -#endif - return 1; - } - - -#if LOG - printf("\tno package access\n"); -#endif - return 0; -} - -/********************************** - * Determine if smember has access to private members of this declaration. - */ - -int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember) -{ - if (smember) - { AggregateDeclaration *cd = NULL; - Dsymbol *smemberparent = smember->toParent(); - if (smemberparent) - cd = smemberparent->isAggregateDeclaration(); - -#if LOG - printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n", - toChars(), smember->toChars()); -#endif - - if (this == cd) // smember is a member of this class - { -#if LOG - printf("\tyes 1\n"); -#endif - return 1; // so we get private access - } - - // If both are members of the same module, grant access - while (1) - { Dsymbol *sp = smember->toParent(); - if (sp->isFuncDeclaration() && smember->isFuncDeclaration()) - smember = sp; - else - break; - } - if (!cd && toParent() == smember->toParent()) - { -#if LOG - printf("\tyes 2\n"); -#endif - return 1; - } - if (!cd && getModule() == smember->getModule()) - { -#if LOG - printf("\tyes 3\n"); -#endif - return 1; - } - } -#if LOG - printf("\tno\n"); -#endif - return 0; -} - -/**************************************** - * Check access to d for expression e.d - */ - -void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d) -{ -#if LOG - if (e) - { printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars()); - printf("\te->type = %s\n", e->type->toChars()); - } - else - { - //printf("accessCheck(%s)\n", d->toChars()); - } -#endif - if (!e) - { - if (d->prot() == PROTprivate && d->getModule() != sc->module || - d->prot() == PROTpackage && !hasPackageAccess(sc, d)) - - error(loc, "%s %s.%s is not accessible from %s", - d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars()); - } - else if (e->type->ty == Tclass) - { // Do access check - ClassDeclaration *cd; - - cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym); -#if 1 - if (e->op == TOKsuper) - { ClassDeclaration *cd2; - - cd2 = sc->func->toParent()->isClassDeclaration(); - if (cd2) - cd = cd2; - } -#endif - cd->accessCheck(loc, sc, d); - } - else if (e->type->ty == Tstruct) - { // Do access check - StructDeclaration *cd; - - cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym); - cd->accessCheck(loc, sc, d); - } -} diff --git a/dmd/aggregate.h b/dmd/aggregate.h deleted file mode 100644 index 3ba0306a..00000000 --- a/dmd/aggregate.h +++ /dev/null @@ -1,373 +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. - -#ifndef DMD_AGGREGATE_H -#define DMD_AGGREGATE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" - -#include "dsymbol.h" - -#if IN_LLVM -#include -#include -#include -#endif - -struct Identifier; -struct Type; -struct TypeFunction; -struct Expression; -struct FuncDeclaration; -struct CtorDeclaration; -struct DtorDeclaration; -struct InvariantDeclaration; -struct NewDeclaration; -struct DeleteDeclaration; -struct InterfaceDeclaration; -struct ClassInfoDeclaration; -struct VarDeclaration; -struct dt_t; - -#if IN_LLVM -namespace llvm -{ - class Type; - class Value; - class Constant; - class ConstantStruct; - class GlobalVariable; -} -#endif - -enum Sizeok -{ - SIZEOKnone, // size of aggregate is not computed yet - SIZEOKdone, // size of aggregate is set correctly - SIZEOKfwd, // error in computing size of aggregate -}; - -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 - structalign_t structalign; // struct member alignment in effect - int hasUnions; // set if aggregate has overlapping fields - VarDeclarations fields; // VarDeclaration fields - enum Sizeok sizeok; // set when structsize contains valid data - int 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 - Expressions *attributes; // GCC decl/type attributes - FuncDeclarations 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(structalign_t salign, unsigned size, unsigned *poffset); - static unsigned placeField(unsigned *nextoffset, - unsigned memsize, unsigned memalignsize, structalign_t memalign, - unsigned *paggsize, unsigned *paggalignsize, bool isunion); - Type *getType(); - 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 - - // For 64 bit Efl function call/return ABI - Type *arg1type; - Type *arg2type; - - 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(Scope *sc); - bool isPOD(); -#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 -#define CLASSINFO_SIZE_64 (0x98) // value of ClassInfo.size -#endif - -struct ClassDeclaration : AggregateDeclaration -{ - static ClassDeclaration *object; - static ClassDeclaration *classinfo; - 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[] - - ClassInfoDeclaration *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/dmd/apply.c b/dmd/apply.c deleted file mode 100644 index f5a5ede8..00000000 --- a/dmd/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/dmd/argtypes.c b/dmd/argtypes.c deleted file mode 100644 index 1021b390..00000000 --- a/dmd/argtypes.c +++ /dev/null @@ -1,441 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2010-2012 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" - -#define tfloat2 tfloat64 -//#define tfloat2 tcomplex32 - -/**************************************************** - * 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 *TypeError::toArgTypes() -{ - return new TypeTuple(Type::terror); -} - -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::tfloat2; - 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; -} - -#if DMDV2 -TypeTuple *TypeVector::toArgTypes() -{ - return new TypeTuple(this); -} -#endif - -TypeTuple *TypeSArray::toArgTypes() -{ -#if DMDV2 - if (dim) - { - /* Should really be done as if it were a struct with dim members - * of the array's elements. - * I.e. int[2] should be done like struct S { int a; int b; } - */ - dinteger_t sz = dim->toInteger(); - if (sz == 1) - // T[1] should be passed like T - return next->toArgTypes(); - } - return new TypeTuple(); // pass on the stack for efficiency -#else - return new TypeTuple(); // pass on the stack for efficiency -#endif -} - -TypeTuple *TypeDArray::toArgTypes() -{ - /* Should be done as if it were: - * struct S { size_t length; void* ptr; } - */ - return new TypeTuple(Type::tsize_t, Type::tvoidptr); -} - -TypeTuple *TypeAArray::toArgTypes() -{ - return new TypeTuple(Type::tvoidptr); -} - -TypeTuple *TypePointer::toArgTypes() -{ - return new TypeTuple(Type::tvoidptr); -} - -TypeTuple *TypeDelegate::toArgTypes() -{ - /* Should be done as if it were: - * struct S { void* ptr; void* funcptr; } - */ - return new TypeTuple(Type::tvoidptr, Type::tvoidptr); -} - -/************************************* - * Convert a floating point type into the equivalent integral type. - */ - -Type *mergeFloatToInt(Type *t) -{ - switch (t->ty) - { - case Tfloat32: - case Timaginary32: - t = Type::tint32; - break; - case Tfloat64: - case Timaginary64: - case Tcomplex32: - t = Type::tint64; - break; - default: -#ifdef DEBUG - printf("mergeFloatToInt() %s\n", t->toChars()); -#endif - assert(0); - } - return t; -} - -/************************************* - * This merges two types into an 8byte type. - */ - -Type *argtypemerge(Type *t1, Type *t2, unsigned offset2) -{ - //printf("argtypemerge(%s, %s, %d)\n", t1 ? t1->toChars() : "", t2 ? t2->toChars() : "", offset2); - if (!t1) - { assert(!t2 || offset2 == 0); - return t2; - } - if (!t2) - return t1; - - unsigned sz1 = t1->size(0); - unsigned sz2 = t2->size(0); - - if (t1->ty != t2->ty && - (t1->ty == Tfloat80 || t2->ty == Tfloat80)) - return NULL; - - // [float,float] => [cfloat] - if (t1->ty == Tfloat32 && t2->ty == Tfloat32 && offset2 == 4) - return Type::tfloat2; - - // Merging floating and non-floating types produces the non-floating type - if (t1->isfloating()) - { - if (!t2->isfloating()) - t1 = mergeFloatToInt(t1); - } - else if (t2->isfloating()) - t2 = mergeFloatToInt(t2); - - Type *t; - - // Pick type with larger size - if (sz1 < sz2) - t = t2; - else - t = t1; - - // If t2 does not lie within t1, need to increase the size of t to enclose both - if (offset2 && sz1 < offset2 + sz2) - { - switch (offset2 + sz2) - { - case 2: - t = Type::tint16; - break; - case 3: - case 4: - t = Type::tint32; - break; - case 5: - case 6: - case 7: - case 8: - t = Type::tint64; - break; - default: - assert(0); - } - } - return t; -} - -TypeTuple *TypeStruct::toArgTypes() -{ - //printf("TypeStruct::toArgTypes() %s\n", toChars()); - if (!sym->isPOD()) - { - Lmemory: - //printf("\ttoArgTypes() %s => [ ]\n", toChars()); - return new TypeTuple(); // pass on the stack - } - Type *t1 = NULL; - Type *t2 = NULL; - d_uns64 sz = size(0); - assert(sz < 0xFFFFFFFF); - switch ((unsigned)sz) - { - case 1: - t1 = Type::tint8; - break; - case 2: - t1 = Type::tint16; - break; - case 4: - t1 = Type::tint32; - break; - case 8: - t1 = Type::tint64; - break; - case 16: - t1 = NULL; // could be a TypeVector - break; - default: - goto Lmemory; - } - if (global.params.is64bit && sym->fields.dim) - { -#if 1 - unsigned sz1 = 0; - unsigned sz2 = 0; - t1 = NULL; - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *f = sym->fields[i]; - //printf("f->type = %s\n", f->type->toChars()); - - TypeTuple *tup = f->type->toArgTypes(); - if (!tup) - goto Lmemory; - size_t dim = tup->arguments->dim; - Type *ft1 = NULL; - Type *ft2 = NULL; - switch (dim) - { - case 2: - ft1 = (*tup->arguments)[0]->type; - ft2 = (*tup->arguments)[1]->type; - break; - case 1: - if (f->offset < 8) - ft1 = (*tup->arguments)[0]->type; - else - ft2 = (*tup->arguments)[0]->type; - break; - default: - goto Lmemory; - } - - if (f->offset & 7) - { - // Misaligned fields goto Lmemory - unsigned alignsz = f->type->alignsize(); - if (f->offset & (alignsz - 1)) - goto Lmemory; - - // Fields that overlap the 8byte boundary goto Lmemory - unsigned fieldsz = f->type->size(0); - if (f->offset < 8 && (f->offset + fieldsz) > 8) - goto Lmemory; - } - - // First field in 8byte must be at start of 8byte - assert(t1 || f->offset == 0); - - if (ft1) - { - t1 = argtypemerge(t1, ft1, f->offset); - if (!t1) - goto Lmemory; - } - - if (ft2) - { - unsigned off2 = f->offset; - if (ft1) - off2 = 8; - assert(t2 || off2 == 8); - t2 = argtypemerge(t2, ft2, off2 - 8); - if (!t2) - goto Lmemory; - } - } - - if (t2) - { - if (t1->isfloating() && t2->isfloating()) - { - if (t1->ty == Tfloat64 && t2->ty == Tfloat64) - ; - else - goto Lmemory; - } - else if (t1->isfloating()) - goto Lmemory; - else if (t2->isfloating()) - goto Lmemory; - else - ; - } -#else - if (sym->fields.dim == 1) - { VarDeclaration *f = sym->fields[0]; - //printf("f->type = %s\n", f->type->toChars()); - TypeTuple *tup = f->type->toArgTypes(); - if (tup) - { - size_t dim = tup->arguments->dim; - if (dim == 1) - t1 = (*tup->arguments)[0]->type; - } - } -#endif - } - - //printf("\ttoArgTypes() %s => [%s,%s]\n", toChars(), t1 ? t1->toChars() : "", t2 ? t2->toChars() : ""); - - TypeTuple *t; - if (t1) - { - //if (t1) printf("test1: %s => %s\n", toChars(), t1->toChars()); - if (t2) - t = new TypeTuple(t1, t2); - else - t = new TypeTuple(t1); - } - else - goto Lmemory; - return t; -} - -TypeTuple *TypeEnum::toArgTypes() -{ - return toBasetype()->toArgTypes(); -} - -TypeTuple *TypeTypedef::toArgTypes() -{ - return sym->basetype->toArgTypes(); -} - -TypeTuple *TypeClass::toArgTypes() -{ - return new TypeTuple(Type::tvoidptr); -} - diff --git a/dmd/arrayop.c b/dmd/arrayop.c deleted file mode 100644 index c6e17869..00000000 --- a/dmd/arrayop.c +++ /dev/null @@ -1,660 +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 "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; -#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) -{ - //printf("BinExp::arrayOp() %s\n", toChars()); - - 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 - -#if IN_LLVM - const size_t namelen = buf.offset; -#endif - - buf.writeByte(0); - char *name = buf.toChars(); - Identifier *ident = Lexer::idPool(name); - - /* Look up name in hash table - */ -#if IN_DMD - FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&arrayfuncs, ident); - FuncDeclaration *fd = (FuncDeclaration *)*pfd; -#elif IN_LLVM - StringValue *sv = sc->module->arrayfuncs.update(name, namelen); - FuncDeclaration *fd = (FuncDeclaration *)sv->ptrvalue; -#endif - if (!fd) - { -#if IN_DMD - static const char *libArrayopFuncs[] = - { - "_arrayExpSliceAddass_a", - "_arrayExpSliceAddass_d", // T[]+=T - "_arrayExpSliceAddass_f", // T[]+=T - "_arrayExpSliceAddass_g", - "_arrayExpSliceAddass_h", - "_arrayExpSliceAddass_i", - "_arrayExpSliceAddass_k", - "_arrayExpSliceAddass_s", - "_arrayExpSliceAddass_t", - "_arrayExpSliceAddass_u", - "_arrayExpSliceAddass_w", - - "_arrayExpSliceDivass_d", // T[]/=T - "_arrayExpSliceDivass_f", // T[]/=T - - "_arrayExpSliceMinSliceAssign_a", - "_arrayExpSliceMinSliceAssign_d", // T[]=T-T[] - "_arrayExpSliceMinSliceAssign_f", // T[]=T-T[] - "_arrayExpSliceMinSliceAssign_g", - "_arrayExpSliceMinSliceAssign_h", - "_arrayExpSliceMinSliceAssign_i", - "_arrayExpSliceMinSliceAssign_k", - "_arrayExpSliceMinSliceAssign_s", - "_arrayExpSliceMinSliceAssign_t", - "_arrayExpSliceMinSliceAssign_u", - "_arrayExpSliceMinSliceAssign_w", - - "_arrayExpSliceMinass_a", - "_arrayExpSliceMinass_d", // T[]-=T - "_arrayExpSliceMinass_f", // T[]-=T - "_arrayExpSliceMinass_g", - "_arrayExpSliceMinass_h", - "_arrayExpSliceMinass_i", - "_arrayExpSliceMinass_k", - "_arrayExpSliceMinass_s", - "_arrayExpSliceMinass_t", - "_arrayExpSliceMinass_u", - "_arrayExpSliceMinass_w", - - "_arrayExpSliceMulass_d", // T[]*=T - "_arrayExpSliceMulass_f", // T[]*=T - "_arrayExpSliceMulass_i", - "_arrayExpSliceMulass_k", - "_arrayExpSliceMulass_s", - "_arrayExpSliceMulass_t", - "_arrayExpSliceMulass_u", - "_arrayExpSliceMulass_w", - - "_arraySliceExpAddSliceAssign_a", - "_arraySliceExpAddSliceAssign_d", // T[]=T[]+T - "_arraySliceExpAddSliceAssign_f", // T[]=T[]+T - "_arraySliceExpAddSliceAssign_g", - "_arraySliceExpAddSliceAssign_h", - "_arraySliceExpAddSliceAssign_i", - "_arraySliceExpAddSliceAssign_k", - "_arraySliceExpAddSliceAssign_s", - "_arraySliceExpAddSliceAssign_t", - "_arraySliceExpAddSliceAssign_u", - "_arraySliceExpAddSliceAssign_w", - - "_arraySliceExpDivSliceAssign_d", // T[]=T[]/T - "_arraySliceExpDivSliceAssign_f", // T[]=T[]/T - - "_arraySliceExpMinSliceAssign_a", - "_arraySliceExpMinSliceAssign_d", // T[]=T[]-T - "_arraySliceExpMinSliceAssign_f", // T[]=T[]-T - "_arraySliceExpMinSliceAssign_g", - "_arraySliceExpMinSliceAssign_h", - "_arraySliceExpMinSliceAssign_i", - "_arraySliceExpMinSliceAssign_k", - "_arraySliceExpMinSliceAssign_s", - "_arraySliceExpMinSliceAssign_t", - "_arraySliceExpMinSliceAssign_u", - "_arraySliceExpMinSliceAssign_w", - - "_arraySliceExpMulSliceAddass_d", // T[] += T[]*T - "_arraySliceExpMulSliceAddass_f", - "_arraySliceExpMulSliceAddass_r", - - "_arraySliceExpMulSliceAssign_d", // T[]=T[]*T - "_arraySliceExpMulSliceAssign_f", // T[]=T[]*T - "_arraySliceExpMulSliceAssign_i", - "_arraySliceExpMulSliceAssign_k", - "_arraySliceExpMulSliceAssign_s", - "_arraySliceExpMulSliceAssign_t", - "_arraySliceExpMulSliceAssign_u", - "_arraySliceExpMulSliceAssign_w", - - "_arraySliceExpMulSliceMinass_d", // T[] -= T[]*T - "_arraySliceExpMulSliceMinass_f", - "_arraySliceExpMulSliceMinass_r", - - "_arraySliceSliceAddSliceAssign_a", - "_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[] - "_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[] - "_arraySliceSliceAddSliceAssign_g", - "_arraySliceSliceAddSliceAssign_h", - "_arraySliceSliceAddSliceAssign_i", - "_arraySliceSliceAddSliceAssign_k", - "_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[] - "_arraySliceSliceAddSliceAssign_s", - "_arraySliceSliceAddSliceAssign_t", - "_arraySliceSliceAddSliceAssign_u", - "_arraySliceSliceAddSliceAssign_w", - - "_arraySliceSliceAddass_a", - "_arraySliceSliceAddass_d", // T[]+=T[] - "_arraySliceSliceAddass_f", // T[]+=T[] - "_arraySliceSliceAddass_g", - "_arraySliceSliceAddass_h", - "_arraySliceSliceAddass_i", - "_arraySliceSliceAddass_k", - "_arraySliceSliceAddass_s", - "_arraySliceSliceAddass_t", - "_arraySliceSliceAddass_u", - "_arraySliceSliceAddass_w", - - "_arraySliceSliceMinSliceAssign_a", - "_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[] - "_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[] - "_arraySliceSliceMinSliceAssign_g", - "_arraySliceSliceMinSliceAssign_h", - "_arraySliceSliceMinSliceAssign_i", - "_arraySliceSliceMinSliceAssign_k", - "_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[] - "_arraySliceSliceMinSliceAssign_s", - "_arraySliceSliceMinSliceAssign_t", - "_arraySliceSliceMinSliceAssign_u", - "_arraySliceSliceMinSliceAssign_w", - - "_arraySliceSliceMinass_a", - "_arraySliceSliceMinass_d", // T[]-=T[] - "_arraySliceSliceMinass_f", // T[]-=T[] - "_arraySliceSliceMinass_g", - "_arraySliceSliceMinass_h", - "_arraySliceSliceMinass_i", - "_arraySliceSliceMinass_k", - "_arraySliceSliceMinass_s", - "_arraySliceSliceMinass_t", - "_arraySliceSliceMinass_u", - "_arraySliceSliceMinass_w", - - "_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[] - "_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[] - "_arraySliceSliceMulSliceAssign_i", - "_arraySliceSliceMulSliceAssign_k", - "_arraySliceSliceMulSliceAssign_s", - "_arraySliceSliceMulSliceAssign_t", - "_arraySliceSliceMulSliceAssign_u", - "_arraySliceSliceMulSliceAssign_w", - - "_arraySliceSliceMulass_d", // T[]*=T[] - "_arraySliceSliceMulass_f", // T[]*=T[] - "_arraySliceSliceMulass_i", - "_arraySliceSliceMulass_k", - "_arraySliceSliceMulass_s", - "_arraySliceSliceMulass_t", - "_arraySliceSliceMulass_u", - "_arraySliceSliceMulass_w", - }; - - int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *)); - if (i == -1) - { -#ifdef DEBUG // Make sure our array is alphabetized - for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++) - { - if (strcmp(name, libArrayopFuncs[i]) == 0) - assert(0); - } -#endif -#endif - /* Not in library, so generate it. - * Construct the function body: - * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++) - * loopbody; - * return p; - */ - - Parameters *fparams = new Parameters(); - Expression *loopbody = buildArrayLoop(fparams); - Parameter *p = (*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 ExpStatement(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::tsize_t), - 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 = LINKc; - 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_DMD - } - else - { /* In library, refer to it. - */ - fd = FuncDeclaration::genCfunc(type, ident); - } - *pfd = fd; // cache symbol in hash table -#elif IN_LLVM - sv->ptrvalue = fd; // cache symbol in hash table -#endif - } - - /* 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/dmd/arraytypes.h b/dmd/arraytypes.h deleted file mode 100644 index 61eb7b50..00000000 --- a/dmd/arraytypes.h +++ /dev/null @@ -1,74 +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" - -struct Expression; -struct Statement; -struct BaseClass; -struct TemplateParameter; -struct FuncDeclaration; -struct Identifier; -struct Initializer; - -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 Modules; -typedef ArrayBase CaseStatements; - -typedef ArrayBase CompoundStatements; - -typedef ArrayBase GotoCaseStatements; - -typedef ArrayBase TemplateInstances; -typedef ArrayBase Blocks; - -typedef ArrayBase Symbols; - -#endif diff --git a/dmd/artistic.txt b/dmd/artistic.txt deleted file mode 100644 index cd17757e..00000000 --- a/dmd/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/dmd/attrib.c b/dmd/attrib.c deleted file mode 100644 index 62b38568..00000000 --- a/dmd/attrib.c +++ /dev/null @@ -1,1563 +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 // memcpy() - -#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 bool 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::apply(Dsymbol_apply_ft_t fp, void *param) -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - if (s) - { - if (s->apply(fp, param)) - return 1; - } - } - } - return 0; -} - -int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - int m = 0; - Dsymbols *d = include(sc, sd); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[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, - structalign_t 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 (size_t i = 0; i < decl->dim; i++) - { Dsymbol *s = (*decl)[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, - structalign_t 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 (size_t i = 0; i < decl->dim; i++) - { Dsymbol *s = (*decl)[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)[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)[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)[i]; - s->semantic3(sc); - } - } -} - -void AttribDeclaration::inlineScan() -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[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 (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[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 (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[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 (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - s->toObjFile(multiobj); - } - } -} - -#endif - -void AttribDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - s->setFieldOffset(ad, poffset, isunion); - } - } -} - -int AttribDeclaration::hasPointers() -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[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) -{ - Dsymbols *d = include(NULL, NULL); - - return Dsymbol::oneMembers(d, ps); -} - -void AttribDeclaration::checkCtorConstInit() -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - s->checkCtorConstInit(); - } - } -} - -/**************************************** - */ - -void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[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)[0])->toCBuffer(buf, hgs); - else - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - } - else - buf->writeByte(';'); - buf->writenl(); -} - -/************************* StorageClassDeclaration ****************************/ - -StorageClassDeclaration::StorageClassDeclaration(StorageClass stc, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->stc = stc; -} - -Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) -{ - StorageClassDeclaration *scd; - - assert(!s); - scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); - return scd; -} - -void StorageClassDeclaration::setScope(Scope *sc) -{ - if (decl) - { - StorageClass scstc = sc->stc; - - /* These sets of storage classes are mutually exclusive, - * so choose the innermost or most recent one. - */ - if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) - scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); - if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) - scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); - if (stc & (STCconst | STCimmutable | STCmanifest)) - scstc &= ~(STCconst | STCimmutable | STCmanifest); - if (stc & (STCgshared | STCshared | STCtls)) - scstc &= ~(STCgshared | STCshared | STCtls); - if (stc & (STCsafe | STCtrusted | STCsystem)) - scstc &= ~(STCsafe | STCtrusted | STCsystem); - scstc |= stc; - //printf("scstc = x%llx\n", scstc); - - 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; - }; - - 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 (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[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; - - // LDC - case LINKintrinsic: p = "Intrinsic"; break; - - 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) -{ - // LDC - // we only support packed structs, as from the spec: align(1) struct Packed { ... } - // other alignments are simply ignored. my tests show this is what llvm-gcc does too ... - 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) -{ - if (salign == STRUCTALIGN_DEFAULT) - buf->printf("align"); - else - buf->printf("align (%d)", salign); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AnonDeclaration ****************************/ - -AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->alignment = 0; - 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); - - 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; - } - - alignment = sc->structalign; - if (decl) - { - sc = sc->push(); - sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared); - sc->inunion = isunion; - sc->offset = 0; - sc->flags = 0; - - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - s->semantic(sc); - } - sc = sc->pop(); - } -} - - -void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); - - if (decl) - { - /* This works by treating an AnonDeclaration as an aggregate 'member', - * so in order to place that member we need to compute the member's - * size and alignment. - */ - - size_t fieldstart = ad->fields.dim; - - /* Hackishly hijack ad's structsize and alignsize fields - * for use in our fake anon aggregate member. - */ - unsigned savestructsize = ad->structsize; - unsigned savealignsize = ad->alignsize; - ad->structsize = 0; - ad->alignsize = 0; - - unsigned offset = 0; - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - - s->setFieldOffset(ad, &offset, this->isunion); - if (this->isunion) - offset = 0; - } - - unsigned anonstructsize = ad->structsize; - unsigned anonalignsize = ad->alignsize; - ad->structsize = savestructsize; - ad->alignsize = savealignsize; - - // 0 sized structs are set to 1 byte - if (anonstructsize == 0) - { - anonstructsize = 1; - anonalignsize = 1; - } - - /* Given the anon 'member's size and alignment, - * go ahead and place it. - */ - unsigned anonoffset = AggregateDeclaration::placeField( - poffset, - anonstructsize, anonalignsize, alignment, - &ad->structsize, &ad->alignsize, - isunion); - - // Add to the anon fields the base offset of this anonymous aggregate - //printf("anon fields, anonoffset = %d\n", anonoffset); - for (size_t i = fieldstart; i < ad->fields.dim; i++) - { - VarDeclaration *v = ad->fields[i]; - //printf("\t[%d] %s %d\n", i, v->toChars(), v->offset); - v->offset += anonoffset; - } - } -} - - -void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf(isunion ? "union" : "struct"); - buf->writestring("\n{\n"); - if (decl) - { - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - - //buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writestring("}\n"); -} - -const char *AnonDeclaration::kind() -{ - return (isunion ? "anonymous union" : "anonymous struct"); -} - -/********************************* PragmaDeclaration ****************************/ - -static bool parseStringExp(Expression* e, std::string& res) -{ - StringExp *s = NULL; - - e = e->optimize(WANTvalue); - if (e->op == TOKstring && (s = (StringExp *)e)) - { - char* str = (char*)s->string; - res = str; - return true; - } - return false; -} - -PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->ident = ident; - this->args = args; -} - -Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); - PragmaDeclaration *pd; - - assert(!s); - pd = new PragmaDeclaration(loc, ident, - Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void PragmaDeclaration::setScope(Scope *sc) -{ -#if TARGET_NET - if (ident == Lexer::idPool("assembly")) - { - if (!args || args->dim != 1) - { - error("pragma has invalid number of arguments"); - } - else - { - Expression *e = (*args)[0]; - e = e->semantic(sc); - e = e->ctfeInterpret(); - (*args)[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)[i]; - - e = e->semantic(sc); - if (e->op != TOKerror && e->op != TOKtype) - e = e->ctfeInterpret(); - 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)[0]; - - e = e->semantic(sc); - e = e->ctfeInterpret(); - (*args)[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)[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)[1]; - e = e->semantic(sc); - e = e->optimize(WANTvalue); - e = e->toString(); - if (e && ((StringExp *)e)->sz == 1) - s = ((StringExp *)e); - else - error("second argument of GNU_asm must be a character 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)[0]; - e = e->semantic(sc); - e = e->ctfeInterpret(); - (*args)[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++) - { -#if IN_LLVM - // ignore errors in ignored pragmas. - global.gag++; - unsigned errors_save = global.errors; -#endif - - Expression *e = (*args)[i]; - e = e->semantic(sc); - e = e->ctfeInterpret(); - if (i == 0) - printf(" ("); - else - printf(","); - printf("%s", e->toChars()); - -#if IN_LLVM - // restore error state. - global.gag--; - global.errors = errors_save; -#endif - } - if (args->dim) - printf(")"); - } - printf("\n"); - } - goto Lnodecl; - } - else - error("unrecognized pragma(%s)", ident->toChars()); - -Ldecl: - if (decl) - { - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[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) -{ - *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)[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; - - /* Embed the library names into the object file. - * The linker will then automatically - * search that library, too. - */ - if (!obj_includelib(name)) - { - /* 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); - } - } -#if DMDV2 - else if (ident == Id::startaddress) - { - assert(args && args->dim == 1); - Expression *e = (*args)[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) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (Expression *)args->data[i]; - - buf->writestring(", "); - e->toCBuffer(buf, hgs); - } - } - buf->writeByte(')'); - AttribDeclaration::toCBuffer(buf, hgs); -} - - -/********************************* ConditionalDeclaration ****************************/ - -ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl) - : AttribDeclaration(decl) -{ - //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); - this->condition = condition; - this->elsedecl = elsedecl; -} - -Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) -{ - ConditionalDeclaration *dd; - - assert(!s); - dd = new ConditionalDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int ConditionalDeclaration::oneMember(Dsymbol **ps) -{ - //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); - if (condition->inc) - { - Dsymbols *d = condition->include(NULL, NULL) ? decl : elsedecl; - return Dsymbol::oneMembers(d, ps); - } - *ps = NULL; - return TRUE; -} - -void ConditionalDeclaration::emitComment(Scope *sc) -{ - //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc); - if (condition->inc) - { - AttribDeclaration::emitComment(sc); - } - else if (sc->docbuf) - { - /* If generating doc comment, be careful because if we're inside - * a template, then include(NULL, NULL) will fail. - */ - Dsymbols *d = decl ? decl : elsedecl; - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[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 (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[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 (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[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 (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[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 (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writeByte('}'); - if (elsedecl) - { - buf->writenl(); - buf->writestring("else"); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (size_t i = 0; i < elsedecl->dim; i++) - { - Dsymbol *s = (*elsedecl)[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 - - // But do set the scope, in case we need it for forward referencing - Dsymbol::setScope(sc); - - // Set the scopes for both the decl and elsedecl, as we don't know yet - // which will be selected, and the scope will be the same regardless - Dsymbols *d = decl; - for (int j = 0; j < 2; j++) - { - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[i]; - - s->setScope(sc); - } - } - d = elsedecl; - } -} - -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 (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[i]; - - s->semantic(sc); - } - } -} - -const char *StaticIfDeclaration::kind() -{ - return "static if"; -} - - -/***************************** CompileDeclaration *****************************/ - -// These are mixin declarations, like mixin("int x"); - -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->ctfeInterpret(); - 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/dmd/attrib.h b/dmd/attrib.h deleted file mode 100644 index 91b135cd..00000000 --- a/dmd/attrib.h +++ /dev/null @@ -1,204 +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. - -#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 apply(Dsymbol_apply_ft_t fp, void *param); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void setScopeNewSc(Scope *sc, - StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, - structalign_t structalign); - void semanticNewSc(Scope *sc, - StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, - structalign_t 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); - void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - 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 -#endif - -#if IN_LLVM - virtual void codegen(Ir*); -#endif -}; - -struct StorageClassDeclaration: AttribDeclaration -{ - StorageClass stc; - - StorageClassDeclaration(StorageClass stc, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - static void stcToCBuffer(OutBuffer *buf, StorageClass stc); -}; - -struct LinkDeclaration : AttribDeclaration -{ - enum LINK linkage; - - LinkDeclaration(enum LINK p, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void semantic3(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *toChars(); -}; - -struct ProtDeclaration : AttribDeclaration -{ - enum PROT protection; - - ProtDeclaration(enum PROT p, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void importAll(Scope *sc); - void setScope(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - static void protectionToCBuffer(OutBuffer *buf, enum PROT protection); -}; - -struct AlignDeclaration : AttribDeclaration -{ - unsigned salign; - - AlignDeclaration(Loc loc, unsigned sa, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct AnonDeclaration : AttribDeclaration -{ - bool isunion; - structalign_t alignment; - int sem; // 1 if successful semantic() - - AnonDeclaration(Loc loc, int isunion, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); -}; - -struct PragmaDeclaration : AttribDeclaration -{ - Expressions *args; // array of Expression's - - PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void setScope(Scope *sc); - int oneMember(Dsymbol **ps); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -struct ConditionalDeclaration : AttribDeclaration -{ - Condition *condition; - Dsymbols *elsedecl; // array of Dsymbol's for else block - - ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); - Dsymbol *syntaxCopy(Dsymbol *s); - int oneMember(Dsymbol **ps); - void emitComment(Scope *sc); - Dsymbols *include(Scope *sc, ScopeDsymbol *s); - void addComment(unsigned char *comment); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); - void importAll(Scope *sc); - void setScope(Scope *sc); -}; - -struct StaticIfDeclaration : ConditionalDeclaration -{ - ScopeDsymbol *sd; - int addisdone; - - StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void semantic(Scope *sc); - void importAll(Scope *sc); - void setScope(Scope *sc); - const char *kind(); -}; - -// Mixin declarations - -struct CompileDeclaration : AttribDeclaration -{ - Expression *exp; - - ScopeDsymbol *sd; - int compiled; - - CompileDeclaration(Loc loc, Expression *exp); - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *sd, int memnum); - void compileIt(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#endif /* DMD_ATTRIB_H */ diff --git a/dmd/cast.c b/dmd/cast.c deleted file mode 100644 index fbd03637..00000000 --- a/dmd/cast.c +++ /dev/null @@ -1,1676 +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 // mem{set|cpy}() - -#include "rmem.h" - -#include "expression.h" -#include "mtype.h" -#include "utf.h" -#include "declaration.h" -#include "aggregate.h" - -/* ==================== implicitCast ====================== */ - -/************************************** - * Do an implicit cast. - * Issue error if it can't be done. - */ - -Expression *Expression::implicitCastTo(Scope *sc, Type *t) -{ - //printf("implicitCastTo(%s) => %s\n", type->toChars(), t->toChars()); - if (implicitConvTo(t)) - { TY tyfrom = type->toBasetype()->ty; - TY tyto = t->toBasetype()->ty; - 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()); - } - } -#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 *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; - } - if (t->ty == Tbit && isBit()) - return MATCHconvert; - Expression *e = optimize(WANTvalue | WANTflags); - if (e != this) - { //printf("optimzed to %s\n", e->toChars()); - return e->implicitConvTo(t); - } - MATCH match = type->implicitConvTo(t); - if (match) - return match; -#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 - if (type->equals(t)) - return MATCHexact; - - enum TY ty = type->toBasetype()->ty; - enum TY toty = t->toBasetype()->ty; - enum TY oldty = ty; - - if (type->implicitConvTo(t) == MATCHnomatch && t->ty == Tenum) - { - return MATCHnomatch; - } - - switch (ty) - { - case Tbit: - case Tbool: - value &= 1; - ty = Tint32; - break; - - case Tint8: - value = (signed char)value; - ty = Tint32; - break; - - case Tchar: - case Tuns8: - value &= 0xFF; - ty = Tint32; - break; - - case Tint16: - value = (short)value; - ty = Tint32; - break; - - case Tuns16: - case Twchar: - value &= 0xFFFF; - ty = Tint32; - break; - - case Tint32: - value = (int)value; - break; - - case Tuns32: - case Tdchar: - value &= 0xFFFFFFFF; - ty = Tuns32; - break; - - default: - break; - } - - // Only allow conversion if no change in value - switch (toty) - { - case Tbit: - case Tbool: - if ((value & 1) != value) - goto Lno; - goto Lyes; - - case Tint8: - if ((signed char)value != value) - goto Lno; - goto Lyes; - - case Tchar: - if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F) - goto Lno; - 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 Twchar: - if (oldty == Tdchar && value > 0xD7FF && value < 0xE000) - goto Lno; - 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 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; - } - } - 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; - // NULL implicitly converts to any pointer type or dynamic array - if (type->ty == Tpointer && type->next->ty == Tvoid) - { - if (t->ty == Ttypedef) - t = ((TypeTypedef *)t)->sym->basetype; - if (t->ty == Tpointer || t->ty == Tarray || - t->ty == Taarray || t->ty == Tclass || - t->ty == Tdelegate) - return committed ? MATCHconvert : MATCHexact; - } - return Expression::implicitConvTo(t); -} - -#if DMDV2 -MATCH StructLiteralExp::implicitConvTo(Type *t) -{ -#if 0 - printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH m = Expression::implicitConvTo(t); - if (m != MATCHnomatch) - return m; - if (type->ty == t->ty && type->ty == Tstruct && - ((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym) - { - m = MATCHconst; - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - Type *te = e->type; - if (t->mod == 0) - te = te->mutableOf(); - else - { assert(t->mod == MODimmutable); - te = te->invariantOf(); - } - MATCH m2 = e->implicitConvTo(te); - //printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2); - if (m2 < m) - m = m2; - } - } - return m; -} -#endif - -MATCH StringExp::implicitConvTo(Type *t) -{ -#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->next->ty == Tvoid) - { - return MATCHnomatch; - } - if (!committed) - if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer) - { - if (type->next->ty == Tchar) - { - switch (t->ty) - { - case Tsarray: - if (type->ty == Tsarray && - ((TypeSArray *)type)->dim->toInteger() != - ((TypeSArray *)t)->dim->toInteger()) - return MATCHnomatch; - goto L1; - case Tarray: - goto L1; - case Tpointer: - L1: - if (t->next->ty == Tchar) - return MATCHexact; - else if (!committed) - { if (t->next->ty == Twchar) - return MATCHexact; - else if (t->next->ty == Tdchar) - return MATCHexact; - } - 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; - } - - if (!elements->dim && typeb->nextOf()->toBasetype()->ty != Tvoid) - result = MATCHnomatch; - - Type *telement = tb->nextOf(); - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - if (result == MATCHnomatch) - break; // no need to check for worse - MATCH m = (MATCH)e->implicitConvTo(telement); - if (m < result) - result = m; // remember worst match - } - - if (!result) - result = type->implicitConvTo(t); - - return result; - } -#if DMDV2 - else if (tb->ty == Tvector && - (typeb->ty == Tarray || typeb->ty == Tsarray)) - { - // Convert array literal to vector type - TypeVector *tv = (TypeVector *)tb; - TypeSArray *tbase = (TypeSArray *)tv->basetype; - assert(tbase->ty == Tsarray); - if (elements->dim != tbase->dim->toInteger()) - return MATCHnomatch; - - Type *telement = tv->elementType(); - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - MATCH m = (MATCH)e->implicitConvTo(telement); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - } - return result; - } -#endif - else - return Expression::implicitConvTo(t); -} - -MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) -{ MATCH result = MATCHexact; - - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if (tb->ty == Taarray && typeb->ty == Taarray) - { - for (size_t i = 0; i < keys->dim; i++) - { Expression *e = (Expression *)keys->data[i]; - MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->key); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - e = (Expression *)values->data[i]; - m = (MATCH)e->implicitConvTo(tb->nextOf()); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - } - return result; - } - else - return Expression::implicitConvTo(t); -} - -MATCH AddrExp::implicitConvTo(Type *t) -{ -#if 0 - printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - //printf("\tresult = %d\n", result); - - if (result == MATCHnomatch) - { - // Look for pointers to functions where the functions are overloaded. - VarExp *ve; - FuncDeclaration *f; - - t = t->toBasetype(); - if (type->ty == Tpointer && type->next->ty == Tfunction && - t->ty == Tpointer && t->next->ty == Tfunction && - e1->op == TOKvar) - { - ve = (VarExp *)e1; - f = ve->var->isFuncDeclaration(); - if (f && f->overloadExactMatch(t->next, 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->next->ty == Tfunction && - t->ty == Tpointer && t->next->ty == Tfunction) - { - f = var->isFuncDeclaration(); - if (f && f->overloadExactMatch(t->next, m)) - 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 == 0) - { - // Look for pointers to functions where the functions are overloaded. - - t = t->toBasetype(); - if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction && - t->ty == Tdelegate && t->nextOf()->ty == Tfunction) - { - if (func && func->overloadExactMatch(t->nextOf(), m)) - result = MATCHexact; - } - } - return result; -} - -MATCH CondExp::implicitConvTo(Type *t) -{ - MATCH m1; - MATCH m2; - - m1 = e1->implicitConvTo(t); - m2 = e2->implicitConvTo(t); - - // Pick the worst match - return (m1 < m2) ? m1 : m2; -} - - -/* ==================== castTo ====================== */ - -/************************************** - * Do an explicit cast. - */ - -Expression *Expression::castTo(Scope *sc, Type *t) -{ - //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars()); -#if 0 - printf("Expression::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t) - return this; - Expression *e = this; - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { - // Do (type *) cast of (type [dim]) - if (tb->ty == Tpointer && - typeb->ty == Tsarray - ) - { - //printf("Converting [dim] to *\n"); - - if (typeb->size(loc) == 0) - e = new NullExp(loc); - else - e = new AddrExp(loc, e); - } -#if 0 - else if (tb->ty == Tdelegate && type->ty != Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - return toDelegate(sc, tf->nextOf()); - } -#endif - else - { - 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) -{ NullExp *e; - Type *tb; - - //printf("NullExp::castTo(t = %p)\n", t); - if (type == t) - { - committed = 1; - return this; - } - e = (NullExp *)copy(); - e->committed = 1; - tb = t->toBasetype(); - e->type = type->toBasetype(); - if (tb != e->type) - { - // NULL implicitly converts to any pointer type or dynamic array - if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid && - (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray || - tb->ty == Tdelegate)) - { -#if 0 - if (tb->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) - { - return Expression::castTo(sc, t); - } - } -#endif - } - else - { - return e->Expression::castTo(sc, t); - } - } - e->type = t; - return e; -} - -Expression *StringExp::castTo(Scope *sc, Type *t) -{ - /* This follows copy-on-write; any changes to 'this' - * will result in a copy. - * The this->string member is considered immutable. - */ - int copied = 0; - - //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed); - - if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) - { - error("cannot convert string literal to void*"); - return new ErrorExp(); - } - - StringExp *se = this; - if (!committed) - { se = (StringExp *)copy(); - se->committed = 1; - copied = 1; - } - - if (type == t) - { - return se; - } - - Type *tb = t->toBasetype(); - //printf("\ttype = %s\n", type->toChars()); - if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate) - return Expression::castTo(sc, t); - - Type *typeb = type->toBasetype(); - if (typeb == tb) - { - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - se->type = t; - return se; - } - - if (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. - VarExp *ve; - FuncDeclaration *f; - - if (type->ty == Tpointer && type->next->ty == Tfunction && - tb->ty == Tpointer && tb->next->ty == Tfunction && - e1->op == TOKvar) - { - ve = (VarExp *)e1; - f = ve->var->isFuncDeclaration(); - if (f) - { - f = f->overloadExactMatch(tb->next, m); - if (f) - { - e = new VarExp(loc, f); - e->type = f->type; - e = new AddrExp(loc, e); - e->type = t; - return e; - } - } - } - e = Expression::castTo(sc, t); - } - e->type = t; - return e; -} - - -Expression *TupleExp::castTo(Scope *sc, Type *t) -{ TupleExp *e = (TupleExp *)copy(); - e->exps = (Expressions *)exps->copy(); - for (size_t i = 0; i < e->exps->dim; i++) - { Expression *ex = (Expression *)e->exps->data[i]; - ex = ex->castTo(sc, t); - e->exps->data[i] = (void *)ex; - } - return e; -} - - -Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t) - return this; - ArrayLiteralExp *e = this; - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if ((tb->ty == Tarray || tb->ty == Tsarray) && - (typeb->ty == Tarray || typeb->ty == Tsarray) && - // Not trying to convert non-void[] to void[] - !(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)) - { - if (tb->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)tb; - if (elements->dim != tsa->dim->toInteger()) - goto L1; - } - - e = (ArrayLiteralExp *)copy(); - e->elements = (Expressions *)elements->copy(); - for (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) - { - e = (ArrayLiteralExp *)copy(); - e->type = typeb->nextOf()->pointerTo(); - } -#if DMDV2 - else if (tb->ty == Tvector && - (typeb->ty == Tarray || typeb->ty == Tsarray)) - { - // Convert array literal to vector type - TypeVector *tv = (TypeVector *)tb; - TypeSArray *tbase = (TypeSArray *)tv->basetype; - assert(tbase->ty == Tsarray); - if (elements->dim != tbase->dim->toInteger()) - goto L1; - - e = (ArrayLiteralExp *)copy(); - e->elements = (Expressions *)elements->copy(); - Type *telement = tv->elementType(); - for (size_t i = 0; i < elements->dim; i++) - { Expression *ex = (*elements)[i]; - ex = ex->castTo(sc, telement); - (*e->elements)[i] = ex; - } - Expression *ev = new VectorExp(loc, e, tb); - ev = ev->semantic(sc); - return ev; - } -#endif -L1: - return e->Expression::castTo(sc, t); -} - -Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) -{ - if (type == t) - return this; - AssocArrayLiteralExp *e = this; - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if (tb->ty == Taarray && typeb->ty == Taarray && - tb->nextOf()->toBasetype()->ty != Tvoid) - { - e = (AssocArrayLiteralExp *)copy(); - e->keys = (Expressions *)keys->copy(); - e->values = (Expressions *)values->copy(); - assert(keys->dim == values->dim); - for (size_t i = 0; i < keys->dim; i++) - { Expression *ex = (Expression *)values->data[i]; - ex = ex->castTo(sc, tb->nextOf()); - e->values->data[i] = (void *)ex; - - ex = (Expression *)keys->data[i]; - ex = ex->castTo(sc, ((TypeAArray *)tb)->index); - e->keys->data[i] = (void *)ex; - } - e->type = t; - return e; - } - 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 - Expression *e = this; - - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { - // Look for pointers to functions where the functions are overloaded. - FuncDeclaration *f; - - if (typeb->ty == Tpointer && typeb->next->ty == Tfunction && - tb->ty == Tpointer && tb->next->ty == Tfunction) - { - f = var->isFuncDeclaration(); - if (f) - { - f = f->overloadExactMatch(tb->next, m); - if (f) - { -#if DMDV2 - 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 -#endif - { - e = new SymOffExp(loc, f, 0); - e->type = t; - } -#if DMDV2 - f->tookAddressOf++; -#endif - return e; - } - } - } - e = Expression::castTo(sc, t); - } - else - { - e->type = t; - } - 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 = type->toBasetype(); - if (tb != type || hasOverloads) - { - // Look for delegates to functions where the functions are overloaded. - FuncDeclaration *f; - - if (type->ty == Tdelegate && type->next->ty == Tfunction && - tb->ty == Tdelegate && tb->next->ty == Tfunction) - { - if (func) - { - f = func->overloadExactMatch(tb->next, m); - if (f) - { int offset; - if (f->tintro && f->tintro->next->isBaseOf(f->type->next, &offset) && offset) - error("%s", msg); - 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; - - if (func->tintro && func->tintro->next->isBaseOf(func->type->next, &offset) && offset) - error("%s", msg); - } - e->type = t; - return e; -} - -Expression *CondExp::castTo(Scope *sc, Type *t) -{ - Expression *e = this; - - if (type != t) - { - if (1 || e1->op == TOKstring || e2->op == TOKstring) - { e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t)); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - -/* ==================== ====================== */ - -/**************************************** - * Scale addition/subtraction to/from pointer. - */ - -Expression *BinExp::scaleFactor(Scope *sc) -{ d_uns64 stride; - Type *t1b = e1->type->toBasetype(); - Type *t2b = e2->type->toBasetype(); - - if (t1b->ty == Tpointer && t2b->isintegral()) - { // Need to adjust operator by the stride - // Replace (ptr + int) with (ptr + (int * stride)) - Type *t = Type::tptrdiff_t; - - stride = t1b->nextOf()->size(loc); - if (!t->equals(t2b)) - e2 = e2->castTo(sc, t); - // LDC: llvm uses typesafe pointer arithmetic - #if !IN_LLVM - if (t1b->next->isbit()) - // BUG: should add runtime check for misaligned offsets - // This perhaps should be done by rewriting as &p[i] - // and letting back end do it. - e2 = new UshrExp(loc, e2, new IntegerExp(0, 3, t)); - else - 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 - if (t2b->next->isbit()) - // BUG: should add runtime check for misaligned offsets - e = new UshrExp(loc, e, new IntegerExp(0, 3, t)); - else - e = new MulExp(loc, e, new IntegerExp(0, stride, t)); - #endif - e->type = t; - type = e2->type; - e1 = e2; - e2 = e; - } - return this; -} - -/************************************ - * Bring leaves to common type. - */ - -Expression *BinExp::typeCombine(Scope *sc) -{ - Type *t1; - Type *t2; - Type *t; - TY ty; - - //printf("BinExp::typeCombine()\n"); - //dump(0); - - e1 = e1->integralPromotions(sc); - e2 = e2->integralPromotions(sc); - - // BUG: do toBasetype() - t1 = e1->type; - t2 = e2->type; - assert(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)Type::impcnvResult[t1b->ty][t2b->ty]; - if (ty != Terror) - { TY ty1; - TY ty2; - - ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty]; - ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty]; - - if (t1b->ty == ty1) // if no promotions - { - if (t1 == t2) - { - if (!type) - type = t1; - return this; - } - - if (t1b == t2b) - { - if (!type) - type = t1b; - return this; - } - } - - if (!type) - type = Type::basic[ty]; - - t1 = Type::basic[ty1]; - t2 = Type::basic[ty2]; - e1 = e1->castTo(sc, t1); - e2 = e2->castTo(sc, t2); -#if 0 - if (type != Type::basic[ty]) - { t = type; - type = Type::basic[ty]; - return castTo(sc, t); - } -#endif - //printf("after typeCombine():\n"); - //dump(0); - //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2); - return this; - } - - t = t1; - if (t1 == t2) - { - if ((t1->ty == Tstruct || t1->ty == Tclass) && - (op == TOKmin || op == TOKadd)) - goto Lincompatible; - } - else if (t1->isintegral() && t2->isintegral()) - { - printf("t1 = %s, t2 = %s\n", t1->toChars(), t2->toChars()); - int sz1 = t1->size(); - int sz2 = t2->size(); - int sign1 = t1->isunsigned() == 0; - int sign2 = t2->isunsigned() == 0; - - if (sign1 == sign2) - { - if (sz1 < sz2) - goto Lt2; - else - goto Lt1; - } - if (!sign1) - { - if (sz1 >= sz2) - goto Lt1; - else - goto Lt2; - } - else - { - if (sz2 >= sz1) - goto Lt2; - else - goto Lt1; - } - } - else if (t1->ty == Tpointer && t2->ty == Tpointer) - { - // Bring pointers to compatible type - Type *t1n = t1->next; - Type *t2n = t2->next; - -//t1->print(); -//t2->print(); -//if (t1n == t2n) *(char *)0 = 0; - assert(t1n != t2n); - if (t1n->ty == Tvoid) // pointers to void are always compatible - t = t2; - else if (t2n->ty == Tvoid) - ; - else if (t1n->ty == Tclass && t2n->ty == Tclass) - { ClassDeclaration *cd1 = t1n->isClassHandle(); - ClassDeclaration *cd2 = t2n->isClassHandle(); - int offset; - - if (cd1->isBaseOf(cd2, &offset)) - { - if (offset) - e2 = e2->castTo(sc, t); - } - else if (cd2->isBaseOf(cd1, &offset)) - { - t = t2; - if (offset) - e1 = e1->castTo(sc, t); - } - else - goto Lincompatible; - } - else - goto Lincompatible; - } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && - e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid) - { /* (T[n] op void*) - * (T[] op void*) - */ - goto Lx1; - } - else if ((t2->ty == Tsarray || t2->ty == Tarray) && - e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid) - { /* (void* op T[n]) - * (void* op T[]) - */ - goto Lx2; - } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) - { - 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; - } - else if (t1->ty == Tclass || t2->ty == Tclass) - { - while (1) - { - int i1 = e2->implicitConvTo(t1); - int i2 = e1->implicitConvTo(t2); - - if (i1 && i2) - { - // We have the case of class vs. void*, so pick class - if (t1->ty == Tpointer) - i1 = 0; - else if (t2->ty == Tpointer) - i2 = 0; - } - - if (i2) - { - goto Lt2; - } - else if (i1) - { - goto Lt1; - } - else if (t1->ty == Tclass && t2->ty == Tclass) - { TypeClass *tc1 = (TypeClass *)t1; - TypeClass *tc2 = (TypeClass *)t2; - - /* Pick 'tightest' type - */ - ClassDeclaration *cd1 = tc1->sym->baseClass; - ClassDeclaration *cd2 = tc2->sym->baseClass; - - if (cd1 && cd2) - { t1 = cd1->type; - t2 = cd2->type; - } - else if (cd1) - t1 = cd1->type; - else if (cd2) - t2 = cd2->type; - else - goto Lincompatible; - } - else - goto Lincompatible; - } - } - else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2)) - { - goto Lt2; - } -//else if (e2->op == TOKstring) { printf("test2\n"); } - else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1)) - { - goto Lt1; - } - else if (t1->ty == Tsarray && t2->ty == Tsarray && - e2->implicitConvTo(t1->nextOf()->arrayOf())) - { - Lx1: - t = t1->nextOf()->arrayOf(); - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - } - else if (t1->ty == Tsarray && t2->ty == Tsarray && - e1->implicitConvTo(t2->nextOf()->arrayOf())) - { - Lx2: - t = t2->nextOf()->arrayOf(); - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - } - else if (t1->isintegral() && t2->isintegral()) - { - assert(0); - } - else if (e1->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 (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: - incompatibleTypes(); - type = Type::terror; - e1 = new ErrorExp(); - e2 = new ErrorExp(); - return new ErrorExp(); - } -Lret: - if (!type) - type = t; - //dump(0); - return this; - - -Lt1: - e2 = e2->castTo(sc, t1); - t = t1; - goto Lret; - -Lt2: - e1 = e1->castTo(sc, t2); - t = t2; - goto Lret; -} - -/*********************************** - * Do integral promotions (convertchk). - * Don't convert to - */ - -Expression *Expression::integralPromotions(Scope *sc) -{ - Expression *e = this; - - //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars()); - switch (type->toBasetype()->ty) - { - case Tvoid: - error("void has no value"); - return new ErrorExp(); - - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: - case Tbit: - case Tbool: - case Tchar: - case Twchar: - e = e->castTo(sc, Type::tint32); - break; - - case Tdchar: - e = e->castTo(sc, Type::tuns32); - break; - } - return e; -} - diff --git a/dmd/class.c b/dmd/class.c deleted file mode 100644 index 84300229..00000000 --- a/dmd/class.c +++ /dev/null @@ -1,1595 +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 // mem{cpy|set}() - -#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::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; - - ctor = NULL; - defaultCtor = NULL; - 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::Error) - { if (errorException) - errorException->error("%s", msg); - errorException = this; - } - - if (id == Id::ClassInfo) - { if (classinfo) - classinfo->error("%s", msg); - classinfo = this; - } - - if (id == Id::ModuleInfo) - { if (Module::moduleinfo) - Module::moduleinfo->error("%s", msg); - Module::moduleinfo = this; - } - } - - com = 0; - isscope = 0; - isabstract = 0; - isnested = 0; - vthis = NULL; - 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)[i]; - BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); - (*cd->baseclasses)[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 == SIZEOKdone || !scope) - { //printf("\tsemantic for '%s' is already completed\n", toChars()); - return; // semantic() already completed - } - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - unsigned dprogress_save = Module::dprogress; -#ifdef IN_GCC - methods.setDim(0); -#endif - - if (sc->stc & STCdeprecated) - { - isdeprecated = 1; - } - - // Expand any tuples in baseclasses[] - for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = (*baseclasses)[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)[0]; - //b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty != Tclass) - { if (b->type != Type::terror) - 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 == SIZEOKnone) - { // 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 == SIZEOKnone) - { - //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)[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()) - { if (b->type != Type::terror) - 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)[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) - { - if (!object) - { - error("missing or corrupt object.d"); - fatal(); - } - - Type *t = object->type; - t = t->semantic(loc, sc)->toBasetype(); - assert(t->ty == Tclass); - TypeClass *tc = (TypeClass *)t; - - BaseClass *b = new BaseClass(tc, PROTpublic); - baseclasses->shift(b); - - 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; - } - 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)[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() && - (!toParent2() || - !baseClass->toParent2()->getType()->isBaseOf(toParent2()->getType(), NULL))) - { - 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 = new TypePointer(Type::tvoid); - t = t->semantic(0, sc); - } - } - else - assert(0); - 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; - - sc = sc->push(this); - 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 = STRUCTALIGN_DEFAULT; - 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 = SIZEOKnone; - - /* 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) || - s->isTemplateMixin() || - s->isAttribDeclaration() || - s->isAliasDeclaration()) - { - //printf("[%d] setScope %s %s, sc = %p\n", i, s->kind(), s->toChars(), sc); - s->setScope(sc); - } - } - - for (size_t i = 0; i < members_dim; i++) - { Dsymbol *s = (*members)[i]; - s->semantic(sc); - } - - // Set the offsets of the fields and determine the size of the class - - unsigned offset = structsize; - bool isunion = isUnionDeclaration() != NULL; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->setFieldOffset(this, &offset, false); - } - sc->offset = structsize; - - 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 - - for (size_t i = 0; i < fields.dim; i++) - { Dsymbol *s = fields[i]; - VarDeclaration *vd = s->isVarDeclaration(); - if (vd) - vd->offset = 0; - } - 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()); - - //members->print(); - - /* Look for special member functions. - * They must be in this class, not in a base class. - */ - ctor = (CtorDeclaration *)search(0, Id::ctor, 0); - if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration())) - ctor = NULL; - -// dtor = (DtorDeclaration *)search(Id::dtor, 0); -// if (dtor && dtor->toParent() != this) -// dtor = NULL; - -// inv = (InvariantDeclaration *)search(Id::classInvariant, 0); -// if (inv && inv->toParent() != this) -// inv = NULL; - - // Can be in base class - aggNew = (NewDeclaration *)search(0, Id::classNew, 0); - aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); - - // If this class has no constructor, but base class does, create - // a constructor: - // this() { } - if (!ctor && baseClass && baseClass->ctor) - { - //printf("Creating default this(){} for class %s\n", toChars()); - CtorDeclaration *ctor = new CtorDeclaration(loc, 0, NULL, 0); - ctor->fbody = new CompoundStatement(0, new Statements()); - members->push(ctor); - ctor->addMember(sc, this, 1); - *sc = scsave; // why? What about sc->nofree? - 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 - sc->offset = structsize; - for (size_t i = 0; i < vtblInterfaces->dim; i++) - { - BaseClass *b = (*vtblInterfaces)[i]; - unsigned thissize = PTRSIZE; - - alignmember(structalign, thissize, &sc->offset); - assert(b->offset == 0); - b->offset = sc->offset; - - // Take care of single inheritance offsets - while (b->baseInterfaces_dim) - { - b = &b->baseInterfaces[0]; - b->offset = sc->offset; - } - - sc->offset += thissize; - if (alignsize < thissize) - alignsize = thissize; - } - structsize = sc->offset; - sizeok = SIZEOKdone; - 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)[i]; - - //b->fillVtbl(this, &b->vtbl, 1); - } -#endif - //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type); -} - -void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (!isAnonymous()) - { - buf->printf("%s ", kind()); - buf->writestring(toChars()); - if (baseclasses->dim) - buf->writestring(" : "); - } - for (size_t i = 0; i < baseclasses->dim; i++) - { - BaseClass *b = (*baseclasses)[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)[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)[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)[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++; - // If speculatively gagged, ungag now. - unsigned oldgag = global.gag; - if (global.isSpeculativeGagging()) - global.gag = 0; - semantic(sc); - global.gag = oldgag; - 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)[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; - } - FuncDeclaration *fdstart = s->toAlias()->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)[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\n", fd->parent->isClassDeclaration()); - if (!fdmatch) - goto Lfd; - if (fd == fdmatch) - goto Lfdmatch; - - { - // 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) -{ - 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; - - 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[i]->isFuncDeclaration(); - - //printf("\tvtbl[%d] = %p\n", i, fd); - if (!fd || fd->isAbstract()) - { - isabstract |= 1; - return TRUE; - } - } - return FALSE; -} - - -/**************************************** - * Returns !=0 if there's an extra member which is the 'this' - * pointer to the enclosing context (enclosing class or function) - */ - -int ClassDeclaration::isNested() -{ - return isnested; -} - -/**************************************** - * 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; - if (id == Id::IUnknown) // IUnknown is the root of all COM objects - com = 1; -} - -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; - } - - if (sc->stc & STCdeprecated) - { - isdeprecated = true; - } - - // Expand any tuples in baseclasses[] - for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = (*baseclasses)[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++; - } - - // Check for errors, handle forward references - for (size_t i = 0; i < baseclasses->dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (*baseclasses)[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()) - { if (b->type != Type::terror) - 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)[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; - } - } - 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 (size_t k = 0; k < i; k++) - { - if (b == interfaces[k]) - goto Lcontinue; - } - - // Copy vtbl[] from base class - if (b->base->vtblOffset()) - { size_t d = b->base->vtbl.dim; - if (d > 1) - { - vtbl.reserve(d - 1); - for (size_t j = 1; j < d; j++) - vtbl.push(b->base->vtbl[j]); - } - } - else - { - vtbl.append(&b->base->vtbl); - } - - Lcontinue: - ; - } - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->addMember(sc, this, 1); - } - - sc = sc->push(this); - sc->stc &= STCsafe | STCtrusted | STCsystem; - sc->parent = this; - if (isCOMinterface()) - sc->linkage = LINKwindows; - sc->structalign = STRUCTALIGN_DEFAULT; - sc->protection = PROTpublic; - sc->explicitProtection = 0; - structalign = sc->structalign; - sc->offset = PTRSIZE * 2; - structsize = sc->offset; - inuse++; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->semantic(sc); - } - inuse--; - //members->print(); - sc->pop(); - //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); -} - - -/******************************************* - * Determine if 'this' is a base class of cd. - * (Actually, if it is an interface supported by cd) - * Output: - * *poffset offset to start of class - * OFFSET_RUNTIME must determine offset at runtime - * Returns: - * 0 not a base - * 1 is a base - */ - -int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) -{ - unsigned j; - - //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars()); - assert(!baseClass); - for (j = 0; j < cd->interfaces_dim; j++) - { - BaseClass *b = cd->interfaces[j]; - - //printf("\tbase %s\n", b->base->toChars()); - if (this == b->base) - { - //printf("\tfound at offset %d\n", b->offset); - if (poffset) - { *poffset = b->offset; - if (j && cd->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - } - return 1; - } - if (isBaseOf(b, poffset)) - { if (j && poffset && cd->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - return 1; - } - } - - if (cd->baseClass && isBaseOf(cd->baseClass, poffset)) - return 1; - - if (poffset) - *poffset = 0; - return 0; -} - - -int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset) -{ - //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars()); - for (unsigned j = 0; j < bc->baseInterfaces_dim; j++) - { - BaseClass *b = &bc->baseInterfaces[j]; - - if (this == b->base) - { - if (poffset) - { *poffset = b->offset; - if (j && bc->base->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - } - return 1; - } - if (isBaseOf(b, poffset)) - { if (j && poffset && bc->base->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - return 1; - } - } - if (poffset) - *poffset = 0; - return 0; -} - -/********************************************* - * Determine if 'this' has clomplete base class information. - * This is used to detect forward references in covariant overloads. - */ - -int InterfaceDeclaration::isBaseInfoComplete() -{ - assert(!baseClass); - for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *b = (*baseclasses)[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()) - 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[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)[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/dmd/clone.c b/dmd/clone.c deleted file mode 100644 index b2bf8f6b..00000000 --- a/dmd/clone.c +++ /dev/null @@ -1,175 +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" - - -/********************************* - * Generate expression that calls opClone() - * for each member of the struct - * (can be NULL for members that don't need one) - */ - -#if DMDV2 -Expression *StructDeclaration::cloneMembers() -{ - Expression *e = NULL; - - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - 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->opclone) - { - - // this.v - Expression *ex = new ThisExp(0); - ex = new DotVarExp(0, ex, v, 0); - - if (dim == 1) - { // this.v.opClone() - ex = new DotVarExp(0, ex, sd->opclone, 0); - ex = new CallExp(0, ex); - } - else - { - // _callOpClones(&this.v, opclone, dim) - Expressions *args = new Expressions(); - args->push(new AddrExp(0, ex)); - args->push(new SymOffExp(0, sd->opclone, 0)); - args->push(new IntegerExp(dim)); - FuncDeclaration *ec = FuncDeclaration::genCfunc(Type::tvoid, "_callOpClones"); - ex = new CallExp(0, new VarExp(0, ec), args); - } - e = Expression::combine(e, ex); - } - } - } - return e; -} -#endif - -/***************************************** - * Create inclusive destructor for struct by aggregating - * all the destructors in dtors[] with the destructors for - * all the members. - */ - -FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) -{ - //printf("StructDeclaration::buildDtor() %s\n", toChars()); - Expression *e = NULL; - -#if DMDV2 - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - 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 == 1) - { // this.v.dtor() - ex = new DotVarExp(0, ex, sd->dtor, 0); - ex = new CallExp(0, ex); - } - else - { - // Typeinfo.destroy(cast(void*)&this.v); - Expression *ea = new AddrExp(0, ex); - ea = new CastExp(0, ea, Type::tvoid->pointerTo()); - Expressions *args = new Expressions(); - args->push(ea); - - Expression *et = v->type->getTypeInfo(sc); - et = new DotIdExp(0, et, Id::destroy); - - ex = new CallExp(0, et, args); - } - 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 (FuncDeclaration *)dtors.data[0]; - - default: - e = NULL; - for (size_t i = 0; i < dtors.dim; i++) - { FuncDeclaration *fd = (FuncDeclaration *)dtors.data[i]; - Expression *ex = new ThisExp(0); - ex = new DotVarExp(0, ex, fd); - 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/dmd/complex_t.h b/dmd/complex_t.h deleted file mode 100644 index fa39271e..00000000 --- a/dmd/complex_t.h +++ /dev/null @@ -1,76 +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 -{ - longdouble re; - longdouble im; - - complex_t() { this->re = 0; this->im = 0; } - complex_t(longdouble re) { this->re = re; this->im = 0; } - complex_t(double re) { this->re = re; this->im = 0; } - complex_t(longdouble re, longdouble im) { this->re = re; this->im = im; } - complex_t(double re, 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) - { - longdouble abs_y_re = y.re < 0 ? -y.re : y.re; - longdouble abs_y_im = y.im < 0 ? -y.im : y.im; - longdouble 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 * (longdouble x, complex_t y) { return complex_t(x) * y; } -inline complex_t operator * (complex_t x, longdouble y) { return x * complex_t(y); } -inline complex_t operator / (complex_t x, longdouble y) { return x / complex_t(y); } - - -inline longdouble creall(complex_t x) -{ - return x.re; -} - -inline longdouble cimagl(complex_t x) -{ - return x.im; -} - -#endif diff --git a/dmd/cond.c b/dmd/cond.c deleted file mode 100644 index f54fd467..00000000 --- a/dmd/cond.c +++ /dev/null @@ -1,430 +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 // strcmp() - -#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" -#include "arraytypes.h" - -int findCondition(Strings *ids, Identifier *ident) -{ - if (ids) - { - for (size_t i = 0; i < ids->dim; i++) - { - const char *id = (*ids)[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; - this->nest = 0; -} - -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) this=%p inc = %d\n", sc, s, this, inc); - if (s) - { - printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind()); - } -#endif - if (inc == 0) - { - if (exp->op == TOKerror || nest > 100) - { - error(loc, (nest > 1000) ? "unresolvable circular static if expression" - : "error evaluating static if expression"); - if (!global.gag) - inc = 2; // so we don't see the error message again - return 0; - } - - if (!sc) - { - error(loc, "static if conditional cannot be at global scope"); - inc = 2; - return 0; - } - - ++nest; - sc = sc->push(sc->scopesym); - sc->sd = s; // s gets any addMember() - sc->flags |= SCOPEstaticif; - Expression *e = exp->semantic(sc); - sc->pop(); - if (!e->type->checkBoolean()) - { - if (e->type->toBasetype() != Type::terror) - exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars()); - inc = 0; - return 0; - } - e = e->ctfeInterpret(); - --nest; - if (e->op == TOKerror) - { exp = e; - inc = 0; - } - else 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[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[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/dmd/cond.h b/dmd/cond.h deleted file mode 100644 index 71400314..00000000 --- a/dmd/cond.h +++ /dev/null @@ -1,106 +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. - -#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; - int nest; // limit circular dependencies - - 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/dmd/constfold.c b/dmd/constfold.c deleted file mode 100644 index e630ba1c..00000000 --- a/dmd/constfold.c +++ /dev/null @@ -1,1787 +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 // mem{cpy|set|cmp}() -#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" - -#ifdef IN_GCC -#include "d-gcc-real.h" - -/* %% fix? */ -extern "C" bool real_isnan (const real_t *); -#endif - -static real_t zero; // work around DMC bug for now - -#define LOG 0 - -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 *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 - { - 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; - - 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 (type->equals(e1->type) && to->equals(type)) - return 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[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)[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)[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)[i]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2); - if (ex == EXP_CANT_INTERPRET) - return ex; - if (ex->isBool(TRUE)) - { e = (*ae->values)[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)[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)[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)[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); -} - -/* Compare a string slice with another string slice. - * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len]) - */ -int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len) -{ - unsigned char *s1 = (unsigned char *)se1->string; - unsigned char *s2 = (unsigned char *)se2->string; - size_t sz = se1->sz; - assert(sz == se2->sz); - - return memcmp(s1 + sz * lo1, s2 + sz * lo2, sz * len); -} - -/* Compare a string slice with an array literal slice - * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len]) - */ -int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len) -{ - unsigned char *s = (unsigned char *)se1->string; - size_t sz = se1->sz; - - int c = 0; - - for (size_t j = 0; j < len; j++) - { - unsigned value = (unsigned)((*ae2->elements)[j + lo2]->toInteger()); - unsigned svalue; - switch (sz) - { - case 1: svalue = s[j + lo1]; break; - case 2: svalue = ((unsigned short *)s)[j+lo1]; break; - case 4: svalue = ((unsigned *)s)[j + lo1]; break; - default: - assert(0); - } - int c = svalue - value; - if (c) - return c; - } - return 0; -} - -/* 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)[i] = (*ea->elements)[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)[es->len + i] = (*ea->elements)[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 && - e1->type->equals(e2->type)) - { - // Concatenate the arrays - ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); - es1->elements->insert(es1->elements->dim, es2->elements); - e = es1; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(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/dmd/declaration.c b/dmd/declaration.c deleted file mode 100644 index 2075e4c7..00000000 --- a/dmd/declaration.c +++ /dev/null @@ -1,1880 +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 "init.h" -#include "declaration.h" -#include "attrib.h" -#include "mtype.h" -#include "template.h" -#include "scope.h" -#include "aggregate.h" -#include "module.h" -#include "id.h" -#include "expression.h" -#include "hdrgen.h" - -/********************************* Declaration ****************************/ - -Declaration::Declaration(Identifier *id) - : Dsymbol(id) -{ - type = NULL; - originalType = NULL; - storage_class = STCundefined; - protection = PROTundefined; - linkage = LINKdefault; - inuse = 0; -} - -void Declaration::semantic(Scope *sc) -{ -} - -const char *Declaration::kind() -{ - return "declaration"; -} - -unsigned Declaration::size(Loc loc) -{ - assert(type); - return type->size(); -} - -int Declaration::isStaticConstructor() -{ - return FALSE; -} - -int Declaration::isStaticDestructor() -{ - return FALSE; -} - -int Declaration::isDelete() -{ - return FALSE; -} - -int Declaration::isDataseg() -{ - return FALSE; -} - -int Declaration::isThreadlocal() -{ - return FALSE; -} - -int Declaration::isCodeseg() -{ - return FALSE; -} - -enum PROT Declaration::prot() -{ - return protection; -} - -/************************************* - * Check to see if declaration can be modified in this context (sc). - * Issue error if not. - */ - -#if DMDV2 - -void Declaration::checkModify(Loc loc, Scope *sc, Type *t) -{ - if (sc->incontract && isParameter()) - error(loc, "cannot modify parameter '%s' in contract", toChars()); - - if (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)[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)[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(STCin, t, NULL, NULL); -#endif - (*args)[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)[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - if (e->op == TOKdsymbol) - { DsymbolExp *ve = (DsymbolExp *)e; - Declaration *d = ve->s->isDeclaration(); - if (d && d->needThis()) - { - return 1; - } - } - } - } - return 0; -} - -/********************************* TypedefDeclaration ****************************/ - -TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) - : Declaration(id) -{ - this->type = new TypeTypedef(this); - this->basetype = basetype->toBasetype(); - this->init = init; - this->htype = NULL; - this->hbasetype = NULL; - this->sem = 0; - this->loc = loc; -#if IN_DMD - this->sinit = NULL; -#endif -} - -Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) -{ - Type *basetype = this->basetype->syntaxCopy(); - - Initializer *init = NULL; - if (this->init) - init = this->init->syntaxCopy(); - - assert(!s); - TypedefDeclaration *st; - st = new TypedefDeclaration(loc, ident, basetype, init); - - // 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, INITinterpret); - 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 - if (e->op == TOKvar) - { s = ((VarExp *)e)->var; - goto L2; - } - else if (e->op == TOKfunction) - { s = ((FuncExp *)e)->fd; - goto L2; - } - else - { if (e->op != TOKerror) - error("cannot alias an expression %s", e->toChars()); - t = e->type; - } - } - else if (t) - { - type = t->semantic(loc, sc); - - /* If type is class or struct, convert to symbol. - * See bugzilla 6475. - */ - s = type->toDsymbol(sc); - if (s -#if DMDV2 - && ((s->getType() && type->equals(s->getType())) || s->isEnumMember()) -#endif - ) - goto L2; - - //printf("\talias resolved to type %s\n", type->toChars()); - } - if (overnext) - ScopeDsymbol::multiplyDefined(0, this, overnext); - this->inSemantic = 0; - - if (global.gag && 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); - fa->importprot = importprot; - 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 (global.gag && errors != global.errors) - { - type = savedtype; - overnext = savedovernext; - aliassym = NULL; - inSemantic = 0; - return; - } - } - if (!type || type->ty != Terror) - { //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() -{ - //printf("AliasDeclaration::getType() %s\n", type->toChars()); -#if 0 - if (!type->deco && scope) - semantic(scope); - if (type && !type->deco) - error("forward reference to alias %s\n", toChars()); -#endif - 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 == 75) exit(0); //*(char*)0=0; - if (inSemantic) - { error("recursive alias declaration"); - aliassym = new AliasDeclaration(loc, ident, Type::terror); - type = Type::terror; - } - else if (aliassym || type->deco) - ; // semantic is already done. - else if (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) - { -#if !IN_LLVM - haliassym->toCBuffer(buf, hgs); -#else - buf->writestring(haliassym->toChars()); -#endif - 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 - alignment = 0; - 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%x\n", storage_class); - printf("linkage = %d\n", sc->linkage); - //if (strcmp(toChars(), "mul") == 0) halt(); -#endif - - if (scope) - { sc = scope; - scope = NULL; - } - - storage_class |= sc->stc; - 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++; - type = init->inferType(sc); - type = type->semantic(loc, sc); - inuse--; - inferred = 1; - - /* This is a kludge to support the existing syntax for RAII - * declarations. - */ - storage_class &= ~STCauto; - originalType = type; - } - else - { if (!originalType) - originalType = type; - type = type->semantic(loc, sc); - } - //printf(" semantic type = %s\n", type ? type->toChars() : "null"); - - type->checkDeprecated(loc, sc); - linkage = sc->linkage; - this->parent = sc->parent; - //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); - protection = sc->protection; - //printf("sc->stc = %x\n", sc->stc); - //printf("storage_class = x%x\n", storage_class); - -#if DMDV2 - // 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; - - for (size_t i = 0; i < nelems; i++) - { Parameter *arg = Parameter::getNth(tt->arguments, i); - - OutBuffer buf; - buf.printf("_%s_field_%zu", ident->toChars(), i); - buf.writeByte(0); - const char *name = (const char *)buf.extractData(); - Identifier *id = Lexer::idPool(name); - - Expression *einit = ie; - if (ie && ie->op == TOKtuple) - { einit = (Expression *)((TupleExp *)ie)->exps->data[i]; - } - Initializer *ti = init; - if (einit) - { ti = new ExpInitializer(einit->loc, einit); - } - - VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); - //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); - v->semantic(sc); - -#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->data[i] = e; - } - TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); - v2->isexp = 1; - aliassym = v2; - return; - } - - if (storage_class & STCconst && !init && !fd) - // Initialize by constructor only - storage_class = (storage_class & ~STCconst) | STCctorinit; - - if (isConst()) - { - } - else if (isStatic()) - { - } - else 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 & STCtemplateparameter) - { - } - else if (storage_class & STCctfe) - { - } - else - { - AggregateDeclaration *aad = parent->isAggregateDeclaration(); - if (aad) - { -#if DMDV2 - assert(!(storage_class & (STCextern | STCstatic | STCtls | STCgshared))); - - if (storage_class & (STCconst | STCimmutable) && init) - { - if (!type->toBasetype()->isTypeBasic()) - storage_class |= STCstatic; - } - else -#endif - { - storage_class |= STCfield; - alignment = sc->structalign; -#if DMDV2 - if (tb->ty == Tstruct && ((TypeStruct *)tb)->sym->noDefaultCtor || - tb->ty == Tclass && ((TypeClass *)tb)->sym->noDefaultCtor) - aad->noDefaultCtor = TRUE; -#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"); - } -#endif - - if (type->isscope() && !noscope) - { - if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd) - { - error("globals, statics, fields, ref and out parameters cannot be auto"); - } - - if (!(storage_class & STCscope)) - { - if (!(storage_class & STCparameter) && ident != Id::withSym) - error("reference to scope class must be scope"); - } - } - - enum TOK op = TOKconstruct; - if (!init && !sc->inunion && !isStatic() && !isConst() && fd && - !(storage_class & (STCfield | STCin | STCforeach)) && - type->size() != 0) - { - // Provide a default initializer - //printf("Providing default initializer for '%s'\n", toChars()); - if (type->ty == Tstruct && - ((TypeStruct *)type)->sym->zeroInit == 1) - { /* If a struct is all zeros, as a special case - * set it's initializer to the integer 0. - * In AssignExp::toElem(), we check for this and issue - * a memset() to initialize the struct. - * Must do same check in interpreter. - */ - Expression *e = new IntegerExp(loc, 0, Type::tint32); - Expression *e1; - e1 = new VarExp(loc, this); - e = new AssignExp(loc, e1, e); - e->op = TOKconstruct; - e->type = e1->type; // don't type check this, it would fail - init = new ExpInitializer(loc, e); - return; - } - else if (type->ty == Ttypedef) - { TypeTypedef *td = (TypeTypedef *)type; - if (td->sym->init) - { init = td->sym->init; - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - // Make copy so we can modify it - init = new ExpInitializer(ie->loc, ie->exp); - } - else - init = getExpInitializer(); - } - else - { - init = getExpInitializer(); - } - // Default initializer is always a blit - op = TOKblit; - } - - if (init) - { - sc = sc->push(); - sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCref); - - ArrayInitializer *ai = init->isArrayInitializer(); - if (ai && tb->ty == Taarray) - { - init = ai->toAssocArrayInitializer(); - } - - StructInitializer *si = init->isStructInitializer(); - ExpInitializer *ei = init->isExpInitializer(); - - // See if initializer is a NewExp that can be allocated on the stack - if (ei && isScope() && ei->exp->op == TOKnew) - { NewExp *ne = (NewExp *)ei->exp; - if (!(ne->newargs && ne->newargs->dim)) - { ne->onstack = 1; - onstack = 1; - if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) - onstack = 2; - } - } - - // If inside function, there is no semantic3() call - if (sc->func) - { - // If local variable, use AssignExp to handle all the various - // possibilities. - if (fd && !isStatic() && !isConst() && !init->isVoidInitializer()) - { - //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); - if (!ei) - { - Expression *e = init->toExpression(); - if (!e) - { - init = init->semantic(sc, type, INITnointerpret); - e = init->toExpression(); - if (!e) - { error("is not a static and cannot have static initializer"); - return; - } - } - ei = new ExpInitializer(init->loc, e); - init = ei; - } - - Expression *e1 = new VarExp(loc, this); - - Type *t = type->toBasetype(); - if (t->ty == Tsarray && !(storage_class & (STCref | STCout))) - { - ei->exp = ei->exp->semantic(sc); - if (!ei->exp->implicitConvTo(type)) - { - 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 - /* Look to see if initializer is a call to the constructor - */ - if (sd->ctor && // there are constructors - ei->exp->type->ty == Tstruct && // rvalue is the same struct - ((TypeStruct *)ei->exp->type)->sym == sd && - ei->exp->op == TOKstar) - { - /* Look for form of constructor call which is: - * *__ctmp.ctor(arguments...) - */ - PtrExp *pe = (PtrExp *)ei->exp; - if (pe->e1->op == TOKcall) - { CallExp *ce = (CallExp *)pe->e1; - if (ce->e1->op == TOKdotvar) - { DotVarExp *dve = (DotVarExp *)ce->e1; - if (dve->var->isCtorDeclaration()) - { /* It's a constructor call, currently constructing - * a temporary __ctmp. - */ - /* Before calling the constructor, initialize - * variable with a bit copy of the default - * initializer - */ - Expression *e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); - e->op = TOKblit; - e->type = t; - ei->exp = new CommaExp(loc, e, ei->exp); - - /* Replace __ctmp being constructed with e1 - */ - dve->e1 = e1; - return; - } - } - } - } -#endif - if (!ei->exp->implicitConvTo(type)) - { - /* Look for opCall - * See bugzilla 2702 for more discussion - */ - Type *ti = ei->exp->type->toBasetype(); - // 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 = TOKconstruct; - canassign++; - ei->exp = ei->exp->semantic(sc); - canassign--; - ei->exp->optimize(WANTvalue); - } - else - { - init = init->semantic(sc, type, INITinterpret); - if (fd && isConst() && !isStatic()) - { // Make it static - storage_class |= STCstatic; - } - } - } - else if (isConst() || isFinal() || - 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 = e->implicitCastTo(sc, type); - } - else if (si || ai) - { i2 = init->syntaxCopy(); - i2 = i2->semantic(sc, type, INITinterpret); - } - 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->ctfeInterpret(); - 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(); - } -} - -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; -} - -void VarDeclaration::semantic2(Scope *sc) -{ - //printf("VarDeclaration::semantic2('%s')\n", toChars()); - // Inside unions, default to void initializers - if (!init && sc->inunion && !toParent()->isFuncDeclaration()) - { - AggregateDeclaration *aad = parent->isAggregateDeclaration(); - if (aad) - { - if (aad->fields[0] == this) - { - int hasinit = 0; - for (size_t i = 1; i < aad->fields.dim; i++) - { - if (aad->fields[i]->init && - !aad->fields[i]->init->isVoidInitializer()) - { - hasinit = 1; - break; - } - } - if (!hasinit) - init = new ExpInitializer(loc, type->defaultInitLiteral(loc)); - } - else - init = new VoidInitializer(loc); - } - } - 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, INITinterpret); - inuse--; - } -} - -void VarDeclaration::semantic3(Scope *sc) -{ - // LDC - if (!global.params.useAvailableExternally) - availableExternally = false; - - // Preserve call chain - Declaration::semantic3(sc); -} - -void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad->toChars(), toChars()); - - if (aliassym) - { // If this variable was really a tuple, set the offsets for the tuple fields - TupleDeclaration *v2 = aliassym->isTupleDeclaration(); - assert(v2); - for (size_t i = 0; i < v2->objects->dim; i++) - { Object *o = (*v2->objects)[i]; - assert(o->dyncast() == DYNCAST_EXPRESSION); - Expression *e = (Expression *)o; - assert(e->op == TOKdsymbol); - DsymbolExp *se = (DsymbolExp *)e; - se->s->setFieldOffset(ad, poffset, isunion); - } - return; - } - - if (!(storage_class & STCfield)) - return; - assert(!(storage_class & (STCstatic | STCextern | STCparameter | STCtls))); - - /* Fields that are tuples appear both as part of TupleDeclarations and - * as members. That means ignore them if they are already a field. - */ - if (offset) - return; // already a field - for (size_t i = 0; i < ad->fields.dim; i++) - { - if (ad->fields[i] == this) - return; // already a field - } - - // Check for forward referenced types which will fail the size() call - Type *t = type->toBasetype(); - if (storage_class & STCref) - { // References are the size of a pointer - t = Type::tvoidptr; - } - if (t->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)t; -#if DMDV2 - if (ts->sym == ad) - { - ad->error("cannot have field %s with same struct type", toChars()); - } -#endif - - if (ts->sym->sizeok != SIZEOKdone && ts->sym->scope) - ts->sym->semantic(NULL); - if (ts->sym->sizeok != SIZEOKdone) - { - ad->sizeok = SIZEOKfwd; // cannot finish; flag as forward referenced - return; - } - } - if (t->ty == Tident) - { - ad->sizeok = SIZEOKfwd; // cannot finish; flag as forward referenced - return; - } - - unsigned memsize = t->size(loc); // size of member - unsigned memalignsize = t->alignsize(); // size of member for alignment purposes - structalign_t memalign = t->memalign(alignment); // alignment boundaries - - offset = AggregateDeclaration::placeField(poffset, memsize, memalignsize, memalign, - &ad->structsize, &ad->alignsize, isunion); - - //printf("\t%s: alignsize = %d\n", toChars(), alignsize); - - //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad->toChars(), offset, memsize); - ad->fields.push(this); -} - -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)) && 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 && (isStatic() || isConst() || parent->isModule())) - return TRUE; - return FALSE; -} - -void VarDeclaration::checkCtorConstInit() -{ - if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield)) - error("missing initializer in static constructor for const variable"); -} - -/************************************ - * Check to see if this variable is actually in an enclosing function - * rather than the current one. - */ - -void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) -{ - //printf("VarDeclaration::checkNestedReference() %s\n", toChars()); - if (parent && !isDataseg() && parent != sc->parent) - { - // The function that this variable is in - FuncDeclaration *fdv = toParent()->isFuncDeclaration(); - // The current function - FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); - - if (fdv && fdthis && fdv != fdthis) - { - nestedref = 1; -#if !IN_LLVM - // In LDC (D1), __ensure is actually just treated like a normal - // nested function, we don't use the magic stack layout hack like - // DMD (see DMD Bugzilla 7932 for why this was added). - if (fdthis->ident != Id::ensure) -#endif - { - /* __ensure is always called directly, - * so it never becomes closure. - */ - - if (loc.filename) - fdthis->getLevel(loc, fdv); - fdv->nestedFrameRef = 1; -#if IN_LLVM -#if DMDV1 - fdv->nestedVars.insert(this); -#endif -#endif - //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"); - } - } - } -} - -/******************************* - * Does symbol go into data segment? - * Includes extern variables. - */ - -int VarDeclaration::isDataseg() -{ -#if 0 - printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); - printf("%llx, %p, %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance()); - printf("parent = '%s'\n", parent->toChars()); -#endif - Dsymbol *parent = this->toParent(); - if (!parent && !(storage_class & (STCstatic | STCconst))) - { error("forward referenced"); - type = Type::terror; - return 0; - } - return (storage_class & (STCstatic | STCconst) || - parent->isModule() || - parent->isTemplateInstance()); -} - -/************************************ - * Does symbol go into thread local storage? - */ - -int VarDeclaration::isThreadlocal() -{ - return 0; -} - -/******************************************** - * Can variable be read and written by CTFE? - */ - -int VarDeclaration::isCTFE() -{ - //printf("VarDeclaration::isCTFE(%p, '%s')\n", this, toChars()); - //printf("%llx\n", storage_class); - return (storage_class & STCctfe) != 0; // || !isDataseg(); -} - -int VarDeclaration::hasPointers() -{ - //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty); - return (!isDataseg() && type->hasPointers()); -} - -int VarDeclaration::isSameAsInitializer() -{ - if (init && init->isExpInitializer() && - init->isExpInitializer()->exp->op == TOKstructliteral) - return 0; - return isConst(); -} - -/****************************************** - * If a variable has a scope destructor call, return call for it. - * Otherwise, return NULL. - */ - -Expression *VarDeclaration::callScopeDtor(Scope *sc) -{ Expression *e = NULL; - - //printf("VarDeclaration::callScopeDtor() %s\n", toChars()); - if (storage_class & (STCauto | STCscope) && !noscope) - { - 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; -} - -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; -} - -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; - protection = PROTpublic; - linkage = LINKc; -} - -Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void TypeInfoDeclaration::semantic(Scope *sc) -{ - assert(linkage == LINKc); -#if IN_LLVM - if (!global.params.useAvailableExternally) - availableExternally = false; -#endif -} - -/***************************** TypeInfoConstDeclaration **********************/ - -#if DMDV2 -TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoInvariantDeclaration **********************/ - -#if DMDV2 -TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoSharedDeclaration **********************/ - -#if DMDV2 -TypeInfoSharedDeclaration::TypeInfoSharedDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoStructDeclaration **********************/ - -TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoClassDeclaration ***********************/ - -TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoInterfaceDeclaration *******************/ - -TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoTypedefDeclaration *********************/ - -TypeInfoTypedefDeclaration::TypeInfoTypedefDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoPointerDeclaration *********************/ - -TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoArrayDeclaration ***********************/ - -TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoStaticArrayDeclaration *****************/ - -TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoAssociativeArrayDeclaration ************/ - -TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoEnumDeclaration ***********************/ - -TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoFunctionDeclaration ********************/ - -TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoDelegateDeclaration ********************/ - -TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoTupleDeclaration **********************/ - -TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/********************************* ThisDeclaration ****************************/ - -// For the "this" parameter to member functions - -ThisDeclaration::ThisDeclaration(Loc loc, Type *t) - : VarDeclaration(loc, t, Id::This, NULL) -{ - 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/dmd/declaration.h b/dmd/declaration.h deleted file mode 100644 index ba3a79a7..00000000 --- a/dmd/declaration.h +++ /dev/null @@ -1,1088 +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. - -#ifndef DMD_DECLARATION_H -#define DMD_DECLARATION_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#if IN_LLVM -#include -#include -#include -#if LDC_LLVM_VER >= 302 -#include "llvm/DebugInfo.h" -#else -#include "llvm/Analysis/DebugInfo.h" -#endif -#endif - -#include "dsymbol.h" -#include "lexer.h" -#include "mtype.h" - -struct Expression; -struct Statement; -struct LabelDsymbol; -struct LabelStatement; -struct Initializer; -struct Module; -struct InlineScanState; -struct ForeachStatement; -struct FuncDeclaration; -struct ExpInitializer; -struct StructDeclaration; -struct TupleType; -struct InterState; -struct IRState; -struct AnonDeclaration; - -enum PROT; -enum LINK; -enum TOK; -enum MATCH; - -enum STC -{ - STCundefined = 0, - STCstatic = 1, - STCextern = 2, - STCconst = 4, - STCfinal = 8, - STCabstract = 0x10, - STCparameter = 0x20, - STCfield = 0x40, - STCoverride = 0x80, - STCauto = 0x100, - STCsynchronized = 0x200, - STCdeprecated = 0x400, - STCin = 0x800, // in parameter - STCout = 0x1000, // out parameter - STClazy = 0x2000, // lazy parameter - STCforeach = 0x4000, // variable for foreach loop - STCcomdat = 0x8000, // should go into COMDAT record - STCvariadic = 0x10000, // variadic function argument - STCctorinit = 0x20000, // can only be set inside constructor - STCtemplateparameter = 0x40000, // template parameter - STCscope = 0x80000, // template parameter - STCimmutable = 0x100000, - STCref = 0x200000, - STCinit = 0x400000, // has explicit initializer - STCmanifest = 0x800000, // manifest constant - STCnodtor = 0x1000000, // don't run destructor - STCnothrow = 0x2000000, // never throws exceptions - STCpure = 0x4000000, // pure function - STCtls = 0x8000000, // thread local - STCalias = 0x10000000, // alias parameter - STCshared = 0x20000000, // accessible from multiple threads - STCgshared = 0x40000000, // accessible from multiple threads - // but not typed as "shared" - STCwild = 0x80000000, // for "wild" type constructor - STC_TYPECTOR = (STCconst | STCimmutable | STCshared | STCwild), -}; - -#define STCproperty 0x100000000LL -#define STCsafe 0x200000000LL -#define STCtrusted 0x400000000LL -#define STCsystem 0x800000000LL -#define STCctfe 0x1000000000LL // can be used in CTFE, even if it is static -#define STCdisable 0x2000000000LL // for functions that are not callable -#define STCresult 0x4000000000LL // for result variables passed to out contracts - -struct Match -{ - int count; // number of matches found - MATCH last; // match level of lastf - FuncDeclaration *lastf; // last matching function we found - FuncDeclaration *nextf; // current matching function - FuncDeclaration *anyf; // pick a func, any func, to use for error recovery -}; - -void overloadResolveX(Match *m, FuncDeclaration *f, - Expression *ethis, Expressions *arguments, Module *from); -int overloadApply(Module* from, FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param); - -enum Semantic -{ - SemanticStart, // semantic has not been run - SemanticIn, // semantic() is in progress - SemanticDone, // semantic() has been run - Semantic2Done, // semantic2() has been run -}; - -/**************************************************************/ - -struct Declaration : Dsymbol -{ - Type *type; - Type *originalType; // before semantic analysis - StorageClass storage_class; - enum PROT protection; - enum LINK linkage; - int inuse; // used to detect cycles - - 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 isStaticConstructor(); - virtual int isStaticDestructor(); - virtual int isDelete(); - virtual int isDataseg(); - virtual int isThreadlocal(); - virtual int isCodeseg(); - int isCtorinit() { return storage_class & STCctorinit; } - int isFinal() { return storage_class & STCfinal; } - int isAbstract() { return storage_class & STCabstract; } - int isConst() { return storage_class & STCconst; } - int isImmutable() { return storage_class & STCimmutable; } - int isAuto() { return storage_class & STCauto; } - int isScope() { return storage_class & STCscope; } - int isSynchronized() { return storage_class & STCsynchronized; } - int isParameter() { return storage_class & STCparameter; } - int isDeprecated() { return storage_class & STCdeprecated; } - int isOverride() { return storage_class & STCoverride; } - - virtual int isSameAsInitializer() { return isConst(); }; - - int isIn() { return storage_class & STCin; } - int isOut() { return storage_class & STCout; } - int isRef() { return storage_class & STCref; } - - enum PROT prot(); - - Declaration *isDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct TupleDeclaration : Declaration -{ - Objects *objects; - int isexp; // 1: expression tuple - - TypeTuple *tupletype; // !=NULL if this is a type tuple - - TupleDeclaration(Loc loc, Identifier *ident, Objects *objects); - Dsymbol *syntaxCopy(Dsymbol *); - const char *kind(); - Type *getType(); - int needThis(); - - TupleDeclaration *isTupleDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct TypedefDeclaration : Declaration -{ - Type *basetype; - Initializer *init; - int sem; // 0: semantic() has not been run - // 1: semantic() is in progress - // 2: semantic() has been run - // 3: semantic2() has been run - - TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - char *mangle(); - const char *kind(); - Type *getType(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - 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 - structalign_t alignment; - 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 setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - 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(); - - virtual int isSameAsInitializer(); - -#if IN_DMD - Symbol *toSymbol(); - void toObjFile(int multiobj); // compile to .obj file - 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 - Symbol *toSymbol(); - void toObjFile(int multiobj); // compile to .obj file - virtual void toDt(dt_t **pdt); -#endif - - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); - virtual void llvmDefine(); -#endif -}; - -struct TypeInfoStructDeclaration : TypeInfoDeclaration -{ - TypeInfoStructDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoClassDeclaration : TypeInfoDeclaration -{ - TypeInfoClassDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration -{ - TypeInfoInterfaceDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoTypedefDeclaration : TypeInfoDeclaration -{ - TypeInfoTypedefDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoPointerDeclaration : TypeInfoDeclaration -{ - TypeInfoPointerDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoStaticArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoAssociativeArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoEnumDeclaration : TypeInfoDeclaration -{ - TypeInfoEnumDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoFunctionDeclaration : TypeInfoDeclaration -{ - TypeInfoFunctionDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoDelegateDeclaration : TypeInfoDeclaration -{ - TypeInfoDelegateDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoTupleDeclaration : TypeInfoDeclaration -{ - TypeInfoTupleDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -#if DMDV2 -struct TypeInfoConstDeclaration : TypeInfoDeclaration -{ - TypeInfoConstDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoInvariantDeclaration : TypeInfoDeclaration -{ - TypeInfoInvariantDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoSharedDeclaration : TypeInfoDeclaration -{ - TypeInfoSharedDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); -}; - -struct TypeInfoWildDeclaration : TypeInfoDeclaration -{ - TypeInfoWildDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); -}; -#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 - - Identifier *outId; // identifier for out statement - VarDeclaration *vresult; // variable corresponding to outId - LabelDsymbol *returnLabel; // where the return goes - Scope *scout; // out contract scope for vresult->semantic - - 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 - int inlineAsm; // !=0 if has inline assembler - ILS inlineStatusStmt; - ILS inlineStatusExp; - int inlineNest; // !=0 if nested inline - int isArrayOp; // !=0 if array operation - int semanticRun; // 1 semantic() run - // 2 semantic2() run - // 3 semantic3() started - // 4 semantic3() done - // 5 toObjFile() run - // this function's frame ptr - int semantic3Errors; // !=0 if errors in semantic3 - ForeachStatement *fes; // if foreach body, this is the foreach - int introducing; // !=0 if 'introducing' function - Type *tintro; // if !=NULL, then this is the type - // of the 'introducing' function - // this one is overriding - int inferRetType; // !=0 if return type is to be inferred - - // Things that should really go into Scope - int hasReturnExp; // 1 if there's a return exp; statement - // 2 if there's a throw statement - // 4 if there's an assert(0) - // 8 if there's inline asm - - // Support for NRVO (named return value optimization) - int nrvo_can; // !=0 means we can do it - VarDeclaration *nrvo_var; // variable to replace with shidden -#if IN_DMD - Symbol *shidden; // hidden pointer passed to function -#endif - -#if DMDV2 - enum BUILTIN builtin; // set if this is a known, builtin - // function we can evaluate at compile - // time - - int tookAddressOf; // set if someone took the address of - // this function - 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 *&); - - 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, Module *from, int flags = 0); - MATCH leastAsSpecialized(FuncDeclaration *g); - LabelDsymbol *searchLabel(Identifier *ident); - AggregateDeclaration *isThis(); - AggregateDeclaration *isMember2(); - int getLevel(Loc loc, FuncDeclaration *fd); // lexical nesting level difference - void appendExp(Expression *e); - void appendState(Statement *s); - char *mangle(); - const char *toPrettyChars(); - int isMain(); - int isWinMain(); - int isDllMain(); - enum BUILTIN isBuiltin(); - int isExport(); - int isImportedSymbol(); - int isAbstract(); - int isCodeseg(); - int isOverloadable(); - int hasOverloads(); - int isPure(); - int isSafe(); - int isTrusted(); - 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(); - int needsClosure(); - int hasNestedFrameRefs(); - void buildResultVar(); - Statement *mergeFrequire(Statement *); - Statement *mergeFensure(Statement *); - Parameters *getParameters(int *pvarargs); - -// LDC: give argument types to runtime functions - static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name); - static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id); - -#if IN_DMD - Symbol *toSymbol(); - Symbol *toThunkSymbol(int offset); // thunk version - void toObjFile(int multiobj); // compile to .obj file - int cvMember(unsigned char *p); - void buildClosure(IRState *irs); -#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; - uint32_t priority; - - 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; -#endif -}; - -#if DMDV2 -FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, - Objects *tiargs, - Expression *ethis, - Expressions *arguments, - int flags); -#endif - -struct FuncAliasDeclaration : FuncDeclaration -{ - FuncDeclaration *funcalias; - PROT importprot; // if generated by import, store its protection - - FuncAliasDeclaration(FuncDeclaration *funcalias); - - FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } - const char *kind(); -#if IN_DMD - Symbol *toSymbol(); -#endif -}; - -struct FuncLiteralDeclaration : FuncDeclaration -{ - enum TOK tok; // TOKfunction or TOKdelegate - - FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok, - ForeachStatement *fes); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Dsymbol *syntaxCopy(Dsymbol *); - int isNested(); - int isVirtual(); - - FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } - const char *kind(); -}; - -struct CtorDeclaration : FuncDeclaration -{ Parameters *arguments; - int varargs; - - CtorDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void toDocBuffer(OutBuffer *buf); - - CtorDeclaration *isCtorDeclaration() { return this; } -}; - -#if DMDV2 -struct PostBlitDeclaration : FuncDeclaration -{ - PostBlitDeclaration(Loc loc, Loc endloc); - PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - - PostBlitDeclaration *isPostBlitDeclaration() { return this; } -}; -#endif - -struct DtorDeclaration : FuncDeclaration -{ - DtorDeclaration(Loc loc, Loc endloc); - DtorDeclaration(Loc loc, Loc endloc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - - DtorDeclaration *isDtorDeclaration() { return this; } -}; - -struct StaticCtorDeclaration : FuncDeclaration -{ - StaticCtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isStaticConstructor(); - 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); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isStaticDestructor(); - 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/dmd/delegatize.c b/dmd/delegatize.c deleted file mode 100644 index a4d37152..00000000 --- a/dmd/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/dmd/doc.c b/dmd/doc.c deleted file mode 100644 index a616b84f..00000000 --- a/dmd/doc.c +++ /dev/null @@ -1,2230 +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" - -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ -#include "gnuc.h" -#endif - -#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() : - summary(NULL), copyright(NULL), macros(NULL), pmacrotable(NULL), pescapetable(NULL) - { } - - 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/1.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)[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 *srcfilename = srcfile->toChars(); - Macro::define(¯otable, (unsigned char *)"SRCFILENAME", 11, (unsigned char *)srcfilename, strlen(srcfilename)); - - 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::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/dmd/doc.h b/dmd/doc.h deleted file mode 100644 index ffa97fb9..00000000 --- a/dmd/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/dmd/dsymbol.c b/dmd/dsymbol.c deleted file mode 100644 index 6b60124f..00000000 --- a/dmd/dsymbol.c +++ /dev/null @@ -1,1314 +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 "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; - this->errors = false; -#if IN_LLVM - this->llvmInternal = LLVMnone; -#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; - this->errors = false; -#if IN_LLVM - this->llvmInternal = LLVMnone; -#endif -} - -int Dsymbol::equals(Object *o) -{ Dsymbol *s; - - if (this == o) - return TRUE; - s = (Dsymbol *)(o); - if (s && 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) -{ - //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) -{ - //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); - //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); - if (!x) - { - //printf("\tfalse 1\n"); - assert(*ps == NULL); - return FALSE; - } - if (*ps) - { - if (s) // more than one symbol - { *ps = NULL; - //printf("\tfalse 2\n"); - return FALSE; - } - s = *ps; - } - } - } - *ps = s; // s is the one symbol, NULL if none - //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; -} - -void Dsymbol::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ -} - -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; -} - -// 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 *Dsymbol::isSpeculative() -{ - Dsymbol * par = parent; - while (par) - { - TemplateInstance *ti = par->isTemplateInstance(); - if (ti && ti->speculative) - return ti; - par = par->toParent(); - } - 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) -{ - /* 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); - - Dsymbol *s = (Dsymbol *)arg; - Module::clearCache(); - return s->search(0, id, 4|2); -} - -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) - { - sm = s->search_correct(id); - if (sm) - error("template identifier '%s' is not a member of '%s %s', did you mean '%s %s'?", - id->toChars(), s->kind(), s->toChars(), sm->kind(), sm->toChars()); - else - 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; -} - -ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class? -{ - Dsymbol *parent = toParent(); - if (parent && parent->isClassDeclaration()) - return (ClassDeclaration *)parent; - return 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 - -int Dsymbol::hasOverloads() -{ - return 0; -} - -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::apply(Dsymbol_apply_ft_t fp, void *param) -{ - return (*fp)(this, param); -} - -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, kind(), toPrettyChars()); - va_end(ap); -} - -void Dsymbol::error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap, kind(), toPrettyChars()); - va_end(ap); -} - -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: - ; -} - -/********************************** - * 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 will be compiled in. - * This may be different from getModule for templates. - */ - -Module *Dsymbol::getCompilationModule() -{ - Module *m; - TemplateInstance *ti; - Dsymbol *s; - - //printf("Dsymbol::getModule()\n"); - s = this; - while (s) - { - //printf("\ts = '%s'\n", s->toChars()); - m = s->isModule(); - if (m) - return m; - ti = s->isTemplateInstance(); - if (ti && ti->tmodule) - return ti->tmodule; - 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) - { - // 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->isImport() ? 1 : 0); - if (!s) - s = s2; - else if (s2 && s != s2) - { - if (s->toAlias() == s2->toAlias()) - { - /* After following aliases, we found the same symbol, - * so it's not an ambiguity. - * But if one alias is deprecated, prefer the other. - */ - if (s->isDeprecated()) - s = s2; - } - else - { - /* Two imports of the same module should be regarded as - * the same. - */ - Import *i1 = s->isImport(); - Import *i2 = s2->isImport(); - if (!(i1 && i2 && - (i1->mod == i2->mod || - (!i1->parent->isImport() && !i2->parent->isImport() && - i1->ident->equals(i2->ident)) - ) - ) - ) - { - ScopeDsymbol::multiplyDefined(loc, s, s2); - break; - } - } - } - } - if (s) - { - Declaration *d = s->isDeclaration(); - if (d && d->protection == PROTprivate && - !d->parent->isTemplateMixin()) - 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(Expression *e) - : ScopeDsymbol() -{ - assert(e->op == TOKindex || e->op == TOKslice); - exp = e; - type = NULL; - td = NULL; -} - -ArrayScopeSymbol::ArrayScopeSymbol(TypeTuple *t) - : ScopeDsymbol() -{ - exp = NULL; - type = t; - td = NULL; -} - -ArrayScopeSymbol::ArrayScopeSymbol(TupleDeclaration *s) - : ScopeDsymbol() -{ - exp = NULL; - type = NULL; - td = s; -} - -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; - - 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 |= STCconst; - 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 |= STCconst; - 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 - /* 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 compile-time constant. - */ - Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= 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; - v->storage_class |= STCctfe; // it's never a true static variable - } - *pvar = v; - } - return (*pvar); - } - return NULL; -} - - -/****************************** DsymbolTable ******************************/ - -DsymbolTable::DsymbolTable() -{ - tab = NULL; -} - -DsymbolTable::~DsymbolTable() -{ -} - -Dsymbol *DsymbolTable::lookup(Identifier *ident) -{ - //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); - return (Dsymbol *)_aaGetRvalue(tab, ident); -} - -Dsymbol *DsymbolTable::insert(Dsymbol *s) -{ - //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); - Identifier *ident = s->ident; - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - if (*ps) - return NULL; // already in table - *ps = s; - return s; -} - -Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) -{ - //printf("DsymbolTable::insert()\n"); - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - if (*ps) - return NULL; // already in table - *ps = s; - return s; -} - -Dsymbol *DsymbolTable::update(Dsymbol *s) -{ - Identifier *ident = s->ident; - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - *ps = s; - return s; -} - - - - diff --git a/dmd/dsymbol.h b/dmd/dsymbol.h deleted file mode 100644 index 4c5a4538..00000000 --- a/dmd/dsymbol.h +++ /dev/null @@ -1,387 +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. - -#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 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 TypeInfoDeclaration; -struct ClassInfoDeclaration; -struct OverloadSet; -struct AA; -#if TARGET_NET -struct PragmaScope; -#endif -#if IN_GCC -union tree_node; -typedef union tree_node TYPE; -#else -struct TYPE; -#endif - -// Back end -struct Classsym; - -#if IN_LLVM -class Ir; -namespace llvm -{ - class Value; -} -#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 -}; - -typedef int (*Dsymbol_apply_ft_t)(Dsymbol *, void *); - -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() - bool errors; // this symbol failed to pass 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 checkDeprecated(Loc loc, Scope *sc); - Module *getModule(); // module where declared - Module *getCompilationModule(); // possibly different for templates - Dsymbol *pastMixin(); - Dsymbol *toParent(); - Dsymbol *toParent2(); - TemplateInstance *inTemplateInstance(); - TemplateInstance *isSpeculative(); - - 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 apply(Dsymbol_apply_ft_t fp, void *param); - 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 - virtual ClassDeclaration *isClassMember(); // are we a member of a class? - virtual int isExport(); // is Dsymbol exported? - virtual int isImportedSymbol(); // is Dsymbol imported? - virtual int isDeprecated(); // is Dsymbol deprecated? -#if DMDV2 - virtual int isOverloadable(); -#endif - virtual int hasOverloads(); - 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); - static int oneMembers(Dsymbols *members, Dsymbol **ps); - virtual void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - 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 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 SymbolDeclaration *isSymbolDeclaration() { return NULL; } - virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; } - virtual AttribDeclaration *isAttribDeclaration() { return NULL; } - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } - virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } - - virtual OverloadSet *isOverloadSet() { 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; -#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(Expression *e); - ArrayScopeSymbol(TypeTuple *t); - ArrayScopeSymbol(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/dmd/dump.c b/dmd/dump.c deleted file mode 100644 index d1468264..00000000 --- a/dmd/dump.c +++ /dev/null @@ -1,144 +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 - -#include "mars.h" -#include "mtype.h" -#include "declaration.h" -#include "expression.h" -#include "template.h" - -static void indent(int indent) -{ - int i; - - for (i = 0; i < indent; i++) - printf(" "); -} - -static char *type_print(Type *type) -{ - return type ? type->toChars() : (char *) "null"; -} - -void dumpExpressions(int i, Expressions *exps) -{ - for (size_t j = 0; j < exps->dim; j++) - { Expression *e = (Expression *)exps->data[j]; - indent(i); - printf("(\n"); - e->dump(i + 2); - indent(i); - printf(")\n"); - } -} - -void Expression::dump(int i) -{ - indent(i); - printf("%p %s type=%s\n", this, Token::toChars(op), type_print(type)); -} - -void IntegerExp::dump(int i) -{ - indent(i); - printf("%p %jd type=%s\n", this, (intmax_t)value, type_print(type)); -} - -void IdentifierExp::dump(int i) -{ - indent(i); - printf("%p ident '%s' type=%s\n", this, ident->toChars(), type_print(type)); -} - -void DsymbolExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s\n", this, s->toChars(), type_print(type)); -} - -void VarExp::dump(int i) -{ - indent(i); - printf("%p %s var=%s type=%s\n", this, Token::toChars(op), var->toChars(), type_print(type)); -} - -void UnaExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1); - if (e1) - e1->dump(i + 2); -} - -void CallExp::dump(int i) -{ - UnaExp::dump(i); - dumpExpressions(i, arguments); -} - -void SliceExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1); - if (e1) - e1->dump(i + 2); - if (lwr) - lwr->dump(i + 2); - if (upr) - upr->dump(i + 2); -} - -void DotIdExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s ident=%s e1=%p\n", this, Token::toChars(op), type_print(type), ident->toChars(), e1); - if (e1) - e1->dump(i + 2); -} - -void DotVarExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s var='%s' e1=%p\n", this, Token::toChars(op), type_print(type), var->toChars(), e1); - if (e1) - e1->dump(i + 2); -} - -void DotTemplateInstanceExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s ti='%s' e1=%p\n", this, Token::toChars(op), type_print(type), ti->toChars(), e1); - if (e1) - e1->dump(i + 2); -} - -void DelegateExp::dump(int i) -{ - indent(i); - printf("%p %s func=%s type=%s e1=%p\n", this, Token::toChars(op), func->toChars(), type_print(type), e1); - if (e1) - e1->dump(i + 2); -} - -void BinExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s e1=%p e2=%p\n", this, Token::toChars(op), type_print(type), e1, e2); - if (e1) - e1->dump(i + 2); - if (e2) - e2->dump(i + 2); -} - - diff --git a/dmd/entity.c b/dmd/entity.c deleted file mode 100644 index 98b81141..00000000 --- a/dmd/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/dmd/enum.c b/dmd/enum.c deleted file mode 100644 index 7c0c40bd..00000000 --- a/dmd/enum.c +++ /dev/null @@ -1,373 +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 "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 = 0; - minval = 0; - defaultval = 0; -#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 = ((Dsymbol *)members->data[i])->isEnumMember(); - if (em && em->value) - return; - } - - // Can do it - semantic(sc); -} - -void EnumDeclaration::semantic(Scope *sc) -{ - uinteger_t number; - Type *t; - Scope *sce; - - //printf("EnumDeclaration::semantic(sd = %p, '%s')\n", sc->scopesym, sc->scopesym->toChars()); - if (!memtype) - memtype = Type::tint32; - - 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->scopesym; - 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) - { - error("base enum %s is forward referenced", sym->toChars()); - memtype = Type::tint32; - } - } - - if (!memtype->isintegral()) - { error("base type must be of integral type, not %s", memtype->toChars()); - memtype = Type::tint32; - } - - isdone = 1; - Module::dprogress++; - - t = isAnonymous() ? memtype : type; - symtab = new DsymbolTable(); - sce = sc->push(this); - sce->parent = this; - number = 0; - if (!members) // enum ident; - return; - if (members->dim == 0) - error("enum %s must have at least one member", toChars()); - int first = 1; - for (size_t i = 0; i < members->dim; i++) - { - EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); - Expression *e; - - if (!em) - /* The e->semantic(sce) can insert other symbols, such as - * template instances and function literals. - */ - continue; - - //printf("Enum member '%s'\n",em->toChars()); - e = em->value; - if (e) - { - assert(e->dyncast() == DYNCAST_EXPRESSION); - e = e->semantic(sce); - e = e->optimize(WANTvalue); - // Need to copy it because we're going to change the type - e = e->copy(); - e = e->implicitCastTo(sc, memtype); - e = e->optimize(WANTvalue); - number = e->toInteger(); - e->type = t; - } - else - { // Default is the previous number plus 1 - - // Check for overflow - if (!first) - { - switch (t->toBasetype()->ty) - { - case Tbool: - if (number == 2) goto Loverflow; - break; - - case Tint8: - if (number == 128) goto Loverflow; - break; - - case Tchar: - case Tuns8: - if (number == 256) goto Loverflow; - break; - - case Tint16: - if (number == 0x8000) goto Loverflow; - break; - - case Twchar: - case Tuns16: - if (number == 0x10000) goto Loverflow; - break; - - case Tint32: - if (number == 0x80000000) goto Loverflow; - break; - - case Tdchar: - case Tuns32: - if (number == 0x100000000LL) goto Loverflow; - break; - - case Tint64: - if (number == 0x8000000000000000LL) goto Loverflow; - break; - - case Tuns64: - if (number == 0) goto Loverflow; - break; - - Loverflow: - error("overflow of enum value"); - break; - - default: - assert(0); - } - } - e = new IntegerExp(em->loc, number, t); - } - em->value = e; - - // Add to symbol table only after evaluating 'value' - if (isAnonymous()) - { - //sce->enclosing->insert(em); - for (Scope *sct = sce->enclosing; 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); - - if (first) - { first = 0; - defaultval = number; - minval = number; - maxval = number; - } - else if (memtype->isunsigned()) - { - if (number < minval) - minval = number; - if (number > maxval) - maxval = number; - } - else - { - if ((sinteger_t)number < (sinteger_t)minval) - minval = number; - if ((sinteger_t)number > (sinteger_t)maxval) - maxval = number; - } - - number++; - } - //printf("defaultval = %lld\n", defaultval); - - sce->pop(); - //members->print(); -} - -int EnumDeclaration::oneMember(Dsymbol **ps) -{ - if (isAnonymous()) - return Dsymbol::oneMembers(members, ps); - return Dsymbol::oneMember(ps); -} - -void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - 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 = ((Dsymbol *)members->data[i])->isEnumMember(); - if (!em) - continue; - //buf->writestring(" "); - em->toCBuffer(buf, hgs); - buf->writeByte(','); - buf->writenl(); - } - buf->writeByte('}'); - buf->writenl(); -} - -Type *EnumDeclaration::getType() -{ - return type; -} - -const char *EnumDeclaration::kind() -{ - return "enum"; -} - -int EnumDeclaration::isDeprecated() -{ - return isdeprecated; -} - -/********************************* EnumMember ****************************/ - -EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value) - : Dsymbol(id) -{ - this->value = value; - this->loc = loc; -} - -Dsymbol *EnumMember::syntaxCopy(Dsymbol *s) -{ - Expression *e = NULL; - if (value) - e = value->syntaxCopy(); - - EnumMember *em; - if (s) - { em = (EnumMember *)s; - em->loc = loc; - em->value = e; - } - else - em = new EnumMember(loc, ident, e); - return em; -} - -void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - if (value) - { - buf->writestring(" = "); - value->toCBuffer(buf, hgs); - } -} - -const char *EnumMember::kind() -{ - return "enum member"; -} - - diff --git a/dmd/enum.h b/dmd/enum.h deleted file mode 100644 index 439211d1..00000000 --- a/dmd/enum.h +++ /dev/null @@ -1,96 +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); - 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; - - EnumMember(Loc loc, Identifier *id, Expression *value); - 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/dmd/expression.c b/dmd/expression.c deleted file mode 100644 index f8ab2052..00000000 --- a/dmd/expression.c +++ /dev/null @@ -1,10664 +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 -#include -#if _MSC_VER -#include -#else -#include -#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" -#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" -#include "doc.h" - - -Expression *createTypeInfoArray(Scope *sc, Expression *args[], unsigned dim); -Expression *expandVar(int result, VarDeclaration *v); - -#define LOGSEMANTIC 0 - -/************************************************************* - * Given var, we need to get the - * right 'this' pointer if var is in an outer class, but our - * existing 'this' pointer is in an inner class. - * Input: - * e1 existing 'this' - * ad struct or class we need the correct 'this' for - * var the specific member of ad we're accessing - */ - -Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, - Expression *e1, Declaration *var) -{ - //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars()); - L1: - Type *t = e1->type->toBasetype(); - //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars()); - - /* If e1 is not the 'this' pointer for ad - */ - if (ad && - !(t->ty == Tpointer && t->nextOf()->ty == Tstruct && - ((TypeStruct *)t->nextOf())->sym == ad) - && - !(t->ty == Tstruct && - ((TypeStruct *)t)->sym == ad) - ) - { - ClassDeclaration *cd = ad->isClassDeclaration(); - ClassDeclaration *tcd = t->isClassHandle(); - - /* e1 is the right this if ad is a base class of e1 - */ - if (!cd || !tcd || - !(tcd == cd || cd->isBaseOf(tcd, NULL)) - ) - { - /* Only classes can be inner classes with an 'outer' - * member pointing to the enclosing class instance - */ - if (tcd && tcd->isNested()) - { /* e1 is the 'this' pointer for an inner class: tcd. - * Rewrite it as the 'this' pointer for the outer class. - */ - - e1 = new DotVarExp(loc, e1, tcd->vthis); - e1->type = tcd->vthis->type; - // Do not call checkNestedRef() - //e1 = e1->semantic(sc); - - // Skip up over nested functions, and get the enclosing - // class type. - int n = 0; - Dsymbol *s; - for (s = tcd->toParent(); - s && s->isFuncDeclaration(); - s = s->toParent()) - { FuncDeclaration *f = s->isFuncDeclaration(); - if (f->vthis) - { - //printf("rewriting e1 to %s's this\n", f->toChars()); - n++; - - // LDC seems dmd misses it sometimes here :/ - f->vthis->nestedref = 1; - - 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() : ""); - - // 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()); - if (e->type) - { - Type *t = e->type->toBasetype(); - - if (t->ty == Tfunction /*|| e->op == TOKoverloadset*/) - { - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - - /* Look for e being a lazy parameter; rewrite as delegate call - */ - else if (e->op == TOKvar) - { VarExp *ve = (VarExp *)e; - - if (ve->var->storage_class & STClazy) - { - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - } - - else if (e->op == TOKdotexp) - { - e->error("expression has no value"); - return new ErrorExp(); - } - - } - else if (e->op == TOKdottd) - { - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - return e; -} - -/****************************** - * Perform semantic() on an array of Expressions. - */ - -Expressions *arrayExpressionSemantic(Expressions *exps, Scope *sc) -{ - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - if (e) - { e = e->semantic(sc); - exps->data[i] = (void *)e; - } - } - } - return exps; -} - - -/****************************** - * Perform canThrow() on an array of Expressions. - */ - -#if DMDV2 -int arrayExpressionCanThrow(Expressions *exps) -{ - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - if (e && e->canThrow()) - return 1; - } - } - return 0; -} -#endif - -/**************************************** - * Expand tuples. - */ - -void expandTuples(Expressions *exps) -{ - //printf("expandTuples()\n"); - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *arg = (Expression *)exps->data[i]; - if (!arg) - continue; - - // Look for tuple with 0 members - if (arg->op == TOKtype) - { TypeExp *e = (TypeExp *)arg; - if (e->type->toBasetype()->ty == Ttuple) - { TypeTuple *tt = (TypeTuple *)e->type->toBasetype(); - - if (!tt->arguments || tt->arguments->dim == 0) - { - exps->remove(i); - if (i == exps->dim) - return; - i--; - continue; - } - } - } - - // Inline expand all the tuples - while (arg->op == TOKtuple) - { TupleExp *te = (TupleExp *)arg; - - exps->remove(i); // remove arg - exps->insert(i, te->exps); // replace with tuple contents - if (i == exps->dim) - return; // empty tuple, no more arguments - arg = (Expression *)exps->data[i]; - } - } - } -} - -Expressions *arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt) -{ -#if DMDV1 - /* The first element sets the type - */ - Type *t0 = NULL; - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - - if (!e->type) - { error(e->loc, "%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) - { e->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]; - - if (!arg->type) - { -#ifdef DEBUG - if (!global.gag) - printf("1: \n"); -#endif - arg->error("%s is not an expression", arg->toChars()); - arg = new ErrorExp(); - } - - arg = resolveProperties(sc, arg); - (*exps)[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 - } - } -} - -/********************************************* - * Call copy constructor for struct value argument. - */ -#if DMDV2 -Expression *callCpCtor(Loc loc, Scope *sc, Expression *e) -{ - Type *tb = e->type->toBasetype(); - assert(tb->ty == Tstruct); - StructDeclaration *sd = ((TypeStruct *)tb)->sym; - if (sd->cpctor) - { - /* Create a variable tmp, and replace the argument e with: - * (tmp = e),tmp - * and let AssignExp() handle the construction. - * This is not the most efficent, ideally tmp would be constructed - * directly onto the stack. - */ - Identifier *idtmp = Lexer::uniqueId("__tmp"); - VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e)); - tmp->storage_class |= STCctfe; - Expression *ae = new DeclarationExp(loc, tmp); - e = new CommaExp(loc, ae, new VarExp(loc, tmp)); - e = e->semantic(sc); - } - return e; -} -#endif - -/**************************************** - * Now that we know the exact type of the function we're calling, - * the arguments[] need to be adjusted: - * 1. implicitly convert argument to the corresponding parameter type - * 2. add default arguments for any missing arguments - * 3. do default promotions on arguments corresponding to ... - * 4. add hidden _arguments[] argument - */ - -void functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments) -{ - //printf("functionParameters()\n"); - assert(arguments); - size_t nargs = arguments ? arguments->dim : 0; - size_t nparams = Parameter::dim(tf->parameters); - - if (nargs > nparams && tf->varargs == 0) - error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf->toChars()); - -#if DMDV2 - // If inferring return type, and semantic3() needs to be run if not already run - if (!tf->next && fd->inferRetType) - { - TemplateInstance *spec = fd->isSpeculative(); - 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; - } -#endif - - unsigned n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) - - int done = 0; - for (size_t i = 0; i < n; i++) - { - Expression *arg; - - if (i < nargs) - arg = (*arguments)[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; - } - arg = p->defaultArg; - arg = arg->inlineCopy(sc); -#if DMDV2 - arg = arg->resolveLoc(loc, sc); // __FILE__ and __LINE__ -#endif - arguments->push(arg); - nargs++; - } - - if (tf->varargs == 2 && i + 1 == nparams) - { - //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars()); - MATCH m; - if ((m = arg->implicitConvTo(p->type)) != MATCHnomatch) - { - if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()) >= m) - goto L2; - else if (nargs != nparams) - { error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs); - return; - } - goto L1; - } - L2: - Type *tb = p->type->toBasetype(); - Type *tret = p->isLazyArray(); - switch (tb->ty) - { - case Tsarray: - case Tarray: - { // Create a static array variable v of type arg->type -#ifdef IN_GCC - /* GCC 4.0 does not like zero length arrays used like - this; pass a null array value instead. Could also - just make a one-element array. */ - if (nargs - i == 0) - { - arg = new NullExp(loc); - break; - } -#endif - Identifier *id = Lexer::uniqueId("__arrayArg"); - Type *t = new TypeSArray(((TypeArray *)tb)->next, new IntegerExp(nargs - i)); - t = t->semantic(loc, sc); - VarDeclaration *v = new VarDeclaration(loc, t, id, new VoidInitializer(loc)); - v->storage_class |= STCctfe; - v->semantic(sc); - v->parent = sc->parent; - //sc->insert(v); - - Expression *c = new DeclarationExp(0, v); - c->type = v->type; - - for (size_t u = i; u < nargs; u++) - { Expression *a = (*arguments)[u]; - if (tret && !((TypeArray *)tb)->next->equals(a->type)) - a = a->toDelegate(sc, tret); - - Expression *e = new VarExp(loc, v); - e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams)); - AssignExp *ae = new AssignExp(loc, e, a); - if (c) - c = new CommaExp(loc, c, ae); - else - c = ae; - } - arg = new VarExp(loc, v); - if (c) - arg = new CommaExp(loc, c, arg); - break; - } - case Tclass: - { /* Set arg to be: - * new Tclass(arg0, arg1, ..., argn) - */ - Expressions *args = new Expressions(); - args->setDim(nargs - i); - for (size_t u = i; u < nargs; u++) - args->data[u - i] = arguments->data[u]; - arg = new NewExp(loc, NULL, NULL, p->type, args); - break; - } - default: - if (!arg) - { error(loc, "not enough arguments"); - return; - } - break; - } - arg = arg->semantic(sc); - //printf("\targ = '%s'\n", arg->toChars()); - arguments->setDim(i + 1); - done = 1; - } - - L1: - if (!(p->storageClass & STClazy && p->type->ty == Tvoid)) - { - if (p->type != arg->type) - { - //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars()); - if (arg->op == TOKtype) - arg->error("cannot pass type %s as function argument", arg->toChars()); - arg = arg->implicitCastTo(sc, p->type); - arg = arg->optimize(WANTvalue); - } - } - if (p->storageClass & (STCout | STCref)) - { - // BUG: should check that argument to ref is type 'invariant' - // BUG: assignments to ref should also be type 'invariant' - arg = arg->modifiableLvalue(sc, arg); - - //if (arg->op == TOKslice) - //arg->error("cannot modify slice %s", arg->toChars()); - } - -// LDC we don't want this! -#if !IN_LLVM - // Convert static arrays to pointers - Type *tb = arg->type->toBasetype(); - if (tb->ty == Tsarray) - { - arg = arg->checkToPointer(); - } -#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 - - // 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; - } - } - - // 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); - } -#endif - - // Give error for overloaded function addresses -#if DMDV2 - if (arg->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)arg; - if ( - se->hasOverloads && - !se->var->isFuncDeclaration()->isUnique()) - arg->error("function %s is overloaded", arg->toChars()); - } -#endif - arg->rvalue(); - } - arg = arg->optimize(WANTvalue); - arguments->data[i] = (void *) arg; - if (done) - break; - } - -#if !IN_LLVM - // If D linkage and variadic, add _arguments[] as first argument - if (tf->linkage == LINKd && tf->varargs == 1) - { - assert(arguments->dim >= nparams); - Expression *e = createTypeInfoArray(sc, (Expression **)&arguments->data[nparams], - arguments->dim - nparams); - arguments->insert(0, e); - } -#endif -} - -/************************************************** - * Write expression out to buf, but wrap it - * in ( ) if its precedence is less than pr. - */ - -void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) -{ -#ifdef DEBUG - if (precedence[e->op] == PREC_zero) - printf("precedence not defined for token '%s'\n",Token::tochars[e->op]); -#endif - assert(precedence[e->op] != PREC_zero); - assert(pr != PREC_zero); - - //if (precedence[e->op] == 0) e->dump(0); - if (precedence[e->op] < pr || - /* Despite precedence, we don't allow aop] == pr)) - { - buf->writeByte('('); - e->toCBuffer(buf, hgs); - buf->writeByte(')'); - } - else - e->toCBuffer(buf, hgs); -} - -/************************************************** - * Write out argument list to buf. - */ - -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) -{ - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *arg = (Expression *)arguments->data[i]; - - if (arg) - { if (i) - buf->writeByte(','); - expToCBuffer(buf, hgs, arg, PREC_assign); - } - } - } -} - -/************************************************** - * Write out argument types to buf. - */ - -void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) -{ - if (arguments) - { OutBuffer argbuf; - - for (size_t i = 0; i < arguments->dim; i++) - { Expression *arg = (Expression *)arguments->data[i]; - - if (i) - buf->writeByte(','); - argbuf.reset(); - arg->type->toCBuffer2(&argbuf, hgs, 0); - buf->write(&argbuf); - } - } -} - -/******************************** Expression **************************/ - -Expression::Expression(Loc loc, enum TOK op, int size) - : loc(loc) -{ - //printf("Expression::Expression(op = %d) this = %p\n", op, this); - this->loc = loc; - this->op = op; - this->size = size; - 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 ldouble(0); -} - -real_t Expression::toImaginary() -{ - error("Floating point constant expression expected instead of %s", toChars()); - return ldouble(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.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. - */ - -int Expression::isLvalue() -{ - return 0; -} - - -/******************************* - * 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()) - error("'%s' is not a scalar, it is a %s", toChars(), type->toChars()); -} - -void Expression::checkNoBool() -{ - if (type->toBasetype()->ty == Tbool) - error("operation not allowed on bool '%s'", toChars()); -} - -Expression *Expression::checkIntegral() -{ - if (!type->isintegral()) - { error("'%s' is not of integral type, it is a %s", toChars(), type->toChars()); - return new ErrorExp(); - } - 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(); - } - return this; -} - -void Expression::checkDeprecated(Scope *sc, Dsymbol *s) -{ - s->checkDeprecated(loc, sc); -} - -#if DMDV2 -void Expression::checkPurity(Scope *sc, FuncDeclaration *f) -{ - if (sc->func && sc->func->isPure() && !sc->intypeof && !f->isPure()) - error("pure function '%s' cannot call impure function '%s'\n", - sc->func->toChars(), f->toChars()); -} -#endif - -/******************************** - * Check for expressions that have no use. - * Input: - * flag 0 not going to use the result, so issue error message if no - * side effects - * 1 the result of the expression is used, but still check - * for useless subexpressions - * 2 do not issue error messages, just return !=0 if expression - * has side effects - */ - -int Expression::checkSideEffect(int flag) -{ - if (flag == 0) - { if (op == TOKimport) - { - error("%s has no effect", toChars()); - } - else - error("%s has no effect in expression (%s)", - Token::toChars(op), toChars()); - } - return 0; -} - -/***************************** - * Check that expression can be tested for true or false. - */ - -Expression *Expression::checkToBoolean() -{ - // Default is 'yes' - do nothing - -#ifdef DEBUG - if (!type) - dump(0); -#endif - - if (!type->checkBoolean()) - { - error("expression %s of type %s does not have a boolean value", toChars(), type->toChars()); - } - return this; -} - -/**************************** - */ - -Expression *Expression::checkToPointer() -{ - Expression *e; - Type *tb; - - //printf("Expression::checkToPointer()\n"); - e = this; - - // If C static array, convert to pointer - tb = type->toBasetype(); - if (tb->ty == Tsarray) - { TypeSArray *ts = (TypeSArray *)tb; - if (ts->size(loc) == 0) - e = new NullExp(loc); - else - e = new AddrExp(loc, this); - e->type = ts->next->pointerTo(); - } - return e; -} - -/****************************** - * Take address of expression. - */ - -Expression *Expression::addressOf(Scope *sc) -{ - Expression *e; - 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; -} - -/******************************** - * Can this expression throw an exception? - * Valid only after semantic() pass. - */ - -int Expression::canThrow() -{ -#if DMDV2 - return FALSE; -#else - return TRUE; -#endif -} - - - -Expressions *Expression::arraySyntaxCopy(Expressions *exps) -{ Expressions *a = NULL; - - if (exps) - { - a = new Expressions(); - a->setDim(exps->dim); - for (size_t i = 0; i < a->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - if (e) - e = e->syntaxCopy(); - a->data[i] = e; - } - } - return a; -} - -/******************************** IntegerExp **************************/ - -IntegerExp::IntegerExp(Loc loc, dinteger_t value, Type *type) - : Expression(loc, TOKint64, sizeof(IntegerExp)) -{ - //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : ""); - if (type && !type->isscalar()) - { - //printf("%s, loc = %d\n", toChars(), loc.linnum); - if (type->ty != Terror) - error("integral constant must be scalar type, not %s", type->toChars()); - type = Type::terror; - } - this->type = type; - this->value = value; -} - -IntegerExp::IntegerExp(dinteger_t value) - : Expression(0, TOKint64, sizeof(IntegerExp)) -{ - this->type = Type::tint32; - this->value = value; -} - -int IntegerExp::equals(Object *o) -{ IntegerExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKint64 && - ((ne = (IntegerExp *)o), type->equals(ne->type)) && - value == ne->value)) - return 1; - return 0; -} - -char *IntegerExp::toChars() -{ -#if 1 - return Expression::toChars(); -#else - static char buffer[sizeof(value) * 3 + 1]; - - sprintf(buffer, "%jd", value); - return buffer; -#endif -} - -dinteger_t IntegerExp::toInteger() -{ Type *t; - - t = type; - while (t) - { - switch (t->ty) - { - case Tbit: - case Tbool: value = (value != 0); break; - case Tint8: value = (d_int8) value; break; - case Tchar: - case Tuns8: value = (d_uns8) value; break; - case Tint16: value = (d_int16) value; break; - case Twchar: - case Tuns16: value = (d_uns16) value; break; - case Tint32: value = (d_int32) value; break; - case Tdchar: - case Tuns32: value = (d_uns32) value; break; - case Tint64: value = (d_int64) value; break; - case Tuns64: value = (d_uns64) value; break; - case Tpointer: - if (PTRSIZE == 4) - value = (d_uns32) value; - else if (PTRSIZE == 8) - value = (d_uns64) value; - else - assert(0); - break; - - case Tenum: - { - TypeEnum *te = (TypeEnum *)t; - t = te->sym->memtype; - continue; - } - - case Ttypedef: - { - TypeTypedef *tt = (TypeTypedef *)t; - t = tt->sym->basetype; - continue; - } - - default: - /* This can happen if errors, such as - * the type is painted on like in fromConstInitializer(). - */ - if (!global.errors) - { type->print(); - assert(0); - } - break; - } - break; - } - return value; -} - -real_t IntegerExp::toReal() -{ - Type *t; - - toInteger(); - t = type->toBasetype(); - if (t->ty == Tuns64) - return ldouble((d_uns64)value); - else - return ldouble((d_int64)value); -} - -real_t IntegerExp::toImaginary() -{ - return ldouble(0); -} - -complex_t IntegerExp::toComplex() -{ - return toReal(); -} - -int IntegerExp::isBool(int result) -{ - int r = toInteger() != 0; - return result ? r : !r; -} - -Expression *IntegerExp::semantic(Scope *sc) -{ - if (!type) - { - // Determine what the type of this number is - dinteger_t number = value; - - if (number & 0x8000000000000000LL) - type = Type::tuns64; - else if (number & 0xFFFFFFFF80000000LL) - type = Type::tint64; - else - type = Type::tint32; - } - else - { if (!type->deco) - type = type->semantic(loc, sc); - } - return this; -} - -Expression *IntegerExp::toLvalue(Scope *sc, Expression *e) -{ - if (!e) - e = this; - else if (!loc.filename) - loc = e->loc; - e->error("constant %s is not an lvalue", e->toChars()); - return this; -} - -void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - dinteger_t v = toInteger(); - - if (type) - { Type *t = type; - - L1: - switch (t->ty) - { - case Tenum: - { TypeEnum *te = (TypeEnum *)t; - buf->printf("cast(%s)", te->sym->toChars()); - t = te->sym->memtype; - goto L1; - } - - case Ttypedef: - { TypeTypedef *tt = (TypeTypedef *)t; - buf->printf("cast(%s)", tt->sym->toChars()); - t = tt->sym->basetype; - goto L1; - } - - case Twchar: // BUG: need to cast(wchar) - case Tdchar: // BUG: need to cast(dchar) - if ((uinteger_t)v > 0xFF) - { - buf->printf("'\\U%08x'", (unsigned)v); - break; - } - case Tchar: - { - 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 Tbit: - case Tbool: - buf->writestring((char *)(v ? "true" : "false")); - break; - - case Tpointer: - buf->writestring("cast("); - buf->writestring(t->toChars()); - buf->writeByte(')'); - if (PTRSIZE == 4) - goto L3; - else if (PTRSIZE == 8) - goto L4; - else - assert(0); - - default: - /* This can happen if errors, such as - * the type is painted on like in fromConstInitializer(). - */ - if (!global.errors) - { -#ifdef DEBUG - t->print(); -#endif - assert(0); - } - break; - } - } - else if (v & 0x8000000000000000LL) - buf->printf("0x%jx", v); - else - buf->printf("%jd", v); -} - -void IntegerExp::toMangleBuffer(OutBuffer *buf) -{ - if ((sinteger_t)value < 0) - buf->printf("N%jd", -value); - else - { - /* This is an awful hack to maintain backwards compatibility. - * There really always should be an 'i' before a number, but - * there wasn't in earlier implementations, so to maintain - * backwards compatibility it is only done if necessary to disambiguate. - * See bugzilla 3029 - */ - if (buf->offset > 0 && isdigit(buf->data[buf->offset - 1])) - buf->writeByte('i'); - - buf->printf("%jd", value); - } -} - -/******************************** ErrorExp **************************/ - -/* Use this expression for error recovery. - * It should behave as a 'sink' to prevent further cascaded error messages. - */ - -ErrorExp::ErrorExp() - : IntegerExp(0, 0, Type::terror) -{ - op = TOKerror; -} - -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 : ldouble(0); -} - -real_t RealExp::toImaginary() -{ - return type->isreal() ? ldouble(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)) || - /* In some cases, the REALPAD bytes get garbage in them, - * so be sure and ignore them. - */ - memcmp(&x1, &x2, REALSIZE - REALPAD) == 0; -} - -int RealExp::equals(Object *o) -{ RealExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKfloat64 && - ((ne = (RealExp *)o), type->equals(ne->type)) && - 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)) - 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]; - - char buf1[sizeof(value) * 3 + 8 + 1]; - char buf2[sizeof(value) * 3 + 8 + 1]; -#ifdef IN_GCC - creall(value).format(buf1, sizeof(buf1)); - cimagl(value).format(buf2, sizeof(buf2)); -#else - ld_sprint(buf1, 'g', creall(value)); - ld_sprint(buf2, 'g', cimagl(value)); -#endif - sprintf(buffer, "(%s+%si)", buf1, buf2); - assert(strlen(buffer) < sizeof(buffer)); - 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->equals(ne->type)) && - 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) - { - 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 (!s->parent && scopesym->isArrayScopeSymbol()) - { // Kludge to run semantic() here because - // ArrayScopeSymbol::search() doesn't have access to sc. - s->semantic(sc); - } - /* 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; - } - } - e = new DsymbolExp(loc, s); - } - return e->semantic(sc); - } -#if DMDV2 - if (ident == Id::ctfe) - { // Create the magic __ctfe bool variable - VarDeclaration *vd = new VarDeclaration(loc, Type::tbool, Id::ctfe, NULL); - Expression *e = new VarExp(loc, vd); - e = e->semantic(sc); - return e; - } -#endif - const char *n = importHint(ident->toChars()); - if (n) - error("'%s' is not defined, perhaps you need to import %s; ?", ident->toChars(), n); - else - { - s = sc->search_correct(ident); - if (s) - error("undefined identifier %s, did you mean %s %s?", ident->toChars(), s->kind(), s->toChars()); - else - error("undefined identifier %s", ident->toChars()); - } - return new ErrorExp(); -} - -char *IdentifierExp::toChars() -{ - return ident->toChars(); -} - -void IdentifierExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - buf->writestring(ident->toHChars2()); - else - buf->writestring(ident->toChars()); -} - - -int IdentifierExp::isLvalue() -{ - return 1; -} - - -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) - : Expression(loc, TOKdsymbol, sizeof(DsymbolExp)) -{ - this->s = s; -} - -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; - 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 && !s->needThis()) - 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->copy(); - e->loc = loc; - 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->isSameAsInitializer() && type->toBasetype()->ty != Tsarray) - { - if (v->init) - { - if (v->inuse) - { - error("circular reference to '%s'", v->toChars()); - return new ErrorExp(); - } - ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { - e = ei->exp->copy(); // make copy so we can change loc - if (e->op == TOKstring || !e->type) - e = e->semantic(sc); - e = e->implicitCastTo(sc, type); - e->loc = loc; - return e; - } - } - else - { - e = type->defaultInit(); - e->loc = loc; - 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 - { - unsigned oldgag = global.gag; - if (global.isSpeculativeGagging() && !f->isSpeculative()) - global.gag = 0; - f->semantic(f->scope); - global.gag = oldgag; - } - -#if DMDV2 - // if inferring return type, sematic3 needs to be run - if (f->inferRetType && f->scope && f->type && !f->type->nextOf()) - { - TemplateInstance *spec = f->isSpeculative(); - 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; - } -#endif - - 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); - } - 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) - { - for (size_t i = 0; i < tup->objects->dim; i++) - { - Dsymbol *sa = getDsymbol((*tup->objects)[i]); - if (sa && sa->needThis()) - { - if (hasThis(sc) -#if DMDV2 - && !sa->isFuncDeclaration() -#endif - ) - { - // Supply an implicit 'this', as in - // this.ident - (*tup->objects)[i] = new DotVarExp(loc, new ThisExp(loc), sa->isDeclaration()); - } - } - } - - e = new TupleExp(loc, tup); - e = e->semantic(sc); - return e; - } - - TemplateInstance *ti = s->isTemplateInstance(); - if (ti) - { if (!ti->semanticRun) - ti->semantic(sc); - s = ti->toAlias(); - if (!s->isTemplateInstance()) - goto Lagain; - if (ti->errors) - return new ErrorExp(); - e = new ScopeExp(loc, ti); - e = e->semantic(sc); - return e; - } - - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td) - { - e = new TemplateExp(loc, td); - e = e->semantic(sc); - return e; - } - - 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()); -} - - -int DsymbolExp::isLvalue() -{ - return 1; -} - - -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) - { //assert(global.errors || var); - 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); - 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"); -} - - -int ThisExp::isLvalue() -{ - return 1; -} - - -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; -#if DMDV2 - type = type->castMod(var->type->mod); -#endif - } - - var->isVarDeclaration()->checkNestedReference(sc, loc); - - if (!sc->intypeof) - sc->callSuper |= CSXsuper; - return this; - - -Lerr: - error("'super' is only allowed in non-static class member functions"); - return new ErrorExp(); -} - -void SuperExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("super"); -} - - -/******************************** NullExp **************************/ - -NullExp::NullExp(Loc loc, Type *type) - : Expression(loc, TOKnull, sizeof(NullExp)) -{ - committed = 0; - this->type = type; -} - -Expression *NullExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("NullExp::semantic('%s')\n", toChars()); -#endif - // NULL is the same as (void *)0 - if (!type) - type = Type::tvoid->pointerTo(); - return this; -} - -int NullExp::isBool(int result) -{ - return result ? FALSE : TRUE; -} - -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)); - 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)); - committed = 1; - break; - - case 'c': - committed = 1; - default: - type = new TypeSArray(Type::tchar, new IntegerExp(loc, len, Type::tindex)); - break; - } - type = type->semantic(loc, sc); - } - 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; -} - - -int StringExp::isLvalue() -{ - /* string literal is rvalue in default, but - * conversion to reference of static array is only allowed. - */ - return 0; -} - -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); - this->ownedByCtfe = false; -} - -Expression *ArrayLiteralExp::syntaxCopy() -{ - return new ArrayLiteralExp(loc, arraySyntaxCopy(elements)); -} - -Expression *ArrayLiteralExp::semantic(Scope *sc) -{ Expression *e; - Type *t0 = NULL; - -#if LOGSEMANTIC - printf("ArrayLiteralExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - // Run semantic() on each element - for (size_t i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - e = e->semantic(sc); - elements->data[i] = (void *)e; - } - expandTuples(elements); - for (size_t i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - - if (!e->type) - error("%s has no value", e->toChars()); - e = resolveProperties(sc, e); - - unsigned char committed = 1; - if (e->op == TOKstring) - committed = ((StringExp *)e)->committed; - - if (!t0) - { t0 = e->type; - // Convert any static arrays to dynamic arrays - if (t0->ty == Tsarray) - { - t0 = ((TypeSArray *)t0)->next->arrayOf(); - e = e->implicitCastTo(sc, t0); - } - } - else - e = e->implicitCastTo(sc, t0); - if (!committed && e->op == TOKstring) - { StringExp *se = (StringExp *)e; - se->committed = 0; - } - elements->data[i] = (void *)e; - } - - if (!t0) - t0 = Type::tvoid; - - type = new TypeSArray(t0, new IntegerExp(elements->dim)); - type = type->semantic(loc, sc); - - /* 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::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; - - f |= e->hasSideEffect(); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -int ArrayLiteralExp::isBool(int result) -{ - size_t dim = elements ? elements->dim : 0; - return result ? (dim != 0) : (dim == 0); -} - -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)[i]; - if (ch->op != TOKint64) - return NULL; - buf.writeUTF8(ch->toInteger()); - } - buf.writebyte(0); - - char prefix = 'c'; - if (telem == Twchar) prefix = 'w'; - else if (telem == Tdchar) prefix = 'd'; - - const size_t len = buf.offset - 1; - StringExp *se = new StringExp(loc, buf.extractData(), len, 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%u", dim); - for (size_t i = 0; i < dim; i++) - { Expression *e = (*elements)[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); - - if (tkey == Type::terror || tvalue == Type::terror) - return new ErrorExp; - - type = new TypeAArray(tvalue, tkey); - type = type->semantic(loc, sc); - return this; -} - -int AssocArrayLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - f |= key->hasSideEffect(); - f |= value->hasSideEffect(); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -int AssocArrayLiteralExp::isBool(int result) -{ - size_t dim = keys->dim; - return result ? (dim != 0) : (dim == 0); -} - -#if DMDV2 -int AssocArrayLiteralExp::canThrow() -{ - return 1; -} -#endif - -void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('['); - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (*keys)[i]; - Expression *value = (*values)[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%u", dim); - for (size_t i = 0; i < dim; i++) - { Expression *key = (*keys)[i]; - Expression *value = (*values)[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; - -#if LOGSEMANTIC - printf("StructLiteralExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - // Run semantic() on each element - for (size_t i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - if (!e) - continue; - e = e->semantic(sc); - elements->data[i] = (void *)e; - } - expandTuples(elements); - size_t offset = 0; - for (size_t i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - if (!e) - continue; - - if (!e->type) - { error("%s has no value", e->toChars()); - return new ErrorExp(); - } - e = resolveProperties(sc, e); - if (i >= sd->fields.dim) - { error("more initializers than fields of %s", sd->toChars()); - break; - } - Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - if (v->offset < offset) - error("overlapping initialization for %s", v->toChars()); - offset = v->offset + v->type->size(); - - Type *telem = v->type; - while (!e->implicitConvTo(telem) && telem->toBasetype()->ty == Tsarray) - { /* Static array initialization, as in: - * T[3][5] = e; - */ - telem = telem->toBasetype()->nextOf(); - } - - e = e->implicitCastTo(sc, telem); - - elements->data[i] = (void *)e; - } - - /* Fill out remainder of elements[] with default initializers for fields[] - */ - for (size_t i = elements->dim; i < sd->fields.dim; i++) - { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - 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, INITinterpret); - 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; - return this; -} - -/************************************** - * Gets expression at offset of type. - * Returns NULL if not found. - */ - -Expression *StructLiteralExp::getField(Type *type, unsigned offset) -{ - //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n", -// /*toChars()*/"", type->toChars(), offset); - Expression *e = NULL; - int i = getFieldIndex(type, offset); - - if (i != -1) - { - //printf("\ti = %d\n", i); - assert(i < elements->dim); - e = (Expression *)elements->data[i]; - if (e) - { - //printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars()); - - /* If type is a static array, and e is an initializer for that array, - * then the field initializer should be an array literal of e. - */ - if (e->type != type && type->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)type; - uinteger_t length = tsa->dim->toInteger(); - Expressions *z = new Expressions; - z->setDim(length); - for (int q = 0; q < length; ++q) - z->data[q] = e->copy(); - e = new ArrayLiteralExp(loc, z); - e->type = type; - } - else - { - e = e->copy(); - e->type = type; - } - } - } - return e; -} - -/************************************ - * Get index of field. - * Returns -1 if not found. - */ - -int StructLiteralExp::getFieldIndex(Type *type, unsigned offset) -{ - /* Find which field offset is by looking at the field offsets - */ - if (elements->dim) - { - for (size_t i = 0; i < sd->fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - if (offset == v->offset && - type->size() == v->type->size()) - { Expression *e = (Expression *)elements->data[i]; - if (e) - { - return i; - } - break; - } - } - } - return -1; -} - -#if DMDV2 -int StructLiteralExp::isLvalue() -{ - return 1; -} -#endif - -Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - - -int StructLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - if (!e) - continue; - - f |= e->hasSideEffect(); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -#if DMDV2 -int StructLiteralExp::canThrow() -{ - return arrayExpressionCanThrow(elements); -} -#endif - -void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(sd->toChars()); - buf->writeByte('('); - argsToCBuffer(buf, elements, hgs); - buf->writeByte(')'); -} - -void StructLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = elements ? elements->dim : 0; - buf->printf("S%u", dim); - for (size_t i = 0; i < dim; i++) - { Expression *e = (*elements)[i]; - if (e) - e->toMangleBuffer(buf); - else - buf->writeByte('v'); // 'v' for void - } -} - -/************************ TypeDotIdExp ************************************/ - -/* Things like: - * int.size - * foo.size - * (foo).size - * cast(foo).size - */ - -Expression *typeDotIdExp(Loc loc, Type *type, Identifier *ident) -{ - return new DotIdExp(loc, new TypeExp(loc, type), ident); -} - - -/************************************************************/ - -// Mainly just a placeholder - -TypeExp::TypeExp(Loc loc, Type *type) - : Expression(loc, TOKtype, sizeof(TypeExp)) -{ - //printf("TypeExp::TypeExp(%s)\n", type->toChars()); - this->type = type; -} - -Expression *TypeExp::syntaxCopy() -{ - //printf("TypeExp::syntaxCopy()\n"); - return new TypeExp(loc, type->syntaxCopy()); -} - -Expression *TypeExp::semantic(Scope *sc) -{ - //printf("TypeExp::semantic(%s)\n", type->toChars()); - type = type->semantic(loc, sc); - return this; -} - -void TypeExp::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 && !ti->errors) - { - unsigned olderrs = global.errors; - if (!ti->semanticRun) - ti->semantic(sc); - if (ti->inst) - { - if (ti->inst->errors) - return new ErrorExp(); - 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 (olderrs != 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) - { TypeFunction *tf; - - TypeClass *tc = (TypeClass *)(tb); - ClassDeclaration *cd = tc->sym->isClassDeclaration(); - if (cd->isInterfaceDeclaration()) - { error("cannot create instance of interface %s", cd->toChars()); - goto Lerr; - } - else if (cd->isAbstract()) - { error("cannot create instance of abstract class %s", cd->toChars()); - for (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; - } - 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 - } - 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 if (thisexp) - { error("e.new is only for allocating nested classes"); - goto Lerr; - } - - FuncDeclaration *f = cd->ctor; - if (f) - { - assert(f); - f = f->overloadResolve(loc, NULL, arguments, sc->module); - checkDeprecated(sc, f); - member = f->isCtorDeclaration(); - assert(member); - - cd->accessCheck(loc, sc, member); - - tf = (TypeFunction *)f->type; - type = tf->next; - - if (!arguments) - arguments = new Expressions(); - unsigned olderrors = global.errors; - functionParameters(loc, sc, tf, arguments); - if (olderrors != global.errors) - return new ErrorExp(); - - } - 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, sc->module); - allocator = f->isNewDeclaration(); - assert(allocator); - - tf = (TypeFunction *)f->type; - unsigned olderrors = global.errors; - functionParameters(loc, sc, tf, newargs); - 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; - FuncDeclaration *f = sd->aggNew; - TypeFunction *tf; - - if (arguments && arguments->dim) - error("no constructor for %s", type->toChars()); - - if (f) - { - Expression *e; - - // Prepend the uint size argument to newargs[] - e = new IntegerExp(loc, sd->size(loc), Type::tuns32); - if (!newargs) - newargs = new Expressions(); - newargs->shift(e); - - f = f->overloadResolve(loc, NULL, newargs, sc->module); - allocator = f->isNewDeclaration(); - assert(allocator); - - tf = (TypeFunction *)f->type; - unsigned olderrors = global.errors; - functionParameters(loc, sc, tf, newargs); - if (olderrors != global.errors) - return new ErrorExp(); - - e = new VarExp(loc, f); - e = new CallExp(loc, e, newargs); - e = e->semantic(sc); - e->type = type->pointerTo(); - return e; - } - - 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); - if (arg->op == TOKint64 && (long long)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(); -} - -int NewExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int NewExp::canThrow(bool mustNotThrow) -{ - if (arrayExpressionCanThrow(newargs, mustNotThrow) || - arrayExpressionCanThrow(arguments, mustNotThrow)) - return 1; - if (member) - { - // See if constructor call can throw - Type *t = member->type->toBasetype(); - if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow) - { - if (mustNotThrow) - error("constructor %s is not nothrow", member->toChars()); - return 1; - } - } - // regard storage allocation failures as not recoverable - return 0; -} -#endif - -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); -} - -int NewAnonClassExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int NewAnonClassExp::canThrow() -{ - return 1; -} -#endif - -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) - : Expression(loc, TOKsymoff, sizeof(SymOffExp)) -{ - assert(var); - this->var = var; - this->offset = offset; - m = NULL; - VarDeclaration *v = var->isVarDeclaration(); - if (v && v->needThis()) - error("need 'this' for address of %s", v->toChars()); -} - -Expression *SymOffExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("SymOffExp::semantic('%s')\n", toChars()); -#endif - //var->semantic(sc); - m = sc->module; - if (!type) - type = var->type->pointerTo(); - VarDeclaration *v = var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, loc); - return this; -} - -int SymOffExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - -void SymOffExp::checkEscape() -{ - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg() && !(v->storage_class & (STCref | STCout))) - { /* BUG: This should be allowed: - * void foo() - * { int a; - * int* bar() { return &a; } - * } - */ - error("escaping reference to local %s", v->toChars()); - } - } -} - -void SymOffExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (offset) - buf->printf("(& %s+%u)", var->toChars(), offset); - else - buf->printf("& %s", var->toChars()); -} - -/******************************** VarExp **************************/ - -VarExp::VarExp(Loc loc, Declaration *var) - : Expression(loc, TOKvar, sizeof(VarExp)) -{ - //printf("VarExp(this = %p, '%s')\n", this, var->toChars()); - this->var = var; - this->type = var->type; -} - -int VarExp::equals(Object *o) -{ VarExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKvar && - ((ne = (VarExp *)o), type->equals(ne->type)) && - var == ne->var)) - return 1; - return 0; -} - -Expression *VarExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("VarExp::semantic(%s)\n", toChars()); -#endif - if (!type) - { type = var->type; -#if 0 - if (var->storage_class & STClazy) - { - TypeFunction *tf = new TypeFunction(NULL, type, 0, LINKd); - type = new TypeDelegate(tf); - type = type->semantic(loc, sc); - } -#endif - } - - 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) - { - if (v->isSameAsInitializer() && type->toBasetype()->ty != Tsarray && v->init) - { - ExpInitializer *ei = v->init->isExpInitializer(); - if (ei && ei->exp->type) - { - //ei->exp->implicitCastTo(sc, type)->print(); - return ei->exp->implicitCastTo(sc, type); - } - } - v->checkNestedReference(sc, loc); -#if DMDV2 - if (sc->func && sc->func->isPure() && !sc->intypeof) - { - if (v->isDataseg() && !v->isImmutable()) - error("pure function '%s' cannot access mutable static data '%s'", sc->func->toChars(), v->toChars()); - } -#endif - } -#if 0 - else if ((fd = var->isFuncLiteralDeclaration()) != NULL) - { Expression *e; - e = new FuncExp(loc, fd); - e->type = type; - return e; - } -#endif - - return this; -} - -char *VarExp::toChars() -{ - return var->toChars(); -} - -void VarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(var->toChars()); -} - -void VarExp::checkEscape() -{ - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { Type *tb = v->type->toBasetype(); - // if reference type - if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass) - { - if (v->isScope() && !v->noscope) - error("escaping reference to auto 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()); - } -} - - -int VarExp::isLvalue() -{ - if (var->storage_class & STClazy) - return 0; - return 1; -} - - -Expression *VarExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - if (var->storage_class & STClazy) - error("lazy variables cannot be lvalues"); - return this; -} - -Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("VarExp::modifiableLvalue('%s')\n", var->toChars()); - if (sc->incontract && var->isParameter()) - error("cannot modify parameter '%s' in contract", var->toChars()); - - if (type && type->toBasetype()->ty == Tsarray) - error("cannot change reference to static array '%s'", var->toChars()); - - VarDeclaration *v = var->isVarDeclaration(); - if (v && v->canassign == 0 && - (var->isConst() || (global.params.Dversion > 1 && var->isFinal()))) - error("cannot modify final variable '%s'", var->toChars()); - - if (var->isCtorinit()) - { // It's only modifiable if inside the right constructor - Dsymbol *s = sc->func; - while (1) - { - FuncDeclaration *fd = NULL; - if (s) - fd = s->isFuncDeclaration(); - if (fd && - ((fd->isCtorDeclaration() && var->storage_class & STCfield) || - (fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) && - fd->toParent() == var->toParent() - ) - { - VarDeclaration *v = var->isVarDeclaration(); - assert(v); - v->ctorinit = 1; - //printf("setting ctorinit\n"); - } - else - { - if (s) - { s = s->toParent2(); - continue; - } - else - { - const char *p = var->isStatic() ? "static " : ""; - error("can only initialize %sconst %s inside %sconstructor", - p, var->toChars(), p); - } - } - break; - } - } - - // 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; - 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()); - e = 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(')'); -} - -int TupleExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - - f |= e->hasSideEffect(); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -#if DMDV2 -int TupleExp::canThrow(bool mustNotThrow) -{ - return arrayExpressionCanThrow(exps, mustNotThrow); -} -#endif - -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) - : Expression(loc, TOKfunction, sizeof(FuncExp)) -{ - this->fd = fd; -} - -Expression *FuncExp::syntaxCopy() -{ - return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL)); -} - -Expression *FuncExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("FuncExp::semantic(%s)\n", toChars()); -#endif - if (!type) - { - 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()) - { - type = new TypeDelegate(fd->type); - type = type->semantic(loc, sc); - } - else - { - type = fd->type->pointerTo(); - } - } - return this; -} - -char *FuncExp::toChars() -{ - return fd->toChars(); -} - -void FuncExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - fd->toCBuffer(buf, hgs); - //buf->writestring(fd->toChars()); -} - - -/******************************** DeclarationExp **************************/ - -DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration) - : Expression(loc, TOKdeclaration, sizeof(DeclarationExp)) -{ - this->declaration = declaration; -} - -Expression *DeclarationExp::syntaxCopy() -{ - return new DeclarationExp(loc, declaration->syntaxCopy(NULL)); -} - -Expression *DeclarationExp::semantic(Scope *sc) -{ - if (type) - return this; - -#if LOGSEMANTIC - printf("DeclarationExp::semantic() %s\n", toChars()); -#endif - - 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()); - 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()); - } - else if (!global.params.useDeprecated) - { // Disallow shadowing - - for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing) - { Dsymbol *s2; - - if (scx->scopesym && scx->scopesym->symtab && - (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL && - s != s2) - { - error("shadowing declaration %s is deprecated", s->toPrettyChars()); - } - } - } - } - } - if (!s->isVarDeclaration()) - { - Scope *sc2 = sc; - if (sc2->stc & (STCpure | STCnothrow)) - sc2 = sc->push(); - sc2->stc &= ~(STCpure | STCnothrow); - declaration->semantic(sc2); - if (sc2 != sc) - sc2->pop(); - s->parent = sc->parent; - } - if (global.errors == 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; -} - -int DeclarationExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int DeclarationExp::canThrow() -{ - VarDeclaration *v = declaration->isVarDeclaration(); - if (v && v->init) - { ExpInitializer *ie = v->init->isExpInitializer(); - return ie && ie->exp->canThrow(); - } - return 0; -} -#endif - -void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - declaration->toCBuffer(buf, hgs); -} - - -/************************ TypeidExp ************************************/ - -/* - * typeid(int) - */ - -TypeidExp::TypeidExp(Loc loc, Type *typeidType) - : Expression(loc, TOKtypeid, sizeof(TypeidExp)) -{ - this->typeidType = typeidType; -} - - -Expression *TypeidExp::syntaxCopy() -{ - return new TypeidExp(loc, typeidType->syntaxCopy()); -} - - -Expression *TypeidExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("TypeidExp::semantic()\n"); -#endif - typeidType = typeidType->semantic(loc, sc); - e = typeidType->getTypeInfo(sc); - if (e->loc.linnum == 0) - e->loc = loc; // so there's at least some line number info - return e; -} - -void TypeidExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typeid("); - typeidType->toCBuffer(buf, NULL, hgs); - buf->writeByte(')'); -} - -/************************ TraitsExp ************************************/ -#if DMDV2 -/* - * __traits(identifier, args...) - */ - -TraitsExp::TraitsExp(Loc loc, Identifier *ident, Objects *args) - : Expression(loc, TOKtraits, sizeof(TraitsExp)) -{ - this->ident = ident; - this->args = args; -} - - -Expression *TraitsExp::syntaxCopy() -{ - return new TraitsExp(loc, ident, TemplateInstance::arraySyntaxCopy(args)); -} - - -void TraitsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("__traits("); - buf->writestring(ident->toChars()); - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - buf->writeByte(','); - Object *oarg = (Object *)args->data[i]; - ObjectToCBuffer(buf, hgs, oarg); - } - } - buf->writeByte(')'); -} -#endif - -/************************************************************/ - -HaltExp::HaltExp(Loc loc) - : Expression(loc, TOKhalt, sizeof(HaltExp)) -{ -} - -Expression *HaltExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("HaltExp::semantic()\n"); -#endif - type = Type::tvoid; - return this; -} - -int HaltExp::checkSideEffect(int flag) -{ - return 1; -} - -void HaltExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("halt"); -} - -/************************************************************/ - -IsExp::IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, - Type *tspec, enum TOK tok2) - : Expression(loc, TOKis, sizeof(IsExp)) -{ - this->targ = targ; - this->id = id; - this->tok = tok; - this->tspec = tspec; - this->tok2 = tok2; -} - -Expression *IsExp::syntaxCopy() -{ - return new IsExp(loc, - targ->syntaxCopy(), - id, - tok, - tspec ? tspec->syntaxCopy() : NULL, - tok2); -} - -Expression *IsExp::semantic(Scope *sc) -{ Type *tded; - - /* is(targ id tok tspec) - * is(targ id == tok2) - */ - - //printf("IsExp::semantic(%s)\n", toChars()); - if (id && !(sc->flags & SCOPEstaticif)) - error("can only declare type aliases within static if conditionals"); - - unsigned errors_save = global.startGagging(); - targ = targ->semantic(loc, sc); - if (global.endGagging(errors_save)) // if any errors happened - { // then condition is false - goto Lno; - } - else if (tok2 != TOKreserved) - { - switch (tok2) - { - case TOKtypedef: - if (targ->ty != Ttypedef) - goto Lno; - tded = ((TypeTypedef *)targ)->sym->basetype; - break; - - case TOKstruct: - if (targ->ty != Tstruct) - goto Lno; - if (((TypeStruct *)targ)->sym->isUnionDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKunion: - if (targ->ty != Tstruct) - goto Lno; - if (!((TypeStruct *)targ)->sym->isUnionDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKclass: - if (targ->ty != Tclass) - goto Lno; - if (((TypeClass *)targ)->sym->isInterfaceDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKinterface: - if (targ->ty != Tclass) - goto Lno; - if (!((TypeClass *)targ)->sym->isInterfaceDeclaration()) - goto Lno; - tded = targ; - break; -#if DMDV2 - case TOKconst: - if (!targ->isConst()) - goto Lno; - tded = targ; - break; - - case TOKinvariant: - case TOKimmutable: - if (!targ->isImmutable()) - goto Lno; - tded = targ; - break; - - case TOKshared: - if (!targ->isShared()) - goto Lno; - tded = targ; - break; -#endif - - case TOKsuper: - // If class or interface, get the base class and interfaces - if (targ->ty != Tclass) - goto Lno; - else - { ClassDeclaration *cd = ((TypeClass *)targ)->sym; - Parameters *args = new Parameters; - args->reserve(cd->baseclasses->dim); - for (size_t i = 0; i < cd->baseclasses->dim; i++) - { BaseClass *b = (BaseClass *)cd->baseclasses->data[i]; - args->push(new Parameter(STCin, b->type, NULL, NULL)); - } - tded = new TypeTuple(args); - } - break; - - case TOKenum: - if (targ->ty != Tenum) - goto Lno; - tded = ((TypeEnum *)targ)->sym->memtype; - break; - - case TOKdelegate: - if (targ->ty != Tdelegate) - goto Lno; - tded = ((TypeDelegate *)targ)->next; // the underlying function type - break; - - case TOKfunction: - { - if (targ->ty != Tfunction) - goto Lno; - tded = targ; - - /* Generate tuple from function parameter types. - */ - assert(tded->ty == Tfunction); - Parameters *params = ((TypeFunction *)tded)->parameters; - size_t dim = Parameter::dim(params); - Parameters *args = new Parameters; - args->reserve(dim); - for (size_t i = 0; i < dim; i++) - { Parameter *arg = Parameter::getNth(params, i); - assert(arg && arg->type); - args->push(new Parameter(arg->storageClass, arg->type, NULL, NULL)); - } - tded = new TypeTuple(args); - break; - } - case TOKreturn: - /* Get the 'return type' for the function, - * delegate, or pointer to function. - */ - if (targ->ty == Tfunction) - tded = ((TypeFunction *)targ)->next; - else if (targ->ty == Tdelegate) - tded = targ->next->next; - else if (targ->ty == Tpointer && targ->next->ty == Tfunction) - tded = targ->next->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. - */ - - TemplateTypeParameter tp(loc, id, NULL, NULL); - - TemplateParameters parameters; - parameters.setDim(1); - parameters.data[0] = (void *)&tp; - - Objects dedtypes; - dedtypes.setDim(parameters.dim); - dedtypes.zero(); - - MATCH m = targ->deduceType(sc, tspec, ¶meters, &dedtypes); - if (m == MATCHnomatch || - (m != MATCHexact && tok == TOKequal)) - { - goto Lno; - } - else - { - assert(dedtypes.dim == 1); - tded = (Type *)dedtypes.data[0]; - if (!tded) - tded = targ; -#if DMDV2 - Objects tiargs; - tiargs.setDim(1); - tiargs.data[0] = (void *)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); - } - return new IntegerExp(1); - -Lno: - return new IntegerExp(0); -} - -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 = (TemplateParameter *)parameters->data[i]; - tp->toCBuffer(buf, hgs); - } - } -#endif - buf->writeByte(')'); -} - - -/************************************************************/ - -UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1) - : Expression(loc, op, size) -{ - this->e1 = e1; -} - -Expression *UnaExp::syntaxCopy() -{ UnaExp *e; - - e = (UnaExp *)copy(); - e->type = NULL; - e->e1 = e->e1->syntaxCopy(); - return e; -} - -Expression *UnaExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("UnaExp::semantic('%s')\n", toChars()); -#endif - e1 = e1->semantic(sc); -// if (!e1->type) -// error("%s has no value", e1->toChars()); - return this; -} - -#if DMDV2 -int UnaExp::canThrow() -{ - return e1->canThrow(); -} -#endif - -void UnaExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -BinExp::BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) - : Expression(loc, op, size) -{ - this->e1 = e1; - this->e2 = e2; -} - -Expression *BinExp::syntaxCopy() -{ BinExp *e; - - e = (BinExp *)copy(); - e->type = NULL; - e->e1 = e->e1->syntaxCopy(); - e->e2 = e->e2->syntaxCopy(); - return e; -} - -Expression *BinExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("BinExp::semantic('%s')\n", toChars()); -#endif - e1 = e1->semantic(sc); - if (!e1->type && - !(op == TOKassign && e1->op == TOKdottd)) // a.template = e2 - { - error("%s has no value", e1->toChars()); - e1 = new ErrorExp(); - } - e2 = e2->semantic(sc); - if (!e2->type) - { - error("%s has no value", e2->toChars()); - e2 = new ErrorExp(); - } - 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; -} - -/*************************** - * Common semantic routine for some xxxAssignExp's. - */ - -Expression *BinExp::commonSemanticAssign(Scope *sc) -{ Expression *e; - - if (!type) - { - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] op= ... - 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()); - } - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - - if (op == TOKmodass && e2->type->iscomplex()) - { error("cannot perform modulo complex arithmetic"); - return new ErrorExp(); - } - } - return this; -} - -Expression *BinExp::commonSemanticAssignIntegral(Scope *sc) -{ Expression *e; - - if (!type) - { - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] op= ... - 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; -} - -int BinExp::checkSideEffect(int flag) -{ - if (op == TOKplusplus || - op == TOKminusminus || - op == TOKassign || - op == TOKconstruct || - op == TOKblit || - op == TOKaddass || - op == TOKminass || - op == TOKcatass || - op == TOKmulass || - op == TOKdivass || - op == TOKmodass || - op == TOKshlass || - op == TOKshrass || - op == TOKushrass || - op == TOKandass || - op == TOKorass || - op == TOKxorass || - op == TOKin || - op == TOKremove) - return 1; - return Expression::checkSideEffect(flag); -} - -// generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary -void BinExp::checkComplexMulAssign() -{ - // Any multiplication by an imaginary or complex number yields a complex result. - // r *= c, i*=c, r*=i, i*=i are all forbidden operations. - const char *opstr = Token::toChars(op); - if ( e1->type->isreal() && e2->type->iscomplex()) - { - error("%s %s %s is undefined. Did you mean %s %s %s.re ?", - e1->type->toChars(), opstr, e2->type->toChars(), - e1->type->toChars(), opstr, e2->type->toChars()); - } - else if (e1->type->isimaginary() && e2->type->iscomplex()) - { - error("%s %s %s is undefined. Did you mean %s %s %s.im ?", - e1->type->toChars(), opstr, e2->type->toChars(), - e1->type->toChars(), opstr, e2->type->toChars()); - } - else if ((e1->type->isreal() || e1->type->isimaginary()) && - e2->type->isimaginary()) - { - error("%s %s %s is an undefined operation", e1->type->toChars(), - opstr, e2->type->toChars()); - } -} - -// generate an error if this is a nonsensical += or -=, eg real += imaginary -void BinExp::checkComplexAddAssign() -{ - // Addition or subtraction of a real and an imaginary is a complex result. - // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. - if ( (e1->type->isreal() && (e2->type->isimaginary() || e2->type->iscomplex())) || - (e1->type->isimaginary() && (e2->type->isreal() || e2->type->iscomplex())) - ) - { - error("%s %s %s is undefined (result is complex)", - e1->type->toChars(), Token::toChars(op), e2->type->toChars()); - } -} - -void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte(' '); - buf->writestring(Token::toChars(op)); - buf->writeByte(' '); - expToCBuffer(buf, hgs, e2, (enum PREC)(precedence[op] + 1)); -} - -int BinExp::isunsigned() -{ - return e1->type->isunsigned() || e2->type->isunsigned(); -} - -#if DMDV2 -int BinExp::canThrow() -{ - return e1->canThrow() || e2->canThrow(); -} -#endif - -void BinExp::incompatibleTypes() -{ - if (e1->type->toBasetype() != Type::terror && - e2->type->toBasetype() != Type::terror - ) - error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", - e1->toChars(), Token::toChars(op), e2->toChars(), - e1->type->toChars(), e2->type->toChars()); -} - -/************************************************************/ - -Expression *BinAssignExp::semantic(Scope *sc) -{ Expression *e; - - //printf("BinAssignExp::semantic()\n"); - if (type) - return this; - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); -#if !IN_LLVM - e2 = e2->castTo(sc, Type::tshiftcnt); -#else - e2 = e2->castTo(sc, e1->type); -#endif - return this; -} - -int BinAssignExp::isLvalue() -{ - return 1; -} - -/************************************************************/ - -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->ctfeInterpret(); - 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 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->ctfeInterpret(); - 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((Strings *)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(); - if (msg) - { - msg = msg->semantic(sc); - msg = resolveProperties(sc, msg); - msg = msg->implicitCastTo(sc, Type::tchar->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; -} - -int AssertExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int AssertExp::canThrow() -{ - /* assert()s are non-recoverable errors, so functions that - * use them can be considered "nothrow" - */ - return 0; //(global.params.useAssert != 0); -} -#endif - -void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("assert("); - expToCBuffer(buf, hgs, e1, PREC_assign); - if (msg) - { - buf->writeByte(','); - expToCBuffer(buf, hgs, msg, PREC_assign); - } - buf->writeByte(')'); -} - -/************************************************************/ - -DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident) - : UnaExp(loc, TOKdot, sizeof(DotIdExp), e) -{ - this->ident = ident; -} - -Expression *DotIdExp::semantic(Scope *sc) -{ Expression *e; - Expression *eleft; - Expression *eright; - -#if LOGSEMANTIC - printf("DotIdExp::semantic(this = %p, '%s')\n", this, toChars()); - //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); -#endif - -//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } - -#if 0 - /* Don't do semantic analysis if we'll be converting - * it to a string. - */ - if (ident == Id::stringof) - { char *s = e1->toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } -#endif - - /* Special case: rewrite this.id and super.id - * to be classtype.id and baseclasstype.id - * if we have no this pointer. - */ - if ((e1->op == TOKthis || e1->op == TOKsuper) && !hasThis(sc)) - { ClassDeclaration *cd; - StructDeclaration *sd; - AggregateDeclaration *ad; - - ad = sc->getStructClassScope(); - if (ad) - { - cd = ad->isClassDeclaration(); - if (cd) - { - if (e1->op == TOKthis) - { - e = typeDotIdExp(loc, cd->type, ident); - return e->semantic(sc); - } - else if (cd->baseClass && e1->op == TOKsuper) - { - e = typeDotIdExp(loc, cd->baseClass->type, ident); - return e->semantic(sc); - } - } - else - { - sd = ad->isStructDeclaration(); - if (sd) - { - if (e1->op == TOKthis) - { - e = typeDotIdExp(loc, sd->type, ident); - return e->semantic(sc); - } - } - } - } - } - - UnaExp::semantic(sc); - - if (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 = (Expression *)te->exps->data[i]; - e = e->semantic(sc); - e = new DotIdExp(e->loc, e, Id::offsetof); - exps->data[i] = (void *)e; - } - e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } -#endif - - if (e1->op == TOKtuple && ident == Id::length) - { - TupleExp *te = (TupleExp *)e1; - e = new IntegerExp(loc, te->exps->dim, Type::tsize_t); - return e; - } - - if (e1->op == TOKdottd) - { - error("template %s does not have property %s", e1->toChars(), ident->toChars()); - return new ErrorExp(); - } - - if (!e1->type) - { - error("expression %s does not have property %s", e1->toChars(), ident->toChars()); - return new ErrorExp(); - } - - 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()); - type = Type::tint32; - return this; - } - type = v->type; - if (v->isSameAsInitializer()) - { - if (v->init) - { - ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { - //printf("\tei: %p (%s)\n", ei->exp, ei->exp->toChars()); - //ei->exp = ei->exp->semantic(sc); - if (ei->exp->type == type) - { - e = ei->exp->copy(); // make copy so we can change loc - e->loc = loc; - return e; - } - } - } - else if (type->isscalar()) - { - e = type->defaultInit(); - e->loc = loc; - return e; - } - } - 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); - 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; - } - s = ie->sds->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(); - } - else if (e1->type->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 *)e1->type)->next; - return e->type->dotExp(sc, e, ident); - } -#if DMDV2 - else if (t1b->ty == Tarray || - t1b->ty == Tsarray || - t1b->ty == Taarray) - { /* If ident is not a valid property, rewrite: - * e1.ident - * as: - * .ident(e1) - */ - unsigned errors = global.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); - 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) - : UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e) -{ - //printf("DotVarExp()\n"); - this->var = v; -} - -Expression *DotVarExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotVarExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - var = var->toAlias()->isDeclaration(); - - TupleDeclaration *tup = var->isTupleDeclaration(); - if (tup) - { /* Replace: - * e1.tuple(a, b, c) - * with: - * tuple(e1.a, e1.b, e1.c) - */ - Expressions *exps = new Expressions; - - exps->reserve(tup->objects->dim); - for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = (Object *)tup->objects->data[i]; - if (o->dyncast() != DYNCAST_EXPRESSION) - { - error("%s is not an expression", o->toChars()); - } - else - { - Expression *e = (Expression *)o; - if (e->op != TOKdsymbol) - error("%s is not a member", e->toChars()); - else - { DsymbolExp *ve = (DsymbolExp *)e; - - e = new DotVarExp(loc, e1, ve->s->isDeclaration()); - exps->push(e); - } - } - } - Expression *e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } - - e1 = e1->semantic(sc); - type = var->type; - if (!type && global.errors) - { // var is goofed up, just return 0 - return new ErrorExp(); - } - assert(type); - - if (!var->isFuncDeclaration()) // for functions, do checks after overload resolution - { - 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(); - if (v && v->isSameAsInitializer()) - { ExpInitializer *ei = v->getExpInitializer(); - if (ei) - { Expression *e = ei->exp->copy(); - e = e->semantic(sc); - return e; - } - if (v->init) - { Expression *e = v->init->toExpression(); - if (e) - { e = e->copy(); - e = e->semantic(sc); - return e; - } - } - } - } - } - //printf("-DotVarExp::semantic('%s')\n", toChars()); - return this; -} - - -int DotVarExp::isLvalue() -{ - return 1; -} - - -Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) -{ - //printf("DotVarExp::toLvalue(%s)\n", toChars()); - return this; -} - -Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) -{ -#if 0 - printf("DotVarExp::modifiableLvalue(%s)\n", toChars()); - printf("e1->type = %s\n", e1->type->toChars()); - printf("var->type = %s\n", var->type->toChars()); -#endif - - if (var->isCtorinit()) - { // It's only modifiable if inside the right constructor - Dsymbol *s = sc->func; - while (1) - { - FuncDeclaration *fd = NULL; - if (s) - fd = s->isFuncDeclaration(); - if (fd && - ((fd->isCtorDeclaration() && var->storage_class & STCfield) || - (fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) && - fd->toParent2() == var->toParent() && - e1->op == TOKthis - ) - { - VarDeclaration *v = var->isVarDeclaration(); - assert(v); - v->ctorinit = 1; - //printf("setting ctorinit\n"); - } - else - { - if (s) - { s = s->toParent2(); - continue; - } - else - { - const char *p = var->isStatic() ? "static " : ""; - error("can only initialize %sconst member %s inside %sconstructor", - p, var->toChars(), p); - } - } - break; - } - } -#if DMDV2 - else - { - Type *t1 = e1->type->toBasetype(); - - if (!t1->isMutable() || - (t1->ty == Tpointer && !t1->nextOf()->isMutable()) || - !var->type->isMutable() || - !var->type->isAssignable() || - var->storage_class & STCmanifest - ) - error("cannot modify const/immutable expression %s", toChars()); - } -#endif - return this; -} - -void DotVarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(var->toChars()); -} - -/************************************************************/ - -/* Things like: - * foo.bar!(args) - */ - -DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti) - : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e) -{ - //printf("DotTemplateInstanceExp()\n"); - this->ti = ti; -} - -Expression *DotTemplateInstanceExp::syntaxCopy() -{ - DotTemplateInstanceExp *de = new DotTemplateInstanceExp(loc, - e1->syntaxCopy(), - (TemplateInstance *)ti->syntaxCopy(NULL)); - return de; -} - -Expression *DotTemplateInstanceExp::semantic(Scope *sc) -{ -#if 1 -#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 (ti->errors) - return new ErrorExp(); - DotTemplateExp *dte = (DotTemplateExp *)e; - TemplateDeclaration *td = dte->td; - eleft = dte->e1; - ti->tempdecl = td; -#if DMDV2 - if (ti->needsTypeInference(sc)) - { - e1 = eleft; // save result of semantic() - return this; - } - else -#endif - ti->semantic(sc); - if (!ti->inst) // if template failed to expand - return new ErrorExp(); - Dsymbol *s = ti->inst->toAlias(); - Declaration *v = s->isDeclaration(); - if (v) - { - /* Fix for Bugzilla 4003 - * The problem is a class template member function v returning a reference to the same - * type as the enclosing template instantiation. This results in a nested instantiation, - * which of course gets short circuited. The return type then gets set to - * the template instance type before instantiation, rather than after. - * We can detect this by the deco not being set. If so, go ahead and retry - * the return type semantic. - * The offending code is the return type from std.typecons.Tuple.slice: - * ref Tuple!(Types[from .. to]) slice(uint from, uint to)() - * { - * return *cast(typeof(return) *) &(field[from]); - * } - * and this line from the following unittest: - * auto s = a.slice!(1, 3); - * where s's type wound up not having semantic() run on it. - */ - if (v->type && !v->type->deco) - v->type = v->type->semantic(v->loc, sc); - - e = new DotVarExp(loc, eleft, v); - e = e->semantic(sc); - return e; - } - e = new ScopeExp(loc, ti); - e = new DotExp(loc, eleft, e); - e = e->semantic(sc); - return e; - } - else if (e->op == TOKimport) - { ScopeExp *se = (ScopeExp *)e; - TemplateDeclaration *td = se->sds->isTemplateDeclaration(); - if (!td) - { error("%s is not a template", e->toChars()); - return new ErrorExp(); - } - ti->tempdecl = td; - e = new ScopeExp(loc, ti); - e = e->semantic(sc); - return e; - } - else if (e->op == TOKdotexp) - { DotExp *de = (DotExp *)e; - - if (de->e2->op == TOKimport) - { // This should *really* be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)de->e2; - de->e2 = new DsymbolExp(loc, se->sds); - de->e2 = de->e2->semantic(sc); - } - - if (de->e2->op == TOKtemplate) - { TemplateExp *te = (TemplateExp *) de->e2; - e = new DotTemplateExp(loc,de->e1,te->td); - } - goto L1; - } - error("%s isn't a template", e->toChars()); - return new ErrorExp(); -#else - Dsymbol *s; - Dsymbol *s2; - TemplateDeclaration *td; - Expression *e; - Identifier *id; - Type *t1; - Expression *eleft = NULL; - Expression *eright; - -#if LOGSEMANTIC - printf("DotTemplateInstanceExp::semantic('%s')\n", toChars()); -#endif - //e1->print(); - //print(); - e1 = e1->semantic(sc); - t1 = e1->type; - if (t1) - t1 = t1->toBasetype(); - //t1->print(); - - /* Extract the following from e1: - * s: the symbol which ti should be a member of - * eleft: if not NULL, it is the 'this' pointer for ti - */ - - if (e1->op == TOKdotexp) - { DotExp *de = (DotExp *)e1; - eleft = de->e1; - eright = de->e2; - } - else - { eleft = NULL; - eright = e1; - } - if (eright->op == TOKimport) - { - s = ((ScopeExp *)eright)->sds; - } - else if (e1->op == TOKtype) - { - s = t1->isClassHandle(); - if (!s) - { if (t1->ty == Tstruct) - s = ((TypeStruct *)t1)->sym; - else - goto L1; - } - } - else if (t1 && (t1->ty == Tstruct || t1->ty == Tclass)) - { - s = t1->toDsymbol(sc); - eleft = e1; - } - else if (t1 && t1->ty == Tpointer) - { - t1 = ((TypePointer *)t1)->next->toBasetype(); - if (t1->ty != Tstruct) - goto L1; - s = t1->toDsymbol(sc); - eleft = e1; - } - else - { - L1: - error("template %s is not a member of %s", ti->toChars(), e1->toChars()); - goto Lerr; - } - - assert(s); - id = ti->name; - s2 = s->search(loc, id, 0); - if (!s2) - { - if (!s->ident) - error("template identifier %s is not a member of undefined %s", id->toChars(), s->kind()); - else - error("template identifier %s is not a member of %s %s", id->toChars(), s->kind(), s->ident->toChars()); - goto Lerr; - } - s = s2; - s->semantic(sc); - s = s->toAlias(); - td = s->isTemplateDeclaration(); - if (!td) - { - error("%s is not a template", id->toChars()); - goto Lerr; - } - if (global.errors) - goto Lerr; - - ti->tempdecl = td; - - if (eleft) - { Declaration *v; - - ti->semantic(sc); - s = ti->inst->toAlias(); - v = s->isDeclaration(); - if (v) - { e = new DotVarExp(loc, eleft, v); - e = e->semantic(sc); - return e; - } - } - - e = new ScopeExp(loc, ti); - if (eleft) - { - e = new DotExp(loc, eleft, e); - } - e = e->semantic(sc); - return e; - -Lerr: - return new IntegerExp(loc, 0, Type::tint32); -#endif -} - -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) - : UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e) -{ - this->func = f; - this->hasOverloads = 0; - m = NULL; -} - -Expression *DelegateExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DelegateExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - m = sc->module; - e1 = e1->semantic(sc); - // LDC we need a copy as we store the LLVM tpye in TypeFunction, and delegate/members have different types for 'this' - type = new TypeDelegate(func->type->syntaxCopy()); - type = type->semantic(loc, sc); - AggregateDeclaration *ad = func->toParent()->isAggregateDeclaration(); - if (func->needThis()) - e1 = getRightThis(loc, sc, ad, e1, func); - if (ad && ad->isClassDeclaration() && ad->type != e1->type) - { // A downcast is required for interfaces, see Bugzilla 3706 - e1 = new CastExp(loc, e1, ad->type); - e1 = e1->semantic(sc); - } - } - return this; -} - -void DelegateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('&'); - if (!func->isNested()) - { - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - } - buf->writestring(func->toChars()); -} - -/************************************************************/ - -DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s) - : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e) -{ - this->sym = s; - this->type = s->getType(); -} - -Expression *DotTypeExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotTypeExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - return this; -} - -void DotTypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(sym->toChars()); -} - -/************************************************************/ - -CallExp::CallExp(Loc loc, Expression *e, Expressions *exps) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - this->arguments = exps; -} - -CallExp::CallExp(Loc loc, Expression *e) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - this->arguments = NULL; -} - -CallExp::CallExp(Loc loc, Expression *e, Expression *earg1) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - Expressions *arguments = new Expressions(); - if (earg1) - { arguments->setDim(1); - arguments->data[0] = (void *)earg1; - } - this->arguments = arguments; -} - -CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - Expressions *arguments = new Expressions(); - arguments->setDim(2); - arguments->data[0] = (void *)earg1; - arguments->data[1] = (void *)earg2; - - this->arguments = arguments; -} - -Expression *CallExp::syntaxCopy() -{ - return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); -} - - -Expression *CallExp::semantic(Scope *sc) -{ - TypeFunction *tf; - FuncDeclaration *f; - Type *t1; - int istemp; - Objects *targsi = NULL; // initial list of template arguments - -#if LOGSEMANTIC - printf("CallExp::semantic() %s\n", toChars()); -#endif - if (type) - return this; // semantic() already run -#if 0 - if (arguments && arguments->dim) - { - Expression *earg = (Expression *)arguments->data[0]; - earg->print(); - if (earg->type) earg->type->print(); - } -#endif - - if (e1->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)e1; - - e1 = new DotVarExp(de->loc, de->e1, de->func); - return semantic(sc); - } - - /* Transform: - * array.id(args) into id(array,args) - * aa.remove(arg) into delete aa[arg] - */ - if (e1->op == TOKdot) - { - // BUG: we should handle array.a.b.c.e(args) too - - DotIdExp *dotid = (DotIdExp *)(e1); - dotid->e1 = dotid->e1->semantic(sc); - assert(dotid->e1); - if (dotid->e1->type) - { - TY e1ty = dotid->e1->type->toBasetype()->ty; - if (e1ty == Taarray && dotid->ident == Id::remove) - { - if (!arguments || arguments->dim != 1) - { error("expected key as argument to aa.remove()"); - goto Lagain; - } - Expression *key = (Expression *)arguments->data[0]; - key = key->semantic(sc); - key = resolveProperties(sc, key); - key->rvalue(); - - TypeAArray *taa = (TypeAArray *)dotid->e1->type->toBasetype(); - key = key->implicitCastTo(sc, taa->index); - key = key->implicitCastTo(sc, taa->key); - - return new RemoveExp(loc, dotid->e1, key); - } - else if (e1ty == Tarray || e1ty == Tsarray || e1ty == Taarray) - { - if (!arguments) - arguments = new Expressions(); - arguments->shift(dotid->e1); -#if DMDV2 - e1 = new DotIdExp(dotid->loc, new IdentifierExp(dotid->loc, Id::empty), dotid->ident); -#else - e1 = new IdentifierExp(dotid->loc, dotid->ident); -#endif - } - } - } - -#if 1 - /* This recognizes: - * foo!(tiargs)(funcargs) - */ - if (e1->op == TOKimport && !e1->type) - { ScopeExp *se = (ScopeExp *)e1; - TemplateInstance *ti = se->sds->isTemplateInstance(); - if (ti && !ti->semanticRun) - { - /* Attempt to instantiate ti. If that works, go with it. - * If not, go with partial explicit specialization. - */ - ti->semanticTiargs(sc); - unsigned errors = global.startGagging(); - ti->semantic(sc); - if (global.endGagging(errors)) - { - /* Didn't work, go with partial explicit specialization - */ - targsi = ti->tiargs; - e1 = new IdentifierExp(loc, ti->name); - } - } - } - - /* This recognizes: - * expr.foo!(tiargs)(funcargs) - */ - if (e1->op == TOKdotti && !e1->type) - { DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)e1; - TemplateInstance *ti = se->ti; - if (!ti->semanticRun) - { - /* Attempt to instantiate ti. If that works, go with it. - * If not, go with partial explicit specialization. - */ - ti->semanticTiargs(sc); - Expression *etmp; - unsigned errors = global.startGagging(); - etmp = e1->semantic(sc); - if (global.endGagging(errors)) - { - targsi = ti->tiargs; - e1 = new DotIdExp(loc, se->e1, ti->name); - } - else - e1 = etmp; - } - } -#endif - - istemp = 0; -Lagain: - //printf("Lagain: %s\n", toChars()); - f = NULL; - if (e1->op == TOKthis || e1->op == TOKsuper) - { - // semantic() run later for these - } - 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) - { - TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd); - TypeDelegate *t = new TypeDelegate(tf); - ve->type = t->semantic(loc, sc); - } - } - - if (e1->op == TOKimport) - { // Perhaps this should be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)e1; - e1 = new DsymbolExp(loc, se->sds); - e1 = e1->semantic(sc); - } -#if DMDV2 - 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 == TOKimport) - { // This should *really* be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)de->e2; - de->e2 = new DsymbolExp(loc, se->sds); - de->e2 = de->e2->semantic(sc); - } - - if (de->e2->op == TOKtemplate) - { TemplateExp *te = (TemplateExp *) de->e2; - e1 = new DotTemplateExp(loc,de->e1,te->td); - } - } -#endif - } - - if (e1->op == TOKcomma) - { - CommaExp *ce = (CommaExp *)e1; - - e1 = ce->e2; - e1->type = ce->type; - ce->e2 = this; - ce->type = NULL; - return ce->semantic(sc); - } - - t1 = NULL; - if (e1->type) - t1 = e1->type->toBasetype(); - - // Check for call operator overload - if (t1) - { AggregateDeclaration *ad; - - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; -#if DMDV2 - // First look for constructor - if (ad->ctor && arguments && arguments->dim) - { - // Create variable that will get constructed - Identifier *idtmp = Lexer::uniqueId("__ctmp"); - VarDeclaration *tmp = new VarDeclaration(loc, t1, idtmp, NULL); - Expression *av = new DeclarationExp(loc, tmp); - av = new CommaExp(loc, av, new VarExp(loc, tmp)); - - Expression *e; - CtorDeclaration *cf = ad->ctor->isCtorDeclaration(); - if (cf) - e = new DotVarExp(loc, av, cf, 1); - else - { TemplateDeclaration *td = ad->ctor->isTemplateDeclaration(); - assert(td); - e = new DotTemplateExp(loc, av, td); - } - e = new CallExp(loc, e, arguments); -#if !STRUCTTHISREF - /* Constructors return a pointer to the instance - */ - e = new PtrExp(loc, e); -#endif - e = e->semantic(sc); - return e; - } -#endif - // No constructor, look for overload of opCall - if (search_function(ad, Id::call)) - goto L1; // overload of opCall, therefore it's a call - - if (e1->op != TOKtype) - error("%s %s does not overload ()", ad->kind(), ad->toChars()); - /* It's a struct literal - */ - Expression *e = new StructLiteralExp(loc, (StructDeclaration *)ad, arguments); - e = e->semantic(sc); - e->type = e1->type; // in case e1->type was a typedef - return e; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - goto L1; - L1: - // Rewrite as e1.call(arguments) - Expression *e = new DotIdExp(loc, e1, Id::call); - e = new CallExp(loc, e, arguments); - e = e->semantic(sc); - return e; - } - } - - arrayExpressionSemantic(arguments, sc); - preFunctionParameters(loc, sc, arguments); - - // If there was an error processing any template argument, - // return an error without trying to resolve the template. - if (targsi && targsi->dim) - { - for (size_t k = 0; k < targsi->dim; k++) - { Object *o = targsi->tdata()[k]; - if (isError(o)) - return new ErrorExp(); - } - } - - 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, NULL, arguments, sc->module); - - 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, NULL, arguments); - if (!f) - return new ErrorExp(); - ad = td->toParent()->isAggregateDeclaration(); - } - if (f->needThis()) - { - ue->e1 = getRightThis(loc, sc, ad, ue->e1, f); - } - - /* Cannot call public functions from inside invariant - * (because then the invariant would have infinite recursion) - */ - if (sc->func && sc->func->isInvariantDeclaration() && - ue->e1->op == TOKthis && - f->addPostInvariant() - ) - { - error("cannot call public/export function %s from invariant", f->toChars()); - return new ErrorExp(); - } - - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); - checkSafety(sc, f); -#endif - accessCheck(loc, sc, ue->e1, f); - if (!f->needThis()) - { - VarExp *ve = new VarExp(loc, f); - 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); - } - - // 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 - { - f = cd->baseClass->ctor; - if (!f) - { 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 = f->overloadResolve(loc, NULL, arguments, sc->module); - 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 - ClassDeclaration *cd = NULL; - - if (sc->func) - cd = sc->func->toParent()->isClassDeclaration(); - if (!cd || !sc->func->isCtorDeclaration()) - { - error("class 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 = cd->ctor; - f = f->overloadResolve(loc, NULL, arguments, sc->module); - 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 (!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); - goto Lcheckargs; - } - else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction) - { - Expression *e = new PtrExp(loc, e1); - t1 = ((TypePointer *)t1)->next; - 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) - { - 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); - - // Look to see if f is really a function template - if (0 && !istemp && f->parent) - { TemplateInstance *ti = f->parent->isTemplateInstance(); - - if (ti && - (ti->name == f->ident || - ti->toAlias()->ident == f->ident) - && - 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) - */ - TemplateDeclaration *tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - e1 = new TemplateExp(loc, tempdecl); - istemp = 1; - goto Lagain; - } - } - - f = f->overloadResolve(loc, NULL, arguments, sc->module); - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); - checkSafety(sc, f); -#endif - - if (f->needThis() && hasThis(sc)) - { - // Supply an implicit 'this', as in - // this.ident - - e1 = new DotVarExp(loc, new ThisExp(loc), f); - goto Lagain; - } - - accessCheck(loc, sc, NULL, f); - - ve->var = f; - ve->type = f->type; - t1 = f->type; - } - assert(t1->ty == Tfunction); - tf = (TypeFunction *)(t1); - -Lcheckargs: - assert(tf->ty == Tfunction); - type = tf->next; - - if (!arguments) - arguments = new Expressions(); - int olderrors = global.errors; - functionParameters(loc, sc, tf, arguments); - 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; -} - -int CallExp::checkSideEffect(int flag) -{ -#if DMDV2 - int result = 1; - - /* Calling a function or delegate that is pure nothrow - * has no side effects. - */ - if (e1->type) - { - Type *t = 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) - ) - { - result = 0; - //if (flag == 0) - //warning("pure nothrow function %s has no effect", e1->toChars()); - } - else - result = 1; - } - - result |= e1->checkSideEffect(1); - - /* If any of the arguments have side effects, this expression does - */ - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; - - result |= e->checkSideEffect(1); - } - - return result; -#else - return 1; -#endif -} - -#if DMDV2 -int CallExp::canThrow() -{ - //printf("CallExp::canThrow() %s\n", toChars()); - if (e1->canThrow()) - return 1; - - /* If any of the arguments can throw, then this expression can throw - */ - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; - - if (e && e->canThrow()) - return 1; - } - - if (global.errors && !e1->type) - return 0; // error recovery - - /* If calling a function or delegate that is typed as nothrow, - * then this expression cannot throw. - * Note that pure functions can throw. - */ - Type *t = e1->type->toBasetype(); - if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow) - return 0; - if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) - return 0; - - return 1; -} -#endif - -int CallExp::isLvalue() -{ - Type *tb = e1->type->toBasetype(); - if (tb->ty == Tdelegate || tb->ty == Tpointer) - tb = tb->nextOf(); -#if DMDV2 - if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) - { - if (e1->op == TOKdotvar) - if (((DotVarExp *)e1)->var->isCtorDeclaration()) - return 0; - return 1; // function returns a reference - } -#endif - return 0; -} - - -Expression *CallExp::toLvalue(Scope *sc, Expression *e) -{ -#if 1 - if (type->toBasetype()->ty == Tstruct) - return this; - else -#endif - return Expression::toLvalue(sc, e); -} - -Expression *CallExp::modifiableLvalue(Scope *sc, Expression *e) -{ -#if 1 - return Expression::modifiableLvalue(sc, e); -#else - /* Although function return values being usable as "ref" parameters is - * unsound, disabling it breaks existing code. - * Bugzilla 3167 - */ - error("cannot assign to function call"); - return toLvalue(sc, e); -#endif -} - -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) -{ - m = NULL; -} - -Expression *AddrExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AddrExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - m = sc->module; - 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) - { Expression *e = new DelegateExp(loc, dve->e1, f); - e = e->semantic(sc); - return e; - } - } - else if (e1->op == TOKvar) - { - VarExp *dve = (VarExp *)e1; - FuncDeclaration *f = dve->var->isFuncDeclaration(); - VarDeclaration *v = dve->var->isVarDeclaration(); - - // LDC - if (f && f->isIntrinsic()) - { - error("cannot take the address of intrinsic function %s", e1->toChars()); - return this; - } - - if (f) - { - if (f->isNested()) - { - if (f->isFuncLiteralDeclaration()) - { - if (!f->FuncDeclaration::isNested()) - { /* Supply a 'null' for a this pointer if no this is available - */ - Expression *e = new DelegateExp(loc, new NullExp(loc, Type::tvoidptr), f); - e = e->semantic(sc); - return e; - } - } - Expression *e = new DelegateExp(loc, e1, f); - e = e->semantic(sc); - return e; - } - } - } - else if (e1->op == TOKarray) - { - if (e1->type->toBasetype()->ty == Tbit) - error("cannot take address of bit in array"); - } - 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) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - if (!e1->type) - printf("PtrExp::semantic('%s')\n", toChars()); - 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; -} - - -int PtrExp::isLvalue() -{ - return 1; -} - - -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) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - 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); - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e = op_overload(sc); - if (e) - return e; - e1->checkNoBool(); - e1->checkArithmetic(); - return e1; -} - -/************************************************************/ - -ComExp::ComExp(Loc loc, Expression *e) - : UnaExp(loc, TOKtilde, sizeof(ComExp), e) -{ -} - -Expression *ComExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e = op_overload(sc); - if (e) - return e; - - e1->checkNoBool(); - if (!e1->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) -{ - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToBoolean(); - type = Type::tboolean; - return this; -} - -int NotExp::isBit() -{ - return TRUE; -} - - - -/************************************************************/ - -BoolExp::BoolExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKtobool, sizeof(BoolExp), e) -{ - type = t; -} - -Expression *BoolExp::semantic(Scope *sc) -{ - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToBoolean(); - type = Type::tboolean; - return this; -} - -int BoolExp::isBit() -{ - return TRUE; -} - -/************************************************************/ - -DeleteExp::DeleteExp(Loc loc, Expression *e) - : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e) -{ -} - -Expression *DeleteExp::semantic(Scope *sc) -{ - Type *tb; - - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->toLvalue(sc, NULL); - 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; - - if (f) - { - Type *tpv = Type::tvoid->pointerTo(); - - Expression *e = e1->castTo(sc, tpv); - Expression *ec = new VarExp(loc, f); - e = new CallExp(loc, ec, e); - return e->semantic(sc); - } - } - break; - - case Tarray: - break; - - default: - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - break; - } - error("cannot delete type %s", e1->type->toChars()); - return new ErrorExp(); - } - - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - { if (!global.params.useDeprecated) - error("delete aa[key] deprecated, use aa.remove(key)"); - } - } - - return this; -} - -int DeleteExp::checkSideEffect(int flag) -{ - return 1; -} - -Expression *DeleteExp::checkToBoolean() -{ - 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; -} - -#if DMDV2 -/* For cast(const) and cast(immutable) - */ -CastExp::CastExp(Loc loc, Expression *e, unsigned mod) - : UnaExp(loc, TOKcast, sizeof(CastExp), e) -{ - to = NULL; - this->mod = mod; -} -#endif - -Expression *CastExp::syntaxCopy() -{ - return new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy()); -} - - -Expression *CastExp::semantic(Scope *sc) -{ Expression *e; - -#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); - to = to->semantic(loc, sc); - - e = op_overload(sc); - if (e) - { - return e->implicitCastTo(sc, to); - } - - if (e1->op == TOKtemplate) - { - error("cannot cast template %s to type %s", e1->toChars(), to->toChars()); - return new ErrorExp(); - } - - Type *t1b = e1->type->toBasetype(); - Type *tob = to->toBasetype(); - if (tob->ty == Tstruct && - !tob->equals(t1b) && - ((TypeStruct *)to)->sym->search(0, Id::call, 0) - ) - { - /* Look to replace: - * cast(S)t - * with: - * S(t) - */ - - // Rewrite as to.call(e1) - e = new TypeExp(loc, to); - e = new DotIdExp(loc, e, Id::call); - e = new CallExp(loc, e, e1); - e = e->semantic(sc); - return e; - } - - // Struct casts are possible only when the sizes match - // 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(); - } - } - } - - if (!e1->type) - { error("cannot cast %s", e1->toChars()); - return new ErrorExp(); - } - - e = e1->castTo(sc, to); - return e; -} - -int CastExp::checkSideEffect(int flag) -{ - /* if not: - * cast(void) - * cast(classtype)func() - */ - if (!to->equals(Type::tvoid) && - !(to->ty == Tclass && e1->op == TOKcall && e1->type->ty == Tclass)) - return Expression::checkSideEffect(flag); - return 1; -} - -void CastExp::checkEscape() -{ Type *tb = type->toBasetype(); - if (tb->ty == Tarray && e1->op == TOKvar && - e1->type->toBasetype()->ty == Tsarray) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg() && !v->isParameter()) - error("escaping reference to local %s", v->toChars()); - } - } -} - -void CastExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("cast("); -#if DMDV1 - to->toCBuffer(buf, NULL, hgs); -#else - if (to) - to->toCBuffer(buf, NULL, hgs); - else - { - MODtoBuffer(buf, mod); - } -#endif - buf->writeByte(')'); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - - -/************************************************************/ - -SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr) - : UnaExp(loc, TOKslice, sizeof(SliceExp), e1) -{ - this->upr = upr; - this->lwr = lwr; - lengthVar = NULL; -} - -Expression *SliceExp::syntaxCopy() -{ - Expression *lwr = NULL; - if (this->lwr) - lwr = this->lwr->syntaxCopy(); - - Expression *upr = NULL; - if (this->upr) - upr = this->upr->syntaxCopy(); - - return new SliceExp(loc, e1->syntaxCopy(), lwr, upr); -} - -Expression *SliceExp::semantic(Scope *sc) -{ Expression *e; - AggregateDeclaration *ad; - //FuncDeclaration *fd; - ScopeDsymbol *sym; - -#if LOGSEMANTIC - printf("SliceExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - e = this; - - Type *t = e1->type->toBasetype(); - if (t->ty == Tpointer) - { - if (!lwr || !upr) - { error("need upper and lower bound to slice pointer"); - return new ErrorExp(); - } - } - else if (t->ty == Tarray) - { - } - else if (t->ty == Tsarray) - { - } - else if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - goto L1; - } - else if (t->ty == Tstruct) - { - ad = ((TypeStruct *)t)->sym; - - L1: - if (search_function(ad, Id::slice)) - { - // Rewrite as e1.slice(lwr, upr) - e = new DotIdExp(loc, e1, Id::slice); - - if (lwr) - { - assert(upr); - e = new CallExp(loc, e, lwr, upr); - } - else - { assert(!upr); - e = new CallExp(loc, e); - } - e = e->semantic(sc); - return e; - } - goto Lerror; - } - else if (t->ty == Ttuple) - { - if (!lwr && !upr) - return e1; - if (!lwr || !upr) - { error("need upper and lower bound to slice tuple"); - goto Lerror; - } - } - else 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(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->ctfeInterpret(); - upr = upr->ctfeInterpret(); - uinteger_t i1 = lwr->toUInteger(); - uinteger_t i2 = upr->toUInteger(); - - size_t length; - TupleExp *te; - TypeTuple *tup; - - if (e1->op == TOKtuple) // slicing an expression tuple - { te = (TupleExp *)e1; - length = te->exps->dim; - } - else if (e1->op == TOKtype) // slicing a type tuple - { tup = (TypeTuple *)t; - length = Parameter::dim(tup->arguments); - } - else - assert(0); - - if (i1 <= i2 && i2 <= length) - { size_t j1 = (size_t) i1; - size_t j2 = (size_t) i2; - - if (e1->op == TOKtuple) - { Expressions *exps = new Expressions; - exps->setDim(j2 - j1); - for (size_t i = 0; i < j2 - j1; i++) - { Expression *e = (Expression *)te->exps->data[j1 + i]; - exps->data[i] = (void *)e; - } - e = new TupleExp(loc, exps); - } - else - { Parameters *args = new Parameters; - args->reserve(j2 - j1); - for (size_t i = j1; i < j2; i++) - { Parameter *arg = Parameter::getNth(tup->arguments, i); - args->push(arg); - } - e = new TypeExp(e1->loc, new TypeTuple(args)); - } - e = e->semantic(sc); - } - else - { - error("string slice [%ju .. %ju] is out of bounds", i1, i2); - goto Lerr; - } - return e; - } - - if (t->ty == Tarray) - { - type = e1->type; - } - else - type = t->nextOf()->arrayOf(); - return e; - -Lerror: - if (e1->op == TOKerror) - return e1; - char *s; - if (t->ty == Tvoid) - s = e1->toChars(); - else - s = t->toChars(); - error("%s cannot be sliced with []", s); -Lerr: - e = new ErrorExp(); - return e; -} - -void SliceExp::checkEscape() -{ - e1->checkEscape(); -} - -void SliceExp::checkEscapeRef() -{ - e1->checkEscapeRef(); -} - - -int SliceExp::isLvalue() -{ - return 1; -} - - -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(']'); -} - -int SliceExp::canThrow() -{ - return UnaExp::canThrow() - || (lwr != NULL && lwr->canThrow()) - || (upr != NULL && upr->canThrow()); -} - -/********************** 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; -} - -void ArrayLengthExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writestring(".length"); -} - -/*********************** ArrayExp *************************************/ - -// e1 [ i1, i2, i3, ... ] - -ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args) - : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1) -{ - arguments = args; -} - -Expression *ArrayExp::syntaxCopy() -{ - return new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); -} - -Expression *ArrayExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - -#if LOGSEMANTIC - printf("ArrayExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - if (e1->op == TOKerror) - return 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)[0]); - return e->semantic(sc); - } - - // Run semantic() on each argument - for (size_t i = 0; i < arguments->dim; i++) - { e = (*arguments)[i]; - - e = e->semantic(sc); - if (!e->type) - { error("%s has no value", e->toChars()); - goto Lerr; - } - else if (e->type == Type::terror) - goto Lerr; - (*arguments)[i] = e; - } - - expandTuples(arguments); - assert(arguments && arguments->dim); - - e = op_overload(sc); - if (!e) - { error("no [] operator overload for type %s", e1->type->toChars()); - goto Lerr; - } - return e; - -Lerr: - return new ErrorExp(); -} - - -int ArrayExp::isLvalue() -{ - if (type && type->toBasetype()->ty == Tvoid) - return 0; - return 1; -} - - -Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) -{ - if (type && type->toBasetype()->ty == Tvoid) - error("voids have no value"); - return this; -} - - -void ArrayExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('['); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(']'); -} - -/************************* DotExp ***********************************/ - -DotExp::DotExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdotexp, sizeof(DotExp), e1, e2) -{ -} - -Expression *DotExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotExp::semantic('%s')\n", toChars()); - if (type) printf("\ttype = %s\n", type->toChars()); -#endif - e1 = e1->semantic(sc); - e2 = e2->semantic(sc); - if (e2->op == TOKimport) - { - ScopeExp *se = (ScopeExp *)e2; - TemplateDeclaration *td = se->sds->isTemplateDeclaration(); - if (td) - { Expression *e = new DotTemplateExp(loc, e1, td); - e = e->semantic(sc); - return e; - } - } - if (!type) - type = e2->type; - return this; -} - -void DotExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - expToCBuffer(buf, hgs, e2, PREC_primary); -} - -/************************* CommaExp ***********************************/ - -CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2) -{ -} - -Expression *CommaExp::semantic(Scope *sc) -{ - if (!type) - { BinExp::semanticp(sc); - type = e2->type; - } - return this; -} - -void CommaExp::checkEscape() -{ - e2->checkEscape(); -} - -void CommaExp::checkEscapeRef() -{ - e2->checkEscapeRef(); -} - - -int CommaExp::isLvalue() -{ - return e2->isLvalue(); -} - - -Expression *CommaExp::toLvalue(Scope *sc, Expression *e) -{ - e2 = e2->toLvalue(sc, NULL); - return this; -} - -Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e) -{ - e2 = e2->modifiableLvalue(sc, e); - return this; -} - -int CommaExp::isBool(int result) -{ - return e2->isBool(result); -} - -int CommaExp::checkSideEffect(int flag) -{ - if (flag == 2) - return e1->hasSideEffect() || e2->hasSideEffect(); - else - { - // Don't check e1 until we cast(void) the a,b code generation - return e2->checkSideEffect(flag); - } -} - -/************************** IndexExp **********************************/ - -// e1 [ e2 ] - -IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2) -{ - //printf("IndexExp::IndexExp('%s')\n", toChars()); - lengthVar = NULL; - modifiable = 0; // assume it is an rvalue -} - -Expression *IndexExp::semantic(Scope *sc) -{ Expression *e; - 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(this); - sym->loc = loc; - sym->parent = sc->scopesym; - sc = sc->push(sym); - } - - e2 = e2->semantic(sc); - if (!e2->type) - { - error("%s has no value", e2->toChars()); - goto Lerr; - } - if (e2->type->ty == Ttuple && ((TupleExp *)e2)->exps->dim == 1) // bug 4444 fix - e2 = (*((TupleExp *)e2)->exps)[0]; - e2 = resolveProperties(sc, e2); - if (e2->type == Type::terror) - goto Lerr; - - if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) - sc = sc->pop(); - - switch (t1->ty) - { - case Tpointer: - case Tarray: - e2 = e2->implicitCastTo(sc, Type::tsize_t); - e->type = 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; - - e2 = e2->implicitCastTo(sc, taa->index); // type checking - e2 = e2->implicitCastTo(sc, taa->key); // actual argument type - type = taa->next; - break; - } - - case Ttuple: - { - e2 = e2->implicitCastTo(sc, Type::tsize_t); - e2 = e2->optimize(WANTvalue); - uinteger_t index = e2->toUInteger(); - size_t length; - TupleExp *te; - TypeTuple *tup; - - if (e1->op == TOKtuple) - { te = (TupleExp *)e1; - length = te->exps->dim; - } - else if (e1->op == TOKtype) - { - tup = (TypeTuple *)t1; - length = Parameter::dim(tup->arguments); - } - else - assert(0); - - if (index < length) - { - - if (e1->op == TOKtuple) - e = (Expression *)te->exps->data[(size_t)index]; - else - e = new TypeExp(e1->loc, Parameter::getNth(tup->arguments, (size_t)index)->type); - } - else - { - error("array index [%ju] is outside array bounds [0 .. %zu]", - index, length); - e = e1; - } - break; - } - - default: - 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(); -} - - -int IndexExp::isLvalue() -{ - return 1; -} - - -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 (e1->type->toBasetype()->ty == Taarray) - e1 = e1->modifiableLvalue(sc, e1); - return toLvalue(sc, e); -} - -void IndexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('['); - expToCBuffer(buf, hgs, e2, PREC_assign); - buf->writeByte(']'); -} - - -/************************* PostExp ***********************************/ - -PostExp::PostExp(enum TOK op, Loc loc, Expression *e) - : BinExp(loc, op, sizeof(PostExp), e, - new IntegerExp(loc, 1, Type::tint32)) -{ -} - -Expression *PostExp::semantic(Scope *sc) -{ Expression *e = this; - - if (!type) - { - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e = this; - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - if (e1->type->ty == Tpointer) - e = scaleFactor(sc); - else - e2 = e2->castTo(sc, e1->type); - e->type = e1->type; - } - return e; -} - -void PostExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writestring((op == TOKplusplus) ? (char *)"++" : (char *)"--"); -} - -/************************************************************/ - -/* op can be TOKassign, TOKconstruct, or TOKblit */ - -AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2) -{ - ismemset = 0; -} - -Expression *AssignExp::semantic(Scope *sc) -{ - Expression *e1old = e1; - -#if LOGSEMANTIC - printf("AssignExp::semantic('%s')\n", toChars()); -#endif - //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); - //printf("e2->op = %d, '%s'\n", e2->op, Token::toChars(e2->op)); - - if (type) - return this; - - if (e2->op == TOKcomma) - { /* Rewrite to get rid of the comma from rvalue - */ - AssignExp *ea = new AssignExp(loc, e1, ((CommaExp *)e2)->e2); - ea->op = op; - Expression *e = new CommaExp(loc, ((CommaExp *)e2)->e1, ea); - return e->semantic(sc); - } - - /* Look for operator overloading of a[i]=value. - * Do it before semantic() otherwise the a[i] will have been - * converted to a.opIndex() already. - */ - if (e1->op == TOKarray) - { - ArrayExp *ae = (ArrayExp *)e1; - AggregateDeclaration *ad = NULL; - Identifier *id = Id::index; - - ae->e1 = ae->e1->semantic(sc); - ae->e1 = resolveProperties(sc, ae->e1); - Type *t1 = ae->e1->type->toBasetype(); - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - goto L1; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - L1: - // Rewrite (a[i] = value) to (a.opIndexAssign(value, i)) - if (search_function(ad, Id::indexass)) - { Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); - Expressions *a = (Expressions *)ae->arguments->copy(); - - a->insert(0, e2); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - else - { - // Rewrite (a[i] = value) to (a.opIndex(i, value)) - if (search_function(ad, id)) - { Expression *e = new DotIdExp(loc, ae->e1, id); - - if (1 || !global.params.useDeprecated) - { error("operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i)"); - return new ErrorExp(); - } - - e = new CallExp(loc, e, (Expression *)ae->arguments->data[0], e2); - e = e->semantic(sc); - return e; - } - } - } - } - /* Look for operator overloading of a[i..j]=value. - * Do it before semantic() otherwise the a[i..j] will have been - * converted to a.opSlice() already. - */ - if (e1->op == TOKslice) - { Type *t1; - SliceExp *ae = (SliceExp *)e1; - AggregateDeclaration *ad = 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.opIndexAssign(value, i, j)) - if (search_function(ad, Id::sliceass)) - { Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass); - Expressions *a = new Expressions(); - - a->push(e2); - if (ae->lwr) - { a->push(ae->lwr); - assert(ae->upr); - a->push(ae->upr); - } - else - assert(!ae->upr); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - } - } - - Expression *e = BinExp::semantic(sc); - if (e->op == TOKerror) - return e; - - if (e1->op == TOKdottd) - { // Rewrite a.b=e2, when b is a template, as a.b(e2) - Expression *e = new CallExp(loc, e1, e2); - e = e->semantic(sc); - return e; - } - - e2 = resolveProperties(sc, e2); - assert(e1->type); - - /* Rewrite tuple assignment as a tuple of assignments. - */ - if (e1->op == TOKtuple && e2->op == TOKtuple) - { TupleExp *tup1 = (TupleExp *)e1; - TupleExp *tup2 = (TupleExp *)e2; - size_t dim = tup1->exps->dim; - if (dim != tup2->exps->dim) - { - error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim); - } - else - { Expressions *exps = new Expressions; - exps->setDim(dim); - - for (size_t i = 0; i < dim; i++) - { Expression *ex1 = (Expression *)tup1->exps->data[i]; - Expression *ex2 = (Expression *)tup2->exps->data[i]; - exps->data[i] = (void *) new AssignExp(loc, ex1, ex2); - } - Expression *e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } - } - - // Determine if this is an initialization of a reference - int refinit = 0; - if (op == TOKconstruct && e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v->storage_class & (STCout | STCref)) - refinit = 1; - } - - Type *t1 = e1->type->toBasetype(); - - if (t1->ty == Tfunction) - { // Rewrite f=value to f(value) - Expression *e = new CallExp(loc, e1, e2); - e = e->semantic(sc); - return e; - } - - /* If it is an assignment from a 'foreign' type, - * check for operator overloading. - */ - if (t1->ty == Tclass || t1->ty == Tstruct) - { // Disallow assignment operator overloads for same type - if (/*op == TOKassign &&*/ // construction shouldn't be allowed, but OK to avoid breaking existing code - !e2->implicitConvTo(e1->type)) - { - Expression *e = op_overload(sc); - if (e) - return e; - } - } - - 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) - ; - else - { // Try to do a decent error message with the expression - // before it got constant folded - if (op != TOKconstruct) - e1 = e1->modifiableLvalue(sc, e1old); - } - - // If it is a array, get the element type. Note that it may be - // multi-dimensional. - Type *telem = t1; - while (telem->ty == Tarray) - telem = telem->nextOf(); - - // Check for block assignment. If it is of type void[], void[][], etc, - // '= null' is the only allowable block assignment (Bug 7493) - if (e1->op == TOKslice && - t1->nextOf() && (telem->ty != Tvoid || e2->op == TOKnull) && - e2->implicitConvTo(t1->nextOf()) -// !(t1->nextOf()->equals(e2->type->nextOf())) - ) - { // memset - ismemset = 1; // make it easy for back end to tell what this is - e2 = e2->implicitCastTo(sc, t1->next); - } - else if (t1->ty == Tsarray && !refinit) - { - error("cannot assign to static array %s", e1->toChars()); - } - 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() -{ - // 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; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if (e1->op == TOKslice) - { - 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; - e = this; - } - else - { - e1->checkScalar(); - e1->checkNoBool(); - if (tb1->ty == Tpointer && tb2->isintegral()) - e = scaleFactor(sc); - else if (tb1->ty == Tbit || tb1->ty == Tbool) - { -#if 0 - // Need to rethink this - if (e1->op != TOKvar) - { // Rewrite e1+=e2 to (v=&e1),*v=*v+e2 - VarDeclaration *v; - Expression *ea; - Expression *ex; - - Identifier *id = Lexer::uniqueId("__name"); - - v = new VarDeclaration(loc, tb1->pointerTo(), id, NULL); - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - - ea = new AddrExp(loc, e1); - ea = new AssignExp(loc, new VarExp(loc, v), ea); - - ex = new VarExp(loc, v); - ex = new PtrExp(loc, ex); - e = new AddExp(loc, ex, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, ex->syntaxCopy(), e); - - e = new CommaExp(loc, ea, e); - } - else -#endif - { // Rewrite e1+=e2 to e1=e1+e2 - // BUG: doesn't account for side effects in e1 - // BUG: other assignment operators for bits aren't handled at all - e = new AddExp(loc, e1, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, e1->syntaxCopy(), e); - } - e = e->semantic(sc); - } - else - { - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - checkComplexAddAssign(); - if (type->isreal() || type->isimaginary()) - { - assert(global.errors || e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - } - return e; -} - -/************************************************************/ - -MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2) -{ -} - -Expression *MinAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - 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; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { SliceExp *se = (SliceExp *)e1; - - if (se->e1->type->toBasetype()->ty == Tsarray) - { error("cannot append to static array %s", se->e1->type->toChars()); - return new ErrorExp(); - } - } - - e1 = e1->modifiableLvalue(sc, e1); - if (e1->op == TOKerror) - return 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; -// Reenable when _d_arrayappendwd and cd are in the runtime. -/* } - - 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->ty == Tarray) && - e2->implicitConvTo(tb1next) - ) - { // Append element - e2 = e2->castTo(sc, tb1next); - type = e1->type; - e = this; - } - 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; - - if (type) - return this; - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - 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->isfloating()) - { Type *t1; - Type *t2; - - t1 = e1->type; - t2 = e2->type; - if (t1->isreal()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - e2 = e2->castTo(sc, t1); - } - } - else if (t1->isimaginary()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - } - } - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - return this; -} - -/************************************************************/ - -DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2) -{ -} - -Expression *DivAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - 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; - Type *t2; - - t1 = e1->type; - if (t1->isreal()) - { // x/iv = i(-x/v) - // Therefore, the result is 0 - e2 = new CommaExp(loc, e2, new RealExp(loc, ldouble(0), t1)); - e2->type = t1; - e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - else if (t1->isimaginary()) - { Expression *e; - - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - } - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - - return this; -} - -/************************************************************/ - -ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2) -{ -} - -Expression *ModAssignExp::semantic(Scope *sc) -{ - if (type) - return this; - BinExp::semantic(sc); - checkComplexMulAssign(); - return commonSemanticAssign(sc); -} - -/************************************************************/ - -ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2) -{ -} - -/************************************************************/ - -ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2) -{ -} - -/************************************************************/ - -UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2) -{ -} - -/************************************************************/ - -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); -} - -/************************* AddExp *****************************/ - -AddExp::AddExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2) -{ -} - -Expression *AddExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("AddExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - BinExp::semanticp(sc); - - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if ((tb1->ty == Tarray || tb1->ty == Tsarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - tb1->nextOf()->equals(tb2->nextOf()) - ) - { - type = e1->type; - e = this; - } - else if (tb1->ty == Tpointer && e2->type->isintegral() || - tb2->ty == Tpointer && e1->type->isintegral()) - e = scaleFactor(sc); - else if (tb1->ty == Tpointer && tb2->ty == Tpointer) - { - incompatibleTypes(); - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if ((e1->type->isreal() && e2->type->isimaginary()) || - (e1->type->isimaginary() && e2->type->isreal())) - { - switch (type->toBasetype()->ty) - { - case Tfloat32: - case Timaginary32: - type = Type::tcomplex32; - break; - - case Tfloat64: - case Timaginary64: - type = Type::tcomplex64; - break; - - case Tfloat80: - case Timaginary80: - type = Type::tcomplex80; - break; - - default: - assert(0); - } - } - e = this; - } - return e; - } - return this; -} - -/************************************************************/ - -MinExp::MinExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmin, sizeof(MinExp), e1, e2) -{ -} - -Expression *MinExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - Type *t2; - -#if LOGSEMANTIC - printf("MinExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - BinExp::semanticp(sc); - - e = op_overload(sc); - if (e) - return e; - - e = this; - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if (t1->ty == Tpointer) - { - if (t2->ty == Tpointer) - { // Need to divide the result by the stride - // Replace (ptr - ptr) with (ptr - ptr) / stride - d_int64 stride; - Expression *e; - - typeCombine(sc); // make sure pointer types are compatible - type = Type::tptrdiff_t; - stride = t2->nextOf()->size(); - if (stride == 0) - { - e = new IntegerExp(loc, 0, Type::tptrdiff_t); - } - else - { - e = new DivExp(loc, this, new IntegerExp(0, stride, Type::tptrdiff_t)); - e->type = Type::tptrdiff_t; - } - return e; - } - else if (t2->isintegral()) - e = scaleFactor(sc); - else - { error("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->isreal() && t2->isimaginary()) || - (t1->isimaginary() && t2->isreal())) - { - switch (type->ty) - { - case Tfloat32: - case Timaginary32: - type = Type::tcomplex32; - break; - - case Tfloat64: - case Timaginary64: - type = Type::tcomplex64; - break; - - case Tfloat80: - case Timaginary80: - type = Type::tcomplex80; - break; - - default: - assert(0); - } - } - } - return e; -} - -/************************* CatExp *****************************/ - -CatExp::CatExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcat, sizeof(CatExp), e1, e2) -{ -} - -Expression *CatExp::semantic(Scope *sc) -{ Expression *e; - - //printf("CatExp::semantic() %s\n", toChars()); - if (!type) - { - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - - /* BUG: Should handle things like: - * char c; - * c ~ ' ' - * ' ' ~ c; - */ - -#if 0 - e1->type->print(); - e2->type->print(); -#endif - if ((tb1->ty == Tsarray || tb1->ty == Tarray) && - e2->type->equals(tb1->next)) - { - type = tb1->nextOf()->arrayOf(); - if (tb2->ty == Tarray) - { // Make e2 into [e2] - e2 = new ArrayLiteralExp(e2->loc, e2); - e2->type = type; - } - return this; - } - else if ((tb2->ty == Tsarray || tb2->ty == Tarray) && - e1->type->equals(tb2->next)) - { - type = tb2->nextOf()->arrayOf(); - if (tb1->ty == Tarray) - { // Make e1 into [e1] - e1 = new ArrayLiteralExp(e1->loc, e1); - e1->type = type; - } - return this; - } - - typeCombine(sc); - - if (type->toBasetype()->ty == Tsarray) - type = type->toBasetype()->next->arrayOf(); -#if 0 - e1->type->print(); - e2->type->print(); - type->print(); - print(); -#endif - if (e1->op == TOKstring && e2->op == TOKstring) - e = optimize(WANTvalue); - else if (e1->type->equals(e2->type) && - (e1->type->toBasetype()->ty == Tarray || - e1->type->toBasetype()->ty == Tsarray)) - { - e = this; - } - else - { - //printf("(%s) ~ (%s)\n", e1->toChars(), e2->toChars()); - error("Can only concatenate arrays, not (%s ~ %s)", - e1->type->toChars(), e2->type->toChars()); - type = Type::tint32; - e = this; - } - e->type = e->type->semantic(loc, sc); - return e; - } - return this; -} - -/************************************************************/ - -MulExp::MulExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmul, sizeof(MulExp), e1, e2) -{ -} - -Expression *MulExp::semantic(Scope *sc) -{ Expression *e; - -#if 0 - printf("MulExp::semantic() %s\n", toChars()); -#endif - if (type) - { - return this; - } - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkArithmetic(); - if (!e2->isArrayOperand()) - e2->checkArithmetic(); - if (type->isfloating()) - { Type *t1 = e1->type; - Type *t2 = e2->type; - - if (t1->isreal()) - { - type = t2; - } - else if (t2->isreal()) - { - type = t1; - } - else if (t1->isimaginary()) - { - if (t2->isimaginary()) - { Expression *e; - - switch (t1->toBasetype()->ty) - { - case Timaginary32: type = Type::tfloat32; break; - case Timaginary64: type = Type::tfloat64; break; - case Timaginary80: type = Type::tfloat80; break; - default: assert(0); - } - - // iy * iv = -yv - e1->type = type; - e2->type = type; - e = new NegExp(loc, this); - e = e->semantic(sc); - return e; - } - else - type = t2; // t2 is complex - } - else if (t2->isimaginary()) - { - type = t1; // t1 is complex - } - } - return this; -} - -/************************************************************/ - -DivExp::DivExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2) -{ -} - -Expression *DivExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkArithmetic(); - if (!e2->isArrayOperand()) - e2->checkArithmetic(); - if (type->isfloating()) - { Type *t1 = e1->type; - Type *t2 = e2->type; - - if (t1->isreal()) - { - type = t2; - if (t2->isimaginary()) - { Expression *e; - - // x/iv = i(-x/v) - e2->type = t1; - e = new NegExp(loc, this); - e = e->semantic(sc); - return e; - } - } - else if (t2->isreal()) - { - type = t1; - } - else if (t1->isimaginary()) - { - if (t2->isimaginary()) - { - switch (t1->toBasetype()->ty) - { - case Timaginary32: type = Type::tfloat32; break; - case Timaginary64: type = Type::tfloat64; break; - case Timaginary80: type = Type::tfloat80; break; - default: assert(0); - } - } - else - type = t2; // t2 is complex - } - else if (t2->isimaginary()) - { - type = t1; // t1 is complex - } - } - return this; -} - -/************************************************************/ - -ModExp::ModExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2) -{ -} - -Expression *ModExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkArithmetic(); - if (!e2->isArrayOperand()) - e2->checkArithmetic(); - if (type->isfloating()) - { type = e1->type; - if (e2->type->iscomplex()) - { error("cannot perform modulo complex arithmetic"); - return new IntegerExp(0); - } - } - return this; -} - -/************************************************************/ - -ShlExp::ShlExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshl, sizeof(ShlExp), e1, e2) -{ -} - -Expression *ShlExp::semantic(Scope *sc) -{ Expression *e; - - //printf("ShlExp::semantic(), type = %p\n", type); - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); -#if !IN_LLVM - e2 = e2->castTo(sc, Type::tshiftcnt); -#else - e2 = e2->castTo(sc, e1->type); -#endif - type = e1->type; - } - return this; -} - -/************************************************************/ - -ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2) -{ -} - -Expression *ShrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); -#if !IN_LLVM - e2 = e2->castTo(sc, Type::tshiftcnt); -#else - e2 = e2->castTo(sc, e1->type); -#endif - type = e1->type; - } - return this; -} - -/************************************************************/ - -UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2) -{ -} - -Expression *UshrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); -#if !IN_LLVM - e2 = e2->castTo(sc, Type::tshiftcnt); -#else - e2 = e2->castTo(sc, e1->type); -#endif - 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(); - 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(); - 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() -{ - e2 = e2->checkToBoolean(); - return this; -} - -int OrOrExp::isBit() -{ - return TRUE; -} - -int OrOrExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return e1->hasSideEffect() || e2->hasSideEffect(); - } - else - { e1->checkSideEffect(1); - return e2->checkSideEffect(flag); - } -} - -/************************************************************/ - -AndAndExp::AndAndExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKandand, sizeof(AndAndExp), e1, e2) -{ -} - -Expression *AndAndExp::semantic(Scope *sc) -{ - unsigned cs1; - - // same as for OrOr - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToPointer(); - e1 = e1->checkToBoolean(); - cs1 = sc->callSuper; - - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate e2 if we don't have to. - */ - e1 = e1->optimize(WANTflags); - if (e1->isBool(FALSE)) - { - return new IntegerExp(loc, 0, Type::tboolean); - } - } - - e2 = e2->semantic(sc); - sc->mergeCallSuper(loc, cs1); - e2 = resolveProperties(sc, e2); - e2 = e2->checkToPointer(); - - if (e2->type->ty == Tvoid) - type = Type::tvoid; - else - { - e2 = e2->checkToBoolean(); - 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() -{ - e2 = e2->checkToBoolean(); - return this; -} - -int AndAndExp::isBit() -{ - return TRUE; -} - -int AndAndExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return e1->hasSideEffect() || e2->hasSideEffect(); - } - else - { - e1->checkSideEffect(1); - return e2->checkSideEffect(flag); - } -} - -/************************************************************/ - -InExp::InExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKin, sizeof(InExp), e1, e2) -{ -} - -Expression *InExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - //type = Type::tboolean; - Type *t2b = e2->type->toBasetype(); - switch (t2b->ty) - { - case Taarray: - { - TypeAArray *ta = (TypeAArray *)t2b; - -#if DMDV2 - // Special handling for array keys - if (!arrayTypeCompatible(e1->loc, e1->type, ta->index)) -#endif - { - // Convert key to type of key - e1 = e1->implicitCastTo(sc, ta->index); - } - - // Return type is pointer to value - type = ta->nextOf()->pointerTo(); - break; - } - - default: - error("rvalue of in expression must be an associative array, not %s", e2->type->toChars()); - case Terror: - return new ErrorExp(); - } - return this; -} - -int InExp::isBit() -{ - return FALSE; -} - - -/************************************************************/ - -/* This deletes the key e1 from the associative array e2 - */ - -RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2) -{ - type = Type::tvoid; -} - -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"); - } - - e = op_overload(sc); - if (e) - { - if (!e->type->isscalar() && e->type->equals(e1->type)) - { - error("recursive opCmp expansion"); - e = new ErrorExp(); - } - else - { e = new CmpExp(op, loc, e, new IntegerExp(loc, 0, Type::tint32)); - e = e->semantic(sc); - } - return e; - } - - /* Disallow comparing T[]==T and T==T[] - */ - if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) || - e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) - { - incompatibleTypes(); - return new ErrorExp(); - } - - typeCombine(sc); - type = Type::tboolean; - - // Special handling for array comparisons - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if ((t1->ty == Tarray || t1->ty == Tsarray) && - (t2->ty == Tarray || t2->ty == Tsarray)) - { - if (!t1->next->equals(t2->next)) - error("array comparison type mismatch, %s vs %s", t1->next->toChars(), t2->next->toChars()); - e = this; - } - else if (t1->ty == Tstruct || t2->ty == Tstruct || - (t1->ty == Tclass && t2->ty == Tclass)) - { - if (t2->ty == Tstruct) - error("need member function opCmp() for %s %s to compare", t2->toDsymbol(sc)->kind(), t2->toChars()); - else - error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars()); - e = this; - } -#if 1 - else if (t1->iscomplex() || t2->iscomplex()) - { - error("compare not defined for complex operands"); - e = new IntegerExp(0); - } -#endif - else - e = this; - //printf("CmpExp: %s\n", e->toChars()); - return e; -} - -int CmpExp::isBit() -{ - return TRUE; -} - - -/************************************************************/ - -EqualExp::EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(EqualExp), e1, e2) -{ - assert(op == TOKequal || op == TOKnotequal); -} - -Expression *EqualExp::semantic(Scope *sc) -{ Expression *e; - - //printf("EqualExp::semantic('%s')\n", toChars()); - if (type) - return this; - - BinExp::semanticp(sc); - - /* Before checking for operator overloading, check to see if we're - * comparing the addresses of two statics. If so, we can just see - * if they are the same symbol. - */ - if (e1->op == TOKaddress && e2->op == TOKaddress) - { AddrExp *ae1 = (AddrExp *)e1; - AddrExp *ae2 = (AddrExp *)e2; - - if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar) - { VarExp *ve1 = (VarExp *)ae1->e1; - VarExp *ve2 = (VarExp *)ae2->e1; - - if (ve1->var == ve2->var /*|| ve1->var->toSymbol() == ve2->var->toSymbol()*/) - { - // They are the same, result is 'true' for ==, 'false' for != - e = new IntegerExp(loc, (op == TOKequal), Type::tboolean); - return e; - } - } - } - - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - if (t1->ty == Tclass && e2->op == TOKnull || - t2->ty == Tclass && e1->op == TOKnull) - { - error("use '%s' instead of '%s' when comparing with null", - Token::toChars(op == TOKequal ? TOKidentity : TOKnotidentity), - Token::toChars(op)); - } - - //if (e2->op != TOKnull) - { - e = op_overload(sc); - if (e) - { - if (op == TOKnotequal) - { - e = new NotExp(e->loc, e); - e = e->semantic(sc); - } - return e; - } - } - - /* Disallow comparing T[]==T and T==T[] - */ - if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) || - e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) - { - incompatibleTypes(); - return new ErrorExp(); - } - - e = typeCombine(sc); - type = Type::tboolean; - - // Special handling for array comparisons - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if ((t1->ty == Tarray || t1->ty == Tsarray) && - (t2->ty == Tarray || t2->ty == Tsarray)) - { - if (!t1->next->equals(t2->next)) - error("array comparison type mismatch, %s vs %s", t1->next->toChars(), t2->next->toChars()); - } - else - { - if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) - { - // Cast both to complex - e1 = e1->castTo(sc, Type::tcomplex80); - e2 = e2->castTo(sc, Type::tcomplex80); - } - } - return e; -} - -int EqualExp::isBit() -{ - return TRUE; -} - - - -/************************************************************/ - -IdentityExp::IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(IdentityExp), e1, e2) -{ -} - -Expression *IdentityExp::semantic(Scope *sc) -{ - if (type) - return this; - - BinExp::semanticp(sc); - type = Type::tboolean; - typeCombine(sc); - if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) - { - // Cast both to complex - e1 = e1->castTo(sc, Type::tcomplex80); - e2 = e2->castTo(sc, Type::tcomplex80); - } - return this; -} - -int IdentityExp::isBit() -{ - return TRUE; -} - - -/****************************************************************/ - -CondExp::CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2) - : BinExp(loc, TOKquestion, sizeof(CondExp), e1, e2) -{ - this->econd = econd; -} - -Expression *CondExp::syntaxCopy() -{ - return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy()); -} - - -Expression *CondExp::semantic(Scope *sc) -{ Type *t1; - Type *t2; - unsigned cs0; - unsigned cs1; - -#if LOGSEMANTIC - printf("CondExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - econd = econd->semantic(sc); - econd = resolveProperties(sc, econd); - econd = econd->checkToPointer(); - econd = econd->checkToBoolean(); - -#if 0 /* this cannot work right because the types of e1 and e2 - * both contribute to the type of the result. - */ - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate what we don't have to. - */ - econd = econd->optimize(WANTflags); - if (econd->isBool(TRUE)) - { - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - return e1; - } - else if (econd->isBool(FALSE)) - { - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - return e2; - } - } -#endif - - - cs0 = sc->callSuper; - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - cs1 = sc->callSuper; - sc->callSuper = cs0; - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - sc->mergeCallSuper(loc, cs1); - - - // If either operand is void, the result is void - t1 = e1->type; - t2 = e2->type; - if (t1->ty == Tvoid || t2->ty == Tvoid) - type = Type::tvoid; - else if (t1 == t2) - type = t1; - else - { - typeCombine(sc); - switch (e1->type->toBasetype()->ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - e2 = e2->castTo(sc, e1->type); - break; - } - switch (e2->type->toBasetype()->ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - e1 = e1->castTo(sc, e2->type); - break; - } - } -#if 0 - printf("res: %s\n", type->toChars()); - printf("e1 : %s\n", e1->type->toChars()); - printf("e2 : %s\n", e2->type->toChars()); -#endif - return this; -} - - -int CondExp::isLvalue() -{ - return e1->isLvalue() && e2->isLvalue(); -} - - -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()); - return this; -} - -void CondExp::checkEscape() -{ - e1->checkEscape(); - e2->checkEscape(); -} - -void CondExp::checkEscapeRef() -{ - e1->checkEscapeRef(); - e2->checkEscapeRef(); -} - - -Expression *CondExp::checkToBoolean() -{ - e1 = e1->checkToBoolean(); - e2 = e2->checkToBoolean(); - return this; -} - -int CondExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return econd->hasSideEffect() || - e1->hasSideEffect() || - e2->hasSideEffect(); - } - else - { - econd->checkSideEffect(1); - e1->checkSideEffect(flag); - return e2->checkSideEffect(flag); - } -} - -#if DMDV2 -int CondExp::canThrow() -{ - return econd->canThrow() || e1->canThrow() || e2->canThrow(); -} -#endif - -void CondExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, econd, PREC_oror); - buf->writestring(" ? "); - expToCBuffer(buf, hgs, e1, PREC_expr); - buf->writestring(" : "); - expToCBuffer(buf, hgs, e2, PREC_cond); -} - -/************************************************************/ - -#if IN_LLVM - -// Strictly LDC specific stuff - -GEPExp::GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx) - : UnaExp(loc, TOKgep, sizeof(GEPExp), e) -{ - index = idx; - ident = id; -} - -void GEPExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(ident->toChars()); -} - -Expression* GEPExp::toLvalue(Scope* sc, Expression* e) -{ - // GEP's are always lvalues, at least in the "LLVM sense" ... - return this; -} - -#endif diff --git a/dmd/expression.h b/dmd/expression.h deleted file mode 100644 index e8ffdcda..00000000 --- a/dmd/expression.h +++ /dev/null @@ -1,2063 +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. - -#ifndef DMD_EXPRESSION_H -#define DMD_EXPRESSION_H - -#include "mars.h" -#include "identifier.h" -#include "lexer.h" -#include "arraytypes.h" - -struct Type; -struct Scope; -struct TupleDeclaration; -struct VarDeclaration; -struct FuncDeclaration; -struct FuncLiteralDeclaration; -struct Declaration; -struct CtorDeclaration; -struct NewDeclaration; -struct Dsymbol; -struct Import; -struct Module; -struct ScopeDsymbol; -struct InlineCostState; -struct InlineDoState; -struct InlineScanState; -struct Expression; -struct Declaration; -struct AggregateDeclaration; -struct StructDeclaration; -struct TemplateInstance; -struct TemplateDeclaration; -struct ClassDeclaration; -struct HdrGenState; -struct BinExp; -struct AssignExp; -struct InterState; -struct OverloadSet; -struct Initializer; -struct StringExp; - -enum TOK; - -#if IN_DMD -// Back end -struct IRState; -struct dt_t; -struct elem; -struct Symbol; // back end symbol -#endif - -#ifdef IN_GCC -union tree_node; typedef union tree_node 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); -Dsymbol *search_function(AggregateDeclaration *ad, Identifier *funcid); -void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Module* from); -void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); -void expandTuples(Expressions *exps); -FuncDeclaration *hasThis(Scope *sc); -Expression *fromConstInitializer(int result, Expression *e); -int arrayExpressionCanThrow(Expressions *exps); -TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s); - -/* 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 IntRange -{ uinteger_t imin; - uinteger_t imax; -}; - -struct Expression : Object -{ - Loc loc; // file location - enum TOK op; // handy to minimize use of dynamic_cast - Type *type; // !=NULL means that semantic() has been run - int size; // # of bytes in Expression so we can copy() it - - Expression(Loc loc, enum TOK op, int size); - Expression *copy(); - virtual Expression *syntaxCopy(); - virtual 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 Expression *castTo(Scope *sc, Type *t); - virtual void checkEscape(); - virtual void checkEscapeRef(); - void checkScalar(); - void checkNoBool(); - Expression *checkIntegral(); - Expression *checkArithmetic(); - void checkDeprecated(Scope *sc, Dsymbol *s); - virtual Expression *checkToBoolean(); - Expression *checkToPointer(); - Expression *addressOf(Scope *sc); - Expression *deref(); - Expression *integralPromotions(Scope *sc); - - 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 - - // Entry point for CTFE. - // A compile-time result is required. Give an error if not possible - Expression *ctfeInterpret(); - - // Implementation of CTFE for this expression - virtual Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - - virtual int isConst(); - virtual int isBool(int result); - virtual int isBit(); - bool hasSideEffect(); - virtual int checkSideEffect(int flag); - virtual int canThrow(); - - 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); - 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); - 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); -}; - -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); - 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); - 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); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - int compare(Object *obj); - int isBool(int result); - int isLvalue(); - 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(); - int checkSideEffect(int flag); - 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); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - int checkSideEffect(int flag); - 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); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if 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 - int checkSideEffect(int flag); - 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); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - Expression *toLvalue(Scope *sc, Expression *e); - - int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if 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); - 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 - int checkSideEffect(int flag); - 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); - int checkSideEffect(int flag); - 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); - - elem *toElem(IRState *irs); -}; -#endif - -// Offset from symbol - -struct SymOffExp : Expression -{ - Declaration *var; - unsigned offset; - Module* m; // starting point for overload resolution - - SymOffExp(Loc loc, Declaration *var, unsigned offset); - 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 - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// Variable - -struct VarExp : Expression -{ - Declaration *var; - - VarExp(Loc loc, Declaration *var); - 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 - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#endif - - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); - void cacheLvalue(IRState* irs); -#endif -}; - -#if DMDV2 -// Overload Set - -struct OverExp : Expression -{ - OverloadSet *vars; - - OverExp(OverloadSet *s); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; -#endif - -// Function/Delegate literal - -struct FuncExp : Expression -{ - FuncLiteralDeclaration *fd; - - FuncExp(Loc loc, FuncLiteralDeclaration *fd); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - 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); - int checkSideEffect(int flag); - 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 -{ - Type *typeidType; - - TypeidExp(Loc loc, Type *typeidType); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#if DMDV2 -struct TraitsExp : Expression -{ - Identifier *ident; - Objects *args; - - TraitsExp(Loc loc, Identifier *ident, Objects *args); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; -#endif - -struct HaltExp : Expression -{ - HaltExp(Loc loc); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int checkSideEffect(int flag); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct IsExp : Expression -{ - /* is(targ id tok tspec) - * is(targ id == tok2) - */ - Type *targ; - Identifier *id; // can be NULL - enum TOK tok; // ':' or '==' - Type *tspec; // can be NULL - enum TOK tok2; // 'struct', 'union', 'typedef', etc. - - IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec, enum TOK tok2); - 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 *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - Expression *op_overload(Scope *sc); // doesn't need to be virtual -}; - -struct BinExp : Expression -{ - Expression *e1; - Expression *e2; - - BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - Expression *semanticp(Scope *sc); - Expression *commonSemanticAssign(Scope *sc); - Expression *commonSemanticAssignIntegral(Scope *sc); - int checkSideEffect(int flag); - void checkComplexMulAssign(); - void checkComplexAddAssign(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *scaleFactor(Scope *sc); - Expression *typeCombine(Scope *sc); - Expression *optimize(int result); - int isunsigned(); - void incompatibleTypes(); - void dump(int indent); - Expression *interpretCommon(InterState *istate, CtfeGoal goal, - Expression *(*fp)(Type *, Expression *, Expression *)); - Expression *interpretCommon2(InterState *istate, CtfeGoal goal, - Expression *(*fp)(Loc, TOK, Type *, Expression *, Expression *)); - Expression *interpretAssignCommon(InterState *istate, CtfeGoal goal, - Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); - Expression *interpretFourPointerRelation(InterState *istate, CtfeGoal goal); - Expression *arrayOp(Scope *sc); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - Expression *op_overload(Scope *sc); - -#if IN_DMD - elem *toElemBin(IRState *irs, int op); -#endif -}; - -struct BinAssignExp : BinExp -{ - BinAssignExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) - : BinExp(loc, op, size, e1, e2) - { - } - - Expression *semantic(Scope *sc); - int isLvalue(); -}; - -/****************************************************************/ - -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); - int checkSideEffect(int flag); - 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); - 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; - - DotVarExp(Loc loc, Expression *e, Declaration *var); - 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, TemplateInstance *ti); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); -}; - -struct DelegateExp : UnaExp -{ - FuncDeclaration *func; - Module* m; // starting point for overload resolution - int hasOverloads; - - DelegateExp(Loc loc, Expression *e, FuncDeclaration *func); - 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 - - 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 *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); - 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 *modifiableLvalue(Scope *sc, Expression *e); - - int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - void cacheLvalue(IRState* p); - DValue* toElem(IRState* irs); -#endif -}; - -struct AddrExp : UnaExp -{ - Module* m; // starting point for overload resolution - - AddrExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void checkEscape(); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *optimize(int result); - 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); - 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); - -#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); - - // 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); - - // 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(); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct CastExp : UnaExp -{ - // Possible to cast to one type while painting to another type - Type *to; // type to cast to - - CastExp(Loc loc, Expression *e, Type *t); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); - void checkEscape(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - - // For operator overloading - Identifier *opId(); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - - -struct SliceExp : UnaExp -{ - Expression *upr; // NULL if implicit 0 - Expression *lwr; // NULL if implicit [length - 1] - VarDeclaration *lengthVar; - - SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr); - Expression *syntaxCopy(); - 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); - int canThrow(); - - 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 - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// e1[a0,a1,a2,a3,...] - -struct ArrayExp : UnaExp -{ - Expressions *arguments; // Array of Expression's - - ArrayExp(Loc loc, Expression *e1, Expressions *arguments); - Expression *syntaxCopy(); - 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 *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(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - int isBool(int result); - int checkSideEffect(int flag); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - void cacheLvalue(IRState* p); - DValue* toElem(IRState* irs); -#endif -}; - -struct IndexExp : BinExp -{ - VarDeclaration *lengthVar; - int modifiable; - - IndexExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - Expression *interpret(InterState *istate, 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 -}; - -struct AssignExp : BinExp -{ int ismemset; // !=0 if setting the contents of an array - - AssignExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - Expression *interpret(InterState *istate, 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); -#endif - - AssignExp* isAssignExp() { return this; } -}; - -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); \ - S(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 -#define S(a) a -ASSIGNEXP(Add) -ASSIGNEXP(Min) -ASSIGNEXP(Mul) -ASSIGNEXP(Div) -ASSIGNEXP(Mod) -ASSIGNEXP(And) -ASSIGNEXP(Or) -ASSIGNEXP(Xor) -#undef S - -#if DMDV2 -#define S(a) a -ASSIGNEXP(Pow) -#undef S -#endif - -#undef X - -#define X(a) -#define S(a) - -ASSIGNEXP(Shl) -ASSIGNEXP(Shr) -ASSIGNEXP(Ushr) -#undef S - -#define S(a) a -ASSIGNEXP(Cat) - -#undef S -#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); - - // 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); - - // 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); - - // 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); - - // 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); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -#if DMDV2 -struct PowExp : BinExp -{ - PowExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); -}; -#endif - -struct ShlExp : BinExp -{ - ShlExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, 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 ShrExp : BinExp -{ - ShrExp(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 UshrExp : BinExp -{ - UshrExp(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 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); - - // 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); - - // 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); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct OrOrExp : BinExp -{ - OrOrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct AndAndExp : BinExp -{ - AndAndExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct CmpExp : BinExp -{ - CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBit(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct InExp : BinExp -{ - InExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - 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(); - -#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(); - int checkSideEffect(int flag); - 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); - virtual Expression *resolve(Loc loc, Scope *sc) = 0; - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct FileInitExp : DefaultInitExp -{ - FileInitExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *resolve(Loc loc, Scope *sc); -}; - -struct LineInitExp : DefaultInitExp -{ - LineInitExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *resolve(Loc loc, Scope *sc); -}; -#endif - -/****************************************************************/ - -#if IN_LLVM - -// this stuff is strictly LDC - -// Special expression to represent a LLVM GetElementPtr instruction. -struct GEPExp : UnaExp -{ - unsigned index; - Identifier* ident; - - GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *toLvalue(Scope *sc, Expression *e); - - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -}; - -#endif - -/****************************************************************/ - -/* Special values used by the interpreter - */ -#define EXP_CANT_INTERPRET ((Expression *)1) -#define EXP_CONTINUE_INTERPRET ((Expression *)2) -#define EXP_BREAK_INTERPRET ((Expression *)3) -#define EXP_GOTO_INTERPRET ((Expression *)4) -#define EXP_VOID_INTERPRET ((Expression *)5) - -Expression *expType(Type *type, Expression *e); - -Expression *Neg(Type *type, Expression *e1); -Expression *Com(Type *type, Expression *e1); -Expression *Not(Type *type, Expression *e1); -Expression *Bool(Type *type, Expression *e1); -Expression *Cast(Type *type, Type *to, Expression *e1); -Expression *ArrayLength(Type *type, Expression *e1); -Expression *Ptr(Type *type, Expression *e1); - -Expression *Add(Type *type, Expression *e1, Expression *e2); -Expression *Min(Type *type, Expression *e1, Expression *e2); -Expression *Mul(Type *type, Expression *e1, Expression *e2); -Expression *Div(Type *type, Expression *e1, Expression *e2); -Expression *Mod(Type *type, Expression *e1, Expression *e2); -Expression *Shl(Type *type, Expression *e1, Expression *e2); -Expression *Shr(Type *type, Expression *e1, Expression *e2); -Expression *Ushr(Type *type, Expression *e1, Expression *e2); -Expression *And(Type *type, Expression *e1, Expression *e2); -Expression *Or(Type *type, Expression *e1, Expression *e2); -Expression *Xor(Type *type, Expression *e1, Expression *e2); -Expression *Index(Type *type, Expression *e1, Expression *e2); -Expression *Cat(Type *type, Expression *e1, Expression *e2); - -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2); - -Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr); - -// 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); - -int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len); -int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len); - - -#endif /* DMD_EXPRESSION_H */ diff --git a/dmd/func.c b/dmd/func.c deleted file mode 100644 index 540bb8ef..00000000 --- a/dmd/func.c +++ /dev/null @@ -1,3653 +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 "declaration.h" -#include "attrib.h" -#include "expression.h" -#include "scope.h" -#include "mtype.h" -#include "aggregate.h" -#include "identifier.h" -#include "id.h" -#include "module.h" -#include "statement.h" -#include "template.h" -#include "hdrgen.h" - -#ifdef IN_GCC -#include "d-dmd-gcc.h" -#endif - -/********************************* FuncDeclaration ****************************/ - -FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type) - : Declaration(id) -{ - //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); - //printf("storage_class = x%x\n", storage_class); - this->storage_class = storage_class; - this->type = type; - this->loc = loc; - this->endloc = endloc; - fthrows = NULL; - frequire = NULL; - fdrequire = NULL; - fdensure = NULL; - outId = NULL; - vresult = NULL; - returnLabel = NULL; - scout = 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; - inlineAsm = 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); - 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; - -#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 - - if (!originalType) - originalType = type; - if (!type->deco) - { - type = type->semantic(loc, sc); - } - //type->print(); - if (type->ty != Tfunction) - { - error("%s must be a function", toChars()); - return; - } - f = (TypeFunction *)(type); - size_t nparams = Parameter::dim(f->parameters); - - linkage = sc->linkage; - protection = sc->protection; - - storage_class |= sc->stc; - ad = isThis(); - if (ad) - storage_class |= ad->storage_class & (STC_TYPECTOR | STCsynchronized); - //printf("function storage_class = x%x\n", storage_class); - - if (ident == Id::ctor && !isCtorDeclaration()) - error("_ctor is reserved for constructors"); - - if (isConst() || isAuto() || isScope()) - error("functions cannot be const or auto"); - - if (isAbstract() && !isVirtual()) - error("non-virtual functions cannot be abstract"); - - // https://github.com/donc/dmd/commit/9f7b2f8cfe5d7482f2de7f9678c176d54abe237f#commitcomment-321724 - //if (isOverride() && !isVirtual()) - //error("cannot override a non-virtual function"); - - 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) - { - // Verify no constructors, destructors, etc. - if (isCtorDeclaration() || - isDtorDeclaration() - //|| isInvariantDeclaration() - //|| isUnitTestDeclaration() - ) - { - error("special member functions not allowed for %ss", sd->kind()); - } - -#if 0 - if (!sd->inv) - sd->inv = isInvariantDeclaration(); - - if (!sd->aggNew) - sd->aggNew = isNewDeclaration(); - - if (isDelete()) - { - if (sd->aggDelete) - error("multiple delete's for struct %s", sd->toChars()); - sd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - } - - id = parent->isInterfaceDeclaration(); - if (id) - { - storage_class |= STCabstract; - - if (isCtorDeclaration() || -#if DMDV2 - isPostBlitDeclaration() || -#endif - isDtorDeclaration() || - isInvariantDeclaration() || - isUnitTestDeclaration() || isNewDeclaration() || isDelete()) - error("special function not allowed in interface %s", id->toChars()); - if (fbody && isVirtual()) - error("function body is not abstract in interface %s", id->toChars()); - } - - /* Template member functions aren't virtual: - * interface TestInterface { void tpl(T)(); } - * and so won't work in interfaces - */ - if ((pd = toParent()) != NULL && - pd->isTemplateInstance() && - (pd = toParent2()) != NULL && - (id = pd->isInterfaceDeclaration()) != NULL) - { - error("template member 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; - } - // Suppress further errors if the return type is an error - if (type->nextOf() == Type::terror) - goto Ldone; - - /* Find index of existing function in base class's vtbl[] to override - * (the index will be the same as in cd's current vtbl[]) - */ - vi = cd->baseClass ? findVtblIndex(&cd->baseClass->vtbl, cd->baseClass->vtbl.dim) - : -1; - - switch (vi) - { - case -1: - /* Didn't find one, so - * This is an 'introducing' function which gets a new - * slot in the vtbl[]. - */ - - // Verify this doesn't override previous final function - if (cd->baseClass) - { Dsymbol *s = cd->baseClass->search(loc, ident, 0); - if (s) - { - FuncDeclaration *f = s->isFuncDeclaration(); - f = f->overloadExactMatch(type, getModule()); - if (f && f->isFinal() && f->prot() != PROTprivate) - error("cannot override final function %s", f->toPrettyChars()); - } - } - - if (isFinal()) - { - if (isOverride()) - error("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 = SIZEOKfwd; // 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()); - -#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 is mixin) && (fdc is not mixin) then fdc overrides - if (!this->parent->isClassDeclaration() && fdc->parent->isClassDeclaration()) - break; - - if (!this->parent->isClassDeclaration() // if both are mixins then error -#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 = SIZEOKfwd; // 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.startGagging(); // suppress printing of error messages - int offset; - int baseOf = fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset); - if (global.endGagging(errors)) - { - // any error in isBaseOf() is a forward reference error, so we bail out - cd->sizeok = SIZEOKfwd; // can't finish due to forward reference - Module::dprogress = dprogress_save; - return; - } - if (baseOf) - { - ti = fdv->type; - } - } - if (ti) - { - if (tintro) - { - if (!tintro->nextOf()->equals(ti->nextOf()) && - !tintro->nextOf()->isBaseOf(ti->nextOf(), NULL) && - !ti->nextOf()->isBaseOf(tintro->nextOf(), NULL)) - { - error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); - } - } - tintro = ti; - } - goto L2; - } - } - } - - if (introducing && isOverride()) - { - error("does not override any function"); - } - - L2: ; - } - else if (isOverride() && !parent->isTemplateInstance()) - error("override only applies to class member functions"); - - /* Do not allow template instances to add virtual functions - * to a class. - */ - if (isVirtual()) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - ClassDeclaration *cd = ti->tempdecl->isClassMember(); - if (cd) - { - error("cannot use template to add virtual function to class '%s'", cd->toChars()); - } - } - } - - if (isMain()) - { - // Check parameters to see if they are either () or (char[][] args) - switch (nparams) - { - case 0: - break; - - case 1: - { - Parameter *arg0 = Parameter::getNth(f->parameters, 0); - if (arg0->type->ty != Tarray || - arg0->type->nextOf()->ty != Tarray || - arg0->type->nextOf()->nextOf()->ty != Tchar || - arg0->storageClass & (STCout | STCref | STClazy)) - goto Lmainerr; - break; - } - - default: - goto Lmainerr; - } - - if (!f->nextOf()) - error("must return int or void"); - else if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) - error("must return int or void, not %s", f->nextOf()->toChars()); - if (f->varargs) - { - Lmainerr: - error("parameters must be main() or main(string[] args)"); - } - } - - if (ident == Id::assign && (sd || cd)) - { // Disallow identity assignment operator. - - // opAssign(...) - if (nparams == 0) - { if (f->varargs == 1) - goto Lassignerr; - } - else - { - Parameter *arg0 = Parameter::getNth(f->parameters, 0); - Type *t0 = arg0->type->toBasetype(); - Type *tb = sd ? sd->type : cd->type; - if (arg0->type->implicitConvTo(tb) || - (sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb)) - ) - { - if (nparams == 1) - goto Lassignerr; - Parameter *arg1 = Parameter::getNth(f->parameters, 1); - if (arg1->defaultArg) - goto Lassignerr; - } - } - } - - if (isVirtual() && semanticRun != PASSsemanticdone) - { - /* Rewrite contracts as nested functions, then call them. - * Doing it as nested functions means that overriding functions - * can call them. - */ - if (frequire) - { /* in { ... } - * becomes: - * void __require() { ... } - * __require(); - */ - Loc loc = frequire->loc; - TypeFunction *tf = new TypeFunction(NULL, Type::tvoid, 0, LINKd); - FuncDeclaration *fd = new FuncDeclaration(loc, loc, - Id::require, STCundefined, tf); - fd->fbody = frequire; - Statement *s1 = new ExpStatement(loc, fd); - Expression *e = new CallExp(loc, new VarExp(loc, fd), (Expressions *)NULL); - Statement *s2 = new ExpStatement(loc, e); - frequire = new CompoundStatement(loc, s1, s2); - fdrequire = fd; - } - - if (!outId && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid) - outId = Id::result; // provide a default - - if (fensure) - { /* out (result) { ... } - * becomes: - * tret __ensure(ref tret result) { ... } - * __ensure(result); - */ - Loc loc = fensure->loc; - Parameters *arguments = new Parameters(); - Parameter *a = NULL; - if (outId) - { a = new Parameter(STCref, f->nextOf(), outId, NULL); - arguments->push(a); - } - TypeFunction *tf = new TypeFunction(arguments, Type::tvoid, 0, LINKd); - FuncDeclaration *fd = new FuncDeclaration(loc, loc, - Id::ensure, STCundefined, tf); - fd->fbody = fensure; - Statement *s1 = new ExpStatement(loc, fd); - Expression *eresult = NULL; - if (outId) - eresult = new IdentifierExp(loc, outId); - Expression *e = new CallExp(loc, new VarExp(loc, fd), eresult); - 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: - 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; - -#if IN_LLVM - if (!global.params.useAvailableExternally) - availableExternally = false; -#endif - if (!type || type->ty != Tfunction) - return; - f = (TypeFunction *)(type); - - // Check the 'throws' clause - if (fthrows) - { - for (int i = 0; i < fthrows->dim; i++) - { - Type *t = (Type *)fthrows->data[i]; - - t = t->semantic(loc, sc); - if (!t->isClassHandle()) - error("can only throw classes, not %s", t->toChars()); - } - } - - if (!fbody && inferRetType && !type->nextOf()) - { - error("has no function body with return type inference"); - return; - } - - if (frequire) - { - for (int i = 0; i < foverrides.dim; i++) - { - FuncDeclaration *fdv = (FuncDeclaration *)foverrides.data[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) - { - /* 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 = STRUCTALIGN_DEFAULT; - sc2->incontract = 0; - sc2->enclosingFinally = NULL; - sc2->enclosingScopeExit = NULL; - sc2->noctor = 0; - - // Declare 'this' - AggregateDeclaration *ad = isThis(); - if (ad) - { VarDeclaration *v; - - if (isFuncLiteralDeclaration() && isNested() && !sc->intypeof) - { - error("function literals cannot be class members"); - return; - } - else - { - assert(!isNested() || sc->intypeof); // can't be both member and nested - assert(ad->handle); - v = new ThisDeclaration(loc, ad->handle); - v->storage_class |= STCparameter | STCin; - v->semantic(sc2); - if (!sc2->insert(v)) - assert(0); - v->parent = this; - vthis = v; - } - } - else if (isNested()) - { - /* The 'this' for a nested function is the link to the - * enclosing function's stack frame. - * Note that nested functions and member functions are disjoint. - */ - VarDeclaration *v = new ThisDeclaration(loc, Type::tvoid->pointerTo()); - v->storage_class |= STCparameter | STCin; - v->semantic(sc2); - if (!sc2->insert(v)) - assert(0); - v->parent = this; - vthis = v; - } - - // Declare hidden variable _arguments[] and _argptr - if (f->varargs == 1) - { -#if TARGET_NET - varArgs(sc2, f, argptr, _arguments); -#else - Type *t; - -#if !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 std.c.stdarg 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[] - v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); - v_arguments->storage_class = STCparameter | STCin; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; - - t = Type::typeinfo->type->arrayOf(); - _arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - _arguments->semantic(sc2); - sc2->insert(_arguments); - _arguments->parent = this; - } - 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--; - } - } - } -#endif - -#if 0 - // Propagate storage class from tuple parameters to their element-parameters. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Parameter *arg = (Parameter *)f->parameters->data[i]; - - //printf("[%d] arg->type->ty = %d %s\n", i, arg->type->ty, arg->type->toChars()); - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Parameter::dim(t->arguments); - for (size_t j = 0; j < dim; j++) - { Parameter *narg = Parameter::getNth(t->arguments, j); - narg->storageClass = arg->storageClass; - } - } - } - } -#endif - - /* Declare all the function parameters as variables - * and install them in parameters[] - */ - size_t nparams = Parameter::dim(f->parameters); - if (nparams) - { /* parameters[] has all the tuples removed, as the back end - * doesn't know about tuples - */ - parameters = new 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; - 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); - if (v->storage_class & STClazy) - v->storage_class |= STCin; - v->semantic(sc2); - if (!sc2->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - else - parameters->push(v); - localsymtab->insert(v); - v->parent = this; - } - } - - // Declare the tuple symbols and put them in the symbol table, - // but not in parameters[]. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Parameter *arg = (*f->parameters)[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)[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; - } - } - } - - // Precondition invariant - Statement *fpreinv = NULL; - if (addPreInvariant()) - { - Expression *e = 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 - Expression *v = new ThisExp(0); - v->type = vthis->type; -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - Expression *se = new StringExp(0, (char *)"null this"); - se = se->semantic(sc); - se->type = Type::tchar->arrayOf(); - e = new AssertExp(loc, v, se); - } - if (e) - fpreinv = new ExpStatement(0, e); - } - - // Postcondition invariant - Statement *fpostinv = NULL; - 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 - Expression *v = new ThisExp(0); - v->type = vthis->type; -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - e = new AssertExp(0, v); - } - if (e) - fpostinv = new ExpStatement(0, e); - } - - if (fensure || addPostInvariant()) - { - if ((fensure && global.params.useOut) || fpostinv) - { returnLabel = new LabelDsymbol(Id::returnLabel); - } - - // scope of out contract (need for vresult->semantic) - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc2->scopesym; - scout = sc2->push(sym); - } - - if (fbody) - { - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc2->scopesym; - sc2 = sc2->push(sym); - - ClassDeclaration *cd = isClassMember(); - - /* If this is a class constructor - */ - if (isCtorDeclaration() && cd) - { - for (int i = 0; i < cd->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - - v->ctorinit = 0; - } - } - - if (inferRetType || f->retStyle() != RETstack) - nrvo_can = 0; - - fbody = fbody->semantic(sc2); - - if (inferRetType) - { // If no return type inferred yet, then infer a void - if (!type->nextOf()) - { - ((TypeFunction *)type)->next = Type::tvoid; - type = type->semantic(loc, sc); - } - f = (TypeFunction *)type; - } - - int offend = fbody ? fbody->blockExit(FALSE) & BEfallthru : TRUE; - - if (isStaticCtorDeclaration()) - { /* It's a static constructor. Ensure that all - * ctor consts were initialized. - */ - - Dsymbol *p = toParent(); - ScopeDsymbol *ad = p->isScopeDsymbol(); - if (!ad) - { - error("static constructor can only be member of struct/class/module, not %s %s", p->kind(), p->toChars()); - } - else - { - for (size_t i = 0; i < ad->members->dim; i++) - { Dsymbol *s = (Dsymbol *)ad->members->data[i]; - - s->checkCtorConstInit(); - } - } - } - - if (isCtorDeclaration() && cd) - { - //printf("callSuper = x%x\n", sc2->callSuper); - - // Verify that all the ctorinit fields got initialized - if (!(sc2->callSuper & CSXthis_ctor)) - { - for (size_t i = 0; i < cd->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - - if (v->ctorinit == 0 && v->isCtorinit()) - error("missing initializer for const field %s", v->toChars()); - } - } - - if (!(sc2->callSuper & CSXany_ctor) && - cd->baseClass && cd->baseClass->ctor) - { - sc2->callSuper = 0; - - // Insert implicit super() at start of fbody - Expression *e1 = new SuperExp(0); - Expression *e = new CallExp(0, e1); - - e = e->trySemantic(sc2); - if (!e) - error("no match for implicit super() call in constructor"); - else - { - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, s, fbody); - } - } - } - else if (fes) - { // For foreach(){} body, append a return 0; - Expression *e = new IntegerExp(0); - Statement *s = new ReturnStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - assert(!returnLabel); - } - else if (!hasReturnExp && type->nextOf()->ty != Tvoid) - error("expected to return a value of type %s", type->nextOf()->toChars()); - else if (!inlineAsm) - { -#if DMDV2 - int blockexit = fbody ? fbody->blockExit() : BEfallthru; - if (f->isnothrow && blockexit & BEthrow) - error("'%s' is nothrow yet may throw", toChars()); - - int offend = blockexit & BEfallthru; -#endif - if (type->nextOf()->ty != Tvoid) - { - if (offend) - { 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); - } - } - } - - sc2 = sc2->pop(); - } - - Statement *freq = frequire; - Statement *fens = fensure; - - /* Do the semantic analysis on the [in] preconditions and - * [out] postconditions. - */ - if (freq) - { /* frequire is composed of the [in] contracts - */ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc2->scopesym; - sc2 = sc2->push(sym); - sc2->incontract++; - - // 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 - DsymbolTable *labtab_save = labtab; - labtab = NULL; // so in contract can't refer to out/body labels - freq = freq->semantic(sc2); - labtab = labtab_save; - - sc2->incontract--; - sc2 = sc2->pop(); - - if (!global.params.useIn) - freq = NULL; - } - - if (fens) - { /* fensure is composed of the [out] contracts - */ - if (type->nextOf()->ty == Tvoid && outId) - { - error("void functions have no result"); - } - - if (type->nextOf()->ty != Tvoid) - buildResultVar(); - - sc2 = scout; //push - sc2->incontract++; - - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - DsymbolTable *labtab_save = labtab; - labtab = NULL; // so out contract can't refer to in/body labels - fens = fens->semantic(sc2); - labtab = labtab_save; - - sc2->incontract--; - sc2 = sc2->pop(); - - if (!global.params.useOut) - fens = NULL; - } - - { - Statements *a = new Statements(); - - // Merge in initialization of 'out' parameters - if (parameters) - { for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - if (v->storage_class & STCout) - { - assert(v->init); - ExpInitializer *ie = v->init->isExpInitializer(); - assert(ie); - ie->exp->op = TOKassign; // construction occurred in parameter processing - a->push(new ExpStatement(0, ie->exp)); - } - } - } - -// we'll handle variadics ourselves -#if !IN_LLVM - if (argptr) - { // Initialize _argptr to point past non-variadic arg -#if IN_GCC - // Handled in FuncDeclaration::toObjFile - v_argptr = argptr; - v_argptr->init = new VoidInitializer(loc); -#else - Type *t = argptr->type; - 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 = (VarDeclaration *)parameters->data[lastNonref]; - /* The trouble with out and ref parameters is that taking - * the address of it doesn't work, because later processing - * adds in an extra level of indirection. So we skip over them. - */ - while (p->storage_class & (STCout | STCref)) - { - --lastNonref; - offset += PTRSIZE; - if (lastNonref < 0) - { - p = v_arguments; - break; - } - p = (VarDeclaration *)parameters->data[lastNonref]; - } - } - else - p = v_arguments; // last parameter is _arguments[] - if (p->storage_class & STClazy) - // If the last parameter is lazy, it's the size of a delegate - offset += PTRSIZE * 2; - else - offset += p->type->size(); - offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1); // assume stack aligns on pointer size - Expression *e = new SymOffExp(0, p, offset); - e->type = Type::tvoidptr; - //e = e->semantic(sc); - e = new AssignExp(0, e1, e); - e->type = t; - a->push(new ExpStatement(0, e)); - } -#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 AssignExp(0, e1, e); - e->op = TOKconstruct; - e = e->semantic(sc2); - a->push(new ExpStatement(0, e)); - } - -#endif // !IN_LLVM - - // Merge contracts together with body into one compound statement - - if (freq || fpreinv) - { - if (!freq) - freq = fpreinv; - else if (fpreinv) - freq = new CompoundStatement(0, freq, fpreinv); - - freq->incontract = 1; - a->push(freq); - } - - if (fbody) - a->push(fbody); - - if (fens || fpostinv) - { - if (!fens) - fens = fpostinv; - else if (fpostinv) - fens = new CompoundStatement(0, fpostinv, fens); - - LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fens); - returnLabel->statement = ls; - a->push(returnLabel->statement); - - if (type->nextOf()->ty != Tvoid && vresult) - { - // Create: return vresult; - Expression *e = new VarExp(0, vresult); - if (tintro) - { e = e->implicitCastTo(sc, tintro->nextOf()); - e = e->semantic(sc); - } - ReturnStatement *s = new ReturnStatement(0, e); - a->push(s); - } - } - if (isMain() && type->nextOf()->ty == Tvoid) - { // Add a return 0; statement - Statement *s = new ReturnStatement(0, new IntegerExp(0)); - a->push(s); - } - - fbody = new CompoundStatement(0, a); -#if DMDV2 - /* Append destructor calls for parameters as finally blocks. - */ - if (parameters) - { for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = (*parameters)[i]; - - if (v->storage_class & (STCref | STCout)) - continue; - - /* Don't do this for static arrays, since static - * arrays are called by reference. Remove this - * when we change them to call by value. - */ - if (v->type->toBasetype()->ty == Tsarray) - continue; - - Expression *e = v->callScopeDtor(sc); - if (e) - { Statement *s = new ExpStatement(0, e); - s = s->semantic(sc); - if (fbody->blockExit() == BEfallthru) - fbody = new CompoundStatement(0, fbody, s); - else - fbody = new TryFinallyStatement(0, fbody, s); - } - } - } -#endif - - // wrap body of synchronized functions in a synchronized statement - if (isSynchronized()) - { - AggregateDeclaration *ad = isThis(); - ClassDeclaration *cd = ad ? ad->isClassDeclaration() : parent->isClassDeclaration(); - - 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 - Statement* nbody = new PeelStatement(fbody); - nbody = new SynchronizedStatement(loc, sync, nbody); - nbody = nbody->semantic(sc2); - - // LDC - LabelMap::iterator it, end = labmap.end(); - for (it = labmap.begin(); it != end; ++it) - if (it->second->enclosingScopeExit == NULL) - it->second->enclosingScopeExit = nbody; - - fbody = nbody; - } - } - - sc2->callSuper = 0; - sc2->pop(); - } - - 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()); - - type->toCBuffer(buf, ident, hgs); - bodyToCBuffer(buf, hgs); -} - - -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(); - } -} - -/**************************************************** - * Declare result variable lazily. - */ - -void FuncDeclaration::buildResultVar() -{ - if (vresult) - return; - - assert(type->nextOf()); - assert(type->nextOf()->toBasetype()->ty != Tvoid); - TypeFunction *tf = (TypeFunction *)(type); - - Loc loc = this->loc; - - if (fensure) - loc = fensure->loc; - - if (!outId) - outId = Id::result; // provide a default - - 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 (tf->isref) - { - v->storage_class |= STCref | STCforeach; - } -#endif - v->semantic(scout); - if (!scout->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() -} - -/**************************************************** - * Merge into this function the 'in' contracts of all it overrides. - * 'in's are OR'd together, i.e. only one of them needs to pass. - */ - -Statement *FuncDeclaration::mergeFrequire(Statement *sf) -{ - /* Implementing this is done by having the overriding function call - * nested functions (the fdrequire functions) nested inside the overridden - * function. This requires that the stack layout of the calling function's - * parameters and 'this' pointer be in the same place (as the nested - * function refers to them). - * This is easy for the parameters, as they are all on the stack in the same - * place by definition, since it's an overriding function. The problem is - * getting the 'this' pointer in the same place, since it is a local variable. - * We did some hacks in the code generator to make this happen: - * 1. always generate exception handler frame, or at least leave space for it - * in the frame (Windows 32 SEH only) - * 2. always generate an EBP style frame - * 3. since 'this' is passed in a register that is subsequently copied into - * a stack local, allocate that local immediately following the exception - * handler block, so it is always at the same offset from EBP. - */ - for (int i = 0; i < foverrides.dim; i++) - { - FuncDeclaration *fdv = foverrides[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); - if (sf && fdv->fdrequire) - { - //printf("fdv->frequire: %s\n", fdv->frequire->toChars()); - /* Make the call: - * try { __require(); } - * catch { frequire; } - */ - Expression *eresult = NULL; - Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire), eresult); - Statement *s2 = new ExpStatement(loc, e); - - Catch *c = new Catch(loc, NULL, NULL, sf); - 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) -{ - /* 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[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); - if (fdv->fdensure) - { - //printf("fdv->fensure: %s\n", fdv->fensure->toChars()); - // Make the call: __ensure(result) - Expression *eresult = NULL; - if (outId) - eresult = new IdentifierExp(loc, outId); - Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure), eresult); - Statement *s2 = new ExpStatement(loc, e); - - if (sf) - { - sf = new CompoundStatement(fensure->loc, s2, sf); - } - else - sf = s2; - } - } - return sf; -} - -/**************************************************** - * Determine if 'this' overrides fd. - * Return !=0 if it does. - */ - -int FuncDeclaration::overrides(FuncDeclaration *fd) -{ int result = 0; - - if (fd->ident == ident) - { - int cov = type->covariant(fd->type); - if (cov) - { ClassDeclaration *cd1 = toParent()->isClassDeclaration(); - ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration(); - - if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL)) - result = 1; - } - } - return result; -} - -/************************************************* - * Find index of function in vtbl[0..dim] that - * this function overrides. - * Prefer an exact match to a covariant one. - * Returns: - * -1 didn't find one - * -2 can't determine because of forward references - */ - -int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) -{ - FuncDeclaration *mismatch = NULL; - int exactvi = -1; - int bestvi = -1; - for (int vi = 0; vi < dim; vi++) - { - FuncDeclaration *fdv = (*vtbl)[vi]->isFuncDeclaration(); - if (fdv && fdv->ident == ident) - { - if (type->equals(fdv->type)) // if exact match - { - if (fdv->parent->isClassDeclaration()) - return vi; // no need to look further - - if (exactvi >= 0) - { - error("cannot determine overridden function"); - return exactvi; - } - exactvi = vi; - - bestvi = vi; - continue; - } - - 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)\n", s->toChars()); - a = s->isAliasDeclaration(); - if (a) - { - if (overnext) - return overnext->overloadInsert(a); - if (!a->aliassym && a->type->ty != Tident && a->type->ty != Tinstance) - { - //printf("\ta = '%s'\n", a->type->toChars()); - return FALSE; - } - overnext = a; - //printf("\ttrue: no conflict\n"); - return TRUE; - } - f = s->isFuncDeclaration(); - if (!f) - return FALSE; - - if (type && f->type && // can be NULL for overloaded constructors - f->type->covariant(type) && - !isFuncAliasDeclaration()) - { - //printf("\tfalse: conflict %s\n", kind()); - return FALSE; - } - - if (overnext) - return overnext->overloadInsert(f); - overnext = f; - //printf("\ttrue: no conflict\n"); - return TRUE; -} - -/******************************************** - * Find function in overload list that exactly matches t. - */ - -/*************************************************** - * Visit each overloaded function in turn, and call - * (*fp)(param, f) on it. - * Exit when no more, or (*fp)(param, f) returns 1. - * Returns: - * 0 continue - * 1 done - */ - -int overloadApply(Module* from, FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param) -{ - FuncDeclaration *f; - Declaration *d; - Declaration *next; - - for (d = fstart; d; d = next) - { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); - - if (fa) - { - if (fa->getModule() == from || fa->importprot != PROTprivate) - if (overloadApply(from, fa->funcalias, fp, param)) - return 1; - next = fa->overnext; - } - else - { - AliasDeclaration *a = d->isAliasDeclaration(); - - if (a) - { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - if (next == fstart) - break; - if (a->importprot == PROTprivate && a->getModule() != from) - if (FuncDeclaration* fd = next->isFuncDeclaration()) - next = fd->overnext; - } - else - { - f = d->isFuncDeclaration(); - if (!f) - { d->error("is aliased to a function"); - break; // BUG: should print error message? - } - if ((*fp)(param, f)) - return 1; - - next = f->overnext; - } - } - } - return 0; -} - -/******************************************** - * If there are no overloads of function f, return that function, - * otherwise return NULL. - */ - -static int fpunique(void *param, FuncDeclaration *f) -{ FuncDeclaration **pf = (FuncDeclaration **)param; - - if (*pf) - { *pf = NULL; - return 1; // ambiguous, done - } - else - { *pf = f; - return 0; - } -} - -FuncDeclaration *FuncDeclaration::isUnique() -{ FuncDeclaration *result = NULL; - - overloadApply(getModule(), this, &fpunique, &result); - return result; -} - -/******************************************** - * Find function in overload list that exactly matches t. - */ - -struct Param1 -{ - Type *t; // type to match - FuncDeclaration *f; // return value -}; - -int fp1(void *param, FuncDeclaration *f) -{ Param1 *p = (Param1 *)param; - Type *t = p->t; - - if (t->equals(f->type)) - { p->f = f; - return 1; - } - -#if DMDV2 - /* Allow covariant matches, if it's just a const conversion - * of the return type - */ - if (t->ty == Tfunction) - { TypeFunction *tf = (TypeFunction *)f->type; - if (tf->covariant(t) == 1 && - tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst) - { - p->f = f; - return 1; - } - } -#endif - return 0; -} - -FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t, Module* from) -{ - Param1 p; - p.t = t; - p.f = NULL; - overloadApply(from, this, &fp1, &p); - return p.f; -} - - -/******************************************** - * Decide which function matches the arguments best. - */ - -struct Param2 -{ - Match *m; -#if DMDV2 - Expression *ethis; -#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; - match = (MATCH) tf->callMatch(arguments); - //printf("1match = %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.arguments = arguments; - overloadApply(from, fstart, &fp2, &p); -} - - -FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, Module *from, int flags) -{ - TypeFunction *tf; - Match m; - -#if 0 -printf("FuncDeclaration::overloadResolve('%s')\n", toChars()); -if (arguments) -{ int i; - - for (i = 0; i < arguments->dim; i++) - { Expression *arg; - - arg = (Expression *)arguments->data[i]; - assert(arg->type); - printf("\t%s: ", arg->toChars()); - arg->type->print(); - } -} -#endif - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - overloadResolveX(&m, this, NULL, arguments, from); - - if (m.count == 1) // exactly one match - { - return m.lastf; - } - else - { - OutBuffer buf; - - if (arguments) - { - HdrGenState hgs; - - argExpTypesToCBuffer(&buf, arguments, &hgs); - } - - if (m.last == MATCHnomatch) - { - tf = (TypeFunction *)type; - - //printf("tf = %s, args = %s\n", tf->deco, ((Expression *)arguments->data[0])->type->deco); - error(loc, "%s does not match parameter types (%s)", - Parameter::argsTypesToChars(tf->parameters, tf->varargs), - 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()); -#endif - - /* This works by calling g() with f()'s parameters, and - * if that is possible, then f() is at least as specialized - * as g() is. - */ - - TypeFunction *tf = (TypeFunction *)type; - TypeFunction *tg = (TypeFunction *)g->type; - size_t nfparams = Parameter::dim(tf->parameters); - size_t ngparams = Parameter::dim(tg->parameters); - MATCH match = MATCHexact; - - /* If both functions have a 'this' pointer, and the mods are not - * the same and g's is not const, then this is less specialized. - */ - if (needThis() && g->needThis()) - { - if (tf->mod != tg->mod) - { - if (tg->mod == MODconst) - match = MATCHconst; - else - return MATCHnomatch; - } - } - - /* Create a dummy array of arguments out of the parameters to f() - */ - Expressions args; - args.setDim(nfparams); - for (int u = 0; u < nfparams; u++) - { - Parameter *p = Parameter::getNth(tf->parameters, u); - Expression *e; - if (p->storageClass & (STCref | STCout)) - { - e = new IdentifierExp(0, p->ident); - e->type = p->type; - } - else - e = p->type->defaultInit(); - args.data[u] = e; - } - - MATCH m = (MATCH) tg->callMatch(NULL, &args); - 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) -{ //printf("test4\n"); - break; -} - if (!s->parent || - (!s->parent->isTemplateInstance())) -{ //printf("test5\n"); - break; -} - } - //printf("-FuncDeclaration::isMember2() %p\n", ad); - return ad; -} - -/***************************************** - * Determine lexical level difference from 'this' to nested function 'fd'. - * Error if this cannot call fd. - * Returns: - * 0 same level - * -1 increase nesting by 1 (fd is nested within 'this') - * >0 decrease nesting by number - */ - -int FuncDeclaration::getLevel(Loc loc, FuncDeclaration *fd) -{ int level; - Dsymbol *s; - Dsymbol *fdparent; - - //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars()); - fdparent = fd->toParent2(); - if (fdparent == this) - return -1; - s = this; - level = 0; - while (fd != s && fdparent != s->toParent2()) - { - //printf("\ts = '%s'\n", s->toChars()); - FuncDeclaration *thisfd = s->isFuncDeclaration(); - if (thisfd) - { if (!thisfd->isNested() && !thisfd->vthis) - goto Lerr; - } - else - { - ClassDeclaration *thiscd = s->isClassDeclaration(); - if (thiscd) - { if (!thiscd->isNested()) - goto Lerr; - } - else - goto Lerr; - } - - s = s->toParent2(); - assert(s); - level++; - } - return level; - -Lerr: - error(loc, "cannot access frame of function %s", fd->toChars()); - return 1; -} - -void FuncDeclaration::appendExp(Expression *e) -{ Statement *s; - - s = new ExpStatement(0, e); - appendState(s); -} - -void FuncDeclaration::appendState(Statement *s) -{ - if (!fbody) - { Statements *a; - - a = new Statements(); - fbody = new CompoundStatement(0, a); - } - CompoundStatement *cs = fbody->isCompoundStatement(); - cs->statements->push(s); -} - -const char *FuncDeclaration::toPrettyChars() -{ - if (isMain()) - return "D main"; - else - return Dsymbol::toPrettyChars(); -} - -int FuncDeclaration::isMain() -{ - return ident == Id::main && - linkage != LINKc && !isMember() && !isNested(); -} - -int FuncDeclaration::isWinMain() -{ - //printf("FuncDeclaration::isWinMain() %s\n", toChars()); -#if 0 - int x = ident == Id::WinMain && - linkage != LINKc && !isMember(); - printf("%s\n", x ? "yes" : "no"); - return x; -#else - return ident == Id::WinMain && - linkage != LINKc && !isMember(); -#endif -} - -int FuncDeclaration::isDllMain() -{ - return ident == Id::DllMain && - linkage != LINKc && !isMember(); -} - -int FuncDeclaration::isExport() -{ - return protection == PROTexport; -} - -int FuncDeclaration::isImportedSymbol() -{ - //printf("isImportedSymbol()\n"); - //printf("protection = %d\n", protection); - return (protection == PROTexport) && !fbody; -} - -// Determine if function goes into virtual function pointer table - -int FuncDeclaration::isVirtual() -{ -#if 0 - printf("FuncDeclaration::isVirtual(%s)\n", toChars()); - printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); - printf("result is %d\n", - isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration()); -#endif - return isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration(); -} - -// 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)\n", toChars()); - printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); - printf("result is %d\n", - isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - (cd = toParent()->isClassDeclaration()) != NULL && - cd->storage_class & STCfinal); -#endif - return isMember() && - (Declaration::isFinal() || - ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); -} - -int FuncDeclaration::isAbstract() -{ - return storage_class & STCabstract; -} - -int FuncDeclaration::isCodeseg() -{ - return TRUE; // functions are always in the code segment -} - -int FuncDeclaration::hasOverloads() -{ - return overnext != NULL; -} -// Determine if function needs -// a static frame pointer to its lexically enclosing function - -int FuncDeclaration::isNested() -{ - //if (!toParent()) - //printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent); - //printf("\ttoParent2() = '%s'\n", toParent2()->toChars()); - return ((storage_class & STCstatic) == 0) && toParent2() && - (toParent2()->isFuncDeclaration() != NULL); -} - -int FuncDeclaration::needThis() -{ - //printf("FuncDeclaration::needThis() '%s'\n", toChars()); - int i = isThis() != NULL; - //printf("\t%d\n", i); - if (!i && isFuncAliasDeclaration()) - i = ((FuncAliasDeclaration *)this)->funcalias->needThis(); - return i; -} - -int FuncDeclaration::addPreInvariant() -{ - AggregateDeclaration *ad = isThis(); - return (ad && - //ad->isClassDeclaration() && - global.params.useInvariants && - (protection == PROTpublic || protection == PROTexport) && - !naked); -} - -int FuncDeclaration::addPostInvariant() -{ - AggregateDeclaration *ad = isThis(); - return (ad && - ad->inv && - //ad->isClassDeclaration() && - global.params.useInvariants && - (protection == PROTpublic || protection == PROTexport) && - !naked); -} - -/********************************** - * 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"; -} - -/******************************* - * Look at all the variables in this function that are referenced - * by nested functions, and determine if a closure needs to be - * created for them. - */ - -#if DMDV2 -int FuncDeclaration::needsClosure() -{ - /* Need a closure for all the closureVars[] if any of the - * closureVars[] are accessed by a - * function that escapes the scope of this function. - * We take the conservative approach and decide that any function that: - * 1) is a virtual function - * 2) has its address taken - * 3) has a parent that escapes - * - * Note that since a non-virtual function can be called by - * a virtual one, if that non-virtual function accesses a closure - * var, the closure still has to be taken. Hence, we check for isThis() - * instead of isVirtual(). (thanks to David Friedman) - */ - - //printf("FuncDeclaration::needsClosure() %s\n", toChars()); - for (int i = 0; i < closureVars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)closureVars.data[i]; - assert(v->isVarDeclaration()); - //printf("\tv = %s\n", v->toChars()); - - for (int j = 0; j < v->nestedrefs.dim; j++) - { FuncDeclaration *f = (FuncDeclaration *)v->nestedrefs.data[j]; - assert(f != this); - - //printf("\t\tf = %s, %d, %p, %d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf); - if (f->isThis() || f->tookAddressOf) - goto Lyes; // assume f escapes this function's scope - - // Look to see if any parents of f that are below this escape - for (Dsymbol *s = f->parent; s && s != this; s = s->parent) - { - f = s->isFuncDeclaration(); - if (f && (f->isThis() || f->tookAddressOf)) - goto Lyes; - } - } - } - return 0; - -Lyes: - //printf("\tneeds closure\n"); - return 1; -} -#endif - -/*********************************************** - * 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; - } - else // Constructors don't have type's - { CtorDeclaration *fctor = isCtorDeclaration(); - assert(fctor); - fparameters = fctor->arguments; - fvarargs = fctor->varargs; - } - if (pvarargs) - *pvarargs = fvarargs; - return fparameters; -} - - -/****************************** FuncAliasDeclaration ************************/ - -// Used as a way to import a set of functions from another scope into this one. - -FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) - : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, - (enum STC)funcalias->storage_class, funcalias->type) -{ - assert(funcalias != this); - this->funcalias = funcalias; - importprot = PROTundefined; -} - -const char *FuncAliasDeclaration::kind() -{ - return "function alias"; -} - - -/****************************** FuncLiteralDeclaration ************************/ - -FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, - enum TOK tok, ForeachStatement *fes) - : FuncDeclaration(loc, endloc, NULL, STCundefined, type) -{ - const char *id; - - if (fes) - id = "__foreachbody"; - else if (tok == TOKdelegate) - id = "__dgliteral"; - else - id = "__funcliteral"; - this->ident = Lexer::uniqueId(id); - this->tok = tok; - this->fes = fes; - //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); -} - -Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) -{ - FuncLiteralDeclaration *f; - - //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncLiteralDeclaration *)s; - else - { f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); - f->ident = ident; // keep old identifier - } - FuncDeclaration::syntaxCopy(f); - return f; -} - -int FuncLiteralDeclaration::isNested() -{ - //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); - return (tok == TOKdelegate); -} - -int FuncLiteralDeclaration::isVirtual() -{ - return FALSE; -} - -const char *FuncLiteralDeclaration::kind() -{ - // GCC requires the (char*) casts - return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; -} - -void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(kind()); - buf->writeByte(' '); - type->toCBuffer(buf, NULL, hgs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* CtorDeclaration ****************************/ - -CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::ctor, STCundefined, NULL) -{ - this->arguments = arguments; - this->varargs = varargs; - //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); -} - -Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) -{ - CtorDeclaration *f; - - f = new CtorDeclaration(loc, endloc, NULL, varargs); - - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - - f->arguments = Parameter::arraySyntaxCopy(arguments); - return f; -} - - -void CtorDeclaration::semantic(Scope *sc) -{ - //printf("CtorDeclaration::semantic() %s\n", toChars()); - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static constructor - - parent = sc->parent; - Dsymbol *parent = toParent(); - Type *tret; - ClassDeclaration *cd = parent->isClassDeclaration(); - if (!cd) - { - error("constructors are only for class definitions"); - fatal(); - tret = Type::tvoid; - } - else - tret = cd->type; //->referenceTo(); - if (!type) - type = new TypeFunction(arguments, tret, varargs, LINKd); -#if STRUCTTHISREF - if (ad && ad->isStructDeclaration()) - ((TypeFunction *)type)->isref = 1; -#endif - if (!originalType) - originalType = type; - - sc->flags |= SCOPEctor; - type = type->semantic(loc, sc); - sc->flags &= ~SCOPEctor; - - // Append: - // return this; - // to the function body - if (fbody && semanticRun < PASSsemantic) - { - Expression *e = new ThisExp(loc); - Statement *s = new ReturnStatement(loc, e); - fbody = new CompoundStatement(loc, fbody, s); - } - - FuncDeclaration::semantic(sc); - - sc->pop(); - - // See if it's the default constructor - if (cd && varargs == 0 && Parameter::dim(arguments) == 0) - cd->defaultCtor = this; -} - -const char *CtorDeclaration::kind() -{ - return "constructor"; -} - -char *CtorDeclaration::toChars() -{ - return (char *)"this"; -} - -int CtorDeclaration::isVirtual() -{ - return FALSE; -} - -int CtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int CtorDeclaration::addPostInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - - -void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this"); - Parameter::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - -/********************************* PostBlitDeclaration ****************************/ - -#if DMDV2 -PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::_postblit, STCundefined, NULL) -{ -} - -PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id) - : FuncDeclaration(loc, endloc, id, STCundefined, NULL) -{ -} - -Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, ident); - return FuncDeclaration::syntaxCopy(dd); -} - - -void PostBlitDeclaration::semantic(Scope *sc) -{ - //printf("PostBlitDeclaration::semantic() %s\n", toChars()); - //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); - //printf("stc = x%llx\n", sc->stc); - parent = sc->parent; - Dsymbol *parent = toParent(); - StructDeclaration *ad = parent->isStructDeclaration(); - if (!ad) - { - error("post blits are only for struct/union definitions, not %s %s", parent->kind(), parent->toChars()); - } - else if (ident == Id::_postblit && semanticRun < PASSsemantic) - ad->postblits.push(this); - - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not static - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int PostBlitDeclaration::overloadInsert(Dsymbol *s) -{ - return FALSE; // cannot overload postblits -} - -int PostBlitDeclaration::addPreInvariant() -{ - return FALSE; -} - -int PostBlitDeclaration::addPostInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - -int PostBlitDeclaration::isVirtual() -{ - return FALSE; -} - -void PostBlitDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this(this)"); - bodyToCBuffer(buf, hgs); -} -#endif - -/********************************* DtorDeclaration ****************************/ - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) -{ -} - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, Identifier *id) - : FuncDeclaration(loc, endloc, id, STCundefined, NULL) -{ -} - -Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - DtorDeclaration *dd = new DtorDeclaration(loc, endloc, ident); - return FuncDeclaration::syntaxCopy(dd); -} - - -void DtorDeclaration::semantic(Scope *sc) -{ - //printf("DtorDeclaration::semantic() %s\n", toChars()); - //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); - parent = sc->parent; - Dsymbol *parent = toParent(); - ClassDeclaration *cd = parent->isClassDeclaration(); - if (!cd) - { - error("destructors are only for class/struct/union definitions, not %s %s", parent->kind(), parent->toChars()); - fatal(); - } - else if (semanticRun < PASSsemantic) - cd->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() -{ - // FALSE so that dtor's don't get put into the vtbl[] - return FALSE; -} - -void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticCtorDeclaration ****************************/ - -StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticCtor"), STCstatic, NULL) -{ -} - -Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) -{ - 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 = STCstatic; - 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::isStaticConstructor() -{ - return TRUE; -} - -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 && !hgs->tpltMember) - { buf->writestring("static this();"); - buf->writenl(); - return; - } - buf->writestring("static this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticDtorDeclaration ****************************/ - -StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticDtor"), STCstatic, NULL) -{ - vgate = NULL; -} - -Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticDtorDeclaration *sdd; - - assert(!s); - sdd = new StaticDtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(sdd); -} - - -void StaticDtorDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd = 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 = STCstatic; - 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::isStaticDestructor() -{ - return TRUE; -} - -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); -} - -/********************************* InvariantDeclaration ****************************/ - -InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL) -{ -} - -Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) -{ - InvariantDeclaration *id; - - assert(!s); - id = new InvariantDeclaration(loc, endloc); - FuncDeclaration::syntaxCopy(id); - return id; -} - - -void InvariantDeclaration::semantic(Scope *sc) -{ - parent = sc->parent; - Dsymbol *parent = toParent(); - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - if (!ad) - { - error("invariants are only for struct/union/class definitions"); - return; - } - else if (ad->inv && ad->inv != this && semanticRun < PASSsemantic) - { - error("more than one invariant for %s", ad->toChars()); - } - ad->inv = this; - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static invariant - sc->incontract++; - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int InvariantDeclaration::isVirtual() -{ - return FALSE; -} - -int InvariantDeclaration::addPreInvariant() -{ - return FALSE; -} - -int InvariantDeclaration::addPostInvariant() -{ - return FALSE; -} - -void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("invariant"); - bodyToCBuffer(buf, hgs); -} - - -/********************************* UnitTestDeclaration ****************************/ - -/******************************* - * Generate unique unittest function Id so we can have multiple - * instances per module. - */ - -static Identifier *unitTestId() -{ - return Lexer::uniqueId("__unittest"); -} - -UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL) -{ -} - -Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) -{ - UnitTestDeclaration *utd; - - assert(!s); - utd = new UnitTestDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(utd); -} - - -void UnitTestDeclaration::semantic(Scope *sc) -{ -#if 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(); - 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/dmd/gpl.txt b/dmd/gpl.txt deleted file mode 100644 index cc468912..00000000 --- a/dmd/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/dmd/hdrgen.c b/dmd/hdrgen.c deleted file mode 100644 index 6fa5af42..00000000 --- a/dmd/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, Array *arguments, HdrGenState *hgs); - -void Module::genhdrfile() -{ - OutBuffer hdrbufr; - - hdrbufr.printf("// D import file generated from '%s'", srcfile->toChars()); - hdrbufr.writenl(); - - HdrGenState hgs; - memset(&hgs, 0, sizeof(hgs)); - hgs.hdrgen = 1; - - toCBuffer(&hdrbufr, &hgs); - - // Transfer image to file - hdrfile->setbuffer(hdrbufr.data, hdrbufr.offset); - hdrbufr.data = NULL; - - char *pt = FileName::path(hdrfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - hdrfile->writev(); -} - - -void Module::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (md) - { - buf->writestring("module "); - buf->writestring(md->toChars()); - buf->writebyte(';'); - buf->writenl(); - } - - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - - s->toHBuffer(buf, hgs); - } -} - - -void Dsymbol::toHBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - toCBuffer(buf, hgs); -} - - -/*************************************/ diff --git a/dmd/hdrgen.h b/dmd/hdrgen.h deleted file mode 100644 index 44e3a5dd..00000000 --- a/dmd/hdrgen.h +++ /dev/null @@ -1,35 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 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. - -#include // memset() - -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/dmd/html.c b/dmd/html.c deleted file mode 100644 index 93b752ee..00000000 --- a/dmd/html.c +++ /dev/null @@ -1,757 +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 - -#include "mars.h" -#include "html.h" - -#if MARS || IN_LLVM -#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, ...) -{ - if (!global.gag) - { - fprintf(stderr, "%s(%d) : HTML Error: ", sourcename, linnum); - - va_list ap; - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); - - fprintf(stderr, "\n"); - fflush(stderr); - } - - global.errors++; -} - -/********************************************** - * Extract all the code from an HTML file, - * concatenate it all together, and store in buf. - */ - -void Html::extractCode(OutBuffer *buf) -{ - //printf("Html::extractCode()\n"); - dbuf = buf; // save for other routines - buf->reserve(end - p); - inCode = 0; - while (1) - { - //printf("p = %p, *p = x%x\n", p, *p); - switch (*p) - { -#if 0 // strings are not recognized outside of tags - case '"': - case '\'': - skipString(); - continue; -#endif - case '<': - if (p[1] == '!' && isCommentStart()) - { // Comments start with - * Netscape: comments nest - * w3c: whitespace can appear between -- and > of comment close - */ - -void Html::scanComment() -{ - // Most of the complexity is dealing with the case that - // an arbitrary amount of whitespace can appear between - // the -- and the > of a comment close. - int scangt = 0; - - //printf("scanComment()\n"); - if (*p == '\n') - { linnum++; - // Always extract new lines, so that D lexer counts the - // lines right. - dbuf->writeByte(*p); - } - while (1) - { - //scangt = 1; // IE 5.0 compatibility - p++; - switch (*p) - { - case '-': - if (p[1] == '-') - { - if (p[2] == '>') // optimize for most common case - { - p += 3; - break; - } - p++; - scangt = 1; - } - else - scangt = 0; - continue; - - case '>': - if (scangt) - { // found --> - p++; - break; - } - continue; - - case ' ': - case '\t': - case '\f': - case '\v': - // skip white space - continue; - - case '\r': - if (p[1] == '\n') - goto Ldefault; - case '\n': - linnum++; // remember to count lines - // Always extract new lines, so that D lexer counts the - // lines right. - dbuf->writeByte(*p); - continue; - - case 0: - case 0x1a: - error("end of file before closing --> of comment"); - break; - - default: - Ldefault: - scangt = 0; // it's not --> - continue; - } - break; - } - //printf("*p = '%c'\n", *p); -} - -/******************************************** - * Determine if we are at the start of a comment. - * Input: - * p is on the opening '<' - * Returns: - * 0 if not start of a comment - * 1 if start of a comment, p is adjusted to point past -- - */ - -int Html::isCommentStart() -#ifdef __DMC__ - __out(result) - { - if (result == 0) - ; - else if (result == 1) - { - assert(p[-2] == '-' && p[-1] == '-'); - } - else - assert(0); - } - __body -#endif /* __DMC__ */ - { unsigned char *s; - - if (p[0] == '<' && p[1] == '!') - { - for (s = p + 2; 1; s++) - { - switch (*s) - { - case ' ': - case '\t': - case '\r': - case '\f': - case '\v': - // skip white space, even though spec says no - // white space is allowed - continue; - - case '-': - if (s[1] == '-') - { - p = s + 2; - return 1; - } - goto No; - - default: - goto No; - } - } - } - No: - return 0; - } - -int Html::isCDATAStart() -{ - const char * CDATA_START_MARKER = "0) - { - /* Always extract new lines, so that D lexer counts the lines - * right. - */ - linnum++; - dbuf->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/dmd/html.h b/dmd/html.h deleted file mode 100644 index 98a5285b..00000000 --- a/dmd/html.h +++ /dev/null @@ -1,42 +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. - -#ifndef DMD_HTML_H -#define DMD_HTML_H 1 - -struct OutBuffer; - -struct Html -{ - const char *sourcename; - - unsigned char *base; // pointer to start of buffer - unsigned char *end; // past end of buffer - unsigned char *p; // current character - unsigned linnum; // current line number - OutBuffer *dbuf; // code source buffer - int inCode; // !=0 if in code - - - Html(const char *sourcename, unsigned char *base, unsigned length); - - void error(const char *format, ...) IS_PRINTF(2); - void extractCode(OutBuffer *buf); - void skipTag(); - void skipString(); - unsigned char *skipWhite(unsigned char *q); - void scanComment(); - int isCommentStart(); - void scanCDATA(); - int isCDATAStart(); - int charEntity(); - static int namedEntity(unsigned char *p, int length); -}; - -#endif diff --git a/dmd/identifier.c b/dmd/identifier.c deleted file mode 100644 index 01413859..00000000 --- a/dmd/identifier.c +++ /dev/null @@ -1,101 +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; -} - - -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/dmd/identifier.h b/dmd/identifier.h deleted file mode 100644 index 1abb3a41..00000000 --- a/dmd/identifier.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_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/dmd/idgen.c b/dmd/idgen.c deleted file mode 100644 index 0374f425..00000000 --- a/dmd/idgen.c +++ /dev/null @@ -1,378 +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/branches/dmd-1.x/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 -#include - -struct Msgtable -{ - const char *ident; // name to use in DMD source - const char *name; // name in D executable -}; - -Msgtable msgtable[] = -{ - { "IUnknown" }, - { "Object" }, - { "object" }, - { "max" }, - { "min" }, - { "This", "this" }, - { "ctor", "_ctor" }, - { "dtor", "_dtor" }, - { "classInvariant", "__invariant" }, - { "unitTest", "_unitTest" }, - { "require", "__require" }, - { "ensure", "__ensure" }, - { "init" }, - { "size" }, - { "__sizeof", "sizeof" }, - { "__xalignof", "alignof" }, - { "mangleof" }, - { "stringof" }, - { "tupleof" }, - { "length" }, - { "remove" }, - { "ptr" }, - { "funcptr" }, - { "dollar", "__dollar" }, - { "offset" }, - { "offsetof" }, - { "ModuleInfo" }, - { "ClassInfo" }, - { "classinfo" }, - { "typeinfo" }, - { "outer" }, - { "Exception" }, - { "Error" }, - { "withSym", "__withSym" }, - { "result", "__result" }, - { "returnLabel", "__returnLabel" }, - { "delegate" }, - { "line" }, - { "empty", "" }, - { "p" }, - { "coverage", "__coverage" }, - { "__vptr" }, - { "__monitor" }, - - { "TypeInfo" }, - { "TypeInfo_Class" }, - { "TypeInfo_Interface" }, - { "TypeInfo_Struct" }, - { "TypeInfo_Enum" }, - { "TypeInfo_Typedef" }, - { "TypeInfo_Pointer" }, - { "TypeInfo_Array" }, - { "TypeInfo_StaticArray" }, - { "TypeInfo_AssociativeArray" }, - { "TypeInfo_Function" }, - { "TypeInfo_Delegate" }, - { "TypeInfo_Tuple" }, - { "TypeInfo_Const" }, - { "TypeInfo_Invariant" }, - { "elements" }, - { "_arguments_typeinfo" }, - { "_arguments" }, - { "_argptr" }, - { "_match" }, - { "m_align" }, - - { "LINE", "__LINE__" }, - { "FILE", "__FILE__" }, - { "DATE", "__DATE__" }, - { "TIME", "__TIME__" }, - { "TIMESTAMP", "__TIMESTAMP__" }, - { "VENDOR", "__VENDOR__" }, - { "VERSIONX", "__VERSION__" }, - - { "nan" }, - { "infinity" }, - { "dig" }, - { "epsilon" }, - { "mant_dig" }, - { "max_10_exp" }, - { "max_exp" }, - { "min_10_exp" }, - { "min_exp" }, - { "re" }, - { "im" }, - - { "C" }, - { "D" }, - { "Windows" }, - { "Pascal" }, - { "System" }, - - { "exit" }, - { "success" }, - { "failure" }, - - { "keys" }, - { "values" }, - { "rehash" }, - - { "sort" }, - { "reverse" }, - { "dup" }, - { "idup" }, - - // For inline assembler - { "___out", "out" }, - { "___in", "in" }, - { "__int", "int" }, - { "__dollar", "$" }, - { "__LOCAL_SIZE" }, - - // For operator overloads - { "uadd", "opPos" }, - { "neg", "opNeg" }, - { "com", "opCom" }, - { "add", "opAdd" }, - { "add_r", "opAdd_r" }, - { "sub", "opSub" }, - { "sub_r", "opSub_r" }, - { "mul", "opMul" }, - { "mul_r", "opMul_r" }, - { "div", "opDiv" }, - { "div_r", "opDiv_r" }, - { "mod", "opMod" }, - { "mod_r", "opMod_r" }, - { "eq", "opEquals" }, - { "cmp", "opCmp" }, - { "iand", "opAnd" }, - { "iand_r", "opAnd_r" }, - { "ior", "opOr" }, - { "ior_r", "opOr_r" }, - { "ixor", "opXor" }, - { "ixor_r", "opXor_r" }, - { "shl", "opShl" }, - { "shl_r", "opShl_r" }, - { "shr", "opShr" }, - { "shr_r", "opShr_r" }, - { "ushr", "opUShr" }, - { "ushr_r", "opUShr_r" }, - { "cat", "opCat" }, - { "cat_r", "opCat_r" }, - { "assign", "opAssign" }, - { "addass", "opAddAssign" }, - { "subass", "opSubAssign" }, - { "mulass", "opMulAssign" }, - { "divass", "opDivAssign" }, - { "modass", "opModAssign" }, - { "andass", "opAndAssign" }, - { "orass", "opOrAssign" }, - { "xorass", "opXorAssign" }, - { "shlass", "opShlAssign" }, - { "shrass", "opShrAssign" }, - { "ushrass", "opUShrAssign" }, - { "catass", "opCatAssign" }, - { "postinc", "opPostInc" }, - { "postdec", "opPostDec" }, - { "index", "opIndex" }, - { "indexass", "opIndexAssign" }, - { "slice", "opSlice" }, - { "sliceass", "opSliceAssign" }, - { "call", "opCall" }, - { "cast", "opCast" }, - { "match", "opMatch" }, - { "next", "opNext" }, - { "opIn" }, - { "opIn_r" }, - - { "classNew", "new" }, - { "classDelete", "delete" }, - - // For foreach - { "apply", "opApply" }, - { "applyReverse", "opApplyReverse" }, - - { "adDup", "_adDupT" }, - { "adReverse", "_adReverse" }, - - // For internal functions - { "aaLen", "_aaLen" }, - { "aaKeys", "_aaKeys" }, - { "aaValues", "_aaValues" }, - { "aaRehash", "_aaRehash" }, - { "monitorenter", "_d_monitorenter" }, - { "monitorexit", "_d_monitorexit" }, - { "criticalenter", "_d_criticalenter" }, - { "criticalexit", "_d_criticalexit" }, - - // For pragma's - { "GNU_asm" }, - { "lib" }, - { "msg" }, - -#if IN_LLVM - // LDC-specific pragmas. - { "LDC_intrinsic" }, - { "LDC_no_typeinfo" }, - { "LDC_no_moduleinfo" }, - { "LDC_alloca" }, - { "LDC_va_start" }, - { "LDC_va_copy" }, - { "LDC_va_end" }, - { "LDC_va_arg" }, - { "LDC_verbose" }, - { "LDC_allow_inline" }, - { "LDC_inline_asm" }, - { "LDC_inline_ir" }, - { "LDC_fence" }, - { "LDC_atomic_load" }, - { "LDC_atomic_store" }, - { "LDC_atomic_cmp_xchg" }, - { "LDC_atomic_rmw" }, - { "LDC_global_crt_ctor" }, - { "LDC_global_crt_dtor" }, - - // Deprecated LDC pragmas lacking the vendor prefix. - { "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" }, - { "llvm_inline_ir" }, - { "fence" }, - { "atomic_load" }, - { "atomic_store" }, - { "atomic_cmp_xchg" }, - { "atomic_rmw" }, -#endif - - // For special functions - { "tohash", "toHash" }, - { "tostring", "toString" }, - - // Special functions - //{ "alloca" }, - { "main" }, - { "WinMain" }, - { "DllMain" }, - - // 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" }, -}; - - -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/dmd/impcnvgen.c b/dmd/impcnvgen.c deleted file mode 100644 index 6e7a1993..00000000 --- a/dmd/impcnvgen.c +++ /dev/null @@ -1,457 +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" - -enum TY impcnvResult[TMAX][TMAX]; -enum TY impcnvType1[TMAX][TMAX]; -enum TY impcnvType2[TMAX][TMAX]; -int impcnvWarn[TMAX][TMAX]; - -int integral_promotion(int t) -{ - switch (t) - { - case Tchar: - case Twchar: - case Tbit: - case Tbool: - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: return Tint32; - case Tdchar: return Tuns32; - default: return t; - } -} - -void init() -{ int i, j; - - // Set conversion tables - for (i = 0; i < TMAX; i++) - for (j = 0; j < TMAX; j++) - { impcnvResult[i][j] = Terror; - impcnvType1[i][j] = Terror; - impcnvType2[i][j] = Terror; - impcnvWarn[i][j] = 0; - } - -#define X(t1,t2, nt1,nt2, rt) \ - impcnvResult[t1][t2] = rt; \ - impcnvType1[t1][t2] = nt1; \ - impcnvType2[t1][t2] = nt2; - - /* ======================= */ - - X(Tbit,Tbit, Tint32,Tint32, Tint32) - X(Tbit,Tint8, Tint32,Tint32, Tint32) - X(Tbit,Tuns8, Tint32,Tint32, Tint32) - X(Tbit,Tint16, Tint32,Tint32, Tint32) - X(Tbit,Tuns16, Tint32,Tint32, Tint32) - X(Tbit,Tint32, Tint32,Tint32, Tint32) - X(Tbit,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tbit,Tint64, Tint64,Tint64, Tint64) - X(Tbit,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tbit,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tbit,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tbit,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tbit,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tbit,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tbit,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tbit,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tbit,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tbit,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - 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(Tint8, Tbit) - Y(Tuns8, Tbit) - Y(Tint16, Tbit) - Y(Tuns16, Tbit) - Y(Tint32, Tbit) - Y(Tuns32, Tbit) - Y(Tint64, Tbit) - Y(Tuns64, Tbit) - - 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/dmd/imphint.c b/dmd/imphint.c deleted file mode 100644 index df86e01c..00000000 --- a/dmd/imphint.c +++ /dev/null @@ -1,84 +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[] = - { "tango.stdc.stdio", - "tango.io.Stdout", - "tango.math.Math", - }; - static const char *names[] = - { - "printf", NULL, - "Stdout", NULL, - "sin", "cos", "sqrt", "abs", NULL, - }; -#else - static const char *modules[] = - { "core.stdc.stdio", - "std.stdio", - "std.math", - }; - static const char *names[] = - { - "printf", NULL, - "writeln", NULL, - "sin", "cos", "sqrt", "fabs", NULL, - }; -#endif - int m = 0; - for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) - { - const char *p = names[n]; - if (p == NULL) - { m++; - continue; - } - assert(m < sizeof(modules)/sizeof(modules[0])); - if (strcmp(s, p) == 0) - return modules[m]; - } - return NULL; // didn't find it -} - -#if UNITTEST - -void unittest_importHint() -{ - const char *p; - - p = importHint("printf"); - assert(p); - p = importHint("fabs"); - assert(p); - p = importHint("xxxxx"); - assert(!p); -} - -#endif diff --git a/dmd/import.c b/dmd/import.c deleted file mode 100644 index 575fb340..00000000 --- a/dmd/import.c +++ /dev/null @@ -1,411 +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 "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() -{ - assert(id); - this->loc = loc; - this->packages = packages; - this->id = id; - this->aliasId = aliasId; - this->isstatic = isstatic; - protection = PROTundefined; - pkg = NULL; - mod = NULL; -} - -void Import::addAlias(Identifier *name, Identifier *alias) -{ - if (isstatic) - error("cannot have an import bind list"); - - 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 = new Import(loc, packages, id, aliasId, isstatic); - - for (size_t i = 0; i < names.dim; i++) - { - si->addAlias(names[i], aliases[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); -#if TARGET_NET //dot net needs modules and packages with same name -#else - if (pkg && pkg->isModule()) - { - ::error(loc, "can only import from a module, not from a member of module %s. Did you mean `import %s : %s`?", - pkg->toChars(), pkg->toPrettyChars(), id->toChars()); - mod = pkg->isModule(); // Error recovery - treat as import of that module - return; - } -#endif - Dsymbol *s = dst->lookup(id); - if (s) - { -#if TARGET_NET - mod = (Module *)s; -#else - if (s->isModule()) - mod = (Module *)s; - else - { - if (pkg) - { - ::error(loc, "can only import from a module, not from package %s.%s", - pkg->toPrettyChars(), id->toChars()); - } - else - { - ::error(loc, "can only import from a module, not from package %s", - id->toChars()); - } - } -#endif - } - - if (!mod) - { - // Load module - mod = Module::load(loc, packages, id); - if (mod) - { - 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); - - /* Default to private importing - */ - enum PROT prot = sc->protection; - if (!sc->explicitProtection) - prot = PROTprivate; - sc->scopesym->importScope(this, prot); - } -} - -void Import::semantic(Scope *sc) -{ - //printf("Import::semantic('%s')\n", toChars()); - - // Load if not already done so - if (!mod) - { load(sc); - if (mod) - 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); - - /* Default to private importing - */ - enum PROT prot = sc->protection; - if (!sc->explicitProtection) - prot = PROTprivate; - for (Scope *scd = sc; scd; scd = scd->enclosing) - { - if (scd->scopesym) - { - scd->scopesym->importScope(this, prot); - break; - } - } - - mod->semantic(); - - if (mod->needmoduleinfo) - { //printf("module4 %s because of %s\n", sc->module->toChars(), mod->toChars()); - sc->module->needmoduleinfo = 1; - } - - if (aliasId) - { - AliasDeclaration *ad = new AliasDeclaration(loc, aliasId, mod); - sc->insert(ad); - ad->semantic(sc); - } - } - //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); - - if (global.params.moduleDeps != NULL && - // object self-imports itself, so skip that (Bugzilla 7547) - !(id == Id::object && sc->module->ident == Id::object)) - { - /* 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)[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[i]; - Identifier *alias = aliases[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::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(); - } - - if (names.dim) // selective import - { - for (size_t i = 0; i < names.dim; i++) - { - Identifier *name = (Identifier *)names[i]; - Identifier *alias = (Identifier *)aliases[i]; - - if (!alias) - alias = name; - - if (alias->equals(ident)) - return mod->search(loc, name, flags); - } - - // What should happen when renamed and selective imports are mixed? - // This makes the whole module available with the renamed id. - if (aliasId && aliasId->equals(ident)) - return mod; - } - else // non-selective import - { - // For renamed imports, only the alias name is visible. - if (aliasId) - { - if (aliasId->equals(ident)) - return mod; - return 0; - } - - // For non-static imports, prefer symbols in the module over the module name. - if (!isstatic) - { - Dsymbol *s = mod->search(loc, ident, flags); - if (s) - return s; - } - - // Make the start of the package name available. - if (pkg->ident->equals(ident)) - { - return pkg; - } - } - return 0; -} - -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)[i]; - - buf->printf("%s.", pid->toChars()); - } - } - buf->printf("%s", id->toChars()); - if (names.dim) - { - buf->writestring(" : "); - for (size_t i = 0; i < names.dim; i++) - { - Identifier *name = names[i]; - Identifier *alias = aliases[i]; - - if (alias) - buf->printf("%s = %s", alias->toChars(), name->toChars()); - else - buf->printf("%s", name->toChars()); - - if (i < names.dim - 1) - buf->writestring(", "); - } - } - buf->printf(";"); - buf->writenl(); -} - -char *Import::toChars() -{ - return id->toChars(); -} diff --git a/dmd/import.h b/dmd/import.h deleted file mode 100644 index e054bbb7..00000000 --- a/dmd/import.h +++ /dev/null @@ -1,63 +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. - -#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 -{ - // isstatic import aliasId = packages.id; - 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; - - 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 *search(Loc loc, Identifier *ident, int flags); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *toChars(); - - Import *isImport() { return this; } -}; - -#endif /* DMD_IMPORT_H */ diff --git a/dmd/init.c b/dmd/init.c deleted file mode 100644 index b58468a2..00000000 --- a/dmd/init.c +++ /dev/null @@ -1,845 +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 "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, NeedInterpret 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)[i]; - - e = e->syntaxCopy(); - (*a)[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, NeedInterpret 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[i] = field[i]; - - Initializer *init = value[i]; - init = init->syntaxCopy(); - ai->value[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, NeedInterpret 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; - size_t nfields = ad->fields.dim; -#if DMDV2 - if (((StructDeclaration *)ad)->isnested) - nfields--; // don't count pointer to outer -#endif - for (size_t i = 0; i < field.dim; i++) - { - Identifier *id = field[i]; - Initializer *val = value[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[fieldi]; - } - } - else - { - //s = ad->symtab->lookup(id); - s = ad->search(loc, id, 0); - if (!s) - { - s = ad->search_correct(id); - if (s) - error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?", - id->toChars(), t->toChars(), s->kind(), s->toChars()); - else - 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[fieldi]) - break; - } - } - if (s && (v = s->isVarDeclaration()) != NULL) - { - val = val->semantic(sc, v->type, needInterpret); - value[i] = val; - vars[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; - - //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)[i] = NULL; - } - unsigned fieldi = 0; - for (size_t i = 0; i < value.dim; i++) - { - Identifier *id = field[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[fieldi]) - break; - } - } - else if (fieldi >= nfields) - { error(loc, "too many initializers for '%s'", ad->toChars()); - goto Lno; - } - Initializer *iz = value[i]; - if (!iz) - goto Lno; - Expression *ex = iz->toExpression(); - if (!ex) - goto Lno; - if ((*elements)[fieldi]) - { error(loc, "duplicate initializer for field '%s'", - ad->fields[fieldi]->toChars()); - goto Lno; - } - (*elements)[fieldi] = ex; - ++fieldi; - } - // Now, fill in any missing elements with default initializers. - // We also need to validate any anonymous unions - for (size_t i = 0; i < elements->dim; ) - { - VarDeclaration * vd = ad->fields[i]->isVarDeclaration(); - int unionSize = ad->numFieldsInUnion(i); - if (unionSize == 1) - { // Not a union -- default initialize if missing - if (!(*elements)[i]) - { // Default initialize - if (vd->init) - (*elements)[i] = vd->init->toExpression(); - else - (*elements)[i] = vd->type->defaultInit(); - } - } - else - { // anonymous union -- check for errors - int found = -1; // index of the first field with an initializer - for (size_t j = i; j < i + unionSize; ++j) - { - if (!(*elements)[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; - } - 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[i]; - if (id) - { - buf->writestring(id->toChars()); - buf->writebyte(':'); - } - Initializer *iz = value[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[i]; - if (e) - e = e->syntaxCopy(); - ai->index[i] = e; - - Initializer *init = value[i]; - init = init->syntaxCopy(); - ai->value[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, NeedInterpret 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[i]; - if (idx) - { idx = idx->semantic(sc); - idx = idx->ctfeInterpret(); - index[i] = idx; - length = idx->toInteger(); - } - - Initializer *val = value[i]; - ExpInitializer *ei = val->isExpInitializer(); - if (ei && !idx) - ei->expandTuples = 1; - val = val->semantic(sc, t->nextOf(), needInterpret); - - ei = val->isExpInitializer(); - // found a tuple, expand it - if (ei && ei->exp->op == TOKtuple) - { - TupleExp *te = (TupleExp *)ei->exp; - index.remove(i); - value.remove(i); - - for (size_t j = 0; j < te->exps->dim; ++j) - { - Expression *e = (*te->exps)[j]; - index.insert(i + j, (Expression *)NULL); - value.insert(i + j, new ExpInitializer(e->loc, e)); - } - i--; - continue; - } - else - { - value[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. - */ - -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[i]) - j = index[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[i]) - j = (index[i])->toInteger(); - assert(j < edim); - Initializer *iz = value[i]; - if (!iz) - goto Lno; - Expression *ex = iz->toExpression(); - if (!ex) - { - goto Lno; - } - (*elements)[j] = ex; - } - - /* Fill in any missing elements with the default initializer - */ - { - Expression *init = NULL; - for (size_t i = 0; i < edim; i++) - { - if (!(*elements)[i]) - { - if (!type) - goto Lno; - if (!init) - init = t->next->defaultInit(); - (*elements)[i] = init; - } - } - - Expression *e = new ArrayLiteralExp(loc, elements); - e->type = type; - return e; - } - -Lno: - delete elements; - error(loc, "array initializers as expressions are not allowed"); - return new ErrorExp(); -} - - -/******************************** - * If possible, convert array initializer to associative array initializer. - */ - -Initializer *ArrayInitializer::toAssocArrayInitializer() -{ - 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[i]; - if (!e) - goto Lno; - (*keys)[i] = e; - - Initializer *iz = value[i]; - if (!iz) - goto Lno; - e = iz->toExpression(); - if (!e) - goto Lno; - (*values)[i] = e; - } - e = new AssocArrayLiteralExp(loc, keys, values); - return new ExpInitializer(loc, e); - -Lno: - delete keys; - delete values; - error(loc, "not an associative array initializer"); - return this; -} - - -Type *ArrayInitializer::inferType(Scope *sc) -{ - for (size_t i = 0; i < value.dim; i++) - { - if (index.data[i]) - goto Laa; - } - if (value.dim) - { - Initializer *iz = (Initializer *)value.data[0]; - if (iz) - { Type *t = iz->inferType(sc); - t = new TypeSArray(t, new IntegerExp(value.dim)); - t = t->semantic(loc, sc); - return t; - } - } - -Laa: - /* It's possibly an associative array initializer - */ - 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; -} - - -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[i]; - if (ex) - { - ex->toCBuffer(buf, hgs); - buf->writebyte(':'); - } - Initializer *iz = value[i]; - if (iz) - iz->toCBuffer(buf, hgs); - } - buf->writebyte(']'); -} - - -/********************************** ExpInitializer ************************************/ - -ExpInitializer::ExpInitializer(Loc loc, Expression *exp) - : Initializer(loc) -{ - this->exp = exp; - this->expandTuples = 0; -} - -Initializer *ExpInitializer::syntaxCopy() -{ - return new ExpInitializer(loc, exp->syntaxCopy()); -} - -Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) -{ - //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); - exp = exp->semantic(sc); - if (exp->op == TOKerror) - return this; - - int olderrors = global.errors; - if (needInterpret) - exp = exp->ctfeInterpret(); - else - exp = exp->optimize(WANTvalue); - if (!global.gag && olderrors != global.errors) - return this; // Failed, suppress duplicate error messages - - if (exp->op == TOKtype) - exp->error("initializer must be an expression, not '%s'", exp->toChars()); - Type *tb = t->toBasetype(); - - if (exp->op == TOKtuple && - expandTuples && - !exp->implicitConvTo(t)) - return new ExpInitializer(loc, exp); - - /* 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); - if (exp->op == TOKerror) - return this; -L1: - if (needInterpret) - exp = exp->ctfeInterpret(); - else - exp = exp->optimize(WANTvalue); - //printf("-ExpInitializer::semantic(): "); exp->print(); - return this; -} - -Type *ExpInitializer::inferType(Scope *sc) -{ - //printf("ExpInitializer::inferType() %s\n", toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - - // Give error for overloaded function addresses - if (exp->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)exp; - if ( -#if DMDV2 - se->hasOverloads && -#else - se->var->isFuncDeclaration() && -#endif - !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->hasOverloads && - 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/dmd/init.h b/dmd/init.h deleted file mode 100644 index 08503335..00000000 --- a/dmd/init.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 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; - -enum NeedInterpret { INITnointerpret, INITinterpret }; - -#if IN_LLVM -namespace llvm { - class StructType; -} -#endif - -struct Initializer : Object -{ - Loc loc; - - Initializer(Loc loc); - virtual Initializer *syntaxCopy(); - virtual Initializer *semantic(Scope *sc, Type *t, NeedInterpret 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, NeedInterpret 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, NeedInterpret 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, NeedInterpret needInterpret); - Type *inferType(Scope *sc); - Expression *toExpression(); - Initializer *toAssocArrayInitializer(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); - dt_t *toDtBit(); // for bit arrays -#endif - - ArrayInitializer *isArrayInitializer() { return this; } -}; - -struct ExpInitializer : Initializer -{ - Expression *exp; - int expandTuples; - - ExpInitializer(Loc loc, Expression *exp); - Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t, NeedInterpret 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/dmd/inline.c b/dmd/inline.c deleted file mode 100644 index 78438659..00000000 --- a/dmd/inline.c +++ /dev/null @@ -1,1825 +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. - -// Routines to perform function inlining - -#define LOG 0 - -#include -#include -#include -#include // memset() - -#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 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) -{ - //printf("DelegateExp::inlineCost3()\n"); - // This breaks on LDC too, since nested functions have internal linkage - // and thus can't be referenced from other objects. - return COST_MAX; -} - -int DeclarationExp::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; - } - } - 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() || vd->isConst()) - ; - 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 - { - ExpInitializer *ie = vd->init->isExpInitializer(); - assert(ie); - vto->init = new ExpInitializer(ie->loc, ie->exp->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; - } - - 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); - } - - 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). - else - { CtorDeclaration *ctor = isCtorDeclaration(); - - if (ctor && ctor->varargs == 1) - goto Lno; - } -#endif - - if ( - !fbody || - ident == Id::ensure || // ensure() has magic properties the inliner loses - (ident == Id::require && // require() has magic properties too - toParent()->isFuncDeclaration() && // see bug 7699 - toParent()->isFuncDeclaration()->needThis()) || - !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 !IN_LLVM -#if !SARRAYVALUE - /* 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 -#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 - 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 AssignExp(vto->loc, ve, arg); - ei->exp->op = TOKconstruct; - 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 = 0; - vd->linkage = tf->linkage; - vd->parent = iss->fd; - - VarExp *ve = new VarExp(loc, vd); - ve->type = tf->next; - - ei->exp = new AssignExp(loc, ve, e); - ei->exp->op = TOKconstruct; - 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 - if (op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)this; - - if (de->func->isNested()) - { /* See Bugzilla 4820 - * Defer checking until later if we actually need the 'this' pointer - */ - Expression *e = de->copy(); - return e; - } - } - - 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/dmd/interpret.c b/dmd/interpret.c deleted file mode 100644 index da2d1561..00000000 --- a/dmd/interpret.c +++ /dev/null @@ -1,7083 +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 // mem{cpy|set}() - -#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" -#include "port.h" -int RealEquals(real_t x1, real_t x2); - - -#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. - Note that when a function is forward referenced, the interpreter must - run semantic3, and that may start CTFE again with a NULL istate. Thus - the stack might not be empty when CTFE begins. - - 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), maxStackPointer(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[v->ctfeAdrOnStack]; - } - assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer()); - return values[v->ctfeAdrOnStack]; - } - void setValue(VarDeclaration *v, Expression *e) - { - assert(!v->isDataseg() || v->isCTFE()); - assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer()); - values[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[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[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[i]; - v->ctfeAdrOnStack = (size_t)(savedId[i]); - } - values.setDim(stackpointer); - vars.setDim(stackpointer); - savedId.setDim(stackpointer); - } - void saveGlobalConstant(VarDeclaration *v, Expression *e) - { -#if DMDV2 - assert( v->init && (v->isConst() || v->isImmutable()) && !v->isCTFE()); -#else - assert( v->init && v->isConst() && !v->isCTFE()); -#endif - 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(Loc loc, 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); -Expression *ctfeEqual(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2); - -// 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(); - } - VarDeclaration *getFieldAt(int index) - { - ClassDeclaration *cd = originalClass(); - size_t fieldsSoFar = 0; - while (index - fieldsSoFar >= cd->fields.dim) - { fieldsSoFar += cd->fields.dim; - cd = cd->baseClass; - } - return cd->fields[index - fieldsSoFar]; - } - // 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[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[j - fieldsSoFar]; - VarDeclaration *v2 = s->isVarDeclaration(); - if (v == v2) - { return value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar); - } - } - return -1; - } -}; - -struct VoidInitExp : Expression -{ - VarDeclaration *var; - - VoidInitExp(VarDeclaration *var, Type *type) - : Expression(var->loc, TOKvoid, sizeof(VoidInitExp)) - { - this->var = var; - this->type = var->type; - } - char *toChars() - { - return (char *)"void"; - } - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue) - { - error("CTFE internal error: trying to read uninitialized variable"); - assert(0); - return EXP_CANT_INTERPRET; - } -}; - -// 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[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[i]; - z = (*elements)[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[i - fieldsSoFar]; - size_t indx = (elements->dim - fieldsSoFar)- cd->fields.dim + i; - assert(indx >= 0); - assert(indx < elements->dim); - z = (*elements)[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); - } - } -} - -/************************************* - * - * Entry point for CTFE. - * A compile-time result is required. Give an error if not possible - */ -Expression *Expression::ctfeInterpret() -{ - return optimize(WANTvalue | WANTinterpret); -} - -/************************************* - * 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, - * or EXP_VOID_INTERPRET if function returned void. - */ - -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 = isSpeculative(); - if (global.gag && !spec) - global.gag = 0; - semantic3(scope); - 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)[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; - /* Struct literals are passed by value, but we don't need to - * copy them if they are passed as const - */ - if (earg->op == TOKstructliteral -#if DMDV2 - && !(arg->storageClass & (STCconst | STCimmutable)) -#endif - ) - earg = copyLiteral(earg); - } - if (earg->op == TOKthrownexception) - { - if (istate) - return earg; - ((ThrownExceptionExp *)earg)->generateUncaughtError(); - return EXP_CANT_INTERPRET; - } - eargs[i] = earg; - } - - for (size_t i = 0; i < dim; i++) - { Expression *earg = eargs[i]; - Parameter *arg = Parameter::getNth(tf->parameters, i); - VarDeclaration *v = (*parameters)[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 result is void, return void - if (e == EXP_VOID_INTERPRET) - return e; - - // 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 we're about to leave CTFE, make sure we don't crash the - // compiler by returning a CTFE-internal expression. - 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)[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)[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; -} - -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); -} - -bool scrubArray(Loc loc, Expressions *elems, bool structlit = false); - -/* 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 == TOKvoid) - { - error(loc, "uninitialized variable '%s' cannot be returned from CTFE", ((VoidInitExp *)e)->var->toChars()); - e = new ErrorExp(); - } - if (e->op == TOKslice) - { - e = resolveSlice(e); - } - if (e->op == TOKstructliteral) - { - StructLiteralExp *se = (StructLiteralExp *)e; - se->ownedByCtfe = false; - if (!scrubArray(loc, se->elements, true)) - return EXP_CANT_INTERPRET; - } - if (e->op == TOKstring) - { - ((StringExp *)e)->ownedByCtfe = false; - } - if (e->op == TOKarrayliteral) - { - ((ArrayLiteralExp *)e)->ownedByCtfe = false; - if (!scrubArray(loc, ((ArrayLiteralExp *)e)->elements)) - return EXP_CANT_INTERPRET; - } - if (e->op == TOKassocarrayliteral) - { - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e; - aae->ownedByCtfe = false; - if (!scrubArray(loc, aae->keys)) - return EXP_CANT_INTERPRET; - if (!scrubArray(loc, aae->values)) - return EXP_CANT_INTERPRET; - } - return e; -} - -// Scrub all members of an array. Return false if error -bool scrubArray(Loc loc, Expressions *elems, bool structlit) -{ - for (size_t i = 0; i < elems->dim; i++) - { - Expression *m = elems->tdata()[i]; - if (!m) - continue; - if (m && m->op == TOKvoid && structlit) - m = NULL; - if (m) - m = scrubReturnValue(loc, m); - if (m == EXP_CANT_INTERPRET) - return false; - elems->tdata()[i] = m; - } - return true; -} - - -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; - - while (1) - { - bool wasGoto = !!istate->start; - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (wasGoto && istate->start) - return NULL; - 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); - } - while (1) - { - if (condition && !istate->start) - { - e = condition->interpret(istate); - if (exceptionOrCantInterpret(e)) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (e->isBool(FALSE)) - { e = NULL; - break; - } - assert( isTrueBool(e) ); - } - - bool wasGoto = !!istate->start; - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (wasGoto && istate->start) - return NULL; - - 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 - istate->gotoTarget = NULL; - - if (increment) - { - e = increment->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - } - } - 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)[i]; - Expression * caseExp = cs->exp->interpret(istate); - if (exceptionOrCantInterpret(caseExp)) - return caseExp; - e = ctfeEqual(caseExp->loc, 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; - } - - 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 ? ca->handler->interpret(istate) : NULL; - } - } - 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 == EXP_CANT_INTERPRET) - return val; - 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 - // 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(); - assert(v); - 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->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->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); - ctfeStack.saveGlobalConstant(v, e); - } - } - else if (v->isCTFE() && !v->hasValue()) - { - if (v->init && v->type->size() != 0) - { - if (v->init->isVoidInitializer()) - { - // var should have been initialized when it was created - error(loc, "CTFE internal error - trying to access uninitialized var"); - assert(0); - e = EXP_CANT_INTERPRET; - } - else - { - 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) - { assert(!(v->init && v->init->isVoidInitializer())); - // CTFE initiated from inside a function - error(loc, "variable %s cannot be read at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } - 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 if (e->op == TOKvoid) - { - VoidInitExp *ve = (VoidInitExp *)e; - error(loc, "cannot read uninitialized variable %s in ctfe", v->toPrettyChars()); - errorSupplemental(ve->var->loc, "%s was uninitialized and used before set", ve->var->toChars()); - e = EXP_CANT_INTERPRET; - } - else - e = e->interpret(istate, goal); - } - if (!e) - e = EXP_CANT_INTERPRET; - } - else if (s) - { -#if !IN_LLVM - // Struct static initializers, for example - if (s->dsym->toInitializer() == s->sym) - { -#endif - e = s->dsym->type->defaultInitLiteral(loc); - e = e->semantic(NULL); - if (e->op == TOKerror) - e = EXP_CANT_INTERPRET; - else // Convert NULL to VoidExp - e = e->interpret(istate, goal); -#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 = v->type->voidInitLiteral(v); - // There is no AssignExp for void initializers, - // so set it here. - v->setValue(e); - } - 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)[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)[j] = (*exps)[j]; - } - } - (*expsx)[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)[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)[j] = (*elements)[j]; - } - } - (*expsx)[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(loc, 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)[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)[j] = (*elements)[j]; - } - } - (*expsx)[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)[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)[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)[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(loc)->toInteger()), - len, elemType->size()); - return createBlockDuplicatedArrayLiteral(loc, newtype, - elemType->defaultInitLiteral(loc), - 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(loc); -#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[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - Expression *m = v->init ? v->init->toExpression() : v->type->defaultInitLiteral(loc); - 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 (op == TOKadd || op == TOKaddass || op == TOKplusplus) - indx = indx + ofs2/sz; - else if (op == TOKmin || op == TOKminass || op == TOKminusminus) - indx -= ofs2/sz; - 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 %lld inside memory block [0..%lld]", 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)(Loc loc, enum TOK, Type *, Expression *, Expression *); - -/** Return true if agg1 and agg2 are pointers to the same memory block -*/ -bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2) -{ - // Note that type painting can occur with VarExp, so we - // must compare the variables being pointed to. - return agg1 == agg2 || - (agg1->op == TOKvar && agg2->op == TOKvar && - ((VarExp *)agg1)->var == ((VarExp *)agg2)->var); -} - -// Return 1 if true, 0 if false -// -1 if comparison is illegal because they point to non-comparable memory blocks -int comparePointers(Loc loc, enum TOK op, Type *type, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2) -{ - if ( pointToSameMemoryBlock(agg1, agg2) ) - { - 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 n; - } - bool null1 = ( agg1->op == TOKnull ); - bool null2 = ( agg2->op == TOKnull ); - - int cmp; - if (null1 || null2) - { - switch (op) - { - case TOKlt: cmp = null1 && !null2; break; - case TOKgt: cmp = !null1 && null2; break; - case TOKle: cmp = null1; break; - case TOKge: cmp = null2; break; - case TOKidentity: - case TOKequal: - case TOKnotidentity: // 'cmp' gets inverted below - case TOKnotequal: - cmp = (null1 == null2); - break; - } - } - else - { - switch(op) - { - case TOKidentity: - case TOKequal: - case TOKnotidentity: // 'cmp' gets inverted below - case TOKnotequal: - cmp = 0; - break; - default: - return -1; // memory blocks are different - } - } - if (op == TOKnotidentity || op == TOKnotequal) - cmp ^= 1; - return cmp; -} - - -int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2); - -/* Conceptually the same as memcmp(e1, e2). - * e1 and e2 may be strings, arrayliterals, or slices. - * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. - * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. - */ -int ctfeCmpArrays(Loc loc, Expression *e1, Expression *e2, uinteger_t len) -{ - // Resolve slices, if necessary - uinteger_t lo1 = 0; - uinteger_t lo2 = 0; - - Expression *x = e1; - if (x->op == TOKslice) - { lo1 = ((SliceExp *)x)->lwr->toInteger(); - x = ((SliceExp*)x)->e1; - } - StringExp *se1 = (x->op == TOKstring) ? (StringExp *)x : 0; - ArrayLiteralExp *ae1 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : 0; - - x = e2; - if (x->op == TOKslice) - { lo2 = ((SliceExp *)x)->lwr->toInteger(); - x = ((SliceExp*)x)->e1; - } - StringExp *se2 = (x->op == TOKstring) ? (StringExp *)x : 0; - ArrayLiteralExp *ae2 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : 0; - - // Now both must be either TOKarrayliteral or TOKstring - if (se1 && se2) - return sliceCmpStringWithString(se1, se2, lo1, lo2, len); - if (se1 && ae2) - return sliceCmpStringWithArray(se1, ae2, lo1, lo2, len); - if (se2 && ae1) - return -sliceCmpStringWithArray(se2, ae1, lo2, lo1, len); - - assert (ae1 && ae2); - // Comparing two array literals. This case is potentially recursive. - // If they aren't strings, we just need an equality check rather than - // a full cmp. - bool needCmp = ae1->type->nextOf()->isintegral(); - for (size_t i = 0; i < len; i++) - { Expression *ee1 = (*ae1->elements)[lo1 + i]; - Expression *ee2 = (*ae2->elements)[lo2 + i]; - if (needCmp) - { int c = ee1->toInteger() - ee2->toInteger(); - if (c) - return c; - } - else - { if (ctfeRawCmp(loc, ee1, ee2)) - return 1; - } - } - return 0; -} - -bool isArray(Expression *e) -{ - return e->op == TOKarrayliteral || e->op == TOKstring || - e->op == TOKslice || e->op == TOKnull; -} - -/* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. - * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. - */ -int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2) -{ - if (e1->op == TOKclassreference || e2->op == TOKclassreference) - { if (e1->op == TOKclassreference && e2->op == TOKclassreference && - ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value) - return 0; - return 1; - } - if (e1->op == TOKnull && e2->op == TOKnull) - return 0; - - if (e1->type->ty == Tpointer && e2->type->ty == Tpointer) - { // Can only be an equality test. - if (e1->op == TOKnull && e2->op == TOKnull) - return 0; - dinteger_t ofs1, ofs2; - Expression *agg1 = getAggregateFromPointer(e1, &ofs1); - Expression *agg2 = getAggregateFromPointer(e2, &ofs2); - if ((agg1 == agg2) || (agg1->op == TOKvar && agg2->op == TOKvar && - ((VarExp *)agg1)->var == ((VarExp *)agg2)->var)) - { if (ofs1 == ofs2) - return 0; - } - return 1; - } - if (isArray(e1) && isArray(e2)) - { - uinteger_t len1 = resolveArrayLength(e1); - uinteger_t len2 = resolveArrayLength(e2); - if (len1 != len2) // only for equality - return len1 - len2; - if (len1 == 0 || len2 == 0) - return len1 - len2; // Equal - both are empty - return ctfeCmpArrays(loc, e1, e2, len1); - } - if (e1->type->isintegral()) - { - return e1->toInteger() - e2->toInteger(); - } - real_t r1; - real_t r2; - if (e1->type->isreal()) - { - r1 = e1->toReal(); - r2 = e2->toReal(); - goto L1; - } - else if (e1->type->isimaginary()) - { - r1 = e1->toImaginary(); - r2 = e2->toImaginary(); - L1: -#if __DMC__ - return (r1 != r2); -#else - if (Port::isNan(r1) || Port::isNan(r2)) // if unordered - { - return 1; - } - else - { - return (r1 != r2); - } -#endif - } - else if (e1->type->iscomplex()) - { - return e1->toComplex() != e2->toComplex(); - } - - if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) - { StructLiteralExp *es1 = (StructLiteralExp *)e1; - StructLiteralExp *es2 = (StructLiteralExp *)e2; - // For structs, we only need to return 0 or 1 (< and > aren't legal). - - if (es1->sd != es2->sd) - return 1; - else if ((!es1->elements || !es1->elements->dim) && - (!es2->elements || !es2->elements->dim)) - return 0; // both arrays are empty - else if (!es1->elements || !es2->elements) - return 1; - else if (es1->elements->dim != es2->elements->dim) - return 1; - else - { - 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) - return 1; - int cmp = ctfeRawCmp(loc, ee1, ee2); - if (cmp) - return 1; - } - return 0; // All elements are equal - } - } - error(loc, "CTFE internal error: bad compare"); - assert(0); - return 0; -} - -// As Equal, but resolves slices before comparing -Expression *ctfeEqual(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) -{ - int cmp = !ctfeRawCmp(loc, e1, e2); - if (op == TOKnotequal) - cmp ^= 1; - return new IntegerExp(loc, cmp, type); -} - -Expression *ctfeIdentity(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) -{ - 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 - cmp = !ctfeRawCmp(loc, e1, e2); - - if (op == TOKnotidentity || op == TOKnotequal) - cmp ^= 1; - return new IntegerExp(loc, cmp, type); -} - -Expression *ctfeCmp(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) -{ - return Cmp(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; - dinteger_t ofs1, ofs2; - Expression *agg1 = getAggregateFromPointer(e1, &ofs1); - Expression *agg2 = getAggregateFromPointer(e2, &ofs2); - int cmp = comparePointers(loc, op, type, agg1, ofs1, agg2, ofs2); - if (cmp == -1) - { - char dir = (op == TOKgt || op == TOKge) ? '<' : '>'; - error("The ordering of pointers to unrelated memory blocks is indeterminate in CTFE." - " To check if they point to the same memory block, use both > and < inside && or ||, " - "eg (%s && %s %c= %s + 1)", - toChars(), this->e1->toChars(), dir, this->e2->toChars()); - return EXP_CANT_INTERPRET; - } - return new IntegerExp(loc, cmp, type); - } - 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)(loc, 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, ctfeEqual) -BIN_INTERPRET2(Identity, ctfeIdentity) -BIN_INTERPRET2(Cmp, ctfeCmp) - -/* 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)[j] = newelem; - else - (*expsx)[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(loc, 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[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - // If it is a void assignment, use the default initializer - if (!m) - m = v->type->voidInitLiteral(v); - 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 - || e->op == TOKvoid) - { // 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 && e->op != TOKvoid) - { - 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) - || e1->type->toBasetype()->ty == Tclass) - // 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(loc); - - 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)[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)[i] = copyLiteral(defaultElem); - } - else - { - for (size_t i = copylen; i < newlen; i++) - (*elements)[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(loc))); - - // --------------------------------------- - // 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(loc, 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, isPointer(type)? ctfeNeedLvalueRef : 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 - ? findFieldIndexByName(se->sd, member) - : ((ClassReferenceExp *)exx)->findFieldIndexByName(member); - 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 it's a union, set all other members of this union to void - if (exx->op == TOKstructliteral) - { - assert(se->sd); - int unionStart = se->sd->firstFieldInUnion(fieldi); - int unionSize = se->sd->numFieldsInUnion(fieldi); - for(int i = unionStart; i < unionStart + unionSize; ++i) - { if (i == fieldi) - continue; - Expression **el = &se->elements->tdata()[i]; - if ((*el)->op != TOKvoid) - *el = (*el)->type->voidInitLiteral(member); - } - } - - 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; - if (aggregate->op != TOKslice && aggregate->op != TOKstring && - aggregate->op != TOKarrayliteral && aggregate->op != TOKassocarrayliteral) - { - if (indexToModify != 0) - { - error("pointer index [%lld] lies outside memory block [0..1]", indexToModify); - return EXP_CANT_INTERPRET; - } - // It is equivalent to *aggregate = newval. - // Aggregate could be varexp, a dotvar, ... - // TODO: we could support this - error("indexed assignment of non-array pointers is not yet supported at compile time; use *%s = %s instead", - ie->e1->toChars(), e2->toChars()); - return EXP_CANT_INTERPRET; - } - 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(loc, (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); - if (exceptionOrCantInterpret(oldval)) - return oldval; - 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) - { - if (assignmentToSlicedPointer) - { - error("pointer %s cannot be sliced at compile time (it does not point to an array)", - sexp->e1->toChars()); - } - else - 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(loc, (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..%lld]", - 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); - if (aggregate->op == TOKnull) - { - error("cannot slice null pointer %s", sexp->e1->toChars()); - return EXP_CANT_INTERPRET; - } - dinteger_t hi = upperbound + ofs; - firstIndex = lowerbound + ofs; - if (firstIndex < 0 || hi > dim) - { - error("slice [lld..%lld] exceeds memory block bounds [0..%lld]", - 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()); - } - 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; -} - -/* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison; - * -1 if e is a p1 < p2 or p1 <= p2 pointer comparison; - * 0 otherwise - */ -int isPointerCmpExp(Expression *e, Expression **p1, Expression **p2) -{ - int ret = 1; - while (e->op == TOKnot) - { ret *= -1; - e = ((NotExp *)e)->e1; - } - switch(e->op) - { - case TOKlt: - case TOKle: - ret *= -1; - /* fall through */ - case TOKgt: - case TOKge: - *p1 = ((BinExp *)e)->e1; - *p2 = ((BinExp *)e)->e2; - if ( !(isPointer((*p1)->type) && isPointer((*p2)->type)) ) - ret = 0; - break; - default: - ret = 0; - break; - } - return ret; -} - -/** Negate a relational operator, eg >= becomes < - */ -TOK reverseRelation(TOK op) -{ - switch(op) - { - case TOKge: return TOKlt; - case TOKgt: return TOKle; - case TOKle: return TOKgt; - case TOKlt: return TOKge; - default: - return assert(0), TOKreserved; - } -} - -/** If this is a four pointer relation, evaluate it, else return NULL. - * - * This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2) - * where p1, p2 are expressions yielding pointers to memory block p, - * and q1, q2 are expressions yielding pointers to memory block q. - * This expression is valid even if p and q are independent memory - * blocks and are therefore not normally comparable; the && form returns true - * if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns - * true if [p1..p2] lies outside [q1..q2], and false otherwise. - * - * Within the expression, any ordering of p1, p2, q1, q2 is permissible; - * the comparison operators can be any of >, <, <=, >=, provided that - * both directions (p > q and p < q) are checked. Additionally the - * relational sub-expressions can be negated, eg - * ( !(q1 < p1) && p2 <= q2 ) is valid. - */ -Expression *BinExp::interpretFourPointerRelation(InterState *istate, CtfeGoal goal) -{ - assert(op == TOKandand || op == TOKoror); - - /* It can only be an isInside expression, if both e1 and e2 are - * directional pointer comparisons. - * Note that this check can be made statically; it does not depends on - * any runtime values. This allows a JIT implementation to compile a - * special AndAndPossiblyInside, keeping the normal AndAnd case efficient. - */ - - // Save the pointer expressions and the comparison directions, - // so we can use them later. - Expression *p1, *p2, *p3, *p4; - int dir1 = isPointerCmpExp(e1, &p1, &p2); - int dir2 = isPointerCmpExp(e2, &p3, &p4); - if ( dir1 == 0 || dir2 == 0 ) - return NULL; - - //printf("FourPointerRelation %s\n", toChars()); - - // Evaluate the first two pointers - p1 = p1->interpret(istate); - if (exceptionOrCantInterpret(p1)) - return p1; - p2 = p2->interpret(istate); - if (exceptionOrCantInterpret(p1)) - return p1; - dinteger_t ofs1, ofs2; - Expression *agg1 = getAggregateFromPointer(p1, &ofs1); - Expression *agg2 = getAggregateFromPointer(p2, &ofs2); - - if ( !pointToSameMemoryBlock(agg1, agg2) - && agg1->op != TOKnull && agg2->op != TOKnull) - { // Here it is either CANT_INTERPRET, - // or an IsInside comparison returning FALSE. - p3 = p3->interpret(istate); - if (p3 == EXP_CANT_INTERPRET) - return p3; - // Note that it is NOT legal for it to throw an exception! - Expression *except = NULL; - if (exceptionOrCantInterpret(p3)) - except = p3; - else - { - p4 = p4->interpret(istate); - if (p4 == EXP_CANT_INTERPRET) - return p4; - if (exceptionOrCantInterpret(p3)) - except = p4; - } - if (except) - { error("Comparison %s of pointers to unrelated memory blocks remains " - "indeterminate at compile time " - "because exception %s was thrown while evaluating %s", - this->e1->toChars(), except->toChars(), this->e2->toChars()); - return EXP_CANT_INTERPRET; - } - dinteger_t ofs3,ofs4; - Expression *agg3 = getAggregateFromPointer(p3, &ofs3); - Expression *agg4 = getAggregateFromPointer(p4, &ofs4); - // The valid cases are: - // p1 > p2 && p3 > p4 (same direction, also for < && <) - // p1 > p2 && p3 < p4 (different direction, also < && >) - // Changing any > into >= doesnt affect the result - if ( (dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) - && pointToSameMemoryBlock(agg2, agg3)) - || (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) - && pointToSameMemoryBlock(agg2, agg4)) ) - { // it's a legal two-sided comparison - return new IntegerExp(loc, (op == TOKandand) ? 0 : 1, type); - } - // It's an invalid four-pointer comparison. Either the second - // comparison is in the same direction as the first, or else - // more than two memory blocks are involved (either two independent - // invalid comparisons are present, or else agg3 == agg4). - error("Comparison %s of pointers to unrelated memory blocks is " - "indeterminate at compile time, even when combined with %s.", - e1->toChars(), e2->toChars()); - return EXP_CANT_INTERPRET; - } - // The first pointer expression didn't need special treatment, so we - // we need to interpret the entire expression exactly as a normal && or ||. - // This is easy because we haven't evaluated e2 at all yet, and we already - // know it will return a bool. - // But we mustn't evaluate the pointer expressions in e1 again, in case - // they have side-effects. - bool nott = false; - Expression *e = e1; - while (e->op == TOKnot) - { nott= !nott; - e = ((NotExp *)e)->e1; - } - TOK cmpop = e->op; - if (nott) - cmpop = reverseRelation(cmpop); - int cmp = comparePointers(loc, cmpop, e1->type, agg1, ofs1, agg2, ofs2); - // We already know this is a valid comparison. - assert(cmp >= 0); - if ( (op == TOKandand && cmp == 1) || (op == TOKoror && cmp == 0) ) - return e2->interpret(istate); - return new IntegerExp(loc, (op == TOKandand) ? 0 : 1, type); -} - -Expression *AndAndExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("AndAndExp::interpret() %s\n", toChars()); -#endif - - // Check for an insidePointer expression, evaluate it if so - Expression *e = interpretFourPointerRelation(istate, goal); - if (e) - return e; - - 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->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 - - // Check for an insidePointer expression, evaluate it if so - Expression *e = interpretFourPointerRelation(istate, goal); - if (e) - return e; - - 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 (ecall->op == TOKsymoff) - fd = ((SymOffExp *)ecall)->var->isFuncDeclaration(); - } - } - 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)[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); - } - else if (eresult == EXP_VOID_INTERPRET) - ; - else - eresult->loc = loc; - 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) - { - 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(loc))); - } - 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(Loc loc, 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(loc, TOKequal, Type::tbool, ekey, e2); - if (ex == EXP_CANT_INTERPRET) - 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; - } - if ( 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 [%lld] exceeds allocated memory block [0..%lld]", - indx+ofs, len); - return EXP_CANT_INTERPRET; - } - return ctfeIndex(loc, type, agg, indx+ofs); - } - else - { // Pointer to a non-array variable - if ((indx + ofs) != 0) - { - error("pointer index [%lld] lies outside memory block [0..1]", - indx+ofs); - return EXP_CANT_INTERPRET; - } - return agg->interpret(istate); - } - } - 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 %llu exceeds array length %llu", 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(loc, (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); - if (goal == ctfeNeedRvalue && e->op == TOKvoid) - { - error("%s is used before initialized", toChars()); - errorSupplemental(e->loc, "originally uninitialized here"); - return EXP_CANT_INTERPRET; - } - 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; - } - if (agg->op != TOKarrayliteral && agg->op != TOKstring) - { - error("pointer %s cannot be sliced at compile time (it does not point to an array)", - 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 [%lld..%lld] exceeds allocated memory block [0..%lld]", - 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 [%llu..%llu] 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[%llu..%llu] exceeds array bounds[%llu..%llu]", - 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 [%lld..%lld] exceeds array bounds [0..%lld]", - 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(loc, (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()); - return e; - } - // 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 && sym->parent && - sym->parent->parent && - sym->parent->parent->ident == Id::object) - { - 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; - } - - // Check if we have a null pointer (eg, inside a struct) - e1 = e1->interpret(istate); - if (e1->op != TOKnull) - { - 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) - { // Note that the slice may be void[], so when checking for dangerous - // casts, we need to use the original type, which is se->e1. - SliceExp *se = (SliceExp *)e1; - if ( !isSafePointerCast( se->e1->type->nextOf(), to->nextOf() ) ) - { - error("array cast from %s to %s is not supported at compile time", - se->e1->type->toChars(), to->toChars()); - return EXP_CANT_INTERPRET; - } - e1 = new SliceExp(e1->loc, se->e1, se->lwr, se->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..%lld]", - 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 = findKeyInAA(loc, (AssocArrayLiteralExp *)ie->e1, ie->e2); - assert(e != EXP_CANT_INTERPRET); - e = paintTypeOntoLiteral(type, e); - 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 - else 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 (e->op == TOKvoid) - { - VoidInitExp *ve = (VoidInitExp *)e; - error("cannot read uninitialized variable %s in ctfe", toChars()); - ve->var->error("was uninitialized and used before set"); - return EXP_CANT_INTERPRET; - } - 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(loc, 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[numParams - 1] = evalue; - if (numParams == 2) args[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 - { str->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[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[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)[i]; - earg = earg->interpret(istate); - if (exceptionOrCantInterpret(earg)) - return earg; - args[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)[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)[0]; - str = str->interpret(istate); - if (exceptionOrCantInterpret(str)) - return str; - return foreachApplyUtf(istate, str, (*arguments)[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 (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; - } - if (newval->op == TOKvoid) - { - 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); -} - - -Expression *Type::voidInitLiteral(VarDeclaration *var) -{ - return new VoidInitExp(var, this); -} - -Expression *TypeSArray::voidInitLiteral(VarDeclaration *var) -{ - return createBlockDuplicatedArrayLiteral(var->loc, this, next->voidInitLiteral(var), dim->toInteger()); -} - -Expression *TypeStruct::voidInitLiteral(VarDeclaration *var) -{ - Expressions *exps = new Expressions(); - exps->setDim(sym->fields.dim); - for (size_t i = 0; i < sym->fields.dim; i++) - { - //(*exps)[i] = new VoidInitExp(var, sym->fields[i]->type); - (*exps)[i] = sym->fields[i]->type->voidInitLiteral(var); - } - StructLiteralExp *se = new StructLiteralExp(var->loc, sym, exps); - se->type = this; - se->ownedByCtfe = true; - return se; -} diff --git a/dmd/json.c b/dmd/json.c deleted file mode 100644 index d3efacf5..00000000 --- a/dmd/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/dmd/json.h b/dmd/json.h deleted file mode 100644 index 2c7e2e60..00000000 --- a/dmd/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/dmd/lexer.c b/dmd/lexer.c deleted file mode 100644 index 98de26e8..00000000 --- a/dmd/lexer.c +++ /dev/null @@ -1,3227 +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. - -#if __sun && __SVR4 -#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more, LDC#313 -#endif - -#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(tokenLoc(), 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); -} - -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", p - pstart, pstart, 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->toDchars(),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) - SINGLE('@', TOKat) -#undef SINGLE - -#define DOUBLE(c1,tok1,c2,tok2) \ - case c1: \ - p++; \ - if (*p == c2) \ - { p++; \ - t->value = tok2; \ - } \ - else \ - t->value = tok1; \ - return; - - DOUBLE('*', TOKmul, '=', TOKmulass) - DOUBLE('%', TOKmod, '=', TOKmodass) -#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); -#if 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; - } - goto Lerr; - - 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; -} - -/******************************************* - * Search actual location of current token - * even when infinite look-ahead was done. - */ -Loc Lexer::tokenLoc() -{ - Loc result = this->loc; - Token* last = &token; - while (last->next) - last = last->next; - - unsigned char* start = token.ptr; - unsigned char* stop = last->ptr; - - for (unsigned char* p = start; p < stop; ++p) - { - switch (*p) - { - case '\n': - result.linnum--; - break; - case '\r': - if (p[1] != '\n') - result.linnum--; - break; - default: - break; - } - } - return result; -} - -/******************************************** - * 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->toDchars(), 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->toDchars(),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] = "=>"; - Token::tochars[TOKpound] = "#"; -#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/dmd/lexer.h b/dmd/lexer.h deleted file mode 100644 index b8b51d7a..00000000 --- a/dmd/lexer.h +++ /dev/null @@ -1,321 +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. - -#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, - TOKat, -#if DMDV2 - TOKtraits, - TOKoverloadset, - TOKpure, - TOKnothrow, - TOKtls, - TOKgshared, - TOKline, - TOKfile, - TOKshared, - TOKpow, - TOKpowass, - TOKgoesto, - TOKvector, - TOKpound, -#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_int64 int64value; - d_uns64 uns64value; - - // Floats -#ifdef IN_GCC - // real_t float80value; // can't use this in a union! -#else - d_float80 float80value; -#endif - - struct - { unsigned char *ustring; // UTF8 string - unsigned len; - unsigned char postfix; // 'c', 'w', 'd' - }; - - Identifier *ident; - }; -#ifdef IN_GCC - real_t float80value; // can't use this in a union! -#endif - - static const char *tochars[TOKMAX]; - static void *operator new(size_t sz); - - int isKeyword(); - void print(); - const char *toChars(); - static const char *toChars(enum TOK); -}; - -struct Lexer -{ - static StringTable stringtable; - static OutBuffer stringbuffer; - static Token *freelist; - - Loc loc; // for error messages - - unsigned char *base; // pointer to start of buffer - unsigned char *end; // past end of buffer - unsigned char *p; // current character - Token token; - Module *mod; - int doDocComment; // collect doc comment information - int anyToken; // !=0 means seen at least one token - int commentToken; // !=0 means comments are TOKcomment's - - Lexer(Module *mod, - unsigned char *base, unsigned begoffset, unsigned endoffset, - int doDocComment, int commentToken); - - static void initKeywords(); - static Identifier *idPool(const char *s); - static Identifier *uniqueId(const char *s); - static Identifier *uniqueId(const char *s, int num); - - TOK nextToken(); - TOK peekNext(); - TOK peekNext2(); - void scan(Token *t); - Token *peek(Token *t); - Token *peekPastParen(Token *t); - unsigned escapeSequence(); - TOK wysiwygStringConstant(Token *t, int tc); - TOK hexStringConstant(Token *t); -#if DMDV2 - TOK delimitedStringConstant(Token *t); - TOK tokenStringConstant(Token *t); -#endif - TOK escapeStringConstant(Token *t, int wide); - TOK charConstant(Token *t, int wide); - void stringPostfix(Token *t); - unsigned wchar(unsigned u); - TOK number(Token *t); - TOK inreal(Token *t); - void error(const char *format, ...) IS_PRINTF(2); - void error(Loc loc, const char *format, ...) IS_PRINTF(3); - void pragma(); - unsigned decodeUTF(); - void getDocComment(Token *t, unsigned lineComment); - - static int isValidIdentifier(char *p); - static unsigned char *combineComments(unsigned char *c1, unsigned char *c2); - - Loc tokenLoc(); -}; - -#endif /* DMD_LEXER_H */ diff --git a/dmd/macro.c b/dmd/macro.c deleted file mode 100644 index 398ba77f..00000000 --- a/dmd/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/dmd/macro.h b/dmd/macro.h deleted file mode 100644 index 7c939621..00000000 --- a/dmd/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/dmd/mangle.c b/dmd/mangle.c deleted file mode 100644 index bd089803..00000000 --- a/dmd/mangle.c +++ /dev/null @@ -1,300 +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 -#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), type %s\n", sthis->toChars(), sthis->type->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()) // 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 DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS) - 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()) - return ident->toChars(); - - assert(this); - return Declaration::mangle(); - } - -char *StructDeclaration::mangle() -{ - //printf("StructDeclaration::mangle() '%s'\n", toChars()); - return Dsymbol::mangle(); -} - - -char *TypedefDeclaration::mangle() -{ - //printf("TypedefDeclaration::mangle() '%s'\n", toChars()); - return Dsymbol::mangle(); -} - - -char *ClassDeclaration::mangle() -{ - Dsymbol *parentsave = parent; - - //printf("ClassDeclaration::mangle() %s.%s\n", parent->toChars(), toChars()); - - /* These are reserved to the compiler, so keep simple - * names for them. - */ - if (ident == Id::Exception) - { if (parent->ident == Id::object) - parent = NULL; - } - else if (ident == Id::TypeInfo || -// ident == Id::Exception || - ident == Id::TypeInfo_Struct || - ident == Id::TypeInfo_Class || - ident == Id::TypeInfo_Typedef || - ident == Id::TypeInfo_Tuple || - this == object || - this == classinfo || - this == Module::moduleinfo || - memcmp(ident->toChars(), "TypeInfo_", 9) == 0 - ) - parent = NULL; - - char *id = Dsymbol::mangle(); - parent = parentsave; - return id; -} - - -char *TemplateInstance::mangle() -{ - OutBuffer buf; - -#if 0 - printf("TemplateInstance::mangle() %s", 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; -} - - -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; -} - -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/dmd/mars.c b/dmd/mars.c deleted file mode 100644 index 15c0281a..00000000 --- a/dmd/mars.c +++ /dev/null @@ -1,396 +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 -#include -#include -#if IN_LLVM -#include -#endif - -#if POSIX -#include -#endif - -#include "rmem.h" -#include "root.h" - -#include "mars.h" -#include "module.h" -#include "mtype.h" -#include "id.h" -#include "cond.h" -#include "expression.h" -#include "lexer.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); - -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"; - -// LDC - ll_ext = "ll"; - bc_ext = "bc"; - s_ext = "s"; - obj_ext = "o"; - obj_ext_alt = "obj"; - - copyright = "Copyright (c) 1999-2012 by Digital Mars and Tomas Lindquist Olsen"; - written = "written by Walter Bright and Tomas Lindquist Olsen"; - version = "v1.075"; - ldc_version = "trunk"; - llvm_version = "LLVM "LDC_LLVM_VERSION_STRING; - global.structalign = STRUCTALIGN_DEFAULT; - - // 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; -} - -bool Global::isSpeculativeGagging() -{ - return gag && gag == speculativeGag; -} - - -char *Loc::toChars() const -{ - 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, const char *p1, const char *p2) -{ - if (!global.gag) - { - char *p = loc.toChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Error: "); - if (p1) - fprintf(stdmsg, "%s ", p1); - if (p2) - fprintf(stdmsg, "%s ", p2); -#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); - if (global.errors >= 20) // moderate blizzard of cascading messages - fatal(); -//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 -} - -/*********************************** - * 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); - - size_t argc_left = 0; - for (size_t 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 { - argv->data[i] = (void *)(*pargv)[i]; - } - } - // 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/dmd/mars.h b/dmd/mars.h deleted file mode 100644 index eb67e031..00000000 --- a/dmd/mars.h +++ /dev/null @@ -1,528 +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. - -#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 - -#if IN_LLVM -#include "llvm/ADT/Triple.h" -#endif - -#ifdef __DMC__ -#ifdef DEBUG -#undef assert -#define assert(e) (static_cast((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt()))) -#endif -#endif - -#ifndef IS_PRINTF -# ifdef __GNUC__ -# define IS_PRINTF(FMTARG) __attribute__((__format__ (__printf__, (FMTARG), (FMTARG)+1) )) -# else -# define IS_PRINTF(FMTARG) -# endif -#endif - -#ifndef IS_VPRINTF -# ifdef __GNUC__ -# define IS_VPRINTF(FMTARG) __attribute__((__format__ (__printf__, (FMTARG), 0) )) -# else -# define IS_VPRINTF(FMTARG) -# endif -#endif - -#ifdef IN_GCC -/* Changes for the GDC compiler by David Friedman */ -#endif - -#define DMDV2 0 // Version 2.0 features -#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; - -#if IN_LLVM -enum OUTPUTFLAG -{ - OUTPUTFLAGno, - OUTPUTFLAGdefault, // for the .o default - OUTPUTFLAGset // for -output -}; - -enum OS -{ - OSinvalid = llvm::Triple::UnknownOS, - OSLinux = llvm::Triple::Linux, - OSHaiku = llvm::Triple::Haiku, - OSWindows = llvm::Triple::Win32, - OSMacOSX = llvm::Triple::MacOSX, - OSFreeBSD = llvm::Triple::FreeBSD, - OSSolaris = llvm::Triple::Solaris, -}; -#endif - -typedef unsigned char ubyte; - -// Can't include arraytypes.h here, need to declare these directly. -template struct ArrayBase; -//typedef ArrayBase Identifiers; -typedef ArrayBase Strings; - -// Put command line switches in here -struct Param -{ - bool obj; // write object file - bool link; // perform link - bool verbose; // verbose compile - ubyte symdebug; // insert debug symbolic information -#if !IN_LLVM - // LDC uses a different mechanism - bool optimize; // run optimizer - char optimizeLevel; // optimization level -#endif - char vtls; // identify thread local variables -// KN Start merge conflict - 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 -// KN End merge conflict -#if 0 - char symdebug; // insert debug symbolic information - char alwaysframe; // always emit standard stack frame - char optimize; // run optimizer - char map; // generate linker .map file - char cpu; // target CPU - char is64bit; // generate 64 bit code - char isLinux; // generate code for linux - char isOSX; // generate code for Mac OSX - char isWindows; // generate code for Windows - char isFreeBSD; // generate code for FreeBSD - char isOPenBSD; // generate code for OpenBSD - char isSolaris; // generate code for Solaris - char scheduler; // which scheduler to use - char useDeprecated; // allow use of deprecated features - char useAssert; // generate runtime code for assert()'s - char useInvariants; // generate class invariant checks - char useIn; // generate precondition checks - char useOut; // generate postcondition checks - char useArrayBounds; // 0: no array bounds checks - // 1: array bounds checks for safe functions only - // 2: array bounds checks for all functions - char noboundscheck; // no array bounds checking at all - char useSwitchError; // check for switches without a default - char useUnitTests; // generate unittest code - char useInline; // inline expand functions - char release; // build release version - char preservePaths; // !=0 means don't strip path from source file - char warnings; // 0: enable warnings -#endif - // 1: warnings as errors - // 2: informational warnings (no errors) - ubyte Dversion; // D version number - bool ignoreUnsupportedPragmas; // rather than error on them - char safe; // enforce safe memory model - - 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/.lib 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 useInlineAsm; - bool verbose_cg; - bool useAvailableExternally; - - // target stuff - llvm::Triple targetTriple; - - // Codegen cl options - bool singleObj; - bool disableRedZone; -#endif -}; - -typedef unsigned structalign_t; -#define STRUCTALIGN_DEFAULT ~0 // magic value means "match whatever the underlying C compiler does" -// other values are all powers of 2 - -struct Global -{ - const char *mars_ext; - const char *sym_ext; - const char *obj_ext; -#if IN_LLVM - const char *obj_ext_alt; - const char *ll_ext; - const char *bc_ext; - const 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 - - structalign_t structalign; // default alignment for struct fields - - const char *version; - char *ldc_version; - char *llvm_version; - - 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 - - /* Gagging can either be speculative (is(typeof()), etc) - * or because of forward references - */ - unsigned speculativeGag; // == gag means gagging is for is(typeof); - bool isSpeculativeGagging(); - - // 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__) - -#include "longdouble.h" - -#ifdef __DMC__ - #include - 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 longdouble 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 longdouble 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() const; - 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 ap, const char *p1 = NULL, const char *p2 = NULL); -void vwarning(Loc loc, const char *format, va_list); -void verrorSupplemental(Loc loc, const char *format, va_list); - -#if defined(__GNUC__) || defined(__clang__) -__attribute__((noreturn)) -#endif -void fatal(); - -void err_nomem(); -#if IN_LLVM -void error(const char *format, ...) IS_PRINTF(1); -#else -void inifile(char *argv0, const char *inifile); -#endif -void halt(); - -const char *importHint(const char *s); - -/*** Where to send error messages ***/ -#if IN_GCC || IN_LLVM -#define stdmsg stderr -#else -#define stdmsg stderr -#endif - -#endif /* DMD_MARS_H */ diff --git a/dmd/mem.c b/dmd/mem.c deleted file mode 100644 index 35aec3cf..00000000 --- a/dmd/mem.c +++ /dev/null @@ -1,269 +0,0 @@ - -/* Copyright (c) 2000 Digital Mars */ -/* All Rights Reserved */ - -#include -#include -#include -#include - -#include "rmem.h" - -#if USE_BOEHM_GC - // I needed to perfix the dir after upgrading to gc 7.0 - #include "gc/gc.h" -#endif - -/* This implementation of the storage allocator uses the standard C allocation package. - */ - -Mem mem; - -#if USE_BOEHM_GC - -static bool gc_was_init = false; - -void Mem::init() -{ - GC_init(); - gc_was_init = true; -} - -char *Mem::strdup(const char *s) -{ - char *p; - - if (s) - { - p = GC_strdup(s); - if (p) - return p; - error(); - } - return NULL; -} - -void *Mem::malloc(size_t size) -{ void *p; - - if (!size) - p = NULL; - else - { - p = GC_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 = GC_malloc(size * n); - if (!p) - error(); - memset(p, 0, size * n); - } - return p; -} - -void *Mem::realloc(void *p, size_t size) -{ - if (!size) - { if (p) - { GC_free(p); - p = NULL; - } - } - else if (!p) - { - p = GC_malloc(size); - if (!p) - error(); - } - else - { - p = GC_realloc(p, size); - if (!p) - error(); - } - return p; -} - -void Mem::free(void *p) -{ - if (p) - GC_free(p); -} - -void *Mem::mallocdup(void *o, size_t size) -{ void *p; - - if (!size) - p = NULL; - else - { - p = GC_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() -{ - GC_gcollect(); -} - -void Mem::mark(void *pointer) -{ - (void) pointer; // necessary for VC /W4 -} - -/* =================================================== */ - -void * operator new(size_t m_size) -{ - // without this we segfault with gc 7.0 - if (!gc_was_init) { - mem.init(); - } - void *p = GC_malloc(m_size); - if (p) - return p; - printf("Error: out of memory\n"); - exit(EXIT_FAILURE); - return p; -} - -void operator delete(void *p) -{ - GC_free(p); -} - -#elif !USE_BOEHM_GC - -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 = ::malloc(size * n); - if (!p) - error(); - memset(p, 0, size * n); - } - 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 - { - p = ::realloc(p, size); - if (!p) - 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 Mem::setStackBottom(void */*stackbottom*/) -{ -} - -#endif // USE_BOEHM_GC diff --git a/dmd/mem.h b/dmd/mem.h deleted file mode 100644 index 85ebda62..00000000 --- a/dmd/mem.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2000-2001 by Chromium Communications -// All Rights Reserved - -#ifndef ROOT_MEM_H -#define ROOT_MEM_H - -#include // for size_t - -typedef void (*FINALIZERPROC)(void* pObj, void* pClientData); - -struct GC; // thread specific allocator - -struct Mem -{ - GC *gc; // pointer to our thread specific allocator - Mem() { gc = NULL; } - - void init(); - - // Derive from Mem to get these storage allocators instead of global new/delete - void * operator new(size_t m_size); - void * operator new(size_t m_size, Mem *mem); - void * operator new(size_t m_size, GC *gc); - void operator delete(void *p); - - void * operator new[](size_t m_size); - void operator delete[](void *p); - - char *strdup(const char *s); - void *malloc(size_t size); - void *malloc_uncollectable(size_t size); - void *calloc(size_t size, size_t n); - void *realloc(void *p, size_t size); - void free(void *p); - void free_uncollectable(void *p); - void *mallocdup(void *o, size_t size); - void error(); - void check(void *p); // validate pointer - void fullcollect(); // do full garbage collection - void fullcollectNoStack(); // do full garbage collection, no scan stack - void mark(void *pointer); - void addroots(char* pStart, char* pEnd); - void removeroots(char* pStart); - void setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData); - void setStackBottom(void *bottom); - GC *getThreadGC(); // get apartment allocator for this thread -}; - -extern Mem mem; - -#endif /* ROOT_MEM_H */ diff --git a/dmd/module.c b/dmd/module.c deleted file mode 100644 index 50723083..00000000 --- a/dmd/module.c +++ /dev/null @@ -1,1257 +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 - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#if defined(_MSC_VER) || defined(__MINGW32__) -#include -#endif - -#ifdef 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 - -// stricmp -#if __GNUC__ && !_WIN32 -#include "gnuc.h" -#endif - -static llvm::cl::opt preservePaths("op", - llvm::cl::desc("Do not strip paths from source file"), - llvm::cl::ZeroOrMore); - -static llvm::cl::opt fqnNames("oq", - llvm::cl::desc("Write object files with fully qualified names"), - llvm::cl::ZeroOrMore); -#endif - -ClassDeclaration *Module::moduleinfo; - -Module *Module::rootModule; -DsymbolTable *Module::modules; -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; - FileName *objfilename; - FileName *symfilename; - -// printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars()); - this->arg = filename; - md = NULL; - errors = 0; - numlines = 0; - members = NULL; - isHtml = 0; - isDocFile = 0; - needmoduleinfo = 0; -#ifdef IN_GCC - strictlyneedmoduleinfo = 0; -#endif - 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; - stest = NULL; - sfilename = NULL; -#endif - root = 0; - importedFrom = NULL; - srcfile = NULL; - objfile = NULL; - docfile = NULL; - hdrfile = NULL; - - debuglevel = 0; - debugids = NULL; - debugidsNot = NULL; - versionlevel = 0; - versionids = NULL; - versionidsNot = NULL; - - macrotable = NULL; - escapetable = NULL; - safe = FALSE; -#if IN_DMD - doppelganger = 0; - cov = NULL; - covb = NULL; -#endif - - srcfilename = FileName::defaultExt(filename, global.mars_ext); - if (!srcfilename->equalsExt(global.mars_ext) && - !srcfilename->equalsExt(global.hdr_ext) && - !srcfilename->equalsExt("dd")) - { - if (srcfilename->equalsExt("html") || - srcfilename->equalsExt("htm") || - srcfilename->equalsExt("xhtml")) - isHtml = 1; - else - { error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); - fatal(); - } - } - srcfile = new File(srcfilename); - -#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.init(); -#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)); -} - -static void check_and_add_output_file(Module* NewMod, const std::string& str) -{ - typedef std::map map_t; - static map_t files; - - map_t::iterator i = files.find(str); - if (i != files.end()) - { - Module* ThisMod = i->second; - error("Output file '%s' for module '%s' collides with previous module '%s'. See the -oq option", - str.c_str(), NewMod->toPrettyChars(), ThisMod->toPrettyChars()); - fatal(); - } - files.insert(std::make_pair(str, NewMod)); -} - -void Module::buildTargetFiles(bool singleObj) -{ - if(objfile && - (!doDocComment || docfile) && - (!doHdrGen || hdrfile)) - return; - - if(!objfile) - { - if (global.params.output_bc) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.bc_ext); - else if (global.params.output_ll) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.ll_ext); - else if (global.params.output_s) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.s_ext); - else - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, - global.params.targetTriple.isOSWindows() ? global.obj_ext_alt : global.obj_ext); - } - if(doDocComment && !docfile) - docfile = Module::buildFilePath(global.params.docname, global.params.docdir, global.doc_ext); - if(doHdrGen && !hdrfile) - hdrfile = Module::buildFilePath(global.params.hdrname, global.params.hdrdir, global.hdr_ext); - - // safety check: never allow obj, doc or hdr file to have the source file's name - if(stricmp(FileName::name(objfile->name->str), FileName::name((char*)this->arg)) == 0) - { - error("Output object files with the same name as the source file are forbidden"); - fatal(); - } - if(docfile && stricmp(FileName::name(docfile->name->str), FileName::name((char*)this->arg)) == 0) - { - error("Output doc files with the same name as the source file are forbidden"); - fatal(); - } - if(hdrfile && stricmp(FileName::name(hdrfile->name->str), FileName::name((char*)this->arg)) == 0) - { - error("Output header files with the same name as the source file are forbidden"); - fatal(); - } - - // LDC - // another safety check to make sure we don't overwrite previous output files - if (!singleObj) - check_and_add_output_file(this, objfile->name->str); - if (docfile) - check_and_add_output_file(this, docfile->name->str); - if (hdrfile) - check_and_add_output_file(this, hdrfile->name->str); -} -#endif - -void Module::deleteObjFile() -{ - if (global.params.obj) - objfile->remove(); - //if (global.params.llvmBC) - //bcfile->remove(); - if (doDocComment && docfile) - docfile->remove(); -} - -Module::~Module() -{ -#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)[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)[i]; - printf("%s.", pid->toChars()); - } - } - printf("%s\t(%s)\n", ident->toChars(), m->srcfile->toChars()); - } - - if (!m->read(loc)) - return NULL; - - m->parse(); - -#ifdef IN_GCC - d_gcc_magic_module(m); -#endif - - return m; -} - -bool 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)[i]; - fprintf(stdmsg, "import path[%llu] = %s\n", (ulonglong)i, p); - } - } - else - fprintf(stdmsg, "Specify path to file '%s' with -I switch\n", srcfile->toChars()); - fatal(); - } - return false; - } - return true; -} - -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) -#else -void Module::parse() -#endif -{ - //printf("Module::parse()\n"); - - char *srcname = srcfile->name->toChars(); - //printf("Module::parse(srcname = '%s')\n", srcname); - - unsigned char *buf = srcfile->buffer; - unsigned 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 - */ - - unsigned le; - unsigned 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 (global.params.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; - 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 (global.params.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; - Package *ppack = NULL; - dst = Package::resolve(md->packages, &this->parent, &ppack); - if (ppack && ppack->isModule()) - { - error(loc, "package name '%s' in file %s conflicts with usage as a module name in file %s", - ppack->toChars(), srcname, ppack->isModule()->srcfile->toChars()); - dst = modules; - } - } - 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(pkg->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)[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)[i]; - s->setScope(sc); - } - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->importAll(sc); - } - - sc = sc->pop(); - sc->pop(); // 2 pops because Scope::createGlobal() created 2 -} - -void Module::semantic() -{ - 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)[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)[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() -{ - if (deferred.dim) - { - for (size_t i = 0; i < deferred.dim; i++) - { - Dsymbol *sd = deferred[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)[i]; - s->semantic2(sc); - } - - sc = sc->pop(); - sc->pop(); - semanticRun = semanticstarted; - //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); -} - -void Module::semantic3() -{ - //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)[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)[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)[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[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[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[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[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[i]; - //printf("\t[%d] %s\n", i, mi->toChars()); - mi->insearch = 0; - } - } - return selfimports - 1; -} - - -/* =========================== ModuleDeclaration ===================== */ - -ModuleDeclaration::ModuleDeclaration(Identifiers *packages, Identifier *id) -{ - this->packages = packages; - this->id = id; -} - -char *ModuleDeclaration::toChars() -{ - OutBuffer buf; - - if (packages && packages->dim) - { - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = (*packages)[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)[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()); - // It might already be a module, not a package, but that needs - // to be checked at a higher level, where a nice error message - // can be generated. - // dot net needs modules and packages with same name - } - parent = p; - dst = ((Package *)p)->symtab; - if (ppkg && !*ppkg) - *ppkg = (Package *)p; -#if TARGET_NET -#else - if (p->isModule()) - { // Return the module so that a nice error message can be generated - if (ppkg) - *ppkg = (Package *)p; - break; - } -#endif - } - if (pparent) - { - *pparent = parent; - } - } - return dst; -} diff --git a/dmd/module.h b/dmd/module.h deleted file mode 100644 index dabc9a31..00000000 --- a/dmd/module.h +++ /dev/null @@ -1,225 +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. - -#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 ClassDeclaration *moduleinfo; - - - const char *arg; // original argument name - ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration - File *srcfile; // input source file - - File *objfile; // output object file - File *docfile; // output doc file - File *hdrfile; // output hdr file - - unsigned errors; // if any errors in file - unsigned numlines; // number of lines in source file - int isHtml; // if it is an HTML file - int isDocFile; // if it is a documentation input file, not D source - int needmoduleinfo; -#ifdef IN_GCC - int strictlyneedmoduleinfo; -#endif - - int selfimports; // 0: don't know, 1: does not, 2: does - int selfImports(); // returns !=0 if module imports itself - - int insearch; - Identifier *searchCacheIdent; - Dsymbol *searchCacheSymbol; // cached value of search - int searchCacheFlags; // cached flags - - int semanticstarted; // has semantic() been started? - int semanticRun; // has semantic() been done? - int root; // != 0 if this is a 'root' module, - // i.e. a module that will be taken all the - // way to an object file - Module *importedFrom; // module from command line we're imported from, - // i.e. a module that will be taken all the - // way to an object file - - 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 - struct Escape *escapetable; // document comment escapes - - int doDocComment; // enable generating doc comments for this module - int doHdrGen; // enable generating header file for this module - - bool safe; // TRUE if module is marked as 'safe' - - 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(); - bool read(Loc loc); // read file, returns 'true' if succeed, 'false' otherwise. -#if IN_LLVM - void parse(bool gen_docs = false); // syntactic parse -#else - void setDocfile(); // set docfile member - void parse(); // syntactic parse -#endif - void importAll(Scope *sc); - void semantic(); // semantic analysis - void semantic2(); // pass 2 semantic analysis - void semantic3(); // pass 3 semantic analysis - void inlineScan(); // scan for functions to inline - void setHdrfile(); // set hdrfile member - void genhdrfile(); // generate D import file - void genobjfile(int multiobj); -// 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 *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(); - elem *toEmodulename(); - - Symbol *toSymbol(); -#endif - void genmoduleinfo(); - -#if IN_LLVM - // LDC - llvm::Module* genLLVMModule(llvm::LLVMContext& context, Ir* sir); - void buildTargetFiles(bool singleObj); - File* buildFilePath(const char* forcename, const char* path, const char* ext); - Module *isModule() { return this; } - llvm::GlobalVariable* moduleInfoSymbol(); - - bool llvmForceLogging; - llvm::GlobalVariable* moduleInfoVar; - llvm::StructType* moduleInfoType; - - // array ops emitted in this module already - StringTable arrayfuncs; - - bool isRoot; -#endif -}; - - -struct ModuleDeclaration -{ - Identifier *id; - Identifiers *packages; // array of Identifier's representing packages - bool safe; - - ModuleDeclaration(Identifiers *packages, Identifier *id); - - char *toChars(); -}; - -#endif /* DMD_MODULE_H */ diff --git a/dmd/mtype.c b/dmd/mtype.c deleted file mode 100644 index 5c0c246d..00000000 --- a/dmd/mtype.c +++ /dev/null @@ -1,6089 +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/branches/dmd-1.x/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); - - -#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; - -/***************************** 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::typeinfoenum; -ClassDeclaration *Type::typeinfofunction; -ClassDeclaration *Type::typeinfodelegate; -ClassDeclaration *Type::typeinfotypelist; - -Type *Type::tvoidptr; -Type *Type::tstring; -Type *Type::basic[TMAX]; -unsigned char Type::mangleChar[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); - deco_stringtable.init(); - Lexer::initKeywords(); - - 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[Tbit] = '@'; - mangleChar[Tinstance] = '@'; - mangleChar[Terror] = '@'; - mangleChar[Ttypeof] = '@'; - mangleChar[Ttuple] = 'B'; - mangleChar[Tslice] = '@'; - mangleChar[Treturn] = '@'; - - 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++) - basic[basetab[i]] = new TypeBasic(basetab[i]); - basic[Terror] = new TypeError(); - - tvoidptr = tvoid->pointerTo(); - tstring = tchar->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 - { - Tsize_t = Tuns32; - Tptrdiff_t = Tint32; - PTRSIZE = 4; - } - - // set real size and padding - if (global.params.targetTriple.getArch() == llvm::Triple::x86) - { - REALSIZE = 12; - REALPAD = 2; - } - else if (global.params.targetTriple.getArch() == llvm::Triple::x86_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) -{ - if (next) - next = next->semantic(loc,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; -} -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; -} - -Dsymbol *Type::toDsymbol(Scope *sc) -{ - return NULL; -} - -/******************************* - * If this is a shell around another type, - * get that other type. - */ - -Type *Type::toBasetype() -{ - return this; -} - -/******************************** - * Name mangling. - */ - -void Type::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - buf->writeByte(mangleChar[ty]); - if (next) - { - assert(next != this); - //printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this->ty, next, next->ty); - next->toDecoBuffer(buf, mangle); - } -} - -/******************************** - * 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) - { const char *p; - - switch (this->mod) - { - case 0: - toCBuffer2(buf, hgs, this->mod); - break; - case MODconst: - p = "const("; - goto L1; - case MODimmutable: - p = "invariant("; - L1: buf->writestring(p); - toCBuffer2(buf, hgs, this->mod); - buf->writeByte(')'); - break; - default: - assert(0); - } - } -} - - -/************************************ - */ - -Type *Type::merge() -{ - if (ty == Terror) return this; - //printf("merge(%s)\n", toChars()); - Type *t = this; - assert(t); - if (!deco) - { - if (next) - next = next->merge(); - - OutBuffer buf; - toDecoBuffer(&buf, false); - StringValue *sv = stringtable.update((char *)buf.data, buf.offset); - if (sv->ptrvalue) - { t = (Type *) sv->ptrvalue; - 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, 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->toDchars(); - } - //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::isbit() -{ - return FALSE; -} - -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; -} - -int Type::checkBoolean() -{ - return isscalar(); -} - -/********************************* - * Check type to see if it is based on a deprecated symbol. - */ - -void Type::checkDeprecated(Loc loc, Scope *sc) -{ - for (Type *t = this; t; t = t->next) - { - Dsymbol *s = t->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: - * 0 can't convert - * 1 can convert using implicit conversions - * 2 this and to are the same type - */ - -MATCH Type::implicitConvTo(Type *to) -{ - //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to); - //printf("\tthis->next=%p, to->next=%p\n", this->next, to->next); - if (this == to) - return MATCHexact; -// if (to->ty == Tvoid) -// return 1; - return MATCHnomatch; -} - -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 = defaultInit(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 = ((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(loc); - } - } - e = e->ctfeInterpret(); -// if (!e->isConst()) -// error(loc, ".init cannot be evaluated at compile time"); - } - return e; - } -#endif - Expression *ex = defaultInit(e->loc); - return ex; - } - } - if (ident == Id::typeinfo) - { - if (!global.params.useDeprecated) - error(e->loc, ".typeinfo deprecated, use typeid(type)"); - e = getTypeInfo(sc); - return e; - } - if (ident == Id::stringof) - { char *s = e->toChars(); - e = new StringExp(e->loc, s, strlen(s), 'c'); - Scope sc; - e = e->semantic(&sc); - return e; - } - return getProperty(e->loc, ident); -} - -structalign_t Type::memalign(structalign_t 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; - - //toTypeInfoBuffer(&buf); - if (internal) - { buf.writeByte(mangleChar[ty]); - if (ty == Tarray) - buf.writeByte(mangleChar[((TypeArray *)this)->next->ty]); - } - else - toDecoBuffer(&buf, true); - len = buf.offset; - name = (char *)alloca(19 + sizeof(len) * 3 + len + 1); - buf.writeByte(0); - sprintf(name, "_D%dTypeInfo_%s6__initZ", 9 + len, buf.data); -// 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() -{ - if (!next) - return NULL; - else - return next->reliesOnTident(); -} - -/******************************** - * 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() -{ - return FALSE; -} - -/* ============================= TypeError =========================== */ - -TypeError::TypeError() - : Type(Terror, NULL) -{ -} - -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(); } - -/* ============================= TypeBasic =========================== */ - -TypeBasic::TypeBasic(TY ty) - : Type(ty, NULL) -{ const char *c; - const char *d; - unsigned flags; - -#define TFLAGSintegral 1 -#define TFLAGSfloating 2 -#define TFLAGSunsigned 4 -#define TFLAGSreal 8 -#define TFLAGSimaginary 0x10 -#define TFLAGScomplex 0x20 - - flags = 0; - switch (ty) - { - case Tvoid: d = Token::toChars(TOKvoid); - c = "void"; - break; - - case Tint8: d = Token::toChars(TOKint8); - c = "byte"; - flags |= TFLAGSintegral; - break; - - case Tuns8: d = Token::toChars(TOKuns8); - c = "ubyte"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tint16: d = Token::toChars(TOKint16); - c = "short"; - flags |= TFLAGSintegral; - break; - - case Tuns16: d = Token::toChars(TOKuns16); - c = "ushort"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tint32: d = Token::toChars(TOKint32); - c = "int"; - flags |= TFLAGSintegral; - break; - - case Tuns32: d = Token::toChars(TOKuns32); - c = "uint"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tfloat32: d = Token::toChars(TOKfloat32); - c = "float"; - flags |= TFLAGSfloating | TFLAGSreal; - break; - - case Tint64: d = Token::toChars(TOKint64); - c = "long"; - flags |= TFLAGSintegral; - break; - - case Tuns64: d = Token::toChars(TOKuns64); - c = "ulong"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tfloat64: d = Token::toChars(TOKfloat64); - c = "double"; - flags |= TFLAGSfloating | TFLAGSreal; - break; - - case Tfloat80: d = Token::toChars(TOKfloat80); - c = "real"; - flags |= TFLAGSfloating | TFLAGSreal; - break; - - case Timaginary32: d = Token::toChars(TOKimaginary32); - c = "ifloat"; - flags |= TFLAGSfloating | TFLAGSimaginary; - break; - - case Timaginary64: d = Token::toChars(TOKimaginary64); - c = "idouble"; - flags |= TFLAGSfloating | TFLAGSimaginary; - break; - - case Timaginary80: d = Token::toChars(TOKimaginary80); - c = "ireal"; - flags |= TFLAGSfloating | TFLAGSimaginary; - break; - - case Tcomplex32: d = Token::toChars(TOKcomplex32); - c = "cfloat"; - flags |= TFLAGSfloating | TFLAGScomplex; - break; - - case Tcomplex64: d = Token::toChars(TOKcomplex64); - c = "cdouble"; - flags |= TFLAGSfloating | TFLAGScomplex; - break; - - case Tcomplex80: d = Token::toChars(TOKcomplex80); - c = "creal"; - flags |= TFLAGSfloating | TFLAGScomplex; - break; - - - case Tbool: d = "bool"; - c = d; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tascii: d = Token::toChars(TOKchar); - c = "char"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Twchar: d = Token::toChars(TOKwchar); - c = "wchar"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tdchar: d = Token::toChars(TOKdchar); - c = "dchar"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - default: assert(0); - } - this->dstring = d; - this->cstring = c; - this->flags = flags; - merge(); -} - -Type *TypeBasic::syntaxCopy() -{ - // No semantic analysis done on basic types, no need to copy - return this; -} - - -char *TypeBasic::toChars() -{ - return (char *)dstring; -} - -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 IN_LLVM - if (ty == Tvoid) - return 1; - return GetTypeAlignment(sir, this); -#else - unsigned sz; - - switch (ty) - { - case Tfloat80: - case Timaginary80: - case Tcomplex80: - sz = REALALIGNSIZE; - break; - -#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 - - default: - sz = size(0); - break; - } - return sz; -#endif -} - -#if IN_LLVM -unsigned TypeBasic::memalign(unsigned salign) -{ - if (global.params.targetTriple.getArch() == llvm::Triple::x86_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: 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; - } - } - -Ldefault: - 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 (size_t 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(e->loc, ldouble(0.0), t); - break; - - default: - return Type::getProperty(e->loc, ident); - } - } - 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->type = t; - break; - - case Tfloat32: - case Tfloat64: - case Tfloat80: - e = new RealExp(e->loc, ldouble(0.0), this); - break; - - default: - return Type::getProperty(e->loc, ident); - } - } - else - { - return Type::dotExp(sc, e, ident); - } - return e; -} - -Expression *TypeBasic::defaultInit(Loc loc) -{ dinteger_t value = 0; - -#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: - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - return getProperty(loc, Id::nan); - - 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::isbit() -{ - return 0; -} - -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) - { - return (mod == to->mod) ? MATCHexact : MATCHconst; - } -#endif - - if (ty == Tvoid || to->ty == Tvoid) - return MATCHnomatch; - if (to->ty == Tbool) - return MATCHnomatch; - if (!to->isTypeBasic()) - return MATCHnomatch; - - TypeBasic *tob = (TypeBasic *)to; - if (flags & TFLAGSintegral) - { - // Disallow implicit conversion of integers to imaginary or complex - if (tob->flags & (TFLAGSimaginary | TFLAGScomplex)) - return MATCHnomatch; - -#if DMDV2 - // If converting from integral to integral - if (1 && tob->flags & TFLAGSintegral) - { d_uns64 sz = size(0); - d_uns64 tosz = tob->size(0); - - /* Can't convert to smaller size - */ - if (sz > tosz) - return MATCHnomatch; - - /* Can't 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; -} - -/***************************** TypeArray *****************************/ - -TypeArray::TypeArray(TY ty, Type *next) - : Type(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 (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) - { - Expression *ec; - Expressions *arguments; - int size = next->size(e->loc); - int dup; - - assert(size); - dup = (ident == Id::dup); - //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) { - e = new CastExp(e->loc, e, e->type); - e->type = Type::tvoid->arrayOf(); - } - arguments->push(e); - - if (!dup) - arguments->push(new IntegerExp(0, size, Type::tsize_t)); - e = new CallExp(e->loc, ec, arguments); - e->type = next->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) { - e = new CastExp(e->loc, e, e->type); - e->type = Type::tvoid->arrayOf(); - } - 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); - } - 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); - 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((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(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; - e = new IndexExp(loc, *pe, dim); - *pe = e; - } - else if (*ps) - { Dsymbol *s = *ps; - TupleDeclaration *td = s->isTupleDeclaration(); - if (td) - { - ScopeDsymbol *sym = new ArrayScopeSymbol(td); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - dim = dim->semantic(sc); - dim = dim->ctfeInterpret(); - 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 = (Object *)td->objects->data[(size_t)d]; - if (o->dyncast() == DYNCAST_DSYMBOL) - { - *ps = (Dsymbol *)o; - return; - } - if (o->dyncast() == DYNCAST_EXPRESSION) - { - *ps = NULL; - *pe = (Expression *)o; - return; - } - if (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->data[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->ctfeInterpret(); - 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)[(size_t)d]; - if (o->dyncast() != DYNCAST_TYPE) - { error(loc, "%s is not a type", toChars()); - return Type::terror; - } - t = (Type *)o; - return t; - } - - next = next->semantic(loc,sc); - Type *tbn = next->toBasetype(); - - if (dim) - { dinteger_t n, n2; - - int errors = global.errors; - dim = semanticLength(sc, tbn, dim); - if (errors != global.errors) - goto Lerror; - - dim = dim->ctfeInterpret(); - if (sc && sc->parameterSpecialization && dim->op == TOKvar && - ((VarExp *)dim)->var->storage_class & STCtemplateparameter) - { - /* It could be a template parameter N which has no value yet: - * template Foo(T : T[N], size_t N); - */ - return this; - } - dinteger_t d1 = dim->toInteger(); - dim = dim->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 Tfunction: - case Tnone: - error(loc, "can't have array of %s", tbn->toChars()); - goto Lerror; - } - if (tbn->isscope()) - { error(loc, "cannot have array of auto %s", tbn->toChars()); - goto Lerror; - } - return merge(); - -Lerror: - return Type::terror; -} - -void TypeSArray::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - buf->writeByte(mangleChar[ty]); - if (dim) - buf->printf("%ju", dim->toInteger()); - if (next) - next->toDecoBuffer(buf, 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); - } - return e; -} - -int TypeSArray::isString() -{ - TY nty = next->toBasetype()->ty; - return nty == Tchar || nty == Twchar || nty == Tdchar; -} - -structalign_t TypeSArray::memalign(structalign_t salign) -{ - return next->memalign(salign); -} - -MATCH TypeSArray::implicitConvTo(Type *to) -{ - //printf("TypeSArray::implicitConvTo()\n"); - - // Allow implicit conversion of static array to pointer or dynamic array - if ((IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer) && - (to->next->ty == Tvoid || next->equals(to->next) - /*|| to->next->isBaseOf(next)*/)) - { - return MATCHconvert; - } - if (to->ty == Tarray) - { int offset = 0; - - if (next->equals(to->next) || - (to->next->isBaseOf(next, &offset) && offset == 0) || - to->next->ty == Tvoid) - return MATCHconvert; - } -#if 0 - if (to->ty == Tsarray) - { - TypeSArray *tsa = (TypeSArray *)to; - - if (next->equals(tsa->next) && dim->equals(tsa->dim)) - { - return MATCHconvert; - } - } -#endif - return Type::implicitConvTo(to); -} - -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); -} - -Expression *TypeSArray::defaultInitLiteral(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars()); -#endif - size_t d = dim->toInteger(); - Expression *elementinit = next->defaultInitLiteral(loc); - Expressions *elements = new Expressions(); - elements->setDim(d); - for (size_t i = 0; i < d; i++) - elements->data[i] = elementinit; - ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); - ae->type = this; - return ae; -} - -Expression *TypeSArray::toExpression() -{ - Expression *e = next->toExpression(); - if (e) - { Expressions *arguments = new Expressions(); - arguments->push(dim); - e = new ArrayExp(dim->loc, e, arguments); - } - 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); - 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()); - tn = next = tint32; - break; - } - if (tn->isscope()) - error(loc, "cannot have array of scope %s", tn->toChars()); - if (next != tn) - //deco = NULL; // redo - return tn->arrayOf(); - return merge(); -} - -void TypeDArray::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - buf->writeByte(mangleChar[ty]); - if (next) - next->toDecoBuffer(buf, mangle); -} - -void TypeDArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - 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()\n"); - - // Allow implicit conversion of array to pointer - if (IMPLICIT_ARRAY_TO_PTR && - to->ty == Tpointer && - (to->next->ty == Tvoid || next->equals(to->next) /*|| to->next->isBaseOf(next)*/)) - { - return MATCHconvert; - } - - if (to->ty == Tarray) - { int offset = 0; - - if ((to->next->isBaseOf(next, &offset) && offset == 0) || - to->next->ty == Tvoid) - return MATCHconvert; - } - 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->key = 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); - 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); - - // 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"); - } - else - index = index->semantic(loc,sc); - - // Compute key type; the purpose of the key type is to - // minimize the permutations of runtime library - // routines as much as possible. - key = index->toBasetype(); - switch (key->ty) - { -#if 0 - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: - key = tint32; - break; -#endif - - case Tsarray: -#if 0 - // Convert to Tarray - key = key->next->arrayOf(); -#endif - break; - case Tbool: - case Tfunction: - case Tvoid: - case Tnone: - case Ttuple: - error(loc, "can't have associative array key of %s", key->toChars()); - break; - } - next = next->semantic(loc,sc); - switch (next->toBasetype()->ty) - { - case Tfunction: - case Tvoid: - case Tnone: - error(loc, "can't have associative array of %s", next->toChars()); - break; - } - if (next->isscope()) - error(loc, "cannot have array of auto %s", next->toChars()); - - return merge(); -} - -void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ - //printf("TypeAArray::resolve() %s\n", toChars()); - - // Deal with the case where we thought the index was a type, but - // in reality it was an expression. - if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray) - { - Expression *e; - Type *t; - Dsymbol *s; - - index->resolve(loc, sc, &e, &t, &s); - if (e) - { // It was an expression - - // Rewrite as a static array - - TypeSArray *tsa = new TypeSArray(next, e); - return tsa->resolve(loc, sc, pe, pt, ps); - } - else if (t) - index = t; - else - index->error(loc, "index is not a type or an expression"); - } - Type::resolve(loc, sc, pe, pt, ps); -} - - -Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (ident == Id::length) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *aaLen_fd = NULL; - if(!aaLen_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->pointerTo(), NULL, NULL)); // FIXME: Real parameter type is AA. - 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->next; - } - else if (ident == Id::keys) - { - Expression *ec; - Expressions *arguments; - int size = key->size(e->loc); - - assert(size); - //LDC: Build arguments. - static FuncDeclaration *aaKeys_fd = NULL; - if(!aaKeys_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)); - 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) { - 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)); - args->push(new Parameter(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 = key->size(e->loc); - if (global.params.is64bit) - keysize = (keysize + 15) & ~15; - else - 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) { - 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::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(key->getTypeInfo(sc)); // LDC doesn't support getInternalTypeInfo, see above - e = new CallExp(e->loc, ec, arguments); - e->type = this; - } - else - { - e = Type::dotExp(sc, e, ident); - } - return e; -} - -void TypeAArray::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - buf->writeByte(mangleChar[ty]); - index->toDecoBuffer(buf, mangle); - next->toDecoBuffer(buf, 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; -} - -Expression *TypeAArray::toExpression() -{ - Expression *e = next->toExpression(); - if (e) - { - Expression *ei = index->toExpression(); - if (ei) - { - Expressions *arguments = new Expressions(); - arguments->push(ei); - return new ArrayExp(0, e, arguments); - } - } - return NULL; -} - -int TypeAArray::hasPointers() -{ - return TRUE; -} - -/***************************** TypePointer *****************************/ - -TypePointer::TypePointer(Type *t) - : Type(Tpointer, t) -{ -} - -Type *TypePointer::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - t = new TypePointer(t); - return t; -} - -Type *TypePointer::semantic(Loc loc, Scope *sc) -{ - if (deco) - return this; - - //printf("TypePointer::semantic()\n"); - Type *n = next->semantic(loc, sc); - switch (n->toBasetype()->ty) - { - case Ttuple: - error(loc, "can't have pointer to %s", n->toChars()); - n = tint32; - break; - } - if (n != next) - deco = NULL; - next = n; - 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()\n"); - - if (this == to) - return MATCHexact; - if (to->ty == Tpointer && to->next) - { - if (to->next->ty == Tvoid) - return MATCHconvert; - -#if 0 - if (to->next->isBaseOf(next)) - return MATCHconvert; -#endif - - if (next->ty == Tfunction && to->next->ty == Tfunction) - { TypeFunction *tf; - TypeFunction *tfto; - - tf = (TypeFunction *)(next); - tfto = (TypeFunction *)(to->next); - return tfto->equals(tf) ? MATCHexact : MATCHnomatch; - } - } -// if (to->ty == Tvoid) -// return MATCHconvert; - return MATCHnomatch; -} - -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) - : Type(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); - return t; -} - -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) - : Type(Tfunction, treturn) -{ -//if (!treturn) *(char*)0=0; -// assert(treturn); - this->parameters = parameters; - this->varargs = varargs; - this->linkage = linkage; - this->inuse = 0; - -#if IN_LLVM - this->funcdecl = NULL; -#endif -} - -Type *TypeFunction::syntaxCopy() -{ - Type *treturn = next ? next->syntaxCopy() : NULL; - Parameters *params = Parameter::arraySyntaxCopy(parameters); - Type *t = new TypeFunction(params, treturn, varargs, linkage); - return t; -} - -/******************************* - * 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); -#endif - - int inoutmismatch = 0; - - if (equals(t)) - goto Lcovariant; - if (ty != Tfunction || t->ty != Tfunction) - goto Ldistinct; - - { - TypeFunction *t1 = (TypeFunction *)this; - TypeFunction *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)) - goto Ldistinct; - if (arg1->storageClass != arg2->storageClass) - 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) - { - ClassDeclaration *cd = ((TypeClass *)t1n)->sym; - ClassDeclaration *cd2 = ((TypeClass *)t2n)->sym; - if (cd == cd2) - goto Lcovariant; - - // If t1n is forward referenced: -#if 0 - if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) -#else - if (!cd->isBaseInfoComplete()) -#endif - { - return 3; // forward references - } - } - if (t1n->implicitConvTo(t2n)) - goto Lcovariant; - - goto Lnotcovariant; - } - -Lcovariant: - //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, 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++; - 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); - - // 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, false); - } - /* 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, 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 - next->toDecoBuffer(buf, 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) -{ - const char *p = NULL; - - if (inuse) - { inuse = 2; // flag error to caller - return; - } - inuse++; - if (hgs->ddoc != 1) - { - switch (linkage) - { - case LINKd: p = NULL; break; - case LINKc: p = "C "; break; - case LINKwindows: p = "Windows "; break; - case LINKpascal: p = "Pascal "; break; - case LINKcpp: p = "C++ "; break; - - // LDC - case LINKintrinsic: p = "Intrinsic"; break; - - default: - assert(0); - } - if (!hgs->hdrgen && p) - { - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - } - } - if (next && (!ident || ident->toHChars2() == ident->toChars())) - { next->toCBuffer2(buf, hgs, 0); - } - - if (ident) - { 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--; -} - -// kind is inserted before the argument list and will usually be "function" or "delegate". -void functionToCBuffer2(TypeFunction *t, OutBuffer *buf, HdrGenState *hgs, int mod, const char *kind) -{ - if (hgs->ddoc != 1) - { - const char *p = NULL; - switch (t->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; -#if IN_LLVM - case LINKintrinsic: p = "Intrinsic"; break; -#endif - default: - assert(0); - } - if (!hgs->hdrgen && p) - { - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - } - } - if (t->next) - { - t->next->toCBuffer2(buf, hgs, 0); - buf->writeByte(' '); - } - buf->writestring(kind); - Parameter::argsToCBuffer(buf, hgs, t->parameters, t->varargs); -} - -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++; - - functionToCBuffer2(this, buf, hgs, mod, "function"); - - inuse--; -} - -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 = %x\n", toChars(), sc->stc); - - /* 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(tf->linkage == LINKd) - tf->linkage = sc->linkage; - - if (tf->next) - { - tf->next = tf->next->semantic(loc,sc); -#if !SARRAYVALUE - if (tf->next->toBasetype()->ty == Tsarray) - { error(loc, "functions cannot return static array %s", tf->next->toChars()); - tf->next = Type::terror; - } -#endif - if (tf->next->toBasetype()->ty == Tfunction) - { error(loc, "functions cannot return a function"); - tf->next = Type::terror; - } - if (tf->next->toBasetype()->ty == Ttuple) - { error(loc, "functions cannot return a tuple"); - tf->next = Type::terror; - } - if (tf->next->isscope() && !(sc->flags & SCOPEctor)) - error(loc, "functions cannot return scope %s", tf->next->toChars()); - } - - if (tf->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--; - - // each function needs its own copy of a tuple arg, since - // they mustn't share arg flags like inreg, ... - if (fparam->type->ty == Ttuple) { - fparam->type = fparam->type->syntaxCopy(); - tf->inuse++; - fparam->type = fparam->type->semantic(loc,sc); - if (tf->inuse == 1) tf->inuse--; - } - - 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 & STClazy) && t->ty == Tvoid) - error(loc, "cannot have parameter of type %s", fparam->type->toChars()); - - if (fparam->defaultArg) - { Expression *e = fparam->defaultArg; - e = e->semantic(argsc); - e = resolveProperties(argsc, e); - if (e->op == TOKfunction) // see Bugzilla 4820 - { FuncExp *fe = (FuncExp *)e; - if (fe->fd) - { // Replace function literal with a function symbol, - // since default arg expression must be copied when used - // and copying the literal itself is wrong. - e = new VarExp(e->loc, fe->fd); - e = new AddrExp(e->loc, e); - e = e->semantic(argsc); - } - } - e = e->implicitCastTo(argsc, fparam->type); - fparam->defaultArg = e; - } - - /* If fparam after semantic() turns out to be a tuple, the number of parameters may - * change. - */ - if (t->ty == Ttuple) - { - // Propagate storage class from tuple parameters to their element-parameters. - TypeTuple *tt = (TypeTuple *)t; - if (tt->arguments) - { - size_t tdim = tt->arguments->dim; - for (size_t j = 0; j < tdim; j++) - { Parameter *narg = (Parameter *)tt->arguments->data[j]; - narg->storageClass = fparam->storageClass; - } - } - - /* Reset number of parameters, and back up one to do this arg again, - * now that it is the first element of a tuple - */ - dim = Parameter::dim(tf->parameters); - i--; - continue; - } - } - argsc->pop(); - } - if (tf->next) - tf->deco = tf->merge()->deco; - - if (tf->inuse) - { error(loc, "recursive type"); - tf->inuse = 0; - return terror; - } - - 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; -} - -/******************************** - * 'args' are being matched to function 'this' - * Determine match level. - * Returns: - * MATCHxxxx - */ - -int TypeFunction::callMatch(Expressions *args) -{ - //printf("TypeFunction::callMatch()\n"); - int match = MATCHexact; // assume exact match - - 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 < nparams; u++) - { int m; - Expression *arg; - - // BUG: what about out and ref? - - Parameter *p = Parameter::getNth(parameters, u); - assert(p); - if (u >= nargs) - { - if (p->defaultArg) - continue; - if (varargs == 2 && u + 1 == nparams) - goto L1; - goto Nomatch; // not enough arguments - } - arg = (*args)[u]; - assert(arg); - if (p->storageClass & STClazy && p->type->ty == Tvoid && arg->type->ty != Tvoid) - m = MATCHconvert; - else - m = arg->implicitConvTo(p->type); - /* 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: - for (; u < nargs; u++) - { - arg = (*args)[u]; - assert(arg); -#if 1 - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type *tret = p->isLazyArray(); - if (tret) - { - if (tb->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(tb->next); -#else - m = arg->implicitConvTo(tb->next); -#endif - if (m == 0) - 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() -{ - if (parameters) - { - for (size_t i = 0; i < parameters->dim; i++) - { Parameter *arg = (Parameter *)parameters->data[i]; - Type *t = arg->type->reliesOnTident(); - if (t) - return t; - } - } - return next->reliesOnTident(); -} - -Expression *TypeFunction::defaultInit(Loc loc) -{ - error(loc, "function does not have a default initializer"); - return new ErrorExp(); -} - -/***************************** TypeDelegate *****************************/ - -TypeDelegate::TypeDelegate(Type *t) - : Type(Tfunction, t) -{ - ty = Tdelegate; -} - -Type *TypeDelegate::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - t = new TypeDelegate(t); - 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); - 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 -#if DMDV1 - // See Bugzilla 942 for discussion - if (!global.params.is64bit) - return PTRSIZE * 2; -#endif - return PTRSIZE; -} - -void TypeDelegate::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - - functionToCBuffer2((TypeFunction *)next, buf, hgs, mod, "delegate"); -} - -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) - { -#if IN_LLVM - e = new GEPExp(e->loc, e, ident, 0); -#endif - e->type = tvoidptr; - return e; - } - else if (ident == Id::funcptr) - { - if (!e->isLvalue()) - { - Identifier *idtmp = Lexer::uniqueId("__dgtmp"); - VarDeclaration *tmp = new VarDeclaration(e->loc, this, idtmp, new ExpInitializer(0, e)); - tmp->storage_class |= STCctfe; - e = new DeclarationExp(e->loc, tmp); - e = new CommaExp(e->loc, e, new VarExp(e->loc, tmp)); - e = e->semantic(sc); - } -#if IN_LLVM - e = new GEPExp(e->loc, e, ident, 1); -#else - e = e->addressOf(sc); - e->type = tvoidptr; - e = new AddExp(e->loc, e, new IntegerExp(PTRSIZE)); - e->type = tvoidptr; - e = new PtrExp(e->loc, e); -#endif - 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, NULL) -{ - 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[i]; - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; - - ti = (TemplateInstance *)ti->syntaxCopy(NULL); - id = (Identifier *)ti; - } - idents[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[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; - TupleDeclaration *td; - Type *t; - 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[i]; - Dsymbol *sm = s->searchX(loc, sc, id); - //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - //printf("getType = '%s'\n", s->getType()->toChars()); - if (!sm) - { - v = s->isVarDeclaration(); - if (v && id == Id::length) - { - if (v->isSameAsInitializer() && v->getExpInitializer()) - { e = v->getExpInitializer()->exp; - } - else - 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); - 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 = %p\n", e->toChars(), id->toChars(), e->type); - e = e->type->dotExp(sc, e, id); - } - if (e->op == TOKtype) - *pt = e->type; - else - *pe = e; - } - else - { - Lerror: - if (id->dyncast() == DYNCAST_DSYMBOL) - { // searchX already handles errors for template instances - assert(global.errors); - } - else - { - sm = s->search_correct(id); - if (sm) - error(loc, "identifier '%s' of '%s' is not defined, did you mean '%s %s'?", - id->toChars(), toChars(), sm->kind(), sm->toChars()); - else - 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) - { - // It's not a type, it's an expression - if (v->isSameAsInitializer() && v->getExpInitializer()) - { - ExpInitializer *ei = v->getExpInitializer(); - assert(ei); - *pe = ei->exp->copy(); // make copy so we can change loc - (*pe)->loc = loc; - } - else - { -#if 0 - WithScopeSymbol *withsym; - if (scopesym && (withsym = scopesym->isWithScopeSymbol()) != NULL) - { - // Same as wthis.ident - e = new VarExp(loc, withsym->withstate->wthis); - e = new DotIdExp(loc, e, ident); - //assert(0); // BUG: should handle this - } - else -#endif - *pe = new VarExp(loc, v); - } - return; - } - em = s->isEnumMember(); - if (em) - { - // It's not a type, it's an expression - *pe = em->value->copy(); - return; - } - -L1: - 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 if (t->ty == Ttypeof) - *pt = t->semantic(loc, sc); - 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); - return t; -} - -void TypeIdentifier::toDecoBuffer(OutBuffer *buf, bool mangle) -{ unsigned len; - char *name; - - name = ident->toChars(); - len = strlen(name); - buf->printf("%c%d%s", mangleChar[ty], len, name); - //buf->printf("%c%s", mangleChar[ty], 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 *s; - Dsymbol *scopesym; - - //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, toChars()); - s = sc->search(loc, ident, &scopesym); - resolveHelper(loc, sc, s, scopesym, pe, pt, ps); -} - -/***************************************** - * 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 = (Identifier *)idents.data[i]; - s = s->searchX(loc, sc, id); - if (!s) // failed to find a symbol - { //printf("\tdidn't find a symbol\n"); - break; - } - } - } - return s; -} - -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()); - } - } - else - { -#ifdef DEBUG - if (!global.gag) - printf("1: "); -#endif - if (s) - { - s->error(loc, "is used as a type"); - } - else - error(loc, "%s is used as a type", toChars()); - t = tvoid; - } - //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 = (Identifier *)idents.data[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); - 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) - s->semantic(sc); - resolveHelper(loc, sc, s, NULL, pe, pt, ps); - //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) - { -#if 0 - if (s) printf("s = %s\n", s->kind()); - printf("2: e:%p s:%p ", e, s); -#endif - 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); - 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); -} - -void TypeTypeof::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - assert(0); -} - -Type *TypeTypeof::semantic(Loc loc, Scope *sc) -{ Expression *e; - Type *t; - - //printf("TypeTypeof::semantic() %p\n", this); - - //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++; - unsigned oldspecgag = global.speculativeGag; - if (global.gag) - global.speculativeGag = global.gag; - exp = exp->semantic(sc2); - global.speculativeGag = oldspecgag; -#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; - } - } - - if (idents.dim) - { - Dsymbol *s = t->toDsymbol(sc); - for (size_t i = 0; i < idents.dim; i++) - { - if (!s) - break; - Identifier *id = (Identifier *)idents.data[i]; - s = s->searchX(loc, sc, id); - } - if (s) - { - t = s->getType(); - if (!t) - { error(loc, "%s is not a type", s->toChars()); - goto Lerr; - } - } - else - { error(loc, "cannot resolve .property for %s", toChars()); - goto Lerr; - } - } - 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); -} - - - -/***************************** TypeEnum *****************************/ - -TypeEnum::TypeEnum(EnumDeclaration *sym) - : Type(Tenum, NULL) -{ - this->sym = sym; -} - -char *TypeEnum::toChars() -{ - return sym->toChars(); -} - -Type *TypeEnum::syntaxCopy() -{ - return this; -} - -Type *TypeEnum::semantic(Loc loc, Scope *sc) -{ - //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 terror; - } - return sym->memtype->toBasetype(); -} - -void TypeEnum::toDecoBuffer(OutBuffer *buf, bool mangle) -{ char *name; - - name = sym->mangle(); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - buf->printf("%c%s", mangleChar[ty], 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) -{ - EnumMember *m; - Dsymbol *s; - Expression *em; - -#if LOGDOTEXP - printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars()); -#endif - if (!sym->symtab) - goto Lfwd; - s = sym->symtab->lookup(ident); - 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); - } - m = s->isEnumMember(); - em = m->value->copy(); - em->loc = e->loc; - return em; - -Lfwd: - error(e->loc, "forward reference of enum %s.%s", toChars(), ident->toChars()); - return new IntegerExp(0, 0, Type::terror); -} - -Expression *TypeEnum::getProperty(Loc loc, Identifier *ident) -{ Expression *e; - - if (ident == Id::max) - { - if (!sym->symtab) - goto Lfwd; - e = new IntegerExp(0, sym->maxval, this); - } - else if (ident == Id::min) - { - if (!sym->symtab) - goto Lfwd; - e = new IntegerExp(0, sym->minval, this); - } - else if (ident == Id::init) - { - if (!sym->symtab) - goto Lfwd; - e = defaultInit(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 - { - if (!sym->memtype) - goto Lfwd; - e = sym->memtype->getProperty(loc, ident); - } - return e; - -Lfwd: - error(loc, "forward reference of %s.%s", toChars(), ident->toChars()); - return new IntegerExp(0, 0, this); -} - -int TypeEnum::isintegral() -{ - return 1; -} - -int TypeEnum::isfloating() -{ - return 0; -} - -int TypeEnum::isunsigned() -{ - return sym->memtype->isunsigned(); -} - -int TypeEnum::isscalar() -{ - return 1; - //return sym->memtype->isscalar(); -} - -MATCH TypeEnum::implicitConvTo(Type *to) -{ MATCH m; - - //printf("TypeEnum::implicitConvTo()\n"); - if (this->equals(to)) - m = MATCHexact; // exact match - else if (sym->memtype->implicitConvTo(to)) - m = MATCHconvert; // match with conversions - else - m = MATCHnomatch; // no match - return m; -} - -Expression *TypeEnum::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeEnum::defaultInit() '%s'\n", toChars()); -#endif - // Initialize to first member of enum - Expression *e; - e = new IntegerExp(loc, sym->defaultval, this); - return e; -} - -int TypeEnum::isZeroInit(Loc loc) -{ - //printf("TypeEnum::isZeroInit() '%s'\n", toChars()); - if (!sym->isdone && sym->scope) - { // Enum is forward referenced. We need to resolve the whole thing. - sym->semantic(NULL); - } - if (!sym->isdone) - { -#ifdef DEBUG - printf("3: "); -#endif - error(loc, "enum %s is forward referenced", sym->toChars()); - return 0; - } - return (sym->defaultval == 0); -} - -int TypeEnum::hasPointers() -{ - return toBasetype()->hasPointers(); -} - -/***************************** TypeTypedef *****************************/ - -TypeTypedef::TypeTypedef(TypedefDeclaration *sym) - : Type(Ttypedef, NULL) -{ - this->sym = sym; -} - -Type *TypeTypedef::syntaxCopy() -{ - return this; -} - -char *TypeTypedef::toChars() -{ - return sym->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, bool mangle) -{ unsigned len; - char *name; - - name = sym->mangle(); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - //len = strlen(name); - //buf->printf("%c%d%s", mangleChar[ty], len, name); - buf->printf("%c%s", mangleChar[ty], 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 (ident == Id::init) - { - return Type::getProperty(loc, ident); - } - return sym->basetype->getProperty(loc, ident); -} - -int TypeTypedef::isbit() -{ - return sym->basetype->isbit(); -} - -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::checkBoolean() -{ - return sym->basetype->checkBoolean(); -} - -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; - return t; -} - -MATCH TypeTypedef::implicitConvTo(Type *to) -{ MATCH m; - - //printf("TypeTypedef::implicitConvTo()\n"); - if (this->equals(to)) - m = MATCHexact; // exact match - else if (sym->basetype->implicitConvTo(to)) - m = MATCHconvert; // match with conversions - else - m = MATCHnomatch; // no match - return m; -} - -Expression *TypeTypedef::defaultInit(Loc loc) -{ Expression *e; - Type *bt; - -#if LOGDEFAULTINIT - printf("TypeTypedef::defaultInit() '%s'\n", toChars()); -#endif - if (sym->init) - { - //sym->init->toExpression()->print(); - return sym->init->toExpression(); - } - bt = sym->basetype; - e = bt->defaultInit(loc); - e->type = this; - while (bt->ty == Tsarray) - { - e->type = bt->next; - bt = bt->next->toBasetype(); - } - 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(); -} - -/***************************** TypeStruct *****************************/ - -TypeStruct::TypeStruct(StructDeclaration *sym) - : Type(Tstruct, NULL) -{ - this->sym = sym; - - // LDC - this->unaligned = 0; -} - -char *TypeStruct::toChars() -{ - //printf("sym.parent: %s, deco = %s\n", sym->parent->toChars(), deco); - 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 (sym->structalign == STRUCTALIGN_DEFAULT) - { - if (sz > 8) - sz = 8; - } - else if (sz > sym->structalign) - sz = sym->structalign; - return sz; -} - -Dsymbol *TypeStruct::toDsymbol(Scope *sc) -{ - return sym; -} - -void TypeStruct::toDecoBuffer(OutBuffer *buf, bool mangle) -{ unsigned len; - char *name; - - name = sym->mangle(); - //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", toChars(), name); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - //len = strlen(name); - //buf->printf("%c%d%s", mangleChar[ty], len, name); - buf->printf("%c%s", mangleChar[ty], 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) -{ - Expression *b; - 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); - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields[i]; - Expression *fe = new DotVarExp(e->loc, e, v); - exps->push(fe); - } - e = new TupleExp(e->loc, exps); - sc = sc->push(); - sc->noaccesscheck = 1; - e = e->semantic(sc); - sc->pop(); - return e; - } - - if (e->op == TOKdotexp) - { DotExp *de = (DotExp *)e; - - if (de->e1->op == TOKimport) - { - 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 getProperty(e->loc, ident); - return Type::dotExp(sc, e, ident); - } - if (!s->isFuncDeclaration()) // because of overloading - s->checkDeprecated(e->loc, sc); - s = s->toAlias(); - - v = s->isVarDeclaration(); - if (v && v->isSameAsInitializer() && v->type->toBasetype()->ty != Tsarray) - { ExpInitializer *ei = v->getExpInitializer(); - - if (ei) - { e = ei->exp->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->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); - e = e->semantic(sc); - return e; - } - - 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->needThis() && fd && fd->vthis && - fd->toParent2()->isStructDeclaration() == sym) - { - e = new DotVarExp(e->loc, new ThisExp(e->loc), d); - e = e->semantic(sc); - return e; - } - if (d->isTupleDeclaration()) - { - e = new TupleExp(e->loc, d->isTupleDeclaration()); - e = e->semantic(sc); - return e; - } - return new VarExp(e->loc, d); - } - - 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 - 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(); - e = new PtrExp(e->loc, b); - e->type = v->type; - return e; -#endif - } - - de = new DotVarExp(e->loc, e, d); - return de->semantic(sc); -} - -structalign_t TypeStruct::memalign(structalign_t 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 - Expressions *structelems = new Expressions(); - structelems->setDim(sym->fields.dim); - for (size_t j = 0; j < structelems->dim; j++) - { - VarDeclaration *vd = sym->fields[j]; - Expression *e; - if (vd->init) - { if (vd->init->isVoidInitializer()) - e = NULL; - else - e = vd->init->toExpression(); - } - else - e = vd->type->defaultInitLiteral(loc); - (*structelems)[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::hasPointers() -{ - StructDeclaration *s = sym; - - sym->size(0); // give error for forward references - if (s->members) - { - for (size_t i = 0; i < s->members->dim; i++) - { - Dsymbol *sm = (Dsymbol *)s->members->data[i]; - if (sm->hasPointers()) - return TRUE; - } - } - return FALSE; -} - - -/***************************** TypeClass *****************************/ - -TypeClass::TypeClass(ClassDeclaration *sym) - : Type(Tclass, NULL) -{ - this->sym = sym; -} - -char *TypeClass::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, bool mangle) -{ unsigned len; - char *name; - - name = sym->mangle(); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - //printf("TypeClass::toDecoBuffer('%s') = '%s'\n", toChars(), name); - //len = strlen(name); - //buf->printf("%c%d%s", mangleChar[ty], len, name); - buf->printf("%c%s", mangleChar[ty], 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; - DotVarExp *de; - -#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 - e->type->size(); // do semantic of type - Expressions *exps = new Expressions; - exps->reserve(sym->fields.dim); - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields[i]; - // Don't include hidden 'this' pointer - if (v->isThisDeclaration()) - continue; - Expression *fe = new DotVarExp(e->loc, e, v); - exps->push(fe); - } - e = new TupleExp(e->loc, exps); - sc = sc->push(); - sc->noaccesscheck = 1; - e = e->semantic(sc); - sc->pop(); - return e; - } - - s = sym->search(e->loc, ident, 0); -L1: - if (!s) - { - // See if it's a base class - 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 ClassInfoDeclaration(sym); - e = new VarExp(e->loc, sym->vclassinfo); - e = e->addressOf(sc); - e->type = t; // do this so we don't get redundant dereference - } - else - { - /* 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->next; - e = new PtrExp(e->loc, e); - e->type = ct->next->next; - - 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->next->next->next; - } - } - -#else - - e = new PtrExp(e->loc, e); - e->type = t->pointerTo(); - 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->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(void***)e - */ - e = e->castTo(sc, tvoidptr->pointerTo()->pointerTo()); - e = new PtrExp(e->loc, e); - e = e->semantic(sc); - return e; - } - - if (ident == Id::__monitor) - { /* The handle to the monitor (call it a void*) - * *(cast(void**)e + 1) - */ - e = e->castTo(sc, tvoidptr->pointerTo()); - e = new AddExp(e->loc, e, new IntegerExp(1)); - e = new PtrExp(e->loc, e); - e = e->semantic(sc); - return e; - } - - 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 getProperty(e->loc, ident); - return Type::dotExp(sc, e, ident); - } - } - if (!s->isFuncDeclaration()) // because of overloading - s->checkDeprecated(e->loc, sc); - s = s->toAlias(); - v = s->isVarDeclaration(); - if (v && v->isSameAsInitializer() && v->type->toBasetype()->ty != Tsarray) - { ExpInitializer *ei = v->getExpInitializer(); - - if (ei) - { e = ei->exp->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->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 - - 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); - 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); - e = new CommaExp(e->loc, e, ve); - e->type = d->type; - return e; - } - - 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('%s')\n", to->toChars()); - if (this == to) - return MATCHexact; - - ClassDeclaration *cdto = to->isClassHandle(); - if (cdto && cdto->isBaseOf(sym, NULL)) - { //printf("'to' is base\n"); - return MATCHconvert; - } - - if (global.params.Dversion == 1) - { - // Allow conversion to (void *) - if (to->ty == Tpointer && to->next->ty == Tvoid) - return MATCHconvert; - } - - return MATCHnomatch; -} - -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, NULL) -{ - //printf("TypeTuple(this = %p)\n", this); - this->arguments = arguments; - //printf("TypeTuple() %s\n", toChars()); -#ifdef DEBUG - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { - Parameter *arg = (Parameter *)arguments->data[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, NULL) -{ - Parameters *arguments = new Parameters; - if (exps) - { - arguments->setDim(exps->dim); - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - if (e->type->ty == Ttuple) - e->error("cannot form tuple of tuples"); - Parameter *arg = new Parameter(STCin, e->type, NULL, NULL); - arguments->data[i] = (void *)arg; - } - } - this->arguments = arguments; -} - -/******************************************* - * Type tuple with 0, 1 or 2 types in it. - */ -TypeTuple::TypeTuple() - : Type(Ttuple, NULL) -{ - arguments = new Parameters(); -} - -TypeTuple::TypeTuple(Type *t1) - : Type(Ttuple, NULL) -{ - arguments = new Parameters(); - arguments->push(new Parameter(0, t1, NULL, NULL)); -} - -TypeTuple::TypeTuple(Type *t1, Type *t2) - : Type(Ttuple, NULL) -{ - 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); - return t; -} - -Type *TypeTuple::semantic(Loc loc, Scope *sc) -{ - //printf("TypeTuple::semantic(this = %p)\n", this); - //printf("TypeTuple::semantic() %s\n", 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 = (Parameter *)arguments->data[i]; - Parameter *arg2 = (Parameter *)tt->arguments->data[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 = (Parameter *)arguments->data[i]; - Type *t = arg->type->reliesOnTident(); - if (t) - return t; - } - } - return NULL; -} - -void TypeTuple::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - Parameter::argsToCBuffer(buf, hgs, arguments, 0); -} - -void TypeTuple::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - //printf("TypeTuple::toDecoBuffer() this = %p\n", this); - OutBuffer buf2; - Parameter::argsToDecoBuffer(&buf2, arguments, mangle); - unsigned len = buf2.offset; - buf->printf("%c%d%.*s", mangleChar[ty], 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 IntegerExp(loc, 1, Type::tint32); - } - return e; -} - -/***************************** TypeSlice *****************************/ - -/* This is so we can slice a TypeTuple */ - -TypeSlice::TypeSlice(Type *next, Expression *lwr, Expression *upr) - : Type(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()); - return t; -} - -Type *TypeSlice::semantic(Loc loc, Scope *sc) -{ - //printf("TypeSlice::semantic() %s\n", toChars()); - next = next->semantic(loc, sc); - //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->ctfeInterpret(); - uinteger_t i1 = lwr->toUInteger(); - - upr = semanticLength(sc, tbn, upr); - upr = upr->ctfeInterpret(); - 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 = (Parameter *)tt->arguments->data[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(td); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - lwr = lwr->semantic(sc); - lwr = lwr->ctfeInterpret(); - uinteger_t i1 = lwr->toUInteger(); - - upr = upr->semantic(sc); - upr = upr->ctfeInterpret(); - 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->data[i] = td->objects->data[(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()); -} - -/***************************** 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)[i]; - - arg = arg->syntaxCopy(); - (*a)[i] = arg; - } - } - return a; -} - -char *Parameter::argsTypesToChars(Parameters *args, int varargs) -{ - OutBuffer *buf = new OutBuffer(); - - HdrGenState hgs; - argsToCBuffer(buf, &hgs, args, varargs); - - return buf->toChars(); -} - -void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *arguments, int varargs) -{ - buf->writeByte('('); - if (arguments) - { - OutBuffer argbuf; - - for (size_t i = 0; i < arguments->dim; i++) - { - if (i) - buf->writestring(", "); - Parameter *arg = (Parameter *)arguments->data[i]; - if (arg->storageClass & STCout) - buf->writestring("out "); - else if (arg->storageClass & STCref) - buf->writestring((global.params.Dversion == 1) - ? (char *)"inout " : (char *)"ref "); - else if (arg->storageClass & STClazy) - buf->writestring("lazy "); - argbuf.reset(); - 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); -} - -/**************************************** - * 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 = 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) -{ - 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); - } - type->toDecoBuffer(buf, mangle); -} - -/*************************************** - * 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/dmd/mtype.h b/dmd/mtype.h deleted file mode 100644 index e699be9d..00000000 --- a/dmd/mtype.h +++ /dev/null @@ -1,861 +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. - -#ifndef DMD_MTYPE_H -#define DMD_MTYPE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "stringtable.h" - -#include "arraytypes.h" -#include "expression.h" - -#if IN_LLVM -#include "../ir/irfuncty.h" -namespace llvm { class Type; } -class Ir; -class IrType; -#endif - -struct Scope; -struct Identifier; -struct Expression; -struct StructDeclaration; -struct ClassDeclaration; -struct VarDeclaration; -struct EnumDeclaration; -struct TypedefDeclaration; -struct TypeInfoDeclaration; -struct Dsymbol; -struct TemplateInstance; -struct CppMangleState; -enum LINK; - -struct TypeBasic; -struct HdrGenState; -struct Parameter; - -// Back end -#if IN_GCC -union tree_node; typedef union tree_node TYPE; -typedef TYPE type; -#else -typedef struct TYPE type; -#endif -struct Symbol; -struct TypeTuple; - -enum TY -{ - Tarray, // dynamic array - Tsarray, // static array - Taarray, // associative array - Tpointer, - Treference, - Tfunction, - Tident, - Tclass, - Tstruct, - Tenum, - Ttypedef, - Tdelegate, - - Tnone, - Tvoid, - Tint8, - Tuns8, - Tint16, - Tuns16, - Tint32, - Tuns32, - Tint64, - Tuns64, - Tfloat32, - Tfloat64, - Tfloat80, - - Timaginary32, - Timaginary64, - Timaginary80, - - Tcomplex32, - Tcomplex64, - Tcomplex80, - - Tbit, - Tbool, - Tchar, - Twchar, - Tdchar, - - Terror, - Tinstance, - Ttypeof, - Ttuple, - Tslice, - Treturn, - TMAX, - Tnull -}; - -#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; - Type *pto; // merged pointer to this type - Type *rto; // reference to this type - Type *arrayof; // array of this type - TypeInfoDeclaration *vtinfo; // TypeInfo object for this Type - -#if IN_DMD - type *ctype; // for back end -#endif - - #define tvoid basic[Tvoid] - #define tint8 basic[Tint8] - #define tuns8 basic[Tuns8] - #define tint16 basic[Tint16] - #define tuns16 basic[Tuns16] - #define tint32 basic[Tint32] - #define tuns32 basic[Tuns32] - #define tint64 basic[Tint64] - #define tuns64 basic[Tuns64] - #define tfloat32 basic[Tfloat32] - #define tfloat64 basic[Tfloat64] - #define tfloat80 basic[Tfloat80] - - #define timaginary32 basic[Timaginary32] - #define timaginary64 basic[Timaginary64] - #define timaginary80 basic[Timaginary80] - - #define tcomplex32 basic[Tcomplex32] - #define tcomplex64 basic[Tcomplex64] - #define tcomplex80 basic[Tcomplex80] - - #define tbit basic[Tbit] - #define tbool basic[Tbool] - #define tchar basic[Tchar] - #define twchar basic[Twchar] - #define tdchar basic[Tdchar] - - // Some special types - #define tshiftcnt tint32 // right side of shift expression -// #define tboolean tint32 // result of boolean expression - #define tboolean tbool // result of boolean expression - #define tindex tsize_t // array/ptr index - static Type *tvoidptr; // void* - static Type *tstring; // immutable(char)[] - #define terror basic[Terror] // for error recovery - - #define tsize_t basic[Tsize_t] // matches size_t alias - #define tptrdiff_t basic[Tptrdiff_t] // matches ptrdiff_t alias - #define thash_t tsize_t // matches hash_t alias - - static ClassDeclaration *typeinfo; - static ClassDeclaration *typeinfoclass; - static ClassDeclaration *typeinfointerface; - static ClassDeclaration *typeinfostruct; - static ClassDeclaration *typeinfotypedef; - static ClassDeclaration *typeinfopointer; - static ClassDeclaration *typeinfoarray; - static ClassDeclaration *typeinfostaticarray; - static ClassDeclaration *typeinfoassociativearray; - static ClassDeclaration *typeinfoenum; - static ClassDeclaration *typeinfofunction; - static ClassDeclaration *typeinfodelegate; - static ClassDeclaration *typeinfotypelist; - - static Type *basic[TMAX]; - static unsigned char mangleChar[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, Type *next); - 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, bool mangle); - 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); - virtual int isbit(); - 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 checkBoolean(); // if can be converted to boolean value - void checkDeprecated(Loc loc, Scope *sc); - Type *pointerTo(); - Type *referenceTo(); - Type *arrayOf(); - virtual Dsymbol *toDsymbol(Scope *sc); - virtual Type *toBasetype(); - virtual int isBaseOf(Type *t, int *poffset); - virtual MATCH implicitConvTo(Type *to); - virtual ClassDeclaration *isClassHandle(); - virtual Expression *getProperty(Loc loc, Identifier *ident); - virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - virtual structalign_t memalign(structalign_t salign); - virtual Expression *defaultInit(Loc loc = 0); - virtual Expression *defaultInitLiteral(Loc loc); - virtual Expression *voidInitLiteral(VarDeclaration *var); - virtual int isZeroInit(Loc loc = 0); // if initializer is 0 -#if IN_DMD - virtual dt_t **toDt(dt_t **pdt); -#endif - Identifier *getTypeInfoIdent(int internal); - virtual MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Expression *getInternalTypeInfo(Scope *sc); - Expression *getTypeInfo(Scope *sc); - virtual TypeInfoDeclaration *getTypeInfoDeclaration(); - virtual int builtinTypeInfo(); - virtual Type *reliesOnTident(); - virtual Expression *toExpression(); - virtual int hasPointers(); - virtual TypeTuple *toArgTypes(); - Type *next; - Type *nextOf() { return next; } - - static void error(Loc loc, const char *format, ...) IS_PRINTF(2); - static void warning(Loc loc, const char *format, ...) IS_PRINTF(2); - -#if IN_DMD - // For backend - virtual unsigned totym(); - virtual type *toCtype(); - virtual type *toCParamtype(); - virtual Symbol *toSymbol(); -#endif - - // For eliminating dynamic_cast - virtual TypeBasic *isTypeBasic(); - -#if IN_LLVM - static Ir* sir; - IrType* irtype; -#endif -}; - -struct TypeError : Type -{ - TypeError(); - - void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - - d_uns64 size(Loc loc); - Expression *getProperty(Loc loc, Identifier *ident); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - Expression *defaultInitLiteral(Loc loc); - TypeTuple *toArgTypes(); -}; - -#if DMDV2 -struct TypeNext : Type -{ - Type *next; - - TypeNext(TY ty, Type *next); - void toDecoBuffer(OutBuffer *buf, int flag); - void checkDeprecated(Loc loc, Scope *sc); - Type *reliesOnTident(); - int hasWild(); - unsigned wildMatch(Type *targ); - Type *nextOf(); - Type *makeConst(); - Type *makeInvariant(); - Type *makeShared(); - Type *makeSharedConst(); - Type *makeWild(); - Type *makeSharedWild(); - Type *makeMutable(); - MATCH constConv(Type *to); - void transitive(); -}; -#endif - -struct TypeBasic : Type -{ - const char *dstring; - const char *cstring; - 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); - int isintegral(); - int isbit(); - int isfloating(); - int isreal(); - int isimaginary(); - int iscomplex(); - int isscalar(); - int isunsigned(); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - int builtinTypeInfo(); - TypeTuple *toArgTypes(); - - // For eliminating dynamic_cast - TypeBasic *isTypeBasic(); -}; - -struct TypeArray : Type -{ - 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, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int isString(); - int isZeroInit(Loc loc); - structalign_t memalign(structalign_t salign); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - Expression *defaultInitLiteral(Loc loc); - Expression *voidInitLiteral(VarDeclaration *var); -#if IN_DMD - dt_t **toDt(dt_t **pdt); - dt_t **toDtElem(dt_t **pdt, Expression *e); -#endif - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Expression *toExpression(); - int hasPointers(); - TypeTuple *toArgTypes(); - -#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, 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(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeAArray : TypeArray -{ - Type *index; // key type for type checking - Type *key; // actual key type - - TypeAArray(Type *t, Type *index); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toDecoBuffer(OutBuffer *buf, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - int isZeroInit(Loc loc); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Expression *toExpression(); - int hasPointers(); - TypeTuple *toArgTypes(); - -#if IN_DMD - // Back end - Symbol *aaGetSymbol(const char *func, int flags); - - type *toCtype(); -#endif -}; - -struct TypePointer : Type -{ - TypePointer(Type *t); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - MATCH implicitConvTo(Type *to); - int isscalar(); - // LDC: pointers are unsigned - int isunsigned() { return TRUE; }; - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeReference : Type -{ - TypeReference(Type *t); - Type *syntaxCopy(); - 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); -}; - -enum RET -{ - RETregs = 1, // returned in registers - RETstack = 2, // returned on stack -}; - -struct TypeFunction : Type -{ - Parameters *parameters; // function parameters - int varargs; // 1: T t, ...) style for variable number of arguments - // if extern (C) then this is C style va_args - // if extern (D) then D style va_args - // 2: T t ...) style for variable number of arguments - // where the args are stored in a local, and a - // dynamic array is passed to the function - enum LINK linkage; // calling convention - - int inuse; - - TypeFunction(Parameters *parameters, Type *treturn, int varargs, enum LINK linkage); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - void toDecoBuffer(OutBuffer *buf, 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); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Type *reliesOnTident(); - - int callMatch(Expressions *toargs); -#if IN_DMD - type *toCtype(); -#endif - - enum RET retStyle(); - -#if IN_DMD - unsigned totym(); -#elif IN_LLVM - // LDC - IrFuncTy fty; - - FuncDeclaration* funcdecl; -#endif - - Expression *defaultInit(Loc loc); -}; - -struct TypeDelegate : Type -{ - TypeDelegate(Type *t); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - unsigned alignsize(); - 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 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, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Dsymbol *toDsymbol(Scope *sc); - Type *semantic(Loc loc, Scope *sc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - Type *reliesOnTident(); - Expression *toExpression(); -}; - -/* Similar to TypeIdentifier, but with a TemplateInstance as the root - */ -struct TypeInstance : TypeQualified -{ - TemplateInstance *tempinst; - - TypeInstance(Loc loc, TemplateInstance *tempinst); - Type *syntaxCopy(); - //char *toChars(); - //void toDecoBuffer(OutBuffer *buf, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); -}; - -struct TypeTypeof : TypeQualified -{ - Expression *exp; - int inuse; - - TypeTypeof(Loc loc, Expression *exp); - Type *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void toDecoBuffer(OutBuffer *buf, bool mangle); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); -}; - -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, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - structalign_t memalign(structalign_t salign); - Expression *defaultInit(Loc loc); - Expression *defaultInitLiteral(Loc loc); - Expression *voidInitLiteral(VarDeclaration *var); - int isZeroInit(Loc loc); - int checkBoolean(); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); -#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, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *getProperty(Loc loc, Identifier *ident); - int isintegral(); - int isfloating(); - int isscalar(); - int isunsigned(); - MATCH implicitConvTo(Type *to); - Type *toBasetype(); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - 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, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *getProperty(Loc loc, Identifier *ident); - int isbit(); - int isintegral(); - int isfloating(); - int isreal(); - int isimaginary(); - int iscomplex(); - int isscalar(); - int isunsigned(); - int checkBoolean(); - Type *toBasetype(); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); - -#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, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - ClassDeclaration *isClassHandle(); - int isBaseOf(Type *t, int *poffset); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - int isscope(); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); - int builtinTypeInfo(); -#if DMDV2 - Type *toHeadMutable(); - MATCH constConv(Type *to); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif -#endif - -#if IN_DMD - type *toCtype(); - - Symbol *toSymbol(); -#endif -}; - -struct TypeTuple : Type -{ - Parameters *arguments; // types making up the tuple - - TypeTuple(Parameters *arguments); - TypeTuple(Expressions *exps); - 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, bool mangle); - Expression *getProperty(Loc loc, Identifier *ident); - TypeInfoDeclaration *getTypeInfoDeclaration(); -}; - -struct TypeSlice : Type -{ - Expression *lwr; - Expression *upr; - - TypeSlice(Type *next, Expression *lwr, Expression *upr); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); -}; - -/**************************************************************/ - -//enum InOut { None, In, Out, InOut, Lazy }; - -struct 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); - -#endif /* DMD_MTYPE_H */ diff --git a/dmd/opover.c b/dmd/opover.c deleted file mode 100644 index eaa7841c..00000000 --- a/dmd/opover.c +++ /dev/null @@ -1,787 +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 -#include // memset() -#if _MSC_VER -#include -#else -#include -#endif - -#include "rmem.h" - -//#include "port.h" -#include "mtype.h" -#include "init.h" -#include "expression.h" -#include "id.h" -#include "declaration.h" -#include "aggregate.h" -#include "template.h" -#include "scope.h" - -static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id); -static void inferApplyArgTypesX(Module* from, FuncDeclaration *fstart, Parameters *arguments); -static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments); -static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments); - -/******************************** Expression **************************/ - - -/*********************************** - * Determine if operands of binary op can be reversed - * to fit operator overload. - */ - -int Expression::isCommutative() -{ - return FALSE; // default is no reverse -} - -/*********************************** - * Get Identifier for operator overload. - */ - -Identifier *Expression::opId() -{ - assert(0); - return NULL; -} - -/*********************************** - * Get Identifier for reverse operator overload, - * NULL if not supported for this operator. - */ - -Identifier *Expression::opId_r() -{ - return NULL; -} - -/************************* Operators *****************************/ - -Identifier *UAddExp::opId() { return Id::uadd; } - -Identifier *NegExp::opId() { return Id::neg; } - -Identifier *ComExp::opId() { return Id::com; } - -Identifier *CastExp::opId() { return Id::cast; } - -Identifier *InExp::opId() { return Id::opIn; } -Identifier *InExp::opId_r() { return Id::opIn_r; } - -Identifier *PostExp::opId() { return (op == TOKplusplus) - ? Id::postinc - : Id::postdec; } - -int AddExp::isCommutative() { return TRUE; } -Identifier *AddExp::opId() { return Id::add; } -Identifier *AddExp::opId_r() { return Id::add_r; } - -Identifier *MinExp::opId() { return Id::sub; } -Identifier *MinExp::opId_r() { return Id::sub_r; } - -int MulExp::isCommutative() { return TRUE; } -Identifier *MulExp::opId() { return Id::mul; } -Identifier *MulExp::opId_r() { return Id::mul_r; } - -Identifier *DivExp::opId() { return Id::div; } -Identifier *DivExp::opId_r() { return Id::div_r; } - -Identifier *ModExp::opId() { return Id::mod; } -Identifier *ModExp::opId_r() { return Id::mod_r; } - -Identifier *ShlExp::opId() { return Id::shl; } -Identifier *ShlExp::opId_r() { return Id::shl_r; } - -Identifier *ShrExp::opId() { return Id::shr; } -Identifier *ShrExp::opId_r() { return Id::shr_r; } - -Identifier *UshrExp::opId() { return Id::ushr; } -Identifier *UshrExp::opId_r() { return Id::ushr_r; } - -int AndExp::isCommutative() { return TRUE; } -Identifier *AndExp::opId() { return Id::iand; } -Identifier *AndExp::opId_r() { return Id::iand_r; } - -int OrExp::isCommutative() { return TRUE; } -Identifier *OrExp::opId() { return Id::ior; } -Identifier *OrExp::opId_r() { return Id::ior_r; } - -int XorExp::isCommutative() { return TRUE; } -Identifier *XorExp::opId() { return Id::ixor; } -Identifier *XorExp::opId_r() { return Id::ixor_r; } - -Identifier *CatExp::opId() { return Id::cat; } -Identifier *CatExp::opId_r() { return Id::cat_r; } - -Identifier * AssignExp::opId() { return Id::assign; } -Identifier * AddAssignExp::opId() { return Id::addass; } -Identifier * MinAssignExp::opId() { return Id::subass; } -Identifier * MulAssignExp::opId() { return Id::mulass; } -Identifier * DivAssignExp::opId() { return Id::divass; } -Identifier * ModAssignExp::opId() { return Id::modass; } -Identifier * AndAssignExp::opId() { return Id::andass; } -Identifier * OrAssignExp::opId() { return Id::orass; } -Identifier * XorAssignExp::opId() { return Id::xorass; } -Identifier * ShlAssignExp::opId() { return Id::shlass; } -Identifier * ShrAssignExp::opId() { return Id::shrass; } -Identifier *UshrAssignExp::opId() { return Id::ushrass; } -Identifier * CatAssignExp::opId() { return Id::catass; } - -int EqualExp::isCommutative() { return TRUE; } -Identifier *EqualExp::opId() { return Id::eq; } - -int CmpExp::isCommutative() { return TRUE; } -Identifier *CmpExp::opId() { return Id::cmp; } - -Identifier *ArrayExp::opId() { return Id::index; } - - -/************************************ - * Operator overload. - * Check for operator overload, if so, replace - * with function call. - * Return NULL if not an operator overload. - */ - -Expression *UnaExp::op_overload(Scope *sc) -{ - //printf("UnaExp::op_overload() (%s)\n", toChars()); - AggregateDeclaration *ad; - Dsymbol *fd; - Type *t1 = e1->type->toBasetype(); - - if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - goto L1; - } - else if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - - L1: - fd = search_function(ad, opId()); - if (fd) - { - if (op == TOKarray) - { - /* Rewrite op e1[arguments] as: - * e1.fd(arguments) - */ - Expression *e = new DotIdExp(loc, e1, fd->ident); - ArrayExp *ae = (ArrayExp *)this; - e = new CallExp(loc, e, ae->arguments); - e = e->semantic(sc); - return e; - } - else - { - // Rewrite +e1 as e1.add() - return build_overload(loc, sc, e1, NULL, fd->ident); - } - } - -#if DMDV2 - // Didn't find it. Forward to aliasthis - if (ad->aliasthis) - { - /* Rewrite op(e1) as: - * op(e1.aliasthis) - */ - Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->semantic(sc); - return e; - } -#endif - } - return NULL; -} - - -Expression *BinExp::op_overload(Scope *sc) -{ - //printf("BinExp::op_overload() (%s)\n", toChars()); - - AggregateDeclaration *ad; - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - Identifier *id = opId(); - Identifier *id_r = opId_r(); - - Match m; - Expressions args1; - Expressions args2; - int argsset = 0; - - AggregateDeclaration *ad1; - if (t1->ty == Tclass) - ad1 = ((TypeClass *)t1)->sym; - else if (t1->ty == Tstruct) - ad1 = ((TypeStruct *)t1)->sym; - else - ad1 = NULL; - - AggregateDeclaration *ad2; - if (t2->ty == Tclass) - ad2 = ((TypeClass *)t2)->sym; - else if (t2->ty == Tstruct) - ad2 = ((TypeStruct *)t2)->sym; - else - ad2 = NULL; - - Dsymbol *s = NULL; - Dsymbol *s_r = NULL; - FuncDeclaration *fd = NULL; - TemplateDeclaration *td = NULL; - if (ad1 && id) - { - s = search_function(ad1, id); - } - if (ad2 && id_r) - { - s_r = search_function(ad2, id_r); - } - - if (s || s_r) - { - /* Try: - * a.opfunc(b) - * b.opfunc_r(a) - * and see which is better. - */ - Expression *e; - FuncDeclaration *lastf; - - args1.setDim(1); - args1.data[0] = (void*) e1; - args2.setDim(1); - args2.data[0] = (void*) e2; - argsset = 1; - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - - if (s) - { - fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2, sc->module); - } - else - { td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, NULL, &args2); - } - } - - lastf = m.lastf; - - if (s_r) - { - fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args1, sc->module); - } - else - { td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, NULL, &args1); - } - } - - if (m.count > 1) - { - // Error, ambiguous - error("overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); - } - else if (m.last == MATCHnomatch) - { - m.lastf = m.anyf; - } - - if (op == TOKplusplus || op == TOKminusminus) - // Kludge because operator overloading regards e++ and e-- - // as unary, but it's implemented as a binary. - // Rewrite (e1 ++ e2) as e1.postinc() - // Rewrite (e1 -- e2) as e1.postdec() - e = build_overload(loc, sc, e1, NULL, id); - else if (lastf && m.lastf == lastf || m.last == MATCHnomatch) - // Rewrite (e1 op e2) as e1.opfunc(e2) - e = build_overload(loc, sc, e1, e2, id); - else - // Rewrite (e1 op e2) as e2.opfunc_r(e1) - e = build_overload(loc, sc, e2, e1, id_r); - return e; - } - - if (isCommutative()) - { - s = NULL; - s_r = NULL; - if (ad1 && id_r) - { - s_r = search_function(ad1, id_r); - } - if (ad2 && id) - { - s = search_function(ad2, id); - } - - if (s || s_r) - { - /* Try: - * a.opfunc_r(b) - * b.opfunc(a) - * and see which is better. - */ - FuncDeclaration *lastf; - - if (!argsset) - { args1.setDim(1); - args1.data[0] = (void*) e1; - args2.setDim(1); - args2.data[0] = (void*) e2; - } - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - - if (s_r) - { - fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2, sc->module); - } - else - { td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, NULL, &args2); - } - } - lastf = m.lastf; - - if (s) - { - fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args1, sc->module); - } - else - { td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, NULL, &args1); - } - } - - if (m.count > 1) - { - // Error, ambiguous - error("overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); - } - else if (m.last == MATCHnomatch) - { - m.lastf = m.anyf; - } - - Expression *e; - if (lastf && m.lastf == lastf || - id_r && m.last == MATCHnomatch) - // Rewrite (e1 op e2) as e1.opfunc_r(e2) - e = build_overload(loc, sc, e1, e2, id_r); - else - // Rewrite (e1 op e2) as e2.opfunc(e1) - e = build_overload(loc, sc, e2, e1, id); - - // When reversing operands of comparison operators, - // need to reverse the sense of the op - switch (op) - { - case TOKlt: op = TOKgt; break; - case TOKgt: op = TOKlt; break; - case TOKle: op = TOKge; break; - case TOKge: op = TOKle; break; - - // Floating point compares - case TOKule: op = TOKuge; break; - case TOKul: op = TOKug; break; - case TOKuge: op = TOKule; break; - case TOKug: op = TOKul; break; - - // These are symmetric - case TOKunord: - case TOKlg: - case TOKleg: - case TOKue: - break; - } - - return e; - } - } - -#if DMDV2 - // Try alias this on first operand - if (ad1 && ad1->aliasthis) - { - /* Rewrite (e1 op e2) as: - * (e1.aliasthis op e2) - */ - Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e1 = e1; - e = e->semantic(sc); - return e; - } - - // Try alias this on second operand - if (ad2 && ad2->aliasthis) - { - /* Rewrite (e1 op e2) as: - * (e1 op e2.aliasthis) - */ - Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e2 = e2; - e = e->semantic(sc); - return e; - } -#endif - return NULL; -} - -/*********************************** - * Utility to build a function call out of this reference and argument. - */ - -Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id) -{ - Expression *e; - - //printf("build_overload(id = '%s')\n", id->toChars()); - //earg->print(); - //earg->type->print(); - e = new DotIdExp(loc, ethis, id); - - if (earg) - e = new CallExp(loc, e, earg); - else - e = new CallExp(loc, e); - - e = e->semantic(sc); - return e; -} - -/*************************************** - * Search for function funcid in aggregate ad. - */ - -Dsymbol *search_function(AggregateDeclaration *ad, Identifier *funcid) -{ - Dsymbol *s; - FuncDeclaration *fd; - TemplateDeclaration *td; - - s = ad->search(0, funcid, 0); - if (s) - { Dsymbol *s2; - - //printf("search_function: s = '%s'\n", s->kind()); - s2 = s->toAlias(); - //printf("search_function: s2 = '%s'\n", s2->kind()); - fd = s2->isFuncDeclaration(); - if (fd && fd->type->ty == Tfunction) - return fd; - - td = s2->isTemplateDeclaration(); - if (td) - return td; - } - return NULL; -} - - -/***************************************** - * Given array of arguments and an aggregate type, - * if any of the argument types are missing, attempt to infer - * them from the aggregate type. - */ - -void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Module* from) -{ - if (!arguments || !arguments->dim) - return; - - /* Return if no arguments need types. - */ - for (size_t u = 0; 1; u++) - { if (u == arguments->dim) - return; - Parameter *arg = (Parameter *)arguments->data[u]; - if (!arg->type) - break; - } - - AggregateDeclaration *ad; - - Parameter *arg = (Parameter *)arguments->data[0]; - Type *taggr = aggr->type; - if (!taggr) - return; - Type *tab = taggr->toBasetype(); - switch (tab->ty) - { - case Tarray: - case Tsarray: - case Ttuple: - if (arguments->dim == 2) - { - if (!arg->type) - arg->type = Type::tsize_t; // key type - arg = (Parameter *)arguments->data[1]; - } - if (!arg->type && tab->ty != Ttuple) - arg->type = tab->nextOf(); // value type - break; - - case Taarray: - { TypeAArray *taa = (TypeAArray *)tab; - - if (arguments->dim == 2) - { - if (!arg->type) - arg->type = taa->index; // key type - arg = (Parameter *)arguments->data[1]; - } - if (!arg->type) - arg->type = taa->next; // value type - break; - } - - case Tclass: - ad = ((TypeClass *)tab)->sym; - goto Laggr; - - case Tstruct: - ad = ((TypeStruct *)tab)->sym; - goto Laggr; - - Laggr: -#if 0 - if (arguments->dim == 1) - { - if (!arg->type) - { - /* Look for an opNext() overload - */ - Dsymbol *s = search_function(ad, Id::next); - fd = s ? s->isFuncDeclaration() : NULL; - if (!fd) - goto Lapply; - arg->type = fd->type->next; - } - break; - } -#endif - Lapply: - { /* Look for an - * int opApply(int delegate(ref Type [, ...]) dg); - * overload - */ - Dsymbol *s = search_function(ad, - (op == TOKforeach_reverse) ? Id::applyReverse - : Id::apply); - if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - inferApplyArgTypesX(from, fd, arguments); - } - break; - } - - case Tdelegate: - { - if (0 && aggr->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)aggr; - - FuncDeclaration *fd = de->func->isFuncDeclaration(); - if (fd) - inferApplyArgTypesX(from, fd, arguments); - } - else - { - inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments); - } - break; - } - - default: - break; // ignore error, caught later - } -} - -/******************************** - * Recursive helper function, - * analogous to func.overloadResolveX(). - */ - -int fp3(void *param, FuncDeclaration *f) -{ - Parameters *arguments = (Parameters *)param; - TypeFunction *tf = (TypeFunction *)f->type; - if (inferApplyArgTypesY(tf, arguments) == 1) - return 0; - if (arguments->dim == 0) - return 1; - return 0; -} - -static void inferApplyArgTypesX(Module* from, FuncDeclaration *fstart, Parameters *arguments) -{ - overloadApply(from, fstart, &fp3, arguments); -} - -#if 0 -static void inferApplyArgTypesX(FuncDeclaration *fstart, Parameters *arguments) -{ - Declaration *d; - Declaration *next; - - for (d = fstart; d; d = next) - { - FuncDeclaration *f; - FuncAliasDeclaration *fa; - AliasDeclaration *a; - - fa = d->isFuncAliasDeclaration(); - if (fa) - { - inferApplyArgTypesX(fa->funcalias, arguments); - next = fa->overnext; - } - else if ((f = d->isFuncDeclaration()) != NULL) - { - next = f->overnext; - - TypeFunction *tf = (TypeFunction *)f->type; - if (inferApplyArgTypesY(tf, arguments) == 1) - continue; - if (arguments->dim == 0) - return; - } - else if ((a = d->isAliasDeclaration()) != NULL) - { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - if (next == fstart) - break; - } - else - { d->error("is aliased to a function"); - break; - } - } -} -#endif - -/****************************** - * Infer arguments from type of function. - * Returns: - * 0 match for this function - * 1 no match for this function - */ - -static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments) -{ size_t nparams; - Parameter *p; - - if (Parameter::dim(tf->parameters) != 1) - goto Lnomatch; - p = Parameter::getNth(tf->parameters, 0); - if (p->type->ty != Tdelegate) - goto Lnomatch; - tf = (TypeFunction *)p->type->nextOf(); - assert(tf->ty == Tfunction); - - /* We now have tf, the type of the delegate. Match it against - * the arguments, filling in missing argument types. - */ - nparams = Parameter::dim(tf->parameters); - if (nparams == 0 || tf->varargs) - goto Lnomatch; // not enough parameters - if (arguments->dim != nparams) - goto Lnomatch; // not enough parameters - - for (size_t u = 0; u < nparams; u++) - { - Parameter *arg = (Parameter *)arguments->data[u]; - Parameter *param = Parameter::getNth(tf->parameters, u); - if (arg->type) - { if (!arg->type->equals(param->type)) - { - /* Cannot resolve argument types. Indicate an - * error by setting the number of arguments to 0. - */ - arguments->dim = 0; - goto Lmatch; - } - continue; - } - arg->type = param->type; - } - Lmatch: - return 0; - - Lnomatch: - return 1; -} - -/************************************** - */ - -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, NULL, arguments); - if (!fd) - return; - m->anyf = fd; - if (m->last >= MATCHexact) - { - m->nextf = fd; - m->count++; - } - else - { - m->last = MATCHexact; - m->lastf = fd; - m->count = 1; - } -} - diff --git a/dmd/optimize.c b/dmd/optimize.c deleted file mode 100644 index 5bfc0d0c..00000000 --- a/dmd/optimize.c +++ /dev/null @@ -1,896 +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 expression is a variable with a const initializer, - * return that initializer. - */ - -Expression *fromConstInitializer(int result, Expression *e1) -{ - //printf("fromConstInitializer(%s)\n", e1->toChars()); - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && !v->originalType && v->scope) // semantic() not yet run - v->semantic (v->scope); - if (!v || !v->type) - return e1; - Type * tb = v->type->toBasetype(); - if (v->isConst() && v->init - && (result & WANTinterpret || (tb->isscalar() || - ((result & WANTexpand) && (tb->ty != Tsarray && tb->ty != Tstruct)))) - ) - { Expression *ei = v->init->toExpression(); - if (ei && ei->type) - e1 = ei; - } - } - return e1; -} - - -Expression *Expression::optimize(int result) -{ - //printf("Expression::optimize(result = x%x) %s\n", result, toChars()); - return this; -} - -Expression *VarExp::optimize(int result) -{ - return fromConstInitializer(result, this); - return this; -} - -Expression *TupleExp::optimize(int result) -{ - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - exps->data[i] = (void *)e; - } - return this; -} - -Expression *ArrayLiteralExp::optimize(int result) -{ - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - elements->data[i] = (void *)e; - } - } - return this; -} - -Expression *AssocArrayLiteralExp::optimize(int result) -{ - assert(keys->dim == values->dim); - for (size_t i = 0; i < keys->dim; i++) - { Expression *e = (Expression *)keys->data[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - keys->data[i] = (void *)e; - - e = (Expression *)values->data[i]; - e = e->optimize(WANTvalue | (result & WANTinterpret)); - values->data[i] = (void *)e; - } - return this; -} - -Expression *StructLiteralExp::optimize(int result) -{ - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - if (!e) - continue; - e = e->optimize(WANTvalue | (result & WANTinterpret)); - (*elements)[i] = e; - } - } - return this; -} - -Expression *TypeExp::optimize(int result) -{ - return this; -} - -Expression *UnaExp::optimize(int result) -{ - e1 = e1->optimize(result); - return this; -} - -Expression *NegExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Neg(type, e1); - } - else - e = this; - return e; -} - -Expression *ComExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Com(type, e1); - } - else - e = this; - return e; -} - -Expression *NotExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Not(type, e1); - } - else - e = this; - return e; -} - -Expression *BoolExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Bool(type, e1); - } - else - e = this; - return e; -} - -Expression *AddrExp::optimize(int result) -{ Expression *e; - - //printf("AddrExp::optimize(result = %d) %s\n", result, toChars()); - // never try to interpret: it could change the semantics by turning - // const p = &s; into an something like const p = &(Struct()); - e1 = e1->optimize(result & ~WANTinterpret); - // Convert &*ex to ex - if (e1->op == TOKstar) - { Expression *ex; - - ex = ((PtrExp *)e1)->e1; - if (type->equals(ex->type)) - e = ex; - else - { - e = ex->copy(); - e->type = type; - } - return e; - } -#if !IN_LLVM - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - if (!ve->var->isOut() && !ve->var->isRef() && - !ve->var->isImportedSymbol()) - { - e = new SymOffExp(loc, ve->var, 0); - e->type = type; - return e; - } - } - if (e1->op == TOKindex) - { // Convert &array[n] to &array+n - IndexExp *ae = (IndexExp *)e1; - - if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) - { - dinteger_t index = ae->e2->toInteger(); - VarExp *ve = (VarExp *)ae->e1; - if (ve->type->ty == Tsarray && ve->type->next->ty != Tbit - && !ve->var->isImportedSymbol()) - { - TypeSArray *ts = (TypeSArray *)ve->type; - 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->next->size()); - e->type = type; - return e; - } - } - } -#endif - return this; -} - -Expression *PtrExp::optimize(int result) -{ - //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars()); - e1 = e1->optimize(result); - // Convert *&ex to ex - if (e1->op == TOKaddress) - { Expression *e; - Expression *ex; - - ex = ((AddrExp *)e1)->e1; - if (type->equals(ex->type)) - e = ex; - else - { - e = ex->copy(); - e->type = type; - } - return e; - } - // Constant fold *(&structliteral + offset) - if (e1->op == TOKadd) - { - Expression *e; - e = Ptr(type, e1); - if (e != EXP_CANT_INTERPRET) - return e; - } - - return this; -} - -Expression *DotVarExp::optimize(int result) -{ - //printf("DotVarExp::optimize(result = x%x) %s\n", result, toChars()); - e1 = e1->optimize(result); - -#if DMDV2 - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - Expression *e = expandVar(result, v); - if (e && e->op == TOKstructliteral) - { StructLiteralExp *sle = (StructLiteralExp *)e; - VarDeclaration *vf = var->isVarDeclaration(); - if (vf) - { - e = sle->getField(type, vf->offset); - if (e && e != EXP_CANT_INTERPRET) - return e; - } - } - } - else -#endif - if (e1->op == TOKstructliteral) - { StructLiteralExp *sle = (StructLiteralExp *)e1; - VarDeclaration *vf = var->isVarDeclaration(); - if (vf) - { - Expression *e = sle->getField(type, vf->offset); - if (e && e != EXP_CANT_INTERPRET) - return e; - } - } - - return this; -} - -Expression *NewExp::optimize(int result) -{ - if (thisexp) - thisexp = thisexp->optimize(WANTvalue); - - // Optimize parameters - if (newargs) - { - for (size_t i = 0; i < newargs->dim; i++) - { Expression *e = 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; - } - } - 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 (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()); - } - return e; -} - - -Expression *CastExp::optimize(int result) -{ - //printf("CastExp::optimize(result = %d) %s\n", result, toChars()); - //printf("from %s to %s\n", type->toChars(), to->toChars()); - //printf("from %s\n", type->toChars()); - //printf("e1->type %s\n", e1->type->toChars()); - //printf("type = %p\n", type); - assert(type); - enum TOK op1 = e1->op; - - e1 = e1->optimize(result); - if (result & WANTinterpret) - e1 = fromConstInitializer(result, e1); - - if ((e1->op == TOKstring || e1->op == TOKarrayliteral) && - (type->ty == Tpointer || type->ty == Tarray) && - type->next->equals(e1->type->next) - ) - { - // make a copy before adjusting type to avoid - // messing up the type of an existing initializer - e1 = e1->syntaxCopy(); - e1->type = type; - return e1; - } - /* The first test here is to prevent infinite loops - */ - if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral) - return e1->castTo(NULL, to); - if (e1->op == TOKnull && - (type->ty == Tpointer || type->ty == Tclass)) - { - e1->type = type; - return e1; - } - - if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass) - { - // See if we can remove an unnecessary cast - ClassDeclaration *cdfrom; - ClassDeclaration *cdto; - int offset; - - cdfrom = e1->type->isClassHandle(); - cdto = type->isClassHandle(); - if (cdto->isBaseOf(cdfrom, &offset) && offset == 0) - { - e1->type = type; - return e1; - } - } - - Expression *e; - - if (e1->isConst()) - { - if (e1->op == TOKsymoff) - { - if (type->size() == e1->type->size() && - type->toBasetype()->ty != Tsarray) - { - e1->type = type; - return e1; - } - return this; - } - if (to->toBasetype()->ty == Tvoid) - e = this; - else - e = Cast(type, to, e1); - } - else - e = this; - return e; -} - -Expression *BinExp::optimize(int result) -{ - //printf("BinExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (op == TOKshlass || op == TOKshrass || op == TOKushrass) - { - if (e2->isConst() == 1) - { - 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 *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)); - if (result & WANTinterpret) - e1 = fromConstInitializer(result, 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)); - 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; - } - if (result & WANTinterpret) - 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(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Cmp(op, type, this->e1, this->e2); - } - else - e = this; - return e; -} - -Expression *CatExp::optimize(int result) -{ Expression *e; - - //printf("CatExp::optimize(%d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - e = Cat(type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - - -Expression *CondExp::optimize(int result) -{ Expression *e; - - econd = econd->optimize(WANTflags | (result & WANTinterpret)); - if (econd->isBool(TRUE)) - e = e1->optimize(result); - else if (econd->isBool(FALSE)) - e = e2->optimize(result); - else - { e1 = e1->optimize(result); - e2 = e2->optimize(result); - e = this; - } - return e; -} - - diff --git a/dmd/parse.c b/dmd/parse.c deleted file mode 100644 index a16d0819..00000000 --- a/dmd/parse.c +++ /dev/null @@ -1,5689 +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 is the D parser - -#include -#include -#include // strlen(),memcpy() - -#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" -#if DMDV2 -#include "aliasthis.h" -#endif - -// How multiple declarations are parsed. -// If 1, treat as C. -// If 0, treat: -// int *p, i; -// as: -// int* p; -// int* i; -#define CDECLSYNTAX 0 - -// Support C cast syntax: -// (type)(expression) -#define CCASTSYNTAX 1 - -// Support postfix C array declarations, such as -// int a[3][4]; -#define CARRAYDECL 1 - -// Support left-to-right array declarations -#define LTORARRAYDECL 1 - - -Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment) - : Lexer(module, base, 0, length, doDocComment, 0) -{ - //printf("Parser::Parser()\n"); - md = NULL; - linkage = LINKd; - endloc = 0; - inBrackets = 0; - //nextToken(); // start up the scanner -} - -Dsymbols *Parser::parseModule() -{ - Dsymbols *decldefs; - - // ModuleDeclation leads off - if (token.value == TOKmodule) - { - unsigned char *comment = token.blockComment; - - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following module"); - goto Lerr; - } - else - { - 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); - - check(TOKsemicolon, "module declaration"); - addComment(mod, comment); - } - } - - decldefs = parseDeclDefs(0); - if (token.value != TOKeof) - { error(loc, "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; - Condition *condition; - unsigned char *comment; - - //printf("Parser::parseDeclDefs()\n"); - decldefs = new Dsymbols(); - do - { - comment = token.blockComment; - switch (token.value) - { - case TOKenum: - s = parseEnum(); - break; - - case TOKstruct: - case TOKunion: - case TOKclass: - case TOKinterface: - s = parseAggregate(); - break; - - case TOKimport: - s = parseImport(decldefs, 0); - break; - - case TOKtemplate: - s = (Dsymbol *)parseTemplateDeclaration(); - break; - - case TOKmixin: - { Loc loc = this->loc; - if (peek(&token)->value == TOKlparen) - { // mixin(string) - nextToken(); - check(TOKlparen, "mixin"); - Expression *e = parseAssignExp(); - check(TOKrparen); - check(TOKsemicolon); - s = new CompileDeclaration(loc, e); - break; - } - s = parseMixin(); - break; - } - - case BASIC_TYPES: - case TOKalias: - case TOKtypedef: - case TOKidentifier: - case TOKtypeof: - case TOKdot: - Ldeclaration: - a = parseDeclarations(); - decldefs->append(a); - continue; - - case TOKthis: - s = parseCtor(); - break; - - case TOKtilde: - s = parseDtor(); - break; - - case TOKinvariant: -#if 1 - s = parseInvariant(); -#else - if (peek(&token)->value == TOKlcurly) - s = parseInvariant(); - else - { - stc = STCimmutable; - goto Lstc; - } -#endif - break; - - case TOKunittest: - s = parseUnitTest(); - break; - - case TOKnew: - s = parseNew(); - break; - - case TOKdelete: - s = parseDelete(); - break; - - case TOKeof: - case TOKrcurly: - return decldefs; - - case TOKstatic: - nextToken(); - if (token.value == TOKthis) - s = parseStaticCtor(); - else if (token.value == TOKtilde) - s = parseStaticDtor(); - else if (token.value == TOKassert) - s = parseStaticAssert(); - else if (token.value == TOKif) - { condition = parseStaticIfCondition(); - a = parseBlock(); - aelse = NULL; - if (token.value == TOKelse) - { nextToken(); - aelse = parseBlock(); - } - s = new StaticIfDeclaration(condition, a, aelse); - break; - } - else if (token.value == TOKimport) - { - s = parseImport(decldefs, 1); - } - else - { stc = STCstatic; - goto Lstc2; - } - break; - - case TOKconst: stc = STCconst; goto Lstc; - case TOKfinal: stc = STCfinal; goto Lstc; - case TOKauto: stc = STCauto; goto Lstc; - case TOKscope: stc = STCscope; goto Lstc; - case TOKoverride: stc = STCoverride; goto Lstc; - case TOKabstract: stc = STCabstract; goto Lstc; - case TOKsynchronized: stc = STCsynchronized; goto Lstc; - case TOKdeprecated: stc = STCdeprecated; goto Lstc; -#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: - nextToken(); - Lstc2: - switch (token.value) - { - case TOKconst: stc |= STCconst; goto Lstc; - case TOKfinal: stc |= STCfinal; goto Lstc; - case TOKauto: stc |= STCauto; goto Lstc; - case TOKscope: stc |= STCscope; goto Lstc; - case TOKoverride: stc |= STCoverride; goto Lstc; - case TOKabstract: stc |= STCabstract; goto Lstc; - case TOKsynchronized: stc |= STCsynchronized; goto Lstc; - case TOKdeprecated: stc |= STCdeprecated; goto Lstc; - //case TOKinvariant: stc |= STCimmutable; goto Lstc; - default: - break; - } - - /* Look for auto initializers: - * storage_class identifier = initializer; - */ - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - while (1) - { - Identifier *ident = token.ident; - nextToken(); - nextToken(); - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = stc; - s = v; - if (token.value == TOKsemicolon) - { - nextToken(); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - decldefs->push(s); - addComment(s, comment); - continue; - } - else - error("Identifier expected following comma"); - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - break; - } - } - else - { a = parseBlock(); - s = new StorageClassDeclaration(stc, a); - } - break; - - case TOKextern: - if (peek(&token)->value != TOKlparen) - { stc = STCextern; - goto Lstc; - } - { - enum LINK linksave = linkage; - linkage = parseLinkage(); - a = parseBlock(); - s = new LinkDeclaration(linkage, a); - linkage = linksave; - break; - } - case TOKprivate: prot = PROTprivate; goto Lprot; - case TOKpackage: prot = PROTpackage; goto Lprot; - case TOKprotected: prot = PROTprotected; goto Lprot; - case TOKpublic: prot = PROTpublic; goto Lprot; - case TOKexport: prot = PROTexport; goto Lprot; - - Lprot: - nextToken(); - 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) - { - if (token.uns64value & (token.uns64value - 1)) - error("align(%s) must be a power of 2", token.toChars()); - 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(); - check(TOKsemicolon, "debug declaration"); - 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(); - check(TOKsemicolon, "version declaration"); - break; - } - condition = parseVersionCondition(); - goto Lcondition; - - Lcondition: - a = parseBlock(); - aelse = NULL; - if (token.value == TOKelse) - { nextToken(); - aelse = parseBlock(); - } - s = new ConditionalDeclaration(condition, a, aelse); - break; - - case TOKsemicolon: // empty declaration - nextToken(); - continue; - - default: - error("Declaration expected, not '%s'",token.toChars()); - Lerror: - while (token.value != TOKsemicolon && token.value != TOKeof) - nextToken(); - nextToken(); - s = NULL; - continue; - } - if (s) - { decldefs->push(s); - addComment(s, comment); - } - } while (!once); - return decldefs; -} - -/********************************************* - * Give error on conflicting storage classes. - */ - -#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)); -} -#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 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: - nextToken(); - a = parseDeclDefs(0); - if (token.value != TOKrcurly) - { /* { */ - error("matching '}' expected, not %s", token.toChars()); - } - else - nextToken(); - break; - - case TOKcolon: - nextToken(); -#if 0 - a = NULL; -#else - a = parseDeclDefs(0); // grab declarations up to closing curly bracket -#endif - break; - - default: - a = parseDeclDefs(1); - break; - } - return a; -} - -/********************************** - * Parse a static assertion. - */ - -StaticAssert *Parser::parseStaticAssert() -{ - Loc loc = this->loc; - Expression *exp; - Expression *msg = NULL; - - //printf("parseStaticAssert()\n"); - nextToken(); - check(TOKlparen); - exp = parseAssignExp(); - if (token.value == TOKcomma) - { nextToken(); - msg = parseAssignExp(); - } - check(TOKrparen); - check(TOKsemicolon, "static assert"); - return new StaticAssert(loc, exp, msg); -} - -/*********************************** - * Parse typeof(expression). - * Current token is on the 'typeof'. - */ - -#if DMDV2 -TypeQualified *Parser::parseTypeof() -{ TypeQualified *t; - Loc loc = this->loc; - - nextToken(); - check(TOKlparen); - if (token.value == TOKreturn) // typeof(return) - { - nextToken(); - t = new TypeReturn(loc); - } - else - { Expression *exp = parseExpression(); // typeof(expression) - t = new TypeTypeof(loc, exp); - } - check(TOKrparen); - return t; -} -#endif - -/*********************************** - * Parse extern (linkage) - * The parser is on the 'extern' token. - */ - -enum LINK Parser::parseLinkage() -{ - enum LINK link = LINKdefault; - nextToken(); - assert(token.value == TOKlparen); - nextToken(); - if (token.value == TOKidentifier) - { Identifier *id = token.ident; - - nextToken(); - if (id == Id::Windows) - link = LINKwindows; - else if (id == Id::Pascal) - link = LINKpascal; - else if (id == Id::D) - link = LINKd; - else if (id == Id::C) - { - link = LINKc; - if (token.value == TOKplusplus) - { link = LINKcpp; - nextToken(); - } - } - else if (id == Id::System) - { -#if IN_LLVM - if (global.params.targetTriple.isOSWindows()) - link = LINKwindows; - else - link = LINKc; -#else -#if _WIN32 - link = LINKwindows; -#else - link = LINKc; -#endif -#endif - } - else - { - error("valid linkage identifiers are D, C, C++, Pascal, Windows, System"); - link = LINKd; - } - } - else - { - link = LINKd; // default - } - check(TOKrparen); - return link; -} - -/************************************** - * Parse a debug conditional - */ - -Condition *Parser::parseDebugCondition() -{ - Condition *c; - - if (token.value == TOKlparen) - { - nextToken(); - unsigned level = 1; - Identifier *id = NULL; - - if (token.value == TOKidentifier) - id = token.ident; - else if (token.value == TOKint32v || 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 } - * Current token is 'this'. - */ - -Dsymbol *Parser::parseCtor() -{ - Loc loc = this->loc; - - nextToken(); - int varargs; - Parameters *parameters = parseParameters(&varargs); - CtorDeclaration *f = new CtorDeclaration(loc, 0, parameters, varargs); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a destructor definition: - * ~this() { body } - * Current token is '~'. - */ - -DtorDeclaration *Parser::parseDtor() -{ - DtorDeclaration *f; - Loc loc = this->loc; - - nextToken(); - check(TOKthis, "~"); - check(TOKlparen, "~this"); - 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, "static this"); - 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'. - */ -#if DMDV2 -SharedStaticCtorDeclaration *Parser::parseSharedStaticCtor() -{ - Loc loc = this->loc; - - nextToken(); - nextToken(); - nextToken(); - check(TOKlparen, "shared static this"); - check(TOKrparen); - - SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, 0); - parseContracts(f); - return f; -} -#endif - -/***************************************** - * Parse a static destructor definition: - * static ~this() { body } - * Current token is '~'. - */ - -StaticDtorDeclaration *Parser::parseStaticDtor() -{ - Loc loc = this->loc; - - nextToken(); - check(TOKthis, "~"); - check(TOKlparen, "~this"); - 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'. - */ -#if DMDV2 -SharedStaticDtorDeclaration *Parser::parseSharedStaticDtor() -{ - Loc loc = this->loc; - - nextToken(); - nextToken(); - nextToken(); - check(TOKthis, "shared static ~"); - check(TOKlparen, "shared static ~this"); - check(TOKrparen); - - SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, 0); - parseContracts(f); - return f; -} -#endif - -/***************************************** - * Parse an invariant definition: - * invariant() { body } - * Current token is 'invariant'. - */ - -InvariantDeclaration *Parser::parseInvariant() -{ - InvariantDeclaration *f; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) // optional () - { - nextToken(); - check(TOKrparen); - } - - f = new InvariantDeclaration(loc, 0); - f->fbody = parseStatement(PScurly); - return f; -} - -/***************************************** - * Parse a unittest definition: - * unittest { body } - * Current token is 'unittest'. - */ - -UnitTestDeclaration *Parser::parseUnitTest() -{ - UnitTestDeclaration *f; - Statement *body; - Loc loc = this->loc; - - nextToken(); - - body = parseStatement(PScurly); - - f = new UnitTestDeclaration(loc, this->loc); - f->fbody = body; - return f; -} - -/***************************************** - * Parse a new definition: - * new(arguments) { body } - * Current token is 'new'. - */ - -NewDeclaration *Parser::parseNew() -{ - NewDeclaration *f; - Parameters *arguments; - int varargs; - Loc loc = this->loc; - - nextToken(); - arguments = parseParameters(&varargs); - f = new NewDeclaration(loc, 0, arguments, varargs); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a delete definition: - * delete(arguments) { body } - * Current token is 'delete'. - */ - -DeleteDeclaration *Parser::parseDelete() -{ - DeleteDeclaration *f; - Parameters *arguments; - int varargs; - Loc loc = this->loc; - - nextToken(); - arguments = parseParameters(&varargs); - if (varargs) - error("... not allowed in delete function parameter list"); - f = new DeleteDeclaration(loc, 0, arguments); - parseContracts(f); - return f; -} - -/********************************************** - * Parse parameter list. - */ - -Parameters *Parser::parseParameters(int *pvarargs) -{ - Parameters *arguments = new Parameters(); - int varargs = 0; - int hasdefault = 0; - - check(TOKlparen, "start of parameter list"); - while (1) - { Type *tb; - Identifier *ai = NULL; - Type *at; - Parameter *a; - StorageClass storageClass = 0; - Expression *ae; - - storageClass = STCin; // parameter is "in" by default - switch (token.value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - varargs = 1; - nextToken(); - break; - - case TOKin: - storageClass = STCin; - nextToken(); - goto L1; - - case TOKout: - storageClass = STCout; - nextToken(); - goto L1; - - case TOKinout: - case TOKref: - storageClass = STCref; - nextToken(); - goto L1; - - case TOKlazy: - storageClass = STClazy; - nextToken(); - goto L1; - - default: - L1: - tb = parseBasicType(); - at = parseDeclarator(tb, &ai); - ae = NULL; - if (token.value == TOKassign) // = defaultArg - { nextToken(); - ae = parseAssignExp(); - hasdefault = 1; - } - else - { if (hasdefault) - error("default argument expected for %s", - ai ? ai->toChars() : at->toChars()); - } - if (token.value == TOKdotdotdot) - { /* This is: - * at ai ... - */ - - if (storageClass & (STCout | STCref)) - error("variadic argument cannot be out or ref"); - varargs = 2; - a = new Parameter(storageClass, at, ai, ae); - arguments->push(a); - nextToken(); - break; - } - a = new Parameter(storageClass, at, ai, ae); - arguments->push(a); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - break; - } - check(TOKrparen); - *pvarargs = varargs; - return arguments; -} - - -/************************************* - */ - -EnumDeclaration *Parser::parseEnum() -{ EnumDeclaration *e; - Identifier *id; - Type *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(); - } - 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) - { - if (token.value == TOKidentifier) - { - Expression *value; - Identifier *ident; - - loc = this->loc; - ident = token.ident; - value = NULL; - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - value = parseAssignExp(); - } - EnumMember *em = new EnumMember(loc, ident, value); - e->members->push(em); - - if (token.value == TOKrcurly) - ; - else - { addComment(em, comment); - comment = NULL; - check(TOKcomma, "enum member"); - } - addComment(em, comment); - comment = token.blockComment; - } - else - { error("enum member expected"); - nextToken(); - } - } - nextToken(); - } - else - error("enum declaration is invalid"); - - //printf("-parseEnum() %s\n", e->toChars()); - return e; -} - -/******************************** - * 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(); - } - } - - 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); - 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, "if"); - e = parseExpression(); - check(TOKrparen); - } - return e; -} -#endif - -/************************************** - * Parse a TemplateDeclaration. - */ - -TemplateDeclaration *Parser::parseTemplateDeclaration() -{ - TemplateDeclaration *tempdecl; - Identifier *id; - TemplateParameters *tpl; - Dsymbols *decldefs; - Loc loc = this->loc; - - nextToken(); - if (token.value != TOKidentifier) - { error("TemplateIdentifier expected following template"); - goto Lerr; - } - id = token.ident; - nextToken(); - tpl = parseTemplateParameterList(); - if (!tpl) - goto Lerr; - - if (token.value != TOKlcurly) - { error("members of template declaration expected"); - goto Lerr; - } - else - { - nextToken(); - decldefs = parseDeclDefs(0); - if (token.value != TOKrcurly) - { error("template member expected"); - goto Lerr; - } - nextToken(); - } - - tempdecl = new TemplateDeclaration(loc, id, tpl, NULL, decldefs); - return tempdecl; - -Lerr: - return NULL; -} - -/****************************************** - * Parse template parameter list. - * Input: - * flag 0: parsing "( list )" - * 1: parsing non-empty "list )" - */ - -TemplateParameters *Parser::parseTemplateParameterList(int flag) -{ - TemplateParameters *tpl = new TemplateParameters(); - - if (token.value != TOKlparen) - { error("parenthesized TemplateParameterList expected following TemplateIdentifier"); - goto Lerr; - } - nextToken(); - - // Get array of TemplateParameters - if (token.value != TOKrparen) - { int isvariadic = 0; - - while (1) - { TemplateParameter *tp; - Identifier *tp_ident = NULL; - Type *tp_spectype = NULL; - Type *tp_valtype = NULL; - Type *tp_defaulttype = NULL; - Expression *tp_specvalue = NULL; - Expression *tp_defaultvalue = NULL; - Token *t; - - // Get TemplateParameter - - // First, look ahead to see if it is a TypeParameter or a ValueParameter - t = peek(&token); - if (token.value == TOKalias) - { // AliasParameter - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected for template parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseBasicType(); - tp_spectype = parseDeclarator(tp_spectype, NULL); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseBasicType(); - tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); - } - tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } - else if (t->value == TOKcolon || t->value == TOKassign || - t->value == TOKcomma || t->value == TOKrparen) - { // TypeParameter - if (token.value != TOKidentifier) - { error("identifier expected for template type parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseBasicType(); - tp_spectype = parseDeclarator(tp_spectype, NULL); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseBasicType(); - tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); - } - tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } - else if (token.value == TOKidentifier && t->value == TOKdotdotdot) - { // ident... - if (isvariadic) - error("variadic template parameter must be last"); - isvariadic = 1; - tp_ident = token.ident; - nextToken(); - nextToken(); - tp = new TemplateTupleParameter(loc, tp_ident); - } -#if DMDV2 - else if (token.value == TOKthis) - { // ThisParameter - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected for template this parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseType(); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseType(); - } - tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } -#endif - else - { // ValueParameter - tp_valtype = parseBasicType(); - tp_valtype = parseDeclarator(tp_valtype, &tp_ident); - if (!tp_ident) - { - error("identifier expected for template value parameter"); - tp_ident = new Identifier("error", TOKidentifier); - } - if (token.value == TOKcolon) // : CondExpression - { - nextToken(); - tp_specvalue = parseCondExp(); - } - if (token.value == TOKassign) // = CondExpression - { - nextToken(); - tp_defaultvalue = parseCondExp(); - } - tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); - } - tpl->push(tp); - if (token.value != TOKcomma) - break; - nextToken(); - } - } - check(TOKrparen); -Lerr: - return tpl; -} - -/****************************************** - * Parse template mixin. - * mixin Foo; - * mixin Foo!(args); - * mixin a.b.c!(args).Foo!(args); - * mixin Foo!(args) identifier; - * mixin typeof(expr).identifier!(args); - */ - -Dsymbol *Parser::parseMixin() -{ - TemplateMixin *tm; - Identifier *id; - Type *tqual; - Objects *tiargs; - Identifiers *idents; - - //printf("parseMixin()\n"); - nextToken(); - tqual = NULL; - if (token.value == TOKdot) - { - id = Id::empty; - } - else - { - if (token.value == TOKtypeof) - { Expression *exp; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - tqual = new TypeTypeof(loc, exp); - check(TOKdot, "typeof (expression)"); - } - 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(); - tiargs = parseTemplateArgumentList(); - } - - if (token.value != TOKdot) - break; - - if (tiargs) - { TemplateInstance *tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = tiargs; - id = (Identifier *)tempinst; - tiargs = NULL; - } - idents->push(id); - - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following '.' instead of '%s'", token.toChars()); - break; - } - id = token.ident; - nextToken(); - } - idents->push(id); - - if (token.value == TOKidentifier) - { - id = token.ident; - nextToken(); - } - else - id = NULL; - - tm = new TemplateMixin(loc, id, tqual, idents, tiargs); - check(TOKsemicolon, "template mixin"); - return tm; -} - -/****************************************** - * Parse template argument list. - * Input: - * current token is opening '(' - * Output: - * current token is one after closing ')' - */ - -Objects *Parser::parseTemplateArgumentList() -{ - //printf("Parser::parseTemplateArgumentList()\n"); - Objects *tiargs = new Objects(); - if (token.value != TOKlparen) - { error("!(TemplateArgumentList) expected following TemplateIdentifier"); - return tiargs; - } - nextToken(); - - // Get TemplateArgumentList - if (token.value != TOKrparen) - { - while (1) - { - // See if it is an Expression or a Type - if (isDeclaration(&token, 0, TOKreserved, NULL)) - { // Type - // Get TemplateArgument - Type *ta = parseBasicType(); - ta = parseDeclarator(ta, NULL); - tiargs->push(ta); - } - else - { // Template argument is an expression - Expression *ea = parseAssignExp(); - tiargs->push(ea); - } - if (token.value != TOKcomma) - break; - nextToken(); - } - } - check(TOKrparen, "template argument list"); - return tiargs; -} - -Import *Parser::parseImport(Array *decldefs, int isstatic) -{ Import *s; - Identifier *id; - Identifier *aliasid = NULL; - 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 - { - check(TOKsemicolon, "import declaration"); - } - - return NULL; -} - -#if DMDV2 -Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl) -{ Type *t; - - /* Take care of the storage class prefixes that - * serve as type attributes: - * const shared, shared const, const, invariant, shared - */ - if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() != TOKlparen || - token.value == TOKshared && peekNext() == TOKconst && peekNext2() != TOKlparen) - { - nextToken(); - nextToken(); - /* shared const type - */ - t = parseType(pident, tpl); - t = t->makeSharedConst(); - return t; - } - else if (token.value == TOKwild && peekNext() == TOKshared && peekNext2() != TOKlparen || - token.value == TOKshared && peekNext() == TOKwild && peekNext2() != TOKlparen) - { - nextToken(); - nextToken(); - /* shared wild type - */ - t = parseType(pident, tpl); - t = t->makeSharedWild(); - return t; - } - else if (token.value == TOKconst && peekNext() != TOKlparen) - { - nextToken(); - /* const type - */ - t = parseType(pident, tpl); - t = t->makeConst(); - return t; - } - else if ((token.value == TOKinvariant || token.value == TOKimmutable) && - peekNext() != TOKlparen) - { - nextToken(); - /* invariant type - */ - t = parseType(pident, tpl); - t = t->makeInvariant(); - return t; - } - else if (token.value == TOKshared && peekNext() != TOKlparen) - { - nextToken(); - /* shared type - */ - t = parseType(pident, tpl); - t = t->makeShared(); - return t; - } - else if (token.value == TOKwild && peekNext() != TOKlparen) - { - nextToken(); - /* wild type - */ - t = parseType(pident, tpl); - t = t->makeWild(); - return t; - } - else - t = parseBasicType(); - t = parseDeclarator(t, pident, tpl); - return t; -} -#endif - -Type *Parser::parseBasicType() -{ Type *t; - Identifier *id; - TypeQualified *tid; - - //printf("parseBasicType()\n"); - switch (token.value) - { - case BASIC_TYPES_X(t): - nextToken(); - break; - - case TOKidentifier: - id = token.ident; - nextToken(); - if (token.value == TOKnot) - { // ident!(template_arguments) - TemplateInstance *tempinst = new TemplateInstance(loc, id); - nextToken(); - tempinst->tiargs = parseTemplateArgumentList(); - tid = new TypeInstance(loc, tempinst); - goto Lident2; - } - Lident: - tid = new TypeIdentifier(loc, id); - Lident2: - while (token.value == TOKdot) - { nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following '.' instead of '%s'", token.toChars()); - break; - } - id = token.ident; - nextToken(); - if (token.value == TOKnot) - { - nextToken(); - TemplateInstance *tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = parseTemplateArgumentList(); - tid->addIdent((Identifier *)tempinst); - } - else - tid->addIdent(id); - } - t = tid; - break; - - case TOKdot: - // Leading . as in .foo - id = Id::empty; - goto Lident; - - case TOKtypeof: - { - nextToken(); - check(TOKlparen); - Expression *exp = parseExpression(); - check(TOKrparen); - tid = new TypeTypeof(loc, exp); - goto Lident2; - } - - default: - error("basic type expected, not %s", token.toChars()); - t = Type::tint32; - break; - } - return t; -} - -/****************************************** - * Parse things that follow the initial type t. - * t * - * t [] - * t [type] - * t [expression] - * t [expression .. expression] - * t function - * t delegate - */ - -Type *Parser::parseBasicType2(Type *t) -{ - Type *ts; - Type *ta; - - //printf("parseBasicType2()\n"); - while (1) - { - switch (token.value) - { - case TOKmul: - t = new TypePointer(t); - nextToken(); - continue; - - case TOKlbracket: -#if LTORARRAYDECL - // Handle []. Make sure things like - // int[3][1] a; - // is (array[1] of array[3] of int) - nextToken(); - if (token.value == TOKrbracket) - { - t = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - - //printf("it's an associative array\n"); - Type *index = parseBasicType(); - index = parseDeclarator(index, NULL); // [ type ] - t = new TypeAArray(t, index); - check(TOKrbracket); - } - else - { - //printf("it's [expression]\n"); - inBrackets++; - Expression *e = parseExpression(); // [ expression ] - if (token.value == TOKslice) - { - nextToken(); - Expression *e2 = parseExpression(); // [ exp .. exp ] - t = new TypeSlice(t, e, e2); - } - else - t = new TypeSArray(t,e); - inBrackets--; - check(TOKrbracket); - } - continue; -#else - // Handle []. Make sure things like - // int[3][1] a; - // is (array[3] of array[1] of int) - ts = t; - while (token.value == TOKlbracket) - { - nextToken(); - if (token.value == TOKrbracket) - { - ta = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - Type *index; - - //printf("it's an associative array\n"); - index = parseBasicType(); - index = parseDeclarator(index, NULL); // [ type ] - check(TOKrbracket); - ta = new TypeAArray(t, index); - } - else - { - //printf("it's [expression]\n"); - Expression *e = parseExpression(); // [ expression ] - ta = new TypeSArray(t,e); - check(TOKrbracket); - } - Type **pt; - for (pt = &ts; *pt != t; pt = &(*pt)->next) - ; - *pt = ta; - } - t = ts; - continue; -#endif - - case TOKdelegate: - case TOKfunction: - { // Handle delegate declaration: - // t delegate(parameter list) - // t function(parameter list) - Parameters *arguments; - int varargs; - enum TOK save = token.value; - - nextToken(); - arguments = parseParameters(&varargs); - t = new TypeFunction(arguments, t, varargs, linkage); - if (save == TOKdelegate) - t = new TypeDelegate(t); - else - t = new TypePointer(t); // pointer to function - continue; - } - - default: - ts = t; - break; - } - break; - } - return ts; -} - -Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl) -{ Type *ts; - Type *ta; - - //printf("parseDeclarator(tpl = %p)\n", tpl); - t = parseBasicType2(t); - - switch (token.value) - { - - case TOKidentifier: - if (pident) - *pident = token.ident; - else - error("unexpected identifer '%s' in declarator", token.ident->toChars()); - ts = t; - nextToken(); - break; - - case TOKlparen: - /* Parse things with parentheses around the identifier, like: - * int (*ident[3])[] - * although the D style would be: - * int[]*[3] ident - */ - nextToken(); - ts = parseDeclarator(t, pident); - check(TOKrparen); - break; - - default: - ts = t; - break; - } - - // 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. - nextToken(); - if (token.value == TOKrbracket) - { // It's a dynamic array - ta = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - - //printf("it's an associative array\n"); - Type *index = parseBasicType(); - index = parseDeclarator(index, NULL); // [ type ] - check(TOKrbracket); - ta = new TypeAArray(t, index); - } - else - { - //printf("it's [expression]\n"); - Expression *e = parseExpression(); // [ expression ] - ta = new TypeSArray(t, e); - check(TOKrbracket); - } - - /* Insert ta into - * ts -> ... -> t - * so that - * ts -> ... -> ta -> t - */ - Type **pt; - for (pt = &ts; *pt != t; pt = &(*pt)->next) - ; - *pt = ta; - continue; - } -#endif - case TOKlparen: - { - 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); - Type *ta = new TypeFunction(arguments, t, varargs, linkage); - Type **pt; - for (pt = &ts; *pt != t; pt = &(*pt)->next) - ; - *pt = ta; - break; - } - } - break; - } - - return ts; -} - -/********************************** - * Parse Declarations. - * These can be: - * 1. declarations at global/class level - * 2. declarations at statement level - * Return array of Declaration *'s. - */ - -Dsymbols *Parser::parseDeclarations() -{ - StorageClass storage_class; - StorageClass stc; - Type *ts; - Type *t; - Type *tfirst; - Identifier *ident; - Dsymbols *a; - enum TOK tok = TOKreserved; - unsigned char *comment = token.blockComment; - enum LINK link = linkage; - - //printf("parseDeclarations()\n"); - switch (token.value) - { - case TOKtypedef: - case TOKalias: - tok = token.value; - nextToken(); - break; - - default: - tok = TOKreserved; - break; - } - - storage_class = STCundefined; - while (1) - { - switch (token.value) - { - case TOKconst: stc = STCconst; goto L1; - case TOKstatic: stc = STCstatic; goto L1; - case TOKfinal: stc = STCfinal; goto L1; - case TOKauto: stc = STCauto; goto L1; - case TOKscope: stc = STCscope; goto L1; - case TOKoverride: stc = STCoverride; goto L1; - case TOKabstract: stc = STCabstract; goto L1; - case TOKsynchronized: stc = STCsynchronized; goto L1; - case TOKdeprecated: stc = STCdeprecated; goto L1; -#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 TOKenum: stc = STCmanifest; goto L1; -#endif - L1: - if (storage_class & stc) - error("redundant storage class '%s'", token.toChars()); - storage_class = (STC) (storage_class | stc); - nextToken(); - continue; - - case TOKextern: - if (peek(&token)->value != TOKlparen) - { stc = STCextern; - goto L1; - } - - link = parseLinkage(); - continue; - - default: - break; - } - break; - } - - a = new Dsymbols(); - - /* Look for auto initializers: - * storage_class identifier = initializer; - */ - while (storage_class && - token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - ident = token.ident; - nextToken(); - nextToken(); - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = storage_class; - a->push(v); - if (token.value == TOKsemicolon) - { - nextToken(); - addComment(v, comment); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (!(token.value == TOKidentifier && peek(&token)->value == TOKassign)) - { - error("Identifier expected following comma"); - } - else - continue; - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - return a; - } - - if (token.value == TOKclass) - { AggregateDeclaration *s; - - s = (AggregateDeclaration *)parseAggregate(); - s->storage_class |= storage_class; - a->push(s); - addComment(s, comment); - return a; - } - - ts = parseBasicType(); - ts = parseBasicType2(ts); - tfirst = NULL; - - while (1) - { - Loc loc = this->loc; - TemplateParameters *tpl = NULL; - - ident = NULL; - t = parseDeclarator(ts, &ident, &tpl); - assert(t); - if (!tfirst) - tfirst = t; - else if (t != tfirst) - error("multiple declarations must have the same type, not %s and %s", - tfirst->toChars(), t->toChars()); - if (!ident) - error("no identifier for declarator %s", t->toChars()); - - if (tok == TOKtypedef || tok == TOKalias) - { Declaration *v; - Initializer *init = NULL; - - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - if (tok == TOKtypedef) - v = new TypedefDeclaration(loc, ident, t, init); - else - { if (init) - error("alias cannot have initializer"); - v = new AliasDeclaration(loc, ident, t); - } - v->storage_class = storage_class; - if (link == linkage) - a->push(v); - else - { - Dsymbols *ax = new Dsymbols(); - ax->push(v); - Dsymbol *s = new LinkDeclaration(link, ax); - a->push(s); - } - switch (token.value) - { case TOKsemicolon: - nextToken(); - addComment(v, comment); - break; - - case TOKcomma: - nextToken(); - addComment(v, comment); - continue; - - default: - error("semicolon expected to close %s declaration", Token::toChars(tok)); - break; - } - } - else if (t->ty == Tfunction) - { FuncDeclaration *f = - new FuncDeclaration(loc, 0, ident, storage_class, t); - addComment(f, comment); - 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); - } - if (tpl) // it's a function template - { - // Wrap a template around the aggregate declaration - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(s); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, s->ident, tpl, NULL, decldefs); - s = tempdecl; - } - addComment(s, comment); - a->push(s); - } - else - { - Initializer *init = NULL; - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - - VarDeclaration *v = new VarDeclaration(loc, t, ident, init); - v->storage_class = storage_class; - if (link == linkage) - a->push(v); - else - { - 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 declaration, not '%s'", token.toChars()); - break; - } - } - break; - } - return a; -} - -/***************************************** - * Parse auto declarations of the form: - * storageClass ident = init, ident = init, ... ; - * and return the array of them. - * Starts with token on the first ident. - * Ends with scanner past closing ';' - */ - -#if DMDV2 -Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, unsigned char *comment) -{ - Dsymbols *a = new Dsymbols; - - while (1) - { - Identifier *ident = token.ident; - nextToken(); // skip over ident - assert(token.value == TOKassign); - nextToken(); // skip over '=' - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = storageClass; - a->push(v); - if (token.value == TOKsemicolon) - { - nextToken(); - addComment(v, comment); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - addComment(v, comment); - continue; - } - else - error("Identifier expected following comma"); - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - break; - } - return a; -} -#endif - -/***************************************** - * Parse contracts following function declaration. - */ - -void Parser::parseContracts(FuncDeclaration *f) -{ - enum LINK linksave = linkage; - - // The following is irrelevant, as it is overridden by sc->linkage in - // TypeFunction::semantic - linkage = LINKd; // nested functions have D linkage -L1: - switch (token.value) - { - case TOKlcurly: - if (f->frequire || f->fensure) - error("missing body { ... } after in or out"); - f->fbody = parseStatement(PSsemi); - f->endloc = endloc; - break; - - case TOKbody: - nextToken(); - f->fbody = parseStatement(PScurly); - f->endloc = endloc; - break; - - case TOKsemicolon: - if (f->frequire || f->fensure) - error("missing body { ... } after in or out"); - nextToken(); - break; - -#if 0 // Do we want this for function declarations, so we can do: - // int x, y, foo(), z; - case TOKcomma: - nextToken(); - continue; -#endif - -#if 0 // Dumped feature - case TOKthrow: - if (!f->fthrows) - f->fthrows = new Array(); - nextToken(); - check(TOKlparen); - while (1) - { - Type *tb = parseBasicType(); - f->fthrows->push(tb); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - check(TOKrparen); - goto L1; -#endif - - case TOKin: - nextToken(); - if (f->frequire) - error("redundant 'in' statement"); - f->frequire = parseStatement(PScurly | PSscope); - goto L1; - - case TOKout: - // parse: out (identifier) { statement } - nextToken(); - if (token.value != TOKlcurly) - { - check(TOKlparen, "out"); - if (token.value != TOKidentifier) - error("(identifier) following 'out' expected, not %s", token.toChars()); - f->outId = token.ident; - nextToken(); - check(TOKrparen); - } - if (f->fensure) - error("redundant 'out' statement"); - f->fensure = parseStatement(PScurly | PSscope); - goto L1; - - default: - error("semicolon expected following function declaration"); - break; - } - linkage = linksave; -} - -/***************************************** - * Parse initializer for variable declaration. - */ - -Initializer *Parser::parseInitializer() -{ - StructInitializer *is; - ArrayInitializer *ia; - ExpInitializer *ie; - Expression *e; - Identifier *id; - Initializer *value; - int comma; - Loc loc = this->loc; - Token *t; - int braces; - int brackets; - - switch (token.value) - { - case TOKlcurly: - /* Scan ahead to see if it is a struct initializer or - * a function literal. - * If it contains a ';', it is a function literal. - * Treat { } as a struct initializer. - */ - braces = 1; - for (t = peek(&token); 1; t = peek(t)) - { - switch (t->value) - { - case TOKsemicolon: - case TOKreturn: - goto Lexpression; - - case TOKlcurly: - braces++; - continue; - - case TOKrcurly: - if (--braces == 0) - break; - continue; - - case TOKeof: - break; - - default: - continue; - } - break; - } - - is = new StructInitializer(loc); - nextToken(); - comma = 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 ';', 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(); - if (token.value == TOKcolon) - { - nextToken(); - e = value->toExpression(); - value = parseInitializer(); - } - else - e = NULL; - ia->addInit(e, 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 - -/***************************************** - * Input: - * flags PSxxxx - */ - -Statement *Parser::parseStatement(int flags) -{ Statement *s; - Token *t; - Condition *condition; - Statement *ifbody; - Statement *elsebody; - Loc loc = this->loc; - - //printf("parseStatement()\n"); - - if (flags & PScurly && token.value != TOKlcurly) - error("statement expected to be { }, not %s", token.toChars()); - - switch (token.value) - { - case TOKidentifier: - /* A leading identifier can be a declaration, label, or expression. - * The easiest case to check first is label: - */ - t = peek(&token); - if (t->value == TOKcolon) - { // It's a label - - Identifier *ident = token.ident; - nextToken(); - nextToken(); - s = parseStatement(PSsemi); - s = new LabelStatement(loc, ident, s); - break; - } - // fallthrough to TOKdot - case TOKdot: - case TOKtypeof: - if (isDeclaration(&token, 2, TOKreserved, NULL)) - goto Ldeclaration; - else - goto Lexp; - break; - - case TOKassert: - case TOKthis: - case TOKsuper: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKstring: - case TOKlparen: - case TOKcast: - case TOKmul: - case TOKmin: - case TOKadd: - case TOKplusplus: - case TOKminusminus: - case TOKnew: - case TOKdelete: - case TOKdelegate: - case TOKfunction: - case TOKtypeid: - case TOKis: - case TOKlbracket: -#if DMDV2 - case TOKtilde: - case TOKnot: - case TOKtraits: - case TOKfile: - case TOKline: -#endif - Lexp: - { - Expression *exp = parseExpression(); - check(TOKsemicolon, "statement"); - s = new ExpStatement(loc, exp); - break; - } - - case TOKstatic: - { // Look ahead to see if it's static assert() or static if() - Token *t; - - t = peek(&token); - if (t->value == TOKassert) - { - nextToken(); - s = new StaticAssertStatement(parseStaticAssert()); - break; - } - if (t->value == TOKif) - { - nextToken(); - condition = parseStaticIfCondition(); - goto Lcondition; - } - goto Ldeclaration; - } - - case BASIC_TYPES: - case TOKtypedef: - case TOKalias: - case TOKconst: - case TOKauto: - case TOKextern: - case TOKfinal: - case TOKinvariant: -#if DMDV2 - case TOKimmutable: - case TOKshared: - case TOKwild: - case TOKnothrow: - case TOKpure: - case TOKtls: - case TOKgshared: - case TOKat: -#endif -// case TOKtypeof: - Ldeclaration: - { Array *a; - - a = parseDeclarations(); - if (a->dim > 1) - { - Statements *as = new Statements(); - as->reserve(a->dim); - for (size_t i = 0; i < a->dim; i++) - { - Dsymbol *d = (Dsymbol *)a->data[i]; - s = new ExpStatement(loc, d); - as->push(s); - } - s = new CompoundDeclarationStatement(loc, as); - } - else if (a->dim == 1) - { - Dsymbol *d = (Dsymbol *)a->data[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: - { Dsymbol *d; - - d = parseEnum(); - 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: - { - nextToken(); - Statements *statements = new Statements(); - while (token.value != TOKrcurly && token.value != TOKeof) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - endloc = this->loc; - s = new CompoundStatement(loc, statements); - if (flags & (PSscope | PScurlyscope)) - s = new ScopeStatement(loc, s); - check(TOKrcurly, "compound statement"); - break; - } - - case TOKwhile: - { Expression *condition; - Statement *body; - - nextToken(); - check(TOKlparen, "while"); - condition = parseExpression(); - check(TOKrparen); - body = parseStatement(PSscope); - s = new WhileStatement(loc, condition, body); - break; - } - - case TOKsemicolon: - if (!(flags & PSsemi)) - error("use '{ }' for an empty statement, not a ';'"); - nextToken(); - s = new ExpStatement(loc, (Expression *)NULL); - break; - - case TOKdo: - { Statement *body; - Expression *condition; - - nextToken(); - body = parseStatement(PSscope); - check(TOKwhile, "statement"); - check(TOKlparen, "while"); - condition = parseExpression(); - check(TOKrparen); - s = new DoStatement(loc, body, condition); - break; - } - - case TOKfor: - { - Statement *init; - Expression *condition; - Expression *increment; - Statement *body; - - nextToken(); - check(TOKlparen, "for"); - if (token.value == TOKsemicolon) - { init = NULL; - nextToken(); - } - else - { init = parseStatement(0); - } - if (token.value == TOKsemicolon) - { - condition = NULL; - nextToken(); - } - else - { - condition = parseExpression(); - check(TOKsemicolon, "for condition"); - } - if (token.value == TOKrparen) - { increment = NULL; - nextToken(); - } - else - { increment = parseExpression(); - check(TOKrparen); - } - body = parseStatement(PSscope); - s = new ForStatement(loc, init, condition, increment, body); - if (init) - s = new ScopeStatement(loc, s); - break; - } - - case TOKforeach: - case TOKforeach_reverse: - { - enum TOK op = token.value; - - Statement *d; - Statement *body; - Expression *aggr; - - nextToken(); - check(TOKlparen, "foreach"); - - Parameters *arguments = new Parameters(); - - while (1) - { - Type *tb; - Identifier *ai = NULL; - Type *at; - unsigned storageClass; - - storageClass = STCin; - if (token.value == TOKinout || token.value == TOKref) - { storageClass = STCref; - nextToken(); - } - if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKsemicolon) - { ai = token.ident; - at = NULL; // infer argument type - nextToken(); - goto Larg; - } - } - tb = parseBasicType(); - at = parseDeclarator(tb, &ai); - if (!ai) - error("no identifier for declarator %s", at->toChars()); - Larg: - Parameter *a = new Parameter(storageClass, at, ai, NULL); - arguments->push(a); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - check(TOKsemicolon, "foreach statement"); - - aggr = parseExpression(); - check(TOKrparen); - 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"); - - if (token.value == TOKauto) - { - nextToken(); - if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKassign) - { - arg = new Parameter(STCin, NULL, token.ident, NULL); - nextToken(); - nextToken(); - } - else - { error("= expected following auto identifier"); - goto Lerror; - } - } - else - { error("identifier expected following auto"); - goto Lerror; - } - } - else if (isDeclaration(&token, 2, TOKassign, NULL)) - { - Type *tb; - Type *at; - Identifier *ai; - - tb = parseBasicType(); - at = parseDeclarator(tb, &ai); - check(TOKassign); - arg = new Parameter(STCin, at, ai, NULL); - } - - // Check for " ident;" - else if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKsemicolon) - { - arg = new Parameter(STCin, NULL, token.ident, NULL); - nextToken(); - nextToken(); - if (1 || !global.params.useDeprecated) - error("if (v; e) is deprecated, use if (auto v = e)"); - } - } - - condition = parseExpression(); - check(TOKrparen); - ifbody = parseStatement(PSscope); - if (token.value == TOKelse) - { - nextToken(); - elsebody = parseStatement(PSscope); - } - else - elsebody = NULL; - 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, "scope"); - if (token.value != TOKidentifier) - { error("scope (identifier) expected"); - goto Lerror; - } - else - { TOK t = TOKon_scope_exit; - Identifier *id = token.ident; - - if (id == Id::exit) - t = TOKon_scope_exit; - else if (id == Id::failure) - t = TOKon_scope_failure; - else if (id == Id::success) - t = TOKon_scope_success; - else - error("valid scope identifiers are exit, failure, or success, not %s", id->toChars()); - nextToken(); - check(TOKrparen); - Statement *st = parseStatement(PScurlyscope); - s = new OnScopeStatement(loc, t, st); - break; - } - - case TOKdebug: - nextToken(); - condition = parseDebugCondition(); - goto Lcondition; - - case TOKversion: - nextToken(); - condition = parseVersionCondition(); - goto Lcondition; - - Lcondition: - ifbody = parseStatement(0 /*PSsemi*/); - elsebody = NULL; - if (token.value == TOKelse) - { - nextToken(); - elsebody = parseStatement(0 /*PSsemi*/); - } - s = new ConditionalStatement(loc, condition, ifbody, elsebody); - break; - - case TOKpragma: - { Identifier *ident; - Expressions *args = NULL; - Statement *body; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("pragma(identifier expected"); - goto Lerror; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma && peekNext() != TOKrparen) - args = parseArguments(); // pragma(identifier, args...); - else - check(TOKrparen); // pragma(identifier); - if (token.value == TOKsemicolon) - { nextToken(); - body = NULL; - } - else - body = parseStatement(PSsemi); - s = new PragmaStatement(loc, ident, args, body); - break; - } - - case TOKswitch: - { - nextToken(); - check(TOKlparen, "switch"); - Expression *condition = parseExpression(); - check(TOKrparen); - Statement *body = parseStatement(PSscope); - s = new SwitchStatement(loc, condition, body); - break; - } - - case TOKcase: - { Expression *exp; - Statements *statements; - Array cases; // array of Expression's - - while (1) - { - nextToken(); - exp = parseAssignExp(); - cases.push(exp); - if (token.value != TOKcomma) - break; - } - check(TOKcolon, "case expression"); - -#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, "case expression"); - } -#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); - - // Keep cases in order by building the case statements backwards - for (size_t i = cases.dim; i; i--) - { - exp = (Expression *)cases.data[i - 1]; - s = new CaseStatement(loc, exp, s); - } - break; - } - - case TOKdefault: - { - Statements *statements; - - nextToken(); - check(TOKcolon, "default"); - - 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 expression"); - 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, "with"); - 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(); - body = parseStatement(PSscope); - while (token.value == TOKcatch) - { - Statement *handler; - Catch *c; - Type *t; - Identifier *id; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlcurly || token.value != TOKlparen) - { - t = NULL; - id = NULL; - } - else - { - check(TOKlparen, "catch"); - t = parseBasicType(); - id = NULL; - t = parseDeclarator(t, &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; used synchronized statements instead"); -#endif - s = new VolatileStatement(loc, s); - break; - - case TOKasm: - { Statements *statements; - Identifier *label; - Loc labelloc; - Token *toklist; - Token **ptoklist; - - // Parse the asm block into a sequence of AsmStatements, - // each AsmStatement is one instruction. - // Separate out labels. - // Defer parsing of AsmStatements until semantic processing. - - nextToken(); - check(TOKlcurly, "asm"); - toklist = NULL; - ptoklist = &toklist; - label = NULL; - statements = new Statements(); - while (1) - { - switch (token.value) - { - case TOKidentifier: - if (!toklist) - { - // Look ahead to see if it is a label - t = peek(&token); - if (t->value == TOKcolon) - { // It's a label - label = token.ident; - labelloc = this->loc; - nextToken(); - nextToken(); - continue; - } - } - goto Ldefault; - - case TOKrcurly: - if (toklist || label) - { - error("asm statements must end in ';'"); - } - break; - - case TOKsemicolon: - s = NULL; - if (toklist || label) - { // Create AsmStatement from list of tokens we've saved - s = new AsmStatement(this->loc, toklist); - toklist = NULL; - ptoklist = &toklist; - if (label) - { s = new LabelStatement(labelloc, label, s); - label = NULL; - } - statements->push(s); - } - nextToken(); - continue; - - case TOKeof: - /* { */ - error("matching '}' expected, not end of file"); - break; - - default: - Ldefault: - *ptoklist = new Token(); - memcpy(*ptoklist, &token, sizeof(Token)); - ptoklist = &(*ptoklist)->next; - *ptoklist = NULL; - - nextToken(); - continue; - } - break; - } - s = new AsmBlockStatement(loc, statements); - nextToken(); - break; - } - - default: - error("found '%s' instead of statement", token.toChars()); - goto Lerror; - - Lerror: - while (token.value != TOKrcurly && - token.value != TOKsemicolon && - token.value != TOKeof) - nextToken(); - if (token.value == TOKsemicolon) - nextToken(); - s = NULL; - break; - } - - return s; -} - -void Parser::check(enum TOK value) -{ - check(loc, value); -} - -void Parser::check(Loc loc, enum TOK value) -{ - if (token.value != value) - error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value)); - nextToken(); -} - -void Parser::check(enum TOK value, const char *string) -{ - if (token.value != value) - error("found '%s' when expecting '%s' following %s", - token.toChars(), Token::toChars(value), string); - nextToken(); -} - -/************************************ - * Determine if the scanner is sitting on the start of a declaration. - * Input: - * needId 0 no identifier - * 1 identifier optional - * 2 must have identifier - * Output: - * if *pt is not NULL, it is set to the ending token, which would be endtok - */ - -int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt) -{ - //printf("isDeclaration(needId = %d)\n", needId); - int haveId = 0; - -#if DMDV2 - if ((t->value == TOKconst || - t->value == TOKinvariant || - t->value == TOKimmutable || - t->value == 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; - - switch (t->value) - { - case BASIC_TYPES: - t = peek(t); - break; - - case TOKidentifier: - t = peek(t); - if (t->value == TOKnot) - { - goto L4; - } - goto L3; - while (1) - { - L2: - t = peek(t); - L3: - if (t->value == TOKdot) - { - Ldot: - t = peek(t); - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - if (t->value != TOKnot) - goto L3; - L4: - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - if (!skipParens(t, &t)) - goto Lfalse; - } - else - break; - } - break; - - case TOKdot: - goto Ldot; - - case TOKtypeof: - /* typeof(exp).identifier... - */ - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - if (!skipParens(t, &t)) - goto Lfalse; - goto L2; - - default: - goto Lfalse; - } - *pt = t; - //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; - int tmp; - - //printf("isParameters()\n"); - if (t->value != TOKlparen) - return FALSE; - - t = peek(t); - while (1) - { - switch (t->value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - t = peek(t); - break; - - case TOKin: - case TOKout: - case TOKinout: - case TOKref: - case TOKlazy: - t = peek(t); - default: - if (!isBasicType(&t)) - return FALSE; - tmp = FALSE; - if (t->value != TOKdotdotdot && - !isDeclarator(&t, &tmp, TOKreserved)) - return FALSE; - if (t->value == TOKassign) - { t = peek(t); - if (!isExpression(&t)) - return FALSE; - } - if (t->value == TOKdotdotdot) - { - t = peek(t); - break; - } - if (t->value == TOKcomma) - { t = peek(t); - continue; - } - break; - } - break; - } - if (t->value != TOKrparen) - return FALSE; - t = peek(t); - *pt = t; - return TRUE; -} - -int Parser::isExpression(Token **pt) -{ - // This is supposed to determine if something is an expression. - // What it actually does is scan until a closing right bracket - // is found. - - Token *t = *pt; - int brnest = 0; - int panest = 0; - - for (;; t = peek(t)) - { - switch (t->value) - { - case TOKlbracket: - brnest++; - continue; - - case TOKrbracket: - if (--brnest >= 0) - continue; - break; - - case TOKlparen: - panest++; - continue; - - case TOKcomma: - if (brnest || panest) - continue; - break; - - case TOKrparen: - if (--panest >= 0) - continue; - break; - - case TOKslice: - if (brnest) - continue; - break; - - case TOKeof: - return FALSE; - - default: - continue; - } - break; - } - - *pt = t; - return TRUE; -} - -/********************************************** - * Skip over - * instance foo.bar(parameters...) - * Output: - * if (pt), *pt is set to the token following the closing ) - * Returns: - * 1 it's valid instance syntax - * 0 invalid instance syntax - */ - -int Parser::isTemplateInstance(Token *t, Token **pt) -{ - t = peek(t); - if (t->value != TOKdot) - { - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - } - while (t->value == TOKdot) - { - t = peek(t); - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - } - if (t->value != TOKlparen) - goto Lfalse; - - // Skip over the template arguments - while (1) - { - while (1) - { - t = peek(t); - switch (t->value) - { - case TOKlparen: - if (!skipParens(t, &t)) - goto Lfalse; - continue; - case TOKrparen: - break; - case TOKcomma: - break; - case TOKeof: - case TOKsemicolon: - goto Lfalse; - default: - continue; - } - break; - } - - if (t->value != TOKcomma) - break; - } - if (t->value != TOKrparen) - goto Lfalse; - t = peek(t); - if (pt) - *pt = t; - return 1; - -Lfalse: - return 0; -} - -/******************************************* - * Skip parens, brackets. - * Input: - * t is on opening ( - * Output: - * *pt is set to closing token, which is ')' on success - * Returns: - * !=0 successful - * 0 some parsing error - */ - -int Parser::skipParens(Token *t, Token **pt) -{ - int parens = 0; - - while (1) - { - switch (t->value) - { - case TOKlparen: - parens++; - break; - - case TOKrparen: - parens--; - if (parens < 0) - goto Lfalse; - if (parens == 0) - goto Ldone; - break; - - case TOKeof: - goto Lfalse; - - default: - break; - } - t = peek(t); - } - - Ldone: - if (*pt) - *pt = t; - return 1; - - Lfalse: - return 0; -} - -/********************************* Expression Parser ***************************/ - -Expression *Parser::parsePrimaryExp() -{ Expression *e; - Type *t; - Identifier *id; - enum TOK save; - Loc loc = this->loc; - - //printf("parsePrimaryExp(): loc = %d\n", loc.linnum); - switch (token.value) - { - case TOKidentifier: - id = token.ident; - nextToken(); - if (token.value == TOKnot && peek(&token)->value == TOKlparen) - { // identifier!(template-argument-list) - TemplateInstance *tempinst; - - tempinst = new TemplateInstance(loc, id); - nextToken(); - tempinst->tiargs = parseTemplateArgumentList(); - e = new ScopeExp(loc, tempinst); - } - else - e = new IdentifierExp(loc, id); - break; - - case TOKdollar: - if (!inBrackets) - error("'$' is valid only inside [] of index or slice"); - e = new DollarExp(loc); - nextToken(); - break; - - case TOKdot: - // Signal global scope '.' operator with "" identifier - e = new IdentifierExp(loc, Id::empty); - break; - - case TOKthis: - e = new ThisExp(loc); - nextToken(); - break; - - case TOKsuper: - e = new SuperExp(loc); - nextToken(); - break; - - case TOKint32v: - e = new IntegerExp(loc, (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: - { Expression *exp; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - t = new TypeTypeof(loc, exp); - e = new TypeExp(loc, t); - break; - } - - case TOKtypeid: - { Type *t; - - nextToken(); - check(TOKlparen, "typeid"); - t = parseBasicType(); - t = parseDeclarator(t,NULL); // ( type ) - check(TOKrparen); - e = new TypeidExp(loc, t); - break; - } - -#if DMDV2 - case TOKtraits: - { /* __traits(identifier, args...) - */ - Identifier *ident; - Objects *args = NULL; - - nextToken(); - check(TOKlparen, "__traits"); - if (token.value != TOKidentifier) - { error("__traits(identifier, args...) expected"); - goto Lerr; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma) - args = parseTemplateArgumentList2(); // __traits(identifier, args...) - else - check(TOKrparen); // __traits(identifier) - - e = new TraitsExp(loc, ident, args); - break; - } -#endif - - case TOKis: - { Type *targ; - Identifier *ident = NULL; - Type *tspec = NULL; - enum TOK tok = TOKreserved; - enum TOK tok2 = TOKreserved; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - targ = parseBasicType(); - targ = parseDeclarator(targ, &ident); - if (token.value == TOKcolon || token.value == TOKequal) - { - tok = token.value; - nextToken(); - if (tok == TOKequal && - (token.value == TOKtypedef || - token.value == TOKstruct || - token.value == TOKunion || - token.value == TOKclass || - token.value == TOKsuper || - token.value == TOKenum || - token.value == TOKinterface || - token.value == 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 || -#endif - token.value == TOKfunction || - token.value == TOKdelegate || - token.value == TOKreturn)) - { - tok2 = token.value; - nextToken(); - } - else - { - tspec = parseBasicType(); - tspec = parseDeclarator(tspec, NULL); - } - } - check(TOKrparen); - } - else - { error("(type identifier : specialization) expected following is"); - goto Lerr; - } - e = new IsExp(loc, targ, ident, tok, tspec, tok2); - break; - } - - case TOKassert: - { Expression *msg = NULL; - - nextToken(); - check(TOKlparen, "assert"); - e = parseAssignExp(); - if (token.value == TOKcomma) - { nextToken(); - msg = parseAssignExp(); - } - check(TOKrparen); - e = new AssertExp(loc, e, msg); - break; - } - - case TOKmixin: - { - nextToken(); - check(TOKlparen, "mixin"); - e = parseAssignExp(); - check(TOKrparen); - e = new CompileExp(loc, e); - break; - } - - case TOKimport: - { - nextToken(); - check(TOKlparen, "import"); - e = parseAssignExp(); - check(TOKrparen); - e = new FileExp(loc, e); - break; - } - - case TOKlparen: - if (peekPastParen(&token)->value == TOKlcurly) - { // (arguments) { statements... } - save = TOKdelegate; - goto case_delegate; - } - // ( expression ) - nextToken(); - e = parseExpression(); - check(loc, TOKrparen); - break; - - case TOKlbracket: - { /* Parse array literals and associative array literals: - * [ value, value, value ... ] - * [ key:value, key:value, key:value ... ] - */ - Expressions *values = new Expressions(); - Expressions *keys = NULL; - - nextToken(); - if (token.value != TOKrbracket) - { - while (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, "literal element"); - } - } - check(TOKrbracket); - - if (keys) - e = new AssocArrayLiteralExp(loc, keys, values); - else - e = new ArrayLiteralExp(loc, values); - break; - } - - case TOKlcurly: - // { statements... } - save = TOKdelegate; - goto case_delegate; - - case TOKfunction: - case TOKdelegate: - save = token.value; - nextToken(); - case_delegate: - { - /* function type(parameters) { body } - * delegate type(parameters) { body } - */ - Parameters *arguments; - int varargs; - FuncLiteralDeclaration *fd; - Type *t; - - if (token.value == TOKlcurly) - { - t = NULL; - varargs = 0; - arguments = new Parameters(); - } - else - { - if (token.value == TOKlparen) - t = NULL; - else - { - t = parseBasicType(); - t = parseBasicType2(t); // function return type - } - arguments = parseParameters(&varargs); - } - t = new TypeFunction(arguments, t, varargs, linkage); - fd = new FuncLiteralDeclaration(loc, 0, t, save, NULL); - parseContracts(fd); - e = new FuncExp(loc, fd); - break; - } - - default: - error("expression expected, not '%s'", token.toChars()); - Lerr: - // Anything for e, as long as it's not NULL - e = new IntegerExp(loc, 0, Type::tint32); - nextToken(); - break; - } - return parsePostExp(e); -} - -Expression *Parser::parsePostExp(Expression *e) -{ - Loc loc; - - while (1) - { - loc = this->loc; - switch (token.value) - { - case TOKdot: - nextToken(); - if (token.value == TOKidentifier) - { Identifier *id = token.ident; - - nextToken(); - if (token.value == TOKnot && peek(&token)->value == TOKlparen) - { // identifier!(template-argument-list) - TemplateInstance *tempinst; - - tempinst = new TemplateInstance(loc, id); - nextToken(); - tempinst->tiargs = parseTemplateArgumentList(); - e = new DotTemplateInstanceExp(loc, e, tempinst); - } - else - e = new DotIdExp(loc, e, id); - continue; - } - else if (token.value == TOKnew) - { - e = parseNewExp(e); - continue; - } - else - error("identifier expected following '.', not '%s'", token.toChars()); - break; - - case TOKplusplus: - e = new PostExp(TOKplusplus, loc, e); - break; - - case TOKminusminus: - e = new PostExp(TOKminusminus, loc, e); - break; - - case TOKlparen: - e = new CallExp(loc, e, parseArguments()); - continue; - - case TOKlbracket: - { // array dereferences: - // array[index] - // array[] - // array[lwr .. upr] - Expression *index; - Expression *upr; - - inBrackets++; - nextToken(); - if (token.value == TOKrbracket) - { // array[] - 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 (1) - { - Expression *arg = parseAssignExp(); - arguments->push(arg); - if (token.value == TOKrbracket) - break; - check(TOKcomma, "array literal element"); - } - } - e = new ArrayExp(loc, e, arguments); - } - check(TOKrbracket); - inBrackets--; - } - continue; - } - - default: - return e; - } - nextToken(); - } -} - -Expression *Parser::parseUnaryExp() -{ Expression *e; - Loc loc = this->loc; - - switch (token.value) - { - case TOKand: - nextToken(); - e = parseUnaryExp(); - e = new AddrExp(loc, e); - break; - - case TOKplusplus: - nextToken(); - e = parseUnaryExp(); - e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - break; - - case TOKminusminus: - nextToken(); - e = parseUnaryExp(); - e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - break; - - case TOKmul: - nextToken(); - e = parseUnaryExp(); - e = new PtrExp(loc, e); - break; - - case TOKmin: - nextToken(); - e = parseUnaryExp(); - e = new NegExp(loc, e); - break; - - case TOKadd: - nextToken(); - e = parseUnaryExp(); - e = new UAddExp(loc, e); - break; - - case TOKnot: - nextToken(); - e = parseUnaryExp(); - e = new NotExp(loc, e); - break; - - case TOKtilde: - nextToken(); - e = parseUnaryExp(); - e = new ComExp(loc, e); - break; - - case TOKdelete: - nextToken(); - e = parseUnaryExp(); - e = new DeleteExp(loc, e); - break; - - case TOKnew: - e = parseNewExp(NULL); - break; - - case TOKcast: // cast(type) expression - { Type *t; - - nextToken(); - check(TOKlparen); - t = parseBasicType(); - t = parseDeclarator(t,NULL); // ( type ) - check(TOKrparen); - - e = parseUnaryExp(); - e = new CastExp(loc, e, t); - break; - } - - case TOKlparen: - { Token *tk; - - tk = peek(&token); -#if CCASTSYNTAX - // If cast - if (isDeclaration(tk, 0, TOKrparen, &tk)) - { - tk = peek(tk); // skip over right parenthesis - switch (tk->value) - { - case TOKnot: - tk = peek(tk); - if (tk->value == TOKis) // !is - break; - case TOKdot: - case TOKplusplus: - case TOKminusminus: - case TOKdelete: - case TOKnew: - case TOKlparen: - case TOKidentifier: - case TOKthis: - case TOKsuper: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKstring: -#if 0 - case TOKtilde: - case TOKand: - case TOKmul: - case TOKmin: - case TOKadd: -#endif - case TOKfunction: - case TOKdelegate: - case TOKtypeof: -#if DMDV2 - case TOKfile: - case TOKline: -#endif - case BASIC_TYPES: // (type)int.size - { // (type) una_exp - Type *t; - - nextToken(); - t = parseBasicType(); - t = parseDeclarator(t,NULL); - check(TOKrparen); - - // if .identifier - if (token.value == TOKdot) - { - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following (type)."); - return NULL; - } - e = typeDotIdExp(loc, t, token.ident); - nextToken(); - e = parsePostExp(e); - } - else - { - e = parseUnaryExp(); - e = new CastExp(loc, e, t); - error("C style cast illegal, use %s", e->toChars()); - } - return e; - } - } - } -#endif - e = parsePrimaryExp(); - break; - } - default: - e = parsePrimaryExp(); - break; - } - assert(e); - return e; -} - -Expression *Parser::parseMulExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseUnaryExp(); - while (1) - { - switch (token.value) - { - case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue; - case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue; - case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseAddExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseMulExp(); - while (1) - { - switch (token.value) - { - case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue; - case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue; - case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseShiftExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAddExp(); - while (1) - { - switch (token.value) - { - case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue; - case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue; - case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseRelExp() -{ Expression *e; - Expression *e2; - enum TOK op; - Loc loc = this->loc; - - e = parseShiftExp(); - while (1) - { - switch (token.value) - { - case TOKlt: - case TOKle: - case TOKgt: - case TOKge: - case TOKunord: - case TOKlg: - case TOKleg: - case TOKule: - case TOKul: - case TOKuge: - case TOKug: - case TOKue: - op = token.value; - nextToken(); - e2 = parseShiftExp(); - e = new CmpExp(op, loc, e, e2); - continue; - -#if DMDV2 - 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; -#endif - - case TOKin: - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseEqualExp() -{ Expression *e; - Expression *e2; - Token *t; - Loc loc = this->loc; - - e = parseRelExp(); - while (1) - { enum TOK value = token.value; - - switch (value) - { - case TOKequal: - case TOKnotequal: - nextToken(); - e2 = parseRelExp(); - e = new EqualExp(value, loc, e, e2); - continue; - - case TOKidentity: - error("'===' is no longer legal, use 'is' instead"); - goto L1; - - case TOKnotidentity: - error("'!==' is no longer legal, use '!is' instead"); - goto L1; - - case TOKis: - value = TOKidentity; - goto L1; - - case TOKnot: - // Attempt to identify '!is' - t = peek(&token); - if (t->value != TOKis) - break; - nextToken(); - value = TOKnotidentity; - goto L1; - - L1: - nextToken(); - e2 = parseRelExp(); - e = new IdentityExp(value, loc, e, e2); - continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseCmpExp() -{ Expression *e; - Expression *e2; - Token *t; - Loc loc = this->loc; - - e = parseShiftExp(); - enum TOK op = token.value; - - switch (op) - { - case TOKequal: - case TOKnotequal: - nextToken(); - e2 = parseShiftExp(); - e = new EqualExp(op, loc, e, e2); - break; - - case TOKis: - op = TOKidentity; - goto L1; - - case TOKnot: - // Attempt to identify '!is' - t = peek(&token); -#if DMDV2 - if (t->value == TOKin) - { - nextToken(); - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - e = new NotExp(loc, e); - break; - } -#endif - if (t->value != TOKis) - break; - nextToken(); - op = TOKnotidentity; - goto L1; - - L1: - nextToken(); - e2 = parseShiftExp(); - e = new IdentityExp(op, loc, e, e2); - break; - - case TOKlt: - case TOKle: - case TOKgt: - case TOKge: - case TOKunord: - case TOKlg: - case TOKleg: - case TOKule: - case TOKul: - case TOKuge: - case TOKug: - case TOKue: - nextToken(); - e2 = parseShiftExp(); - e = new CmpExp(op, loc, e, e2); - break; - - case TOKin: - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - break; - - default: - break; - } - return e; -} - -Expression *Parser::parseAndExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - if (global.params.Dversion == 1) - { - e = parseEqualExp(); - while (token.value == TOKand) - { - nextToken(); - e2 = parseEqualExp(); - e = new AndExp(loc,e,e2); - loc = this->loc; - } - } - else - { - e = parseCmpExp(); - while (token.value == TOKand) - { - nextToken(); - e2 = parseCmpExp(); - e = new AndExp(loc,e,e2); - loc = this->loc; - } - } - return e; -} - -Expression *Parser::parseXorExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAndExp(); - while (token.value == TOKxor) - { - nextToken(); - e2 = parseAndExp(); - e = new XorExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseOrExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseXorExp(); - while (token.value == TOKor) - { - nextToken(); - e2 = parseXorExp(); - e = new OrExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseAndAndExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseOrExp(); - while (token.value == TOKandand) - { - nextToken(); - e2 = parseOrExp(); - e = new AndAndExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseOrOrExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAndAndExp(); - while (token.value == TOKoror) - { - nextToken(); - e2 = parseAndAndExp(); - e = new OrOrExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseCondExp() -{ Expression *e; - Expression *e1; - Expression *e2; - Loc loc = this->loc; - - e = parseOrOrExp(); - if (token.value == TOKquestion) - { - nextToken(); - e1 = parseExpression(); - check(TOKcolon, "condition ? expression"); - e2 = parseCondExp(); - e = new CondExp(loc, e, e1, e2); - } - return e; -} - -Expression *Parser::parseAssignExp() -{ Expression *e; - Expression *e2; - Loc loc; - - e = parseCondExp(); - while (1) - { - loc = this->loc; - switch (token.value) - { -#define X(tok,ector) \ - case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue; - - X(TOKassign, AssignExp); - X(TOKaddass, AddAssignExp); - X(TOKminass, MinAssignExp); - X(TOKmulass, MulAssignExp); - X(TOKdivass, DivAssignExp); - X(TOKmodass, ModAssignExp); - X(TOKandass, AndAssignExp); - X(TOKorass, OrAssignExp); - X(TOKxorass, XorAssignExp); - X(TOKshlass, ShlAssignExp); - X(TOKshrass, ShrAssignExp); - X(TOKushrass, UshrAssignExp); - X(TOKcatass, CatAssignExp); - -#undef X - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseExpression() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - //printf("Parser::parseExpression() loc = %d\n", loc.linnum); - e = parseAssignExp(); - while (token.value == TOKcomma) - { - nextToken(); - e2 = parseAssignExp(); - e = new CommaExp(loc, e, e2); - loc = this->loc; - } - return e; -} - - -/************************* - * Collect argument list. - * Assume current token is '(' or '['. - */ - -Expressions *Parser::parseArguments() -{ // function call - Expressions *arguments; - Expression *arg; - enum TOK endtok; - - arguments = new Expressions(); - if (token.value == TOKlbracket) - endtok = TOKrbracket; - else - endtok = TOKrparen; - - { - nextToken(); - if (token.value != endtok) - { - while (token.value != TOKeof) - { - arg = parseAssignExp(); - arguments->push(arg); - if (token.value == endtok) - break; - check(TOKcomma, "argument"); - } - } - check(endtok, "argument list"); - } - 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; - } - -#if LTORARRAYDECL - t = parseBasicType(); - t = parseBasicType2(t); - if (t->ty == Taarray) - { - Type *index = ((TypeAArray *)t)->index; - - Expression *e = index->toExpression(); - if (e) - { arguments = new Expressions(); - arguments->push(e); - t = new TypeDArray(t->next); - } - else - { - error("need size of rightmost array, not type %s", index->toChars()); - return new NullExp(loc); - } - } - else if (t->ty == Tsarray) - { - TypeSArray *tsa = (TypeSArray *)t; - Expression *e = tsa->dim; - - arguments = new Expressions(); - arguments->push(e); - t = new TypeDArray(t->next); - } - else if (token.value == TOKlparen) - { - arguments = parseArguments(); - } -#else - t = parseBasicType(); - while (token.value == TOKmul) - { t = new TypePointer(t); - nextToken(); - } - if (token.value == TOKlbracket) - { - Expression *e; - - nextToken(); - e = parseAssignExp(); - arguments = new Array(); - arguments->push(e); - check(TOKrbracket); - t = parseDeclarator(t, NULL); - t = new TypeDArray(t); - } - else if (token.value == TOKlparen) - arguments = parseArguments(); -#endif - e = new NewExp(loc, thisexp, newargs, t, arguments); - return e; -} - -/********************************************** - */ - -void Parser::addComment(Dsymbol *s, unsigned char *blockComment) -{ - s->addComment(combineComments(blockComment, token.lineComment)); - 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; - precedence[TOKvoid] = 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[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; - -#if IN_LLVM - // Need to set precedence for TOKgep as well, as expToCBuffer expects it. - precedence[TOKgep] = PREC_primary; -#endif -} - - - diff --git a/dmd/parse.h b/dmd/parse.h deleted file mode 100644 index 4e212e40..00000000 --- a/dmd/parse.h +++ /dev/null @@ -1,172 +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. - -#ifndef DMD_PARSE_H -#define DMD_PARSE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "arraytypes.h" -#include "lexer.h" -#include "enum.h" - -struct Type; -struct TypeQualified; -struct Expression; -struct Declaration; -struct Statement; -struct Import; -struct Initializer; -struct FuncDeclaration; -struct CtorDeclaration; -struct PostBlitDeclaration; -struct DtorDeclaration; -struct StaticCtorDeclaration; -struct StaticDtorDeclaration; -struct ConditionalDeclaration; -struct InvariantDeclaration; -struct UnitTestDeclaration; -struct NewDeclaration; -struct DeleteDeclaration; -struct Condition; -struct Module; -struct ModuleDeclaration; -struct TemplateDeclaration; -struct TemplateInstance; -struct StaticAssert; - -/************************************ - * These control how parseStatement() works. - */ - -enum ParseStatementFlags -{ - PSsemi = 1, // empty ';' statements are allowed - PSscope = 2, // start a new scope - PScurly = 4, // { } statement is required - PScurlyscope = 8, // { } starts a new scope -}; - - -struct Parser : Lexer -{ - ModuleDeclaration *md; - enum LINK linkage; - Loc endloc; // set to location of last right curly - int inBrackets; // inside [] of array index or slice - - Parser(Module *module, unsigned char *base, unsigned length, int doDocComment); - - Dsymbols *parseModule(); - Dsymbols *parseDeclDefs(int once); - Array *parseAutoDeclarations(StorageClass storageClass, unsigned char *comment); - Dsymbols *parseBlock(); - void composeStorageClass(StorageClass stc); - Expression *parseConstraint(); - TemplateDeclaration *parseTemplateDeclaration(); - TemplateParameters *parseTemplateParameterList(int flag = 0); - Dsymbol *parseMixin(); - Objects *parseTemplateArgumentList(); - Objects *parseTemplateArgumentList2(); - Objects *parseTemplateArgument(); - StaticAssert *parseStaticAssert(); - TypeQualified *parseTypeof(); - enum LINK parseLinkage(); - Condition *parseDebugCondition(); - Condition *parseVersionCondition(); - Condition *parseStaticIfCondition(); - Dsymbol *parseCtor(); - PostBlitDeclaration *parsePostBlit(); - DtorDeclaration *parseDtor(); - StaticCtorDeclaration *parseStaticCtor(); - StaticDtorDeclaration *parseStaticDtor(); - InvariantDeclaration *parseInvariant(); - UnitTestDeclaration *parseUnitTest(); - NewDeclaration *parseNew(); - DeleteDeclaration *parseDelete(); - Parameters *parseParameters(int *pvarargs); - EnumDeclaration *parseEnum(); - Dsymbol *parseAggregate(); - BaseClasses *parseBaseClasses(); - Import *parseImport(Array *decldefs, int isstatic); - Type *parseType(Identifier **pident = NULL, TemplateParameters **tpl = NULL); - Type *parseBasicType(); - Type *parseBasicType2(Type *t); - Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL); - Dsymbols *parseDeclarations(); - void parseContracts(FuncDeclaration *f); - Statement *parseStatement(int flags); - Initializer *parseInitializer(); - Expression *parseDefaultInitExp(); - void check(Loc loc, enum TOK value); - void check(enum TOK value); - void check(enum TOK value, const char *string); - int isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt); - int isBasicType(Token **pt); - int isDeclarator(Token **pt, int *haveId, enum TOK endtok); - int isParameters(Token **pt); - int isExpression(Token **pt); - int isTemplateInstance(Token *t, Token **pt); - int skipParens(Token *t, Token **pt); - - Expression *parseExpression(); - Expression *parsePrimaryExp(); - Expression *parseUnaryExp(); - Expression *parsePostExp(Expression *e); - Expression *parseMulExp(); - Expression *parseAddExp(); - Expression *parseShiftExp(); - Expression *parseRelExp(); - Expression *parseEqualExp(); - Expression *parseCmpExp(); - Expression *parseAndExp(); - Expression *parseXorExp(); - Expression *parseOrExp(); - Expression *parseAndAndExp(); - Expression *parseOrOrExp(); - Expression *parseCondExp(); - Expression *parseAssignExp(); - - Expressions *parseArguments(); - - Expression *parseNewExp(Expression *thisexp); - - void addComment(Dsymbol *s, unsigned char *blockComment); -}; - -// Operator precedence - greater values are higher precedence - -enum PREC -{ - PREC_zero, - PREC_expr, - PREC_assign, - PREC_cond, - PREC_oror, - PREC_andand, - PREC_or, - PREC_xor, - PREC_and, - PREC_equal, - PREC_rel, - PREC_shift, - PREC_add, - PREC_mul, - PREC_unary, - PREC_primary, -}; - -extern enum PREC precedence[TOKMAX]; - -void initPrecedence(); - -#endif /* DMD_PARSE_H */ diff --git a/dmd/readme.txt b/dmd/readme.txt deleted file mode 100644 index 42a7a9df..00000000 --- a/dmd/readme.txt +++ /dev/null @@ -1,27 +0,0 @@ - - The D Programming Language - Compiler Front End Source - Copyright (c) 1999-2002, by Digital Mars - 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 -www.digitalmars.com/d/ - -The optimizer, code generator, and object file generator are not part -of this source, hence the source does not currently constitute a complete, -compilable program. However, many people have expressed a strong interested -in producing a D compiler with the GNU compiler sources. This release should -enable that. - -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). - -It does not apply to anything else distributed by Digital Mars, -including D compiler executables. - --Walter Bright diff --git a/dmd/rmem.h b/dmd/rmem.h deleted file mode 100644 index 5d84828d..00000000 --- a/dmd/rmem.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __RMEM_H__ -#define __RMEM_H__ - -// jam memory stuff here - -#include "mem.h" - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#ifdef __MINGW32__ -#include -#endif - -#endif // __RMEM_H__ diff --git a/dmd/root/aav.c b/dmd/root/aav.c deleted file mode 100644 index ca685d42..00000000 --- a/dmd/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/dmd/root/aav.h b/dmd/root/aav.h deleted file mode 100644 index 266b5a83..00000000 --- a/dmd/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/dmd/root/array.c b/dmd/root/array.c deleted file mode 100644 index 3ef48322..00000000 --- a/dmd/root/array.c +++ /dev/null @@ -1,256 +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 "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/dmd/root/async.c b/dmd/root/async.c deleted file mode 100644 index 78f17c68..00000000 --- a/dmd/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/dmd/root/async.h b/dmd/root/async.h deleted file mode 100644 index 6f25f367..00000000 --- a/dmd/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/dmd/root/gnuc.c b/dmd/root/gnuc.c deleted file mode 100644 index 8f33d839..00000000 --- a/dmd/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/dmd/root/gnuc.h b/dmd/root/gnuc.h deleted file mode 100644 index 00c9851d..00000000 --- a/dmd/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/dmd/root/longdouble.c b/dmd/root/longdouble.c deleted file mode 100644 index 8a0f00e7..00000000 --- a/dmd/root/longdouble.c +++ /dev/null @@ -1,636 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Rainer Schuetze -// 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. - -// 80 bit floating point value implementation for Microsoft compiler - -#if _MSC_VER -#include "longdouble.h" - -#include "assert.h" - -#include -#include -#include - -extern "C" -{ - // implemented in ldfpu.asm for _WIN64 - int ld_initfpu(int bits, int mask); - void ld_expl(longdouble* ld, int exp); - longdouble ld_add(longdouble ld1, longdouble ld2); - longdouble ld_sub(longdouble ld1, longdouble ld2); - longdouble ld_mul(longdouble ld1, longdouble ld2); - longdouble ld_div(longdouble ld1, longdouble ld2); - longdouble ld_mod(longdouble ld1, longdouble ld2); - bool ld_cmpb(longdouble ld1, longdouble ld2); - bool ld_cmpbe(longdouble ld1, longdouble ld2); - bool ld_cmpa(longdouble ld1, longdouble ld2); - bool ld_cmpae(longdouble ld1, longdouble ld2); - bool ld_cmpe(longdouble ld1, longdouble ld2); - bool ld_cmpne(longdouble ld1, longdouble ld2); - longdouble ld_sqrt(longdouble ld1); - longdouble ld_sin(longdouble ld1); - longdouble ld_cos(longdouble ld1); - longdouble ld_tan(longdouble ld1); -} - -bool initFPU() -{ -#ifdef _WIN64 -// int old_cw = ld_initfpu(_RC_NEAR); - int old_cw = ld_initfpu(0x300 /*_PC_64 | _RC_NEAR*/, // #defines NOT identical to CPU FPU control word! - 0xF00 /*_MCW_PC | _MCW_RC*/); -#else - int old_cw = _control87(_MCW_EM | _PC_64 | _RC_NEAR, - _MCW_EM | _MCW_PC | _MCW_RC); -#endif - return true; -} -static bool doInitFPU = initFPU(); - -#ifndef _WIN64 -extern "C" -{ - -double ld_read(const longdouble* pthis) -{ - double res; - __asm - { - mov eax, pthis - fld tbyte ptr [eax] - fstp res - } - return res; -} -long long ld_readll(const longdouble* pthis) -{ -#if 1 - return ld_readull(pthis); -#elif defined _WIN64 - return ld_readll(this); -#else - longdouble* pthis = this; - long long res; - __asm - { - mov eax, pthis - fld tbyte ptr [eax] - fistp qword ptr res - } - return res; -#endif -} - -unsigned long long ld_readull(const longdouble* pthis) -{ -#if 1 - // somehow the FPU does not respect the CHOP mode of the rounding control - // in 64-bit mode - // so we roll our own conversion (it also allows the usual C wrap-around - // instead of the "invalid value" created by the FPU) - int expo = pthis->exponent - 0x3fff; - unsigned long long u; - if(expo < 0 || expo > 127) - return 0; - if(expo < 64) - u = pthis->mantissa >> (63 - expo); - else - u = pthis->mantissa << (expo - 63); - if(pthis->sign) - u = ~u + 1; - return u; -#else - longdouble* pthis = this; - long long res; // cannot use unsigned, VC will not generate "fistp qword" - longdouble twoPow63 = { 1ULL << 63, 0x3fff + 63, 0 }; - __asm - { - mov eax, pthis - fld tbyte ptr [eax] - fld tbyte ptr twoPow63 - fsubp ST(1),ST(0) // move it into signed range - - lea eax, res - fistp qword ptr [eax] - } - res ^= (1LL << 63); - return res; -#endif -} - -void ld_set(longdouble* pthis, double d) -{ - __asm - { - mov eax, pthis - fld d - fstp tbyte ptr [eax] - } -} -void ld_setll(longdouble* pthis, long long d) -{ - __asm - { - fild qword ptr d - mov eax, pthis - fstp tbyte ptr [eax] - } -} -void ld_setull(longdouble* pthis, unsigned long long d) -{ - d ^= (1LL << 63); - longdouble twoPow63 = { 1ULL << 63, 0x3fff + 63, 0 }; - __asm - { - fild qword ptr d - fld tbyte ptr twoPow63 - faddp ST(1),ST(0) - mov eax, pthis - fstp tbyte ptr [eax] - } -} - -} // extern "C" -#endif // !_WIN64 - -longdouble ldexpl(longdouble ld, int exp) -{ -#ifdef _WIN64 - ld_expl(&ld, exp); -#else - __asm - { - fild dword ptr exp - fld tbyte ptr ld - fscale // ST(0) = ST(0) * (2**ST(1)) - fstp ST(1) - fstp tbyte ptr ld - } -#endif - return ld; -} - -/////////////////////////////////////////////////////////////////////// -longdouble operator+(longdouble ld1, longdouble ld2) -{ -#ifdef _WIN64 - return ld_add(ld1, ld2); -#else - longdouble res; - __asm - { - fld tbyte ptr ld1 - fld tbyte ptr ld2 - fadd - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble operator-(longdouble ld1, longdouble ld2) -{ -#ifdef _WIN64 - return ld_sub(ld1, ld2); -#else - longdouble res; - __asm - { - fld tbyte ptr ld1 - fld tbyte ptr ld2 - fsub - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble operator*(longdouble ld1, longdouble ld2) -{ -#ifdef _WIN64 - return ld_mul(ld1, ld2); -#else - longdouble res; - __asm - { - fld tbyte ptr ld1 - fld tbyte ptr ld2 - fmul - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble operator/(longdouble ld1, longdouble ld2) -{ -#ifdef _WIN64 - return ld_div(ld1, ld2); -#else - longdouble res; - __asm - { - fld tbyte ptr ld1 - fld tbyte ptr ld2 - fdiv - fstp tbyte ptr res; - } - return res; -#endif -} - -bool operator< (longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpb(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - setb AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator<=(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpbe(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - setbe AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator> (longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpa(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - seta AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator>=(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpae(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - setae AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator==(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpe(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - sete AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator!=(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpne(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - setne AL - setp AH - or AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} - - -int _isnan(longdouble ld) -{ - return (ld.exponent == 0x7fff && ld.mantissa != 0); -} - -longdouble fabsl(longdouble ld) -{ - ld.sign = 0; - return ld; -} - -longdouble sqrtl(longdouble ld) -{ -#ifdef _WIN64 - return ld_sqrt(ld); -#else - longdouble res; - __asm - { - fld tbyte ptr ld; - fsqrt; - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble sinl (longdouble ld) -{ -#ifdef _WIN64 - return ld_sin(ld); -#else - longdouble res; - __asm - { - fld tbyte ptr ld; - fsin; // exact for |x|<=PI/4 - fstp tbyte ptr res - } - return res; -#endif -} -longdouble cosl (longdouble ld) -{ -#ifdef _WIN64 - return ld_cos(ld); -#else - longdouble res; - __asm - { - fld tbyte ptr ld; - fcos; // exact for |x|<=PI/4 - fstp tbyte ptr res; - } - return res; -#endif -} -longdouble tanl (longdouble ld) -{ -#ifdef _WIN64 - return ld_tan(ld); -#else - longdouble res; - __asm - { - fld tbyte ptr ld; - fptan; - fstp ST(0); // always 1 - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble fmodl(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_mod(x, y); -#else - short sw; - longdouble res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y -FM1: // We don't use fprem1 because for some inexplicable - // reason we get -5 when we do _modulo(15, 10) - fprem // ST = ST % ST1 - fstsw word ptr sw - fwait - mov AH,byte ptr sw+1 // get msb of status word in AH - sahf // transfer to flags - jp FM1 // continue till ST < ST1 - fstp ST(1) // leave remainder on stack - fstp tbyte ptr res; - } - return res; -#endif -} - -////////////////////////////////////////////////////////////// - -longdouble ld_qnan = { 0x8000000000000000ULL, 0x7fff, 0 }; -longdouble ld_snan = { 0x0000000000000001ULL, 0x7fff, 0 }; -longdouble ld_inf = { 0x0000000000000000ULL, 0x7fff, 0 }; - -longdouble ld_zero = { 0, 0, 0 }; -longdouble ld_one = { 0x8000000000000000ULL, 0x3fff, 0 }; -longdouble ld_pi = { 0xc90fdaa22168c235ULL, 0x4000, 0 }; -longdouble ld_log2t = { 0xd49a784bcd1b8afeULL, 0x4000, 0 }; -longdouble ld_log2e = { 0xb8aa3b295c17f0bcULL, 0x3fff, 0 }; -longdouble ld_log2 = { 0x9a209a84fbcff799ULL, 0x3ffd, 0 }; -longdouble ld_ln2 = { 0xb17217f7d1cf79acULL, 0x3ffe, 0 }; - -longdouble ld_pi2 = ld_pi*2; -longdouble ld_piOver2 = ld_pi*0.5; -longdouble ld_piOver4 = ld_pi*0.25; - -////////////////////////////////////////////////////////////// - -#define LD_TYPE_OTHER 0 -#define LD_TYPE_ZERO 1 -#define LD_TYPE_INFINITE 2 -#define LD_TYPE_SNAN 3 -#define LD_TYPE_QNAN 4 - -int ld_type(longdouble x) -{ - if(x.exponent == 0) - return x.mantissa == 0 ? LD_TYPE_ZERO : LD_TYPE_OTHER; // dnormal if not zero - if(x.exponent != 0x7fff) - return LD_TYPE_OTHER; - if(x.mantissa == 0) - return LD_TYPE_INFINITE; - if(x.mantissa & (1LL << 63)) - return LD_TYPE_QNAN; - return LD_TYPE_SNAN; -} - -int ld_sprint(char* str, int fmt, longdouble x) -{ - // fmt is 'a','A','f' or 'g' - if(fmt != 'a' && fmt != 'A') - { - char format[] = { '%', fmt, 0 }; - return sprintf(str, format, ld_read(&x)); - } - - unsigned short exp = x.exponent; - unsigned long long mantissa = x.mantissa; - - switch(ld_type(x)) - { - case LD_TYPE_ZERO: - return sprintf(str, "0x0.0L"); - case LD_TYPE_QNAN: - case LD_TYPE_SNAN: - return sprintf(str, "NAN"); - case LD_TYPE_INFINITE: - return sprintf(str, x.sign ? "-INF" : "INF"); - } - - int len = 0; - if(x.sign) - str[len++] = '-'; - len += sprintf(str + len, mantissa & (1LL << 63) ? "0x1." : "0x0."); - mantissa = mantissa << 1; - while(mantissa) - { - int dig = (mantissa >> 60) & 0xf; - dig += dig < 10 ? '0' : fmt - 10; - str[len++] = dig; - mantissa = mantissa << 4; - } - str[len++] = 'p'; - if(exp < 0x3fff) - { - str[len++] = '-'; - exp = 0x3fff - exp; - } - else - { - str[len++] = '+'; - exp = exp - 0x3fff; - } - int exppos = len; - for(int i = 12; i >= 0; i -= 4) - { - int dig = (exp >> i) & 0xf; - if(dig != 0 || len > exppos || i == 0) - str[len++] = dig + (dig < 10 ? '0' : fmt - 10); - } - str[len] = 0; - return len; -} - -////////////////////////////////////////////////////////////// - -#if UNITTEST -static bool unittest() -{ - char buffer[32]; - ld_sprint(buffer, 'a', ld_pi); - assert(strcmp(buffer, "0x1.921fb54442d1846ap+1") == 0); - - longdouble ldb = ldouble(0.4); - long long b = ldb; - assert(b == 0); - - b = ldouble(0.9); - assert(b == 0); - - long long x = 0x12345678abcdef78LL; - longdouble ldx = ldouble(x); - assert(ldx > 0); - long long y = ldx; - assert(x == y); - - x = -0x12345678abcdef78LL; - ldx = ldouble(x); - assert(ldx < 0); - y = ldx; - assert(x == y); - - unsigned long long u = 0x12345678abcdef78LL; - longdouble ldu = ldouble(u); - assert(ldu > 0); - unsigned long long v = ldu; - assert(u == v); - - u = 0xf234567812345678ULL; - ldu = ldouble(u); - assert(ldu > 0); - v = ldu; - assert(u == v); - - u = 0xf2345678; - ldu = ldouble(u); - ldu = ldu * ldu; - ldu = sqrt(ldu); - v = ldu; - assert(u == v); - - u = 0x123456789A; - ldu = ldouble(u); - ldu = ldu * (1LL << 23); - v = ldu; - u = u * (1LL << 23); - assert(u == v); - - return true; -} - -static bool runUnittest = unittest(); - -#endif // UNITTEST - -#endif // _MSC_VER - diff --git a/dmd/root/longdouble.h b/dmd/root/longdouble.h deleted file mode 100644 index d25223a7..00000000 --- a/dmd/root/longdouble.h +++ /dev/null @@ -1,254 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Rainer Schuetze -// 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. - -// 80 bit floating point value implementation for Microsoft compiler - -#ifndef __LONG_DOUBLE_H__ -#define __LONG_DOUBLE_H__ - -#if IN_GCC -#include "d-gcc-real.h" -typedef real_t longdouble; - -template longdouble ldouble(T x) { return (longdouble) x; } -inline int ld_sprint(char* str, int fmt, longdouble x) -{ - if(fmt == 'a' || fmt == 'A') - return x.formatHex(buffer, 46); // don't know the size here, but 46 is the max - return x.format(buffer, 46); -} - -#elif !_MSC_VER // has native 10 byte doubles -#include -typedef long double longdouble; -typedef volatile long double volatile_longdouble; - -// also used from within C code, so use a #define rather than a template -// template longdouble ldouble(T x) { return (longdouble) x; } -#define ldouble(x) ((longdouble)(x)) - -inline int ld_sprint(char* str, int fmt, longdouble x) -{ - char sfmt[4] = "%Lg"; - sfmt[2] = fmt; - return sprintf(str, sfmt, x); -} - -#else - -#include -#include - -struct longdouble; - -extern "C" -{ - // implemented in ldfpu.asm for _WIN64 - double ld_read(const longdouble* ld); - long long ld_readll(const longdouble* ld); - unsigned long long ld_readull(const longdouble* ld); - void ld_set(longdouble* ld, double d); - void ld_setll(longdouble* ld, long long d); - void ld_setull(longdouble* ld, unsigned long long d); -} - -struct longdouble -{ - unsigned long long mantissa; - unsigned short exponent:15; // bias 0x3fff - unsigned short sign:1; - unsigned short fill:16; // for 12 byte alignment - - // no constructor to be able to use this class in a union - // use ldouble() to explicitely create a longdouble value - - template longdouble& operator=(T x) { set(x); return *this; } - - void set(longdouble ld) { mantissa = ld.mantissa; exponent = ld.exponent; sign = ld.sign; } - - // we need to list all basic types to avoid ambiguities - void set(float d) { ld_set(this, d); } - void set(double d) { ld_set(this, d); } - void set(long double d) { ld_set(this, d); } - - void set(signed char d) { ld_set(this, d); } - void set(short d) { ld_set(this, d); } - void set(int d) { ld_set(this, d); } - void set(long d) { ld_set(this, d); } - void set(long long d) { ld_setll(this, d); } - - void set(unsigned char d) { ld_set(this, d); } - void set(unsigned short d) { ld_set(this, d); } - void set(unsigned int d) { ld_set(this, d); } - void set(unsigned long d) { ld_set(this, d); } - void set(unsigned long long d) { ld_setull(this, d); } - void set(bool d) { ld_set(this, d); } - - operator float () { return ld_read(this); } - operator double () { return ld_read(this); } - - operator signed char () { return ld_read(this); } - operator short () { return ld_read(this); } - operator int () { return ld_read(this); } - operator long () { return ld_read(this); } - operator long long () { return ld_readll(this); } - - operator unsigned char () { return ld_read(this); } - operator unsigned short () { return ld_read(this); } - operator unsigned int () { return ld_read(this); } - operator unsigned long () { return ld_read(this); } - operator unsigned long long() { return ld_readull(this); } - operator bool () { return mantissa != 0 || exponent != 0; } // correct? -}; - -// some optimizations are avoided by adding volatile to the longdouble -// type, but this introduces bad ambiguities when using the class implementation above -// as we are going through asm these optimizations won't kick in anyway, so "volatile" -// is not required. -typedef longdouble volatile_longdouble; - -inline longdouble ldouble(unsigned long long mantissa, int exp, int sign = 0) -{ - longdouble d; - d.mantissa = mantissa; - d.exponent = exp; - d.sign = sign; - return d; -} -template inline longdouble ldouble(T x) { longdouble d; d.set(x); return d; } -//template inline longdouble ldouble(volatile T x) { longdouble d; d.set(x); return d; } - -longdouble operator+(longdouble ld1, longdouble ld2); -longdouble operator-(longdouble ld1, longdouble ld2); -longdouble operator*(longdouble ld1, longdouble ld2); -longdouble operator/(longdouble ld1, longdouble ld2); - -bool operator< (longdouble ld1, longdouble ld2); -bool operator<=(longdouble ld1, longdouble ld2); -bool operator> (longdouble ld1, longdouble ld2); -bool operator>=(longdouble ld1, longdouble ld2); -bool operator==(longdouble ld1, longdouble ld2); -bool operator!=(longdouble ld1, longdouble ld2); - -inline longdouble operator-(longdouble ld1) { ld1.sign ^= 1; return ld1; } -inline longdouble operator+(longdouble ld1) { return ld1; } - -template inline longdouble operator+(longdouble ld, T x) { return ld + ldouble(x); } -template inline longdouble operator-(longdouble ld, T x) { return ld - ldouble(x); } -template inline longdouble operator*(longdouble ld, T x) { return ld * ldouble(x); } -template inline longdouble operator/(longdouble ld, T x) { return ld / ldouble(x); } - -template inline longdouble operator+(T x, longdouble ld) { return ldouble(x) + ld; } -template inline longdouble operator-(T x, longdouble ld) { return ldouble(x) - ld; } -template inline longdouble operator*(T x, longdouble ld) { return ldouble(x) * ld; } -template inline longdouble operator/(T x, longdouble ld) { return ldouble(x) / ld; } - -template inline longdouble& operator+=(longdouble& ld, T x) { return ld = ld + x; } -template inline longdouble& operator-=(longdouble& ld, T x) { return ld = ld - x; } -template inline longdouble& operator*=(longdouble& ld, T x) { return ld = ld * x; } -template inline longdouble& operator/=(longdouble& ld, T x) { return ld = ld / x; } - -template inline bool operator< (longdouble ld, T x) { return ld < ldouble(x); } -template inline bool operator<=(longdouble ld, T x) { return ld <= ldouble(x); } -template inline bool operator> (longdouble ld, T x) { return ld > ldouble(x); } -template inline bool operator>=(longdouble ld, T x) { return ld >= ldouble(x); } -template inline bool operator==(longdouble ld, T x) { return ld == ldouble(x); } -template inline bool operator!=(longdouble ld, T x) { return ld != ldouble(x); } - -template inline bool operator< (T x, longdouble ld) { return ldouble(x) < ld; } -template inline bool operator<=(T x, longdouble ld) { return ldouble(x) <= ld; } -template inline bool operator> (T x, longdouble ld) { return ldouble(x) > ld; } -template inline bool operator>=(T x, longdouble ld) { return ldouble(x) >= ld; } -template inline bool operator==(T x, longdouble ld) { return ldouble(x) == ld; } -template inline bool operator!=(T x, longdouble ld) { return ldouble(x) != ld; } - -int _isnan(longdouble ld); - -longdouble fabsl(longdouble ld); -longdouble sqrtl(longdouble ld); -longdouble sinl (longdouble ld); -longdouble cosl (longdouble ld); -longdouble tanl (longdouble ld); - -longdouble fmodl(longdouble x, longdouble y); -longdouble ldexpl(longdouble ldval, int exp); // see strtold - -inline longdouble fabs (longdouble ld) { return fabsl(ld); } -inline longdouble sqrt (longdouble ld) { return sqrtl(ld); } - -#undef LDBL_DIG -#undef LDBL_MAX -#undef LDBL_MIN -#undef LDBL_EPSILON -#undef LDBL_MANT_DIG -#undef LDBL_MAX_EXP -#undef LDBL_MIN_EXP -#undef LDBL_MAX_10_EXP -#undef LDBL_MIN_10_EXP - -#define LDBL_DIG 18 -#define LDBL_MAX ldouble(0xffffffffffffffffULL, 0x7ffe) -#define LDBL_MIN ldouble(0x8000000000000000ULL, 1) -#define LDBL_EPSILON ldouble(0x8000000000000000ULL, 0x3fff - 63) // allow denormal? -#define LDBL_MANT_DIG 64 -#define LDBL_MAX_EXP 16384 -#define LDBL_MIN_EXP (-16381) -#define LDBL_MAX_10_EXP 4932 -#define LDBL_MIN_10_EXP (-4932) - -extern longdouble ld_zero; -extern longdouble ld_one; -extern longdouble ld_pi; -extern longdouble ld_log2t; -extern longdouble ld_log2e; -extern longdouble ld_log2; -extern longdouble ld_ln2; - -extern longdouble ld_inf; -extern longdouble ld_qnan; -extern longdouble ld_snan; - -/////////////////////////////////////////////////////////////////////// -// CLASS numeric_limits -template<> class _CRTIMP2_PURE std::numeric_limits -: public _Num_float_base -{ // limits for type long double -public: - typedef longdouble _Ty; - - static _Ty (__CRTDECL min)() _THROW0() { return LDBL_MIN; } - static _Ty (__CRTDECL max)() _THROW0() { return LDBL_MAX; } - static _Ty __CRTDECL epsilon() _THROW0() { return LDBL_EPSILON; } - static _Ty __CRTDECL round_error() _THROW0() { return ldouble(0.5); } - static _Ty __CRTDECL denorm_min() _THROW0() { return ldouble(0x0000000000000001ULL, 1); } - static _Ty __CRTDECL infinity() _THROW0() { return ld_inf; } - static _Ty __CRTDECL quiet_NaN() _THROW0() { return ld_qnan; } - static _Ty __CRTDECL signaling_NaN() _THROW0() { return ld_snan; } - - _STCONS(int, digits, LDBL_MANT_DIG); - _STCONS(int, digits10, LDBL_DIG); - _STCONS(int, max_exponent, (int)LDBL_MAX_EXP); - _STCONS(int, max_exponent10, (int)LDBL_MAX_10_EXP); - _STCONS(int, min_exponent, (int)LDBL_MIN_EXP); - _STCONS(int, min_exponent10, (int)LDBL_MIN_10_EXP); -}; - -//_STCONSDEF(numeric_limits, int, digits) -//_STCONSDEF(numeric_limits, int, digits10) -//_STCONSDEF(numeric_limits, int, max_exponent) -//_STCONSDEF(numeric_limits, int, max_exponent10) -//_STCONSDEF(numeric_limits, int, min_exponent) -//_STCONSDEF(numeric_limits, int, min_exponent10) - -int ld_sprint(char* str, int fmt, longdouble x); - -#endif // !_MSC_VER - -#endif // __LONG_DOUBLE_H__ diff --git a/dmd/root/man.c b/dmd/root/man.c deleted file mode 100644 index 3770aa96..00000000 --- a/dmd/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/dmd/root/port.c b/dmd/root/port.c deleted file mode 100644 index fce3c952..00000000 --- a/dmd/root/port.c +++ /dev/null @@ -1,663 +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; -longdouble Port::ldbl_max = LDBL_MAX; - -int Port::isNan(double r) -{ - return ::isnan(r); -} - -int Port::isNan(longdouble 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(longdouble 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); -} - -longdouble Port::fmodl(longdouble x, longdouble 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; -longdouble 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(longdouble 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(longdouble 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); -} - -longdouble Port::fmodl(longdouble x, longdouble 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__ || __MINGW32__ || __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; -longdouble 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(longdouble)] = - { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7F }; - Port::ldbl_max = *(longdouble *)&x[0]; - // FreeBSD defaults to double precision. Switch to extended precision. - fpsetprec(FP_PE); -#endif -} - -int Port::isNan(double r) -{ -#if __APPLE__ -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 - return __inline_isnand(r); -#else - return __inline_isnan(r); -#endif -#elif __OpenBSD__ || __MINGW32__ || __HAIKU__ - return isnan(r); -#else - #undef isnan - return ::isnan(r); -#endif -} - -int Port::isNan(longdouble r) -{ -#if __APPLE__ -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 - return __inline_isnanl(r); -#else - return __inline_isnan(r); -#endif -#elif __OpenBSD__ || __MINGW32__ || __HAIKU__ - 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(longdouble 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) -{ -#if __APPLE__ - return fpclassify(r) == FP_INFINITE; -#elif __OpenBSD__ || __MINGW32__ || __HAIKU__ - 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); -} - -longdouble Port::fmodl(longdouble x, longdouble 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 -#ifndef __MINGW32__ - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); -#else - _snwprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); -#endif -#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; -longdouble 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 longdouble 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(longdouble 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(longdouble 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 - diff --git a/dmd/root/port.h b/dmd/root/port.h deleted file mode 100644 index bcd3dafc..00000000 --- a/dmd/root/port.h +++ /dev/null @@ -1,83 +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. - -#include "longdouble.h" - -#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 -longdouble strtold(const char *p,char **endp); -#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 longdouble ldbl_max; - -#if __OpenBSD__ -#elif __GNUC__ && !defined __HAIKU__ - // 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(longdouble); - - static int isSignallingNan(double); - static int isSignallingNan(longdouble); - - static int isFinite(double); - static int isInfinity(double); - static int Signbit(double); - - static double floor(double); - static double pow(double x, double y); - - static longdouble fmodl(longdouble x, longdouble 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/dmd/root/root.c b/dmd/root/root.c deleted file mode 100644 index 71d2bd81..00000000 --- a/dmd/root/root.c +++ /dev/null @@ -1,1992 +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. - -#ifndef POSIX -#define POSIX (linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4) -#endif - -#include -#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 "rmem.h" -#include "mars.h" - -#if 0 //__SC__ //def DEBUG -extern "C" void __cdecl _assert(void *e, void *f, unsigned line) -{ - printf("Assert('%s','%s',%d)\n",e,f,line); - fflush(stdout); - *(char *)0 = 0; -} -#endif - - -/************************************* - * Convert wchar string to ascii string. - */ - -char *wchar2ascii(wchar_t *us) -{ - return wchar2ascii(us, wcslen(us)); -} - -char *wchar2ascii(wchar_t *us, unsigned len) -{ - unsigned i; - char *p; - - p = (char *)mem.malloc(len + 1); - for (i = 0; i <= len; i++) - p[i] = (char) us[i]; - return p; -} - -int wcharIsAscii(wchar_t *us) -{ - return wcharIsAscii(us, wcslen(us)); -} - -int wcharIsAscii(wchar_t *us, unsigned len) -{ - unsigned i; - - for (i = 0; i <= len; i++) - { - if (us[i] & ~0xFF) // if high bits set - return 0; // it's not ascii - } - return 1; -} - - -/*********************************** - * Compare length-prefixed strings (bstr). - */ - -int bstrcmp(unsigned char *b1, unsigned char *b2) -{ - return (*b1 == *b2 && memcmp(b1 + 1, b2 + 1, *b2) == 0) ? 0 : 1; -} - -/*************************************** - * Convert bstr into a malloc'd string. - */ - -char *bstr2str(unsigned char *b) -{ - char *s; - unsigned len; - - len = *b; - s = (char *) mem.malloc(len + 1); - s[len] = 0; - return (char *)memcpy(s,b + 1,len); -} - -/************************************** - * Print error message and exit. - */ - -void error(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - printf("Error: "); - vprintf(format, ap); - va_end( ap ); - printf("\n"); - fflush(stdout); - - exit(EXIT_FAILURE); -} - -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"; -} - -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 - // LDC remember first character - const char* start = p; - 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 '~': - // LDC don't expand unless first character of path - if (p != start) - goto Ldefault; - 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: - Ldefault: - 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%llx off end of file",toChars(),(ulonglong)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) - { -#if defined (__x86_64__) - size = (offset + nbytes) * 2 + 2; -#else - size = (offset + nbytes) * 2; -#endif - 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::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 - writeword(0x0A0D); // newline is CR,LF on Microsoft OS's -#else - writeByte('\n'); -#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::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 0 && _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("%l")); \ - 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); -} - -void OutBuffer::printf(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - vprintf(format,ap); - va_end(ap); -} - -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/dmd/root/root.h b/dmd/root/root.h deleted file mode 100644 index 387218b3..00000000 --- a/dmd/root/root.h +++ /dev/null @@ -1,422 +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 - -#ifndef IS_PRINTF -# ifdef __GNUC__ -# define IS_PRINTF(FMTARG) __attribute((__format__ (__printf__, (FMTARG), (FMTARG)+1) )) -# else -# define IS_PRINTF(FMTARG) -# endif -#endif - -typedef size_t hash_t; - -#include "longdouble.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, ...) IS_PRINTF(1); -#if M_UNICODE -void error(const dchar *format, ...); -#endif -void warning(const char *format, ...) IS_PRINTF(1); - -#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 -longdouble strtold(const char *p,char **endp); -#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 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 prependstring(const char *string); - void writenl(); // write newline - void writeByte(unsigned b); - void writebyte(unsigned b) { writeByte(b); } - void writeUTF8(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, ...) IS_PRINTF(2); -#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/dmd/root/stringtable.c b/dmd/root/stringtable.c deleted file mode 100644 index 58dcd0b6..00000000 --- a/dmd/root/stringtable.c +++ /dev/null @@ -1,189 +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 // uint{8|16|32}_t -#include // memcpy() -#include - -#include "root.h" -#include "rmem.h" // mem -#include "stringtable.h" - -hash_t calcHash(const char *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; - } - } -} - -void StringValue::ctor(const char *p, unsigned length) -{ - this->length = length; - this->lstring[length] = 0; - memcpy(this->lstring, p, length * sizeof(char)); -} - -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 char *s, unsigned len); -}; - -StringEntry *StringEntry::alloc(const char *s, unsigned len) -{ - StringEntry *se; - - se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) + len + 1); - se->value.ctor(s, len); - se->hash = calcHash(s,len); - return se; -} - -void **StringTable::search(const char *s, unsigned len) -{ - hash_t hash; - unsigned u; - int cmp; - StringEntry **se; - - //printf("StringTable::search(%p,%d)\n",s,len); - hash = 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.len() - len; - if (cmp == 0) - { - cmp = ::memcmp(s,(*se)->value.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 char *s, unsigned len) -{ StringEntry *se; - - se = *(StringEntry **)search(s,len); - if (se) - return &se->value; - else - return NULL; -} - -StringValue *StringTable::update(const char *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 char *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/dmd/root/stringtable.h b/dmd/root/stringtable.h deleted file mode 100644 index 170894e6..00000000 --- a/dmd/root/stringtable.h +++ /dev/null @@ -1,71 +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" - -struct StringEntry; - -// StringValue is a variable-length structure as indicated by the last array -// member with unspecified size. It has neither proper c'tors nor a factory -// method because the only thing which should be creating these is StringTable. -struct StringValue -{ - union - { - void *ptrvalue; - char *string; - }; -private: - unsigned length; - -#ifndef IN_GCC - // Disable warning about nonstandard extension - #pragma warning (disable : 4200) -#endif - char lstring[]; - -public: - unsigned len() const { return length; } - const char *toDchars() const { return lstring; } - -private: - friend struct StringEntry; - StringValue(); // not constructible - // This is more like a placement new c'tor - void ctor(const char *p, unsigned length); -}; - -struct StringTable -{ -private: - void **table; - unsigned count; - unsigned tabledim; - -public: - void init(unsigned size = 37); - ~StringTable(); - - StringValue *lookup(const char *s, unsigned len); - StringValue *insert(const char *s, unsigned len); - StringValue *update(const char *s, unsigned len); - -private: - void **search(const char *s, unsigned len); -}; - -#endif diff --git a/dmd/scope.c b/dmd/scope.c deleted file mode 100644 index 0e2592f4..00000000 --- a/dmd/scope.c +++ /dev/null @@ -1,400 +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 // strlen() - -#include "root.h" -#include "speller.h" - -#include "mars.h" -#include "init.h" -#include "identifier.h" -#include "scope.h" -#include "attrib.h" -#include "dsymbol.h" -#include "declaration.h" -#include "aggregate.h" -#include "module.h" -#include "id.h" -#include "lexer.h" - -Scope *Scope::freelist = NULL; - -void *Scope::operator new(size_t size) -{ - if (freelist) - { - Scope *s = freelist; - freelist = s->enclosing; - //printf("freelist %p\n", s); - assert(s->flags & SCOPEfree); - s->flags &= ~SCOPEfree; - return s; - } - - void *p = ::operator new(size); - //printf("new %p\n", p); - return p; -} - -Scope::Scope() -{ // Create root scope - - //printf("Scope::Scope() %p\n", this); - this->module = NULL; - this->scopesym = NULL; - this->sd = NULL; - this->enclosing = NULL; - this->parent = NULL; - this->sw = NULL; - this->enclosingFinally = NULL; - this->enclosingScopeExit = NULL; - this->tinst = NULL; - this->sbreak = NULL; - this->scontinue = NULL; - this->fes = NULL; - this->structalign = global.structalign; - this->func = NULL; - this->slabel = NULL; - this->linkage = LINKd; - this->protection = PROTpublic; - this->explicitProtection = 0; - this->stc = 0; - this->offset = 0; - this->inunion = 0; - this->incontract = 0; - this->nofree = 0; - this->noctor = 0; - this->noaccesscheck = 0; - this->mustsemantic = 0; - this->intypeof = 0; - this->parameterSpecialization = 0; - this->callSuper = 0; - this->flags = 0; - this->lastdc = NULL; - this->lastoffset = 0; - this->docbuf = NULL; -} - -Scope::Scope(Scope *enclosing) -{ - //printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this); - assert(!(enclosing->flags & SCOPEfree)); - this->module = enclosing->module; - this->func = enclosing->func; - this->parent = enclosing->parent; - this->scopesym = NULL; - this->sd = NULL; - this->sw = enclosing->sw; - this->enclosingFinally = enclosing->enclosingFinally; - this->enclosingScopeExit = enclosing->enclosingScopeExit; - this->tinst = enclosing->tinst; - this->sbreak = enclosing->sbreak; - this->scontinue = enclosing->scontinue; - this->fes = enclosing->fes; - this->structalign = enclosing->structalign; - this->enclosing = enclosing; -#ifdef DEBUG - if (enclosing->enclosing) - assert(!(enclosing->enclosing->flags & SCOPEfree)); - if (this == enclosing->enclosing) - { - printf("this = %p, enclosing = %p, enclosing->enclosing = %p\n", this, enclosing, enclosing->enclosing); - } - assert(this != enclosing->enclosing); -#endif - this->slabel = NULL; - this->linkage = enclosing->linkage; - this->protection = enclosing->protection; - this->explicitProtection = enclosing->explicitProtection; - this->stc = enclosing->stc; - this->offset = 0; - this->inunion = enclosing->inunion; - this->incontract = enclosing->incontract; - this->nofree = 0; - this->noctor = enclosing->noctor; - this->noaccesscheck = enclosing->noaccesscheck; - this->mustsemantic = enclosing->mustsemantic; - this->intypeof = enclosing->intypeof; - this->parameterSpecialization = enclosing->parameterSpecialization; - this->callSuper = enclosing->callSuper; - this->flags = 0; - this->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/dmd/scope.h b/dmd/scope.h deleted file mode 100644 index 2fc23af6..00000000 --- a/dmd/scope.h +++ /dev/null @@ -1,130 +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. - -#ifndef DMD_SCOPE_H -#define DMD_SCOPE_H - -#ifdef __DMC__ -#pragma once -#endif - -struct Dsymbol; -struct ScopeDsymbol; -struct Array; -struct Identifier; -struct Module; -struct Statement; -struct SwitchStatement; -struct TryFinallyStatement; -struct LabelStatement; -struct ForeachStatement; -struct ClassDeclaration; -struct AggregateDeclaration; -struct AnonymousAggregateDeclaration; -struct FuncDeclaration; -struct DocComment; -struct TemplateInstance; - -#if IN_LLVM -struct EnclosingHandler; -struct AnonDeclaration; -#endif - -#if __GNUC__ -// Requires a full definition for PROT and LINK -#include "dsymbol.h" // PROT -#include "mars.h" // LINK -#else -enum LINK; -enum PROT; -#endif - -struct Scope -{ - Scope *enclosing; // enclosing Scope - - Module *module; // Root module - ScopeDsymbol *scopesym; // current symbol - ScopeDsymbol *sd; // if in static if, and declaring new symbols, - // sd gets the addMember() - FuncDeclaration *func; // function we are in - Dsymbol *parent; // parent to use - LabelStatement *slabel; // enclosing labelled statement - SwitchStatement *sw; // enclosing switch statement - TryFinallyStatement *enclosingFinally; // enclosing try finally statement; set inside its finally block - TemplateInstance *tinst; // enclosing template instance - Statement *enclosingScopeExit; // enclosing statement that wants to do something on scope exit - Statement *sbreak; // enclosing statement that supports "break" - Statement *scontinue; // enclosing statement that supports "continue" - ForeachStatement *fes; // if nested function for ForeachStatement, this is it - unsigned offset; // next offset to use in aggregate - // This really shouldn't be a part of Scope, because it requires - // semantic() to be done in the lexical field order. It should be - // set in a pass after semantic() on all fields so they can be - // semantic'd in any order. - int inunion; // we're processing members of a union - int incontract; // we're inside contract code - int nofree; // set if shouldn't free it - int noctor; // set if constructor calls aren't allowed - int intypeof; // in typeof(exp) - int parameterSpecialization; // if in template parameter specialization - int noaccesscheck; // don't do access checks - int mustsemantic; // cannot defer semantic() - - unsigned callSuper; // primitive flow analysis for constructors -#define CSXthis_ctor 1 // called this() -#define CSXsuper_ctor 2 // called super() -#define CSXthis 4 // referenced this -#define CSXsuper 8 // referenced super -#define CSXlabel 0x10 // seen a label -#define CSXreturn 0x20 // seen a return statement -#define CSXany_ctor 0x40 // either this() or super() was called - - structalign_t 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 - - - 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/dmd/sideeffect.c b/dmd/sideeffect.c deleted file mode 100644 index 9cc43b70..00000000 --- a/dmd/sideeffect.c +++ /dev/null @@ -1,34 +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" - -/******************************************** - * Determine if Expression has any side effects. - */ - -bool Expression::hasSideEffect() -{ - return checkSideEffect(2); -} - diff --git a/dmd/speller.c b/dmd/speller.c deleted file mode 100644 index 0a93b0e9..00000000 --- a/dmd/speller.c +++ /dev/null @@ -1,262 +0,0 @@ - -#include -#include -#include -#include - -#if __sun&&__SVR4 || _MSC_VER -#include -#endif -#if _MSC_VER -#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/dmd/speller.h b/dmd/speller.h deleted file mode 100644 index bfffb739..00000000 --- a/dmd/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/dmd/statement.c b/dmd/statement.c deleted file mode 100644 index 7d412d45..00000000 --- a/dmd/statement.c +++ /dev/null @@ -1,4665 +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 "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" - -/*********************************** - * Return size of OS critical section. - */ -#if IN_LLVM - -#if linux || __APPLE__ || __FreeBSD__ || __HAIKU__ || __sun&&__SVR4 -#include // Needs pthread_mutex_t for os_critsecsize -#elif _WIN32 -#include -#endif - -// sizes based on those from tollvm.cpp:DtoMutexType() -int os_critsecsize() -{ -#if defined(_MSC_VER) - // Return sizeof(RTL_CRITICAL_SECTION) - return global.params.is64bit ? 40 : 24; -#else - if (global.params.targetTriple.isOSWindows()) - return global.params.is64bit ? 40 : 24; - else if (global.params.targetTriple.getOS() == llvm::Triple::FreeBSD) - 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 - */ -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; -} - -/**************************************** - * If this statement has code that needs to run in a finally clause - * at the end of the current scope, return that code in the form of - * a Statement. - * Output: - * *sentry code executed upon entry to the scope - * *sexception code executed upon exit from the scope via exception - * *sfinally code executed in finally block - */ - -void Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("Statement::scopeCode()\n"); - //print(); - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; -} - -/********************************* - * Flatten out the scope by presenting the statement - * as an array of statements. - * Returns NULL if no flattening necessary. - */ - -Statements *Statement::flatten(Scope *sc) -{ - return NULL; -} - - -/******************************** PeelStatement ***************************/ - -PeelStatement::PeelStatement(Statement *s) - : Statement(s->loc) -{ - this->s = s; -} - -Statement *PeelStatement::semantic(Scope *sc) -{ - /* "peel" off this wrapper, and don't run semantic() - * on the result. - */ - return s; -} - -/******************************** ExpStatement ***************************/ - -ExpStatement::ExpStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -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()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp->checkSideEffect(0); - 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()) - result |= BEthrow; - } - return result; -} - -int ExpStatement::isEmpty() -{ - return exp == NULL; -} - -void 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) - { - Expression *e = v->callScopeDtor(sc); - if (e) - { - //printf("dtor is: "); e->print(); -#if 0 - if (v->type->toBasetype()->ty == Tstruct) - { /* Need a 'gate' to turn on/off destruction, - * in case v gets moved elsewhere. - */ - Identifier *id = Lexer::uniqueId("__runDtor"); - ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(1)); - VarDeclaration *rd = new VarDeclaration(loc, Type::tint32, id, ie); - *sentry = new 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 ExpStatement(loc, e); - } - } - } - } -} - -/******************************** 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->ctfeInterpret(); - 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); -} - - -/******************************** 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->data[i] = s; - } - CompoundStatement *cs = new CompoundStatement(loc, a); - return cs; -} - - -Statement *CompoundStatement::semantic(Scope *sc) -{ Statement *s; - - //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc); - - for (size_t i = 0; i < statements->dim; ) - { - s = (*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; - - s->scopeCode(sc, &sentry, &sexception, &sfinally); - if (sentry) - { - sentry = sentry->semantic(sc); - statements->data[i] = sentry; - } - 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; -} - -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; - 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 (!(result & BEfallthru) && !s->comeFrom()) - { - if (s->blockExit(mustNotThrow) != BEhalt && !s->isEmpty()) - s->warning("statement is not reachable"); - } - else - { - result &= ~BEfallthru; - result |= s->blockExit(mustNotThrow); - } - } - } - 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->data[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; - assert(de->op == TOKdeclaration); - Declaration *d = de->declaration->isDeclaration(); - assert(d); - VarDeclaration *v = d->isVarDeclaration(); - if (v) - { - /* This essentially copies the part of VarDeclaration::toCBuffer() - * that does not print the type. - * Should refactor this. - */ - if (nwritten) - { - buf->writeByte(','); - buf->writestring(v->ident->toChars()); - } - else - { - StorageClassDeclaration::stcToCBuffer(buf, v->storage_class); - if (v->type) - v->type->toCBuffer(buf, v->ident, hgs); - else - buf->writestring(v->ident->toChars()); - } - - if (v->init) - { buf->writestring(" = "); -#if DMDV2 - ExpInitializer *ie = v->init->isExpInitializer(); - if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) - ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); - else -#endif - v->init->toCBuffer(buf, hgs); - } - } - else - d->toCBuffer(buf, hgs); - nwritten++; - } - } - buf->writeByte(';'); - if (!hgs->FLinit.init) - buf->writenl(); -} - -/**************************** UnrolledLoopStatement ***************************/ - -UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s) - : Statement(loc) -{ - statements = s; -} - -Statement *UnrolledLoopStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - s = s->syntaxCopy(); - a->data[i] = s; - } - UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); - return cs; -} - - -Statement *UnrolledLoopStatement::semantic(Scope *sc) -{ - //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); - - sc->noctor++; - Scope *scd = sc->push(); - scd->sbreak = this; - scd->scontinue = this; - - for (size_t i = 0; i < statements->dim; i++) - { - Statement *s = (*statements)[i]; - if (s) - { - //printf("[%d]: %s\n", i, s->toChars()); - s = s->semantic(scd); - statements->data[i] = s; - } - } - - scd->pop(); - sc->noctor--; - return this; -} - -void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("unrolled {"); - buf->writenl(); - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s; - - s = (*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->scopeCode(sc, &sentry, &sexception, &sfinally); - if (sfinally) - { - //printf("adding sfinally\n"); - sfinally = sfinally->semantic(sc); - statement = new CompoundStatement(loc, statement, sfinally); - } - } - - sc->pop(); - } - return this; -} - -int ScopeStatement::hasBreak() -{ - //printf("ScopeStatement::hasBreak() %s\n", toChars()); - return statement ? statement->hasBreak() : FALSE; -} - -int ScopeStatement::hasContinue() -{ - return statement ? statement->hasContinue() : FALSE; -} - -int ScopeStatement::usesEH() -{ - return statement ? statement->usesEH() : FALSE; -} - -int ScopeStatement::blockExit(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()) - 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(); - - 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()) - result |= BEthrow; - if (!(result & BEbreak) && condition->isBool(TRUE)) - result &= ~BEfallthru; - } - result &= ~(BEbreak | BEcontinue); - return result; -} - - -int DoStatement::comeFrom() -{ - if (body) - return body->comeFrom(); - return FALSE; -} - -void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("do"); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writestring("while ("); - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); -} - -/******************************** ForStatement ***************************/ - -ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body) - : Statement(loc) -{ - this->init = init; - this->condition = condition; - this->increment = increment; - this->body = body; -} - -Statement *ForStatement::syntaxCopy() -{ - Statement *i = NULL; - if (init) - i = init->syntaxCopy(); - Expression *c = NULL; - if (condition) - c = condition->syntaxCopy(); - Expression *inc = NULL; - if (increment) - inc = increment->syntaxCopy(); - ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy()); - return s; -} - -Statement *ForStatement::semantic(Scope *sc) -{ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - if (init) - init = init->semantic(sc); -#if 0 - if (!condition) - // Use a default value - condition = new IntegerExp(loc, 1, Type::tboolean); -#endif - sc->noctor++; - if (condition) - { - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - condition = condition->checkToBoolean(); - } - if (increment) - { increment = increment->semantic(sc); - increment = resolveProperties(sc, increment); - increment = increment->optimize(0); - } - - sc->sbreak = this; - sc->scontinue = this; - if (body) - body = body->semanticNoScope(sc); - sc->noctor--; - - sc->pop(); - return this; -} - -void ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("ForStatement::scopeCode()\n"); - //print(); - if (init) - init->scopeCode(sc, sentry, sexception, sfinally); - else - Statement::scopeCode(sc, sentry, sexception, sfinally); -} - -int ForStatement::hasBreak() -{ - //printf("ForStatement::hasBreak()\n"); - return TRUE; -} - -int ForStatement::hasContinue() -{ - return TRUE; -} - -int ForStatement::usesEH() -{ - return (init && init->usesEH()) || body->usesEH(); -} - -int ForStatement::blockExit(bool mustNotThrow) -{ int result = BEfallthru; - - if (init) - { result = init->blockExit(mustNotThrow); - if (!(result & BEfallthru)) - return result; - } - if (condition) - { if (condition->canThrow()) - result |= BEthrow; - if (condition->isBool(TRUE)) - result &= ~BEfallthru; - else if (condition->isBool(FALSE)) - return result; - } - else - result &= ~BEfallthru; // the body must do the exiting - if (body) - { int r = body->blockExit(mustNotThrow); - if (r & (BEbreak | BEgoto)) - result |= BEfallthru; - result |= r & ~(BEfallthru | BEbreak | BEcontinue); - } - if (increment && increment->canThrow()) - result |= BEthrow; - return result; -} - - -int ForStatement::comeFrom() -{ - //printf("ForStatement::comeFrom()\n"); - if (body) - { int result = body->comeFrom(); - //printf("result = %d\n", result); - return result; - } - return FALSE; -} - -void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("for ("); - if (init) - { - hgs->FLinit.init++; - init->toCBuffer(buf, hgs); - hgs->FLinit.init--; - } - else - buf->writebyte(';'); - if (condition) - { buf->writebyte(' '); - condition->toCBuffer(buf, hgs); - } - buf->writebyte(';'); - if (increment) - { buf->writebyte(' '); - increment->toCBuffer(buf, hgs); - } - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/******************************** ForeachStatement ***************************/ - -ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Parameters *arguments, - Expression *aggr, Statement *body) - : Statement(loc) -{ - this->op = op; - this->arguments = arguments; - this->aggr = aggr; - this->body = body; - - this->key = NULL; - this->value = NULL; - - this->func = NULL; - - this->cases = NULL; - this->gotos = NULL; -} - -Statement *ForeachStatement::syntaxCopy() -{ - //printf("ForeachStatement::syntaxCopy()\n"); - 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; - - Type *tn = NULL; - Type *tnv = NULL; - - func = sc->func; - if (func->fes) - func = func->fes->func; - - aggr = aggr->semantic(sc); - aggr = resolveProperties(sc, aggr); - aggr = aggr->optimize(WANTvalue); - if (!aggr->type) - { - error("invalid foreach aggregate %s", aggr->toChars()); - return this; - } - if (aggr->type->toBasetype()->ty == Terror) - return NULL; - - inferApplyArgTypes(op, arguments, aggr, sc->module); - - /* Check for inference errors - */ - if (dim != arguments->dim) - { - //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim); - error("cannot uniquely infer foreach argument types"); - return this; - } - - Type *tab = aggr->type->toBasetype(); - - if (tab->ty == Ttuple) // don't generate new scope for tuple loops - { - if (dim < 1 || dim > 2) - { - error("only one (value) or two (key,value) arguments for tuple foreach"); - return s; - } - - TypeTuple *tuple = (TypeTuple *)tab; - Statements *statements = new Statements(); - //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); - size_t n; - TupleExp *te = NULL; - if (aggr->op == TOKtuple) // expression tuple - { te = (TupleExp *)aggr; - n = te->exps->dim; - } - else if (aggr->op == TOKtype) // type tuple - { - n = Parameter::dim(tuple->arguments); - } - else - assert(0); - for (size_t j = 0; j < n; j++) - { size_t k = (op == TOKforeach) ? j : n - 1 - j; - Expression *e; - Type *t; - if (te) - e = (*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 |= STCconst; - DeclarationExp *de = new DeclarationExp(loc, var); - st->push(new ExpStatement(loc, de)); - arg = (*arguments)[1]; // value - } - // Declare value - if (arg->storageClass & (STCout | STCref | STClazy)) - error("no storage class for value %s", arg->ident->toChars()); - Dsymbol *var; - if (te) - { Type *tb = e->type->toBasetype(); - 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); - } - else if (e->op == TOKtype) - { - var = new AliasDeclaration(loc, arg->ident, e->type); - } - else - { - arg->type = e->type; - Initializer *ie = new ExpInitializer(0, e); - VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); - if (e->isConst() || e->op == TOKstring) - v->storage_class |= STCconst; - var = v; - } - } - else - { - var = new AliasDeclaration(loc, arg->ident, t); - } - DeclarationExp *de = new DeclarationExp(loc, var); - st->push(new ExpStatement(loc, de)); - - st->push(body->syntaxCopy()); - s = new CompoundStatement(loc, st); - s = new ScopeStatement(loc, s); - statements->push(s); - } - - s = new UnrolledLoopStatement(loc, statements); - s = s->semantic(sc); - return s; - } - - for (size_t i = 0; i < dim; i++) - { Parameter *arg = (Parameter *)arguments->data[i]; - if (!arg->type) - { - error("cannot infer type for %s", arg->ident->toChars()); - return this; - } - } - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - sc->noctor++; - - switch (tab->ty) - { - case Tarray: - case Tsarray: - 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); - - if (dim == 2 && i == 0) - key = var; - else - value = var; -#if 0 - DeclarationExp *de = new DeclarationExp(loc, var); - de->semantic(sc); -#endif - } - -#if 1 - { - /* Convert to a ForStatement - * foreach (key, value; a) body => - * for (T[] tmp = a[], size_t key; key < tmp.length; ++key) - * { T value = tmp[k]; body } - * - * foreach_reverse (key, value; a) body => - * for (T[] tmp = a[], size_t key = tmp.length; key--; ) - * { T value = tmp[k]; body } - */ - Identifier *id = Lexer::uniqueId("__aggr"); - ExpInitializer *ie = new ExpInitializer(loc, new SliceExp(loc, aggr, NULL, NULL)); - VarDeclaration *tmp = new VarDeclaration(loc, aggr->type->nextOf()->arrayOf(), id, ie); - - Expression *tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id::length); - - if (!key) - { - Identifier *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); - - ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); - s = fs->semantic(sc); - break; - } -#else - if (!value->type->equals(tab->next)) - { - 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: - taa = (TypeAArray *)tab; - if (dim < 1 || dim > 2) - { - error("only one or two arguments for associative array foreach"); - break; - } - if (op == TOKforeach_reverse) - { - error("no reverse iteration on associative arrays"); - } - goto Lapply; - - case Tclass: - case Tstruct: -#if DMDV2 - { /* Look for range iteration, i.e. the properties - * .empty, .next, .retreat, .head and .rear - * foreach (e; aggr) { ... } - * translates to: - * for (auto __r = aggr[]; !__r.empty; __r.next) - * { auto e = __r.head; - * ... - * } - */ - if (dim != 1) // only one argument allowed with ranges - goto Lapply; - AggregateDeclaration *ad = (tab->ty == Tclass) - ? (AggregateDeclaration *)((TypeClass *)tab)->sym - : (AggregateDeclaration *)((TypeStruct *)tab)->sym; - Identifier *idhead; - Identifier *idnext; - if (op == TOKforeach) - { idhead = Id::Fhead; - idnext = Id::Fnext; - } - else - { idhead = Id::Ftoe; - idnext = Id::Fretreat; - } - Dsymbol *shead = search_function(ad, idhead); - if (!shead) - goto Lapply; - - /* Generate a temporary __r and initialize it with the aggregate. - */ - Identifier *id = Identifier::generateId("__r"); - Expression *rinit = new SliceExp(loc, aggr, NULL, NULL); - rinit = rinit->trySemantic(sc); - if (!rinit) // if application of [] failed - rinit = aggr; - VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, rinit)); -// r->semantic(sc); -//printf("r: %s, init: %s\n", r->toChars(), r->init->toChars()); - Statement *init = new ExpStatement(loc, r); -//printf("init: %s\n", init->toChars()); - - // !__r.empty - Expression *e = new VarExp(loc, r); - e = new DotIdExp(loc, e, Id::Fempty); - Expression *condition = new NotExp(loc, e); - - // __r.next - e = new VarExp(loc, r); - Expression *increment = new DotIdExp(loc, e, idnext); - - /* Declaration statement for e: - * auto e = __r.idhead; - */ - e = new VarExp(loc, r); - Expression *einit = new DotIdExp(loc, e, idhead); -// einit = einit->semantic(sc); - Parameter *arg = (*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); - - Statement *body = new CompoundStatement(loc, - new ExpStatement(loc, de), this->body); - - s = new ForStatement(loc, init, condition, increment, body); -#if 0 - printf("init: %s\n", init->toChars()); - printf("condition: %s\n", condition->toChars()); - printf("increment: %s\n", increment->toChars()); - printf("body: %s\n", body->toChars()); -#endif - s = s->semantic(sc); - break; - } -#endif - case Tdelegate: - Lapply: - { - Expression *ec; - Expression *e; - Parameter *a; - TypeDelegate* dgty; - TypeDelegate* dgty2; - TypeDelegate* fldeTy; - - Type *tret = func->type->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 (arg->storageClass & STCref) - id = arg->ident; - else - { // Make a copy of the ref argument so it isn't - // a reference. - - id = Lexer::uniqueId("__applyArg", i); - Initializer *ie = new ExpInitializer(0, new IdentifierExp(0, id)); - VarDeclaration *v = new VarDeclaration(0, arg->type, arg->ident, ie); - s = new ExpStatement(0, v); - body = new CompoundStatement(loc, s, body); - } - a = new Parameter(STCref, arg->type, id, NULL); - args->push(a); - } - Type *t = new TypeFunction(args, Type::tint32, 0, LINKd); - cases = new Statements(); - gotos = new CompoundStatements(); - FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this); - fld->fbody = body; - Expression *flde = new FuncExp(loc, fld); - flde = flde->semantic(sc); - - // 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"); - } - FuncDeclaration *fdapply; - 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->key->size(); - if (global.params.is64bit) - keysize = (keysize + 15) & ~15; - else - keysize = (keysize + PTRSIZE - 1) & ~(PTRSIZE - 1); - exps->push(new IntegerExp(0, keysize, Type::tsize_t)); - - // LDC paint delegate argument to the type runtime expects - if (!fldeTy->equals(flde->type)) - { - flde = new CastExp(loc, flde, flde->type); - flde->type = fldeTy; - } - 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. - FuncDeclaration *fdapply; - 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 - { - /* Call: - * aggr.apply(flde) - */ - ec = new DotIdExp(loc, aggr, - (op == TOKforeach_reverse) ? Id::applyReverse - : Id::apply); - Expressions *exps = new Expressions(); - 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); - 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; -} - -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()) - 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 - */ - AddExp ea(loc, lwr, upr); - Expression *e = ea.typeCombine(sc); - if (e->op == TOKerror) - return this; - 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) - { // key-- > tmp - cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key)); - cond = new CmpExp(TOKgt, loc, cond, new VarExp(loc, tmp)); - } - else - // key < tmp - cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), new VarExp(loc, tmp)); - - Expression *increment = NULL; - if (op == TOKforeach) - // key += 1 - increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); - - ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); - s = fs->semantic(sc); - return s; -#else - if (!arg->type->isscalar()) - error("%s is not a scalar type", arg->type->toChars()); - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - sc->noctor++; - - key = new VarDeclaration(loc, arg->type, arg->ident, NULL); - DeclarationExp *de = new DeclarationExp(loc, key); - de->semantic(sc); - - if (key->storage_class) - error("foreach range: key cannot have storage class"); - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - - sc->noctor--; - sc->pop(); - return s; -#endif -} - -int ForeachRangeStatement::hasBreak() -{ - return TRUE; -} - -int ForeachRangeStatement::hasContinue() -{ - return TRUE; -} - -int ForeachRangeStatement::usesEH() -{ - assert(0); - return body->usesEH(); -} - -int ForeachRangeStatement::blockExit(bool mustNotThrow) -{ - assert(0); - int result = BEfallthru; - - if (lwr && lwr->canThrow()) - result |= BEthrow; - else if (upr && upr->canThrow()) - 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) -{ - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->checkToBoolean(); - - // If we can short-circuit evaluate the if statement, don't do the - // semantic analysis of the skipped code. - // This feature allows a limited form of conditional compilation. - condition = condition->optimize(WANTflags); - - // Evaluate at runtime - unsigned cs0 = sc->callSuper; - unsigned cs1; - - Scope *scd; - if (arg) - { /* Declare arg, which we will set to be the - * result of condition. - */ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - scd = sc->push(sym); - - Type *t = arg->type ? arg->type : condition->type; - match = new VarDeclaration(loc, t, arg->ident, NULL); - match->noscope = 1; - match->semantic(scd); - if (!scd->insert(match)) - assert(0); - match->parent = sc->func; - - /* Generate: - * (arg = condition) - */ - VarExp *v = new VarExp(0, match); - condition = new AssignExp(loc, v, condition); - condition = condition->semantic(scd); - } - else - scd = sc->push(); - ifbody = ifbody->semanticNoScope(scd); - scd->pop(); - - cs1 = sc->callSuper; - sc->callSuper = cs0; - if (elsebody) - elsebody = elsebody->semanticScope(sc, NULL, NULL); - sc->mergeCallSuper(loc, cs1); - - return this; -} - -int IfStatement::usesEH() -{ - return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); -} - -int IfStatement::blockExit(bool mustNotThrow) -{ - //printf("IfStatement::blockExit(%p)\n", this); - - int result = BEnone; - if (condition->canThrow()) - 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)) - { - ifbody = ifbody->semantic(sc); - return ifbody; - } - else - { - if (elsebody) - elsebody = elsebody->semantic(sc); - return elsebody; - } -} - -Statements *ConditionalStatement::flatten(Scope *sc) -{ - Statement *s; - - if (condition->include(sc, NULL)) - s = ifbody; - else - s = elsebody; - - Statements *a = new Statements(); - a->push(s); - return a; -} - -int ConditionalStatement::usesEH() -{ - return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); -} - -int ConditionalStatement::blockExit(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); - if (e->op != TOKerror && e->op != TOKtype) - e = e->ctfeInterpret(); - 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->ctfeInterpret(); - (*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->ctfeInterpret(); - (*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) - : Statement(loc) -{ - condition = c; - body = b; - sdefault = NULL; - cases = NULL; - hasNoDefault = 0; - // LDC - enclosingScopeExit = NULL; -} - -Statement *SwitchStatement::syntaxCopy() -{ - SwitchStatement *s = new SwitchStatement(loc, - condition->syntaxCopy(), body->syntaxCopy()); - return s; -} - -Statement *SwitchStatement::semantic(Scope *sc) -{ - //printf("SwitchStatement::semantic(%p)\n", this); - assert(!cases); // ensure semantic() is only run once - - // LDC - enclosingScopeExit = sc->enclosingScopeExit; - - 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()); - } - } - 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: - ; - } - - if (!sc->sw->sdefault) - { hasNoDefault = 1; - - warning("switch statement has no default"); - - // Generate runtime error if the default is hit - Statements *a = new Statements(); - CompoundStatement *cs; - Statement *s; - - if (global.params.useSwitchError) - s = new SwitchErrorStatement(loc); - else - { Expression *e = new HaltExp(loc); - s = new ExpStatement(loc, e); - } - - a->reserve(4); - a->push(body); - - // LDC needs semantic to be run on break - Statement *breakstmt = new BreakStatement(loc, NULL); - breakstmt->semantic(sc); - a->push(breakstmt); - - sc->sw->sdefault = new DefaultStatement(loc, s); - a->push(sc->sw->sdefault); - cs = new CompoundStatement(loc, a); - body = cs; - } - -#if DMDV2 - if (isFinal) - { Type *t = condition->type; - while (t->ty == Ttypedef) - { // Don't use toBasetype() because that will skip past enums - t = ((TypeTypedef *)t)->sym->basetype; - } - if (condition->type->ty == Tenum) - { TypeEnum *te = (TypeEnum *)condition->type; - EnumDeclaration *ed = te->toDsymbol(sc)->isEnumDeclaration(); - assert(ed); - size_t dim = ed->members->dim; - for (size_t i = 0; i < dim; i++) - { - EnumMember *em = (*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: - ; - } - } - } -#endif - - 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()) - 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("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; - 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) - { - // LDC - enclosingScopeExit = sc->enclosingScopeExit; - if (enclosingScopeExit != sw->enclosingScopeExit) - { - error("case must be inside the same try, synchronized or volatile level as switch"); - } - - exp = exp->implicitCastTo(sc, sw->condition->type); - exp = exp->ctfeInterpret(); - 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); - } - - 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 - } - } - } - 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->ctfeInterpret(); - - last = last->semantic(sc); - last = last->implicitCastTo(sc, sw->condition->type); - last = last->ctfeInterpret(); - - if (first->op == TOKerror || last->op == TOKerror) - return statement ? statement->semantic(sc) : NULL; - - dinteger_t fval = first->toInteger(); - dinteger_t lval = last->toInteger(); - - if (lval - fval > 256) - { error("more than 256 cases in case range"); - lval = fval + 256; - } - - /* This works by replacing the CaseRange with an array of Case's. - * - * case a: .. case b: s; - * => - * case a: - * [...] - * case b: - * s; - */ - - Statements *statements = new Statements(); - for (dinteger_t i = fval; i <= lval; i++) - { - Statement *s = statement; - if (i != lval) - s = new ExpStatement(loc, NULL); - Expression *e = new IntegerExp(loc, i, first->type); - Statement *cs = new CaseStatement(loc, e, s); - statements->push(cs); - } - Statement *s = new CompoundStatement(loc, statements); - s = s->semantic(sc); - return s; -} - -void CaseRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("case "); - first->toCBuffer(buf, hgs); - buf->writestring(": .. case "); - last->toCBuffer(buf, hgs); - buf->writenl(); - statement->toCBuffer(buf, hgs); -} - -#endif - -/******************************** DefaultStatement ***************************/ - -DefaultStatement::DefaultStatement(Loc loc, Statement *s) - : Statement(loc) -{ - this->statement = s; -#if IN_GCC -+ cblock = NULL; -#endif - bodyBB = NULL; - // LDC - enclosingScopeExit = NULL; -} - -Statement *DefaultStatement::syntaxCopy() -{ - DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy()); - return s; -} - -Statement *DefaultStatement::semantic(Scope *sc) -{ - //printf("DefaultStatement::semantic()\n"); - if (sc->sw) - { - if (sc->sw->sdefault) - { - error("switch statement already has a default"); - } - sc->sw->sdefault = this; - - // LDC - enclosingScopeExit = sc->enclosingScopeExit; - if (enclosingScopeExit != sc->sw->enclosingScopeExit) - { - error("default must be inside the same try, synchronized or volatile level as switch"); - } - } - 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) -{ - return BEthrow; -} - - -void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("SwitchErrorStatement::toCBuffer()"); - buf->writenl(); -} - -/******************************** ReturnStatement ***************************/ - -ReturnStatement::ReturnStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; - this->implicit0 = 0; -} - -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; - 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); - } - - if (!exp) - fd->nrvo_can = 0; - - if (exp) - { - fd->hasReturnExp |= 1; - - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue); - - if (fd->nrvo_can && exp->op == TOKvar) - { VarExp *ve = (VarExp *)exp; - VarDeclaration *v = ve->var->isVarDeclaration(); - - if (!v || v->isOut() || v->isRef()) - 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 0 - if (fd->returnLabel && tbret && tbret->ty != Tvoid) - { - } - else -#endif - if (fd->inferRetType) - { - Type *tfret = fd->type->nextOf(); - if (tfret) - { - if (tfret != Type::terror && !exp->type->equals(tfret)) - error("mismatched function return type inference of %s and %s", - exp->type->toChars(), tfret->toChars()); - } - else - { - fd->type->next = exp->type; - fd->type = fd->type->semantic(loc, sc); - if (!fd->tintro) - { tret = fd->type->nextOf(); - tbret = tret->toBasetype(); - } - } - if (fd->returnLabel) - eorg = exp; - } - else if (tbret->ty != Tvoid) - { - 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); - } - } - 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 - { - fd->type->next = Type::tvoid; - //fd->type = fd->type->semantic(loc, sc); - if (!fd->tintro) - { tret = Type::tvoid; - tbret = tret; - } - } - } - else if (tbret->ty != Tvoid) // if non-void return - error("return expression expected"); - - if (sc->fes) - { - Statement *s; - - if (exp && !implicit0) - { - exp = exp->implicitCastTo(sc, tret); - } - if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 || - exp->op == TOKimaginary80 || exp->op == TOKcomplex80 || - exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull || - exp->op == TOKstring) - { - sc->fes->cases->push(this); - // Construct: return cases->dim+1; - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - } - else if (fd->type->nextOf()->toBasetype() == Type::tvoid) - { - s = new ReturnStatement(0, NULL); - sc->fes->cases->push(s); - - // Construct: { exp; return cases->dim + 1; } - Statement *s1 = new ExpStatement(loc, exp); - Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - else - { - // Construct: return vresult; - if (!fd->vresult) - { // Declare vresult - Scope *sco = fd->scout ? fd->scout : scx; - VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noscope = 1; - v->semantic(sco); - if (!sco->insert(v)) - assert(0); - v->parent = fd; - fd->vresult = v; - } - - s = new ReturnStatement(0, new VarExp(0, fd->vresult)); - sc->fes->cases->push(s); - - // Construct: { vresult = exp; return cases->dim + 1; } - exp = new ConstructExp(loc, new VarExp(0, fd->vresult), exp); - exp = exp->semantic(sc); - Statement *s1 = new ExpStatement(loc, exp); - Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - return s; - } - - if (exp) - { - if (fd->returnLabel && tbret->ty != Tvoid) - { - fd->buildResultVar(); - VarExp *v = new VarExp(0, fd->vresult); - - assert(eorg); - exp = new AssignExp(loc, v, eorg); - exp->op = TOKconstruct; - exp = exp->semantic(sc); - } - //exp->dump(0); - //exp->print(); - exp->checkEscape(); - } - - /* BUG: need to issue an error on: - * this - * { if (x) return; - * super(); - * } - */ - - if (sc->callSuper & CSXany_ctor && - !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor))) - error("return without calling constructor"); - - sc->callSuper |= CSXreturn; - - // See if all returns are instead to be replaced with a goto returnLabel; - if (fd->returnLabel) - { - GotoStatement *gs = new GotoStatement(loc, Id::returnLabel); - - gs->label = fd->returnLabel; - if (exp) - { /* Replace: return exp; - * with: exp; goto returnLabel; - */ - Statement *s = new ExpStatement(0, exp); - return new CompoundStatement(loc, s, gs); - } - return gs; - } - - if (exp && tbret->ty == Tvoid && !implicit0) - { - /* Replace: - * return exp; - * with: - * exp; return; - */ - Statement *s = new ExpStatement(loc, exp); - exp = NULL; - s = s->semantic(sc); - return new CompoundStatement(loc, s, this); - } - - return this; -} - -int ReturnStatement::blockExit(bool mustNotThrow) -{ int result = BEreturn; - - if (exp && exp->canThrow()) - result |= BEthrow; - return result; -} - - -void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("return "); - if (exp) - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - buf->writenl(); -} - -/******************************** BreakStatement ***************************/ - -BreakStatement::BreakStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; -} - -Statement *BreakStatement::syntaxCopy() -{ - BreakStatement *s = new BreakStatement(loc, ident); - return s; -} - -Statement *BreakStatement::semantic(Scope *sc) -{ - //printf("BreakStatement::semantic()\n"); - // If: - // break Identifier; - if (ident) - { - Scope *scx; - FuncDeclaration *thisfunc = sc->func; - - for (scx = sc; scx; scx = scx->enclosing) - { - LabelStatement *ls; - - if (scx->func != thisfunc) // if in enclosing function - { - if (sc->fes) // if this is the body of a foreach - { - /* Post this statement to the fes, and replace - * it with a return value that caller will put into - * a switch. Caller will figure out where the break - * label actually is. - * Case numbers start with 2, not 0, as 0 is continue - * and 1 is break. - */ - Statement *s; - sc->fes->cases->push(this); - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - return s; - } - break; // can't break to it - } - - ls = scx->slabel; - if (ls && ls->ident == ident) - { - Statement *s = ls->statement; - - if (!s->hasBreak()) - error("label '%s' has no break", ident->toChars()); - if (ls->enclosingFinally != sc->enclosingFinally) - error("cannot break out of finally block"); - - this->target = ls; - return this; - } - } - error("enclosing label '%s' for break not found", ident->toChars()); - } - else if (!sc->sbreak) - { - if (sc->fes) - { Statement *s; - - // Replace break; with return 1; - s = new ReturnStatement(0, new IntegerExp(1)); - return s; - } - error("break is not inside a loop or switch"); - } - return this; -} - -int BreakStatement::blockExit(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); - if (exp->op == TOKerror) - goto Lbody; - 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. - */ - if (!ClassDeclaration::object) - { - error("missing or corrupt object.d"); - fatal(); - } - - Type *t = ClassDeclaration::object->type; - t = t->semantic(0, sc)->toBasetype(); - assert(t->ty == Tclass); - - 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)); - - Parameters* enterargs = new Parameters; - enterargs->push(new Parameter(STCin, ClassDeclaration::object->type, NULL, NULL)); - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(enterargs, Type::tvoid, Id::monitorenter); - 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)); - - Parameters* exitargs = new Parameters; - exitargs->push(new Parameter(STCin, ClassDeclaration::object->type, NULL, NULL)); - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(exitargs, Type::tvoid, Id::monitorexit); - 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"); -#if IN_DMD - Type *t = new TypeSArray(Type::tint8, new IntegerExp(PTRSIZE + (global.params.is64bit ? os_critsecsize64() : os_critsecsize32()))); -#elif IN_LLVM - Type *t = new TypeSArray(Type::tint8, new IntegerExp(PTRSIZE + os_critsecsize())); -#endif - VarDeclaration *tmp = new VarDeclaration(loc, t, id, NULL); - tmp->storage_class |= STCgshared | STCstatic; - - Statements *cs = new Statements(); - cs->push(new ExpStatement(loc, tmp)); - - Parameters* enterargs = new Parameters; - enterargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(enterargs, Type::tvoid, Id::criticalenter); - 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)); - - Parameters* exitargs = new Parameters; - exitargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(exitargs, Type::tvoid, Id::criticalexit); - 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 -Lbody: - if (body) - body = body->semantic(sc); - 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()) - 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) - { - 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; -} - -Catch *Catch::syntaxCopy() -{ - Catch *c = new Catch(loc, - (type ? type->syntaxCopy() : NULL), - ident, - (handler ? handler->syntaxCopy() : NULL)); - return c; -} - -void Catch::semantic(Scope *sc) -{ - if (type && type->deco) - return; - - //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 - - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - if (!type) - type = new TypeIdentifier(0, Id::Object); - type = type->semantic(loc, sc); - if (!type->toBasetype()->isClassHandle()) - { - if (type != Type::terror) - { error(loc, "can only catch class objects, 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"); - // This code is different in LDC because LDC needs to know the - // enclosingScopeExit for its labels - 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(); - 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 (tok != TOKon_scope_success); -} - -void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("OnScopeStatement::scopeCode()\n"); - //print(); - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - switch (tok) - { - case TOKon_scope_exit: - *sfinally = statement; - break; - - case TOKon_scope_failure: - *sexception = statement; - break; - - case TOKon_scope_success: - { - /* Create: - * sentry: int x = 0; - * sexception: x = 1; - * sfinally: if (!x) statement; - */ - Identifier *id = Lexer::uniqueId("__os"); - - ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0)); - VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie); - *sentry = new ExpStatement(loc, v); - - Expression *e = new IntegerExp(1); - e = new AssignExp(0, new VarExp(0, v), e); - *sexception = new ExpStatement(0, e); - - e = new VarExp(0, v); - e = new NotExp(0, e); - *sfinally = new IfStatement(0, NULL, e, statement, NULL); - - break; - } - - default: - assert(0); - } -} - -/******************************** ThrowStatement ***************************/ - -ThrowStatement::ThrowStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *ThrowStatement::syntaxCopy() -{ - ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy()); - return s; -} - -Statement *ThrowStatement::semantic(Scope *sc) -{ - //printf("ThrowStatement::semantic()\n"); - - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - fd->hasReturnExp |= 2; - - if (sc->incontract) - error("Throw statements cannot be in contracts"); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (exp->op == TOKerror) - return this; - if (!exp->type->toBasetype()->isClassHandle()) - error("can only throw class objects, not type %s", exp->type->toChars()); - return this; -} - -int ThrowStatement::blockExit(bool mustNotThrow) -{ - 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); - } -} - - -/******************************** 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->asmLabel = false; - this->fwdrefs = NULL; -} - -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; -} diff --git a/dmd/statement.h b/dmd/statement.h deleted file mode 100644 index c78816b1..00000000 --- a/dmd/statement.h +++ /dev/null @@ -1,943 +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. - -#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; -struct AsmBlockStatement; -struct GotoStatement; -struct ScopeStatement; -struct TryCatchStatement; -struct TryFinallyStatement; -struct CaseStatement; -struct DefaultStatement; -struct LabelStatement; -struct HdrGenState; -struct InterState; -struct CaseStatement; -struct LabelStatement; -struct VolatileStatement; -struct SynchronizedStatement; - -enum TOK; -#if IN_LLVM -namespace llvm -{ - class Value; - class BasicBlock; - class ConstantInt; -} -#endif - -// Back end -struct IRState; -struct Blockx; -#if IN_LLVM -struct DValue; -typedef DValue elem; -#endif - -#if IN_GCC -union tree_node; typedef union tree_node block; -//union tree_node; typedef union tree_node elem; -#else -struct block; -//struct elem; -#endif -struct code; - -/* How a statement exits; this is returned by blockExit() - */ -enum BE -{ - BEnone = 0, - BEfallthru = 1, - BEthrow = 2, - BEreturn = 4, - BEgoto = 8, - BEhalt = 0x10, - BEbreak = 0x20, - BEcontinue = 0x40, - BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), -}; - -struct Statement : Object -{ - Loc loc; - - Statement(Loc loc); - virtual Statement *syntaxCopy(); - - void print(); - char *toChars(); - - void error(const char *format, ...) IS_PRINTF(2); - void warning(const char *format, ...) IS_PRINTF(2); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual TryCatchStatement *isTryCatchStatement() { return NULL; } - virtual GotoStatement *isGotoStatement() { return NULL; } - virtual AsmStatement *isAsmStatement() { return NULL; } - virtual AsmBlockStatement *isAsmBlockStatement() { return NULL; } - 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 void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - virtual Statements *flatten(Scope *sc); - virtual Expression *interpret(InterState *istate); - - virtual int inlineCost(InlineCostState *ics); - virtual Expression *doInline(InlineDoState *ids); - virtual Statement *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(); - void 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); - -#if IN_LLVM - void toNakedIR(IRState *irs); -#endif - - ExpStatement *isExpStatement() { return this; } -}; - -struct CompileStatement : Statement -{ - Expression *exp; - - CompileStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statements *flatten(Scope *sc); - Statement *semantic(Scope *sc); -}; - -struct 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); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - virtual void toIR(IRState *irs); - - // LDC - virtual void toNakedIR(IRState *irs); - virtual AsmBlockStatement* endsWithAsm(); - - 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); - void 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 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); -}; - -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; - - DefaultStatement *sdefault; - - GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's - CaseStatements *cases; // array of CaseStatement's - int hasNoDefault; // !=0 if no default statement - - // LDC - Statement *enclosingScopeExit; - - SwitchStatement(Loc loc, Expression *c, Statement *b); - 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 - - // LDC - Statement *enclosingScopeExit; - - 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 - - // LDC - Statement *enclosingScopeExit; - - 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); - - // LDC - llvm::BasicBlock* bodyBB; -}; - -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; - int implicit0; - - 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); - - // LDC: only set if ident is set: label statement to jump to - LabelStatement *target; -}; - -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); - - // LDC: only set if ident is set: label statement to jump to - LabelStatement *target; -}; - -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); - llvm::Value* llsync; -}; - -struct WithStatement : Statement -{ - Expression *exp; - Statement *body; - VarDeclaration *wthis; - - WithStatement(Loc loc, Expression *exp, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int usesEH(); - int blockExit(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); - TryCatchStatement *isTryCatchStatement() { return this; } -}; - -struct Catch : Object -{ - Loc loc; - Type *type; - Identifier *ident; - VarDeclaration *var; - Statement *handler; - - Catch(Loc loc, Type *t, Identifier *id, Statement *handler); - Catch *syntaxCopy(); - void semantic(Scope *sc); - int blockExit(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(); - void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - Expression *interpret(InterState *istate); - - void toIR(IRState *irs); -}; - -struct ThrowStatement : Statement -{ - Expression *exp; - - ThrowStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int blockExit(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 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); - GotoStatement *isGotoStatement() { return this; } -}; - -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); - - // LDC - bool asmLabel; // for labels inside inline assembler - void toNakedIR(IRState *irs); -}; - -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); - virtual AsmStatement *isAsmStatement() { return this; } - - void toIR(IRState *irs); - - // LDC - // non-zero if this is a branch, contains the target labels identifier - Identifier* isBranchToLabel; - - void toNakedIR(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/dmd/staticassert.c b/dmd/staticassert.c deleted file mode 100644 index 062219c2..00000000 --- a/dmd/staticassert.c +++ /dev/null @@ -1,126 +0,0 @@ - -// 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/branches/dmd-1.x/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()); - Expression *e = exp->semantic(sc); - if (!e->type->checkBoolean()) - { - if (e->type->toBasetype() != Type::terror) - exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars()); - return; - } - unsigned olderrs = global.errors; - e = e->ctfeInterpret(); - 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->ctfeInterpret(); - hgs.console = 1; - msg->toCBuffer(&buf, &hgs); - error("%s", buf.toChars()); - } - else - error("(%s) is false", exp->toChars()); - if (sc->tinst) - sc->tinst->printInstantiationTrace(); - if (!global.gag) - fatal(); - } - else if (!e->isBool(TRUE)) - { - error("(%s) is not evaluatable at compile time", exp->toChars()); - } -} - -int StaticAssert::oneMember(Dsymbol **ps) -{ - //printf("StaticAssert::oneMember())\n"); - *ps = NULL; - return TRUE; -} - -void StaticAssert::inlineScan() -{ -} - -void StaticAssert::toObjFile(int multiobj) -{ -} - -const char *StaticAssert::kind() -{ - return "static assert"; -} - -void StaticAssert::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(kind()); - buf->writeByte('('); - exp->toCBuffer(buf, hgs); - if (msg) - { - buf->writeByte(','); - msg->toCBuffer(buf, hgs); - } - buf->writestring(");"); - buf->writenl(); -} diff --git a/dmd/staticassert.h b/dmd/staticassert.h deleted file mode 100644 index 2f7e0906..00000000 --- a/dmd/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); - void toObjFile(int multiobj); - const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#endif diff --git a/dmd/struct.c b/dmd/struct.c deleted file mode 100644 index ad1f5975..00000000 --- a/dmd/struct.c +++ /dev/null @@ -1,683 +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 "root.h" -#include "aggregate.h" -#include "scope.h" -#include "mtype.h" -#include "declaration.h" -#include "module.h" -#include "id.h" -#include "statement.h" -#include "template.h" - -/********************************* AggregateDeclaration ****************************/ - -AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) - : ScopeDsymbol(id) -{ - this->loc = loc; - - storage_class = 0; - protection = PROTpublic; - type = NULL; - handle = NULL; - structsize = 0; // size of struct - alignsize = 0; // size of struct for alignment purposes - structalign = 0; // struct member alignment in effect - hasUnions = 0; - sizeok = SIZEOKnone; // size not determined yet - isdeprecated = 0; - inv = NULL; - aggNew = NULL; - aggDelete = NULL; - -#if IN_DMD - stag = NULL; - sinit = NULL; -#endif -#if DMDV2 - dtor = NULL; - - 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) -{ - // LDC - if (!global.params.useAvailableExternally) - availableExternally = false; - - //printf("AggregateDeclaration::semantic3(%s)\n", toChars()); - if (members) - { - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[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)[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 (loc.linnum == 0) - loc = this->loc; - if (!members) - error(loc, "unknown size"); - if (sizeok != SIZEOKdone && scope) - semantic(NULL); - if (sizeok != SIZEOKdone) - { 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( - structalign_t 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 == STRUCTALIGN_DEFAULT) - salign = 8; - 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", *poffset); -} - -/**************************************** - * Place a member (mem) into an aggregate (agg), which can be a struct, union or class - * Returns: - * offset to place field at - */ -unsigned AggregateDeclaration::placeField( - unsigned *nextoffset, // next location in aggregate - unsigned memsize, // size of member - unsigned memalignsize, // size of member for alignment purposes - structalign_t memalign, // alignment in effect for this member - unsigned *paggsize, // size of aggregate (updated) - unsigned *paggalignsize, // size of aggregate for alignment purposes (updated) - bool isunion // the aggregate is a union - ) -{ - unsigned ofs = *nextoffset; - alignmember(memalign, memalignsize, &ofs); - unsigned memoffset = ofs; - ofs += memsize; - if (ofs > *paggsize) - *paggsize = ofs; - if (!isunion) - *nextoffset = ofs; - if (global.params.is64bit && memalign == 8 && memalignsize == 16) - /* Not sure how to handle this */ - ; - else if (memalign == STRUCTALIGN_DEFAULT && 8 < memalignsize) - memalignsize = 8; - else if (memalign < memalignsize) - memalignsize = memalign; - if (*paggalignsize < memalignsize) - *paggalignsize = memalignsize; - - return memoffset; -} - - -/**************************************** - * 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[indx]; - int firstNonZero = indx; // first index in the union with non-zero size - for (; ;) - { - if (indx == 0) - return firstNonZero; - VarDeclaration * v = fields[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[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[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; - cpctor = NULL; - postblit = NULL; - eq = NULL; -#endif - arg1type = NULL; - arg2type = NULL; - - // For forward references - type = new TypeStruct(this); -} - -Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s) -{ - StructDeclaration *sd; - - if (s) - sd = (StructDeclaration *)s; - else - sd = new StructDeclaration(loc, ident); - ScopeDsymbol::syntaxCopy(sd); - return sd; -} - -void StructDeclaration::semantic(Scope *sc) -{ - Scope *sc2; - - //printf("+StructDeclaration::semantic(this=%p, %s '%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 == SIZEOKdone || !scope) - { //printf("already completed\n"); - scope = NULL; - return; // semantic() already completed - } - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - unsigned dprogress_save = Module::dprogress; - - parent = sc->parent; - type = type->semantic(loc, sc); -#if STRUCTTHISREF - handle = type; -#else - handle = type->pointerTo(); -#endif - structalign = sc->structalign; - protection = sc->protection; - if (sc->stc & STCdeprecated) - isdeprecated = 1; - assert(!isAnonymous()); - if (sc->stc & STCabstract) - error("structs, unions cannot be abstract"); - - if (sizeok == SIZEOKnone) // if not already done the addMember step - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); - s->addMember(sc, this, 1); - } - } - - sizeok = SIZEOKnone; - sc2 = sc->push(this); - sc2->stc = 0; - 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]; - // Ungag errors when not speculative - unsigned oldgag = global.gag; - if (global.isSpeculativeGagging() && !isSpeculative()) - { - global.gag = 0; - } - s->semantic(sc2); - global.gag = oldgag; -#if 0 - if (sizeok == 2) - { //printf("forward reference\n"); - break; - } -#endif - } - finalizeSize(sc2); - -#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(); - - if (sizeok == 2) - { // semantic() failed because of forward references. - // Unwind what we did, and defer it for later - for (size_t i = 0; i < fields.dim; i++) - { Dsymbol *s = fields[i]; - VarDeclaration *vd = s->isVarDeclaration(); - if (vd) - vd->offset = 0; - } - fields.setDim(0); - structsize = 0; - alignsize = 0; - structalign = 0; - - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - - Module::dprogress = dprogress_save; - //printf("\tdeferring %s\n", toChars()); - return; - } - - // 0 sized struct's are set to 1 byte - if (structsize == 0) - { - structsize = 1; - alignsize = 1; - } - - // Round struct size up to next alignsize boundary. - // This will ensure that arrays of structs will get their internals - // aligned properly. - structsize = (structsize + alignsize - 1) & ~(alignsize - 1); - - sizeok = SIZEOKdone; - 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 = (Dsymbol *)fields.data[i]; - VarDeclaration *vd = s->isVarDeclaration(); - if (vd && !vd->isDataseg()) - { - if (vd->init) - { - // Should examine init to see if it is really all 0's - zeroInit = 0; - break; - } - else - { - if (!vd->type->isZeroInit(loc)) - { - zeroInit = 0; - break; - } - } - } - } - - /* Look for special member functions. - */ -#if DMDV2 - ctor = (CtorDeclaration *)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); - - TypeTuple *tup = type->toArgTypes(); - size_t dim = tup->arguments->dim; - if (dim >= 1) - { assert(dim <= 2); - arg1type = (*tup->arguments)[0]->type; - if (dim == 2) - arg2type = (*tup->arguments)[1]->type; - } - - if (sc->func) - { - semantic2(sc); - semantic3(sc); - } -} - -Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s.StructDeclaration::search('%s')\n", toChars(), ident->toChars()); - - if (scope && !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(Scope *sc) -{ - //printf("StructDeclaration::finalizeSize() %s\n", toChars()); - if (sizeok != SIZEOKnone) - return; - - // Set the offsets of the fields and determine the size of the struct - unsigned offset = 0; - bool isunion = isUnionDeclaration() != NULL; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->setFieldOffset(this, &offset, isunion); - } - if (sizeok == SIZEOKfwd) - return; - - // 0 sized struct's are set to 1 byte - if (structsize == 0) - { - structsize = 1; - alignsize = 1; - } - - // Round struct size up to next alignsize boundary. - // This will ensure that arrays of structs will get their internals - // aligned properly. - structsize = (structsize + alignsize - 1) & ~(alignsize - 1); - - sizeok = SIZEOKdone; -} - -/*************************************** - * Return true if struct is POD (Plain Old Data). - * This is defined as: - * not nested - * no postblits, constructors, destructors, or assignment operators - * no fields with with any of those - * The idea being these are compatible with C structs. - * - * Note that D struct constructors can mean POD, since there is always default - * construction with no ctor, but that interferes with OPstrpar which wants it - * on the stack in memory, not in registers. - */ -bool StructDeclaration::isPOD() -{ - return true; -} - -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)[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - buf->writenl(); -} - - -const char *StructDeclaration::kind() -{ - return "struct"; -} - -/********************************* UnionDeclaration ****************************/ - -UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id) - : StructDeclaration(loc, id) -{ -} - -Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s) -{ - UnionDeclaration *ud; - - if (s) - ud = (UnionDeclaration *)s; - else - ud = new UnionDeclaration(loc, ident); - StructDeclaration::syntaxCopy(ud); - return ud; -} - - -const char *UnionDeclaration::kind() -{ - return "union"; -} - - diff --git a/dmd/template.c b/dmd/template.c deleted file mode 100644 index a0b3943f..00000000 --- a/dmd/template.c +++ /dev/null @@ -1,5601 +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 "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 "mars.h" -#include "dsymbol.h" -#include "identifier.h" -#include "hdrgen.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 || !e->type || e->type->ty== Terror); - 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)[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) - { - tempdecl->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[i], - u2->objects[i], - tempdecl, sc)) - goto Lnomatch; - } - } - //printf("match\n"); - return 1; // match - -Lnomatch: - //printf("nomatch\n"); - return 0; // nomatch; -} - - -/************************************ - * Match an array of them. - * This should match what genIdent() does. - */ -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)[j]; - Object *o2 = (*oa2)[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) - : ScopeDsymbol(id) -{ -#if LOG - printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars()); -#endif -#if 0 - if (parameters) - for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = (*parameters)[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 = PASSinit; - this->onemember = NULL; - - // Compute in advance for Ddoc's use - if (members) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s)) - { - if (s && s->ident && s->ident->equals(ident)) - { - 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)[i] = tp->syntaxCopy(); - } - } - Expression *e = NULL; - if (constraint) - e = constraint->syntaxCopy(); - Dsymbols *d = Dsymbol::arraySyntaxCopy(members); - td = new TemplateDeclaration(loc, ident, p, e, d); - -#if IN_LLVM - // LDC - 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 = PASSsemantic; - - 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 - sc->module->toModuleUnittest(); - } -#endif - - /* Remember Scope for later instantiations, but make - * a copy since attributes can change. - */ - if (!this->scope) - { 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 (global.params.doDocComments) - { - origParameters = new TemplateParameters(); - origParameters->setDim(parameters->dim); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - origParameters->data[i] = (void *)tp->syntaxCopy(); - } - } - - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - - tp->declareParameter(paramscope); - } - - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - - tp->semantic(paramscope); - if (i + 1 != parameters->dim && tp->isTemplateTupleParameter()) - error("template tuple parameter must be last one"); - } - - paramscope->pop(); - - // Compute again - onemember = NULL; - if (members) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s)) - { - if (s && s->ident && s->ident->equals(ident)) - { - onemember = s; - s->parent = this; - } - } - } - - /* BUG: should check: - * o no virtual functions or non-static data members of classes - */ -} - -const char *TemplateDeclaration::kind() -{ - return (onemember && onemember->isAggregateDeclaration()) - ? onemember->kind() - : (char *)"template"; -} - -/********************************** - * Overload existing TemplateDeclaration 'this' with the new one 's'. - * Return !=0 if successful; i.e. no conflict. - */ - -int TemplateDeclaration::overloadInsert(Dsymbol *s) -{ - TemplateDeclaration **pf; - TemplateDeclaration *f; - -#if LOG - printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars()); -#endif - f = s->isTemplateDeclaration(); - if (!f) - return FALSE; - TemplateDeclaration *pthis = this; - for (pf = &pthis; *pf; pf = &(*pf)->overnext) - { -#if 0 - // Conflict if TemplateParameter's match - // Will get caught anyway later with TemplateInstance, but - // should check it now. - TemplateDeclaration *f2 = *pf; - - if (f->parameters->dim != f2->parameters->dim) - goto Lcontinue; - - for (size_t i = 0; i < f->parameters->dim; i++) - { TemplateParameter *p1 = (TemplateParameter *)f->parameters->data[i]; - TemplateParameter *p2 = (TemplateParameter *)f2->parameters->data[i]; - - if (!p1->overloadMatch(p2)) - goto Lcontinue; - } - -#if LOG - printf("\tfalse: conflict\n"); -#endif - return FALSE; - - Lcontinue: - ; -#endif - } - - f->overroot = this; - *pf = f; -#if LOG - printf("\ttrue: no conflict\n"); -#endif - return TRUE; -} - -/*************************************** - * Given that ti is an instance of this TemplateDeclaration, - * deduce the types of the parameters to this, and store - * those deduced types in dedtypes[]. - * Input: - * flag 1: don't do semantic() because of dummy types - * 2: don't change types in matchArg() - * Output: - * dedtypes deduced arguments - * Return match level. - */ - -MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, - Objects *dedtypes, int flag) -{ MATCH m; - 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->data[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 = (TemplateParameter *)parameters->data[i]; - Declaration *sparam; - - //printf("\targument [%d]\n", i); -#if LOGM - //printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null"); - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - if (ttp) - printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); -#endif - -#if DMDV1 - m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); -#else - m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam, (flag & 2) ? 1 : 0); - -#endif - //printf("\tm2 = %d\n", m2); - - if (m2 == MATCHnomatch) - { -#if 0 - printf("\tmatchArg() for parameter %i failed\n", i); -#endif - goto Lnomatch; - } - - if (m2 < m) - m = m2; - - if (!flag) - sparam->semantic(paramscope); - if (!paramscope->insert(sparam)) - goto Lnomatch; - } - - if (!flag) - { - /* Any parameter left without a type gets the type of - * its corresponding arg - */ - for (size_t i = 0; i < dedtypes_dim; i++) - { - if (!(*dedtypes)[i]) - { assert(i < ti->tiargs->dim); - (*dedtypes)[i] = (Type *)(*ti->tiargs)[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 (e->op == TOKerror) - goto Lnomatch; - - if (fd && fd->vthis) - fd->vthis = vthissave; - - sc->pop(); - e = e->ctfeInterpret(); - 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)[i]; - Object *oarg; - - printf(" [%d]", i); - - if (i < ti->tiargs->dim) - oarg = (*ti->tiargs)[i]; - else - oarg = NULL; - tp->print(oarg, (*dedtypes)[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) -{ - /* 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 = (TemplateParameter *)parameters->data[i]; - - void *p = tp->dummyArg(); - if (p) - ti.tiargs->data[i] = p; - else - ti.tiargs->setDim(i); - } - - // Temporary Array to hold deduced types - //dedtypes.setDim(parameters->dim); - dedtypes.setDim(td2->parameters->dim); - - // Attempt a type deduction - MATCH m = td2->matchWithInstance(&ti, &dedtypes, 1); - if (m) - { - /* A non-variadic template is more specialized than a - * variadic one. - */ - if (isVariadic() && !td2->isVariadic()) - goto L1; - -#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(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 - -#if 0 - printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars()); - for (size_t i = 0; i < fargs->dim; i++) - { Expression *e = (Expression *)fargs->data[i]; - printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); - } - printf("fd = %s\n", fd->toChars()); - printf("fd->type = %p\n", fd->type); -#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(); - -#if 0 - for (size_t i = 0; i < dedargs->dim; i++) - { - printf("\tdedarg[%d] = ", i); - Object *oarg = (Object *)dedargs->data[i]; - if (oarg) printf("%s", oarg->toChars()); - printf("\n"); - } -#endif - - - nargsi = 0; - if (targsi) - { // Set initial template arguments - - nargsi = targsi->dim; - size_t n = parameters->dim; - if (nargsi > n) - { if (!tp) - goto Lnomatch; - dedargs->setDim(nargsi); - dedargs->zero(); - } - else - n = nargsi; - - /* Test case for nargsi instead of n: - * string foo(T...)() { return ""; } - * void main() { foo!(int, char)(); } - */ - //memcpy(dedargs->data, targsi->data, n * sizeof(*dedargs->data)); - memcpy(dedargs->data, targsi->data, nargsi * sizeof(*dedargs->data)); - - for (size_t i = 0; i < n; i++) - { assert(i < parameters->dim); - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - MATCH m; - Declaration *sparam = NULL; - - 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 = (Object *)dedargs->data[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 - { - Tuple *t = new Tuple(); - //printf("t = %p\n", t); - dedargs->data[parameters->dim - 1] = (void *)t; - declareParameter(paramscope, tp, t); - goto L2; - } - else if (nfargs < nfparams - 1) - goto L1; - else - { - /* Figure out which of the function parameters matches - * the tuple template parameter. Do this by matching - * type identifiers. - * Set the index of this function parameter to fptupindex. - */ - for (fptupindex = 0; fptupindex < nfparams; fptupindex++) - { - Parameter *fparam = (Parameter *)fparameters->data[fptupindex]; - if (fparam->type->ty != Tident) - continue; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (!tp->ident->equals(tid->ident) || tid->idents.dim) - continue; - - if (fvarargs) // variadic function doesn't - goto Lnomatch; // go with variadic template - - /* 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]; - - // Check invalid arguments to detect errors early. - if (farg->op == TOKerror || farg->type->ty == Terror) - goto Lnomatch; - - t->objects.data[i] = (void *)farg->type; - } - declareParameter(paramscope, tp, t); - goto L2; - } - fptupindex = -1; - } - } - -L1: - if (nfparams == nfargs) - ; - else if (nfargs > nfparams) - { - if (fvarargs == 0) - goto Lnomatch; // too many args, no match - match = MATCHconvert; // match ... with a conversion - } - -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; - if (stc & (STCshared | STCsynchronized)) - mod |= MODshared; - if (stc & STCimmutable) - mod |= MODimmutable; - if (stc & STCconst) - mod |= MODconst; - if (stc & STCwild) - mod |= MODwild; - // Fix mod - if (mod & MODimmutable) - mod = MODimmutable; - if (mod & MODconst) - mod &= ~STCwild; - if (tthis->mod != mod) - { - if (!MODimplicitConv(tthis->mod, mod)) - goto Lnomatch; - if (MATCHconst < match) - match = MATCHconst; - } - } - } -#endif - - // Loop through the function parameters - for (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]; - - // Check invalid arguments to detect errors early. - if (farg->op == TOKerror || farg->type->ty == Terror) - goto Lnomatch; - -#if 0 - printf("\tfarg->type = %s\n", farg->type->toChars()); - printf("\tfparam->type = %s\n", fparam->type->toChars()); -#endif - Type *argtype = farg->type; - -#if DMDV2 - /* Allow string literals which are type [] to match with [dim] - */ - if (farg->op == TOKstring) - { StringExp *se = (StringExp *)farg; - if (!se->committed && argtype->ty == Tarray && - fparam->type->toBasetype()->ty == Tsarray) - { - argtype = new TypeSArray(argtype->nextOf(), new IntegerExp(se->loc, se->len, Type::tindex)); - argtype = argtype->semantic(se->loc, NULL); - argtype = argtype->invariantOf(); - } - } - - /* Allow implicit function literals to delegate conversion - */ - if (farg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)farg; - Type *tp = fparam->type; - Expression *e = fe->inferType(tp, 1, parameters); - if (!e) - goto Lvarargs; - farg = e; - argtype = farg->type; - } - - if (!(fparam->storageClass & STClazy) && argtype->ty == Tvoid) - goto Lnomatch; - - /* 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 - - MATCH m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes); - //printf("\tdeduceType m = %d\n", m); - - /* If no match, see if there's a conversion to a delegate - */ - if (!m && fparam->type->toBasetype()->ty == Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype(); - TypeFunction *tf = (TypeFunction *)td->next; - - if (!tf->varargs && Parameter::dim(tf->parameters) == 0) - { - m = farg->type->deduceType(paramscope, tf->next, parameters, &dedtypes); - if (!m && tf->next->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - //printf("\tm2 = %d\n", m); - } - - if (m) - { if (m < match) - match = m; // pick worst match - continue; - } - } - - /* The following code for variadic arguments closely - * matches TypeFunction::callMatch() - */ - if (!(fvarargs == 2 && i + 1 == nfparams)) - goto Lnomatch; - - /* Check for match with function parameter T... - */ - Type *tb = fparam->type->toBasetype(); - switch (tb->ty) - { - // Perhaps we can do better with this, see TypeFunction::callMatch() - case Tsarray: - { TypeSArray *tsa = (TypeSArray *)tb; - dinteger_t sz = tsa->dim->toInteger(); - if (sz != nfargs - i) - goto Lnomatch; - } - case Tarray: - { TypeArray *ta = (TypeArray *)tb; - for (; i < nfargs; i++) - { - Expression *arg = (Expression *)fargs->data[i]; - assert(arg); - MATCH m; - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type *tret = fparam->isLazyArray(); - if (tret) - { - if (ta->next->equals(arg->type)) - { m = MATCHexact; - } - else - { - m = arg->implicitConvTo(tret); - if (m == MATCHnomatch) - { - if (tret->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - } - } - else - { - m = arg->type->deduceType(paramscope, ta->next, parameters, &dedtypes); - //m = arg->implicitConvTo(ta->next); - } - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - } - goto Lmatch; - } - case Tclass: - case Tident: - goto Lmatch; - - default: - goto Lnomatch; - } - } - -Lmatch: - - /* Fill in any missing arguments with their defaults. - */ - for (size_t i = nargsi; i < dedargs->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - //printf("tp[%d] = %s\n", i, tp->ident->toChars()); - /* For T:T*, the dedargs is the T*, dedtypes is the T - * But for function templates, we really need them to match - */ - Object *oarg = (Object *)dedargs->data[i]; - Object *oded = (Object *)dedtypes.data[i]; - //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); - //if (oarg) printf("oarg: %s\n", oarg->toChars()); - //if (oded) printf("oded: %s\n", oded->toChars()); - if (!oarg) - { - if (oded) - { - if (tp->specialization()) - { /* The specialization can work as long as afterwards - * the oded == oarg - */ - Declaration *sparam; - dedargs->data[i] = (void *)oded; - MATCH m2 = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam, 0); - //printf("m2 = %d\n", m2); - if (!m2) - goto Lnomatch; - if (m2 < match) - match = m2; // pick worst match - if (dedtypes.data[i] != oded) - error("specialization not allowed for deduced parameter %s", tp->ident->toChars()); - } - } - else - { oded = tp->defaultArg(loc, paramscope); - if (!oded) - goto Lnomatch; - } - declareParameter(paramscope, tp, oded); - dedargs->data[i] = (void *)oded; - } - } - -#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->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; - if (e->op == TOKerror) - goto Lnomatch; - - e = e->ctfeInterpret(); - 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)[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 (ea && ea->op == TOKtype) - targ = ea->type; - else if (ea && ea->op == TOKimport) - sa = ((ScopeExp *)ea)->sds; - else if (ea && (ea->op == TOKthis || ea->op == TOKsuper)) - sa = ((ThisExp *)ea)->var; - - if (targ) - { - //printf("type %s\n", targ->toChars()); - s = new AliasDeclaration(0, tp->ident, targ); - } - else if (sa) - { - //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars()); - s = new AliasDeclaration(0, tp->ident, sa); - } - else if (ea) - { - // tdtypes.data[i] always matches ea here - Initializer *init = new ExpInitializer(loc, ea); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - assert(tvp); - - VarDeclaration *v = new VarDeclaration(loc, tvp->valType, tp->ident, init); - v->storage_class = STCconst; - s = v; - } - else if (va) - { - //printf("\ttuple\n"); - s = new TupleDeclaration(loc, tp->ident, &va->objects); - } - else - { -#ifdef DEBUG - o->print(); -#endif - assert(0); - } - if (!sc->insert(s)) - error("declaration %s is already defined", tp->ident->toChars()); - s->semantic(sc); -} - -/************************************** - * Determine if TemplateDeclaration is variadic. - */ - -TemplateTupleParameter *isVariadic(TemplateParameters *parameters) -{ size_t dim = parameters->dim; - TemplateTupleParameter *tp = NULL; - - if (dim) - tp = ((TemplateParameter *)parameters->data[dim - 1])->isTemplateTupleParameter(); - return tp; -} - -TemplateTupleParameter *TemplateDeclaration::isVariadic() -{ - return ::isVariadic(parameters); -} - -/*********************************** - * We can overload templates. - */ - -int TemplateDeclaration::isOverloadable() -{ - return 1; -} - -/************************************************* - * Given function arguments, figure out which template function - * to expand, and return that function. - * If no match, give error message and return NULL. - * Input: - * sc instantiation scope - * loc instantiation location - * targsi initial list of template arguments - * 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; - -#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)[i]; - printf("\t%s\n", arg->toChars()); - } - } - printf(" fargs:\n"); - for (size_t i = 0; i < fargs->dim; i++) - { Expression *arg = (*fargs)[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; - } - - Objects dedargs; - - MATCH m = td->deduceFunctionTemplateMatch(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); - MATCH c2 = td_best->leastAsSpecialized(td); - //printf("c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - else - goto Lambig; - } - - Lambig: // td_best and td are ambiguous - td_ambig = td; - continue; - - Ltd_best: // td_best is the best match so far - td_ambig = NULL; - continue; - - Ltd: // td is the new best match - td_ambig = NULL; - assert((size_t)td->scope > 0x10000); - td_best = td; - m_best = m; - tdargs->setDim(dedargs.dim); - memcpy(tdargs->tdata(), dedargs.tdata(), tdargs->dim * sizeof(void *)); - continue; - } - if (!td_best) - { - error(loc, "does not match any function template declaration"); - goto Lerror; - } - if (td_ambig) - { - ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - kind(), parent->toPrettyChars(), ident->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); - fd = ti->toAlias()->isFuncDeclaration(); - if (!fd) - goto Lerror; - - /* As Bugzilla 3682 shows, a template instance can be matched while instantiating - * that same template. Thus, the function type can be incomplete. Complete it. - */ - { TypeFunction *tf = (TypeFunction *)fd->type; - assert(tf->ty == Tfunction); - if (tf->next) - fd->type = tf->semantic(loc, sc); - } - - return fd; - - 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)[i]; - ObjectToCBuffer(&bufa, &hgs, oarg); - } - } - - OutBuffer buf; - argExpTypesToCBuffer(&buf, fargs, &hgs); - if (this->overnext) - ::error(this->loc, "%s %s.%s cannot deduce template function from argument types !(%s)(%s)", - kind(), parent->toPrettyChars(), ident->toChars(), - bufa.toChars(), buf.toChars()); - else - error("cannot deduce template function from argument types !(%s)(%s)", - bufa.toChars(), buf.toChars()); - } - return NULL; -} - -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 = (TemplateParameter *)parameters->data[i]; - if (hgs->ddoc) - tp = (TemplateParameter *)origParameters->data[i]; - if (i) - buf->writeByte(','); - tp->toCBuffer(buf, hgs); - } - buf->writeByte(')'); -#if DMDV2 - if (constraint) - { buf->writestring(" if ("); - constraint->toCBuffer(buf, hgs); - buf->writeByte(')'); - } -#endif - - if (hgs->hdrgen) - { - hgs->tpltMember++; - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->toCBuffer(buf, hgs); - } - buf->writebyte('}'); - buf->writenl(); - hgs->tpltMember--; - } -} - - -char *TemplateDeclaration::toChars() -{ OutBuffer buf; - HdrGenState hgs; - - memset(&hgs, 0, sizeof(hgs)); - buf.writestring(ident->toChars()); - buf.writeByte('('); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - if (i) - buf.writeByte(','); - tp->toCBuffer(&buf, &hgs); - } - buf.writeByte(')'); -#if DMDV2 - if (constraint) - { buf.writestring(" if ("); - constraint->toCBuffer(&buf, &hgs); - buf.writeByte(')'); - } -#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) -{ -#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); - } - - TemplateParameter *tp = parameters->tdata()[i]; - - // Found the corresponding parameter tp - if (!tp->isTemplateTypeParameter()) - goto Lnomatch; - Type *at = (Type *)dedtypes->data[i]; - if (!at) - { - dedtypes->data[i] = (void *)this; - goto Lexact; - } - if (equals(at)) - goto Lexact; - else if (ty == Tclass && at->ty == Tclass) - { - return (MATCH) implicitConvTo(at); - } - else if (ty == Tsarray && at->ty == Tarray && - nextOf()->equals(at->nextOf())) - { - goto Lexact; - } - else - goto Lnomatch; - } - 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); - -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) -{ -#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); - 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); - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); - - Lnomatch: - return MATCHnomatch; -} - -MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ -#if 0 - printf("TypeAArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // Extra check that index type must match - if (tparam && tparam->ty == Taarray) - { - TypeAArray *tp = (TypeAArray *)tparam; - if (!index->deduceType(sc, tp->index, parameters, dedtypes)) - { - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - //printf("TypeFunction::deduceType()\n"); - //printf("\tthis = %d, ", ty); print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - - // Extra check that function characteristics must match - if (tparam && tparam->ty == Tfunction) - { - TypeFunction *tp = (TypeFunction *)tparam; - if (varargs != tp->varargs || - linkage != tp->linkage) - return MATCHnomatch; - - size_t nfargs = Parameter::dim(this->parameters); - size_t nfparams = Parameter::dim(tp->parameters); - - /* See if tuple match - */ - if (nfparams > 0 && nfargs >= nfparams - 1) - { - /* See if 'A' of the template parameter matches 'A' - * of the type of the last function parameter. - */ - 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)[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)[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[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[i] = arg->type; - } - (*dedtypes)[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)) - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - // Extra check - if (tparam && tparam->ty == Tident) - { - TypeIdentifier *tp = (TypeIdentifier *)tparam; - - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id1 = idents[i]; - Identifier *id2 = tp->idents[i]; - - if (!id1->equals(id2)) - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeInstance::deduceType(Scope *sc, - Type *tparam, TemplateParameters *parameters, - Objects *dedtypes) -{ -#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 - */ - TypeIdentifier *tid = new TypeIdentifier(0, tp->tempinst->name); - Type *t; - Expression *e; - Dsymbol *s; - tid->resolve(0, sc, &e, &t, &s); - if (t) - { - s = t->toDsymbol(sc); - if (s) - { TemplateInstance *ti = s->parent->isTemplateInstance(); - s = ti ? ti->tempdecl : NULL; - } - } - if (s) - { - s = s->toAlias(); - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td && td == tempinst->tempdecl) - goto L2; - } - goto Lnomatch; - } - TemplateParameter *tpx = (*parameters)[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)[i]) - { // Must match already deduced symbol - Object *s = (*dedtypes)[i]; - - if (s != sa) - goto Lnomatch; - } - (*dedtypes)[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 = NULL; - if (i < tempinst->tiargs->dim) - o1 = (*tempinst->tiargs)[i]; - else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) - // Pick up default arg - o1 = tempinst->tdtypes[i]; - else if (i >= tp->tempinst->tiargs->dim) - break; - - if (i >= tp->tempinst->tiargs->dim) - goto Lnomatch; - - Object *o2 = (*tp->tempinst->tiargs)[i]; - Type *t2 = isType(o2); - - int j; - if (t2 && - t2->ty == Tident && - i == tp->tempinst->tiargs->dim - 1 && - (j = templateParameterLookup(t2, parameters), j != -1) && - j == parameters->dim - 1 && - (*parameters)[j]->isTemplateTupleParameter()) - { - /* 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) - */ - - /* Create tuple from remaining args - */ - Tuple *vt = new Tuple(); - size_t vtdim = (tempinst->tempdecl->isVariadic() - ? tempinst->tiargs->dim : tempinst->tdtypes.dim) - i; - vt->objects.setDim(vtdim); - for (size_t k = 0; k < vtdim; k++) - { - Object *o; - if (k < tempinst->tiargs->dim) - o = (*tempinst->tiargs)[i + k]; - else // Pick up default arg - o = tempinst->tdtypes[i + k]; - vt->objects[k] = o; - } - - Tuple *v = (Tuple *)(*dedtypes)[j]; - if (v) - { - if (!match(v, vt, tempinst->tempdecl, sc)) - goto Lnomatch; - } - else - (*dedtypes)[j] = vt; - break; //return MATCHexact; - } - else if (!o1) - break; - - Type *t1 = isType(o1); - - 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 - - if (t1 && t2) - { - if (!t1->deduceType(sc, t2, parameters, dedtypes)) - goto Lnomatch; - } - else if (e1 && e2) - { - Le: - e1 = e1->ctfeInterpret(); - e2 = e2->ctfeInterpret(); - - //printf("e1 = %s, type = %s %d\n", e1->toChars(), e1->type->toChars(), e1->type->ty); - //printf("e2 = %s, type = %s %d\n", e2->toChars(), e2->type->toChars(), e2->type->ty); - if (!e1->equals(e2)) - { if (e2->op == TOKvar) - { - /* - * (T:Number!(e2), int e2) - */ - j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); - goto L1; - } - if (!e2->implicitConvTo(e1->type)) - goto Lnomatch; - - e2 = e2->implicitCastTo(sc, e1->type); - e2 = e2->ctfeInterpret(); - if (!e1->equals(e2)) - goto Lnomatch; - } - } - else if (e1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - L1: - if (j == -1) - { - t2->resolve(loc, sc, &e2, &t2, &s2); - if (e2) - goto Le; - goto Lnomatch; - } - TemplateParameter *tp = (*parameters)[j]; - // BUG: use tp->matchArg() instead of the following - TemplateValueParameter *tv = tp->isTemplateValueParameter(); - if (!tv) - goto Lnomatch; - Expression *e = (Expression *)(*dedtypes)[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)[j] = e1; - } - } - else if (s1 && s2) - { - Ls: - if (!s1->equals(s2)) - goto Lnomatch; - } - else if (s1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - if (j == -1) - { - t2->resolve(loc, sc, &e2, &t2, &s2); - if (s2) - goto Ls; - goto Lnomatch; - } - TemplateParameter *tp = (*parameters)[j]; - // BUG: use tp->matchArg() instead of the following - TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); - if (!ta) - goto Lnomatch; - Dsymbol *s = (Dsymbol *)(*dedtypes)[j]; - if (s) - { - if (!s1->equals(s)) - goto Lnomatch; - } - else - { - (*dedtypes)[j] = s1; - } - } - else - goto Lnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); - -Lnomatch: - //printf("no match\n"); - return MATCHnomatch; -} - -MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - //printf("TypeStruct::deduceType()\n"); - //printf("\tthis->parent = %s, ", sym->parent->toChars()); print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - - /* If this struct is a template struct, and we're matching - * it against a template instance, convert the struct type - * to a template instance, too, and try again. - */ - TemplateInstance *ti = sym->parent->isTemplateInstance(); - - if (tparam && tparam->ty == Tinstance) - { - if (ti && ti->toAlias() == sym) - { - TypeInstance *t = new TypeInstance(0, ti); - return t->deduceType(sc, tparam, parameters, dedtypes); - } - - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.dim) - { Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1]; - if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) - { - Type *tparent = sym->parent->getType(); - if (tparent) - { - /* Slice off the .foo in S!(T).foo - */ - tpi->idents.dim--; - MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes); - tpi->idents.dim++; - return m; - } - } - } - } - - // Extra check - if (tparam && tparam->ty == Tstruct) - { - TypeStruct *tp = (TypeStruct *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - // Extra check - if (tparam && tparam->ty == Tenum) - { - TypeEnum *tp = (TypeEnum *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - // Extra check - if (tparam && tparam->ty == Ttypedef) - { - TypeTypedef *tp = (TypeTypedef *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -/* 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->data, dedtypes->data, dedtypes->dim * sizeof(void *)); - - TypeInstance *t = new TypeInstance(0, parti); - MATCH m = t->deduceType(sc, tparam, parameters, tmpdedtypes); - if (m != MATCHnomatch) - { - // If this is the first ever match, it becomes our best estimate - if (numBaseClassMatches==0) - memcpy(best->data, tmpdedtypes->data, tmpdedtypes->dim * sizeof(void *)); - else for (size_t k = 0; k < tmpdedtypes->dim; ++k) - { - // If we've found more than one possible type for a parameter, - // mark it as unknown. - if (tmpdedtypes->data[k] != best->data[k]) - best->data[k] = dedtypes->data[k]; - } - ++numBaseClassMatches; - } - } - // Now recursively test the inherited interfaces - for (size_t j = 0; j < b->baseInterfaces_dim; ++j) - { - deduceBaseClassParameters( &(b->baseInterfaces)[j], - sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - } - -} - -MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - //printf("TypeClass::deduceType(this = %s)\n", toChars()); - - /* 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); - // Even if the match fails, there is still a chance it could match - // a base class. - if (m != MATCHnomatch) - return m; - } - - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.dim) - { Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1]; - if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) - { - Type *tparent = sym->parent->getType(); - if (tparent) - { - /* Slice off the .foo in S!(T).foo - */ - tpi->idents.dim--; - MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes); - tpi->idents.dim++; - return m; - } - } - } - - // If it matches exactly or via implicit conversion, we're done - MATCH m = Type::deduceType(sc, tparam, parameters, dedtypes); - if (m != MATCHnomatch) - return m; - - /* There is still a chance to match via implicit conversion to - * a base class or interface. Because there could be more than one such - * match, we need to check them all. - */ - - int numBaseClassMatches = 0; // Have we found an interface match? - - // Our best guess at dedtypes - Objects *best = new Objects(); - best->setDim(dedtypes->dim); - - ClassDeclaration *s = sym; - while(s && s->baseclasses->dim > 0) - { - // Test the base class - deduceBaseClassParameters((BaseClass *)(s->baseclasses->data[0]), - sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - - // Test the interfaces inherited by the base class - for (size_t i = 0; i < s->interfaces_dim; ++i) - { - BaseClass *b = s->interfaces[i]; - deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - } - s = ((BaseClass *)(s->baseclasses->data[0]))->base; - } - - if (numBaseClassMatches == 0) - return MATCHnomatch; - - // If we got at least one match, copy the known types into dedtypes - memcpy(dedtypes->data, best->data, best->dim * sizeof(void *)); - return MATCHconvert; - } - - // Extra check - if (tparam && tparam->ty == Tclass) - { - TypeClass *tp = (TypeClass *)tparam; - - //printf("\t%d\n", (MATCH) implicitConvTo(tp)); - return implicitConvTo(tp); - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -/* ======================== TemplateParameter =============================== */ - -TemplateParameter::TemplateParameter(Loc loc, Identifier *ident) -{ - this->loc = loc; - this->ident = ident; - this->sparam = NULL; -} - -TemplateTypeParameter *TemplateParameter::isTemplateTypeParameter() -{ - return NULL; -} - -TemplateValueParameter *TemplateParameter::isTemplateValueParameter() -{ - return NULL; -} - -TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter() -{ - return NULL; -} - -TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter() -{ - return NULL; -} - -#if DMDV2 -TemplateThisParameter *TemplateParameter::isTemplateThisParameter() -{ - return NULL; -} -#endif - -/* ======================== TemplateTypeParameter =========================== */ - -// type-parameter - -TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, - Type *defaultType) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specType = specType; - this->defaultType = defaultType; -} - -TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter() -{ - return this; -} - -TemplateParameter *TemplateTypeParameter::syntaxCopy() -{ - TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - if (defaultType) - tp->defaultType = defaultType->syntaxCopy(); - return tp; -} - -void TemplateTypeParameter::declareParameter(Scope *sc) -{ - //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars()); - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - sparam = new AliasDeclaration(loc, ident, ti); - if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); -} - -void TemplateTypeParameter::semantic(Scope *sc) -{ - //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars()); - if (specType) - { - specType = specType->semantic(loc, sc); - } -#if 0 // Don't do semantic() until instantiation - if (defaultType) - { - defaultType = defaultType->semantic(loc, sc); - } -#endif -} - -/**************************************** - * Determine if two TemplateParameters are the same - * as far as TemplateDeclaration overloading goes. - * Returns: - * 1 match - * 0 no match - */ - -int TemplateTypeParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - - if (ttp) - { - if (specType != ttp->specType) - goto Lnomatch; - - if (specType && !specType->equals(ttp->specType)) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - -/******************************************* - * Match to a particular TemplateParameter. - * Input: - * i i'th argument - * tiargs[] actual arguments to template instance - * parameters[] template parameters - * dedtypes[] deduced arguments to template instance - * *psparam set to symbol declared and initialized to dedtypes[i] - * flags 1: don't do 'toHeadMutable()' - */ - -MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam, int flags) -{ - //printf("TemplateTypeParameter::matchArg()\n"); - Type *t; - Object *oarg; - MATCH m = MATCHexact; - Type *ta; - - if (i < tiargs->dim) - oarg = (Object *)tiargs->data[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = (Object *)dedtypes->data[i]; - if (!oarg) - goto Lnomatch; - } - } - - ta = isType(oarg); - if (!ta) - goto Lnomatch; - //printf("ta is %s\n", ta->toChars()); - - t = (Type *)dedtypes->data[i]; - - if (specType) - { - //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars()); - MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes); - if (m2 == MATCHnomatch) - { //printf("\tfailed deduceType\n"); - goto Lnomatch; - } - - if (m2 < m) - m = m2; - t = (Type *)dedtypes->data[i]; - } - else - { - // So that matches with specializations are better - m = MATCHconvert; - if (t) - { // Must match already deduced type - - m = MATCHexact; - if (!t->equals(ta)) - { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); - goto Lnomatch; - } - } - } - - if (!t) - { - dedtypes->data[i] = ta; - t = ta; - } - *psparam = new AliasDeclaration(loc, ident, t); - //printf("\tm = %d\n", m); - return m; - -Lnomatch: - *psparam = NULL; - //printf("\tm = %d\n", MATCHnomatch); - return MATCHnomatch; -} - - -void TemplateTypeParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Type *t = isType(oarg); - Type *ta = isType(oded); - - assert(ta); - - if (specType) - printf("\tSpecialization: %s\n", specType->toChars()); - if (defaultType) - printf("\tDefault: %s\n", defaultType->toChars()); - printf("\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 (?) - t = new TypeIdentifier(loc, ident); - } - 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 *specAliasT, Type *defaultAlias) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specAliasT = specAliasT; - this->defaultAlias = defaultAlias; - - this->specAlias = NULL; -} - -TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() -{ - return this; -} - -TemplateParameter *TemplateAliasParameter::syntaxCopy() -{ - TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specAliasT, defaultAlias); - if (tp->specAliasT) - tp->specAliasT = specAliasT->syntaxCopy(); - if (defaultAlias) - tp->defaultAlias = defaultAlias->syntaxCopy(); - return tp; -} - -void TemplateAliasParameter::declareParameter(Scope *sc) -{ - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - sparam = new AliasDeclaration(loc, ident, ti); - if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); -} - -void TemplateAliasParameter::semantic(Scope *sc) -{ - if (specAliasT) - { - specAlias = specAliasT->toDsymbol(sc); - if (!specAlias) - error(loc, "%s is not a symbol", specAliasT->toChars()); - } -#if 0 // Don't do semantic() until instantiation - if (defaultAlias) - defaultAlias = defaultAlias->semantic(loc, sc); -#endif -} - -int TemplateAliasParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); - - if (tap) - { - if (specAlias != tap->specAlias) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - -MATCH TemplateAliasParameter::matchArg(Scope *sc, - Objects *tiargs, size_t i, TemplateParameters *parameters, - Objects *dedtypes, - Declaration **psparam, int flags) -{ - Dsymbol *sa; - Object *oarg; - Expression *ea; - - //printf("TemplateAliasParameter::matchArg()\n"); - - if (i < tiargs->dim) - oarg = (*tiargs)[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = (*dedtypes)[i]; - if (!oarg) - goto Lnomatch; - } - } - - sa = getDsymbol(oarg); - if (!sa) - goto Lnomatch; - - if (specAlias) - { - if (!sa || sa == sdummy) - goto Lnomatch; - if (sa != specAlias && isDsymbol(sa)) - { - TemplateInstance *ti = isDsymbol(sa)->isTemplateInstance(); - Type *ta = isType(specAlias); - if (!ti || !ta) - goto Lnomatch; - Type *t = new TypeInstance(0, ti); - MATCH m = t->deduceType(sc, ta, parameters, dedtypes); - if (m == MATCHnomatch) - goto Lnomatch; - } - } - else if ((*dedtypes)[i]) - { // Must match already deduced symbol - Object *si = (*dedtypes)[i]; - - if (!sa || si != sa) - goto Lnomatch; - } - (*dedtypes)[i] = sa; - - *psparam = new AliasDeclaration(loc, ident, sa); - 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 "); - buf->writestring(ident->toChars()); - if (specAliasT) - { - buf->writestring(" : "); - specAliasT->toCBuffer(buf, NULL, hgs); - } - if (defaultAlias) - { - buf->writestring(" = "); - defaultAlias->toCBuffer(buf, NULL, hgs); - } -} - - -void *TemplateAliasParameter::dummyArg() -{ Dsymbol *s; - - s = specAlias; - if (!s) - { - if (!sdummy) - sdummy = new Dsymbol(); - s = sdummy; - } - return (void*)s; -} - - -Object *TemplateAliasParameter::specialization() -{ - return specAliasT; -} - - -Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) -{ - Dsymbol *s = NULL; - - if (defaultAlias) - { - s = defaultAlias->toDsymbol(sc); - if (!s) - error(Loc(0), "%s is not a symbol", defaultAlias->toChars()); - } - return s; -} - -/* ======================== 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) -{ - bool wasSame = (sparam->type == valType); - sparam->semantic(sc); - if (sparam->type == Type::terror && wasSame) - { // If sparam has a type error, avoid duplicate errors - valType = Type::terror; - return; - } - 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->ctfeInterpret(); - 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->ctfeInterpret(); - 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, int flags) -{ - //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 (specValue) - { - if (!ei || _aaGetRvalue(edummies, ei->type) == ei) - goto Lnomatch; - - Expression *e = specValue; - - e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); - e = e->ctfeInterpret(); - - ei = ei->syntaxCopy(); - ei = ei->semantic(sc); - ei = ei->ctfeInterpret(); - //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars()); - //printf("e : %s, %s\n", e->toChars(), e->type->toChars()); - if (!ei->equals(e)) - goto Lnomatch; - } - else if (dedtypes->data[i]) - { // Must match already deduced value - Expression *e = (Expression *)dedtypes->data[i]; - - if (!ei || !ei->equals(e)) - goto Lnomatch; - } -Lmatch: - //printf("valType: %s, ty = %d\n", valType->toChars(), valType->ty); - vt = valType->semantic(0, sc); - //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars()); - if (ei->type) - { - m = (MATCH)ei->implicitConvTo(vt); - //printf("m: %d\n", m); - if (!m) - goto Lnomatch; - } - dedtypes->data[i] = ei; - - init = new ExpInitializer(loc, ei); - sparam = new VarDeclaration(loc, vt, ident, init); - sparam->storage_class = STCconst; - *psparam = sparam; - return m; - -Lnomatch: - //printf("\tno match\n"); - *psparam = NULL; - return MATCHnomatch; -} - - -void TemplateValueParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Expression *ea = isExpression(oded); - - if (specValue) - printf("\tSpecialization: %s\n", specValue->toChars()); - printf("\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, int flags) -{ - //printf("TemplateTupleParameter::matchArg()\n"); - - /* The rest of the actual arguments (tiargs[]) form the match - * for the variadic parameter. - */ - assert(i + 1 == dedtypes->dim); // must be the last one - Tuple *ovar; - if (dedtypes->data[i] && isTuple((Object *)dedtypes->data[i])) - // It was already been deduced - ovar = isTuple((Object *)dedtypes->data[i]); - else if (i + 1 == tiargs->dim && isTuple((Object *)tiargs->data[i])) - ovar = isTuple((Object *)tiargs->data[i]); - else - { - ovar = new Tuple(); - //printf("ovar = %p\n", ovar); - if (i < tiargs->dim) - { - //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim); - ovar->objects.setDim(tiargs->dim - i); - for (size_t j = 0; j < ovar->objects.dim; j++) - ovar->objects.data[j] = tiargs->data[i + j]; - } - } - *psparam = new TupleDeclaration(loc, ident, &ovar->objects); - dedtypes->data[i] = (void *)ovar; - return MATCHexact; -} - - -void TemplateTupleParameter::print(Object *oarg, Object *oded) -{ - printf(" %s... [", ident->toChars()); - Tuple *v = isTuple(oded); - assert(v); - - //printf("|%d| ", v->objects.dim); - for (size_t i = 0; i < v->objects.dim; i++) - { - if (i) - printf(", "); - - Object *o = (Object *)v->objects.data[i]; - - Dsymbol *sa = isDsymbol(o); - if (sa) - printf("alias: %s", sa->toChars()); - - Type *ta = isType(o); - if (ta) - printf("type: %s", ta->toChars()); - - Expression *ea = isExpression(o); - if (ea) - printf("exp: %s", ea->toChars()); - - assert(!isTuple(o)); // no nested Tuple arguments - } - - printf("]\n"); -} - -void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - buf->writestring("..."); -} - - -void *TemplateTupleParameter::dummyArg() -{ - return NULL; -} - - -Object *TemplateTupleParameter::specialization() -{ - return NULL; -} - - -Object *TemplateTupleParameter::defaultArg(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 = PASSinit; - this->semantictiargsdone = 0; - this->withsym = NULL; - this->nest = 0; - this->havetempdecl = 0; - this->isnested = NULL; - this->speculative = 0; - -#if IN_LLVM - // LDC - 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 = PASSinit; - this->semantictiargsdone = 1; - this->withsym = NULL; - this->nest = 0; - this->havetempdecl = 1; - this->isnested = NULL; - this->speculative = 0; - -#if IN_LLVM - // LDC - 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++) - { - Type *ta = isType((Object *)objs->data[i]); - if (ta) - a->data[i] = ta->syntaxCopy(); - else - { - Expression *ea = isExpression((Object *)objs->data[i]); - assert(ea); - a->data[i] = ea->syntaxCopy(); - } - } - } - return a; -} - -Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) -{ - TemplateInstance *ti; - - if (s) - ti = (TemplateInstance *)s; - else - ti = new TemplateInstance(loc, name); - - ti->tiargs = arraySyntaxCopy(tiargs); - - ScopeDsymbol::syntaxCopy(ti); - return ti; -} - - -void TemplateInstance::semantic(Scope *sc) -{ - if (global.errors) - { - if (!global.gag) - { - /* Trying to soldier on rarely generates useful messages - * at this point. - */ - fatal(); - } - //return; - } -#if LOG - printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); -#endif - if (inst) // if semantic() was already run - { -#if LOG - printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst); -#endif - return; - } - - // get the enclosing template instance from the scope tinst - tinst = sc->tinst; - - if (semanticRun != PASSinit) - { -#if LOG - printf("Recursive template expansion\n"); -#endif - error(loc, "recursive template expansion"); -// inst = this; - return; - } - semanticRun = PASSsemantic; - - // 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()); - -#if LOG - printf("\tdo semantic\n"); -#endif - if (havetempdecl) - { - assert((size_t)tempdecl->scope > 0x10000); - // Deduce tdtypes - tdtypes.setDim(tempdecl->parameters->dim); - if (!tempdecl->matchWithInstance(this, &tdtypes, 0)) - { - error("incompatible arguments for template instantiation"); - inst = this; - return; - } - } - else - { - /* Find template declaration first. - */ - tempdecl = findTemplateDeclaration(sc); - if (!tempdecl) - { if (!sc->parameterSpecialization) - inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } - - /* Run semantic on each argument, place results in tiargs[] - * (if we have tempdecl, then tiargs is already evaluated) - */ - semanticTiargs(sc); - if (arrayObjectIsError(tiargs)) - { if (!sc->parameterSpecialization) - inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } - - tempdecl = findBestMatch(sc); - if (!tempdecl || global.errors) - { if (!sc->parameterSpecialization) - inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } - } - - 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[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 - for (size_t j = 0; j < tdtypes.dim; j++) - { Object *o1 = (Object *)tdtypes.data[j]; - Object *o2 = (Object *)ti->tdtypes.data[j]; - if (!match(o1, o2, tempdecl, sc)) - { - goto L1; - } - } - - // It's a match - inst = ti; - parent = ti->parent; - - // If 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, %d\n", inst, inst->semanticRun); -#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(); // 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 1 // 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 (size_t i = 0; 1; i++) - { - if (i == a->dim) - { - target_symbol_list = a; - target_symbol_list_idx = i; - a->push(this); - break; - } - if (this == (*a)[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); - - // 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)[i]; -#if LOG - printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum); -#endif - memnum |= s->addMember(scope, this, memnum); - } -#if LOG - printf("adding members done\n"); -#endif - - /* See if there is only one member of template instance, and that - * member has the same name as the template instance. - * If so, this template instance becomes an alias for that member. - */ - //printf("members->dim = %d\n", members->dim); - if (members->dim) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s) && s) - { - //printf("s->kind = '%s'\n", s->kind()); - //s->print(); - //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); - if (s->ident && s->ident->equals(tempdecl->ident)) - { - //printf("setting aliasdecl\n"); - aliasdecl = new AliasDeclaration(loc, s->ident, s); - -#if IN_LLVM - // LDC propagate internal information - if (tempdecl->llvmInternal) { - s->llvmInternal = tempdecl->llvmInternal; - if (FuncDeclaration* fd = s->isFuncDeclaration()) { - fd->intrinsicName = tempdecl->intrinsicName; - } - } -#endif - } - } - } - - // 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->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[i]; - - if (sd->parent == this) - goto Laftersemantic; - } - - /* The problem is when to parse the initializer for a variable. - * Perhaps VarDeclaration::semantic() should do it like it does - * for initializers inside a function. - */ -// if (sc->parent->isFuncDeclaration()) - - /* BUG 782: this has problems if the classes this depends on - * are forward referenced. Find a way to defer semantic() - * on this template. - */ - semantic2(sc2); - - if (sc->func || dosemantic3) - { -#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(); - if (!global.gag) - fatal(); - } - 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)[target_symbol_list_idx] == this); - target_symbol_list->remove(target_symbol_list_idx); - } - semanticRun = PASSinit; - 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() %s\n", toChars()); - if (!tiargs) - return; - for (size_t j = 0; j < tiargs->dim; j++) - { - Object *o = (*tiargs)[j]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - - //printf("1: (*tiargs)[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); - if (ta) - { - //printf("type %s\n", ta->toChars()); - // It might really be an Expression or an Alias - ta->resolve(loc, sc, &ea, &ta, &sa); - if (ea) - { - ea = ea->semantic(sc); - ea = ea->ctfeInterpret(); - (*tiargs)[j] = ea; - } - else if (sa) - { - Ldsym: - (*tiargs)[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)[i]; - tiargs->insert(j + i, arg->type); - } - } - j--; - } - else - (*tiargs)[j] = ta; - } - else - { - assert(global.errors); - (*tiargs)[j] = Type::terror; - } - } - else if (ea) - { - if (!ea) - { assert(global.errors); - ea = new ErrorExp(); - } - assert(ea); - ea = ea->semantic(sc); - ea = ea->ctfeInterpret(); - (*tiargs)[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)[i]); - } - j--; - } - } - else if (sa) - { - } - else - { - assert(0); - } - //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); - } -#if 0 - printf("-TemplateInstance::semanticTiargs('%s', this=%p)\n", toChars(), this); - for (size_t j = 0; j < tiargs->dim; j++) - { - Object *o = (*tiargs)[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 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) -{ - /* 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->data[0]); - - // If more arguments than parameters, - // then this is no match. - if (td->parameters->dim < tiargs->dim) - { - if (!td->isVariadic()) - continue; - } - - dedtypes.setDim(td->parameters->dim); - dedtypes.zero(); - assert(td->semanticRun); - m = td->matchWithInstance(this, &dedtypes, 0); - //printf("matchWithInstance = %d\n", m); - if (!m) // no match at all - continue; - - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; - - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best); - MATCH c2 = td_best->leastAsSpecialized(td); - //printf("c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - else - goto Lambig; - } - - Lambig: // td_best and td are ambiguous - td_ambig = td; - continue; - - Ltd_best: // td_best is the best match so far - td_ambig = NULL; - continue; - - Ltd: // td is the new best match - td_ambig = NULL; - td_best = td; - m_best = m; - tdtypes.setDim(dedtypes.dim); - memcpy(tdtypes.data, dedtypes.data, tdtypes.dim * sizeof(void *)); - continue; - } - - if (!td_best) - { - 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(loc, "%s %s.%s does not match any template declaration", - tempdecl->kind(), tempdecl->parent->toPrettyChars(), tempdecl->ident->toChars()); - return NULL; - } - if (td_ambig) - { - ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - td_best->kind(), td_best->parent->toPrettyChars(), td_best->ident->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 = (Object *)tiargs->data[i]; - Expression *ea = isExpression(o); // value argument - TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - if (tvp) - { - assert(ea); - ea = ea->castTo(tvp->valType); - ea = ea->ctfeInterpret(); - tiargs->data[i] = (Object *)ea; - } - } -#endif - -#if LOG - printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars()); -#endif - return tempdecl; -} - - -/***************************************** - * Determines if a TemplateInstance will need a nested - * generation of the TemplateDeclaration. - */ - -int TemplateInstance::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)[i]; - Expression *ea = isExpression(o); - Type *ta = isType(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - //printf("o %p ea %p ta %p sa %p va %p\n", o, ea, ta, sa, va); - if (ea) - { - if (ea->op == TOKvar) - { - sa = ((VarExp *)ea)->var; - goto Lsa; - } - if (ea->op == TOKthis) - { - sa = ((ThisExp *)ea)->var; - goto Lsa; - } - if (ea->op == TOKfunction) - { - sa = ((FuncExp *)ea)->fd; - goto Lsa; - } - } - else if (ta) - { - if (ta->ty == Tstruct || ta->ty == Tclass) - { sa = ta->toDsymbol(NULL); - TemplateInstance *ti = sa->parent->isTemplateInstance(); - if (ti && ti->isnested) - { sa = ti; - goto Lsa; - } - } - } - else if (sa) - { - Lsa: - //printf("sa = %s %s\n", sa->kind(), sa->toChars()); - Declaration *d = sa->isDeclaration(); - TemplateInstance *ad = sa->isTemplateInstance(); - if ( - (ad && ad->isnested) || - (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->toPrettyChars(), dparent->toPrettyChars()); - } - 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() -{ OutBuffer buf; - - //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); - char *id = tempdecl->ident->toChars(); - buf.printf("__T%zu%s", strlen(id), id); - Objects *args = tiargs; - for (size_t i = 0; i < args->dim; i++) - { Object *o = (Object *)args->data[i]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); - if (ta) - { - buf.writeByte('T'); - if (ta->deco) - buf.writestring(ta->deco); - else - { -#ifdef DEBUG - printf("ta = %d, %s\n", ta->ty, ta->toChars()); -#endif - assert(global.errors); - } - } - else if (ea) - { - ea = ea->ctfeInterpret(); - 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; - } - 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 = (TemplateParameter *)tempdecl->parameters->data[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - assert(tvp); - buf.writestring(tvp->valType->deco); -#endif - ea->toMangleBuffer(&buf); - } - else if (sa) - { - Lsa: - buf.writeByte('S'); - Declaration *d = sa->isDeclaration(); - if (d && (!d->type || !d->type->deco)) - error("forward reference of %s", d->toChars()); - else - { - 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; - //printf("\tgenIdent = %s\n", id); - return new Identifier(id, TOKidentifier); -} - - -/**************************************************** - * 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; - } - -#if DMDV2 - for (size_t i = 0; i < td->parameters->dim; i++) - if (td->parameters->tdata()[i]->isTemplateThisParameter()) - return TRUE; -#endif - - /* Determine if the instance arguments, tiargs, are all that is necessary - * to instantiate the template. - */ - //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)) - { - TemplateParameter *tp = td->isVariadic(); - if (tp && td->parameters->dim > 1) - return TRUE; - - if (tiargs->dim < td->parameters->dim) - { // Can remain tiargs be filled by default arguments? - for (size_t i = tiargs->dim; i < td->parameters->dim; i++) - { tp = (*td->parameters)[i]; - if (TemplateTypeParameter *ttp = tp->isTemplateTypeParameter()) - { if (!ttp->defaultType) - return TRUE; - } - else if (TemplateAliasParameter *tap = tp->isTemplateAliasParameter()) - { if (!tap->defaultAlias) - return TRUE; - } - else if (TemplateValueParameter *tvp = tp->isTemplateValueParameter()) - { if (!tvp->defaultValue) - return TRUE; - } - } - } - } - } - //printf("false\n"); - return multipleMatches; -} - -void TemplateInstance::semantic2(Scope *sc) -{ int i; - - if (semanticRun >= PASSsemantic2) - return; - semanticRun = PASSsemantic2; -#if LOG - printf("+TemplateInstance::semantic2('%s')\n", toChars()); -#endif - if (!errors && members) - { - sc = tempdecl->scope; - assert(sc); - sc = sc->push(argsym); - sc = sc->push(this); - sc->tinst = this; - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; -#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 >= PASSsemantic3) - return; - semanticRun = PASSsemantic3; - if (!errors && members) - { - sc = tempdecl->scope; - sc = sc->push(argsym); - sc = sc->push(this); - sc->tinst = this; - 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)[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); - assert(0 && "multiobj"); - else - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[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)[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)[i]; - ObjectToCBuffer(buf, hgs, oarg); - } - nest--; - } - buf->writeByte(')'); -} - - -Dsymbol *TemplateInstance::toAlias() -{ -#if LOG - printf("TemplateInstance::toAlias()\n"); -#endif - if (!inst) - { - // Maybe we can resolve it - if (scope) - { - /* Anything that affects scope->offset must be - * done in lexical order. Fwd ref error if it is affected, otherwise allow. - */ - unsigned offset = scope->offset; - Scope *sc = scope; - semantic(scope); -// if (offset != sc->offset) -// inst = NULL; // trigger fwd ref error - } - 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) -{ - *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 = PASSsemantic; // do over - else - { -#if LOG - printf("\tsemantic done\n"); -#endif - return; - } - } - if (!semanticRun) - semanticRun = PASSsemantic; -#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 = PASSinit; - AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); - if (ad) - ad->sizeok = SIZEOKfwd; - 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); - if (!tempdecl) - { inst = this; - return; // error recovery - } - - if (!ident) - ident = genIdent(); - - inst = this; - parent = sc->parent; - - /* Detect recursive mixin instantiations. - */ - for (Dsymbol *s = parent; s; s = s->parent) - { - //printf("\ts = '%s'\n", s->toChars()); - TemplateMixin *tm = s->isTemplateMixin(); - if (!tm || tempdecl != tm->tempdecl) - continue; - - /* Different argument list lengths happen with variadic args - */ - if (tiargs->dim != tm->tiargs->dim) - continue; - - for (size_t i = 0; i < tiargs->dim; i++) - { Object *o = (*tiargs)[i]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Object *tmo = (*tm->tiargs)[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 (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[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)[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 >= PASSsemantic2) - return; - semanticRun = PASSsemantic2; -#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)[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 >= PASSsemantic3) - return; - semanticRun = PASSsemantic3; -#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) -{ - return Dsymbol::oneMember(ps); -} - -int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param) -{ - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - if (s) - { - if (s->apply(fp, param)) - return 1; - } - } - } - return 0; -} - -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; -} - -void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - //printf("TemplateMixin::setFieldOffset() %s\n", toChars()); - if (scope) // if fwd reference - semantic(NULL); // try to resolve it - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - //printf("\t%s\n", s->toChars()); - s->setFieldOffset(ad, poffset, isunion); - } - } -} - -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 = (Object *)tiargs->data[i]; - Type *t = isType(oarg); - Expression *e = isExpression(oarg); - Dsymbol *s = isDsymbol(oarg); - if (t) - t->toCBuffer(buf, NULL, hgs); - else if (e) - e->toCBuffer(buf, hgs); - else if (s) - { - char *p = s->ident ? s->ident->toChars() : s->toChars(); - buf->writestring(p); - } - else if (!oarg) - { - buf->writestring("NULL"); - } - else - { - assert(0); - } - } - } - buf->writebyte(')'); - if (ident) - { - buf->writebyte(' '); - buf->writestring(ident->toChars()); - } - buf->writebyte(';'); - buf->writenl(); -} - - -#if IN_DMD -void TemplateMixin::toObjFile(int multiobj) -{ - //printf("TemplateMixin::toObjFile('%s')\n", toChars()); - TemplateInstance::toObjFile(multiobj); -} -#endif - diff --git a/dmd/template.h b/dmd/template.h deleted file mode 100644 index 352b5bcd..00000000 --- a/dmd/template.h +++ /dev/null @@ -1,388 +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. - -#ifndef DMD_TEMPLATE_H -#define DMD_TEMPLATE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include - -#include "root.h" -#include "arraytypes.h" -#include "dsymbol.h" -#include "mtype.h" - - -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; -enum PASS; - -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 - - enum PASS semanticRun; // 1 semantic() run - - Dsymbol *onemember; // if !=NULL then one member of this template - - TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, - Expression *constraint, Dsymbols *decldefs); - 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, int flag); - MATCH leastAsSpecialized(TemplateDeclaration *td2); - - MATCH deduceFunctionTemplateMatch(Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, Objects *dedargs); - FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, int flags = 0); - void declareParameter(Scope *sc, TemplateParameter *tp, Object *o); - - TemplateDeclaration *isTemplateDeclaration() { return this; } - - TemplateTupleParameter *isVariadic(); - int isOverloadable(); - - void makeParamNamesVisibleInConstraint(Scope *paramscope); - -#if IN_LLVM - // LDC - std::string intrinsicName; -#endif -}; - -struct TemplateParameter -{ - /* For type-parameter: - * template Foo(ident) // specType is set to NULL - * template Foo(ident : specType) - * For value-parameter: - * template Foo(valType ident) // specValue is set to NULL - * template Foo(valType ident : specValue) - * For alias-parameter: - * template Foo(alias ident) - * For this-parameter: - * template Foo(this ident) - */ - - Loc loc; - Identifier *ident; - - Declaration *sparam; - - TemplateParameter(Loc loc, Identifier *ident); - - virtual TemplateTypeParameter *isTemplateTypeParameter(); - virtual TemplateValueParameter *isTemplateValueParameter(); - virtual TemplateAliasParameter *isTemplateAliasParameter(); -#if DMDV2 - virtual TemplateThisParameter *isTemplateThisParameter(); -#endif - virtual TemplateTupleParameter *isTemplateTupleParameter(); - - virtual TemplateParameter *syntaxCopy() = 0; - virtual void declareParameter(Scope *sc) = 0; - virtual void semantic(Scope *) = 0; - virtual void print(Object *oarg, Object *oded) = 0; - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; - virtual Object *specialization() = 0; - virtual Object *defaultArg(Loc loc, Scope *sc) = 0; - - /* If TemplateParameter's match as far as overloading goes. - */ - virtual int overloadMatch(TemplateParameter *) = 0; - - /* Match actual argument against parameter. - */ - virtual MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags = 0) = 0; - - /* Create dummy argument based on parameter. - */ - virtual void *dummyArg() = 0; -}; - -struct TemplateTypeParameter : TemplateParameter -{ - /* Syntax: - * ident : specType = defaultType - */ - Type *specType; // type parameter: if !=NULL, this is the type specialization - Type *defaultType; - - TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); - - TemplateTypeParameter *isTemplateTypeParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); - void *dummyArg(); -}; - -#if DMDV2 -struct TemplateThisParameter : TemplateTypeParameter -{ - /* Syntax: - * this ident : specType = defaultType - */ - Type *specType; // type parameter: if !=NULL, this is the type specialization - Type *defaultType; - - TemplateThisParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); - - TemplateThisParameter *isTemplateThisParameter(); - TemplateParameter *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; -#endif - -struct TemplateValueParameter : TemplateParameter -{ - /* Syntax: - * valType ident : specValue = defaultValue - */ - - Type *valType; - Expression *specValue; - Expression *defaultValue; - - static 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, int flags); - void *dummyArg(); -}; - -struct TemplateAliasParameter : TemplateParameter -{ - /* Syntax: - * specType ident : specAlias = defaultAlias - */ - - Type *specAliasT; - Dsymbol *specAlias; - - Type *defaultAlias; - - static Dsymbol *sdummy; - - TemplateAliasParameter(Loc loc, Identifier *ident, Type *specAliasT, Type *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, int flags); - void *dummyArg(); -}; - -struct TemplateTupleParameter : TemplateParameter -{ - /* Syntax: - * ident ... - */ - - TemplateTupleParameter(Loc loc, Identifier *ident); - - TemplateTupleParameter *isTemplateTupleParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); - 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 - enum PASS 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 speculative; // 1 if only instantiated with errors gagged -#ifdef IN_GCC - /* On some targets, it is necessary to know whether a symbol - will be emitted in the output or not before the symbol - is used. This can be different from getModule(). */ - Module * objFileModule; -#endif - - TemplateInstance(Loc loc, Identifier *temp_id); - TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs); - static Objects *arraySyntaxCopy(Objects *objs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Dsymbol *toAlias(); // resolve real symbol - const char *kind(); - int oneMember(Dsymbol **ps); - int needsTypeInference(Scope *sc); - char *toChars(); - char *mangle(); - void printInstantiationTrace(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - - // Internal - static void semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags); - void semanticTiargs(Scope *sc); - TemplateDeclaration *findTemplateDeclaration(Scope *sc); - TemplateDeclaration *findBestMatch(Scope *sc); - void declareParameters(Scope *sc); - int hasNestedArgs(Objects *tiargs); - Identifier *genIdent(); - - TemplateInstance *isTemplateInstance() { return this; } - AliasDeclaration *isAliasDeclaration(); - -#if IN_LLVM - // LDC - Module* tmodule; // module from outermost enclosing template instantiation - Module* emittedInModule; // which module this template instance has been emitted in - - void codegen(Ir*); -#endif -}; - -struct TemplateMixin : TemplateInstance -{ - 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); - int apply(Dsymbol_apply_ft_t fp, void *param); - int hasPointers(); - void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - 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); - -#endif /* DMD_TEMPLATE_H */ diff --git a/dmd/unialpha.c b/dmd/unialpha.c deleted file mode 100644 index 5c407180..00000000 --- a/dmd/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/dmd/utf.c b/dmd/utf.c deleted file mode 100644 index 78f8cd4a..00000000 --- a/dmd/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/dmd/utf.h b/dmd/utf.h deleted file mode 100644 index 22d8d3eb..00000000 --- a/dmd/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/dmd/version.c b/dmd/version.c deleted file mode 100644 index 37f33c06..00000000 --- a/dmd/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/dmd/version.h b/dmd/version.h deleted file mode 100644 index b5ae51d2..00000000 --- a/dmd/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 */ diff --git a/driver/cl_options.cpp b/driver/cl_options.cpp index dda40e86..76878d02 100644 --- a/driver/cl_options.cpp +++ b/driver/cl_options.cpp @@ -31,12 +31,6 @@ cl::list runargs("run", cl::Positional, cl::PositionalEatsArgs); -#if DMDV1 -static cl::opt useDeprecated("d", - cl::desc("Allow deprecated language features"), - cl::ZeroOrMore, - cl::location(global.params.useDeprecated)); -#else static cl::opt useDeprecated( cl::desc("Allow deprecated code/language features:"), cl::ZeroOrMore, @@ -47,14 +41,11 @@ static cl::opt useDeprecated( clEnumValEnd), cl::location(global.params.useDeprecated), cl::init(2)); -#endif -#if DMDV2 cl::opt enforcePropertySyntax("property", cl::desc("Enforce property syntax"), cl::ZeroOrMore, cl::location(global.params.enforcePropertySyntax)); -#endif static cl::opt useDv1( cl::desc("Force language version:"), diff --git a/driver/cl_options.h b/driver/cl_options.h index 605b21e3..d1320894 100644 --- a/driver/cl_options.h +++ b/driver/cl_options.h @@ -31,9 +31,7 @@ namespace opts { extern cl::list fileList; extern cl::list runargs; extern cl::opt compileOnly; -#if DMDV2 extern cl::opt enforcePropertySyntax; -#endif extern cl::opt createStaticLib; extern cl::opt createSharedLib; extern cl::opt noAsm; diff --git a/driver/ldmd.cpp b/driver/ldmd.cpp index 498d1032..d6de17b0 100644 --- a/driver/ldmd.cpp +++ b/driver/ldmd.cpp @@ -185,9 +185,7 @@ Usage:\n\ #if 0 " -map generate linker .map file\n" #endif -#if DMDV2 " -noboundscheck turns off array bounds checking for all functions\n" -#endif " -nofloat do not emit reference to floating point\n\ -O optimize\n\ -o- do not write object file\n\ @@ -450,18 +448,12 @@ Params parseArgs(size_t originalArgc, char** originalArgv, ls::Path ldcPath) result.verbose = true; else if (strcmp(p + 1, "vdmd") == 0) result.vdmd = true; -#if DMDV2 else if (strcmp(p + 1, "vtls") == 0) result.logTlsUse = true; -#endif else if (strcmp(p + 1, "v1") == 0) { -#if DMDV1 - // Just ignore, for backwards compatibility. -#else error("use DMD 1.0 series compilers for -v1 switch"); break; -#endif } else if (strcmp(p + 1, "w") == 0) result.warnings = Warnings::asErrors; @@ -582,10 +574,8 @@ Params parseArgs(size_t originalArgc, char** originalArgv, ls::Path ldcPath) result.quiet = 1; else if (strcmp(p + 1, "release") == 0) result.release = 1; -#if DMDV2 else if (strcmp(p + 1, "noboundscheck") == 0) result.noBoundsChecks = 1; -#endif else if (strcmp(p + 1, "unittest") == 0) result.emitUnitTests = 1; else if (p[1] == 'I') @@ -752,12 +742,10 @@ void buildCommandLine(std::vector& r, const Params& p) if (p.emitSharedLib) r.push_back("-shared"); if (p.pic) r.push_back("-relocation-model=pic"); if (p.emitMap) warning("Map file generation not yet supported by LDC."); -#ifndef DMDV1 // LDMD historically did not enable singleobj mode, so in order not to // break build systems as a D1 parting gift, don't change this right now. // This might change based on user feedback, though. if (!p.multiObj) r.push_back("-singleobj"); -#endif if (p.debugInfo == Debug::normal) r.push_back("-g"); else if (p.debugInfo == Debug::pretendC) r.push_back("-gc"); if (p.alwaysStackFrame) r.push_back("-disable-fp-elim"); diff --git a/driver/main.cpp b/driver/main.cpp index 608fbb17..4dd31edc 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -192,9 +192,7 @@ int main(int argc, char** argv) VersionCondition::addPredefinedGlobalIdent("LLVM"); // For backwards compatibility. VersionCondition::addPredefinedGlobalIdent("LDC"); VersionCondition::addPredefinedGlobalIdent("all"); -#if DMDV2 VersionCondition::addPredefinedGlobalIdent("D_Version2"); -#endif // build complete fixed up list of command line arguments std::vector final_args; @@ -210,11 +208,7 @@ int main(int argc, char** argv) ConfigFile cfg_file; // just ignore errors for now, they are still printed -#if DMDV2 #define CFG_FILENAME "ldc2.conf" -#else -#define CFG_FILENAME "ldc.conf" -#endif cfg_file.read(global.params.argv0, (void*)main, CFG_FILENAME); #undef CFG_FILENAME @@ -374,16 +368,7 @@ int main(int argc, char** argv) } else { -#if DMDV2 global.params.linkswitches->push(mem.strdup("-ldruntime-ldc")); -#else - global.params.linkswitches->push(mem.strdup("-lldc-runtime")); - global.params.linkswitches->push(mem.strdup("-ltango-cc-tango")); - global.params.linkswitches->push(mem.strdup("-ltango-gc-basic")); - // pass the runtime again to resolve issues - // with linking order - global.params.linkswitches->push(mem.strdup("-lldc-runtime")); -#endif } } @@ -748,7 +733,6 @@ int main(int argc, char** argv) if (global.params.doDocComments) VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); -#if DMDV2 // unittests? if (global.params.useUnitTests) VersionCondition::addPredefinedGlobalIdent("unittest"); @@ -758,7 +742,6 @@ int main(int argc, char** argv) if (!global.params.useArrayBounds) VersionCondition::addPredefinedGlobalIdent("D_NoBoundsChecks"); -#endif // Initialization Type::init(&ir); diff --git a/gen/aa.cpp b/gen/aa.cpp index a88b108e..1f370611 100644 --- a/gen/aa.cpp +++ b/gen/aa.cpp @@ -21,7 +21,6 @@ #include "gen/tollvm.h" #include "ir/irmodule.h" -#if DMDV2 // returns the keytype typeinfo static LLValue* to_keyti(DValue* aa) { @@ -30,15 +29,6 @@ static LLValue* to_keyti(DValue* aa) TypeAArray * aatype = static_cast(aa->type->toBasetype()); return DtoTypeInfoOf(aatype->index, false); } -#else -// returns the keytype typeinfo -static LLValue* to_keyti(DValue* key) -{ - // keyti param - Type* keytype = key->getType(); - return DtoTypeInfoOf(keytype, false); -} -#endif ///////////////////////////////////////////////////////////////////////////////////// @@ -57,11 +47,7 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue) // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey) // first get the runtime function -#if DMDV2 llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, lvalue?"_aaGetX":"_aaInX"); -#else - llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, lvalue?"_aaGet":"_aaIn"); -#endif LLFunctionType* funcTy = func->getFunctionType(); // aa param @@ -69,11 +55,7 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue) aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // keyti param -#if DMDV2 LLValue* keyti = to_keyti(aa); -#else - LLValue* keyti = to_keyti(key); -#endif keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // pkey param @@ -113,16 +95,10 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue) std::vector args; -#if DMDV2 // module param LLValue *moduleInfoSymbol = gIR->func()->decl->getModule()->moduleInfoSymbol(); LLType *moduleInfoType = DtoType(Module::moduleinfo->type); args.push_back(DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType))); -#else - // file param - IrModule* irmod = getIrModule(NULL); - args.push_back(DtoLoad(irmod->fileName)); -#endif // line param LLConstant* c = DtoConstUint(loc.linnum); @@ -154,11 +130,7 @@ DValue* DtoAAIn(Loc& loc, Type* type, DValue* aa, DValue* key) // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey) // first get the runtime function -#if DMDV2 llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaInX"); -#else - llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaIn"); -#endif LLFunctionType* funcTy = func->getFunctionType(); if (Logger::enabled()) @@ -174,11 +146,7 @@ DValue* DtoAAIn(Loc& loc, Type* type, DValue* aa, DValue* key) aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // keyti param -#if DMDV2 LLValue* keyti = to_keyti(aa); -#else - LLValue* keyti = to_keyti(key); -#endif keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // pkey param @@ -209,11 +177,7 @@ DValue *DtoAARemove(Loc& loc, DValue* aa, DValue* key) // extern(C) bool _aaDelX(AA aa, TypeInfo keyti, void* pkey) // first get the runtime function -#if DMDV2 llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaDelX"); -#else - llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaDel"); -#endif LLFunctionType* funcTy = func->getFunctionType(); if (Logger::enabled()) @@ -229,11 +193,7 @@ DValue *DtoAARemove(Loc& loc, DValue* aa, DValue* key) aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // keyti param -#if DMDV2 LLValue* keyti = to_keyti(aa); -#else - LLValue* keyti = to_keyti(key); -#endif keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // pkey param @@ -249,11 +209,7 @@ DValue *DtoAARemove(Loc& loc, DValue* aa, DValue* key) // call runtime LLCallSite call = gIR->CreateCallOrInvoke(func, args); -#if DMDV2 return new DImValue(Type::tbool, call.getInstruction()); -#else - return NULL; -#endif } ///////////////////////////////////////////////////////////////////////////////////// @@ -262,7 +218,6 @@ LLValue* DtoAAEquals(Loc& loc, TOK op, DValue* l, DValue* r) { Type* t = l->getType()->toBasetype(); assert(t == r->getType()->toBasetype() && "aa equality is only defined for aas of same type"); -#if DMDV2 llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaEqual"); LLFunctionType* funcTy = func->getFunctionType(); @@ -270,15 +225,6 @@ LLValue* DtoAAEquals(Loc& loc, TOK op, DValue* l, DValue* r) LLValue* abval = DtoBitCast(r->getRVal(), funcTy->getParamType(2)); LLValue* aaTypeInfo = DtoTypeInfoOf(t); LLValue* res = gIR->CreateCallOrInvoke3(func, aaTypeInfo, aaval, abval, "aaEqRes").getInstruction(); -#else - llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaEq"); - LLFunctionType* funcTy = func->getFunctionType(); - - LLValue* aaval = DtoBitCast(l->getRVal(), funcTy->getParamType(0)); - LLValue* abval = DtoBitCast(r->getRVal(), funcTy->getParamType(1)); - LLValue* aaTypeInfo = DtoTypeInfoOf(t); - LLValue* res = gIR->CreateCallOrInvoke3(func, aaval, abval, aaTypeInfo, "aaEqRes").getInstruction(); -#endif res = gIR->ir->CreateICmpNE(res, DtoConstInt(0), "tmp"); if (op == TOKnotequal) res = gIR->ir->CreateNot(res, "tmp"); diff --git a/gen/abi-ppc64.cpp b/gen/abi-ppc64.cpp index bb77d295..d707193c 100644 --- a/gen/abi-ppc64.cpp +++ b/gen/abi-ppc64.cpp @@ -44,10 +44,9 @@ struct PPC64TargetABI : TargetABI { bool returnInArg(TypeFunction* tf) { -#if DMDV2 if (tf->isref) return false; -#endif + // Return structs and static arrays on the stack. The latter is needed // because otherwise LLVM tries to actually return the array in a number // of physical registers, which leads, depending on the target, to diff --git a/gen/abi-win64.cpp b/gen/abi-win64.cpp index 12330644..5bd00aa5 100644 --- a/gen/abi-win64.cpp +++ b/gen/abi-win64.cpp @@ -127,10 +127,8 @@ llvm::CallingConv::ID Win64TargetABI::callingConv(LINK l) bool Win64TargetABI::returnInArg(TypeFunction* tf) { -#if DMDV2 if (tf->isref) return false; -#endif Type* rt = tf->next->toBasetype(); @@ -142,9 +140,7 @@ bool Win64TargetABI::returnInArg(TypeFunction* tf) // or ST(1) & ST(0) (creal) // all other structs and static arrays are returned by struct-return (sret) return (rt->ty == Tstruct -#if SARRAYVALUE || rt->ty == Tsarray -#endif ) && !canRewriteAsInt(rt); } @@ -164,9 +160,7 @@ void Win64TargetABI::rewriteFunctionType(TypeFunction* tf) // RETURN VALUE -#if DMDV2 if (!tf->isref) -#endif { if (rt->ty == Tcomplex80) { diff --git a/gen/abi-x86-64.cpp b/gen/abi-x86-64.cpp index 7ac2ae89..0563315c 100644 --- a/gen/abi-x86-64.cpp +++ b/gen/abi-x86-64.cpp @@ -439,15 +439,12 @@ bool X86_64TargetABI::returnInArg(TypeFunction* tf) { Type* rt = tf->next->toBasetype(); if (tf->linkage == LINKd) { -#if DMDV2 if (tf->isref) return false; -#endif + // All non-structs can be returned in registers. return rt->ty == Tstruct -#if SARRAYVALUE || rt->ty == Tsarray -#endif ; } else { if (rt == Type::tvoid || keepUnchanged(rt)) diff --git a/gen/abi-x86.cpp b/gen/abi-x86.cpp index f7734604..c2e2e1e3 100644 --- a/gen/abi-x86.cpp +++ b/gen/abi-x86.cpp @@ -70,18 +70,15 @@ struct X86TargetABI : TargetABI bool returnInArg(TypeFunction* tf) { -#if DMDV2 if (tf->isref) return false; -#endif + Type* rt = tf->next->toBasetype(); // D only returns structs on the stack if (tf->linkage == LINKd) { return rt->ty == Tstruct -#if SARRAYVALUE || rt->ty == Tsarray -#endif ; } // other ABI's follow C, which is cdouble and creal returned on the stack diff --git a/gen/abi.cpp b/gen/abi.cpp index e2f9f3c1..b76e3d7e 100644 --- a/gen/abi.cpp +++ b/gen/abi.cpp @@ -58,10 +58,9 @@ struct UnknownTargetABI : TargetABI bool returnInArg(TypeFunction* tf) { -#if DMDV2 if (tf->isref) return false; -#endif + // Return structs and static arrays on the stack. The latter is needed // because otherwise LLVM tries to actually return the array in a number // of physical registers, which leads, depending on the target, to diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 609b5683..bbebb884 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -114,13 +114,11 @@ void DtoArrayInit(Loc& loc, DValue* array, DValue* value, int op) Logger::println("DtoArrayInit"); LOG_SCOPE; -#if DMDV2 if (op != -1 && op != TOKblit && arrayNeedsPostblit(array->type)) { DtoArraySetAssign(loc, array, value, op); return; } -#endif LLValue* dim = DtoArrayLen(array); LLValue* ptr = DtoArrayPtr(array); @@ -183,8 +181,6 @@ void DtoArrayInit(Loc& loc, DValue* array, DValue* value, int op) ////////////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - Type *DtoArrayElementType(Type *arrayType) { assert(arrayType->toBasetype()->nextOf()); @@ -252,8 +248,6 @@ void DtoArraySetAssign(Loc &loc, DValue *array, DValue *value, int op) call.setCallingConv(llvm::CallingConv::C); } -#endif - ////////////////////////////////////////////////////////////////////////////////////////// void DtoSetArray(DValue* array, LLValue* dim, LLValue* ptr) @@ -451,11 +445,9 @@ LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit) // be used as an initializer for a static T[] - where modifying contents is allowed. LLGlobalVariable* gvar = new LLGlobalVariable(*gIR->module, constarr->getType(), false, LLGlobalValue::InternalLinkage, constarr, ".constarray"); -#if DMDV2 if (arrty->ty == Tpointer) // we need to return pointer to the static array. return DtoBitCast(gvar, DtoType(arrty)); -#endif LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) }; @@ -589,8 +581,6 @@ DSliceValue* DtoNewDynArray(Loc& loc, Type* arrayType, DValue* dim, bool default defaultInit = false; bool zeroInit = eltType->isZeroInit(); -#if DMDV2 - const char* fnname = zeroInit ? "_d_newarrayT" : "_d_newarrayiT"; LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, fnname); @@ -598,27 +588,6 @@ DSliceValue* DtoNewDynArray(Loc& loc, Type* arrayType, DValue* dim, bool default LLValue* newArray = gIR->CreateCallOrInvoke2(fn, arrayTypeInfo, arrayLen, ".gc_mem").getInstruction(); return getSlice(arrayType, newArray); - -#else - - const char* fnname = defaultInit ? (zeroInit ? "_d_newarrayT" : "_d_newarrayiT") : "_d_newarrayvT"; - LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, fnname); - - // call allocator - LLValue* newptr = gIR->CreateCallOrInvoke2(fn, arrayTypeInfo, arrayLen, ".gc_mem").getInstruction(); - - // cast to wanted type - LLType* dstType = DtoType(arrayType)->getContainedType(1); - if (newptr->getType() != dstType) - newptr = DtoBitCast(newptr, dstType, ".gc_mem"); - - if (Logger::enabled()) - Logger::cout() << "final ptr = " << *newptr << '\n'; - - return new DSliceValue(arrayType, arrayLen, newptr); - - -#endif } ////////////////////////////////////////////////////////////////////////////////////////// @@ -640,7 +609,6 @@ DSliceValue* DtoNewMulDimDynArray(Loc& loc, Type* arrayType, DValue** dims, size if (defaultInit && !isInitialized(vtype)) defaultInit = false; -#if DMDV2 const char* fnname = zeroInit ? "_d_newarraymT" : "_d_newarraymiT"; LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, fnname); @@ -660,35 +628,6 @@ DSliceValue* DtoNewMulDimDynArray(Loc& loc, Type* arrayType, DValue** dims, size Logger::cout() << "final ptr = " << *newptr << '\n'; return getSlice(arrayType, newptr); -#else - - const char* fnname = defaultInit ? (zeroInit ? "_d_newarraymT" : "_d_newarraymiT") : "_d_newarraymvT"; - LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, fnname); - - // build dims - LLValue* dimsArg = DtoArrayAlloca(Type::tsize_t, ndims, ".newdims"); - LLValue* firstDim = NULL; - for (size_t i=0; igetRVal(); - if (!firstDim) firstDim = dim; - DtoStore(dim, DtoGEPi1(dimsArg, i)); - } - - // call allocator - LLValue* newptr = gIR->CreateCallOrInvoke3(fn, arrayTypeInfo, DtoConstSize_t(ndims), dimsArg, ".gc_mem").getInstruction(); - - // cast to wanted type - LLType* dstType = DtoType(arrayType)->getContainedType(1); - if (newptr->getType() != dstType) - newptr = DtoBitCast(newptr, dstType, ".gc_mem"); - - if (Logger::enabled()) - Logger::cout() << "final ptr = " << *newptr << '\n'; - - assert(firstDim); - return new DSliceValue(arrayType, firstDim, newptr); -#endif } ////////////////////////////////////////////////////////////////////////////////////////// @@ -712,33 +651,13 @@ DSliceValue* DtoResizeDynArray(Type* arrayType, DValue* array, LLValue* newdim) args.push_back(DtoTypeInfoOf(arrayType)); args.push_back(newdim); -#if DMDV2 - args.push_back(DtoBitCast(array->getLVal(), fn->getFunctionType()->getParamType(2))); LLValue* newArray = gIR->CreateCallOrInvoke(fn, args, ".gc_mem").getInstruction(); return getSlice(arrayType, newArray); - -#else - - args.push_back(DtoArrayLen(array)); - - LLValue* arrPtr = DtoArrayPtr(array); - if (Logger::enabled()) - Logger::cout() << "arrPtr = " << *arrPtr << '\n'; - args.push_back(DtoBitCast(arrPtr, fn->getFunctionType()->getParamType(3), "tmp")); - - LLValue* newptr = gIR->CreateCallOrInvoke(fn, args, ".gc_mem").getInstruction(); - if (newptr->getType() != arrPtr->getType()) - newptr = DtoBitCast(newptr, arrPtr->getType(), ".gc_mem"); - - return new DSliceValue(arrayType, newdim, newptr); - -#endif } ////////////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 void DtoCatAssignElement(Loc& loc, Type* arrayType, DValue* array, Expression* exp) { @@ -768,32 +687,8 @@ void DtoCatAssignElement(Loc& loc, Type* arrayType, DValue* array, Expression* e callPostblit(loc, exp, val); } -#else - -void DtoCatAssignElement(Loc& loc, Type* arrayType, DValue* array, Expression* exp) -{ - Logger::println("DtoCatAssignElement"); - LOG_SCOPE; - - assert(array); - - LLValue *valueToAppend = makeLValue(loc, exp->toElem(gIR)); - - LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_arrayappendcT"); - LLSmallVector args; - args.push_back(DtoTypeInfoOf(arrayType)); - args.push_back(DtoBitCast(array->getLVal(), fn->getFunctionType()->getParamType(1))); - args.push_back(DtoBitCast(valueToAppend, getVoidPtrType())); - - gIR->CreateCallOrInvoke(fn, args, ".appendedArray"); -} - -#endif - ////////////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - DSliceValue* DtoCatAssignArray(DValue* arr, Expression* exp) { Logger::println("DtoCatAssignArray"); @@ -818,44 +713,8 @@ DSliceValue* DtoCatAssignArray(DValue* arr, Expression* exp) return getSlice(arrayType, newArray); } -#else - -DSliceValue* DtoCatAssignArray(DValue* arr, Expression* exp) -{ - Logger::println("DtoCatAssignArray"); - LOG_SCOPE; - - DValue* e = exp->toElem(gIR); - - llvm::Value *len1, *len2, *src1, *src2, *res; - - len1 = DtoArrayLen(arr); - len2 = DtoArrayLen(e); - res = gIR->ir->CreateAdd(len1,len2,"tmp"); - - DValue* newdim = new DImValue(Type::tsize_t, res); - DSliceValue* slice = DtoResizeDynArray(arr->getType(), arr, newdim->getRVal()); - - src1 = slice->ptr; - src2 = DtoArrayPtr(e); - - // advance ptr - src1 = gIR->ir->CreateGEP(src1,len1,"tmp"); - - // memcpy - LLValue* elemSize = DtoConstSize_t(getTypePaddedSize(src2->getType()->getContainedType(0))); - LLValue* bytelen = gIR->ir->CreateMul(len2, elemSize, "tmp"); - DtoMemCpy(src1,src2,bytelen); - - return slice; -} - -#endif - ////////////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - DSliceValue* DtoCatArrays(Type* arrayType, Expression* exp1, Expression* exp2) { Logger::println("DtoCatAssignArray"); @@ -904,117 +763,6 @@ DSliceValue* DtoCatArrays(Type* arrayType, Expression* exp1, Expression* exp2) return getSlice(arrayType, newArray); } -#else - -DSliceValue* DtoCatArrays(Type* type, Expression* exp1, Expression* exp2) -{ - Logger::println("DtoCatArrays"); - LOG_SCOPE; - - Type* t1 = exp1->type->toBasetype(); - Type* t2 = exp2->type->toBasetype(); - - assert(t1->ty == Tarray || t1->ty == Tsarray); - assert(t2->ty == Tarray || t2->ty == Tsarray); - - DValue* e1 = exp1->toElem(gIR); - DValue* e2 = exp2->toElem(gIR); - - llvm::Value *len1, *len2, *src1, *src2, *res; - - len1 = DtoArrayLen(e1); - len2 = DtoArrayLen(e2); - res = gIR->ir->CreateAdd(len1,len2,"tmp"); - - DValue* lenval = new DImValue(Type::tsize_t, res); - DSliceValue* slice = DtoNewDynArray(exp1->loc, type, lenval, false); - LLValue* mem = slice->ptr; - - src1 = DtoArrayPtr(e1); - src2 = DtoArrayPtr(e2); - - // first memcpy - LLValue* elemSize = DtoConstSize_t(getTypePaddedSize(src1->getType()->getContainedType(0))); - LLValue* bytelen = gIR->ir->CreateMul(len1, elemSize, "tmp"); - DtoMemCpy(mem,src1,bytelen); - - // second memcpy - mem = gIR->ir->CreateGEP(mem,len1,"tmp"); - bytelen = gIR->ir->CreateMul(len2, elemSize, "tmp"); - DtoMemCpy(mem,src2,bytelen); - - return slice; -} - -#endif - -////////////////////////////////////////////////////////////////////////////////////////// - -#if DMDV1 - -DSliceValue* DtoCatArrayElement(Type* type, Expression* exp1, Expression* exp2) -{ - Logger::println("DtoCatArrayElement"); - LOG_SCOPE; - - Type* t1 = exp1->type->toBasetype(); - Type* t2 = exp2->type->toBasetype(); - - DValue* e1 = exp1->toElem(gIR); - DValue* e2 = exp2->toElem(gIR); - - llvm::Value *len1, *src1, *res; - - // handle prefix case, eg. int~int[] - if (t2->nextOf() && t1 == t2->nextOf()->toBasetype()) - { - len1 = DtoArrayLen(e2); - res = gIR->ir->CreateAdd(len1,DtoConstSize_t(1),"tmp"); - - DValue* lenval = new DImValue(Type::tsize_t, res); - DSliceValue* slice = DtoNewDynArray(exp1->loc, type, lenval, false); - LLValue* mem = slice->ptr; - - DVarValue* memval = new DVarValue(e1->getType(), mem); - DtoAssign(exp1->loc, memval, e1); - - src1 = DtoArrayPtr(e2); - - mem = gIR->ir->CreateGEP(mem,DtoConstSize_t(1),"tmp"); - - LLValue* elemSize = DtoConstSize_t(getTypePaddedSize(src1->getType()->getContainedType(0))); - LLValue* bytelen = gIR->ir->CreateMul(len1, elemSize, "tmp"); - DtoMemCpy(mem,src1,bytelen); - - - return slice; - } - // handle suffix case, eg. int[]~int - else - { - len1 = DtoArrayLen(e1); - res = gIR->ir->CreateAdd(len1,DtoConstSize_t(1),"tmp"); - - DValue* lenval = new DImValue(Type::tsize_t, res); - DSliceValue* slice = DtoNewDynArray(exp1->loc, type, lenval, false); - LLValue* mem = slice->ptr; - - src1 = DtoArrayPtr(e1); - - LLValue* elemSize = DtoConstSize_t(getTypePaddedSize(src1->getType()->getContainedType(0))); - LLValue* bytelen = gIR->ir->CreateMul(len1, elemSize, "tmp"); - DtoMemCpy(mem,src1,bytelen); - - mem = gIR->ir->CreateGEP(mem,len1,"tmp"); - DVarValue* memval = new DVarValue(e2->getType(), mem); - DtoAssign(exp1->loc, memval, e2); - - return slice; - } -} - -#endif - ////////////////////////////////////////////////////////////////////////////////////////// DSliceValue* DtoAppendDChar(DValue* arr, Expression* exp, const char *func) @@ -1357,13 +1105,8 @@ DValue* DtoCastArray(Loc& loc, DValue* u, Type* to) void DtoArrayBoundsCheck(Loc& loc, DValue* arr, DValue* index, DValue* lowerBound) { Type* arrty = arr->getType()->toBasetype(); -#if DMDV2 assert((arrty->ty == Tsarray || arrty->ty == Tarray || arrty->ty == Tpointer) && "Can only array bounds check for static or dynamic arrays"); -#else - assert((arrty->ty == Tsarray || arrty->ty == Tarray) && - "Can only array bounds check for static or dynamic arrays"); -#endif // static arrays could get static checks for static indices // but shouldn't since it might be generic code that's never executed @@ -1405,25 +1148,10 @@ void DtoArrayBoundsCheck(Loc& loc, DValue* arr, DValue* index, DValue* lowerBoun std::vector args; Module* funcmodule = gIR->func()->decl->getModule(); -#if DMDV2 // module param LLValue *moduleInfoSymbol = funcmodule->moduleInfoSymbol(); LLType *moduleInfoType = DtoType(Module::moduleinfo->type); args.push_back(DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType))); -#else - // file param - // we might be generating for an imported template function - const char* cur_file = funcmodule->srcfile->name->toChars(); - if (loc.filename && strcmp(loc.filename, cur_file) != 0) - { - args.push_back(DtoConstString(loc.filename)); - } - else - { - IrModule* irmod = getIrModule(funcmodule); - args.push_back(DtoLoad(irmod->fileName)); - } -#endif // line param LLConstant* c = DtoConstUint(loc.linnum); diff --git a/gen/arrays.h b/gen/arrays.h index d32ac898..391eda32 100644 --- a/gen/arrays.h +++ b/gen/arrays.h @@ -36,12 +36,10 @@ void DtoArrayCopySlices(DSliceValue* dst, DSliceValue* src); void DtoArrayCopyToSlice(DSliceValue* dst, DValue* src); void DtoArrayInit(Loc& loc, DValue* array, DValue* value, int op); -#if DMDV2 Type *DtoArrayElementType(Type *arrayType); bool arrayNeedsPostblit(Type *t); void DtoArrayAssign(DValue *from, DValue *to, int op); void DtoArraySetAssign(Loc &loc, DValue *array, DValue *value, int op); -#endif void DtoSetArray(DValue* array, LLValue* dim, LLValue* ptr); void DtoSetArrayToNull(LLValue* v); @@ -52,9 +50,6 @@ DSliceValue* DtoResizeDynArray(Type* arrayType, DValue* array, llvm::Value* newd void DtoCatAssignElement(Loc& loc, Type* type, DValue* arr, Expression* exp); DSliceValue* DtoCatAssignArray(DValue* arr, Expression* exp); DSliceValue* DtoCatArrays(Type* type, Expression* e1, Expression* e2); -#if DMDV1 -DSliceValue* DtoCatArrayElement(Type* type, Expression* exp1, Expression* exp2); -#endif DSliceValue* DtoAppendDCharToString(DValue* arr, Expression* exp); DSliceValue* DtoAppendDCharToUnicodeString(DValue* arr, Expression* exp); diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp index b8aff97b..621a0665 100644 --- a/gen/asmstmt.cpp +++ b/gen/asmstmt.cpp @@ -153,10 +153,8 @@ bool d_have_inline_asm() { return true; } Statement *AsmStatement::semantic(Scope *sc) { -#if DMDV2 if (sc->func && sc->func->isSafe()) error("inline assembler not allowed in @safe function %s", sc->func->toChars()); -#endif bool err = false; llvm::Triple const t = global.params.targetTriple; @@ -176,9 +174,6 @@ Statement *AsmStatement::semantic(Scope *sc) //puts(toChars()); -#if DMDV1 - sc->func->inlineAsm = true; -#endif sc->func->hasReturnExp |= 8; // empty statement -- still do the above things because they might be expected? @@ -201,10 +196,8 @@ Statement *AsmStatement::semantic(Scope *sc) int AsmStatement::blockExit(bool mustNotThrow) { //printf("AsmStatement::blockExit(%p)\n", this); -#if DMDV2 if (mustNotThrow) error("asm statements are assumed to throw"); -#endif // Assume the worst return BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt; } diff --git a/gen/binops.cpp b/gen/binops.cpp index bcf32c76..fb65e59b 100644 --- a/gen/binops.cpp +++ b/gen/binops.cpp @@ -137,7 +137,6 @@ LLValue* DtoBinNumericEquals(Loc loc, DValue* lhs, DValue* rhs, TOK op) LLValue* DtoBinFloatsEquals(Loc loc, DValue* lhs, DValue* rhs, TOK op) { LLValue* res = 0; -#if DMDV2 if (op == TOKequal) { res = gIR->ir->CreateFCmpOEQ(lhs->getRVal(), rhs->getRVal(), "tmp"); } else if (op == TOKnotequal) { @@ -153,14 +152,6 @@ LLValue* DtoBinFloatsEquals(Loc loc, DValue* lhs, DValue* rhs, TOK op) LLValue* val = DtoMemCmp(makeLValue(loc, lhs), makeLValue(loc, rhs), sz); res = gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false), "tmp"); } -#else - LLValue* lv = lhs->getRVal(); - LLValue* rv = rhs->getRVal(); - res = (op == TOKidentity || op == TOKequal) ? - gIR->ir->CreateFCmpOEQ(lv, rv, "tmp") : - gIR->ir->CreateFCmpUNE(lv, rv, "tmp"); - -#endif assert(res); return res; } diff --git a/gen/classes.cpp b/gen/classes.cpp index cf3535d9..5a268b48 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -796,7 +796,6 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) VarDeclaration* defConstructorVar = static_cast(cinfo->fields.data[10]); b.push_funcptr(cd->defaultCtor, defConstructorVar->type); -#if DMDV2 // immutable(void)* m_RTInfo; // The cases where getRTInfo is null are not quite here, but the code is // modelled after what DMD does. @@ -806,10 +805,6 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) b.push_size_as_vp(0); // no pointers else b.push_size_as_vp(1); // has pointers -#else - // typeinfo - since 1.045 - b.push_typeinfo(cd->type); -#endif /*size_t n = inits.size(); for (size_t i=0; icodegen(p); // global variable -#if DMDV2 // taken from dmd2/structs if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init)) -#else - if (isDataseg()) -#endif { Logger::println("data segment"); - #if DMDV2 && 0 // TODO: + #if 0 // TODO: assert(!(storage_class & STCmanifest) && "manifest constant being codegen'd!"); #endif @@ -147,12 +143,8 @@ void VarDeclaration::codegen(Ir* p) Logger::println("parent: %s (%s)", parent->toChars(), parent->kind()); - #if DMDV2 // not sure why this is only needed for d2 bool _isconst = isConst() && init; - #else - bool _isconst = isConst(); - #endif Logger::println("Creating global variable"); @@ -260,10 +252,8 @@ void TemplateInstance::codegen(Ir* p) #if LOG printf("TemplateInstance::codegen('%s', this = %p)\n", toChars(), this); #endif -#if DMDV2 if (ignore) return; -#endif if (!errors && members) { diff --git a/gen/functions.cpp b/gen/functions.cpp index dc1b604a..51a0f48f 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -90,28 +90,12 @@ llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, llvm::AttrBuilder().addAttribute(llvm::Attributes::StructRet) .addAttribute(llvm::Attributes::NoAlias) #endif - #if !STRUCTTHISREF - // In D2 where 'this' in structs is a reference, nocapture - // might not actually be applicable, even if it probably still - // is for all sane code from a high-level semantic standpoint. - // Specifying nocapture on a parameter but then passing it as a - // non-nocapture argument in a function call can lead to - // _silent_ miscompilations (especially in the GVN pass). -#if LDC_LLVM_VER >= 303 - .addAttribute(llvm::Attribute::NoCapture) -#else - .addAttribute(llvm::Attributes::NoCapture) -#endif - #endif #if LDC_LLVM_VER == 302 ) #endif ); #else fty.arg_sret = new IrFuncTyArg(rt, true, StructRet | NoAlias - #if !STRUCTTHISREF - | NoCapture - #endif ); #endif rt = Type::tvoid; @@ -121,10 +105,8 @@ llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, else { Type *t = rt; -#if DMDV2 if (f->isref) t = t->pointerTo(); -#endif #if LDC_LLVM_VER >= 303 if (llvm::Attribute::AttrKind a = DtoShouldExtend(t)) attrBuilder.addAttribute(a); @@ -140,11 +122,7 @@ llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, #elif LDC_LLVM_VER == 302 llvm::Attributes a = llvm::Attributes::get(gIR->context(), attrBuilder); #endif -#if DMDV2 fty.ret = new IrFuncTyArg(rt, f->isref, a); -#else - fty.ret = new IrFuncTyArg(rt, false, a); -#endif } lidx++; @@ -214,9 +192,6 @@ llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, // reference semantics? ref, out and d1 static arrays are bool byref = arg->storageClass & (STCref|STCout); -#if !SARRAYVALUE - byref = byref || (arg->type->toBasetype()->ty == Tsarray); -#endif Type* argtype = arg->type; #if LDC_LLVM_VER >= 302 @@ -426,7 +401,6 @@ llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl) Type *dthis=0, *dnest=0; -#if DMDV2 if (fdecl->ident == Id::ensure || fdecl->ident == Id::require) { FuncDeclaration *p = fdecl->parent->isFuncDeclaration(); assert(p); @@ -434,7 +408,6 @@ llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl) assert(ad); dnest = Type::tvoid->pointerTo(); } else -#endif if (fdecl->needThis()) { if (AggregateDeclaration* ad = fdecl->isMember2()) { Logger::println("isMember = this is: %s", ad->type->toChars()); @@ -752,12 +725,10 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) // calling convention LINK link = f->linkage; if (vafunc || fdecl->llvmInternal == LLVMintrinsic -#if DMDV2 // DMD treats _Dmain as having C calling convention and this has been // hardcoded into druntime, even if the frontend type has D linkage. // See Bugzilla issue 9028. || fdecl->isMain() -#endif ) { link = LINKc; @@ -815,7 +786,6 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) gIR->mainFunc = func; } -#if DMDV2 // shared static ctor if (fdecl->isSharedStaticCtorDeclaration()) { if (mustDefineSymbol(fdecl)) { @@ -830,7 +800,6 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) gIR->sharedGates.push_front(dtorDecl->vgate); } } else -#endif // static ctor if (fdecl->isStaticCtorDeclaration()) { if (mustDefineSymbol(fdecl)) { @@ -841,10 +810,8 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) else if (StaticDtorDeclaration *dtorDecl = fdecl->isStaticDtorDeclaration()) { if (mustDefineSymbol(fdecl)) { gIR->dtors.push_front(fdecl); -#if DMDV2 if (dtorDecl->vgate) gIR->gates.push_front(dtorDecl->vgate); -#endif } } @@ -1024,9 +991,7 @@ void DtoDefineFunction(FuncDeclaration* fd) assert(thisvar); LLValue* thismem = thisvar; - #if STRUCTTHISREF if (!f->fty.arg_this->byref) - #endif { thismem = DtoRawAlloca(thisvar->getType(), 0, "this"); // FIXME: align? DtoStore(thisvar, thismem); @@ -1063,13 +1028,6 @@ void DtoDefineFunction(FuncDeclaration* fd) IrParameter* irparam = vd->ir.irParam; assert(irparam); - #if DMDV1 - if (vd->nestedref) - { - fd->nestedVars.insert(vd); - } - #endif - bool refout = vd->storage_class & (STCref | STCout); bool lazy = vd->storage_class & STClazy; if (!refout && (!irparam->arg->byref || lazy)) @@ -1095,31 +1053,13 @@ void DtoDefineFunction(FuncDeclaration* fd) } } - -#if DMDV1 - // need result variable? (nested) - if (fd->vresult && fd->vresult->nestedref) { - Logger::println("nested vresult value: %s", fd->vresult->toChars()); - fd->nestedVars.insert(fd->vresult); - } - - if (fd->vthis && fd->vthis->nestedref && !fd->nestedVars.empty()) { - Logger::println("nested vthis value: %s", fd->vthis->toChars()); - fd->nestedVars.insert(fd->vthis); - } -#endif - FuncGen fg; irfunction->gen = &fg; DtoCreateNestedContext(fd); if (fd->vresult && ! -#if DMDV2 fd->vresult->nestedrefs.dim // FIXME: not sure here :/ -#else - fd->vresult->nestedref -#endif ) { DtoVarDeclaration(fd->vresult); diff --git a/gen/irstate.h b/gen/irstate.h index 9aa17124..80f263ba 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -73,10 +73,8 @@ struct IRScope const IRScope& operator=(const IRScope& rhs); -#if DMDV2 // list of variables needing destruction std::vector varsInScope; -#endif }; struct IRBuilderHelper @@ -159,9 +157,7 @@ struct IRState // basic block scopes std::vector scopes; IRScope& scope(); -#if DMDV2 std::vector &varsInScope() { return scope().varsInScope; } -#endif llvm::BasicBlock* scopebb(); llvm::BasicBlock* scopeend(); bool scopereturned(); @@ -193,12 +189,10 @@ struct IRState typedef std::list GatesList; FuncDeclList ctors; FuncDeclList dtors; -#if DMDV2 FuncDeclList sharedCtors; FuncDeclList sharedDtors; GatesList gates; GatesList sharedGates; -#endif FuncDeclList unitTests; // all template instances that had members emitted diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 713d2482..e11f0dfa 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -71,12 +71,10 @@ void DtoDeleteClass(LLValue* inst) llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delclass"); // build args LLSmallVector arg; -#if DMDV2 // druntime wants a pointer to object LLValue *ptr = DtoRawAlloca(inst->getType(), 0, "objectPtr"); DtoStore(inst, ptr); inst = ptr; -#endif arg.push_back(DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp")); // call gIR->CreateCallOrInvoke(fn, arg); @@ -93,8 +91,6 @@ void DtoDeleteInterface(LLValue* inst) gIR->CreateCallOrInvoke(fn, arg); } -#if DMDV2 - void DtoDeleteArray(DValue* arr) { // get runtime function @@ -109,24 +105,6 @@ void DtoDeleteArray(DValue* arr) gIR->CreateCallOrInvoke(fn, arg); } -#else - -void DtoDeleteArray(DValue* arr) -{ - // get runtime function - llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delarray"); - - // build args - LLSmallVector arg; - arg.push_back(DtoArrayLen(arr)); - arg.push_back(DtoBitCast(DtoArrayPtr(arr), getVoidPtrType(), ".tmp")); - - // call - gIR->CreateCallOrInvoke(fn, arg); -} - -#endif - /****************************************************************************************/ /*//////////////////////////////////////////////////////////////////////////////////////// // ALLOCA HELPERS @@ -416,7 +394,6 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPostblit) if (t->nextOf()->toBasetype()->equals(t2)) { DtoArrayInit(loc, lhs, rhs, op); } -#if DMDV2 else if (DtoArrayElementType(t)->equals(stripModifiers(t2))) { DtoArrayInit(loc, s, rhs, op); } @@ -425,7 +402,6 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPostblit) ) { DtoArrayAssign(s, rhs, op); } -#endif else if (DSliceValue *s2 = rhs->isSlice()) { DtoArrayCopySlices(s, s2); } @@ -456,7 +432,6 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPostblit) if (t->nextOf()->toBasetype()->equals(t2)) { DtoArrayInit(loc, lhs, rhs, op); } -#if DMDV2 else if (DtoArrayElementType(t)->equals(stripModifiers(t2))) { DtoArrayInit(loc, lhs, rhs, op); } @@ -465,7 +440,6 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPostblit) ) { DtoArrayAssign(lhs, rhs, op); } -#endif // T[n] = T[n] else if (DtoType(lhs->getType()) == DtoType(rhs->getType())) { DtoStaticArrayCopy(lhs->getLVal(), rhs->getRVal()); @@ -772,7 +746,6 @@ DValue* DtoCastNull(Loc& loc, DValue* val, Type* to) } } -#if DMDV2 DValue* DtoCastVector(Loc& loc, DValue* val, Type* to) { assert(val->getType()->toBasetype()->ty == Tvector); @@ -828,19 +801,16 @@ DValue* DtoCastVector(Loc& loc, DValue* val, Type* to) fatal(); } } -#endif DValue* DtoCast(Loc& loc, DValue* val, Type* to) { Type* fromtype = val->getType()->toBasetype(); Type* totype = to->toBasetype(); -#if DMDV2 if (fromtype->ty == Taarray) fromtype = static_cast(fromtype)->getImpl()->type; if (totype->ty == Taarray) totype = static_cast(totype)->getImpl()->type; -#endif if (fromtype->equals(totype)) return val; @@ -848,12 +818,10 @@ DValue* DtoCast(Loc& loc, DValue* val, Type* to) Logger::println("Casting from '%s' to '%s'", fromtype->toChars(), to->toChars()); LOG_SCOPE; -#if DMDV2 if (fromtype->ty == Tvector) { return DtoCastVector(loc, val, to); } else -#endif if (fromtype->isintegral()) { return DtoCastInt(loc, val, to); } @@ -967,13 +935,11 @@ TemplateInstance* DtoIsTemplateInstance(Dsymbol* s, bool checkLiteralOwner) if (!s) return NULL; if (s->isTemplateInstance() && !s->isTemplateMixin()) return s->isTemplateInstance(); -#if DMDV2 if (FuncLiteralDeclaration* fld = s->isFuncLiteralDeclaration()) { if (checkLiteralOwner && fld->owningTemplate) return fld->owningTemplate; } -#endif if (s->parent) return DtoIsTemplateInstance(s->parent, checkLiteralOwner); return NULL; @@ -1061,11 +1027,7 @@ void DtoVarDeclaration(VarDeclaration* vd) Logger::println("vdtype = %s", vd->type->toChars()); -#if DMDV2 if (vd->nestedrefs.dim) -#else - if (vd->nestedref) -#endif { Logger::println("has nestedref set (referenced by nested function/delegate)"); assert(vd->ir.irLocal && "irLocal is expected to be already set by DtoCreateNestedContext"); @@ -1075,7 +1037,6 @@ void DtoVarDeclaration(VarDeclaration* vd) { // Nothing to do if it has already been allocated. } -#if DMDV2 /* Named Return Value Optimization (NRVO): T f(){ T ret; // &ret == hidden pointer @@ -1088,12 +1049,10 @@ void DtoVarDeclaration(VarDeclaration* vd) vd->ir.irLocal = new IrLocal(vd); vd->ir.irLocal->value = gIR->func()->retArg; } -#endif // normal stack variable, allocate storage on the stack if it has not already been done else { vd->ir.irLocal = new IrLocal(vd); -#if DMDV2 /* NRVO again: T t = f(); // t's memory address is taken hidden pointer */ @@ -1123,7 +1082,6 @@ void DtoVarDeclaration(VarDeclaration* vd) } } } -#endif Type* type = isSpecialRefVar(vd) ? vd->type->pointerTo() : vd->type; LLType* lltype = DtoType(type); @@ -1144,7 +1102,6 @@ void DtoVarDeclaration(VarDeclaration* vd) DtoInitializer(vd->ir.irLocal->value, vd->init); // TODO: Remove altogether? -#if DMDV2 Lexit: /* Mark the point of construction of a variable that needs to be destructed. */ @@ -1153,7 +1110,6 @@ Lexit: // Put vd on list of things needing destruction gIR->varsInScope().push_back(vd); } -#endif } DValue* DtoDeclarationExp(Dsymbol* declaration) @@ -1285,11 +1241,7 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr) } // referenced by nested function? -#if DMDV2 if (var->nestedrefs.dim) -#else - if (var->nestedref) -#endif { assert(var->ir.irLocal); if(!var->ir.irLocal->value) @@ -1508,13 +1460,8 @@ static LLConstant* expand_to_sarray(Type *base, Expression* exp) LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) { -#if DMDV2 Type* expbase = stripModifiers(exp->type->toBasetype())->merge(); Type* base = stripModifiers(type->toBasetype())->merge(); -#else - Type* expbase = exp->type->toBasetype(); - Type* base = type->toBasetype(); -#endif // if not the same basetypes, we won't get the same llvm types either if (!expbase->equals(base)) @@ -1529,7 +1476,6 @@ LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) return expand_to_sarray(base, exp); } -#if DMDV2 if (base->ty == Tvector) { LLConstant* val = exp->toConstElem(gIR); @@ -1541,7 +1487,6 @@ LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) return llvm::ConstantVector::getSplat(tv->size(loc), val); #endif } -#endif error(loc, "LDC internal error: cannot yet convert default initializer %s of type %s to %s", exp->toChars(), exp->type->toChars(), type->toChars()); @@ -1793,13 +1738,9 @@ size_t realignOffset(size_t offset, Type* type) Type * stripModifiers( Type * type ) { -#if DMDV2 if (type->ty == Tfunction) return type; return type->castMod(0); -#else - return type; -#endif } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1839,7 +1780,6 @@ LLValue* makeLValue(Loc& loc, DValue* value) ////////////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 void callPostblit(Loc &loc, Expression *exp, LLValue *val) { @@ -1859,7 +1799,6 @@ void callPostblit(Loc &loc, Expression *exp, LLValue *val) } } } -#endif ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index e099dcd8..4a9ec3f8 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -166,9 +166,7 @@ size_t realignOffset(size_t offset, Type* type); /// functions without problems. LLValue* makeLValue(Loc& loc, DValue* value); -#if DMDV2 void callPostblit(Loc &loc, Expression *exp, LLValue *val); -#endif /// Returns whether the given variable is a DMD-internal "ref variable". /// diff --git a/gen/module.cpp b/gen/module.cpp index 9d153db8..6788b448 100644 --- a/gen/module.cpp +++ b/gen/module.cpp @@ -56,10 +56,7 @@ #endif #endif -#if DMDV2 #define NEW_MODULEINFO_LAYOUT 1 -#endif - static llvm::Function* build_module_function(const std::string &name, const std::list &funcs, const std::list &gates = std::list()) @@ -116,11 +113,7 @@ llvm::Function* build_module_ctor() std::string name("_D"); name.append(gIR->dmodule->mangle()); name.append("6__ctorZ"); -#if DMDV2 return build_module_function(name, gIR->ctors, gIR->gates); -#else - return build_module_function(name, gIR->ctors); -#endif } // build module dtor @@ -143,8 +136,6 @@ static llvm::Function* build_module_unittest() return build_module_function(name, gIR->unitTests); } -#if DMDV2 - // build module shared ctor llvm::Function* build_module_shared_ctor() @@ -165,8 +156,6 @@ static llvm::Function* build_module_shared_dtor() return build_module_function(name, gIR->sharedDtors); } -#endif - // build ModuleReference and register function, to register the module info in the global linked list static LLFunction* build_module_reference_and_ctor(LLConstant* moduleinfo) { @@ -372,11 +361,7 @@ void Module::genmoduleinfo() // check for patch else { -#if DMDV2 unsigned sizeof_ModuleInfo = 16 * PTRSIZE; -#else - unsigned sizeof_ModuleInfo = 14 * PTRSIZE; -#endif if (sizeof_ModuleInfo != moduleinfo->structsize) { error("object.d ModuleInfo class is incorrect"); @@ -606,20 +591,12 @@ void Module::genmoduleinfo() LLType* fnptrTy = getPtrToType(LLFunctionType::get(LLType::getVoidTy(gIR->context()), std::vector(), false)); // ctor -#if DMDV2 llvm::Function* fctor = build_module_shared_ctor(); -#else - llvm::Function* fctor = build_module_ctor(); -#endif c = fctor ? fctor : getNullValue(fnptrTy); b.push(c); // dtor -#if DMDV2 llvm::Function* fdtor = build_module_shared_dtor(); -#else - llvm::Function* fdtor = build_module_dtor(); -#endif c = fdtor ? fdtor : getNullValue(fnptrTy); b.push(c); @@ -636,8 +613,6 @@ void Module::genmoduleinfo() c = getNullValue(fnptrTy); b.push(c); -#if DMDV2 - // tls ctor fctor = build_module_ctor(); c = fctor ? fctor : getNullValue(fnptrTy); @@ -653,8 +628,6 @@ void Module::genmoduleinfo() c = getNullValue(AT); b.push(c); -#endif - #endif // create and set initializer diff --git a/gen/nested.cpp b/gen/nested.cpp index e32e6447..eaee88d3 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -44,7 +44,6 @@ static FuncDeclaration* getParentFunc(Dsymbol* sym, bool stopOnStatic) { static void storeVariable(VarDeclaration *vd, LLValue *dst) { LLValue *value = vd->ir.irLocal->value; -#if DMDV2 int ty = vd->type->ty; FuncDeclaration *fd = getParentFunc(vd, true); assert(fd && "No parent function for nested variable?"); @@ -54,7 +53,6 @@ static void storeVariable(VarDeclaration *vd, LLValue *dst) DtoAggrCopy(mem, value); DtoAlignedStore(mem, dst); } else -#endif // Store the address into the frame DtoAlignedStore(value, dst); } @@ -99,27 +97,11 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) LLValue* ctx = 0; if (irfunc->decl->isMember2()) { - #if DMDV2 AggregateDeclaration* cd = irfunc->decl->isMember2(); LLValue* val = irfunc->thisArg; if (cd->isClassDeclaration()) val = DtoLoad(val); ctx = DtoLoad(DtoGEPi(val, 0, cd->vthis->ir.irField->index, ".vthis")); - #else - ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration(); - LLValue* val = DtoLoad(irfunc->thisArg); - ctx = DtoGEPi(val, 0, cd->vthis->ir.irField->index, ".vthis"); - - if (!irfunc->frameType && vd->isThisDeclaration()) - { - // If the only "nested" variable is the outer this pointer, we don't - // emit a normal context, but just store the this pointer - see - // GitHub #127. - return new DVarValue(astype, vd, ctx); - } - - ctx = DtoLoad(ctx); - #endif } else if (irfunc->nestedVar) { ctx = irfunc->nestedVar; @@ -189,11 +171,7 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) return new DVarValue(astype, vd, val); } -#if DMDV2 void DtoResolveNestedContext(Loc loc, AggregateDeclaration *decl, LLValue *value) -#else -void DtoResolveNestedContext(Loc loc, ClassDeclaration *decl, LLValue *value) -#endif { Logger::println("Resolving nested context"); LOG_SCOPE; @@ -238,7 +216,6 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) // or just have a this argument else if (irfunc->thisArg) { -#if DMDV2 AggregateDeclaration* ad = irfunc->decl->isMember2(); val = ad->isClassDeclaration() ? DtoLoad(irfunc->thisArg) : irfunc->thisArg; if (!ad->vthis) @@ -247,12 +224,6 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) // function (but without any variables in the nested context). return val; } -#else - ClassDeclaration* ad = irfunc->decl->isMember2()->isClassDeclaration(); - val = DtoLoad(irfunc->thisArg); - if (!ad || !ad->vthis) - return val; -#endif val = DtoLoad(DtoGEPi(val, 0, ad->vthis->ir.irField->index, ".vthis")); } else @@ -264,20 +235,14 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) } struct FuncDeclaration* fd = 0; -#if DMDV2 if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) // If sym is a nested struct or a nested class, pass the frame // of the function where sym is declared. fd = ad->toParent()->isFuncDeclaration(); else -#endif if (FuncDeclaration* symfd = sym->isFuncDeclaration()) { // Make sure we've had a chance to analyze nested context usage -#if DMDV2 DtoCreateNestedContextType(symfd); -#else - DtoDefineFunction(symfd); -#endif // if this is for a function that doesn't access variables from // enclosing scopes, it doesn't matter what we pass. @@ -331,7 +296,6 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) { return; fd->ir.irFunc->nestedContextCreated = true; -#if DMDV2 if (fd->nestedVars.empty()) { // fill nestedVars size_t nnest = fd->closureVars.dim; @@ -341,7 +305,6 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) { fd->nestedVars.insert(vd); } } -#endif // construct nested variables array if (!fd->nestedVars.empty()) @@ -455,13 +418,10 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { // Create frame for current function and append to frames list // FIXME: alignment ? LLValue* frame = 0; -#if DMDV2 if (fd->needsClosure()) frame = DtoGcMalloc(frameType, ".frame"); else -#endif - frame = DtoRawAlloca(frameType, 0, ".frame"); - + frame = DtoRawAlloca(frameType, 0, ".frame"); // copy parent frames into beginning if (depth != 0) { @@ -470,20 +430,14 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { assert(irfunction->thisArg); assert(fd->isMember2()); LLValue* thisval = DtoLoad(irfunction->thisArg); -#if DMDV2 AggregateDeclaration* cd = fd->isMember2(); -#else - ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); -#endif assert(cd); assert(cd->vthis); Logger::println("Indexing to 'this'"); -#if DMDV2 if (cd->isStructDeclaration()) src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis"); else -#endif - src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); + src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); } else { src = DtoLoad(src); } diff --git a/gen/nested.h b/gen/nested.h index 3eaa6fa9..397236f6 100644 --- a/gen/nested.h +++ b/gen/nested.h @@ -28,11 +28,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd); /// Resolves the nested context for classes and structs with arbitrary nesting. -#if DMDV2 void DtoResolveNestedContext(Loc loc, AggregateDeclaration *decl, LLValue *value); -#else -void DtoResolveNestedContext(Loc loc, ClassDeclaration *decl, LLValue *value); -#endif /// Gets the context value for a call to a nested function or creating a nested /// class or struct with arbitrary nesting. diff --git a/gen/passes/GarbageCollect2Stack.cpp b/gen/passes/GarbageCollect2Stack.cpp index 65f3bd3c..a14c5679 100644 --- a/gen/passes/GarbageCollect2Stack.cpp +++ b/gen/passes/GarbageCollect2Stack.cpp @@ -359,12 +359,7 @@ GarbageCollect2Stack::GarbageCollect2Stack() : FunctionPass(ID), AllocMemoryT(0, true, false), NewArrayVT(0, true, false, false, 1), -#ifdef DMDV1 - // _d_newarrayT returns just the void* ptr in the LDC D1 runtime. - NewArrayT(0, true, false, true, 1) -#else NewArrayT(0, true, true, true, 1) -#endif { KnownFunctions["_d_allocmemoryT"] = &AllocMemoryT; KnownFunctions["_d_newarrayvT"] = &NewArrayVT; diff --git a/gen/pragma.cpp b/gen/pragma.cpp index be2d62b6..806f9df9 100644 --- a/gen/pragma.cpp +++ b/gen/pragma.cpp @@ -46,7 +46,6 @@ static bool parseIntExp(Expression* e, dinteger_t& res) static void pragmaDeprecated(Identifier* oldIdent, Identifier* newIdent) { -#if !DMDV1 // Do not print a deprecation warning for D1 – we do not want to // introduce needless breakage at this stage. if (global.params.useDeprecated == 0) @@ -59,7 +58,6 @@ static void pragmaDeprecated(Identifier* oldIdent, Identifier* newIdent) warning("non-vendor-prefixed pragma '%s' is deprecated; use '%s' instead", oldIdent->toChars(), newIdent->toChars()); } -#endif } bool matchPragma(Identifier* needle, Identifier* ident, Identifier* oldIdent) @@ -388,11 +386,7 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s, TypeFunction* type = static_cast(fd->type); Type* retType = type->next; if (retType->ty != Tvoid || type->parameters->dim > 0 || ( -#if DMDV2 fd->isAggregateMember() -#else - fd->isThis() -#endif && !fd->isStatic())) { error(s->loc, "the '%s' pragma is only allowed on void functions which take no arguments", ident->toChars()); diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 3c63aa16..ddee7b7e 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -218,10 +218,6 @@ static void LLVM_D_BuildRuntimeModule() = NoAttrs.addAttribute(gIR->context(), 1, llvm::Attribute::NoCapture), Attr_NoAlias_1_NoCapture = Attr_1_NoCapture.addAttribute(gIR->context(), 0, llvm::Attribute::NoAlias), -#if DMDV1 - Attr_NoAlias_3_NoCapture - = Attr_NoAlias.addAttribute(gIR->context(), 3, llvm::Attribute::NoCapture), -#endif Attr_1_2_NoCapture = Attr_1_NoCapture.addAttribute(gIR->context(), 2, llvm::Attribute::NoCapture), Attr_1_3_NoCapture @@ -251,10 +247,6 @@ static void LLVM_D_BuildRuntimeModule() = NoAttrs.addAttr(gIR->context(), 1, llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::NoCapture))), Attr_NoAlias_1_NoCapture = Attr_1_NoCapture.addAttr(gIR->context(), 0, llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::NoAlias))), -#if DMDV1 - Attr_NoAlias_3_NoCapture - = Attr_NoAlias.addAttr(gIR->context(), 3, llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::NoCapture))), -#endif Attr_1_2_NoCapture = Attr_1_NoCapture.addAttr(gIR->context(), 2, llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::NoCapture))), Attr_1_3_NoCapture @@ -284,10 +276,6 @@ static void LLVM_D_BuildRuntimeModule() = NoAttrs.addAttr(1, NoCapture), Attr_NoAlias_1_NoCapture = Attr_1_NoCapture.addAttr(0, NoAlias), -#if DMDV1 - Attr_NoAlias_3_NoCapture - = Attr_NoAlias.addAttr(3, NoCapture), -#endif Attr_1_2_NoCapture = Attr_1_NoCapture.addAttr(2, NoCapture), Attr_1_3_NoCapture @@ -308,21 +296,13 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } - // D1: - // void _d_array_bounds( char[] file, uint line ) - // void _d_switch_error( char[] file, uint line ) - // D2: // void _d_array_bounds(ModuleInfo* m, uint line) // void _d_switch_error(ModuleInfo* m, uint line) { llvm::StringRef fname("_d_array_bounds"); llvm::StringRef fname2("_d_switch_error"); LLType *types[] = { -#if DMDV2 getPtrToType(DtoType(Module::moduleinfo->type)), -#else - stringTy, -#endif intTy }; LLFunctionType* fty = llvm::FunctionType::get(voidTy, types, false); @@ -360,40 +340,6 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) ->setAttributes(Attr_NoAlias); } -#if DMDV1 - // void* _d_newarrayT(TypeInfo ti, size_t length) - // void* _d_newarrayiT(TypeInfo ti, size_t length) - // void* _d_newarrayvT(TypeInfo ti, size_t length) - { - llvm::StringRef fname("_d_newarrayT"); - llvm::StringRef fname2("_d_newarrayiT"); - llvm::StringRef fname3("_d_newarrayvT"); - LLType *types[] = { typeInfoTy, sizeTy }; - LLFunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) - ->setAttributes(Attr_NoAlias); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M) - ->setAttributes(Attr_NoAlias); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname3, M) - ->setAttributes(Attr_NoAlias); - } - // void* _d_newarraymT(TypeInfo ti, size_t length, size_t* dims) - // void* _d_newarraymiT(TypeInfo ti, size_t length, size_t* dims) - // void* _d_newarraymvT(TypeInfo ti, size_t length, size_t* dims) - { - llvm::StringRef fname("_d_newarraymT"); - llvm::StringRef fname2("_d_newarraymiT"); - llvm::StringRef fname3("_d_newarraymvT"); - LLType *types[] = { typeInfoTy, sizeTy, rt_ptr(sizeTy) }; - LLFunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) - ->setAttributes(Attr_NoAlias_3_NoCapture); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M) - ->setAttributes(Attr_NoAlias_3_NoCapture); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname3, M) - ->setAttributes(Attr_NoAlias_3_NoCapture); - } -#else // void[] _d_newarrayT(TypeInfo ti, size_t length) // void[] _d_newarrayiT(TypeInfo ti, size_t length) { @@ -414,12 +360,7 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); } -#endif - // D1: - // void* _d_arraysetlengthT(TypeInfo ti, size_t newlength, size_t plength, void* pdata) - // void* _d_arraysetlengthiT(TypeInfo ti, size_t newlength, size_t plength, void* pdata) - // D2: // void[] _d_arraysetlengthT(TypeInfo ti, size_t newlength, void[] *array) // void[] _d_arraysetlengthiT(TypeInfo ti, size_t newlength, void[] *array) { @@ -428,21 +369,13 @@ static void LLVM_D_BuildRuntimeModule() LLType *types[] = { typeInfoTy, sizeTy, -#if DMDV2 voidArrayPtrTy }; LLFunctionType* fty = llvm::FunctionType::get(voidArrayTy, types, false); -#else - sizeTy, - voidPtrTy - }; - LLFunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); -#endif llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); } -#if DMDV2 // byte[] _d_arrayappendcTX(TypeInfo ti, ref byte[] px, size_t n) { llvm::StringRef fname("_d_arrayappendcTX"); @@ -485,15 +418,6 @@ static void LLVM_D_BuildRuntimeModule() LLFunctionType* fty = llvm::FunctionType::get(voidArrayTy, types, true); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } -#else // DMDV1 - // byte[] _d_arrayappendcT(TypeInfo ti, void* array, void* element) - { - llvm::StringRef fname("_d_arrayappendcT"); - LLType *types[] = { typeInfoTy, voidPtrTy, voidPtrTy }; - LLFunctionType* fty = llvm::FunctionType::get(voidArrayTy, types, false); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); - } -#endif // Object _d_allocclass(ClassInfo ci) { @@ -504,8 +428,6 @@ static void LLVM_D_BuildRuntimeModule() ->setAttributes(Attr_NoAlias); } -#if DMDV2 - // void _d_delarray_t(Array *p, TypeInfo ti) { llvm::StringRef fname("_d_delarray_t"); @@ -514,23 +436,6 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } -#else - - // void _d_delarray(size_t plength, void* pdata) - { - llvm::StringRef fname("_d_delarray"); - LLType *types[] = { sizeTy, voidPtrTy }; - LLFunctionType* fty = llvm::FunctionType::get(voidTy, types, false); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); - } - -#endif - - // D1: - // void _d_delmemory(void* p) - // void _d_delinterface(void* p) - // void _d_callfinalizer(void* p) - // D2: // void _d_delmemory(void **p) // void _d_delinterface(void **p) // void _d_callfinalizer(void *p) @@ -545,16 +450,11 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname3, M); } - // D1: void _d_delclass(Object p) // D2: void _d_delclass(Object* p) { llvm::StringRef fname("_d_delclass"); LLType *types[] = { -#if DMDV2 rt_ptr(objectTy) -#else - objectTy -#endif }; LLFunctionType* fty = llvm::FunctionType::get(voidTy, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); @@ -654,8 +554,6 @@ static void LLVM_D_BuildRuntimeModule() ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - // void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to) // void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to) { @@ -680,8 +578,6 @@ static void LLVM_D_BuildRuntimeModule() ->setAttributes(Attr_NoAlias); } -#endif - ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// @@ -802,50 +698,28 @@ static void LLVM_D_BuildRuntimeModule() ->setAttributes(Attr_ReadOnly_NoUnwind_1_NoCapture); } - // D1: - // void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey) - // D2: // void* _aaGetX(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey) { -#if DMDV2 llvm::StringRef fname("_aaGetX"); -#else - llvm::StringRef fname("_aaGet"); -#endif LLType *types[] = { aaTy, typeInfoTy, sizeTy, voidPtrTy }; LLFunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) ->setAttributes(Attr_1_4_NoCapture); } - // D1: - // void* _aaIn(AA aa, TypeInfo keyti, void* pkey) - // D2: // void* _aaInX(AA aa, TypeInfo keyti, void* pkey) { -#if DMDV2 llvm::StringRef fname("_aaInX"); -#else - llvm::StringRef fname("_aaIn"); -#endif LLType *types[] = { aaTy, typeInfoTy, voidPtrTy }; LLFunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) ->setAttributes(Attr_ReadOnly_1_3_NoCapture); } - // D1: - // void _aaDel(AA aa, TypeInfo keyti, void* pkey) - // D2: // bool _aaDelX(AA aa, TypeInfo keyti, void* pkey) { -#if DMDV2 llvm::StringRef fname("_aaDelX"); LLType *retType = boolTy; -#else - llvm::StringRef fname("_aaDel"); - LLType *retType = voidTy; -#endif LLType *types[] = { aaTy, typeInfoTy, voidPtrTy }; LLFunctionType* fty = llvm::FunctionType::get(retType, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) @@ -896,7 +770,6 @@ static void LLVM_D_BuildRuntimeModule() ->setAttributes(Attr_1_NoCapture); } -#if DMDV2 // int _aaEqual(TypeInfo_AssociativeArray ti, AA e1, AA e2) { llvm::StringRef fname("_aaEqual"); @@ -912,16 +785,6 @@ static void LLVM_D_BuildRuntimeModule() LLFunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } -#else - // int _aaEq(AA aa, AA ab, TypeInfo_AssociativeArray ti) - { - llvm::StringRef fname("_aaEq"); - LLType *types[] = { aaTy, aaTy, typeInfoTy }; - LLFunctionType* fty = llvm::FunctionType::get(intTy, types, false); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) - ->setAttributes(Attr_1_2_NoCapture); - } -#endif ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// @@ -1040,12 +903,10 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } -#if DMDV2 // void _d_hidden_func() { llvm::StringRef fname("_d_hidden_func"); LLFunctionType* fty = llvm::FunctionType::get(voidTy, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } -#endif } diff --git a/gen/runtime.h b/gen/runtime.h index 05e62c09..f64e3ae4 100644 --- a/gen/runtime.h +++ b/gen/runtime.h @@ -30,14 +30,8 @@ llvm::Function* LLVM_D_GetRuntimeFunction(llvm::Module* target, const char* name llvm::GlobalVariable* LLVM_D_GetRuntimeGlobal(llvm::Module* target, const char* name); -#if DMDV1 -#define _d_allocclass "_d_allocclass" -#define _adEq "_adEq" -#define _adCmp "_adCmp" -#else #define _d_allocclass "_d_newclass" #define _adEq "_adEq2" #define _adCmp "_adCmp2" -#endif #endif // LDC_GEN_RUNTIME_H diff --git a/gen/statements.cpp b/gen/statements.cpp index 09fcefc3..f6f61355 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -83,11 +83,10 @@ void ReturnStatement::toIR(IRState* p) DValue* e = exp->toElemDtor(p); // store return value DtoAssign(loc, rvar, e); -#if DMDV2 + // call postblit if necessary if (!p->func()->type->isref && !(f->decl->nrvo_can && f->decl->nrvo_var)) callPostblit(loc, exp, rvar->getLVal()); -#endif // emit scopes DtoEnclosingHandlers(loc, NULL); @@ -108,7 +107,6 @@ void ReturnStatement::toIR(IRState* p) } else { if (exp->op == TOKnull) exp->type = p->func()->type->next; -#if DMDV2 DValue* dval = 0; // call postblit if necessary if (!p->func()->type->isref) { @@ -120,10 +118,6 @@ void ReturnStatement::toIR(IRState* p) } // do abi specific transformations on the return value v = p->func()->type->fty.putRet(exp->type, dval); -#else - DValue* dval = exp->toElemDtor(p); - v = p->func()->type->fty.putRet(exp->type, dval); -#endif } if (Logger::enabled()) @@ -137,9 +131,7 @@ void ReturnStatement::toIR(IRState* p) int ty = f->type->next->toBasetype()->ty; if (v->getType() != p->topfunc()->getReturnType() && (ty == Tstruct -#if DMDV2 || ty == Tsarray -#endif ) && isaPointer(v->getType())) { Logger::println("Loading value for return"); @@ -214,8 +206,6 @@ void ExpStatement::toIR(IRState* p) ////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - void DtorExpStatement::toIR(IRState *irs) { assert(irs->func()); @@ -233,8 +223,6 @@ void DtorExpStatement::toIR(IRState *irs) } } -#endif - ////////////////////////////////////////////////////////////////////////////// void IfStatement::toIR(IRState* p) @@ -1290,8 +1278,6 @@ void ForeachStatement::toIR(IRState* p) ////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - void ForeachRangeStatement::toIR(IRState* p) { Logger::println("ForeachRangeStatement::toIR(): %s", loc.toChars()); @@ -1394,8 +1380,6 @@ void ForeachRangeStatement::toIR(IRState* p) p->scope() = IRScope(endbb,oldend); } -#endif // D2 - ////////////////////////////////////////////////////////////////////////////// void LabelStatement::toIR(IRState* p) @@ -1627,16 +1611,10 @@ void SwitchErrorStatement::toIR(IRState* p) std::vector args; -#if DMDV2 // module param LLValue *moduleInfoSymbol = gIR->func()->decl->getModule()->moduleInfoSymbol(); LLType *moduleInfoType = DtoType(Module::moduleinfo->type); args.push_back(DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType))); -#else - // file param - IrModule* irmod = getIrModule(NULL); - args.push_back(DtoLoad(irmod->fileName)); -#endif // line param LLConstant* c = DtoConstUint(loc.linnum); @@ -1645,19 +1623,13 @@ void SwitchErrorStatement::toIR(IRState* p) // call LLCallSite call = gIR->CreateCallOrInvoke(fn, args); call.setDoesNotReturn(); - -#if DMDV1 - gIR->ir->CreateUnreachable(); -#endif } ////////////////////////////////////////////////////////////////////////////// -#if DMDV2 void ImportStatement::toIR(IRState *irs) { } -#endif ////////////////////////////////////////////////////////////////////////////// @@ -1693,10 +1665,7 @@ STUBST(Statement); //STUBST(GotoStatement); //STUBST(UnrolledLoopStatement); //STUBST(OnScopeStatement); - -#if DMDV2 STUBST(PragmaStatement); -#endif ////////////////////////////////////////////////////////////////////////////// diff --git a/gen/structs.cpp b/gen/structs.cpp index 43a4e5bb..efa17310 100644 --- a/gen/structs.cpp +++ b/gen/structs.cpp @@ -253,12 +253,10 @@ std::vector DtoStructLiteralValues(const StructDeclaration* sd, // update offsets lastoffset = os; -#if DMDV2 // sometimes size of the initializer is less than size of the variable, // so make sure that lastsize is correct if (inits[i]->getType()->isSized()) sz = ceil(gDataLayout->getTypeSizeInBits(init->getType()) / 8.0); -#endif lastsize = sz; // go to next explicit init diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 2b44b69d..c6e2ea82 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -135,11 +135,7 @@ static LLValue *fixArgument(DValue *argval, TypeFunction* tf, LLType *callableAr // pointer to a struct, load from it before passing it in. int ty = argval->getType()->toBasetype()->ty; if (isaPointer(arg) && !isaPointer(callableArgType) && -#if DMDV2 (ty == Tstruct || ty == Tsarray)) -#else - ty == Tstruct) -#endif { Logger::println("Loading struct type for function argument"); arg = DtoLoad(arg); @@ -408,7 +404,6 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // then comes a context argument... if(thiscall || delegatecall || nestedcall) { -#if DMDV2 if (dfnval && (dfnval->func->ident == Id::ensure || dfnval->func->ident == Id::require)) { // ... which can be the this "context" argument for a contract // invocation (in D2, we do not generate a full nested contexts @@ -420,7 +415,6 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* args.push_back(thisarg); } else -#endif if (thiscall && dfnval && dfnval->vthis) { // ... or a normal 'this' argument @@ -630,9 +624,7 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // a stack slot before continuing. int ty = tf->next->toBasetype()->ty; if ((ty == Tstruct && !isaPointer(retllval)) -#if DMDV2 || (ty == Tsarray && isaArray(retllval)) -#endif ) { Logger::println("Storing return value to stack slot"); @@ -652,11 +644,9 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* switch(rbase->ty) { case Tarray: - #if DMDV2 if (tf->isref) retllval = DtoBitCast(retllval, DtoType(rbase->pointerTo())); else - #endif retllval = DtoAggrPaint(retllval, DtoType(rbase)); break; @@ -667,15 +657,12 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* case Tclass: case Taarray: case Tpointer: - #if DMDV2 if (tf->isref) retllval = DtoBitCast(retllval, DtoType(rbase->pointerTo())); else - #endif retllval = DtoBitCast(retllval, DtoType(rbase)); break; -#if DMDV2 case Tstruct: if (nextbase->ty == Taarray && !tf->isref) { @@ -694,7 +681,6 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* break; } // Fall through. -#endif default: // Unfortunately, DMD has quirks resp. bugs with regard to name @@ -766,9 +752,7 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // or if we are returning a reference // make sure we provide a lvalue back! if (retinptr -#if DMDV2 || tf->isref -#endif ) return new DVarValue(resulttype, retllval); diff --git a/gen/todebug.cpp b/gen/todebug.cpp index eb6791b0..6792c7b2 100644 --- a/gen/todebug.cpp +++ b/gen/todebug.cpp @@ -298,11 +298,7 @@ static llvm::DIType dwarfCompositeType(Type* type) static llvm::DIGlobalVariable dwarfGlobalVariable(LLGlobalVariable* ll, VarDeclaration* vd) { -#if DMDV2 assert(vd->isDataseg() || (vd->storage_class & (STCconst | STCimmutable) && vd->init)); -#else - assert(vd->isDataseg()); -#endif return gIR->dibuilder.createGlobalVariable( vd->toChars(), // name TODO: mangle() or toPrettyChars() instead? diff --git a/gen/toir.cpp b/gen/toir.cpp index c7410fe2..d922e906 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -60,7 +60,6 @@ void Expression::cacheLvalue(IRState* irs) DValue *Expression::toElemDtor(IRState *irs) { -#if DMDV2 Logger::println("Expression::toElemDtor(): %s", toChars()); LOG_SCOPE @@ -76,9 +75,6 @@ DValue *Expression::toElemDtor(IRState *irs) vd->edtor->toElem(gIR); } return val; -#else - return toElem(irs); -#endif } ////////////////////////////////////////////////////////////////////////////////////////// @@ -117,13 +113,11 @@ DValue* VarExp::toElem(IRState* p) { Logger::println("VarDeclaration ' %s ' of type ' %s '", vd->toChars(), vd->type->toChars()); -#if DMDV2 /* The magic variable __ctfe is always false at runtime */ if (vd->ident == Id::ctfe) { return new DConstValue(type, DtoConstBool(false)); } -#endif // this is an error! must be accessed with DotVarExp if (var->needThis()) @@ -179,11 +173,7 @@ DValue* VarExp::toElem(IRState* p) return new DImValue(type, m); } // nested variable - #if DMDV2 else if (vd->nestedrefs.dim) { - #else - else if (vd->nestedref) { - #endif Logger::println("nested variable"); return DtoNestedVariable(loc, type, vd); } @@ -238,9 +228,7 @@ DValue* VarExp::toElem(IRState* p) { Logger::println("FuncDeclaration"); LLValue* func = 0; -#if DMDV2 fdecl = fdecl->toAliasFunc(); -#endif if (fdecl->llvmInternal == LLVMinline_asm) { error("special ldc inline asm is not a normal function"); fatal(); @@ -608,11 +596,9 @@ DValue* AssignExp::toElem(IRState* p) Logger::println("performing aggregate zero initialization"); assert(e2->toInteger() == 0); DtoAggrZeroInit(l->getLVal()); -#if DMDV2 TypeStruct *ts = static_cast(e1->type); if (ts->sym->isNested() && ts->sym->vthis) DtoResolveNestedContext(loc, ts->sym, l->getLVal()); -#endif // Return value should be irrelevant. return r; } @@ -933,7 +919,6 @@ DValue* CallExp::toElem(IRState* p) // llvm doesn't need the second param hence the override Expression* exp = static_cast(arguments->data[0]); LLValue* arg = exp->toElem(p)->getLVal(); -#if DMDV2 if (LLValue *argptr = gIR->func()->_argptr) { DtoStore(DtoLoad(argptr), DtoBitCast(arg, getPtrToType(getVoidPtrType()))); return new DImValue(type, arg); @@ -943,13 +928,11 @@ DValue* CallExp::toElem(IRState* p) va_list = DtoBitCast(va_list, getVoidPtrType()); return new DImValue(type, gIR->ir->CreateCall(GET_INTRINSIC_DECL(vastart), va_list, "")); } else -#endif { arg = DtoBitCast(arg, getVoidPtrType()); return new DImValue(type, gIR->ir->CreateCall(GET_INTRINSIC_DECL(vastart), arg, "")); } } -#if DMDV2 else if (fndecl->llvmInternal == LLVMva_copy && global.params.targetTriple.getArch() == llvm::Triple::x86_64) { if (arguments->dim != 2) { @@ -967,7 +950,6 @@ DValue* CallExp::toElem(IRState* p) DtoStore(DtoLoad(DtoLoad(arg2)), DtoLoad(arg1)); return new DVarValue(type, arg1); } -#endif // va_arg instruction else if (fndecl->llvmInternal == LLVMva_arg) { if (arguments->dim != 1) { @@ -1525,7 +1507,6 @@ DValue* ThisExp::toElem(IRState* p) LLValue* v; Dsymbol* vdparent = vd->toParent2(); Identifier *ident = p->func()->decl->ident; -#if DMDV2 // In D1, contracts are treated as normal nested methods, 'this' is // just passed in the context struct along with any used parameters. if (ident == Id::ensure || ident == Id::require) { @@ -1533,14 +1514,9 @@ DValue* ThisExp::toElem(IRState* p) v = p->func()->nestArg; v = DtoBitCast(v, DtoType(type)->getPointerTo()); } else -#endif if (vdparent != p->func()->decl) { Logger::println("nested this exp"); -#if STRUCTTHISREF return DtoNestedVariable(loc, type, vd, type->ty == Tstruct); -#else - return DtoNestedVariable(loc, type, vd); -#endif } else { Logger::println("normal this exp"); @@ -1650,11 +1626,7 @@ DValue* SliceExp::toElem(IRState* p) LLValue* vlo = lo->getRVal(); LLValue* vup = up->getRVal(); -#if DMDV2 if(global.params.useArrayBounds) -#else - if(global.params.useArrayBounds && (etype->ty == Tsarray || etype->ty == Tarray)) -#endif DtoArrayBoundsCheck(loc, e, up, lo); // offset by lower @@ -1995,7 +1967,6 @@ DValue* NewExp::toElem(IRState* p) Logger::println("new struct on heap: %s\n", newtype->toChars()); // allocate LLValue* mem = 0; -#if DMDV2 if (allocator) { // custom allocator @@ -2004,7 +1975,6 @@ DValue* NewExp::toElem(IRState* p) DValue* res = DtoCallFunction(loc, NULL, &dfn, newargs); mem = DtoBitCast(res->getRVal(), DtoType(ntype->pointerTo()), ".newstruct_custom"); } else -#endif { // default allocator mem = DtoNew(newtype); @@ -2019,7 +1989,6 @@ DValue* NewExp::toElem(IRState* p) ts->sym->codegen(Type::sir); DtoAggrCopy(mem, ts->sym->ir.irStruct->getInitSymbol()); } -#if DMDV2 if (ts->sym->isNested() && ts->sym->vthis) DtoResolveNestedContext(loc, ts->sym, mem); @@ -2032,7 +2001,6 @@ DValue* NewExp::toElem(IRState* p) DFuncValue dfn(member, member->ir.irFunc->func, mem); DtoCallFunction(loc, ts, &dfn, arguments); } -#endif return new DImValue(type, mem); } // new basic type @@ -2068,14 +2036,7 @@ DValue* DeleteExp::toElem(IRState* p) // simple pointer if (et->ty == Tpointer) { -#if DMDV2 DtoDeleteMemory(dval->isLVal() ? dval->getLVal() : makeLValue(loc, dval)); -#else - LLValue* rval = dval->getRVal(); - DtoDeleteMemory(rval); - if (dval->isVar()) - DtoStore(LLConstant::getNullValue(rval->getType()), dval->getLVal()); -#endif } // class else if (et->ty == Tclass) @@ -2084,11 +2045,7 @@ DValue* DeleteExp::toElem(IRState* p) TypeClass* tc = static_cast(et); if (tc->sym->isInterfaceDeclaration()) { -#if DMDV2 LLValue *val = dval->getLVal(); -#else - LLValue *val = dval->getRVal(); -#endif DtoDeleteInterface(val); onstack = true; } @@ -2620,23 +2577,7 @@ DValue* CatExp::toElem(IRState* p) Logger::print("CatExp::toElem: %s @ %s\n", toChars(), type->toChars()); LOG_SCOPE; -#if DMDV2 return DtoCatArrays(type, e1, e2); -#else - - bool arrNarr = e1->type->toBasetype() == e2->type->toBasetype(); - // array ~ array - if (arrNarr) - { - return DtoCatArrays(type, e1, e2); - } - // array ~ element - // element ~ array - else - { - return DtoCatArrayElement(type, e1, e2); - } -#endif } ////////////////////////////////////////////////////////////////////////////////////////// @@ -2706,17 +2647,14 @@ DValue* FuncExp::toElem(IRState* p) LLValue* cval; IrFunction* irfn = p->func(); if (irfn->nestedVar -#if DMDV2 // We cannot use a frame allocated in one function // for a delegate created in another function // (that happens with anonymous functions) && fd->toParent2() == irfn->decl -#endif ) cval = irfn->nestedVar; else if (irfn->nestArg) cval = DtoLoad(irfn->nestArg); -#if DMDV2 // TODO: should we enable that for D1 as well? else if (irfn->thisArg) { @@ -2728,7 +2666,6 @@ DValue* FuncExp::toElem(IRState* p) cval = DtoLoad(DtoGEPi(cval, 0,ad->vthis->ir.irField->index, ".vthis")); } } -#endif else cval = getNullPtr(getVoidPtrType()); cval = DtoBitCast(cval, dgty->getContainedType(0)); @@ -2884,11 +2821,9 @@ LLConstant* ArrayLiteralExp::toConstElem(IRState* p) LLConstant* globalstore = new LLGlobalVariable(*gIR->module, t, false, LLGlobalValue::InternalLinkage, initval, ".dynarrayStorage"); globalstore = DtoBitCast(globalstore, getPtrToType(arrtype)); -#if DMDV2 if (bt->ty == Tpointer) // we need to return pointer to the static array. return globalstore; -#endif // build a constant dynamic array reference with the .ptr field pointing into globalstore LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) }; @@ -2913,8 +2848,6 @@ DValue* StructLiteralExp::toElem(IRState* p) Logger::print("StructLiteralExp::toElem: %s @ %s\n", toChars(), type->toChars()); LOG_SCOPE; - -#if DMDV2 if (sinit) { // Copied from VarExp::toElem, need to clean this mess up. @@ -2929,7 +2862,6 @@ DValue* StructLiteralExp::toElem(IRState* p) initsym = DtoBitCast(initsym, DtoType(ts->pointerTo())); return new DVarValue(type, initsym); } -#endif // make sure the struct is fully resolved sd->codegen(Type::sir); @@ -2976,13 +2908,11 @@ DValue* StructLiteralExp::toElem(IRState* p) IF_LOG Logger::println("expr %zu = %s", it.index, expr->toChars()); val = expr->toElem(gIR); } -#if DMDV2 else if (vd == sd->vthis) { IF_LOG Logger::println("initializing vthis"); LOG_SCOPE val = new DImValue(vd->type, DtoBitCast(DtoNestedContext(loc, sd), DtoType(vd->type))); } -#endif else { if (vd->init && vd->init->isVoidInitializer()) @@ -2999,10 +2929,8 @@ DValue* StructLiteralExp::toElem(IRState* p) // store the initializer there DtoAssign(loc, &field, val, TOKconstruct); -#if DMDV2 if (expr) callPostblit(loc, expr, field.getLVal()); -#endif // Also zero out padding bytes counted as being part of the type in DMD // but not in LLVM; e.g. real/x86_fp80. @@ -3030,7 +2958,6 @@ LLConstant* StructLiteralExp::toConstElem(IRState* p) Logger::print("StructLiteralExp::toConstElem: %s @ %s\n", toChars(), type->toChars()); LOG_SCOPE; -#if DMDV2 if (sinit) { // Copied from VarExp::toConstElem, need to clean this mess up. @@ -3042,7 +2969,6 @@ LLConstant* StructLiteralExp::toConstElem(IRState* p) return ts->sym->ir.irStruct->getDefaultInit(); } -#endif // make sure the struct is resolved sd->codegen(Type::sir); @@ -3120,7 +3046,6 @@ DValue* AssocArrayLiteralExp::toElem(IRState* p) Type* aatype = basetype; Type* vtype = aatype->nextOf(); -#if DMDV2 if (!keys->dim) goto LruntimeInit; @@ -3185,7 +3110,6 @@ DValue* AssocArrayLiteralExp::toElem(IRState* p) } LruntimeInit: -#endif // it should be possible to avoid the temporary in some cases LLValue* tmp = DtoAlloca(type, "aaliteral"); @@ -3278,8 +3202,6 @@ DValue* TupleExp::toElem(IRState *p) ////////////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - DValue* VectorExp::toElem(IRState* p) { Logger::print("VectorExp::toElem() %s\n", toChars()); @@ -3314,20 +3236,14 @@ DValue* VectorExp::toElem(IRState* p) return new DVarValue(to, vector); } -#endif - - ////////////////////////////////////////////////////////////////////////////////////////// #define STUB(x) DValue *x::toElem(IRState * p) {error("Exp type "#x" not implemented: %s", toChars()); fatal(); return 0; } STUB(Expression); STUB(ScopeExp); - -#if DMDV2 STUB(SymbolExp); STUB(PowExp); STUB(PowAssignExp); -#endif #define CONSTSTUB(x) LLConstant* x::toConstElem(IRState * p) { \ error("expression '%s' is not a constant", toChars()); \ diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 85347fb9..38c5b9ae 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -202,12 +202,10 @@ LLType* DtoType(Type* t) case Taarray: return getVoidPtrType(); -#if DMDV2 case Tvector: { return IrTypeVector::get(t)->getLLType(); } -#endif /* Not needed atm as VarDecls for tuples are rewritten as a string of @@ -1036,11 +1034,7 @@ LLStructType* DtoModuleReferenceType() // add members LLType *types[] = { getPtrToType(st), -#if DMDV1 - DtoType(Module::moduleinfo->type) -#else DtoType(Module::moduleinfo->type->pointerTo()) -#endif }; // resolve type diff --git a/gen/typinf.cpp b/gen/typinf.cpp index 404c450d..f9df4a57 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -82,10 +82,8 @@ Expression *Type::getInternalTypeInfo(Scope *sc) goto Linternal; case Tarray: - #if DMDV2 // convert to corresponding dynamic array type t = t->nextOf()->mutableOf()->arrayOf(); - #endif if (t->nextOf()->ty != Tclass) break; goto Linternal; @@ -129,7 +127,6 @@ Expression *Type::getTypeInfo(Scope *sc) if (!t->vtinfo) { -#if DMDV2 if (t->isShared()) t->vtinfo = new TypeInfoSharedDeclaration(t); else if (t->isConst()) @@ -139,7 +136,6 @@ Expression *Type::getTypeInfo(Scope *sc) else if (t->isWild()) t->vtinfo = new TypeInfoWildDeclaration(t); else -#endif t->vtinfo = t->getTypeInfoDeclaration(); assert(t->vtinfo); @@ -218,12 +214,10 @@ TypeInfoDeclaration *TypeClass::getTypeInfoDeclaration() return new TypeInfoClassDeclaration(this); } -#if DMDV2 TypeInfoDeclaration *TypeVector::getTypeInfoDeclaration() { return new TypeInfoVectorDeclaration(this); } -#endif TypeInfoDeclaration *TypeEnum::getTypeInfoDeclaration() { @@ -258,22 +252,14 @@ int Type::builtinTypeInfo() int TypeBasic::builtinTypeInfo() { -#if DMDV2 return mod ? 0 : 1; -#else - return 1; -#endif } int TypeDArray::builtinTypeInfo() { -#if DMDV2 return !mod && ((next->isTypeBasic() != NULL && !next->mod) || // strings are so common, make them builtin (next->ty == Tchar && next->mod == MODimmutable)); -#else - return next->isTypeBasic() != NULL; -#endif } int TypeClass::builtinTypeInfo() @@ -466,11 +452,7 @@ void TypeInfoEnumDeclaration::llvmDefine() else { LLType* memty = DtoType(sd->memtype); -#if DMDV2 LLConstant* C = LLConstantInt::get(memty, sd->defaultval->toInteger(), !isLLVMUnsigned(sd->memtype)); -#else - LLConstant* C = LLConstantInt::get(memty, sd->defaultval, !isLLVMUnsigned(sd->memtype)); -#endif b.push_void_array(C, sd->memtype, sd); } @@ -546,10 +528,8 @@ void TypeInfoAssociativeArrayDeclaration::llvmDefine() // key typeinfo b.push_typeinfo(tc->index); -#if DMDV2 // impl typeinfo b.push_typeinfo(tc->getImpl()->type); -#endif // finish b.finalize(ir.irGlobal); @@ -646,16 +626,10 @@ void TypeInfoStructDeclaration::llvmDefine() { Scope sc; tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); -#if DMDV2 tftohash ->mod = MODconst; -#endif tftohash = static_cast(tftohash->semantic(0, &sc)); -#if DMDV2 Type *retType = Type::tchar->invariantOf()->arrayOf(); -#else - Type *retType = Type::tchar->arrayOf(); -#endif tftostring = new TypeFunction(NULL, retType, 0, LINKd); tftostring = static_cast(tftostring->semantic(0, &sc)); } @@ -666,18 +640,12 @@ void TypeInfoStructDeclaration::llvmDefine() { Scope sc; Parameters *arguments = new Parameters; -#if STRUCTTHISREF + // arg type is ref const T Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); -#else - // arg type is const T* - Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); -#endif arguments->push(arg); tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); -#if DMDV2 tfcmpptr->mod = MODconst; -#endif tfcmpptr = static_cast(tfcmpptr->semantic(0, &sc)); } @@ -689,11 +657,7 @@ void TypeInfoStructDeclaration::llvmDefine() b.push_funcptr(fd); // opEquals -#if DMDV2 fd = sd->xeq; -#else - fd = find_method_overload(sd, Id::eq, tfcmpptr, gm); -#endif b.push_funcptr(fd); // opCmp @@ -708,8 +672,6 @@ void TypeInfoStructDeclaration::llvmDefine() unsigned hasptrs = tc->hasPointers() ? 1 : 0; b.push_uint(hasptrs); -#if DMDV2 - ClassDeclaration* tscd = Type::typeinfostruct; // On x86_64, class TypeInfo_Struct contains 2 additional fields @@ -759,15 +721,12 @@ void TypeInfoStructDeclaration::llvmDefine() else b.push_size_as_vp(1); // has pointers -#endif - // finish b.finalize(ir.irGlobal); } /* ========================================================================= */ -#if DMDV2 void TypeInfoClassDeclaration::codegen(Ir*i) { @@ -778,28 +737,10 @@ void TypeInfoClassDeclaration::codegen(Ir*i) tc->sym->codegen(Type::sir); // make sure class is resolved irg->value = tc->sym->ir.irStruct->getClassInfoSymbol(); } -#endif void TypeInfoClassDeclaration::llvmDefine() { -#if DMDV2 llvm_unreachable("TypeInfoClassDeclaration should not be called for D2"); -#endif - Logger::println("TypeInfoClassDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // make sure class is resolved - assert(tinfo->ty == Tclass); - TypeClass *tc = static_cast(tinfo); - tc->sym->codegen(Type::sir); - - RTTIBuilder b(Type::typeinfoclass); - - // TypeInfo base - b.push_classinfo(tc->sym); - - // finish - b.finalize(ir.irGlobal); } /* ========================================================================= */ @@ -861,8 +802,6 @@ void TypeInfoTupleDeclaration::llvmDefine() /* ========================================================================= */ -#if DMDV2 - void TypeInfoConstDeclaration::llvmDefine() { Logger::println("TypeInfoConstDeclaration::llvmDefine() %s", toChars()); @@ -933,5 +872,3 @@ void TypeInfoVectorDeclaration::llvmDefine() // finish b.finalize(ir.irGlobal); } - -#endif diff --git a/ir/irclass.cpp b/ir/irclass.cpp index 219f92f5..21c4b057 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -185,7 +185,6 @@ LLConstant * IrStruct::getVtblInit() fd->codegen(Type::sir); assert(fd->ir.irFunc && "invalid vtbl function"); c = fd->ir.irFunc->func; -#if DMDV2 if (cd->isFuncHidden(fd)) { /* fd is hidden from the view of this class. * If fd overlaps with any function in the vtbl[], then @@ -218,7 +217,6 @@ LLConstant * IrStruct::getVtblInit() } } } -#endif } constants.push_back(c); } diff --git a/ir/irlandingpad.cpp b/ir/irlandingpad.cpp index 8f4c25ca..55b0e54d 100644 --- a/ir/irlandingpad.cpp +++ b/ir/irlandingpad.cpp @@ -28,11 +28,7 @@ IRLandingPadInfo::IRLandingPadInfo(Catch* catchstmt_, llvm::BasicBlock* end_) : catchType->codegen(Type::sir); if(catchstmt->var) { - #if DMDV2 if(!catchstmt->var->nestedrefs.dim) { - #else - if(!catchstmt->var->nestedref) { - #endif gIR->func()->gen->landingPadInfo.getExceptionStorage(); } } @@ -56,11 +52,7 @@ void IRLandingPadInfo::toIR() if(catchstmt->var) { // use the same storage for all exceptions that are not accessed in // nested functions - #if DMDV2 if(!catchstmt->var->nestedrefs.dim) { - #else - if(!catchstmt->var->nestedref) { - #endif assert(!catchstmt->var->ir.irLocal); catchstmt->var->ir.irLocal = new IrLocal(catchstmt->var); LLValue* catch_var = gIR->func()->gen->landingPadInfo.getExceptionStorage(); diff --git a/ir/irstruct.cpp b/ir/irstruct.cpp index db7410e3..0873f403 100644 --- a/ir/irstruct.cpp +++ b/ir/irstruct.cpp @@ -67,11 +67,9 @@ LLGlobalVariable * IrStruct::getInitSymbol() // set alignment init->setAlignment(type->alignsize()); -#if DMDV2 StructDeclaration *sd = aggrdecl->isStructDeclaration(); if (sd && sd->alignment != STRUCTALIGN_DEFAULT) init->setAlignment(sd->alignment); -#endif return init; } diff --git a/ir/irtype.cpp b/ir/irtype.cpp index c25f206e..f73c71f6 100644 --- a/ir/irtype.cpp +++ b/ir/irtype.cpp @@ -266,8 +266,6 @@ IrTypeArray* IrTypeArray::get(Type* dt) ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - IrTypeVector::IrTypeVector(Type* dt) : IrType(dt, vector2llvm(dt)) { @@ -297,6 +295,4 @@ llvm::Type* IrTypeVector::vector2llvm(Type* dt) return llvm::VectorType::get(elemType, dim); } -#endif - ////////////////////////////////////////////////////////////////////////////// diff --git a/ir/irtype.h b/ir/irtype.h index 14e5c6a7..c3205350 100644 --- a/ir/irtype.h +++ b/ir/irtype.h @@ -37,9 +37,7 @@ class IrTypeFunction; class IrTypePointer; class IrTypeSArray; class IrTypeStruct; -#if DMDV2 class IrTypeVector; -#endif ////////////////////////////////////////////////////////////////////////////// @@ -72,10 +70,8 @@ public: virtual IrTypeSArray* isSArray() { return NULL; } /// virtual IrTypeStruct* isStruct() { return NULL; } -#if DMDV2 /// IrTypeVector* isVector() { return NULL; } -#endif /// Type* getDType() { return dtype; } @@ -170,7 +166,6 @@ protected: ////////////////////////////////////////////////////////////////////////////// -#if DMDV2 /// IrType for vectors class IrTypeVector : public IrType { @@ -187,6 +182,5 @@ protected: static llvm::Type* vector2llvm(Type* dt); }; -#endif #endif diff --git a/ir/irtypeclass.cpp b/ir/irtypeclass.cpp index 49635811..e29aa7d4 100644 --- a/ir/irtypeclass.cpp +++ b/ir/irtypeclass.cpp @@ -323,7 +323,6 @@ std::vector IrTypeClass::buildVtblType(Type* first, Array* vtbl_arr IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); -#if DMDV2 // If inferring return type and semantic3 has not been run, do it now. // This pops up in some other places in the frontend as well, however // it is probably a bug that it still occurs that late. @@ -336,7 +335,6 @@ std::vector IrTypeClass::buildVtblType(Type* first, Array* vtbl_arr if (spec && global.errors != olderrs) spec->errors = global.errors - olderrs; } -#endif if (!fd->type->nextOf()) { // Return type of the function has not been inferred. This seems to diff --git a/ldc-posix-tango b/ldc-posix-tango deleted file mode 100644 index d5c67c40..00000000 --- a/ldc-posix-tango +++ /dev/null @@ -1,78 +0,0 @@ -ignore=object - -compiler=ldc -inifile=ldc.rebuild.conf - -exeext= -objext=o - - -version=LLVM -version=LDC -noversion=DigitalMars -noversion=GNU -testversion=linux -testversion=darwin -testversion=freebsd -testversion=Unix -testversion=Posix -testversion=Windows -testversion=Win32 -testversion=Win64 -testversion=mingw32 -testversion=X86 -testversion=PPC -testversion=X86_64 -testversion=PPC64 -testversion=D_InlineAsm -testversion=D_InlineAsm_X86 -testversion=D_InlineAsm_PPC -testversion=D_InlineAsm_X86_64 -testversion=D_InlineAsm_PPC64 -testversion=LLVM_InlineAsm_X86 -testversion=LittleEndian -testversion=BigEndian -testversion=LLVM64 -testversion=PIC -testversion=Tango - - -[compile] -oneatatime=yes -cmd=ldmd -c $i - -flag=$i -incdir=-I$i -libdir=-L-L$i -optimize=-O3 -version=-version=$i - - -[link] -oneatatime=yes -cmd=ldc $i -of$o - -libdir=-L-L$i -lib=-L-l$i -flag=-L$i - - -[liblink] -safe=yes -oneatatime=yes -cmd=ar rc $o $i - -libdir= -lib= -flag= - - -[postliblink] -cmd=ranlib $i - - -[shliblink] -shlibs=no - -[dyliblink] -dylibs=no