diff --git a/dmd/aggregate.h b/dmd/aggregate.h index 2e030d2c..6e42c93f 100644 --- a/dmd/aggregate.h +++ b/dmd/aggregate.h @@ -1,259 +1,282 @@ - -// 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_AGGREGATE_H -#define DMD_AGGREGATE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "dsymbol.h" - -#include -#include -#include - -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; - -namespace llvm -{ - class Type; - class Value; - class Constant; - class ConstantStruct; - class GlobalVariable; -} -struct DUnion; - -struct AggregateDeclaration : ScopeDsymbol -{ - Type *type; - unsigned storage_class; - enum PROT protection; - Type *handle; // 'this' type - unsigned structsize; // size of struct - unsigned alignsize; // size of struct for alignment purposes - unsigned structalign; // struct member alignment in effect - int hasUnions; // set if aggregate has overlapping fields - Array fields; // VarDeclaration fields - unsigned sizeok; // set when structsize contains valid data - // 0: no size - // 1: size is correct - // 2: cannot determine size; fwd referenced - int isdeprecated; // !=0 if deprecated - Scope *scope; // !=NULL means context to use - - // Special member functions - InvariantDeclaration *inv; // invariant - NewDeclaration *aggNew; // allocator - DeleteDeclaration *aggDelete; // deallocator - -#ifdef IN_GCC - Array methods; // flat list of all methods for debug information -#endif - - AggregateDeclaration(Loc loc, Identifier *id); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - unsigned size(Loc loc); - static void alignmember(unsigned salign, unsigned size, unsigned *poffset); - Type *getType(); - void addField(Scope *sc, VarDeclaration *v); - int isDeprecated(); // is aggregate deprecated? - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - // For access checking - virtual PROT getAccess(Dsymbol *smember); // determine access to smember - int isFriendOf(AggregateDeclaration *cd); - int hasPrivateAccess(Dsymbol *smember); // does smember have private access to members of this class? - void accessCheck(Loc loc, Scope *sc, Dsymbol *smember); - - enum PROT prot(); - - // Back end - Symbol *stag; // tag symbol for debug data - Symbol *sinit; - Symbol *toInitializer(); - - AggregateDeclaration *isAggregateDeclaration() { return this; } -}; - -struct AnonymousAggregateDeclaration : AggregateDeclaration -{ - AnonymousAggregateDeclaration() - : AggregateDeclaration(0, NULL) - { - } - - AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; } -}; - -struct StructDeclaration : AggregateDeclaration -{ - int zeroInit; // !=0 if initialize with 0 fill - - StructDeclaration(Loc loc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *mangle(); - char *kind(); - void toDocBuffer(OutBuffer *buf); - - PROT getAccess(Dsymbol *smember); // determine access to smember - - void toObjFile(); // compile to .obj file - void toDt(dt_t **pdt); - void toDebug(); // to symbolic debug info - - StructDeclaration *isStructDeclaration() { return this; } -}; - -struct UnionDeclaration : StructDeclaration -{ - UnionDeclaration(Loc loc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - char *kind(); - - UnionDeclaration *isUnionDeclaration() { return this; } -}; - -struct BaseClass -{ - Type *type; // (before semantic processing) - enum PROT protection; // protection for the base interface - - ClassDeclaration *base; - int offset; // 'this' pointer offset - Array vtbl; // for interfaces: Array of FuncDeclaration's - // making up the vtbl[] - - int baseInterfaces_dim; - BaseClass *baseInterfaces; // if BaseClass is an interface, these - // are a copy of the InterfaceDeclaration::interfaces - - BaseClass(); - BaseClass(Type *type, enum PROT protection); - - int fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance); - void copyBaseInterfaces(BaseClasses *); -}; - -#define CLASSINFO_SIZE (0x3C+12) // value of ClassInfo.size - -struct ClassDeclaration : AggregateDeclaration -{ - static ClassDeclaration *object; - static ClassDeclaration *classinfo; - - ClassDeclaration *baseClass; // NULL only if this is Object - CtorDeclaration *ctor; - CtorDeclaration *defaultCtor; // default constructor - FuncDeclarations dtors; // Array of destructors - FuncDeclaration *staticCtor; - FuncDeclaration *staticDtor; - Array vtbl; // Array of FuncDeclaration's making up the vtbl[] - Array vtblFinal; // More FuncDeclaration's that aren't in vtbl[] - - BaseClasses baseclasses; // Array of BaseClass's; first is super, - // rest are Interface's - - int interfaces_dim; - BaseClass **interfaces; // interfaces[interfaces_dim] for this class - // (does not include baseClass) - - BaseClasses *vtblInterfaces; // array of base interfaces that have - // their own vtbl[] - - ClassInfoDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration - int com; // !=0 if this is a COM class - int isauto; // !=0 if this is an auto class - int isabstract; // !=0 if abstract class - - int isnested; // !=0 if is nested - VarDeclaration *vthis; // 'this' parameter if this class is nested - - ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isBaseOf2(ClassDeclaration *cd); - - #define OFFSET_RUNTIME 0x76543210 - virtual int isBaseOf(ClassDeclaration *cd, int *poffset); - - Dsymbol *search(Loc, Identifier *ident, int flags); - FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); - void interfaceSemantic(Scope *sc); - int isNested(); - int isCOMclass(); - virtual int isCOMinterface(); - int isAbstract(); - virtual int vtblOffset(); - char *kind(); - char *mangle(); - void toDocBuffer(OutBuffer *buf); - - PROT getAccess(Dsymbol *smember); // determine access to smember - - void addLocalClass(ClassDeclarations *); - - // Back end - void toObjFile(); // 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; - - void offsetToIndex(Type* t, unsigned os, std::vector& result); - - ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } -}; - -struct InterfaceDeclaration : ClassDeclaration -{ - 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); - char *kind(); - int vtblOffset(); - virtual int isCOMinterface(); - - void toObjFile(); // compile to .obj file - Symbol *toSymbol(); - - InterfaceDeclaration *isInterfaceDeclaration() { return this; } -}; - -#endif /* DMD_AGGREGATE_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_AGGREGATE_H +#define DMD_AGGREGATE_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "dsymbol.h" + +#include +#include +#include + +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; + +namespace llvm +{ + class Type; + class Value; + class Constant; + class ConstantStruct; + class GlobalVariable; +} +struct DUnion; + +struct AggregateDeclaration : ScopeDsymbol +{ + Type *type; + unsigned storage_class; + enum PROT protection; + Type *handle; // 'this' type + unsigned structsize; // size of struct + unsigned alignsize; // size of struct for alignment purposes + unsigned structalign; // struct member alignment in effect + int hasUnions; // set if aggregate has overlapping fields + Array fields; // VarDeclaration fields + unsigned sizeok; // set when structsize contains valid data + // 0: no size + // 1: size is correct + // 2: cannot determine size; fwd referenced + int isdeprecated; // !=0 if deprecated + Scope *scope; // !=NULL means context to use + FuncDeclarations dtors; // Array of destructors + FuncDeclaration *dtor; // aggregate destructor + + // Special member functions + InvariantDeclaration *inv; // invariant + NewDeclaration *aggNew; // allocator + DeleteDeclaration *aggDelete; // deallocator + +#ifdef IN_GCC + Array methods; // flat list of all methods for debug information +#endif + + AggregateDeclaration(Loc loc, Identifier *id); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + void inlineScan(); + unsigned size(Loc loc); + static void alignmember(unsigned salign, unsigned size, unsigned *poffset); + Type *getType(); + void addField(Scope *sc, VarDeclaration *v); + int isDeprecated(); // is aggregate deprecated? + FuncDeclaration *buildDtor(Scope *sc); + + void emitComment(Scope *sc); + void toDocBuffer(OutBuffer *buf); + + // For access checking + virtual PROT getAccess(Dsymbol *smember); // determine access to smember + int isFriendOf(AggregateDeclaration *cd); + int hasPrivateAccess(Dsymbol *smember); // does smember have private access to members of this class? + void accessCheck(Loc loc, Scope *sc, Dsymbol *smember); + + enum PROT prot(); + + // Back end + Symbol *stag; // tag symbol for debug data + Symbol *sinit; + Symbol *toInitializer(); + + AggregateDeclaration *isAggregateDeclaration() { return this; } +}; + +struct AnonymousAggregateDeclaration : AggregateDeclaration +{ + AnonymousAggregateDeclaration() + : AggregateDeclaration(0, NULL) + { + } + + AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; } +}; + +struct StructDeclaration : AggregateDeclaration +{ + int zeroInit; // !=0 if initialize with 0 fill + + StructDeclaration(Loc loc, Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + char *mangle(); + char *kind(); + Expression *cloneMembers(); + void toDocBuffer(OutBuffer *buf); + + PROT getAccess(Dsymbol *smember); // determine access to smember + + void toObjFile(); // compile to .obj file + void toDt(dt_t **pdt); + void toDebug(); // to symbolic debug info + + StructDeclaration *isStructDeclaration() { return this; } +}; + +struct UnionDeclaration : StructDeclaration +{ + UnionDeclaration(Loc loc, Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *s); + char *kind(); + + UnionDeclaration *isUnionDeclaration() { return this; } +}; + +struct BaseClass +{ + Type *type; // (before semantic processing) + enum PROT protection; // protection for the base interface + + ClassDeclaration *base; + int offset; // 'this' pointer offset + Array vtbl; // for interfaces: Array of FuncDeclaration's + // making up the vtbl[] + + int baseInterfaces_dim; + BaseClass *baseInterfaces; // if BaseClass is an interface, these + // are a copy of the InterfaceDeclaration::interfaces + + BaseClass(); + BaseClass(Type *type, enum PROT protection); + + int fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance); + void copyBaseInterfaces(BaseClasses *); +}; + +#if V2 +#define CLASSINFO_SIZE (0x3C+16) // value of ClassInfo.size +#else +#define CLASSINFO_SIZE (0x3C+12) // value of ClassInfo.size +#endif + +struct ClassDeclaration : AggregateDeclaration +{ + static ClassDeclaration *object; + static ClassDeclaration *classinfo; + + ClassDeclaration *baseClass; // NULL only if this is Object + CtorDeclaration *ctor; + CtorDeclaration *defaultCtor; // default constructor + FuncDeclaration *staticCtor; + FuncDeclaration *staticDtor; + Array vtbl; // Array of FuncDeclaration's making up the vtbl[] + Array vtblFinal; // More FuncDeclaration's that aren't in vtbl[] + + BaseClasses baseclasses; // Array of BaseClass's; first is super, + // rest are Interface's + + int interfaces_dim; + BaseClass **interfaces; // interfaces[interfaces_dim] for this class + // (does not include baseClass) + + BaseClasses *vtblInterfaces; // array of base interfaces that have + // their own vtbl[] + + ClassInfoDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration + int com; // !=0 if this is a COM class (meaning + // it derives from IUnknown) + int isauto; // !=0 if this is an auto class + int isabstract; // !=0 if abstract class + + int isnested; // !=0 if is nested + VarDeclaration *vthis; // 'this' parameter if this class is nested + + int inuse; // to prevent recursive attempts + + ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isBaseOf2(ClassDeclaration *cd); + + #define OFFSET_RUNTIME 0x76543210 + virtual int isBaseOf(ClassDeclaration *cd, int *poffset); + + Dsymbol *search(Loc, Identifier *ident, int flags); +#if V2 + int isFuncHidden(FuncDeclaration *fd); +#endif + FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); + void interfaceSemantic(Scope *sc); + int isNested(); + int isCOMclass(); + virtual int isCOMinterface(); +#if V2 + virtual int isCPPinterface(); +#endif + int isAbstract(); + virtual int vtblOffset(); + char *kind(); + char *mangle(); + void toDocBuffer(OutBuffer *buf); + + PROT getAccess(Dsymbol *smember); // determine access to smember + + void addLocalClass(ClassDeclarations *); + + // Back end + void toObjFile(); // 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; + + // llvm + void offsetToIndex(Type* t, unsigned os, std::vector& result); + + ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } +}; + +struct InterfaceDeclaration : ClassDeclaration +{ +#if V2 + 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); + char *kind(); + int vtblOffset(); +#if V2 + int isCPPinterface(); +#endif + virtual int isCOMinterface(); + + void toObjFile(); // compile to .obj file + Symbol *toSymbol(); + + InterfaceDeclaration *isInterfaceDeclaration() { return this; } +}; + +#endif /* DMD_AGGREGATE_H */ diff --git a/dmd/attrib.c b/dmd/attrib.c index eca71fad..38e06cff 100644 --- a/dmd/attrib.c +++ b/dmd/attrib.c @@ -1,1292 +1,1319 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#if _WIN32 || IN_GCC || IN_LLVM -#include "mem.h" -#elif linux -#include "../root/mem.h" -#endif - -#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" - -#include "../gen/enums.h" -#include "../gen/logger.h" - -extern void obj_includelib(char *name); - - -/********************************* AttribDeclaration ****************************/ - -AttribDeclaration::AttribDeclaration(Array *decl) - : Dsymbol() -{ - this->decl = decl; -} - -Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) -{ - return decl; -} - -int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - unsigned i; - int m = 0; - Array *d = include(sc, sd); - - if (d) - { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - m |= s->addMember(sc, sd, m | memnum); - } - } - return m; -} - -void AttribDeclaration::semantic(Scope *sc) -{ - Array *d = include(sc, NULL); - - //printf("\tAttribDeclaration::semantic '%s'\n",toChars()); - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { - Dsymbol *s = (Dsymbol *)d->data[i]; - - s->semantic(sc); - } - } -} - -void AttribDeclaration::semantic2(Scope *sc) -{ - unsigned i; - Array *d = include(sc, NULL); - - if (d) - { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - s->semantic2(sc); - } - } -} - -void AttribDeclaration::semantic3(Scope *sc) -{ - unsigned i; - Array *d = include(sc, NULL); - - if (d) - { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - s->semantic3(sc); - } - } -} - -void AttribDeclaration::inlineScan() -{ - unsigned i; - Array *d = include(NULL, NULL); - - if (d) - { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); - s->inlineScan(); - } - } -} - -void AttribDeclaration::addComment(unsigned char *comment) -{ - if (comment) - { - unsigned i; - Array *d = include(NULL, NULL); - - if (d) - { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - //printf("AttribDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - } -} - -void AttribDeclaration::emitComment(Scope *sc) -{ - //printf("AttribDeclaration::emitComment(sc = %p)\n", sc); - - /* If generating doc comment, skip this because if we're inside - * a template, then include(NULL, NULL) will fail. - */ -// if (sc->docbuf) -// return; - - unsigned i; - Array *d = include(NULL, NULL); - - if (d) - { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - //printf("AttribDeclaration::emitComment %s\n", s->toChars()); - s->emitComment(sc); - } - } -} - -void AttribDeclaration::toObjFile() -{ - unsigned i; - Array *d = include(NULL, NULL); - - if (d) - { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - s->toObjFile(); - } - } -} - -int AttribDeclaration::cvMember(unsigned char *p) -{ - unsigned i; - int nwritten = 0; - int n; - Array *d = include(NULL, NULL); - - if (d) - { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - n = s->cvMember(p); - if (p) - p += n; - nwritten += n; - } - } - return nwritten; -} - -int AttribDeclaration::hasPointers() -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (Dsymbol *)d->data[i]; - if (s->hasPointers()) - return 1; - } - } - return 0; -} - -char *AttribDeclaration::kind() -{ - return "attribute"; -} - -int AttribDeclaration::oneMember(Dsymbol **ps) -{ - Array *d = include(NULL, NULL); - - return Dsymbol::oneMembers(d, ps); -} - -void AttribDeclaration::checkCtorConstInit() -{ - unsigned i; - Array *d = include(NULL, NULL); - - if (d) - { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - s->checkCtorConstInit(); - } - } -} - -/**************************************** - */ - -void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ unsigned i; - Array *d = include(NULL, NULL); - - if (d) - { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - s->addLocalClass(aclasses); - } - } -} - - -void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (decl) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - else - buf->writeByte(';'); - buf->writenl(); -} - -/************************* StorageClassDeclaration ****************************/ - -StorageClassDeclaration::StorageClassDeclaration(unsigned stc, Array *decl) - : AttribDeclaration(decl) -{ - this->stc = stc; -} - -Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) -{ - StorageClassDeclaration *scd; - - assert(!s); - scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); - return scd; -} - -void StorageClassDeclaration::semantic(Scope *sc) -{ - if (decl) - { unsigned stc_save = sc->stc; - - if (stc & (STCauto | STCscope | STCstatic | STCextern)) - sc->stc &= ~(STCauto | STCscope | STCstatic | STCextern); - sc->stc |= stc; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - } - sc->stc = stc_save; - } - else - sc->stc = stc; -} - -void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - struct SCstring - { - int stc; - enum TOK tok; - }; - - static SCstring table[] = - { - { STCauto, TOKauto }, - { STCscope, TOKscope }, - { STCstatic, TOKstatic }, - { STCextern, TOKextern }, - { STCconst, TOKconst }, - { STCfinal, TOKfinal }, - { STCabstract, TOKabstract }, - { STCsynchronized, TOKsynchronized }, - { STCdeprecated, TOKdeprecated }, - { STCoverride, TOKoverride }, - }; - - int written = 0; - for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) - { - if (stc & table[i].stc) - { - if (written) - buf->writeByte(' '); - written = 1; - buf->writestring(Token::toChars(table[i].tok)); - } - } - - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* LinkDeclaration ****************************/ - -LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl) - : AttribDeclaration(decl) -{ - //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); - linkage = p; -} - -Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s) -{ - LinkDeclaration *ld; - - assert(!s); - ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); - return ld; -} - -void LinkDeclaration::semantic(Scope *sc) -{ - //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { enum LINK linkage_save = sc->linkage; - - sc->linkage = linkage; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - } - sc->linkage = linkage_save; - } - else - { - sc->linkage = linkage; - } -} - -void LinkDeclaration::semantic3(Scope *sc) -{ - //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { enum LINK linkage_save = sc->linkage; - - sc->linkage = linkage; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic3(sc); - } - sc->linkage = linkage_save; - } - else - { - sc->linkage = linkage; - } -} - -void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ 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; - default: - assert(0); - break; - } - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - AttribDeclaration::toCBuffer(buf, hgs); -} - -char *LinkDeclaration::toChars() -{ - return "extern ()"; -} - -/********************************* ProtDeclaration ****************************/ - -ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl) - : AttribDeclaration(decl) -{ - protection = p; - //printf("decl = %p\n", decl); -} - -Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s) -{ - ProtDeclaration *pd; - - assert(!s); - pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void ProtDeclaration::semantic(Scope *sc) -{ - if (decl) - { enum PROT protection_save = sc->protection; - int explicitProtection_save = sc->explicitProtection; - - sc->protection = protection; - sc->explicitProtection = 1; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - } - sc->protection = protection_save; - sc->explicitProtection = explicitProtection_save; - } - else - { sc->protection = protection; - sc->explicitProtection = 1; - } -} - -void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ 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); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AlignDeclaration ****************************/ - -AlignDeclaration::AlignDeclaration(unsigned sa, Array *decl) - : AttribDeclaration(decl) -{ - salign = sa; -} - -Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s) -{ - AlignDeclaration *ad; - - assert(!s); - ad = new AlignDeclaration(salign, Dsymbol::arraySyntaxCopy(decl)); - return ad; -} - -void AlignDeclaration::semantic(Scope *sc) -{ - //printf("\tAlignDeclaration::semantic '%s'\n",toChars()); - if (decl) - { unsigned salign_save = sc->structalign; - - sc->structalign = salign; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - } - sc->structalign = salign_save; - } - else - sc->structalign = salign; -} - - -void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("align (%d)", salign); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AnonDeclaration ****************************/ - -AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->isunion = isunion; - this->scope = NULL; - this->sem = 0; -} - -Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s) -{ - AnonDeclaration *ad; - - assert(!s); - ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); - return ad; -} - -void AnonDeclaration::semantic(Scope *sc) -{ - //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; - scope = NULL; - } - - assert(sc->parent); - - Dsymbol *parent = sc->parent->pastMixin(); - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - - if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration())) - { - error("can only be a part of an aggregate"); - return; - } - - if (decl) - { - AnonymousAggregateDeclaration aad; - int adisunion; - - if (sc->anonAgg) - { ad = sc->anonAgg; - adisunion = sc->inunion; - } - else - adisunion = ad->isUnionDeclaration() != NULL; - -// printf("\tsc->anonAgg = %p\n", sc->anonAgg); -// printf("\tad = %p\n", ad); -// printf("\taad = %p\n", &aad); - - sc = sc->push(); - sc->anonAgg = &aad; - sc->stc &= ~(STCauto | STCscope | STCstatic); - sc->inunion = isunion; - sc->offset = 0; - sc->flags = 0; - aad.structalign = sc->structalign; - aad.parent = ad; - - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - if (isunion) - sc->offset = 0; - if (aad.sizeok == 2) - { - break; - } - } - sc = sc->pop(); - - // If failed due to forward references, unwind and try again later - if (aad.sizeok == 2) - { - ad->sizeok = 2; - //printf("\tsetting ad->sizeok %p to 2\n", ad); - if (!sc->anonAgg) - { - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - //printf("\tforward reference %p\n", this); - return; - } - if (sem == 0) - { Module::dprogress++; - sem = 1; - //printf("\tcompleted %p\n", this); - } - else - ;//printf("\talready completed %p\n", this); - - // 0 sized structs are set to 1 byte - if (aad.structsize == 0) - { - aad.structsize = 1; - aad.alignsize = 1; - } - - // Align size of anonymous aggregate -//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset); - ad->alignmember(aad.structalign, aad.alignsize, &sc->offset); - //ad->structsize = sc->offset; -//printf("sc->offset = %d\n", sc->offset); - - // Add members of aad to ad - //printf("\tadding members of aad to '%s'\n", ad->toChars()); - for (unsigned i = 0; i < aad.fields.dim; i++) - { - VarDeclaration *v = (VarDeclaration *)aad.fields.data[i]; - - v->offset += sc->offset; - ad->fields.push(v); - } - - // Add size of aad to ad - if (adisunion) - { - if (aad.structsize > ad->structsize) - ad->structsize = aad.structsize; - sc->offset = 0; - } - else - { - ad->structsize = sc->offset + aad.structsize; - sc->offset = ad->structsize; - } - - if (ad->alignsize < aad.alignsize) - ad->alignsize = aad.alignsize; - } -} - - -void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf(isunion ? "union" : "struct"); - buf->writestring("\n{\n"); - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - //buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writestring("}\n"); -} - -char *AnonDeclaration::kind() -{ - return (char *)(isunion ? "anonymous union" : "anonymous struct"); -} - -/********************************* PragmaDeclaration ****************************/ - -PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->ident = ident; - this->args = args; -} - -Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) -{ - PragmaDeclaration *pd; - - assert(!s); - pd = new PragmaDeclaration(loc, ident, - Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void PragmaDeclaration::semantic(Scope *sc) -{ // Should be merged with PragmaStatement - -#if IN_LLVM - int llvm_internal = 0; - char* llvm_str1 = NULL; - -#endif - - //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); - if (ident == Id::msg) - { - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (Expression *)args->data[i]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKstring) - { - StringExp *se = (StringExp *)e; - fprintf(stdmsg, "%.*s", (int)se->len, se->string); - } - else - error("string expected for message, not '%s'", e->toChars()); - } - fprintf(stdmsg, "\n"); - } - goto Lnodecl; - } - else if (ident == Id::lib) - { - if (!args || args->dim != 1) - error("string expected for library name"); - else - { - Expression *e = (Expression *)args->data[0]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - if (e->op != TOKstring) - error("string expected for library name, not '%s'", e->toChars()); - else if (global.params.verbose) - { - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - printf("library %s\n", name); - mem.free(name); - } - } - goto Lnodecl; - } -#if IN_GCC - else if (ident == Id::GNU_asm) - { - if (! args || args->dim != 2) - error("identifier and string expected for asm name"); - else - { - Expression *e; - Declaration *d = NULL; - StringExp *s = NULL; - - e = (Expression *)args->data[0]; - e = e->semantic(sc); - if (e->op == TOKvar) - { - d = ((VarExp *)e)->var; - if (! d->isFuncDeclaration() && ! d->isVarDeclaration()) - d = NULL; - } - if (!d) - error("first argument of GNU_asm must be a function or variable declaration"); - - e = (Expression *)args->data[1]; - e = e->semantic(sc); - e = e->optimize(WANTvalue); - if (e->op == TOKstring && ((StringExp *)e)->sz == 1) - s = ((StringExp *)e); - else - error("second argument of GNU_asm must be a char string"); - - if (d && s) - d->c_ident = Lexer::idPool((char*) s->string); - } - goto Lnodecl; - } -#endif -#if IN_LLVM - else if (ident == Id::LLVM_internal) - { - if (!args || args->dim < 1 || args->dim > 2) - error("needs 1-3 parameters"); - else if (!decl || decl->dim < 1) - error("must apply to at least one declaration"); - else - { - Expression *e; - StringExp *s = NULL; - - e = (Expression *)args->data[0]; - e = e->semantic(sc); - e = e->optimize(WANTvalue); - if (e->op == TOKstring && (s = (StringExp *)e)) - { - char* str = (char*)s->string; - if (strcmp(str,"intrinsic")==0) { - llvm_internal = LLVMintrinsic; - assert(args->dim == 2); - } - else if (strcmp(str,"va_start")==0) { - llvm_internal = LLVMva_start; - assert(args->dim == 1); - } - else if (strcmp(str,"va_arg")==0) { - llvm_internal = LLVMva_arg; - assert(args->dim == 1); - } - else if (strcmp(str,"va_intrinsic")==0) { - llvm_internal = LLVMva_intrinsic; - assert(args->dim == 2); - } - else if (strcmp(str,"notypeinfo")==0) { - llvm_internal = LLVMnotypeinfo; - assert(args->dim == 1); - } - else if (strcmp(str,"alloca")==0) { - llvm_internal = LLVMalloca; - assert(args->dim == 1); - } - else { - error("unknown pragma command: %s", str); - } - } - else - error("1st argument must be a string"); - - if (llvm_internal) - switch (llvm_internal) - { - case LLVMintrinsic: - case LLVMva_intrinsic: - e = (Expression *)args->data[1]; - e = e->semantic(sc); - e = e->optimize(WANTvalue); - if (e->op == TOKstring && (s = (StringExp *)e)) { - llvm_str1 = (char*)s->string; - } - else - error("2nd argument must be a string"); - break; - - case LLVMva_arg: - case LLVMva_start: - case LLVMnotypeinfo: - case LLVMalloca: - break; - - default: - assert(0); - } - } - } -#endif - else - error("unrecognized pragma(%s)", ident->toChars()); - - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - -#if IN_LLVM - if (llvm_internal) - { - switch(llvm_internal) - { - case LLVMintrinsic: - case LLVMva_intrinsic: - if (FuncDeclaration* fd = s->isFuncDeclaration()) { - fd->llvmInternal = llvm_internal; - fd->llvmInternal1 = llvm_str1; - } - else { - error("may only be used on function declarations"); - assert(0); - } - break; - - case LLVMva_start: - case LLVMva_arg: - if (TemplateDeclaration* td = s->isTemplateDeclaration()) { - td->llvmInternal = llvm_internal; - assert(td->parameters->dim == 1); - assert(!td->overnext); - assert(!td->overroot); - assert(td->onemember); - Logger::println("template->onemember = %s", td->onemember->toChars()); - } - else { - error("can only be used on templates"); - assert(0); - } - break; - - case LLVMnotypeinfo: - s->llvmInternal = llvm_internal; - break; - - case LLVMalloca: - if (FuncDeclaration* fd = s->isFuncDeclaration()) { - fd->llvmInternal = llvm_internal; - } - else { - error("may only be used on function declarations"); - assert(0); - } - break; - - default: - assert(0 && "invalid LLVM_internal pragma got through :/"); - } - } - -#endif - } - } - return; - -Lnodecl: - if (decl) - error("pragma is missing closing ';'"); -} - -int PragmaDeclaration::oneMember(Dsymbol **ps) -{ - *ps = NULL; - return TRUE; -} - -char *PragmaDeclaration::kind() -{ - return "pragma"; -} - -void PragmaDeclaration::toObjFile() -{ - if (ident == Id::lib) - { - assert(args && args->dim == 1); - - Expression *e = (Expression *)args->data[0]; - - assert(e->op == TOKstring); - - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - obj_includelib(name); - } - AttribDeclaration::toObjFile(); -} - -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->writestring(")"); - AttribDeclaration::toCBuffer(buf, hgs); -} - - -/********************************* ConditionalDeclaration ****************************/ - -ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl) - : AttribDeclaration(decl) -{ - //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); - this->condition = condition; - this->elsedecl = elsedecl; -} - -Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) -{ - ConditionalDeclaration *dd; - - assert(!s); - dd = new ConditionalDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int ConditionalDeclaration::oneMember(Dsymbol **ps) -{ - //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); - if (condition->inc) - { - Array *d = condition->include(NULL, NULL) ? decl : elsedecl; - return Dsymbol::oneMembers(d, ps); - } - *ps = NULL; - return TRUE; -} - -void ConditionalDeclaration::emitComment(Scope *sc) -{ - //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc); - if (condition->inc) - { - AttribDeclaration::emitComment(sc); - } -} - -// Decide if 'then' or 'else' code should be included - -Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) -{ - //printf("ConditionalDeclaration::include()\n"); - assert(condition); - return condition->include(sc, sd) ? decl : elsedecl; -} - - -void ConditionalDeclaration::addComment(unsigned char *comment) -{ - /* Because addComment is called by the parser, if we called - * include() it would define a version before it was used. - * But it's no problem to drill down to both decl and elsedecl, - * so that's the workaround. - */ - - if (comment) - { - Array *d = decl; - - for (int j = 0; j < 2; j++) - { - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - d = elsedecl; - } - } -} - -void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - condition->toCBuffer(buf, hgs); - if (decl || elsedecl) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writeByte('}'); - if (elsedecl) - { - buf->writenl(); - buf->writestring("else"); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (unsigned i = 0; i < elsedecl->dim; i++) - { - Dsymbol *s = (Dsymbol *)elsedecl->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - } - else - buf->writeByte(':'); - buf->writenl(); -} - -/***************************** StaticIfDeclaration ****************************/ - -StaticIfDeclaration::StaticIfDeclaration(Condition *condition, - Array *decl, Array *elsedecl) - : ConditionalDeclaration(condition, decl, elsedecl) -{ - //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); - sd = NULL; - addisdone = 0; -} - - -Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticIfDeclaration *dd; - - assert(!s); - dd = new StaticIfDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - /* This is deferred until semantic(), so that - * expressions in the condition can refer to declarations - * in the same scope, such as: - * - * template Foo(int i) - * { - * const int j = i + 1; - * static if (j == 3) - * const int k; - * } - */ - this->sd = sd; - int m = 0; - - if (memnum == 0) - { m = AttribDeclaration::addMember(sc, sd, memnum); - addisdone = 1; - } - return m; -} - - -void StaticIfDeclaration::semantic(Scope *sc) -{ - Array *d = include(sc, sd); - - //printf("\tStaticIfDeclaration::semantic '%s'\n",toChars()); - if (d) - { - if (!addisdone) - { AttribDeclaration::addMember(sc, sd, 1); - addisdone = 1; - } - - for (unsigned i = 0; i < d->dim; i++) - { - Dsymbol *s = (Dsymbol *)d->data[i]; - - s->semantic(sc); - } - } -} - -char *StaticIfDeclaration::kind() -{ - return "static if"; -} - - -/***************************** CompileDeclaration *****************************/ - -CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) - : AttribDeclaration(NULL) -{ - this->exp = exp; - this->sd = NULL; -} - -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) -{ - this->sd = sd; - return memnum; -} - -void CompileDeclaration::semantic(Scope *sc) -{ - //printf("CompileDeclaration::semantic()\n"); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op != TOKstring) - { error("argument to mixin must be a string, not (%s)", exp->toChars()); - return; - } - StringExp *se = (StringExp *)exp; - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - decl = p.parseDeclDefs(0); - if (p.token.value != TOKeof) - { - error("incomplete mixin declaration (%s)", se->toChars()); - } - - AttribDeclaration::addMember(sc, sd, 0); - AttribDeclaration::semantic(sc); -} - -void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - exp->toCBuffer(buf, hgs); - buf->writestring(");"); - buf->writenl(); -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include + +#if _WIN32 || IN_GCC || IN_LLVM +#include "mem.h" +#elif linux +#include "../root/mem.h" +#endif + +#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" + +#include "../gen/enums.h" +#include "../gen/logger.h" + +extern void obj_includelib(char *name); + + +/********************************* AttribDeclaration ****************************/ + +AttribDeclaration::AttribDeclaration(Array *decl) + : Dsymbol() +{ + this->decl = decl; +} + +Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) +{ + return decl; +} + +int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + unsigned i; + int m = 0; + Array *d = include(sc, sd); + + if (d) + { + for (i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + m |= s->addMember(sc, sd, m | memnum); + } + } + return m; +} + +void AttribDeclaration::semantic(Scope *sc) +{ + Array *d = include(sc, NULL); + + //printf("\tAttribDeclaration::semantic '%s'\n",toChars()); + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + + s->semantic(sc); + } + } +} + +void AttribDeclaration::semantic2(Scope *sc) +{ + unsigned i; + Array *d = include(sc, NULL); + + if (d) + { + for (i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + s->semantic2(sc); + } + } +} + +void AttribDeclaration::semantic3(Scope *sc) +{ + unsigned i; + Array *d = include(sc, NULL); + + if (d) + { + for (i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + s->semantic3(sc); + } + } +} + +void AttribDeclaration::inlineScan() +{ + unsigned i; + Array *d = include(NULL, NULL); + + if (d) + { + for (i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); + s->inlineScan(); + } + } +} + +void AttribDeclaration::addComment(unsigned char *comment) +{ + if (comment) + { + unsigned i; + Array *d = include(NULL, NULL); + + if (d) + { + for (i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::addComment %s\n", s->toChars()); + s->addComment(comment); + } + } + } +} + +void AttribDeclaration::emitComment(Scope *sc) +{ + //printf("AttribDeclaration::emitComment(sc = %p)\n", sc); + + /* If generating doc comment, skip this because if we're inside + * a template, then include(NULL, NULL) will fail. + */ +// if (sc->docbuf) +// return; + + unsigned i; + Array *d = include(NULL, NULL); + + if (d) + { + for (i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::emitComment %s\n", s->toChars()); + s->emitComment(sc); + } + } +} + +void AttribDeclaration::toObjFile() +{ + unsigned i; + Array *d = include(NULL, NULL); + + if (d) + { + for (i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + s->toObjFile(); + } + } +} + +int AttribDeclaration::cvMember(unsigned char *p) +{ + unsigned i; + int nwritten = 0; + int n; + Array *d = include(NULL, NULL); + + if (d) + { + for (i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + n = s->cvMember(p); + if (p) + p += n; + nwritten += n; + } + } + return nwritten; +} + +int AttribDeclaration::hasPointers() +{ + Array *d = include(NULL, NULL); + + if (d) + { + for (size_t i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + if (s->hasPointers()) + return 1; + } + } + return 0; +} + +char *AttribDeclaration::kind() +{ + return "attribute"; +} + +int AttribDeclaration::oneMember(Dsymbol **ps) +{ + Array *d = include(NULL, NULL); + + return Dsymbol::oneMembers(d, ps); +} + +void AttribDeclaration::checkCtorConstInit() +{ + unsigned i; + Array *d = include(NULL, NULL); + + if (d) + { + for (i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + s->checkCtorConstInit(); + } + } +} + +/**************************************** + */ + +void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) +{ unsigned i; + Array *d = include(NULL, NULL); + + if (d) + { + for (i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + s->addLocalClass(aclasses); + } + } +} + + +void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (decl) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writeByte('}'); + } + else + buf->writeByte(';'); + buf->writenl(); +} + +/************************* StorageClassDeclaration ****************************/ + +StorageClassDeclaration::StorageClassDeclaration(unsigned stc, Array *decl) + : AttribDeclaration(decl) +{ + this->stc = stc; +} + +Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) +{ + StorageClassDeclaration *scd; + + assert(!s); + scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); + return scd; +} + +void StorageClassDeclaration::semantic(Scope *sc) +{ + if (decl) + { unsigned stc_save = sc->stc; + + if (stc & (STCauto | STCscope | STCstatic | STCextern)) + sc->stc &= ~(STCauto | STCscope | STCstatic | STCextern); + sc->stc |= stc; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + } + sc->stc = stc_save; + } + else + sc->stc = stc; +} + +void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + struct SCstring + { + int stc; + enum TOK tok; + }; + + static SCstring table[] = + { + { STCauto, TOKauto }, + { STCscope, TOKscope }, + { STCstatic, TOKstatic }, + { STCextern, TOKextern }, + { STCconst, TOKconst }, + { STCfinal, TOKfinal }, + { STCabstract, TOKabstract }, + { STCsynchronized, TOKsynchronized }, + { STCdeprecated, TOKdeprecated }, + { STCoverride, TOKoverride }, + }; + + int written = 0; + for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) + { + if (stc & table[i].stc) + { + if (written) + buf->writeByte(' '); + written = 1; + buf->writestring(Token::toChars(table[i].tok)); + } + } + + AttribDeclaration::toCBuffer(buf, hgs); +} + +/********************************* LinkDeclaration ****************************/ + +LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl) + : AttribDeclaration(decl) +{ + //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); + linkage = p; +} + +Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s) +{ + LinkDeclaration *ld; + + assert(!s); + ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); + return ld; +} + +void LinkDeclaration::semantic(Scope *sc) +{ + //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { enum LINK linkage_save = sc->linkage; + + sc->linkage = linkage; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + } + sc->linkage = linkage_save; + } + else + { + sc->linkage = linkage; + } +} + +void LinkDeclaration::semantic3(Scope *sc) +{ + //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { enum LINK linkage_save = sc->linkage; + + sc->linkage = linkage; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic3(sc); + } + sc->linkage = linkage_save; + } + else + { + sc->linkage = linkage; + } +} + +void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ 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; + default: + assert(0); + break; + } + buf->writestring("extern ("); + buf->writestring(p); + buf->writestring(") "); + AttribDeclaration::toCBuffer(buf, hgs); +} + +char *LinkDeclaration::toChars() +{ + return "extern ()"; +} + +/********************************* ProtDeclaration ****************************/ + +ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl) + : AttribDeclaration(decl) +{ + protection = p; + //printf("decl = %p\n", decl); +} + +Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s) +{ + ProtDeclaration *pd; + + assert(!s); + pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl)); + return pd; +} + +void ProtDeclaration::semantic(Scope *sc) +{ + if (decl) + { enum PROT protection_save = sc->protection; + int explicitProtection_save = sc->explicitProtection; + + sc->protection = protection; + sc->explicitProtection = 1; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + } + sc->protection = protection_save; + sc->explicitProtection = explicitProtection_save; + } + else + { sc->protection = protection; + sc->explicitProtection = 1; + } +} + +void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ 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); + AttribDeclaration::toCBuffer(buf, hgs); +} + +/********************************* AlignDeclaration ****************************/ + +AlignDeclaration::AlignDeclaration(unsigned sa, Array *decl) + : AttribDeclaration(decl) +{ + salign = sa; +} + +Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s) +{ + AlignDeclaration *ad; + + assert(!s); + ad = new AlignDeclaration(salign, Dsymbol::arraySyntaxCopy(decl)); + return ad; +} + +void AlignDeclaration::semantic(Scope *sc) +{ + //printf("\tAlignDeclaration::semantic '%s'\n",toChars()); + if (decl) + { unsigned salign_save = sc->structalign; + + sc->structalign = salign; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + } + sc->structalign = salign_save; + } + else + sc->structalign = salign; +} + + +void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("align (%d)", salign); + AttribDeclaration::toCBuffer(buf, hgs); +} + +/********************************* AnonDeclaration ****************************/ + +AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl) + : AttribDeclaration(decl) +{ + this->loc = loc; + this->isunion = isunion; + this->scope = NULL; + this->sem = 0; +} + +Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s) +{ + AnonDeclaration *ad; + + assert(!s); + ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); + return ad; +} + +void AnonDeclaration::semantic(Scope *sc) +{ + //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; + scope = NULL; + } + + assert(sc->parent); + + Dsymbol *parent = sc->parent->pastMixin(); + AggregateDeclaration *ad = parent->isAggregateDeclaration(); + + if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration())) + { + error("can only be a part of an aggregate"); + return; + } + + if (decl) + { + AnonymousAggregateDeclaration aad; + int adisunion; + + if (sc->anonAgg) + { ad = sc->anonAgg; + adisunion = sc->inunion; + } + else + adisunion = ad->isUnionDeclaration() != NULL; + +// printf("\tsc->anonAgg = %p\n", sc->anonAgg); +// printf("\tad = %p\n", ad); +// printf("\taad = %p\n", &aad); + + sc = sc->push(); + sc->anonAgg = &aad; + sc->stc &= ~(STCauto | STCscope | STCstatic); + sc->inunion = isunion; + sc->offset = 0; + sc->flags = 0; + aad.structalign = sc->structalign; + aad.parent = ad; + + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + if (isunion) + sc->offset = 0; + if (aad.sizeok == 2) + { + break; + } + } + sc = sc->pop(); + + // If failed due to forward references, unwind and try again later + if (aad.sizeok == 2) + { + ad->sizeok = 2; + //printf("\tsetting ad->sizeok %p to 2\n", ad); + if (!sc->anonAgg) + { + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + } + //printf("\tforward reference %p\n", this); + return; + } + if (sem == 0) + { Module::dprogress++; + sem = 1; + //printf("\tcompleted %p\n", this); + } + else + ;//printf("\talready completed %p\n", this); + + // 0 sized structs are set to 1 byte + if (aad.structsize == 0) + { + aad.structsize = 1; + aad.alignsize = 1; + } + + // Align size of anonymous aggregate +//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset); + ad->alignmember(aad.structalign, aad.alignsize, &sc->offset); + //ad->structsize = sc->offset; +//printf("sc->offset = %d\n", sc->offset); + + // Add members of aad to ad + //printf("\tadding members of aad to '%s'\n", ad->toChars()); + for (unsigned i = 0; i < aad.fields.dim; i++) + { + VarDeclaration *v = (VarDeclaration *)aad.fields.data[i]; + + v->offset += sc->offset; + ad->fields.push(v); + } + + // Add size of aad to ad + if (adisunion) + { + if (aad.structsize > ad->structsize) + ad->structsize = aad.structsize; + sc->offset = 0; + } + else + { + ad->structsize = sc->offset + aad.structsize; + sc->offset = ad->structsize; + } + + if (ad->alignsize < aad.alignsize) + ad->alignsize = aad.alignsize; + } +} + + +void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf(isunion ? "union" : "struct"); + buf->writestring("\n{\n"); + if (decl) + { + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + //buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + } + buf->writestring("}\n"); +} + +char *AnonDeclaration::kind() +{ + return (char *)(isunion ? "anonymous union" : "anonymous struct"); +} + +/********************************* PragmaDeclaration ****************************/ + +PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl) + : AttribDeclaration(decl) +{ + this->loc = loc; + this->ident = ident; + this->args = args; +} + +Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) +{ + PragmaDeclaration *pd; + + assert(!s); + pd = new PragmaDeclaration(loc, ident, + Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl)); + return pd; +} + +void PragmaDeclaration::semantic(Scope *sc) +{ // Should be merged with PragmaStatement + +#if IN_LLVM + int llvm_internal = 0; + char* llvm_str1 = NULL; + +#endif + + //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); + if (ident == Id::msg) + { + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { + Expression *e = (Expression *)args->data[i]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKstring) + { + StringExp *se = (StringExp *)e; + fprintf(stdmsg, "%.*s", (int)se->len, se->string); + } + else + error("string expected for message, not '%s'", e->toChars()); + } + fprintf(stdmsg, "\n"); + } + goto Lnodecl; + } + else if (ident == Id::lib) + { + if (!args || args->dim != 1) + error("string expected for library name"); + else + { + Expression *e = (Expression *)args->data[0]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + if (e->op != TOKstring) + error("string expected for library name, not '%s'", e->toChars()); + else if (global.params.verbose) + { + StringExp *se = (StringExp *)e; + char *name = (char *)mem.malloc(se->len + 1); + memcpy(name, se->string, se->len); + name[se->len] = 0; + printf("library %s\n", name); + mem.free(name); + } + } + goto Lnodecl; + } +#if IN_GCC + else if (ident == Id::GNU_asm) + { + if (! args || args->dim != 2) + error("identifier and string expected for asm name"); + else + { + Expression *e; + Declaration *d = NULL; + StringExp *s = NULL; + + e = (Expression *)args->data[0]; + e = e->semantic(sc); + if (e->op == TOKvar) + { + d = ((VarExp *)e)->var; + if (! d->isFuncDeclaration() && ! d->isVarDeclaration()) + d = NULL; + } + if (!d) + error("first argument of GNU_asm must be a function or variable declaration"); + + e = (Expression *)args->data[1]; + e = e->semantic(sc); + e = e->optimize(WANTvalue); + if (e->op == TOKstring && ((StringExp *)e)->sz == 1) + s = ((StringExp *)e); + else + error("second argument of GNU_asm must be a char string"); + + if (d && s) + d->c_ident = Lexer::idPool((char*) s->string); + } + goto Lnodecl; + } +#endif +#if IN_LLVM + else if (ident == Id::LLVM_internal) + { + if (!args || args->dim < 1 || args->dim > 2) + error("needs 1-3 parameters"); + else if (!decl || decl->dim < 1) + error("must apply to at least one declaration"); + else + { + Expression *e; + StringExp *s = NULL; + + e = (Expression *)args->data[0]; + e = e->semantic(sc); + e = e->optimize(WANTvalue); + if (e->op == TOKstring && (s = (StringExp *)e)) + { + char* str = (char*)s->string; + if (strcmp(str,"intrinsic")==0) { + llvm_internal = LLVMintrinsic; + assert(args->dim == 2); + } + else if (strcmp(str,"va_start")==0) { + llvm_internal = LLVMva_start; + assert(args->dim == 1); + } + else if (strcmp(str,"va_arg")==0) { + llvm_internal = LLVMva_arg; + assert(args->dim == 1); + } + else if (strcmp(str,"va_intrinsic")==0) { + llvm_internal = LLVMva_intrinsic; + assert(args->dim == 2); + } + else if (strcmp(str,"notypeinfo")==0) { + llvm_internal = LLVMnotypeinfo; + assert(args->dim == 1); + } + else if (strcmp(str,"alloca")==0) { + llvm_internal = LLVMalloca; + assert(args->dim == 1); + } + else { + error("unknown pragma command: %s", str); + } + } + else + error("1st argument must be a string"); + + if (llvm_internal) + switch (llvm_internal) + { + case LLVMintrinsic: + case LLVMva_intrinsic: + e = (Expression *)args->data[1]; + e = e->semantic(sc); + e = e->optimize(WANTvalue); + if (e->op == TOKstring && (s = (StringExp *)e)) { + llvm_str1 = (char*)s->string; + } + else + error("2nd argument must be a string"); + break; + + case LLVMva_arg: + case LLVMva_start: + case LLVMnotypeinfo: + case LLVMalloca: + break; + + default: + assert(0); + } + } + } +#endif + else if (global.params.ignoreUnsupportedPragmas) + { + if (global.params.verbose) + { + /* Print unrecognized pragmas + */ + printf("pragma %s", ident->toChars()); + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { + Expression *e = (Expression *)args->data[i]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + if (i == 0) + printf(" ("); + else + printf(","); + printf("%s", e->toChars()); + } + if (args->dim) + printf(")"); + } + printf("\n"); + } + goto Lnodecl; + } + else + error("unrecognized pragma(%s)", ident->toChars()); + + if (decl) + { + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + +#if IN_LLVM + if (llvm_internal) + { + switch(llvm_internal) + { + case LLVMintrinsic: + case LLVMva_intrinsic: + if (FuncDeclaration* fd = s->isFuncDeclaration()) { + fd->llvmInternal = llvm_internal; + fd->llvmInternal1 = llvm_str1; + } + else { + error("may only be used on function declarations"); + assert(0); + } + break; + + case LLVMva_start: + case LLVMva_arg: + if (TemplateDeclaration* td = s->isTemplateDeclaration()) { + td->llvmInternal = llvm_internal; + assert(td->parameters->dim == 1); + assert(!td->overnext); + assert(!td->overroot); + assert(td->onemember); + Logger::println("template->onemember = %s", td->onemember->toChars()); + } + else { + error("can only be used on templates"); + assert(0); + } + break; + + case LLVMnotypeinfo: + s->llvmInternal = llvm_internal; + break; + + case LLVMalloca: + if (FuncDeclaration* fd = s->isFuncDeclaration()) { + fd->llvmInternal = llvm_internal; + } + else { + error("may only be used on function declarations"); + assert(0); + } + break; + + default: + assert(0 && "invalid LLVM_internal pragma got through :/"); + } + } + +#endif + } + } + return; + +Lnodecl: + if (decl) + error("pragma is missing closing ';'"); +} + +int PragmaDeclaration::oneMember(Dsymbol **ps) +{ + *ps = NULL; + return TRUE; +} + +char *PragmaDeclaration::kind() +{ + return "pragma"; +} + +void PragmaDeclaration::toObjFile() +{ + if (ident == Id::lib) + { + assert(args && args->dim == 1); + + Expression *e = (Expression *)args->data[0]; + + assert(e->op == TOKstring); + + StringExp *se = (StringExp *)e; + char *name = (char *)mem.malloc(se->len + 1); + memcpy(name, se->string, se->len); + name[se->len] = 0; + obj_includelib(name); + } + AttribDeclaration::toObjFile(); +} + +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->writestring(")"); + AttribDeclaration::toCBuffer(buf, hgs); +} + + +/********************************* ConditionalDeclaration ****************************/ + +ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl) + : AttribDeclaration(decl) +{ + //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); + this->condition = condition; + this->elsedecl = elsedecl; +} + +Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) +{ + ConditionalDeclaration *dd; + + assert(!s); + dd = new ConditionalDeclaration(condition->syntaxCopy(), + Dsymbol::arraySyntaxCopy(decl), + Dsymbol::arraySyntaxCopy(elsedecl)); + return dd; +} + + +int ConditionalDeclaration::oneMember(Dsymbol **ps) +{ + //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); + if (condition->inc) + { + Array *d = condition->include(NULL, NULL) ? decl : elsedecl; + return Dsymbol::oneMembers(d, ps); + } + *ps = NULL; + return TRUE; +} + +void ConditionalDeclaration::emitComment(Scope *sc) +{ + //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc); + if (condition->inc) + { + AttribDeclaration::emitComment(sc); + } +} + +// Decide if 'then' or 'else' code should be included + +Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) +{ + //printf("ConditionalDeclaration::include()\n"); + assert(condition); + return condition->include(sc, sd) ? decl : elsedecl; +} + + +void ConditionalDeclaration::addComment(unsigned char *comment) +{ + /* Because addComment is called by the parser, if we called + * include() it would define a version before it was used. + * But it's no problem to drill down to both decl and elsedecl, + * so that's the workaround. + */ + + if (comment) + { + Array *d = decl; + + for (int j = 0; j < 2; j++) + { + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); + s->addComment(comment); + } + } + d = elsedecl; + } + } +} + +void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + condition->toCBuffer(buf, hgs); + if (decl || elsedecl) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + if (decl) + { + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + } + buf->writeByte('}'); + if (elsedecl) + { + buf->writenl(); + buf->writestring("else"); + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (unsigned i = 0; i < elsedecl->dim; i++) + { + Dsymbol *s = (Dsymbol *)elsedecl->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writeByte('}'); + } + } + else + buf->writeByte(':'); + buf->writenl(); +} + +/***************************** StaticIfDeclaration ****************************/ + +StaticIfDeclaration::StaticIfDeclaration(Condition *condition, + Array *decl, Array *elsedecl) + : ConditionalDeclaration(condition, decl, elsedecl) +{ + //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); + sd = NULL; + addisdone = 0; +} + + +Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) +{ + StaticIfDeclaration *dd; + + assert(!s); + dd = new StaticIfDeclaration(condition->syntaxCopy(), + Dsymbol::arraySyntaxCopy(decl), + Dsymbol::arraySyntaxCopy(elsedecl)); + return dd; +} + + +int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + /* This is deferred until semantic(), so that + * expressions in the condition can refer to declarations + * in the same scope, such as: + * + * template Foo(int i) + * { + * const int j = i + 1; + * static if (j == 3) + * const int k; + * } + */ + this->sd = sd; + int m = 0; + + if (memnum == 0) + { m = AttribDeclaration::addMember(sc, sd, memnum); + addisdone = 1; + } + return m; +} + + +void StaticIfDeclaration::semantic(Scope *sc) +{ + Array *d = include(sc, sd); + + //printf("\tStaticIfDeclaration::semantic '%s'\n",toChars()); + if (d) + { + if (!addisdone) + { AttribDeclaration::addMember(sc, sd, 1); + addisdone = 1; + } + + for (unsigned i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + + s->semantic(sc); + } + } +} + +char *StaticIfDeclaration::kind() +{ + return "static if"; +} + + +/***************************** CompileDeclaration *****************************/ + +CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) + : AttribDeclaration(NULL) +{ + this->exp = exp; + this->sd = NULL; +} + +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) +{ + this->sd = sd; + return memnum; +} + +void CompileDeclaration::semantic(Scope *sc) +{ + //printf("CompileDeclaration::semantic()\n"); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp = exp->optimize(WANTvalue | WANTinterpret); + if (exp->op != TOKstring) + { error("argument to mixin must be a string, not (%s)", exp->toChars()); + return; + } + StringExp *se = (StringExp *)exp; + se = se->toUTF8(sc); + Parser p(sc->module, (unsigned char *)se->string, se->len, 0); + p.loc = loc; + p.nextToken(); + decl = p.parseDeclDefs(0); + if (p.token.value != TOKeof) + { + error("incomplete mixin declaration (%s)", se->toChars()); + } + + AttribDeclaration::addMember(sc, sd, 0); + AttribDeclaration::semantic(sc); +} + +void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("mixin("); + exp->toCBuffer(buf, hgs); + buf->writestring(");"); + buf->writenl(); +} diff --git a/dmd/cast.c b/dmd/cast.c index 120ecfeb..aa76b3ab 100644 --- a/dmd/cast.c +++ b/dmd/cast.c @@ -1,1454 +1,1455 @@ - -// 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 - -#if _WIN32 || IN_GCC || IN_LLVM -#include "mem.h" -#else -#include "../root/mem.h" -#endif - -#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)) - { - if (global.params.warnings && - Type::impcnvWarn[type->toBasetype()->ty][t->toBasetype()->ty] && - op != TOKint64) - { - Expression *e = optimize(WANTflags | WANTvalue); - - if (e->op == TOKint64) - return e->implicitCastTo(sc, t); - - fprintf(stdmsg, "warning - "); - error("implicit conversion of expression (%s) of type %s to %s can cause loss of data", - toChars(), type->toChars(), t->toChars()); - } - return castTo(sc, t); - } - - Expression *e = optimize(WANTflags | WANTvalue); - if (e != this) - return e->implicitCastTo(sc, t); - -#if 0 -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->next->arrayOf(), type, t); -fflush(stdout); -#endif - if (!t->deco) - { /* Can happen with: - * enum E { One } - * class A - * { static void fork(EDG dg) { dg(E.One); } - * alias void delegate(E) EDG; - * } - * Should eventually make it work. - */ - error("forward reference to type %s", t->toChars()); - } - else if (t->reliesOnTident()) - error("forward reference to type %s", t->reliesOnTident()->toChars()); - - error("cannot implicitly convert expression (%s) of type %s to %s", - toChars(), type->toChars(), t->toChars()); - return castTo(sc, t); -} - -/******************************************* - * 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 - 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->next; - - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) - { - match = type->implicitConvTo(tf->next); - if (match) - return match; - if (tf->next->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; - - 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: - case Tuns8: - //printf("value = %llu %llu\n", (integer_t)(unsigned char)value, value); - if ((unsigned char)value != value) - goto Lno; - goto Lyes; - - case Tint16: - if ((short)value != value) - goto Lno; - goto Lyes; - - case Tuns16: - if ((unsigned short)value != value) - goto Lno; - goto Lyes; - - case Tint32: - if (ty == Tuns32) - { - } - else if ((int)value != value) - goto Lno; - goto Lyes; - - case Tuns32: - if (ty == Tint32) - { - } - else if ((unsigned)value != value) - goto Lno; - goto Lyes; - - case Tdchar: - if (value > 0x10FFFFUL) - goto Lno; - goto Lyes; - - case Twchar: - if ((unsigned short)value != value) - goto Lno; - goto Lyes; - - case Tfloat32: - { - volatile float f; - if (type->isunsigned()) - { - f = (float)value; - if (f != value) - goto Lno; - } - else - { - f = (float)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tfloat64: - { - volatile double f; - if (type->isunsigned()) - { - f = (double)value; - if (f != value) - goto Lno; - } - else - { - f = (double)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tfloat80: - { - volatile long double f; - if (type->isunsigned()) - { - f = (long double)value; - if (f != value) - goto Lno; - } - else - { - f = (long double)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - } - 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)\n", - toChars(), type->toChars(), t->toChars()); -#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); -} - -MATCH StringExp::implicitConvTo(Type *t) -{ MATCH m; - -#if 0 - printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", - toChars(), committed, type->toChars(), t->toChars()); -#endif - if (!committed) - { - if (!committed && t->ty == Tpointer && t->next->ty == Tvoid) - { - return MATCHnomatch; - } - 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 (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; - - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if ((tb->ty == Tarray || tb->ty == Tsarray) && - (typeb->ty == Tarray || typeb->ty == Tsarray)) - { - if (tb->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)tb; - if (elements->dim != tsa->dim->toInteger()) - result = MATCHnomatch; - } - - for (int i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - MATCH m = (MATCH)e->implicitConvTo(tb->next); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - } - return result; - } - else - return Expression::implicitConvTo(t); -} - -MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) -{ MATCH result = MATCHexact; - - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if (tb->ty == Taarray && typeb->ty == Taarray) - { - for (size_t i = 0; i < keys->dim; i++) - { Expression *e = (Expression *)keys->data[i]; - MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->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->next); - 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)) - 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)) - 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. - FuncDeclaration *f; - - t = t->toBasetype(); - if (type->ty == Tdelegate && type->next->ty == Tfunction && - t->ty == Tdelegate && t->next->ty == Tfunction) - { - if (func && func->overloadExactMatch(t->next)) - 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 *RealExp::castTo(Scope *sc, Type *t) -{ Expression *e = this; - if (type != t) - { - if ((type->isreal() && t->isreal()) || - (type->isimaginary() && t->isimaginary()) - ) - { e = copy(); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - - -Expression *ComplexExp::castTo(Scope *sc, Type *t) -{ Expression *e = this; - if (type != t) - { - if (type->iscomplex() && t->iscomplex()) - { e = copy(); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - - -Expression *NullExp::castTo(Scope *sc, Type *t) -{ NullExp *e; - Type *tb; - - //printf("NullExp::castTo(t = %p)\n", t); - if (type == t) - { - committed = 1; - return this; - } - e = (NullExp *)copy(); - e->committed = 1; - tb = t->toBasetype(); - e->type = type->toBasetype(); - if (tb != e->type) - { - // NULL implicitly converts to any pointer type or dynamic array - if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid && - (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray || - tb->ty == Tdelegate)) - { -#if 0 - if (tb->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) - { - return Expression::castTo(sc, t); - } - } -#endif - } - else - { - return e->Expression::castTo(sc, t); - } - } - e->type = t; - return e; -} - -Expression *StringExp::castTo(Scope *sc, Type *t) -{ - /* This follows copy-on-write; any changes to 'this' - * will result in a copy. - * The this->string member is considered immutable. - */ - StringExp *se; - Type *tb; - int copied = 0; - - //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed); - - if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) - { - error("cannot convert string literal to void*"); - } - - se = this; - if (!committed) - { se = (StringExp *)copy(); - se->committed = 1; - copied = 1; - } - - if (type == t) - { - return se; - } - - tb = t->toBasetype(); - //printf("\ttype = %s\n", type->toChars()); - if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate) - return Expression::castTo(sc, t); - - Type *typeb = type->toBasetype(); - if (typeb == tb) - { - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - se->type = t; - return se; - } - - if (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; - 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; - 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; - 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; - char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); - if (p) - error("%s", p); - buffer.write4(c); - newlen++; - } - buffer.write4(0); - goto L1; - - case X(Tdchar,Tchar): - for (size_t u = 0; u < len; u++) - { - unsigned c = ((unsigned *)se->string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - buffer.writeUTF8(c); - newlen++; - } - newlen = buffer.offset; - buffer.writeUTF8(0); - goto L1; - - case X(Tdchar,Twchar): - for (size_t u = 0; u < len; u++) - { - unsigned c = ((unsigned *)se->string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - buffer.writeUTF16(c); - newlen++; - } - newlen = buffer.offset / 2; - buffer.writeUTF16(0); - goto L1; - - L1: - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - se->string = buffer.extractData(); - se->len = newlen; - se->sz = tb->nextOf()->size(); - break; - - default: - assert(typeb->nextOf()->size() != tb->nextOf()->size()); - goto Lcast; - } - } -#undef X -L2: - assert(copied); - - // See if need to truncate or extend the literal - if (tb->ty == Tsarray) - { - int dim2 = ((TypeSArray *)tb)->dim->toInteger(); - - //printf("dim from = %d, to = %d\n", se->len, dim2); - - // Changing dimensions - if (dim2 != se->len) - { - // Copy when changing the string literal - unsigned newsz = se->sz; - void *s; - int d; - - d = (dim2 < se->len) ? dim2 : se->len; - s = (unsigned char *)mem.malloc((dim2 + 1) * newsz); - memcpy(s, se->string, d * newsz); - // Extend with 0, add terminating 0 - memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz); - se->string = s; - se->len = dim2; - } - } - se->type = t; - return se; - -Lcast: - Expression *e = new CastExp(loc, se, t); - e->type = t; // so semantic() won't be run on e - return e; -} - -Expression *AddrExp::castTo(Scope *sc, Type *t) -{ - Type *tb; - -#if 0 - printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - Expression *e = this; - - tb = t->toBasetype(); - type = type->toBasetype(); - if (tb != type) - { - // Look for pointers to functions where the functions are overloaded. - 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); - 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, t=%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) && - tb->nextOf()->toBasetype()->ty != Tvoid) - { - if (tb->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)tb; - if (elements->dim != tsa->dim->toInteger()) - goto L1; - } - - e = (ArrayLiteralExp *)copy(); - e->elements = (Expressions *)elements->copy(); - for (int i = 0; i < elements->dim; i++) - { Expression *ex = (Expression *)elements->data[i]; - ex = ex->castTo(sc, tb->nextOf()); - e->elements->data[i] = (void *)ex; - } - e->type = t; - return e; - } - if (tb->ty == Tpointer && typeb->ty == Tsarray) - { - e = (ArrayLiteralExp *)copy(); - e->type = typeb->nextOf()->pointerTo(); - } -L1: - return e->Expression::castTo(sc, t); -} - -Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) -{ - if (type == t) - return this; - AssocArrayLiteralExp *e = this; - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if (tb->ty == Taarray && typeb->ty == Taarray && - tb->nextOf()->toBasetype()->ty != Tvoid) - { - e = (AssocArrayLiteralExp *)copy(); - e->keys = (Expressions *)keys->copy(); - e->values = (Expressions *)values->copy(); - assert(keys->dim == values->dim); - for (size_t i = 0; i < keys->dim; i++) - { Expression *ex = (Expression *)values->data[i]; - ex = ex->castTo(sc, tb->nextOf()); - e->values->data[i] = (void *)ex; - - ex = (Expression *)keys->data[i]; - ex = ex->castTo(sc, ((TypeAArray *)tb)->index); - e->keys->data[i] = (void *)ex; - } - e->type = t; - return e; - } -L1: - return e->Expression::castTo(sc, t); -} - - -Expression *SymOffExp::castTo(Scope *sc, Type *t) -{ - Type *tb; - -#if 0 - printf("SymOffExp::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. - FuncDeclaration *f; - - if (type->ty == Tpointer && type->next->ty == Tfunction && - tb->ty == Tpointer && tb->next->ty == Tfunction) - { - f = var->isFuncDeclaration(); - if (f) - { - f = f->overloadExactMatch(tb->next); - if (f) - { - e = new SymOffExp(loc, f, 0); - e->type = t; - return e; - } - } - } - e = Expression::castTo(sc, t); - } - e->type = t; - return e; -} - -Expression *DelegateExp::castTo(Scope *sc, Type *t) -{ - Type *tb; -#if 0 - printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - Expression *e = this; - static char msg[] = "cannot form delegate due to covariant return type"; - - tb = t->toBasetype(); - type = type->toBasetype(); - if (tb != type) - { - // 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); - 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->next->size(); - if (!t->equals(t2b)) - e2 = e2->castTo(sc, t); - // LLVMDC: 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->next->size(); - 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->next->ty == Tvoid) - { - goto Lx1; - } - else if ((t2->ty == Tsarray || t2->ty == Tarray) && - e1->op == TOKnull && t1->ty == Tpointer && t1->next->ty == Tvoid) - { - goto Lx2; - } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) - { - goto Lt2; - } - else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1)) - { - goto Lt1; - } - else if (t1->ty == Tclass || t2->ty == Tclass) - { int i1; - int i2; - - i1 = e2->implicitConvTo(t1); - 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 - 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->next->arrayOf())) - { - Lx1: - t = t1->next->arrayOf(); - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - } - else if (t1->ty == Tsarray && t2->ty == Tsarray && - e1->implicitConvTo(t2->next->arrayOf())) - { - Lx2: - t = t2->next->arrayOf(); - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - } - else - { - Lincompatible: - incompatibleTypes(); - } -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; - - e = this; - switch (type->toBasetype()->ty) - { - case Tvoid: - error("void has no value"); - break; - - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: - case Tbit: - case Tbool: - case Tchar: - case Twchar: - e = e->castTo(sc, Type::tint32); - break; - - case Tdchar: - e = e->castTo(sc, Type::tuns32); - break; - } - return e; -} - + +// 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 + +#if _WIN32 || IN_GCC || IN_LLVM +#include "mem.h" +#else +#include "../root/mem.h" +#endif + +#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)) + { + if (global.params.warnings && + Type::impcnvWarn[type->toBasetype()->ty][t->toBasetype()->ty] && + op != TOKint64) + { + Expression *e = optimize(WANTflags | WANTvalue); + + if (e->op == TOKint64) + return e->implicitCastTo(sc, t); + + fprintf(stdmsg, "warning - "); + error("implicit conversion of expression (%s) of type %s to %s can cause loss of data", + toChars(), type->toChars(), t->toChars()); + } + return castTo(sc, t); + } + + Expression *e = optimize(WANTflags | WANTvalue); + if (e != this) + return e->implicitCastTo(sc, t); + +#if 0 +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->next->arrayOf(), type, t); +fflush(stdout); +#endif + if (!t->deco) + { /* Can happen with: + * enum E { One } + * class A + * { static void fork(EDG dg) { dg(E.One); } + * alias void delegate(E) EDG; + * } + * Should eventually make it work. + */ + error("forward reference to type %s", t->toChars()); + } + else if (t->reliesOnTident()) + error("forward reference to type %s", t->reliesOnTident()->toChars()); + + error("cannot implicitly convert expression (%s) of type %s to %s", + toChars(), type->toChars(), t->toChars()); + return castTo(sc, t); +} + +/******************************************* + * 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 + 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->next; + + if (!tf->varargs && + !(tf->arguments && tf->arguments->dim) + ) + { + match = type->implicitConvTo(tf->next); + if (match) + return match; + if (tf->next->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; + + 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: + case Tuns8: + //printf("value = %llu %llu\n", (integer_t)(unsigned char)value, value); + if ((unsigned char)value != value) + goto Lno; + goto Lyes; + + case Tint16: + if ((short)value != value) + goto Lno; + goto Lyes; + + case Tuns16: + if ((unsigned short)value != value) + goto Lno; + goto Lyes; + + case Tint32: + if (ty == Tuns32) + { + } + else if ((int)value != value) + goto Lno; + goto Lyes; + + case Tuns32: + if (ty == Tint32) + { + } + else if ((unsigned)value != value) + goto Lno; + goto Lyes; + + case Tdchar: + if (value > 0x10FFFFUL) + goto Lno; + goto Lyes; + + case Twchar: + if ((unsigned short)value != value) + goto Lno; + goto Lyes; + + case Tfloat32: + { + volatile float f; + if (type->isunsigned()) + { + f = (float)value; + if (f != value) + goto Lno; + } + else + { + f = (float)(long long)value; + if (f != (long long)value) + goto Lno; + } + goto Lyes; + } + + case Tfloat64: + { + volatile double f; + if (type->isunsigned()) + { + f = (double)value; + if (f != value) + goto Lno; + } + else + { + f = (double)(long long)value; + if (f != (long long)value) + goto Lno; + } + goto Lyes; + } + + case Tfloat80: + { + volatile long double f; + if (type->isunsigned()) + { + f = (long double)value; + if (f != value) + goto Lno; + } + else + { + f = (long double)(long long)value; + if (f != (long long)value) + goto Lno; + } + goto Lyes; + } + } + 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)\n", + toChars(), type->toChars(), t->toChars()); +#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); +} + +MATCH StringExp::implicitConvTo(Type *t) +{ MATCH m; + +#if 0 + printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", + toChars(), committed, type->toChars(), t->toChars()); +#endif + if (!committed) + { + if (!committed && t->ty == Tpointer && t->next->ty == Tvoid) + { + return MATCHnomatch; + } + 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 (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; + + Type *typeb = type->toBasetype(); + Type *tb = t->toBasetype(); + if ((tb->ty == Tarray || tb->ty == Tsarray) && + (typeb->ty == Tarray || typeb->ty == Tsarray)) + { + if (tb->ty == Tsarray) + { TypeSArray *tsa = (TypeSArray *)tb; + if (elements->dim != tsa->dim->toInteger()) + result = MATCHnomatch; + } + + for (int i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + MATCH m = (MATCH)e->implicitConvTo(tb->next); + if (m < result) + result = m; // remember worst match + if (result == MATCHnomatch) + break; // no need to check for worse + } + return result; + } + else + return Expression::implicitConvTo(t); +} + +MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) +{ MATCH result = MATCHexact; + + Type *typeb = type->toBasetype(); + Type *tb = t->toBasetype(); + if (tb->ty == Taarray && typeb->ty == Taarray) + { + for (size_t i = 0; i < keys->dim; i++) + { Expression *e = (Expression *)keys->data[i]; + MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->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->next); + 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)) + 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)) + 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. + FuncDeclaration *f; + + t = t->toBasetype(); + if (type->ty == Tdelegate && type->next->ty == Tfunction && + t->ty == Tdelegate && t->next->ty == Tfunction) + { + if (func && func->overloadExactMatch(t->next)) + 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 *RealExp::castTo(Scope *sc, Type *t) +{ Expression *e = this; + if (type != t) + { + if ((type->isreal() && t->isreal()) || + (type->isimaginary() && t->isimaginary()) + ) + { e = copy(); + e->type = t; + } + else + e = Expression::castTo(sc, t); + } + return e; +} + + +Expression *ComplexExp::castTo(Scope *sc, Type *t) +{ Expression *e = this; + if (type != t) + { + if (type->iscomplex() && t->iscomplex()) + { e = copy(); + e->type = t; + } + else + e = Expression::castTo(sc, t); + } + return e; +} + + +Expression *NullExp::castTo(Scope *sc, Type *t) +{ NullExp *e; + Type *tb; + + //printf("NullExp::castTo(t = %p)\n", t); + if (type == t) + { + committed = 1; + return this; + } + e = (NullExp *)copy(); + e->committed = 1; + tb = t->toBasetype(); + e->type = type->toBasetype(); + if (tb != e->type) + { + // NULL implicitly converts to any pointer type or dynamic array + if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid && + (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray || + tb->ty == Tdelegate)) + { +#if 0 + if (tb->ty == Tdelegate) + { TypeDelegate *td = (TypeDelegate *)tb; + TypeFunction *tf = (TypeFunction *)td->nextOf(); + + if (!tf->varargs && + !(tf->arguments && tf->arguments->dim) + ) + { + return Expression::castTo(sc, t); + } + } +#endif + } + else + { + return e->Expression::castTo(sc, t); + } + } + e->type = t; + return e; +} + +Expression *StringExp::castTo(Scope *sc, Type *t) +{ + /* This follows copy-on-write; any changes to 'this' + * will result in a copy. + * The this->string member is considered immutable. + */ + StringExp *se; + Type *tb; + int copied = 0; + + //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed); + + if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) + { + error("cannot convert string literal to void*"); + } + + se = this; + if (!committed) + { se = (StringExp *)copy(); + se->committed = 1; + copied = 1; + } + + if (type == t) + { + return se; + } + + tb = t->toBasetype(); + //printf("\ttype = %s\n", type->toChars()); + if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate) + return Expression::castTo(sc, t); + + Type *typeb = type->toBasetype(); + if (typeb == tb) + { + if (!copied) + { se = (StringExp *)copy(); + copied = 1; + } + se->type = t; + return se; + } + + if (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; + 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; + 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; + 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; + char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); + if (p) + error("%s", p); + buffer.write4(c); + newlen++; + } + buffer.write4(0); + goto L1; + + case X(Tdchar,Tchar): + for (size_t u = 0; u < len; u++) + { + unsigned c = ((unsigned *)se->string)[u]; + if (!utf_isValidDchar(c)) + error("invalid UCS-32 char \\U%08x", c); + else + buffer.writeUTF8(c); + newlen++; + } + newlen = buffer.offset; + buffer.writeUTF8(0); + goto L1; + + case X(Tdchar,Twchar): + for (size_t u = 0; u < len; u++) + { + unsigned c = ((unsigned *)se->string)[u]; + if (!utf_isValidDchar(c)) + error("invalid UCS-32 char \\U%08x", c); + else + buffer.writeUTF16(c); + newlen++; + } + newlen = buffer.offset / 2; + buffer.writeUTF16(0); + goto L1; + + L1: + if (!copied) + { se = (StringExp *)copy(); + copied = 1; + } + se->string = buffer.extractData(); + se->len = newlen; + se->sz = tb->nextOf()->size(); + break; + + default: + assert(typeb->nextOf()->size() != tb->nextOf()->size()); + goto Lcast; + } + } +#undef X +L2: + assert(copied); + + // See if need to truncate or extend the literal + if (tb->ty == Tsarray) + { + int dim2 = ((TypeSArray *)tb)->dim->toInteger(); + + //printf("dim from = %d, to = %d\n", se->len, dim2); + + // Changing dimensions + if (dim2 != se->len) + { + // Copy when changing the string literal + unsigned newsz = se->sz; + void *s; + int d; + + d = (dim2 < se->len) ? dim2 : se->len; + s = (unsigned char *)mem.malloc((dim2 + 1) * newsz); + memcpy(s, se->string, d * newsz); + // Extend with 0, add terminating 0 + memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz); + se->string = s; + se->len = dim2; + } + } + se->type = t; + return se; + +Lcast: + Expression *e = new CastExp(loc, se, t); + e->type = t; // so semantic() won't be run on e + return e; +} + +Expression *AddrExp::castTo(Scope *sc, Type *t) +{ + Type *tb; + +#if 0 + printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + Expression *e = this; + + tb = t->toBasetype(); + type = type->toBasetype(); + if (tb != type) + { + // Look for pointers to functions where the functions are overloaded. + 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); + 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, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + if (type == t) + return this; + ArrayLiteralExp *e = this; + Type *typeb = type->toBasetype(); + Type *tb = t->toBasetype(); + if ((tb->ty == Tarray || tb->ty == Tsarray) && + (typeb->ty == Tarray || typeb->ty == Tsarray) && + // Not trying to convert non-void[] to void[] + !(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)) + { + if (tb->ty == Tsarray) + { TypeSArray *tsa = (TypeSArray *)tb; + if (elements->dim != tsa->dim->toInteger()) + goto L1; + } + + e = (ArrayLiteralExp *)copy(); + e->elements = (Expressions *)elements->copy(); + for (int i = 0; i < elements->dim; i++) + { Expression *ex = (Expression *)elements->data[i]; + ex = ex->castTo(sc, tb->nextOf()); + e->elements->data[i] = (void *)ex; + } + e->type = t; + return e; + } + if (tb->ty == Tpointer && typeb->ty == Tsarray) + { + e = (ArrayLiteralExp *)copy(); + e->type = typeb->nextOf()->pointerTo(); + } +L1: + return e->Expression::castTo(sc, t); +} + +Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) +{ + if (type == t) + return this; + AssocArrayLiteralExp *e = this; + Type *typeb = type->toBasetype(); + Type *tb = t->toBasetype(); + if (tb->ty == Taarray && typeb->ty == Taarray && + tb->nextOf()->toBasetype()->ty != Tvoid) + { + e = (AssocArrayLiteralExp *)copy(); + e->keys = (Expressions *)keys->copy(); + e->values = (Expressions *)values->copy(); + assert(keys->dim == values->dim); + for (size_t i = 0; i < keys->dim; i++) + { Expression *ex = (Expression *)values->data[i]; + ex = ex->castTo(sc, tb->nextOf()); + e->values->data[i] = (void *)ex; + + ex = (Expression *)keys->data[i]; + ex = ex->castTo(sc, ((TypeAArray *)tb)->index); + e->keys->data[i] = (void *)ex; + } + e->type = t; + return e; + } +L1: + return e->Expression::castTo(sc, t); +} + + +Expression *SymOffExp::castTo(Scope *sc, Type *t) +{ + Type *tb; + +#if 0 + printf("SymOffExp::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. + FuncDeclaration *f; + + if (type->ty == Tpointer && type->next->ty == Tfunction && + tb->ty == Tpointer && tb->next->ty == Tfunction) + { + f = var->isFuncDeclaration(); + if (f) + { + f = f->overloadExactMatch(tb->next); + if (f) + { + e = new SymOffExp(loc, f, 0); + e->type = t; + return e; + } + } + } + e = Expression::castTo(sc, t); + } + e->type = t; + return e; +} + +Expression *DelegateExp::castTo(Scope *sc, Type *t) +{ + Type *tb; +#if 0 + printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + Expression *e = this; + static char msg[] = "cannot form delegate due to covariant return type"; + + tb = t->toBasetype(); + type = type->toBasetype(); + if (tb != type) + { + // 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); + 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->next->size(); + if (!t->equals(t2b)) + e2 = e2->castTo(sc, t); + // LLVMDC: 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->next->size(); + 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->next->ty == Tvoid) + { + goto Lx1; + } + else if ((t2->ty == Tsarray || t2->ty == Tarray) && + e1->op == TOKnull && t1->ty == Tpointer && t1->next->ty == Tvoid) + { + goto Lx2; + } + else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) + { + goto Lt2; + } + else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1)) + { + goto Lt1; + } + else if (t1->ty == Tclass || t2->ty == Tclass) + { int i1; + int i2; + + i1 = e2->implicitConvTo(t1); + 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 + 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->next->arrayOf())) + { + Lx1: + t = t1->next->arrayOf(); + e1 = e1->castTo(sc, t); + e2 = e2->castTo(sc, t); + } + else if (t1->ty == Tsarray && t2->ty == Tsarray && + e1->implicitConvTo(t2->next->arrayOf())) + { + Lx2: + t = t2->next->arrayOf(); + e1 = e1->castTo(sc, t); + e2 = e2->castTo(sc, t); + } + else + { + Lincompatible: + incompatibleTypes(); + } +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; + + e = this; + switch (type->toBasetype()->ty) + { + case Tvoid: + error("void has no value"); + break; + + case Tint8: + case Tuns8: + case Tint16: + case Tuns16: + case Tbit: + case Tbool: + case Tchar: + case Twchar: + e = e->castTo(sc, Type::tint32); + break; + + case Tdchar: + e = e->castTo(sc, Type::tuns32); + break; + } + return e; +} + diff --git a/dmd/class.c b/dmd/class.c index f8c77d23..ab3cbdf0 100644 --- a/dmd/class.c +++ b/dmd/class.c @@ -1,1346 +1,1352 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "root.h" -#include "mem.h" - -#include "enum.h" -#include "init.h" -#include "attrib.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" -#include "mtype.h" -#include "scope.h" -#include "module.h" -#include "expression.h" -#include "statement.h" - -/********************************* ClassDeclaration ****************************/ - -ClassDeclaration *ClassDeclaration::classinfo; -ClassDeclaration *ClassDeclaration::object; - -ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) - : AggregateDeclaration(loc, id) -{ - static char msg[] = "only object.d can define this reserved class name"; - - if (baseclasses) - this->baseclasses = *baseclasses; - baseClass = NULL; - - interfaces_dim = 0; - interfaces = NULL; - - vtblInterfaces = NULL; - - //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses.dim); - - // For forward references - type = new TypeClass(this); - handle = type; - - ctor = NULL; - defaultCtor = NULL; - staticCtor = NULL; - staticDtor = NULL; - - vtblsym = NULL; - vclassinfo = NULL; - - if (id) - { // Look for special class names - - if (id == Id::__sizeof || id == Id::alignof || id == Id::mangleof) - error("illegal class name"); - - // BUG: What if this is the wrong TypeInfo, i.e. it is nested? - if (id->toChars()[0] == 'T') - { - if (id == Id::TypeInfo) - { if (Type::typeinfo) - Type::typeinfo->error("%s", msg); - Type::typeinfo = this; - } - - if (id == Id::TypeInfo_Class) - { if (Type::typeinfoclass) - Type::typeinfoclass->error("%s", msg); - Type::typeinfoclass = this; - } - - if (id == Id::TypeInfo_Interface) - { if (Type::typeinfointerface) - Type::typeinfointerface->error("%s", msg); - Type::typeinfointerface = this; - } - - if (id == Id::TypeInfo_Struct) - { if (Type::typeinfostruct) - Type::typeinfostruct->error("%s", msg); - Type::typeinfostruct = this; - } - - if (id == Id::TypeInfo_Typedef) - { if (Type::typeinfotypedef) - Type::typeinfotypedef->error("%s", msg); - Type::typeinfotypedef = this; - } - - if (id == Id::TypeInfo_Pointer) - { if (Type::typeinfopointer) - Type::typeinfopointer->error("%s", msg); - Type::typeinfopointer = this; - } - - if (id == Id::TypeInfo_Array) - { if (Type::typeinfoarray) - Type::typeinfoarray->error("%s", msg); - Type::typeinfoarray = this; - } - - if (id == Id::TypeInfo_StaticArray) - { //if (Type::typeinfostaticarray) - //Type::typeinfostaticarray->error("%s", msg); - Type::typeinfostaticarray = this; - } - - if (id == Id::TypeInfo_AssociativeArray) - { if (Type::typeinfoassociativearray) - Type::typeinfoassociativearray->error("%s", msg); - Type::typeinfoassociativearray = this; - } - - if (id == Id::TypeInfo_Enum) - { if (Type::typeinfoenum) - Type::typeinfoenum->error("%s", msg); - Type::typeinfoenum = this; - } - - if (id == Id::TypeInfo_Function) - { if (Type::typeinfofunction) - Type::typeinfofunction->error("%s", msg); - Type::typeinfofunction = this; - } - - if (id == Id::TypeInfo_Delegate) - { if (Type::typeinfodelegate) - Type::typeinfodelegate->error("%s", msg); - Type::typeinfodelegate = this; - } - - if (id == Id::TypeInfo_Tuple) - { if (Type::typeinfotypelist) - Type::typeinfotypelist->error("%s", msg); - Type::typeinfotypelist = this; - } - -#if V2 - 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; - } -#endif - } - - if (id == Id::Object) - { if (object) - object->error("%s", msg); - object = this; - } - - if (id == Id::ClassInfo) - { if (classinfo) - classinfo->error("%s", msg); - classinfo = this; - } - - if (id == Id::ModuleInfo) - { if (Module::moduleinfo) - Module::moduleinfo->error("%s", msg); - Module::moduleinfo = this; - } - } - - com = 0; - isauto = 0; - isabstract = 0; - isnested = 0; - vthis = NULL; -} - -Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) -{ - ClassDeclaration *cd; - - //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - cd = (ClassDeclaration *)s; - else - cd = new ClassDeclaration(loc, ident, NULL); - - cd->storage_class |= storage_class; - - cd->baseclasses.setDim(this->baseclasses.dim); - for (int i = 0; i < cd->baseclasses.dim; i++) - { - BaseClass *b = (BaseClass *)this->baseclasses.data[i]; - BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); - cd->baseclasses.data[i] = b2; - } - - ScopeDsymbol::syntaxCopy(cd); - return cd; -} - -void ClassDeclaration::semantic(Scope *sc) -{ int i; - unsigned offset; - - //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); - //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : ""); - //printf("sc->stc = %x\n", sc->stc); - - //{ static int n; if (++n == 20) *(char*)0=0; } - - if (!ident) // if anonymous class - { char *id = "__anonclass"; - - ident = Identifier::generateId(id); - } - - if (!scope) - { - if (!parent && sc->parent && !sc->parent->isModule()) - parent = sc->parent; - - type = type->semantic(loc, sc); - handle = handle->semantic(loc, sc); - } - if (!members) // if forward reference - { //printf("\tclass '%s' is forward referenced\n", toChars()); - return; - } - if (symtab) - { if (!scope) - { //printf("\tsemantic for '%s' is already completed\n", toChars()); - return; // semantic() already completed - } - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } -#ifdef IN_GCC - methods.setDim(0); -#endif - - if (sc->stc & STCdeprecated) - { //printf("test1: %s is deprecated\n", toChars()); - isdeprecated = 1; - } - - // Expand any tuples in baseclasses[] - for (i = 0; i < baseclasses.dim; ) - { BaseClass *b = (BaseClass *)baseclasses.data[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 = Argument::dim(tup->arguments); - for (size_t j = 0; j < dim; j++) - { Argument *arg = Argument::getNth(tup->arguments, j); - b = new BaseClass(arg->type, protection); - baseclasses.insert(i + j, b); - } - } - else - i++; - } - - // See if there's a base class as first in baseclasses[] - if (baseclasses.dim) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (BaseClass *)baseclasses.data[0]; - //b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty != Tclass) - { error("base type must be class or interface, not %s", b->type->toChars()); - baseclasses.remove(0); - } - else - { - tc = (TypeClass *)(tb); - if (tc->sym->isDeprecated()) - { - if (!isDeprecated()) - { - // Deriving from deprecated class makes this one deprecated too - isdeprecated = 1; - - tc->checkDeprecated(loc, sc); - } - } - - if (tc->sym->isInterfaceDeclaration()) - ; - else - { - for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass) - { - if (cdb == this) - { - error("circular inheritance"); - baseclasses.remove(0); - goto L7; - } - } - if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0) - { - //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(); - scope->module->addDeferredSemantic(this); - return; - } - else - { baseClass = tc->sym; - b->base = baseClass; - } - L7: ; - } - } - } - - // Treat the remaining entries in baseclasses as interfaces - // Check for errors, handle forward references - for (i = (baseClass ? 1 : 0); i < baseclasses.dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (BaseClass *)baseclasses.data[i]; - b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty == Tclass) - tc = (TypeClass *)tb; - else - tc = NULL; - if (!tc || !tc->sym->isInterfaceDeclaration()) - { - error("base type must be interface, not %s", b->type->toChars()); - baseclasses.remove(i); - continue; - } - else - { - if (tc->sym->isDeprecated()) - { - if (!isDeprecated()) - { - // Deriving from deprecated class makes this one deprecated too - isdeprecated = 1; - - tc->checkDeprecated(loc, sc); - } - } - - // Check for duplicate interfaces - for (size_t j = (baseClass ? 1 : 0); j < i; j++) - { - BaseClass *b2 = (BaseClass *)baseclasses.data[j]; - if (b2->base == tc->sym) - error("inherits from duplicate interface %s", b2->base->toChars()); - } - - 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(); - scope->module->addDeferredSemantic(this); - return; - } - } - i++; - } - - - // If no base class, and this is not an Object, use Object as base class - if (!baseClass && ident != Id::Object) - { - // BUG: what if Object is redefined in an inner scope? - Type *tbase = new TypeIdentifier(0, Id::Object); - BaseClass *b; - TypeClass *tc; - Type *bt; - - if (!object) - { - error("missing or corrupt object.d"); - fatal(); - } - bt = tbase->semantic(loc, sc)->toBasetype(); - b = new BaseClass(bt, PROTpublic); - baseclasses.shift(b); - assert(b->type->ty == Tclass); - tc = (TypeClass *)(b->type); - baseClass = tc->sym; - assert(!baseClass->isInterfaceDeclaration()); - b->base = baseClass; - } - - interfaces_dim = baseclasses.dim; - interfaces = (BaseClass **)baseclasses.data; - - - if (baseClass) - { - if (baseClass->storage_class & STCfinal) - error("cannot inherit from final class %s", baseClass->toChars()); - - interfaces_dim--; - interfaces++; - - // Copy vtbl[] from base class - vtbl.setDim(baseClass->vtbl.dim); - memcpy(vtbl.data, baseClass->vtbl.data, sizeof(void *) * vtbl.dim); - - // Inherit properties from base class - com = baseClass->isCOMclass(); - isauto = baseClass->isauto; - vthis = baseClass->vthis; - } - else - { - // No base class, so this is the root of the class hierarchy - vtbl.setDim(0); - vtbl.push(this); // leave room for classinfo as first member - } - - protection = sc->protection; - storage_class |= sc->stc; - - if (sizeok == 0) - { - interfaceSemantic(sc); - - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->addMember(sc, this, 1); - } - - /* If this is a nested class, add the hidden 'this' - * member which is a pointer to the enclosing scope. - */ - if (vthis) // if inheriting from nested class - { // Use the base class's 'this' member - isnested = 1; - if (storage_class & STCstatic) - error("static class cannot inherit from nested class %s", baseClass->toChars()); - if (toParent2() != baseClass->toParent2()) - error("super class %s is nested within %s, not %s", - baseClass->toChars(), - baseClass->toParent2()->toChars(), - toParent2()->toChars()); - } - else if (!(storage_class & STCstatic)) - { Dsymbol *s = toParent2(); - if (s) - { - ClassDeclaration *cd = s->isClassDeclaration(); - FuncDeclaration *fd = s->isFuncDeclaration(); - - - if (cd || fd) - { isnested = 1; - Type *t; - if (cd) - t = cd->type; - else if (fd) - { AggregateDeclaration *ad = fd->isMember2(); - if (ad) - t = ad->handle; - else - { - t = new TypePointer(Type::tvoid); - t = t->semantic(0, sc); - } - } - else - assert(0); - assert(!vthis); - vthis = new ThisDeclaration(t); - members->push(vthis); - } - } - } - } - - if (storage_class & (STCauto | STCscope)) - isauto = 1; - if (storage_class & STCabstract) - isabstract = 1; - - sc = sc->push(this); - sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | - STCabstract | STCdeprecated); - sc->parent = this; - sc->inunion = 0; - - if (isCOMclass()) - sc->linkage = LINKwindows; - sc->protection = PROTpublic; - sc->explicitProtection = 0; - sc->structalign = 8; - structalign = sc->structalign; - if (baseClass) - { sc->offset = baseClass->structsize; - alignsize = baseClass->alignsize; -// if (isnested) -// sc->offset += PTRSIZE; // room for uplevel context pointer - } - else - { sc->offset = 8; // allow room for vptr[] and monitor - alignsize = 4; - } - structsize = sc->offset; - Scope scsave = *sc; - int members_dim = members->dim; - sizeok = 0; - for (i = 0; i < members_dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic(sc); - } - - if (sizeok == 2) - { // semantic() failed because of forward references. - // Unwind what we did, and defer it for later - fields.setDim(0); - structsize = 0; - alignsize = 0; - structalign = 0; - - sc = sc->pop(); - - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - - //printf("\tsemantic('%s') failed\n", toChars()); - return; - } - - //printf("\tsemantic('%s') successful\n", toChars()); - - structsize = sc->offset; - //members->print(); - - /* Look for special member functions. - * They must be in this class, not in a base class. - */ - ctor = (CtorDeclaration *)search(0, Id::ctor, 0); - if (ctor && ctor->toParent() != this) - ctor = 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()); - ctor = new CtorDeclaration(0, 0, NULL, 0); - ctor->fbody = new CompoundStatement(0, new Statements()); - members->push(ctor); - ctor->addMember(sc, this, 1); - *sc = scsave; // why? What about sc->nofree? - sc->offset = structsize; - ctor->semantic(sc); - defaultCtor = ctor; - } - -#if 0 - if (baseClass) - { if (!aggDelete) - aggDelete = baseClass->aggDelete; - if (!aggNew) - aggNew = baseClass->aggNew; - } -#endif - - // Allocate instance of each new interface - for (i = 0; i < vtblInterfaces->dim; i++) - { - BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; - unsigned thissize = PTRSIZE; - - alignmember(structalign, thissize, &sc->offset); - assert(b->offset == 0); - b->offset = sc->offset; - - // Take care of single inheritance offsets - while (b->baseInterfaces_dim) - { - b = &b->baseInterfaces[0]; - b->offset = sc->offset; - } - - sc->offset += thissize; - if (alignsize < thissize) - alignsize = thissize; - } - structsize = sc->offset; - sizeok = 1; - Module::dprogress++; - - - sc->pop(); - -#if 0 // Do not call until toObjfile() because of forward references - // Fill in base class vtbl[]s - for (i = 0; i < vtblInterfaces->dim; i++) - { - BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; - - //b->fillVtbl(this, &b->vtbl, 1); - } -#endif - //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type); -} - -void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (!isAnonymous()) - { - buf->printf("%s ", kind()); - buf->writestring(toChars()); - if (baseclasses.dim) - buf->writestring(" : "); - } - for (int i = 0; i < baseclasses.dim; i++) - { - BaseClass *b = (BaseClass *)baseclasses.data[i]; - - if (i) - buf->writeByte(','); - //buf->writestring(b->base->ident->toChars()); - b->type->toCBuffer(buf, NULL, hgs); - } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writestring("}"); - buf->writenl(); -} - -#if 0 -void ClassDeclaration::defineRef(Dsymbol *s) -{ - ClassDeclaration *cd; - - AggregateDeclaration::defineRef(s); - cd = s->isClassDeclaration(); - baseType = cd->baseType; - cd->baseType = NULL; -} -#endif - -/********************************************* - * Determine if 'this' is a base class of cd. - * This is used to detect circular inheritance only. - */ - -int ClassDeclaration::isBaseOf2(ClassDeclaration *cd) -{ - if (!cd) - return 0; - //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); - for (int i = 0; i < cd->baseclasses.dim; i++) - { BaseClass *b = (BaseClass *)cd->baseclasses.data[i]; - - if (b->base == this || isBaseOf2(b->base)) - return 1; - } - return 0; -} - -/******************************************* - * Determine if 'this' is a base class of cd. - */ - -int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) -{ - //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); - if (poffset) - *poffset = 0; - while (cd) - { - if (this == cd->baseClass) - return 1; - - /* cd->baseClass might not be set if cd is forward referenced. - */ - if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration()) - { - cd->error("base class is forward referenced by %s", toChars()); - } - - cd = cd->baseClass; - } - return 0; -} - -Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) -{ - Dsymbol *s; - - //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); - if (scope) - semantic(scope); - - if (!members || !symtab || scope) - { error("is forward referenced when looking for '%s'", ident->toChars()); - //*(char*)0=0; - return NULL; - } - - s = ScopeDsymbol::search(loc, ident, flags); - if (!s) - { - // Search bases classes in depth-first, left to right order - - int i; - - for (i = 0; i < baseclasses.dim; i++) - { - BaseClass *b = (BaseClass *)baseclasses.data[i]; - - if (b->base) - { - if (!b->base->symtab) - error("base %s is forward referenced", b->base->ident->toChars()); - else - { - s = b->base->search(loc, ident, flags); - if (s == this) // happens if s is nested in this and derives from this - s = NULL; - else if (s) - break; - } - } - } - } - return s; -} - -/********************************************************** - * fd is in the vtbl[] for this class. - * Return 1 if function is hidden (not findable through search). - */ - -#if V2 -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(%s)\n", 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); - return !overloadApply(fdstart, &isf, fd); -} -#endif - -/**************** - * Find virtual function matching identifier and type. - * Used to build virtual function tables for interface implementations. - */ - -FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) -{ - //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars()); - - ClassDeclaration *cd = this; - Array *vtbl = &cd->vtbl; - while (1) - { - for (size_t i = 0; i < vtbl->dim; i++) - { - FuncDeclaration *fd = (FuncDeclaration *)vtbl->data[i]; - - //printf("\t[%d] = %s\n", i, fd->toChars()); - if (ident == fd->ident && - //tf->equals(fd->type) - fd->type->covariant(tf) == 1 - ) - { //printf("\t\tfound\n"); - return fd; - } - //else printf("\t\t%d\n", fd->type->covariant(tf)); - } - if (!cd) - break; - vtbl = &cd->vtblFinal; - cd = cd->baseClass; - } - - return NULL; -} - -void ClassDeclaration::interfaceSemantic(Scope *sc) -{ int i; - - vtblInterfaces = new BaseClasses(); - vtblInterfaces->reserve(interfaces_dim); - - for (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; -} - - -/**************************************** - */ - -int ClassDeclaration::isAbstract() -{ - if (isabstract) - return TRUE; - for (int i = 1; i < vtbl.dim; i++) - { - FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration(); - - //printf("\tvtbl[%d] = %p\n", i, fd); - if (!fd || fd->isAbstract()) - { - isabstract |= 1; - return TRUE; - } - } - return FALSE; -} - -/**************************************** - * 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; -} - -/**************************************** - */ - -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) -{ int i; - - //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); - if (!scope) - { type = type->semantic(loc, sc); - handle = handle->semantic(loc, sc); - } - if (!members) // if forward reference - { //printf("\tinterface '%s' is forward referenced\n", toChars()); - return; - } - if (symtab) // if already done - { if (!scope) - return; - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - if (sc->stc & STCdeprecated) - { - isdeprecated = 1; - } - - // Expand any tuples in baseclasses[] - for (i = 0; i < baseclasses.dim; ) - { BaseClass *b = (BaseClass *)baseclasses.data[0]; - b->type = b->type->semantic(loc, sc); - Type *tb = b->type->toBasetype(); - - if (tb->ty == Ttuple) - { TypeTuple *tup = (TypeTuple *)tb; - enum PROT protection = b->protection; - baseclasses.remove(i); - size_t dim = Argument::dim(tup->arguments); - for (size_t j = 0; j < dim; j++) - { Argument *arg = Argument::getNth(tup->arguments, j); - b = new BaseClass(arg->type, protection); - baseclasses.insert(i + j, b); - } - } - else - i++; - } - - // Check for errors, handle forward references - for (i = 0; i < baseclasses.dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (BaseClass *)baseclasses.data[i]; - b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty == Tclass) - tc = (TypeClass *)tb; - else - tc = NULL; - if (!tc || !tc->sym->isInterfaceDeclaration()) - { - error("base type must be interface, not %s", b->type->toChars()); - baseclasses.remove(i); - continue; - } - else - { - // Check for duplicate interfaces - for (size_t j = 0; j < i; j++) - { - BaseClass *b2 = (BaseClass *)baseclasses.data[j]; - if (b2->base == tc->sym) - error("inherits from duplicate interface %s", b2->base->toChars()); - } - - b->base = tc->sym; - if (b->base == this || isBaseOf2(b->base)) - { - error("circular inheritance of interface"); - baseclasses.remove(i); - continue; - } - if (!b->base->symtab || 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", b->base->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - return; - } - } - i++; - } - - interfaces_dim = baseclasses.dim; - interfaces = (BaseClass **)baseclasses.data; - - interfaceSemantic(sc); - - if (vtblOffset()) - vtbl.push(this); // leave room at vtbl[0] for classinfo - - // Cat together the vtbl[]'s from base interfaces - for (i = 0; i < interfaces_dim; i++) - { BaseClass *b = interfaces[i]; - - // Skip if b has already appeared - for (int k = 0; k < i; k++) - { - if (b == interfaces[i]) - goto Lcontinue; - } - - // Copy vtbl[] from base class - if (b->base->vtblOffset()) - { int d = b->base->vtbl.dim; - if (d > 1) - { - vtbl.reserve(d - 1); - for (int j = 1; j < d; j++) - vtbl.push(b->base->vtbl.data[j]); - } - } - else - { - vtbl.append(&b->base->vtbl); - } - - Lcontinue: - ; - } - - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->addMember(sc, this, 1); - } - - sc = sc->push(this); - sc->parent = this; - if (isCOMinterface()) - sc->linkage = LINKwindows; - sc->structalign = 8; - structalign = sc->structalign; - sc->offset = 8; - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic(sc); - } - //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; - } - return 1; - } - if (isBaseOf(b, poffset)) - { - return 1; - } - } - if (poffset) - *poffset = 0; - return 0; -} - -/**************************************** - * Determine if slot 0 of the vtbl[] is reserved for something else. - * For class objects, yes, this is where the ClassInfo ptr goes. - * For COM interfaces, no. - * For non-COM interfaces, yes, this is where the Interface ptr goes. - */ - -int InterfaceDeclaration::vtblOffset() -{ - if (isCOMinterface()) - return 0; - return 1; -} - -int InterfaceDeclaration::isCOMinterface() -{ - return com; -} - -/******************************************* - */ - -char *InterfaceDeclaration::kind() -{ - return "interface"; -} - - -/******************************** BaseClass *****************************/ - -BaseClass::BaseClass() -{ - memset(this, 0, sizeof(BaseClass)); -} - -BaseClass::BaseClass(Type *type, enum PROT protection) -{ - //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); - this->type = type; - this->protection = protection; - base = NULL; - offset = 0; - - baseInterfaces_dim = 0; - baseInterfaces = NULL; -} - -/**************************************** - * Fill in vtbl[] for base class based on member functions of class cd. - * Input: - * vtbl if !=NULL, fill it in - * newinstance !=0 means all entries must be filled in by members - * of cd, not members of any base classes of cd. - * Returns: - * !=0 if any entries were filled in by members of cd (not exclusively - * by base classes) - */ - -int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance) -{ - ClassDeclaration *id = base; - int j; - int result = 0; - - //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars()); - if (vtbl) - vtbl->setDim(base->vtbl.dim); - - // first entry is ClassInfo reference - for (j = base->vtblOffset(); j < base->vtbl.dim; j++) - { - FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration(); - FuncDeclaration *fd; - TypeFunction *tf; - - //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null"); - - assert(ifd); - // Find corresponding function in this class - tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL; - fd = cd->findFunc(ifd->ident, tf); - if (fd && !fd->isAbstract()) - { - //printf(" found\n"); - // Check that calling conventions match - if (fd->linkage != ifd->linkage) - fd->error("linkage doesn't match interface function"); - - // Check that it is current - if (newinstance && - fd->toParent() != cd && - ifd->toParent() == base) - cd->error("interface function %s.%s is not implemented", - id->toChars(), ifd->ident->toChars()); - - if (fd->toParent() == cd) - result = 1; - } - else - { - //printf(" not found\n"); - // BUG: should mark this class as abstract? - if (!cd->isAbstract()) - cd->error("interface function %s.%s isn't implemented", - id->toChars(), ifd->ident->toChars()); - fd = NULL; - } - if (vtbl) - vtbl->data[j] = fd; - } - - return result; -} - -void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces) -{ - //printf("+copyBaseInterfaces(), %s\n", base->toChars()); -// if (baseInterfaces_dim) -// return; - - baseInterfaces_dim = base->interfaces_dim; - baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass)); - - //printf("%s.copyBaseInterfaces()\n", base->toChars()); - for (int i = 0; i < baseInterfaces_dim; i++) - { - BaseClass *b = &baseInterfaces[i]; - BaseClass *b2 = base->interfaces[i]; - - assert(b2->vtbl.dim == 0); // should not be filled yet - memcpy(b, b2, sizeof(BaseClass)); - - if (i) // single inheritance is i==0 - vtblInterfaces->push(b); // only need for M.I. - b->copyBaseInterfaces(vtblInterfaces); - } - //printf("-copyBaseInterfaces\n"); -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include + +#include "root.h" +#include "mem.h" + +#include "enum.h" +#include "init.h" +#include "attrib.h" +#include "declaration.h" +#include "aggregate.h" +#include "id.h" +#include "mtype.h" +#include "scope.h" +#include "module.h" +#include "expression.h" +#include "statement.h" + +/********************************* ClassDeclaration ****************************/ + +ClassDeclaration *ClassDeclaration::classinfo; +ClassDeclaration *ClassDeclaration::object; + +ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) + : AggregateDeclaration(loc, id) +{ + static char msg[] = "only object.d can define this reserved class name"; + + if (baseclasses) + this->baseclasses = *baseclasses; + baseClass = NULL; + + interfaces_dim = 0; + interfaces = NULL; + + vtblInterfaces = NULL; + + //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses.dim); + + // For forward references + type = new TypeClass(this); + handle = type; + + ctor = NULL; + defaultCtor = NULL; + staticCtor = NULL; + staticDtor = NULL; + + vtblsym = NULL; + vclassinfo = NULL; + + if (id) + { // Look for special class names + + if (id == Id::__sizeof || id == Id::alignof || id == Id::mangleof) + error("illegal class name"); + + // BUG: What if this is the wrong TypeInfo, i.e. it is nested? + if (id->toChars()[0] == 'T') + { + if (id == Id::TypeInfo) + { if (Type::typeinfo) + Type::typeinfo->error("%s", msg); + Type::typeinfo = this; + } + + if (id == Id::TypeInfo_Class) + { if (Type::typeinfoclass) + Type::typeinfoclass->error("%s", msg); + Type::typeinfoclass = this; + } + + if (id == Id::TypeInfo_Interface) + { if (Type::typeinfointerface) + Type::typeinfointerface->error("%s", msg); + Type::typeinfointerface = this; + } + + if (id == Id::TypeInfo_Struct) + { if (Type::typeinfostruct) + Type::typeinfostruct->error("%s", msg); + Type::typeinfostruct = this; + } + + if (id == Id::TypeInfo_Typedef) + { if (Type::typeinfotypedef) + Type::typeinfotypedef->error("%s", msg); + Type::typeinfotypedef = this; + } + + if (id == Id::TypeInfo_Pointer) + { if (Type::typeinfopointer) + Type::typeinfopointer->error("%s", msg); + Type::typeinfopointer = this; + } + + if (id == Id::TypeInfo_Array) + { if (Type::typeinfoarray) + Type::typeinfoarray->error("%s", msg); + Type::typeinfoarray = this; + } + + if (id == Id::TypeInfo_StaticArray) + { //if (Type::typeinfostaticarray) + //Type::typeinfostaticarray->error("%s", msg); + Type::typeinfostaticarray = this; + } + + if (id == Id::TypeInfo_AssociativeArray) + { if (Type::typeinfoassociativearray) + Type::typeinfoassociativearray->error("%s", msg); + Type::typeinfoassociativearray = this; + } + + if (id == Id::TypeInfo_Enum) + { if (Type::typeinfoenum) + Type::typeinfoenum->error("%s", msg); + Type::typeinfoenum = this; + } + + if (id == Id::TypeInfo_Function) + { if (Type::typeinfofunction) + Type::typeinfofunction->error("%s", msg); + Type::typeinfofunction = this; + } + + if (id == Id::TypeInfo_Delegate) + { if (Type::typeinfodelegate) + Type::typeinfodelegate->error("%s", msg); + Type::typeinfodelegate = this; + } + + if (id == Id::TypeInfo_Tuple) + { if (Type::typeinfotypelist) + Type::typeinfotypelist->error("%s", msg); + Type::typeinfotypelist = this; + } + +#if V2 + 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; + } +#endif + } + + if (id == Id::Object) + { if (object) + object->error("%s", msg); + object = this; + } + + if (id == Id::ClassInfo) + { if (classinfo) + classinfo->error("%s", msg); + classinfo = this; + } + + if (id == Id::ModuleInfo) + { if (Module::moduleinfo) + Module::moduleinfo->error("%s", msg); + Module::moduleinfo = this; + } + } + + com = 0; + isauto = 0; + isabstract = 0; + 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 (int i = 0; i < cd->baseclasses.dim; i++) + { + BaseClass *b = (BaseClass *)this->baseclasses.data[i]; + BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); + cd->baseclasses.data[i] = b2; + } + + ScopeDsymbol::syntaxCopy(cd); + return cd; +} + +void ClassDeclaration::semantic(Scope *sc) +{ int i; + unsigned offset; + + //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); + //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : ""); + //printf("sc->stc = %x\n", sc->stc); + + //{ static int n; if (++n == 20) *(char*)0=0; } + + if (!ident) // if anonymous class + { char *id = "__anonclass"; + + ident = Identifier::generateId(id); + } + + if (!scope) + { + if (!parent && sc->parent && !sc->parent->isModule()) + parent = sc->parent; + + type = type->semantic(loc, sc); + handle = handle->semantic(loc, sc); + } + if (!members) // if forward reference + { //printf("\tclass '%s' is forward referenced\n", toChars()); + return; + } + if (symtab) + { if (!scope) + { //printf("\tsemantic for '%s' is already completed\n", toChars()); + return; // semantic() already completed + } + } + else + symtab = new DsymbolTable(); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; + } +#ifdef IN_GCC + methods.setDim(0); +#endif + + if (sc->stc & STCdeprecated) + { //printf("test1: %s is deprecated\n", toChars()); + isdeprecated = 1; + } + + // Expand any tuples in baseclasses[] + for (i = 0; i < baseclasses.dim; ) + { BaseClass *b = (BaseClass *)baseclasses.data[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 = Argument::dim(tup->arguments); + for (size_t j = 0; j < dim; j++) + { Argument *arg = Argument::getNth(tup->arguments, j); + b = new BaseClass(arg->type, protection); + baseclasses.insert(i + j, b); + } + } + else + i++; + } + + // See if there's a base class as first in baseclasses[] + if (baseclasses.dim) + { TypeClass *tc; + BaseClass *b; + Type *tb; + + b = (BaseClass *)baseclasses.data[0]; + //b->type = b->type->semantic(loc, sc); + tb = b->type->toBasetype(); + if (tb->ty != Tclass) + { error("base type must be class or interface, not %s", b->type->toChars()); + baseclasses.remove(0); + } + else + { + tc = (TypeClass *)(tb); + if (tc->sym->isDeprecated()) + { + if (!isDeprecated()) + { + // Deriving from deprecated class makes this one deprecated too + isdeprecated = 1; + + tc->checkDeprecated(loc, sc); + } + } + + if (tc->sym->isInterfaceDeclaration()) + ; + else + { + for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass) + { + if (cdb == this) + { + error("circular inheritance"); + baseclasses.remove(0); + goto L7; + } + } + if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0) + { + //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(); + scope->module->addDeferredSemantic(this); + return; + } + else + { baseClass = tc->sym; + b->base = baseClass; + } + L7: ; + } + } + } + + // Treat the remaining entries in baseclasses as interfaces + // Check for errors, handle forward references + for (i = (baseClass ? 1 : 0); i < baseclasses.dim; ) + { TypeClass *tc; + BaseClass *b; + Type *tb; + + b = (BaseClass *)baseclasses.data[i]; + b->type = b->type->semantic(loc, sc); + tb = b->type->toBasetype(); + if (tb->ty == Tclass) + tc = (TypeClass *)tb; + else + tc = NULL; + if (!tc || !tc->sym->isInterfaceDeclaration()) + { + error("base type must be interface, not %s", b->type->toChars()); + baseclasses.remove(i); + continue; + } + else + { + if (tc->sym->isDeprecated()) + { + if (!isDeprecated()) + { + // Deriving from deprecated class makes this one deprecated too + isdeprecated = 1; + + tc->checkDeprecated(loc, sc); + } + } + + // Check for duplicate interfaces + for (size_t j = (baseClass ? 1 : 0); j < i; j++) + { + BaseClass *b2 = (BaseClass *)baseclasses.data[j]; + if (b2->base == tc->sym) + error("inherits from duplicate interface %s", b2->base->toChars()); + } + + 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(); + scope->module->addDeferredSemantic(this); + return; + } + } + i++; + } + + + // If no base class, and this is not an Object, use Object as base class + if (!baseClass && ident != Id::Object) + { + // BUG: what if Object is redefined in an inner scope? + Type *tbase = new TypeIdentifier(0, Id::Object); + BaseClass *b; + TypeClass *tc; + Type *bt; + + if (!object) + { + error("missing or corrupt object.d"); + fatal(); + } + bt = tbase->semantic(loc, sc)->toBasetype(); + b = new BaseClass(bt, PROTpublic); + baseclasses.shift(b); + assert(b->type->ty == Tclass); + tc = (TypeClass *)(b->type); + baseClass = tc->sym; + assert(!baseClass->isInterfaceDeclaration()); + b->base = baseClass; + } + + interfaces_dim = baseclasses.dim; + interfaces = (BaseClass **)baseclasses.data; + + + if (baseClass) + { + if (baseClass->storage_class & STCfinal) + error("cannot inherit from final class %s", baseClass->toChars()); + + interfaces_dim--; + interfaces++; + + // Copy vtbl[] from base class + vtbl.setDim(baseClass->vtbl.dim); + memcpy(vtbl.data, baseClass->vtbl.data, sizeof(void *) * vtbl.dim); + + // Inherit properties from base class + com = baseClass->isCOMclass(); + isauto = baseClass->isauto; + vthis = baseClass->vthis; + } + else + { + // No base class, so this is the root of the class hierarchy + vtbl.setDim(0); + vtbl.push(this); // leave room for classinfo as first member + } + + protection = sc->protection; + storage_class |= sc->stc; + + if (sizeok == 0) + { + interfaceSemantic(sc); + + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->addMember(sc, this, 1); + } + + /* If this is a nested class, add the hidden 'this' + * member which is a pointer to the enclosing scope. + */ + if (vthis) // if inheriting from nested class + { // Use the base class's 'this' member + isnested = 1; + if (storage_class & STCstatic) + error("static class cannot inherit from nested class %s", baseClass->toChars()); + if (toParent2() != baseClass->toParent2()) + error("super class %s is nested within %s, not %s", + baseClass->toChars(), + baseClass->toParent2()->toChars(), + toParent2()->toChars()); + } + else if (!(storage_class & STCstatic)) + { Dsymbol *s = toParent2(); + if (s) + { + ClassDeclaration *cd = s->isClassDeclaration(); + FuncDeclaration *fd = s->isFuncDeclaration(); + + + if (cd || fd) + { isnested = 1; + Type *t; + if (cd) + t = cd->type; + else if (fd) + { AggregateDeclaration *ad = fd->isMember2(); + if (ad) + t = ad->handle; + else + { + t = new TypePointer(Type::tvoid); + t = t->semantic(0, sc); + } + } + else + assert(0); + assert(!vthis); + vthis = new ThisDeclaration(t); + members->push(vthis); + } + } + } + } + + if (storage_class & (STCauto | STCscope)) + isauto = 1; + if (storage_class & STCabstract) + isabstract = 1; + + sc = sc->push(this); + sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | + STCabstract | STCdeprecated); + sc->parent = this; + sc->inunion = 0; + + if (isCOMclass()) + sc->linkage = LINKwindows; + sc->protection = PROTpublic; + sc->explicitProtection = 0; + sc->structalign = 8; + structalign = sc->structalign; + if (baseClass) + { sc->offset = baseClass->structsize; + alignsize = baseClass->alignsize; +// if (isnested) +// sc->offset += PTRSIZE; // room for uplevel context pointer + } + else + { sc->offset = 8; // allow room for vptr[] and monitor + alignsize = 4; + } + structsize = sc->offset; + Scope scsave = *sc; + int members_dim = members->dim; + sizeok = 0; + for (i = 0; i < members_dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic(sc); + } + + if (sizeok == 2) + { // semantic() failed because of forward references. + // Unwind what we did, and defer it for later + fields.setDim(0); + structsize = 0; + alignsize = 0; + structalign = 0; + + sc = sc->pop(); + + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + + //printf("\tsemantic('%s') failed\n", toChars()); + return; + } + + //printf("\tsemantic('%s') successful\n", toChars()); + + structsize = sc->offset; + //members->print(); + + /* Look for special member functions. + * They must be in this class, not in a base class. + */ + ctor = (CtorDeclaration *)search(0, Id::ctor, 0); + if (ctor && ctor->toParent() != this) + ctor = 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()); + ctor = new CtorDeclaration(0, 0, NULL, 0); + ctor->fbody = new CompoundStatement(0, new Statements()); + members->push(ctor); + ctor->addMember(sc, this, 1); + *sc = scsave; // why? What about sc->nofree? + sc->offset = structsize; + ctor->semantic(sc); + defaultCtor = ctor; + } + +#if 0 + if (baseClass) + { if (!aggDelete) + aggDelete = baseClass->aggDelete; + if (!aggNew) + aggNew = baseClass->aggNew; + } +#endif + + // Allocate instance of each new interface + for (i = 0; i < vtblInterfaces->dim; i++) + { + BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; + unsigned thissize = PTRSIZE; + + alignmember(structalign, thissize, &sc->offset); + assert(b->offset == 0); + b->offset = sc->offset; + + // Take care of single inheritance offsets + while (b->baseInterfaces_dim) + { + b = &b->baseInterfaces[0]; + b->offset = sc->offset; + } + + sc->offset += thissize; + if (alignsize < thissize) + alignsize = thissize; + } + structsize = sc->offset; + sizeok = 1; + Module::dprogress++; + + dtor = buildDtor(sc); + + sc->pop(); + +#if 0 // Do not call until toObjfile() because of forward references + // Fill in base class vtbl[]s + for (i = 0; i < vtblInterfaces->dim; i++) + { + BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; + + //b->fillVtbl(this, &b->vtbl, 1); + } +#endif + //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type); +} + +void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (!isAnonymous()) + { + buf->printf("%s ", kind()); + buf->writestring(toChars()); + if (baseclasses.dim) + buf->writestring(" : "); + } + for (int i = 0; i < baseclasses.dim; i++) + { + BaseClass *b = (BaseClass *)baseclasses.data[i]; + + if (i) + buf->writeByte(','); + //buf->writestring(b->base->ident->toChars()); + b->type->toCBuffer(buf, NULL, hgs); + } + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writestring("}"); + buf->writenl(); +} + +#if 0 +void ClassDeclaration::defineRef(Dsymbol *s) +{ + ClassDeclaration *cd; + + AggregateDeclaration::defineRef(s); + cd = s->isClassDeclaration(); + baseType = cd->baseType; + cd->baseType = NULL; +} +#endif + +/********************************************* + * Determine if 'this' is a base class of cd. + * This is used to detect circular inheritance only. + */ + +int ClassDeclaration::isBaseOf2(ClassDeclaration *cd) +{ + if (!cd) + return 0; + //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); + for (int i = 0; i < cd->baseclasses.dim; i++) + { BaseClass *b = (BaseClass *)cd->baseclasses.data[i]; + + if (b->base == this || isBaseOf2(b->base)) + return 1; + } + return 0; +} + +/******************************************* + * Determine if 'this' is a base class of cd. + */ + +int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) +{ + //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); + if (poffset) + *poffset = 0; + while (cd) + { + if (this == cd->baseClass) + return 1; + + /* cd->baseClass might not be set if cd is forward referenced. + */ + if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration()) + { + cd->error("base class is forward referenced by %s", toChars()); + } + + cd = cd->baseClass; + } + return 0; +} + +Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) +{ + Dsymbol *s; + + //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); + if (scope) + semantic(scope); + + if (!members || !symtab || scope) + { error("is forward referenced when looking for '%s'", ident->toChars()); + //*(char*)0=0; + return NULL; + } + + s = ScopeDsymbol::search(loc, ident, flags); + if (!s) + { + // Search bases classes in depth-first, left to right order + + int i; + + for (i = 0; i < baseclasses.dim; i++) + { + BaseClass *b = (BaseClass *)baseclasses.data[i]; + + if (b->base) + { + if (!b->base->symtab) + error("base %s is forward referenced", b->base->ident->toChars()); + else + { + s = b->base->search(loc, ident, flags); + if (s == this) // happens if s is nested in this and derives from this + s = NULL; + else if (s) + break; + } + } + } + } + return s; +} + +/********************************************************** + * fd is in the vtbl[] for this class. + * Return 1 if function is hidden (not findable through search). + */ + +#if V2 +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(%s)\n", 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); + return !overloadApply(fdstart, &isf, fd); +} +#endif + +/**************** + * Find virtual function matching identifier and type. + * Used to build virtual function tables for interface implementations. + */ + +FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) +{ + //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars()); + + ClassDeclaration *cd = this; + Array *vtbl = &cd->vtbl; + while (1) + { + for (size_t i = 0; i < vtbl->dim; i++) + { + FuncDeclaration *fd = (FuncDeclaration *)vtbl->data[i]; + + //printf("\t[%d] = %s\n", i, fd->toChars()); + if (ident == fd->ident && + //tf->equals(fd->type) + fd->type->covariant(tf) == 1 + ) + { //printf("\t\tfound\n"); + return fd; + } + //else printf("\t\t%d\n", fd->type->covariant(tf)); + } + if (!cd) + break; + vtbl = &cd->vtblFinal; + cd = cd->baseClass; + } + + return NULL; +} + +void ClassDeclaration::interfaceSemantic(Scope *sc) +{ int i; + + vtblInterfaces = new BaseClasses(); + vtblInterfaces->reserve(interfaces_dim); + + for (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; +} + + +/**************************************** + */ + +int ClassDeclaration::isAbstract() +{ + if (isabstract) + return TRUE; + for (int i = 1; i < vtbl.dim; i++) + { + FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration(); + + //printf("\tvtbl[%d] = %p\n", i, fd); + if (!fd || fd->isAbstract()) + { + isabstract |= 1; + return TRUE; + } + } + return FALSE; +} + +/**************************************** + * 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; +} + +/**************************************** + */ + +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) +{ int i; + + //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); + if (inuse) + return; + if (!scope) + { type = type->semantic(loc, sc); + handle = handle->semantic(loc, sc); + } + if (!members) // if forward reference + { //printf("\tinterface '%s' is forward referenced\n", toChars()); + return; + } + if (symtab) // if already done + { if (!scope) + return; + } + else + symtab = new DsymbolTable(); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; + } + + if (sc->stc & STCdeprecated) + { + isdeprecated = 1; + } + + // Expand any tuples in baseclasses[] + for (i = 0; i < baseclasses.dim; ) + { BaseClass *b = (BaseClass *)baseclasses.data[0]; + b->type = b->type->semantic(loc, sc); + Type *tb = b->type->toBasetype(); + + if (tb->ty == Ttuple) + { TypeTuple *tup = (TypeTuple *)tb; + enum PROT protection = b->protection; + baseclasses.remove(i); + size_t dim = Argument::dim(tup->arguments); + for (size_t j = 0; j < dim; j++) + { Argument *arg = Argument::getNth(tup->arguments, j); + b = new BaseClass(arg->type, protection); + baseclasses.insert(i + j, b); + } + } + else + i++; + } + + // Check for errors, handle forward references + for (i = 0; i < baseclasses.dim; ) + { TypeClass *tc; + BaseClass *b; + Type *tb; + + b = (BaseClass *)baseclasses.data[i]; + b->type = b->type->semantic(loc, sc); + tb = b->type->toBasetype(); + if (tb->ty == Tclass) + tc = (TypeClass *)tb; + else + tc = NULL; + if (!tc || !tc->sym->isInterfaceDeclaration()) + { + error("base type must be interface, not %s", b->type->toChars()); + baseclasses.remove(i); + continue; + } + else + { + // Check for duplicate interfaces + for (size_t j = 0; j < i; j++) + { + BaseClass *b2 = (BaseClass *)baseclasses.data[j]; + if (b2->base == tc->sym) + error("inherits from duplicate interface %s", b2->base->toChars()); + } + + b->base = tc->sym; + if (b->base == this || isBaseOf2(b->base)) + { + error("circular inheritance of interface"); + baseclasses.remove(i); + continue; + } + if (!b->base->symtab || 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 = (BaseClass **)baseclasses.data; + + interfaceSemantic(sc); + + if (vtblOffset()) + vtbl.push(this); // leave room at vtbl[0] for classinfo + + // Cat together the vtbl[]'s from base interfaces + for (i = 0; i < interfaces_dim; i++) + { BaseClass *b = interfaces[i]; + + // Skip if b has already appeared + for (int k = 0; k < i; k++) + { + if (b == interfaces[i]) + goto Lcontinue; + } + + // Copy vtbl[] from base class + if (b->base->vtblOffset()) + { int d = b->base->vtbl.dim; + if (d > 1) + { + vtbl.reserve(d - 1); + for (int j = 1; j < d; j++) + vtbl.push(b->base->vtbl.data[j]); + } + } + else + { + vtbl.append(&b->base->vtbl); + } + + Lcontinue: + ; + } + + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->addMember(sc, this, 1); + } + + sc = sc->push(this); + sc->parent = this; + if (isCOMinterface()) + sc->linkage = LINKwindows; + sc->structalign = 8; + structalign = sc->structalign; + sc->offset = 8; + inuse++; + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic(sc); + } + inuse--; + //members->print(); + sc->pop(); + //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); +} + + +/******************************************* + * Determine if 'this' is a base class of cd. + * (Actually, if it is an interface supported by cd) + * Output: + * *poffset offset to start of class + * OFFSET_RUNTIME must determine offset at runtime + * Returns: + * 0 not a base + * 1 is a base + */ + +int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) +{ + unsigned j; + + //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars()); + assert(!baseClass); + for (j = 0; j < cd->interfaces_dim; j++) + { + BaseClass *b = cd->interfaces[j]; + + //printf("\tbase %s\n", b->base->toChars()); + if (this == b->base) + { + //printf("\tfound at offset %d\n", b->offset); + if (poffset) + { *poffset = b->offset; + if (j && cd->isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + } + return 1; + } + if (isBaseOf(b, poffset)) + { if (j && poffset && cd->isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + return 1; + } + } + + if (cd->baseClass && isBaseOf(cd->baseClass, poffset)) + return 1; + + if (poffset) + *poffset = 0; + return 0; +} + + +int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset) +{ + //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars()); + for (unsigned j = 0; j < bc->baseInterfaces_dim; j++) + { + BaseClass *b = &bc->baseInterfaces[j]; + + if (this == b->base) + { + if (poffset) + { *poffset = b->offset; + } + return 1; + } + if (isBaseOf(b, poffset)) + { + return 1; + } + } + if (poffset) + *poffset = 0; + return 0; +} + +/**************************************** + * Determine if slot 0 of the vtbl[] is reserved for something else. + * For class objects, yes, this is where the ClassInfo ptr goes. + * For COM interfaces, no. + * For non-COM interfaces, yes, this is where the Interface ptr goes. + */ + +int InterfaceDeclaration::vtblOffset() +{ + if (isCOMinterface()) + return 0; + return 1; +} + +int InterfaceDeclaration::isCOMinterface() +{ + return com; +} + +/******************************************* + */ + +char *InterfaceDeclaration::kind() +{ + return "interface"; +} + + +/******************************** BaseClass *****************************/ + +BaseClass::BaseClass() +{ + memset(this, 0, sizeof(BaseClass)); +} + +BaseClass::BaseClass(Type *type, enum PROT protection) +{ + //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); + this->type = type; + this->protection = protection; + base = NULL; + offset = 0; + + baseInterfaces_dim = 0; + baseInterfaces = NULL; +} + +/**************************************** + * Fill in vtbl[] for base class based on member functions of class cd. + * Input: + * vtbl if !=NULL, fill it in + * newinstance !=0 means all entries must be filled in by members + * of cd, not members of any base classes of cd. + * Returns: + * !=0 if any entries were filled in by members of cd (not exclusively + * by base classes) + */ + +int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance) +{ + ClassDeclaration *id = base; + int j; + int result = 0; + + //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars()); + if (vtbl) + vtbl->setDim(base->vtbl.dim); + + // first entry is ClassInfo reference + for (j = base->vtblOffset(); j < base->vtbl.dim; j++) + { + FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration(); + FuncDeclaration *fd; + TypeFunction *tf; + + //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null"); + + assert(ifd); + // Find corresponding function in this class + tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL; + fd = cd->findFunc(ifd->ident, tf); + if (fd && !fd->isAbstract()) + { + //printf(" found\n"); + // Check that calling conventions match + if (fd->linkage != ifd->linkage) + fd->error("linkage doesn't match interface function"); + + // Check that it is current + if (newinstance && + fd->toParent() != cd && + ifd->toParent() == base) + cd->error("interface function %s.%s is not implemented", + id->toChars(), ifd->ident->toChars()); + + if (fd->toParent() == cd) + result = 1; + } + else + { + //printf(" not found\n"); + // BUG: should mark this class as abstract? + if (!cd->isAbstract()) + cd->error("interface function %s.%s isn't implemented", + id->toChars(), ifd->ident->toChars()); + fd = NULL; + } + if (vtbl) + vtbl->data[j] = fd; + } + + return result; +} + +void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces) +{ + //printf("+copyBaseInterfaces(), %s\n", base->toChars()); +// if (baseInterfaces_dim) +// return; + + baseInterfaces_dim = base->interfaces_dim; + baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass)); + + //printf("%s.copyBaseInterfaces()\n", base->toChars()); + for (int i = 0; i < baseInterfaces_dim; i++) + { + BaseClass *b = &baseInterfaces[i]; + BaseClass *b2 = base->interfaces[i]; + + assert(b2->vtbl.dim == 0); // should not be filled yet + memcpy(b, b2, sizeof(BaseClass)); + + if (i) // single inheritance is i==0 + vtblInterfaces->push(b); // only need for M.I. + b->copyBaseInterfaces(vtblInterfaces); + } + //printf("-copyBaseInterfaces\n"); +} diff --git a/dmd/clone.c b/dmd/clone.c new file mode 100644 index 00000000..ef54c791 --- /dev/null +++ b/dmd/clone.c @@ -0,0 +1,175 @@ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include + +#include "root.h" +#include "aggregate.h" +#include "scope.h" +#include "mtype.h" +#include "declaration.h" +#include "module.h" +#include "id.h" +#include "expression.h" +#include "statement.h" + + +/********************************* + * Generate expression that calls opClone() + * for each member of the struct + * (can be NULL for members that don't need one) + */ + +#if V2 +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(); + size_t dim = 1; + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + dim *= ((TypeSArray *)tv)->dim->toInteger(); + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->opclone) + { Expression *ex; + + // this.v + 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 V2 + 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(); + size_t dim = 1; + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + dim *= ((TypeSArray *)tv)->dim->toInteger(); + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->dtor) + { Expression *ex; + + // this.v + ex = new ThisExp(0); + ex = new DotVarExp(0, ex, v, 0); + + if (dim == 1) + { // this.v.dtor() + ex = new DotVarExp(0, ex, sd->dtor, 0); + ex = new CallExp(0, ex); + } + else + { + // Typeinfo.destroy(cast(void*)&this.v); + Expression *ea = new AddrExp(0, ex); + ea = new CastExp(0, ea, Type::tvoid->pointerTo()); + 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(0, 0, Lexer::idPool("__fieldDtor")); + dd->fbody = new ExpStatement(0, e); + dtors.shift(dd); + members->push(dd); + dd->semantic(sc); + } +#endif + + switch (dtors.dim) + { + case 0: + return NULL; + + case 1: + return (FuncDeclaration *)dtors.data[0]; + + default: + e = NULL; + for (size_t i = 0; i < dtors.dim; i++) + { FuncDeclaration *fd = (FuncDeclaration *)dtors.data[i]; + Expression *ex = new ThisExp(0); + ex = new DotVarExp(0, ex, fd); + ex = new CallExp(0, ex); + e = Expression::combine(ex, e); + } + DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__aggrDtor")); + dd->fbody = new ExpStatement(0, e); + members->push(dd); + dd->semantic(sc); + return dd; + } +} + + diff --git a/dmd/declaration.c b/dmd/declaration.c index 8cdddcc8..f9c0ebbe 100644 --- a/dmd/declaration.c +++ b/dmd/declaration.c @@ -1,1308 +1,1318 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "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; -} - -void Declaration::semantic(Scope *sc) -{ -} - -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::isCodeseg() -{ - return FALSE; -} - -enum PROT Declaration::prot() -{ - return protection; -} - -/********************************* TupleDeclaration ****************************/ - -TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) - : Declaration(id) -{ - this->type = NULL; - this->objects = objects; - this->isexp = 0; - this->tupletype = NULL; -} - -Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); - return NULL; -} - -char *TupleDeclaration::kind() -{ - return "tuple"; -} - -Type *TupleDeclaration::getType() -{ - /* If this tuple represents a type, return that type - */ - - //printf("TupleDeclaration::getType() %s\n", toChars()); - if (isexp) - return NULL; - if (!tupletype) - { - /* It's only a type tuple if all the Object's are types - */ - for (size_t i = 0; i < objects->dim; i++) - { Object *o = (Object *)objects->data[i]; - - if (o->dyncast() != DYNCAST_TYPE) - { - //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); - return NULL; - } - } - - /* We know it's a type tuple, so build the TypeTuple - */ - Arguments *args = new Arguments(); - args->setDim(objects->dim); - OutBuffer buf; - for (size_t i = 0; i < objects->dim; i++) - { Type *t = (Type *)objects->data[i]; - - //printf("type = %s\n", t->toChars()); -#if 0 - buf.printf("_%s_%d", ident->toChars(), i); - char *name = (char *)buf.extractData(); - Identifier *id = new Identifier(name, TOKidentifier); - Argument *arg = new Argument(STCin, t, id, NULL); -#else - Argument *arg = new Argument(STCin, t, NULL, NULL); -#endif - args->data[i] = (void *)arg; - } - - tupletype = new TypeTuple(args); - } - - return tupletype; -} - -int TupleDeclaration::needThis() -{ - //printf("TupleDeclaration::needThis(%s)\n", toChars()); - for (size_t i = 0; i < objects->dim; i++) - { Object *o = (Object *)objects->data[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - if (e->op == TOKdsymbol) - { DsymbolExp *ve = (DsymbolExp *)e; - Declaration *d = ve->s->isDeclaration(); - if (d && d->needThis()) - { - return 1; - } - } - } - } - return 0; -} - -/********************************* TypedefDeclaration ****************************/ - -TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) - : Declaration(id) -{ - this->type = new TypeTypedef(this); - this->basetype = basetype->toBasetype(); - this->init = init; -#ifdef _DH - this->htype = NULL; - this->hbasetype = NULL; -#endif - this->sem = 0; - this->inuse = 0; - this->loc = loc; - this->sinit = NULL; -} - -Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) -{ - Type *basetype = this->basetype->syntaxCopy(); - - Initializer *init = NULL; - if (this->init) - init = this->init->syntaxCopy(); - - assert(!s); - TypedefDeclaration *st; - st = new TypedefDeclaration(loc, ident, basetype, init); -#ifdef _DH - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - st->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - st->htype = htype->syntaxCopy(); - if (!hbasetype) - { if (basetype) - { hbasetype = basetype->syntaxCopy(); - st->hbasetype = basetype->syntaxCopy(); - } - } - else - st->hbasetype = hbasetype->syntaxCopy(); -#endif - return st; -} - -void TypedefDeclaration::semantic(Scope *sc) -{ - //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); - if (sem == 0) - { sem = 1; - basetype = basetype->semantic(loc, sc); - sem = 2; - type = type->semantic(loc, sc); - if (sc->parent->isFuncDeclaration() && init) - semantic2(sc); - } - else if (sem == 1) - { - error("circular definition"); - } -} - -void TypedefDeclaration::semantic2(Scope *sc) -{ - //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); - if (sem == 2) - { sem = 3; - if (init) - { - init = init->semantic(sc, basetype); - - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - { - if (ie->exp->type == basetype) - ie->exp->type = type; - } - } - } -} - -char *TypedefDeclaration::kind() -{ - return "typedef"; -} - -Type *TypedefDeclaration::getType() -{ - return type; -} - -void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typedef "); - basetype->toCBuffer(buf, ident, hgs); - if (init) - { - buf->writestring(" = "); - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -/********************************* AliasDeclaration ****************************/ - -AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) - : Declaration(id) -{ - //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type); - //printf("type = '%s'\n", type->toChars()); - this->loc = loc; - this->type = type; - this->aliassym = NULL; -#ifdef _DH - this->htype = NULL; - this->haliassym = NULL; -#endif - this->overnext = NULL; - this->inSemantic = 0; - assert(type); -} - -AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) - : Declaration(id) -{ - //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s); - assert(s != this); - this->loc = loc; - this->type = NULL; - this->aliassym = s; -#ifdef _DH - this->htype = NULL; - this->haliassym = NULL; -#endif - this->overnext = NULL; - this->inSemantic = 0; - assert(s); -} - -Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - AliasDeclaration *sa; - if (type) - sa = new AliasDeclaration(loc, ident, type->syntaxCopy()); - else - sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); -#ifdef _DH - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sa->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sa->htype = htype->syntaxCopy(); - if (!haliassym) - { if (aliassym) - { haliassym = aliassym->syntaxCopy(s); - sa->haliassym = aliassym->syntaxCopy(s); - } - } - else - sa->haliassym = haliassym->syntaxCopy(s); -#endif - return sa; -} - -void AliasDeclaration::semantic(Scope *sc) -{ - //printf("AliasDeclaration::semantic() %s\n", toChars()); - if (aliassym) - { - if (aliassym->isTemplateInstance()) - aliassym->semantic(sc); - return; - } - this->inSemantic = 1; - - if (storage_class & STCconst) - error("cannot be const"); - - storage_class |= sc->stc & STCdeprecated; - - // Given: - // alias foo.bar.abc def; - // it is not knowable from the syntax whether this is an alias - // for a type or an alias for a symbol. It is up to the semantic() - // pass to distinguish. - // If it is a type, then type is set and getType() will return that - // type. If it is a symbol, then aliassym is set and type is NULL - - // toAlias() will return aliasssym. - - Dsymbol *s; - Type *t; - Expression *e; - - /* This section is needed because resolve() will: - * const x = 3; - * alias x y; - * try to alias y to 3. - */ - s = type->toDsymbol(sc); - if (s) - goto L2; // it's a symbolic alias - - //printf("alias type is %s\n", type->toChars()); - 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 - { error("cannot alias an expression %s", e->toChars()); - t = e->type; - } - } - else if (t) - type = t; - if (overnext) - ScopeDsymbol::multiplyDefined(0, this, overnext); - this->inSemantic = 0; - return; - - L2: - //printf("alias is a symbol %s %s\n", s->kind(), s->toChars()); - type = NULL; - VarDeclaration *v = s->isVarDeclaration(); - if (v && v->linkage == LINKdefault) - { - error("forward reference of %s", v->toChars()); - s = NULL; - } - else - { - FuncDeclaration *f = s->toAlias()->isFuncDeclaration(); - if (f) - { - if (overnext) - { - FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); - if (!fa->overloadInsert(overnext)) - ScopeDsymbol::multiplyDefined(0, f, overnext); - overnext = NULL; - s = fa; - s->parent = sc->parent; - } - } - if (overnext) - ScopeDsymbol::multiplyDefined(0, s, overnext); - if (s == this) - { - assert(global.errors); - s = NULL; - } - } - aliassym = s; - this->inSemantic = 0; -} - -int AliasDeclaration::overloadInsert(Dsymbol *s) -{ - /* Don't know yet what the aliased symbol is, so assume it can - * be overloaded and check later for correctness. - */ - - //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars()); - if (overnext == NULL) - { overnext = s; - return TRUE; - } - else - { - return overnext->overloadInsert(s); - } -} - -char *AliasDeclaration::kind() -{ - return "alias"; -} - -Type *AliasDeclaration::getType() -{ - return type; -} - -Dsymbol *AliasDeclaration::toAlias() -{ - //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : ""); - assert(this != aliassym); - //static int count; if (++count == 10) *(char*)0=0; - if (inSemantic) - { error("recursive alias declaration"); -// return this; - } - Dsymbol *s = aliassym ? aliassym->toAlias() : this; - return s; -} - -void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); -#if 0 && _DH - if (hgs->hdrgen) - { - if (haliassym) - { - haliassym->toCBuffer(buf, hgs); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - htype->toCBuffer(buf, ident, hgs); - } - else -#endif - { - if (aliassym) - { - aliassym->toCBuffer(buf, hgs); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - type->toCBuffer(buf, ident, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -/********************************* VarDeclaration ****************************/ - -VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init) - : Declaration(id) -{ - //printf("VarDeclaration('%s')\n", id->toChars()); -#ifdef DEBUG - if (!type && !init) - { printf("VarDeclaration('%s')\n", id->toChars()); - //*(char*)0=0; - } -#endif - assert(type || init); - this->type = type; - this->init = init; -#ifdef _DH - this->htype = NULL; - this->hinit = NULL; -#endif - this->loc = loc; - offset = 0; - noauto = 0; - nestedref = 0; - inuse = 0; - ctorinit = 0; - aliassym = NULL; - onstack = 0; - canassign = 0; - value = NULL; - - // LLVMDC - needsStorage = false; -} - -Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); - - VarDeclaration *sv; - if (s) - { sv = (VarDeclaration *)s; - } - else - { - Initializer *init = NULL; - if (this->init) - { init = this->init->syntaxCopy(); - //init->isExpInitializer()->exp->print(); - //init->isExpInitializer()->exp->dump(0); - } - - sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); - sv->storage_class = storage_class; - } -#ifdef _DH - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sv->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sv->htype = htype->syntaxCopy(); - if (!hinit) - { if (init) - { hinit = init->syntaxCopy(); - sv->hinit = init->syntaxCopy(); - } - } - else - sv->hinit = hinit->syntaxCopy(); -#endif - return sv; -} - -void VarDeclaration::semantic(Scope *sc) -{ - //printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); - //printf("type = %s\n", type->toChars()); - //printf("linkage = %d\n", sc->linkage); - //if (strcmp(toChars(), "mul") == 0) halt(); - - storage_class |= sc->stc; - if (storage_class & STCextern && init) - error("extern symbols cannot have initializers"); - - /* If auto type inference, do the inference - */ - int inferred = 0; - if (!type) - { inuse++; - type = init->inferType(sc); - inuse--; - inferred = 1; - - /* This is a kludge to support the existing syntax for RAII - * declarations. - */ - storage_class &= ~STCauto; - originalType = type; - } - else - { if (!originalType) - originalType = type; - type = type->semantic(loc, sc); - } - - 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\n", storage_class); - - Dsymbol *parent = toParent(); - FuncDeclaration *fd = parent->isFuncDeclaration(); - - Type *tb = type->toBasetype(); - if (tb->ty == Tvoid && !(storage_class & STClazy)) - { error("voids have no value"); - type = Type::terror; - tb = type; - } - if (tb->ty == Tfunction) - { error("cannot be declared to be a function"); - type = Type::terror; - tb = type; - } - if (tb->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tb; - - if (!ts->sym->members) - { - error("no definition of struct %s", ts->toChars()); - } - } - - if (tb->ty == Ttuple) - { /* Instead, declare variables for each of the tuple elements - * and add those. - */ - TypeTuple *tt = (TypeTuple *)tb; - size_t nelems = Argument::dim(tt->arguments); - Objects *exps = new Objects(); - exps->setDim(nelems); - - for (size_t i = 0; i < nelems; i++) - { Argument *arg = Argument::getNth(tt->arguments, i); - - OutBuffer buf; - buf.printf("_%s_field_%zu", ident->toChars(), i); - buf.writeByte(0); - char *name = (char *)buf.extractData(); - Identifier *id = new Identifier(name, TOKidentifier); - - VarDeclaration *v = new VarDeclaration(loc, arg->type, id, NULL); - //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); - v->semantic(sc); - - if (sc->scopesym) - { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); - if (sc->scopesym->members) - sc->scopesym->members->push(v); - } - - Expression *e = new DsymbolExp(loc, v); - exps->data[i] = e; - } - TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); - v2->isexp = 1; - aliassym = v2; - return; - } - - 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 - { - AggregateDeclaration *aad = sc->anonAgg; - if (!aad) - aad = parent->isAggregateDeclaration(); - if (aad) - { - aad->addField(sc, this); - } - - InterfaceDeclaration *id = parent->isInterfaceDeclaration(); - if (id) - { - error("field not allowed in interface"); - } - - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - AggregateDeclaration *ad = ti->tempdecl->isMember(); - if (ad && storage_class != STCundefined) - { - error("cannot use template to add field to aggregate '%s'", ad->toChars()); - } - } - } - - if (type->isauto() && !noauto) - { - if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd) - { - error("globals, statics, fields, ref and out parameters cannot be auto"); - } - - if (!(storage_class & (STCauto | STCscope))) - { - if (!(storage_class & STCparameter) && ident != Id::withSym) - error("reference to scope class must be scope"); - } - } - - 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->type = e1->type; - init = new ExpInitializer(loc, e/*->type->defaultInit()*/); - 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(); - } - } - - if (init) - { - ArrayInitializer *ai = init->isArrayInitializer(); - if (ai && tb->ty == Taarray) - { - init = ai->toAssocArrayInitializer(); - } - - StructInitializer *si = init->isStructInitializer(); - ExpInitializer *ei = init->isExpInitializer(); - - // See if we can allocate 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()) - { - Expression *e1; - Type *t; - int dim; - - //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); - if (!ei) - { - Expression *e = init->toExpression(); - if (!e) - { - init = init->semantic(sc, type); - e = init->toExpression(); - if (!e) - { error("is not a static and cannot have static initializer"); - return; - } - } - ei = new ExpInitializer(init->loc, e); - init = ei; - } - - e1 = new VarExp(loc, this); - - t = type->toBasetype(); - if (t->ty == Tsarray) - { - ei->exp = ei->exp->semantic(sc); - if (!ei->exp->implicitConvTo(type)) - { - dim = ((TypeSArray *)t)->dim->toInteger(); - // If multidimensional static array, treat as one large array - while (1) - { - t = t->nextOf()->toBasetype(); - if (t->ty != Tsarray) - break; - dim *= ((TypeSArray *)t)->dim->toInteger(); - e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); - } - } - e1 = new SliceExp(loc, e1, NULL, NULL); - } - else if (t->ty == Tstruct) - { - ei->exp = ei->exp->semantic(sc); - if (!ei->exp->implicitConvTo(type)) - ei->exp = new CastExp(loc, ei->exp, type); - } - 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); - if (fd && isConst() && !isStatic()) - { // Make it static - storage_class |= STCstatic; - } - } - } - else if (isConst() || isFinal()) - { - /* Because we may need the results of a const declaration in a - * subsequent type, such as an array dimension, before semantic2() - * gets ordinarily run, try to run semantic2() now. - * Ignore failure. - */ - - if (!global.errors && !inferred) - { - unsigned errors = global.errors; - global.gag++; - //printf("+gag\n"); - Expression *e; - Initializer *i2 = init; - inuse++; - if (ei) - { - e = ei->exp->syntaxCopy(); - e = e->semantic(sc); - e = e->implicitCastTo(sc, type); - } - else if (si || ai) - { i2 = init->syntaxCopy(); - i2 = i2->semantic(sc, type); - } - inuse--; - global.gag--; - //printf("-gag\n"); - if (errors != global.errors) // if errors happened - { - if (global.gag == 0) - global.errors = errors; // act as if nothing happened - } - else if (ei) - { - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKint64 || e->op == TOKstring) - { - ei->exp = e; // no errors, keep result - } - } - else - init = i2; // no errors, keep result - } - } - } -} - -ExpInitializer *VarDeclaration::getExpInitializer() -{ - ExpInitializer *ei; - - if (init) - ei = init->isExpInitializer(); - else - { - Expression *e = type->defaultInit(); - if (e) - ei = new ExpInitializer(loc, e); - else - ei = NULL; - } - return ei; -} - -void VarDeclaration::semantic2(Scope *sc) -{ - //printf("VarDeclaration::semantic2('%s')\n", toChars()); - if (init && !toParent()->isFuncDeclaration()) - { inuse++; -#if 0 - ExpInitializer *ei = init->isExpInitializer(); - if (ei) - { - ei->exp->dump(0); - printf("type = %p\n", ei->exp->type); - } -#endif - init = init->semantic(sc, type); - inuse--; - } -} - -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) -{ - if (storage_class & STCconst) - buf->writestring("const "); - if (storage_class & STCstatic) - buf->writestring("static "); - if (type) - type->toCBuffer(buf, ident, hgs); - else - buf->writestring(ident->toChars()); - if (init) - { buf->writestring(" = "); - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -int VarDeclaration::needThis() -{ - //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); - return storage_class & STCfield; -} - -int VarDeclaration::isImportedSymbol() -{ - if (protection == PROTexport && !init && (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 variable is a reference to an enclosing function - * or not. - */ - -void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) -{ - if (parent && !isDataseg() && parent != sc->parent) - { - FuncDeclaration *fdv = toParent()->isFuncDeclaration(); - FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); - - if (fdv && fdthis) - { - if (loc.filename) - fdthis->getLevel(loc, fdv); - nestedref = 1; - fdv->nestedFrameRef = 1; - fdv->nestedVars.insert(this); - //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); - } - } -} - -/******************************* - * Does symbol go into data segment? - */ - -int VarDeclaration::isDataseg() -{ -#if 0 - printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); - printf("%x, %p, %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance()); - printf("parent = '%s'\n", parent->toChars()); -#endif - 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()); -} - -int VarDeclaration::hasPointers() -{ - return (!isDataseg() && type->hasPointers()); -} - -/****************************************** - * If a variable has an auto destructor call, return call for it. - * Otherwise, return NULL. - */ - -Expression *VarDeclaration::callAutoDtor() -{ Expression *e = NULL; - - //printf("VarDeclaration::callAutoDtor() %s\n", toChars()); - if (storage_class & (STCauto | STCscope) && !noauto) - { - for (ClassDeclaration *cd = type->isClassHandle(); - cd; - cd = cd->baseClass) - { - /* We can do better if there's a way with onstack - * classes to determine if there's no way the monitor - * could be set. - */ - if (cd->isInterfaceDeclaration()) - error("interface %s cannot be scope", cd->toChars()); - if (1 || onstack || cd->dtors.dim) // if any destructors - { - // delete this; - Expression *ec; - - ec = new VarExp(loc, this); - e = new DeleteExp(loc, ec); - e->type = Type::tvoid; - break; - } - } - } - return e; -} - - -/********************************* ClassInfoDeclaration ****************************/ - -ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd) - : VarDeclaration(0, ClassDeclaration::classinfo->type, cd->ident, NULL) -{ - this->cd = cd; - storage_class = STCstatic; -} - -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); -} - -/***************************** TypeInfoConstDeclaration **********************/ - -#if V2 -TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoInvariantDeclaration **********************/ - -#if V2 -TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(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(Type *t) - : VarDeclaration(0, t, Id::This, NULL) -{ - noauto = 1; -} - -Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include + +#include "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; +} + +void Declaration::semantic(Scope *sc) +{ +} + +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::isCodeseg() +{ + return FALSE; +} + +enum PROT Declaration::prot() +{ + return protection; +} + +/********************************* TupleDeclaration ****************************/ + +TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) + : Declaration(id) +{ + this->type = NULL; + this->objects = objects; + this->isexp = 0; + this->tupletype = NULL; +} + +Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); + return NULL; +} + +char *TupleDeclaration::kind() +{ + return "tuple"; +} + +Type *TupleDeclaration::getType() +{ + /* If this tuple represents a type, return that type + */ + + //printf("TupleDeclaration::getType() %s\n", toChars()); + if (isexp) + return NULL; + if (!tupletype) + { + /* It's only a type tuple if all the Object's are types + */ + for (size_t i = 0; i < objects->dim; i++) + { Object *o = (Object *)objects->data[i]; + + if (o->dyncast() != DYNCAST_TYPE) + { + //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); + return NULL; + } + } + + /* We know it's a type tuple, so build the TypeTuple + */ + Arguments *args = new Arguments(); + args->setDim(objects->dim); + OutBuffer buf; + for (size_t i = 0; i < objects->dim; i++) + { Type *t = (Type *)objects->data[i]; + + //printf("type = %s\n", t->toChars()); +#if 0 + buf.printf("_%s_%d", ident->toChars(), i); + char *name = (char *)buf.extractData(); + Identifier *id = new Identifier(name, TOKidentifier); + Argument *arg = new Argument(STCin, t, id, NULL); +#else + Argument *arg = new Argument(STCin, t, NULL, NULL); +#endif + args->data[i] = (void *)arg; + } + + tupletype = new TypeTuple(args); + } + + return tupletype; +} + +int TupleDeclaration::needThis() +{ + //printf("TupleDeclaration::needThis(%s)\n", toChars()); + for (size_t i = 0; i < objects->dim; i++) + { Object *o = (Object *)objects->data[i]; + if (o->dyncast() == DYNCAST_EXPRESSION) + { Expression *e = (Expression *)o; + if (e->op == TOKdsymbol) + { DsymbolExp *ve = (DsymbolExp *)e; + Declaration *d = ve->s->isDeclaration(); + if (d && d->needThis()) + { + return 1; + } + } + } + } + return 0; +} + +/********************************* TypedefDeclaration ****************************/ + +TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) + : Declaration(id) +{ + this->type = new TypeTypedef(this); + this->basetype = basetype->toBasetype(); + this->init = init; +#ifdef _DH + this->htype = NULL; + this->hbasetype = NULL; +#endif + this->sem = 0; + this->inuse = 0; + this->loc = loc; + this->sinit = NULL; +} + +Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) +{ + Type *basetype = this->basetype->syntaxCopy(); + + Initializer *init = NULL; + if (this->init) + init = this->init->syntaxCopy(); + + assert(!s); + TypedefDeclaration *st; + st = new TypedefDeclaration(loc, ident, basetype, init); +#ifdef _DH + // Syntax copy for header file + if (!htype) // Don't overwrite original + { if (type) // Make copy for both old and new instances + { htype = type->syntaxCopy(); + st->htype = type->syntaxCopy(); + } + } + else // Make copy of original for new instance + st->htype = htype->syntaxCopy(); + if (!hbasetype) + { if (basetype) + { hbasetype = basetype->syntaxCopy(); + st->hbasetype = basetype->syntaxCopy(); + } + } + else + st->hbasetype = hbasetype->syntaxCopy(); +#endif + return st; +} + +void TypedefDeclaration::semantic(Scope *sc) +{ + //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); + if (sem == 0) + { sem = 1; + basetype = basetype->semantic(loc, sc); + sem = 2; + type = type->semantic(loc, sc); + if (sc->parent->isFuncDeclaration() && init) + semantic2(sc); + } + else if (sem == 1) + { + error("circular definition"); + } +} + +void TypedefDeclaration::semantic2(Scope *sc) +{ + //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); + if (sem == 2) + { sem = 3; + if (init) + { + init = init->semantic(sc, basetype); + + ExpInitializer *ie = init->isExpInitializer(); + if (ie) + { + if (ie->exp->type == basetype) + ie->exp->type = type; + } + } + } +} + +char *TypedefDeclaration::kind() +{ + return "typedef"; +} + +Type *TypedefDeclaration::getType() +{ + return type; +} + +void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("typedef "); + basetype->toCBuffer(buf, ident, hgs); + if (init) + { + buf->writestring(" = "); + init->toCBuffer(buf, hgs); + } + buf->writeByte(';'); + buf->writenl(); +} + +/********************************* AliasDeclaration ****************************/ + +AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) + : Declaration(id) +{ + //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type); + //printf("type = '%s'\n", type->toChars()); + this->loc = loc; + this->type = type; + this->aliassym = NULL; +#ifdef _DH + this->htype = NULL; + this->haliassym = NULL; +#endif + this->overnext = NULL; + this->inSemantic = 0; + assert(type); +} + +AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) + : Declaration(id) +{ + //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s); + assert(s != this); + this->loc = loc; + this->type = NULL; + this->aliassym = s; +#ifdef _DH + this->htype = NULL; + this->haliassym = NULL; +#endif + this->overnext = NULL; + this->inSemantic = 0; + assert(s); +} + +Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(!s); + AliasDeclaration *sa; + if (type) + sa = new AliasDeclaration(loc, ident, type->syntaxCopy()); + else + sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); +#ifdef _DH + // Syntax copy for header file + if (!htype) // Don't overwrite original + { if (type) // Make copy for both old and new instances + { htype = type->syntaxCopy(); + sa->htype = type->syntaxCopy(); + } + } + else // Make copy of original for new instance + sa->htype = htype->syntaxCopy(); + if (!haliassym) + { if (aliassym) + { haliassym = aliassym->syntaxCopy(s); + sa->haliassym = aliassym->syntaxCopy(s); + } + } + else + sa->haliassym = haliassym->syntaxCopy(s); +#endif + return sa; +} + +void AliasDeclaration::semantic(Scope *sc) +{ + //printf("AliasDeclaration::semantic() %s\n", toChars()); + if (aliassym) + { + if (aliassym->isTemplateInstance()) + aliassym->semantic(sc); + return; + } + this->inSemantic = 1; + + if (storage_class & STCconst) + error("cannot be const"); + + storage_class |= sc->stc & STCdeprecated; + + // Given: + // alias foo.bar.abc def; + // it is not knowable from the syntax whether this is an alias + // for a type or an alias for a symbol. It is up to the semantic() + // pass to distinguish. + // If it is a type, then type is set and getType() will return that + // type. If it is a symbol, then aliassym is set and type is NULL - + // toAlias() will return aliasssym. + + Dsymbol *s; + Type *t; + Expression *e; + + /* This section is needed because resolve() will: + * const x = 3; + * alias x y; + * try to alias y to 3. + */ + s = type->toDsymbol(sc); + if (s) + goto L2; // it's a symbolic alias + + //printf("alias type is %s\n", type->toChars()); + 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 + { error("cannot alias an expression %s", e->toChars()); + t = e->type; + } + } + else if (t) + type = t; + if (overnext) + ScopeDsymbol::multiplyDefined(0, this, overnext); + this->inSemantic = 0; + return; + + L2: + //printf("alias is a symbol %s %s\n", s->kind(), s->toChars()); + type = NULL; + VarDeclaration *v = s->isVarDeclaration(); + if (v && v->linkage == LINKdefault) + { + error("forward reference of %s", v->toChars()); + s = NULL; + } + else + { + FuncDeclaration *f = s->toAlias()->isFuncDeclaration(); + if (f) + { + if (overnext) + { + FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); + if (!fa->overloadInsert(overnext)) + ScopeDsymbol::multiplyDefined(0, f, overnext); + overnext = NULL; + s = fa; + s->parent = sc->parent; + } + } + if (overnext) + ScopeDsymbol::multiplyDefined(0, s, overnext); + if (s == this) + { + assert(global.errors); + s = NULL; + } + } + aliassym = s; + this->inSemantic = 0; +} + +int AliasDeclaration::overloadInsert(Dsymbol *s) +{ + /* Don't know yet what the aliased symbol is, so assume it can + * be overloaded and check later for correctness. + */ + + //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars()); + if (overnext == NULL) + { overnext = s; + return TRUE; + } + else + { + return overnext->overloadInsert(s); + } +} + +char *AliasDeclaration::kind() +{ + return "alias"; +} + +Type *AliasDeclaration::getType() +{ + return type; +} + +Dsymbol *AliasDeclaration::toAlias() +{ + //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : ""); + assert(this != aliassym); + //static int count; if (++count == 10) *(char*)0=0; + if (inSemantic) + { error("recursive alias declaration"); +// return this; + } + Dsymbol *s = aliassym ? aliassym->toAlias() : this; + return s; +} + +void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("alias "); +#if 0 && _DH + if (hgs->hdrgen) + { + if (haliassym) + { + haliassym->toCBuffer(buf, hgs); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + } + else + htype->toCBuffer(buf, ident, hgs); + } + else +#endif + { + if (aliassym) + { + aliassym->toCBuffer(buf, hgs); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + } + else + type->toCBuffer(buf, ident, hgs); + } + buf->writeByte(';'); + buf->writenl(); +} + +/********************************* VarDeclaration ****************************/ + +VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init) + : Declaration(id) +{ + //printf("VarDeclaration('%s')\n", id->toChars()); +#ifdef DEBUG + if (!type && !init) + { printf("VarDeclaration('%s')\n", id->toChars()); + //*(char*)0=0; + } +#endif + assert(type || init); + this->type = type; + this->init = init; +#ifdef _DH + this->htype = NULL; + this->hinit = NULL; +#endif + this->loc = loc; + offset = 0; + noauto = 0; + nestedref = 0; + inuse = 0; + ctorinit = 0; + aliassym = NULL; + onstack = 0; + canassign = 0; + value = NULL; + + // LLVMDC + needsStorage = false; +} + +Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); + + VarDeclaration *sv; + if (s) + { sv = (VarDeclaration *)s; + } + else + { + Initializer *init = NULL; + if (this->init) + { init = this->init->syntaxCopy(); + //init->isExpInitializer()->exp->print(); + //init->isExpInitializer()->exp->dump(0); + } + + sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); + sv->storage_class = storage_class; + } +#ifdef _DH + // Syntax copy for header file + if (!htype) // Don't overwrite original + { if (type) // Make copy for both old and new instances + { htype = type->syntaxCopy(); + sv->htype = type->syntaxCopy(); + } + } + else // Make copy of original for new instance + sv->htype = htype->syntaxCopy(); + if (!hinit) + { if (init) + { hinit = init->syntaxCopy(); + sv->hinit = init->syntaxCopy(); + } + } + else + sv->hinit = hinit->syntaxCopy(); +#endif + return sv; +} + +void VarDeclaration::semantic(Scope *sc) +{ + //printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); + //printf("type = %s\n", type->toChars()); + //printf("linkage = %d\n", sc->linkage); + //if (strcmp(toChars(), "mul") == 0) halt(); + + storage_class |= sc->stc; + if (storage_class & STCextern && init) + error("extern symbols cannot have initializers"); + + /* If auto type inference, do the inference + */ + int inferred = 0; + if (!type) + { inuse++; + type = init->inferType(sc); + inuse--; + inferred = 1; + + /* This is a kludge to support the existing syntax for RAII + * declarations. + */ + storage_class &= ~STCauto; + originalType = type; + } + else + { if (!originalType) + originalType = type; + type = type->semantic(loc, sc); + } + + 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\n", storage_class); + + Dsymbol *parent = toParent(); + FuncDeclaration *fd = parent->isFuncDeclaration(); + + Type *tb = type->toBasetype(); + if (tb->ty == Tvoid && !(storage_class & STClazy)) + { error("voids have no value"); + type = Type::terror; + tb = type; + } + if (tb->ty == Tfunction) + { error("cannot be declared to be a function"); + type = Type::terror; + tb = type; + } + if (tb->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tb; + + if (!ts->sym->members) + { + error("no definition of struct %s", ts->toChars()); + } + } + + if (tb->ty == Ttuple) + { /* Instead, declare variables for each of the tuple elements + * and add those. + */ + TypeTuple *tt = (TypeTuple *)tb; + size_t nelems = Argument::dim(tt->arguments); + Objects *exps = new Objects(); + exps->setDim(nelems); + Expression *ie = init ? init->toExpression() : NULL; + + for (size_t i = 0; i < nelems; i++) + { Argument *arg = Argument::getNth(tt->arguments, i); + + OutBuffer buf; + buf.printf("_%s_field_%zu", ident->toChars(), i); + buf.writeByte(0); + char *name = (char *)buf.extractData(); + Identifier *id = new Identifier(name, TOKidentifier); + + Expression *einit = ie; + if (ie && ie->op == TOKtuple) + { einit = (Expression *)((TupleExp *)ie)->exps->data[i]; + } + Initializer *ti = init; + if (einit) + { ti = new ExpInitializer(einit->loc, einit); + } + + VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); + //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); + v->semantic(sc); + + if (sc->scopesym) + { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); + if (sc->scopesym->members) + sc->scopesym->members->push(v); + } + + Expression *e = new DsymbolExp(loc, v); + exps->data[i] = e; + } + TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); + v2->isexp = 1; + aliassym = v2; + return; + } + + 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 + { + AggregateDeclaration *aad = sc->anonAgg; + if (!aad) + aad = parent->isAggregateDeclaration(); + if (aad) + { + aad->addField(sc, this); + } + + InterfaceDeclaration *id = parent->isInterfaceDeclaration(); + if (id) + { + error("field not allowed in interface"); + } + + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + { + // Take care of nested templates + while (1) + { + TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); + if (!ti2) + break; + ti = ti2; + } + + // If it's a member template + AggregateDeclaration *ad = ti->tempdecl->isMember(); + if (ad && storage_class != STCundefined) + { + error("cannot use template to add field to aggregate '%s'", ad->toChars()); + } + } + } + + if (type->isauto() && !noauto) + { + if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd) + { + error("globals, statics, fields, ref and out parameters cannot be auto"); + } + + if (!(storage_class & (STCauto | STCscope))) + { + if (!(storage_class & STCparameter) && ident != Id::withSym) + error("reference to scope class must be scope"); + } + } + + 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->type = e1->type; + init = new ExpInitializer(loc, e/*->type->defaultInit()*/); + 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(); + } + } + + if (init) + { + ArrayInitializer *ai = init->isArrayInitializer(); + if (ai && tb->ty == Taarray) + { + init = ai->toAssocArrayInitializer(); + } + + StructInitializer *si = init->isStructInitializer(); + ExpInitializer *ei = init->isExpInitializer(); + + // See if we can allocate 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()) + { + Expression *e1; + Type *t; + int dim; + + //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); + if (!ei) + { + Expression *e = init->toExpression(); + if (!e) + { + init = init->semantic(sc, type); + e = init->toExpression(); + if (!e) + { error("is not a static and cannot have static initializer"); + return; + } + } + ei = new ExpInitializer(init->loc, e); + init = ei; + } + + e1 = new VarExp(loc, this); + + t = type->toBasetype(); + if (t->ty == Tsarray) + { + ei->exp = ei->exp->semantic(sc); + if (!ei->exp->implicitConvTo(type)) + { + dim = ((TypeSArray *)t)->dim->toInteger(); + // If multidimensional static array, treat as one large array + while (1) + { + t = t->nextOf()->toBasetype(); + if (t->ty != Tsarray) + break; + dim *= ((TypeSArray *)t)->dim->toInteger(); + e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); + } + } + e1 = new SliceExp(loc, e1, NULL, NULL); + } + else if (t->ty == Tstruct) + { + ei->exp = ei->exp->semantic(sc); + if (!ei->exp->implicitConvTo(type)) + ei->exp = new CastExp(loc, ei->exp, type); + } + 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); + if (fd && isConst() && !isStatic()) + { // Make it static + storage_class |= STCstatic; + } + } + } + else if (isConst() || isFinal()) + { + /* Because we may need the results of a const declaration in a + * subsequent type, such as an array dimension, before semantic2() + * gets ordinarily run, try to run semantic2() now. + * Ignore failure. + */ + + if (!global.errors && !inferred) + { + unsigned errors = global.errors; + global.gag++; + //printf("+gag\n"); + Expression *e; + Initializer *i2 = init; + inuse++; + if (ei) + { + e = ei->exp->syntaxCopy(); + e = e->semantic(sc); + e = e->implicitCastTo(sc, type); + } + else if (si || ai) + { i2 = init->syntaxCopy(); + i2 = i2->semantic(sc, type); + } + inuse--; + global.gag--; + //printf("-gag\n"); + if (errors != global.errors) // if errors happened + { + if (global.gag == 0) + global.errors = errors; // act as if nothing happened + } + else if (ei) + { + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKint64 || e->op == TOKstring) + { + ei->exp = e; // no errors, keep result + } + } + else + init = i2; // no errors, keep result + } + } + } +} + +ExpInitializer *VarDeclaration::getExpInitializer() +{ + ExpInitializer *ei; + + if (init) + ei = init->isExpInitializer(); + else + { + Expression *e = type->defaultInit(); + if (e) + ei = new ExpInitializer(loc, e); + else + ei = NULL; + } + return ei; +} + +void VarDeclaration::semantic2(Scope *sc) +{ + //printf("VarDeclaration::semantic2('%s')\n", toChars()); + if (init && !toParent()->isFuncDeclaration()) + { inuse++; +#if 0 + ExpInitializer *ei = init->isExpInitializer(); + if (ei) + { + ei->exp->dump(0); + printf("type = %p\n", ei->exp->type); + } +#endif + init = init->semantic(sc, type); + inuse--; + } +} + +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) +{ + if (storage_class & STCconst) + buf->writestring("const "); + if (storage_class & STCstatic) + buf->writestring("static "); + if (type) + type->toCBuffer(buf, ident, hgs); + else + buf->writestring(ident->toChars()); + if (init) + { buf->writestring(" = "); + init->toCBuffer(buf, hgs); + } + buf->writeByte(';'); + buf->writenl(); +} + +int VarDeclaration::needThis() +{ + //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); + return storage_class & STCfield; +} + +int VarDeclaration::isImportedSymbol() +{ + if (protection == PROTexport && !init && (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 variable is a reference to an enclosing function + * or not. + */ + +void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) +{ + if (parent && !isDataseg() && parent != sc->parent) + { + FuncDeclaration *fdv = toParent()->isFuncDeclaration(); + FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); + + if (fdv && fdthis) + { + if (loc.filename) + fdthis->getLevel(loc, fdv); + nestedref = 1; + fdv->nestedFrameRef = 1; + fdv->nestedVars.insert(this); + //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); + } + } +} + +/******************************* + * Does symbol go into data segment? + */ + +int VarDeclaration::isDataseg() +{ +#if 0 + printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); + printf("%x, %p, %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance()); + printf("parent = '%s'\n", parent->toChars()); +#endif + 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()); +} + +int VarDeclaration::hasPointers() +{ + return (!isDataseg() && type->hasPointers()); +} + +/****************************************** + * If a variable has an auto destructor call, return call for it. + * Otherwise, return NULL. + */ + +Expression *VarDeclaration::callAutoDtor() +{ Expression *e = NULL; + + //printf("VarDeclaration::callAutoDtor() %s\n", toChars()); + if (storage_class & (STCauto | STCscope) && !noauto) + { + for (ClassDeclaration *cd = type->isClassHandle(); + cd; + cd = cd->baseClass) + { + /* We can do better if there's a way with onstack + * classes to determine if there's no way the monitor + * could be set. + */ + //if (cd->isInterfaceDeclaration()) + //error("interface %s cannot be scope", cd->toChars()); + if (1 || onstack || cd->dtors.dim) // if any destructors + { + // delete this; + Expression *ec; + + ec = new VarExp(loc, this); + e = new DeleteExp(loc, ec); + e->type = Type::tvoid; + break; + } + } + } + return e; +} + + +/********************************* ClassInfoDeclaration ****************************/ + +ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd) + : VarDeclaration(0, ClassDeclaration::classinfo->type, cd->ident, NULL) +{ + this->cd = cd; + storage_class = STCstatic; +} + +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); +} + +/***************************** TypeInfoConstDeclaration **********************/ + +#if V2 +TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} +#endif + +/***************************** TypeInfoInvariantDeclaration **********************/ + +#if V2 +TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(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(Type *t) + : VarDeclaration(0, t, Id::This, NULL) +{ + noauto = 1; +} + +Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + + diff --git a/dmd/declaration.h b/dmd/declaration.h index c30994f4..8b36061a 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -1,758 +1,770 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_DECLARATION_H -#define DMD_DECLARATION_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include - -#include "dsymbol.h" -#include "lexer.h" -#include "mtype.h" - -struct Expression; -struct Statement; -struct LabelDsymbol; -struct Initializer; -struct Module; -struct InlineScanState; -struct ForeachStatement; -struct FuncDeclaration; -struct ExpInitializer; -struct StructDeclaration; -struct TupleType; -struct InterState; - -enum PROT; -enum LINK; -enum TOK; -enum MATCH; - -enum STC -{ - STCundefined = 0, - STCstatic = 1, - STCextern = 2, - STCconst = 4, - STCfinal = 8, - STCabstract = 0x10, - STCparameter = 0x20, - STCfield = 0x40, - STCoverride = 0x80, - STCauto = 0x100, - STCsynchronized = 0x200, - STCdeprecated = 0x400, - STCin = 0x800, // in parameter - STCout = 0x1000, // out parameter - STClazy = 0x2000, // lazy parameter - STCforeach = 0x4000, // variable for foreach loop - STCcomdat = 0x8000, // should go into COMDAT record - STCvariadic = 0x10000, // variadic function argument - STCctorinit = 0x20000, // can only be set inside constructor - STCtemplateparameter = 0x40000, // template parameter - STCscope = 0x80000, // template parameter - STCinvariant = 0x100000, - STCref = 0x200000, -}; - -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, Expressions *arguments); -int overloadApply(FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param); - -/**************************************************************/ - -struct Declaration : Dsymbol -{ - Type *type; - Type *originalType; // before semantic analysis - unsigned storage_class; - enum PROT protection; - enum LINK linkage; - - Declaration(Identifier *id); - void semantic(Scope *sc); - char *kind(); - unsigned size(Loc loc); - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - char *mangle(); - int isStatic() { return storage_class & STCstatic; } - virtual int isStaticConstructor(); - virtual int isStaticDestructor(); - virtual int isDelete(); - virtual int isDataseg(); - virtual int isCodeseg(); - int isCtorinit() { return storage_class & STCctorinit; } - int isFinal() { return storage_class & STCfinal; } - int isAbstract() { return storage_class & STCabstract; } - int isConst() { return storage_class & STCconst; } - int isInvariant() { return 0; } - int isAuto() { return storage_class & STCauto; } - int isScope() { return storage_class & (STCscope | STCauto); } - int isSynchronized() { return storage_class & STCsynchronized; } - int isParameter() { return storage_class & STCparameter; } - int isDeprecated() { return storage_class & STCdeprecated; } - int isOverride() { return storage_class & STCoverride; } - - int isIn() { return storage_class & STCin; } - int isOut() { return storage_class & STCout; } - int isRef() { return storage_class & STCref; } - - enum PROT prot(); - - Declaration *isDeclaration() { return this; } - - virtual void toObjFile(); // compile to .obj file -}; - -/**************************************************************/ - -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 *); - char *kind(); - Type *getType(); - int needThis(); - - TupleDeclaration *isTupleDeclaration() { return this; } -}; - -/**************************************************************/ - -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 - int inuse; // used to detect typedef cycles - - TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - char *mangle(); - char *kind(); - Type *getType(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH - Type *htype; - Type *hbasetype; -#endif - - void toDocBuffer(OutBuffer *buf); - - void toObjFile(); // compile to .obj file - void toDebug(); - int cvMember(unsigned char *p); - - TypedefDeclaration *isTypedefDeclaration() { return this; } - - Symbol *sinit; - Symbol *toInitializer(); -}; - -/**************************************************************/ - -struct AliasDeclaration : Declaration -{ - Dsymbol *aliassym; - Dsymbol *overnext; // next in overload list - int inSemantic; - - 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); - char *kind(); - Type *getType(); - Dsymbol *toAlias(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH - Type *htype; - Dsymbol *haliassym; -#endif - - void toDocBuffer(OutBuffer *buf); - - AliasDeclaration *isAliasDeclaration() { return this; } -}; - -/**************************************************************/ - -struct VarDeclaration : Declaration -{ - Initializer *init; - unsigned offset; - int noauto; // no auto semantics - int nestedref; // referenced by a lexically nested function - int inuse; - int ctorinit; // it has been initialized in a ctor - int onstack; // 1: it has been allocated on the stack - // 2: on stack, run destructor anyway - int canassign; // it can be assigned to - Dsymbol *aliassym; // if redone as alias to another symbol - Expression *value; // when interpreting, this is the value - // (NULL if value not determinable) - - VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH - Type *htype; - Initializer *hinit; -#endif - int needThis(); - int isImportedSymbol(); - int isDataseg(); - int hasPointers(); - Expression *callAutoDtor(); - ExpInitializer *getExpInitializer(); - void checkCtorConstInit(); - void checkNestedReference(Scope *sc, Loc loc); - Dsymbol *toAlias(); - - Symbol *toSymbol(); - void toObjFile(); // compile to .obj file - int cvMember(unsigned char *p); - - // Eliminate need for dynamic_cast - VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } - - // LLVMDC - bool needsStorage; -}; - -/**************************************************************/ - -// This is a shell around a back end symbol - -struct SymbolDeclaration : Declaration -{ - Symbol *sym; - StructDeclaration *dsym; - - SymbolDeclaration(Loc loc, Symbol *s, StructDeclaration *dsym); - - Symbol *toSymbol(); - - // Eliminate need for dynamic_cast - SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; } -}; - -struct ClassInfoDeclaration : VarDeclaration -{ - ClassDeclaration *cd; - - ClassInfoDeclaration(ClassDeclaration *cd); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - - Symbol *toSymbol(); - - ClassInfoDeclaration* isClassInfoDeclaration() { return this; } -}; - -struct ModuleInfoDeclaration : VarDeclaration -{ - Module *mod; - - ModuleInfoDeclaration(Module *mod); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - - Symbol *toSymbol(); -}; - -struct TypeInfoDeclaration : VarDeclaration -{ - Type *tinfo; - - TypeInfoDeclaration(Type *tinfo, int internal); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - - Symbol *toSymbol(); - void toObjFile(); // compile to .obj file - virtual void toDt(dt_t **pdt); - - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } - - // LLVMDC - virtual void llvmDeclare(); - virtual void llvmDefine(); -}; - -struct TypeInfoStructDeclaration : TypeInfoDeclaration -{ - TypeInfoStructDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LLVMDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoClassDeclaration : TypeInfoDeclaration -{ - TypeInfoClassDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LLVMDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration -{ - TypeInfoInterfaceDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LLVMDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoTypedefDeclaration : TypeInfoDeclaration -{ - TypeInfoTypedefDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LLVMDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoPointerDeclaration : TypeInfoDeclaration -{ - TypeInfoPointerDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LLVMDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoArrayDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LLVMDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoStaticArrayDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LLVMDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoAssociativeArrayDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LLVMDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoEnumDeclaration : TypeInfoDeclaration -{ - TypeInfoEnumDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LLVMDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoFunctionDeclaration : TypeInfoDeclaration -{ - TypeInfoFunctionDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LLVMDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoDelegateDeclaration : TypeInfoDeclaration -{ - TypeInfoDelegateDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LLVMDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoTupleDeclaration : TypeInfoDeclaration -{ - TypeInfoTupleDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LLVMDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct ThisDeclaration : VarDeclaration -{ - ThisDeclaration(Type *t); - Dsymbol *syntaxCopy(Dsymbol *); -}; - -enum ILS -{ - ILSuninitialized, // not computed yet - ILSno, // cannot inline - ILSyes, // can inline -}; - -/**************************************************************/ - -#if V2 - -enum BUILTIN -{ - BUILTINunknown = -1, // not known if this is a builtin - BUILTINnot, // this is not a builtin - BUILTINsin, // std.math.sin - BUILTINcos, // std.math.cos - BUILTINtan, // std.math.tan - BUILTINsqrt, // std.math.sqrt - BUILTINfabs, // std.math.fabs -}; - -Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments); - -#endif - -struct FuncDeclaration : Declaration -{ - Array *fthrows; // Array of Type's of exceptions (not used) - Statement *frequire; - Statement *fensure; - Statement *fbody; - - Identifier *outId; // identifier for out statement - VarDeclaration *vresult; // variable corresponding to outId - LabelDsymbol *returnLabel; // where the return goes - - DsymbolTable *localsymtab; // used to prevent symbols in different - // scopes from having the same name - VarDeclaration *vthis; // 'this' parameter (member and nested) - VarDeclaration *v_arguments; // '_arguments' parameter -#if IN_GCC - VarDeclaration *v_argptr; // '_argptr' variable -#endif - Dsymbols *parameters; // Array of VarDeclaration's for parameters - DsymbolTable *labtab; // statement label symbol table - Declaration *overnext; // next in overload list - Loc endloc; // location of closing curly bracket - int vtblIndex; // for member functions, index into vtbl[] - int naked; // !=0 if naked - int inlineAsm; // !=0 if has inline assembler - ILS inlineStatus; - int inlineNest; // !=0 if nested inline - int cantInterpret; // !=0 if cannot interpret function - int semanticRun; // !=0 if semantic3() had been run - 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 - Scope *scope; // !=NULL means context to use - - // 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 - Symbol *shidden; // hidden pointer passed to function - -#if V2 - enum BUILTIN builtin; // set if this is a known, builtin - // function we can evaluate at compile - // time - - int tookAddressOf; // set if someone took the address of - // this function - Dsymbols closureVars; // local variables in this function - // which are referenced by nested - // functions -#else - int nestedFrameRef; // !=0 if nested variables referenced -#endif - - FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); - int overrides(FuncDeclaration *fd); - int overloadInsert(Dsymbol *s); - FuncDeclaration *overloadExactMatch(Type *t); - FuncDeclaration *overloadResolve(Loc loc, Expressions *arguments); - 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(); - int isMain(); - int isWinMain(); - int isDllMain(); - int isExport(); - int isImportedSymbol(); - int isAbstract(); - int isCodeseg(); - virtual int isNested(); - int needThis(); - virtual int isVirtual(); - virtual int addPreInvariant(); - virtual int addPostInvariant(); - Expression *interpret(InterState *istate, Expressions *arguments); - void inlineScan(); - int canInline(int hasthis, int hdrscan = 0); - Expression *doInline(InlineScanState *iss, Expression *ethis, Array *arguments); - char *kind(); - void toDocBuffer(OutBuffer *buf); - - static FuncDeclaration *genCfunc(Type *treturn, char *name); - static FuncDeclaration *genCfunc(Type *treturn, Identifier *id); - - Symbol *toSymbol(); - Symbol *toThunkSymbol(int offset); // thunk version - void toObjFile(); // compile to .obj file - int cvMember(unsigned char *p); - - FuncDeclaration *isFuncDeclaration() { return this; } - - // llvmdc stuff - bool runTimeHack; - std::set nestedVars; -}; - -struct FuncAliasDeclaration : FuncDeclaration -{ - FuncDeclaration *funcalias; - - FuncAliasDeclaration(FuncDeclaration *funcalias); - - FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } - char *kind(); - Symbol *toSymbol(); -}; - -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(); - - FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } - char *kind(); -}; - -struct CtorDeclaration : FuncDeclaration -{ Arguments *arguments; - int varargs; - - CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); - char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void toDocBuffer(OutBuffer *buf); - - CtorDeclaration *isCtorDeclaration() { return this; } -}; - -struct DtorDeclaration : FuncDeclaration -{ - DtorDeclaration(Loc loc, Loc endloc); - 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); - - DtorDeclaration *isDtorDeclaration() { return this; } -}; - -struct StaticCtorDeclaration : FuncDeclaration -{ - StaticCtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isStaticConstructor(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } -}; - -struct StaticDtorDeclaration : FuncDeclaration -{ - StaticDtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isStaticDestructor(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } -}; - -struct InvariantDeclaration : FuncDeclaration -{ - InvariantDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - InvariantDeclaration *isInvariantDeclaration() { return this; } -}; - - -struct UnitTestDeclaration : FuncDeclaration -{ - UnitTestDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - UnitTestDeclaration *isUnitTestDeclaration() { return this; } -}; - -struct NewDeclaration : FuncDeclaration -{ Arguments *arguments; - int varargs; - - NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - - NewDeclaration *isNewDeclaration() { return this; } -}; - - -struct DeleteDeclaration : FuncDeclaration -{ Arguments *arguments; - - DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); - int isDelete(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); -#ifdef _DH - DeleteDeclaration *isDeleteDeclaration() { return this; } -#endif -}; - -#endif /* DMD_DECLARATION_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-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_DECLARATION_H +#define DMD_DECLARATION_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include + +#include "dsymbol.h" +#include "lexer.h" +#include "mtype.h" + +struct Expression; +struct Statement; +struct LabelDsymbol; +struct Initializer; +struct Module; +struct InlineScanState; +struct ForeachStatement; +struct FuncDeclaration; +struct ExpInitializer; +struct StructDeclaration; +struct TupleType; +struct InterState; +struct IRState; + +enum PROT; +enum LINK; +enum TOK; +enum MATCH; + +enum STC +{ + STCundefined = 0, + STCstatic = 1, + STCextern = 2, + STCconst = 4, + STCfinal = 8, + STCabstract = 0x10, + STCparameter = 0x20, + STCfield = 0x40, + STCoverride = 0x80, + STCauto = 0x100, + STCsynchronized = 0x200, + STCdeprecated = 0x400, + STCin = 0x800, // in parameter + STCout = 0x1000, // out parameter + STClazy = 0x2000, // lazy parameter + STCforeach = 0x4000, // variable for foreach loop + STCcomdat = 0x8000, // should go into COMDAT record + STCvariadic = 0x10000, // variadic function argument + STCctorinit = 0x20000, // can only be set inside constructor + STCtemplateparameter = 0x40000, // template parameter + STCscope = 0x80000, // template parameter + STCinvariant = 0x100000, + 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 +}; + +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, Expressions *arguments); +int overloadApply(FuncDeclaration *fstart, + int (*fp)(void *, FuncDeclaration *), + void *param); + +/**************************************************************/ + +struct Declaration : Dsymbol +{ + Type *type; + Type *originalType; // before semantic analysis + unsigned storage_class; + enum PROT protection; + enum LINK linkage; + + Declaration(Identifier *id); + void semantic(Scope *sc); + char *kind(); + unsigned size(Loc loc); + void checkModify(Loc loc, Scope *sc, Type *t); + + void emitComment(Scope *sc); + void toDocBuffer(OutBuffer *buf); + + char *mangle(); + int isStatic() { return storage_class & STCstatic; } + virtual int isStaticConstructor(); + virtual int isStaticDestructor(); + virtual int isDelete(); + virtual int isDataseg(); + virtual int isCodeseg(); + int isCtorinit() { return storage_class & STCctorinit; } + int isFinal() { return storage_class & STCfinal; } + int isAbstract() { return storage_class & STCabstract; } + int isConst() { return storage_class & STCconst; } + int isInvariant() { return 0; } + int isAuto() { return storage_class & STCauto; } + int isScope() { return storage_class & (STCscope | STCauto); } + int isSynchronized() { return storage_class & STCsynchronized; } + int isParameter() { return storage_class & STCparameter; } + int isDeprecated() { return storage_class & STCdeprecated; } + int isOverride() { return storage_class & STCoverride; } + + int isIn() { return storage_class & STCin; } + int isOut() { return storage_class & STCout; } + int isRef() { return storage_class & STCref; } + + enum PROT prot(); + + Declaration *isDeclaration() { return this; } + + // llvm + virtual void toObjFile(); // compile to .obj file +}; + +/**************************************************************/ + +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 *); + char *kind(); + Type *getType(); + int needThis(); + + TupleDeclaration *isTupleDeclaration() { return this; } +}; + +/**************************************************************/ + +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 + int inuse; // used to detect typedef cycles + + TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + char *mangle(); + char *kind(); + Type *getType(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#ifdef _DH + Type *htype; + Type *hbasetype; +#endif + + void toDocBuffer(OutBuffer *buf); + + void toObjFile(); // compile to .obj file + void toDebug(); + int cvMember(unsigned char *p); + + TypedefDeclaration *isTypedefDeclaration() { return this; } + + Symbol *sinit; + Symbol *toInitializer(); +}; + +/**************************************************************/ + +struct AliasDeclaration : Declaration +{ + Dsymbol *aliassym; + Dsymbol *overnext; // next in overload list + int inSemantic; + + 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); + char *kind(); + Type *getType(); + Dsymbol *toAlias(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#ifdef _DH + Type *htype; + Dsymbol *haliassym; +#endif + + void toDocBuffer(OutBuffer *buf); + + AliasDeclaration *isAliasDeclaration() { return this; } +}; + +/**************************************************************/ + +struct VarDeclaration : Declaration +{ + Initializer *init; + unsigned offset; + int noauto; // no auto semantics + int nestedref; // referenced by a lexically nested function + int inuse; + int ctorinit; // it has been initialized in a ctor + int onstack; // 1: it has been allocated on the stack + // 2: on stack, run destructor anyway + int canassign; // it can be assigned to + Dsymbol *aliassym; // if redone as alias to another symbol + Expression *value; // when interpreting, this is the value + // (NULL if value not determinable) + + VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + char *kind(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#ifdef _DH + Type *htype; + Initializer *hinit; +#endif + int needThis(); + int isImportedSymbol(); + int isDataseg(); + int hasPointers(); + Expression *callAutoDtor(); + ExpInitializer *getExpInitializer(); + void checkCtorConstInit(); + void checkNestedReference(Scope *sc, Loc loc); + Dsymbol *toAlias(); + + Symbol *toSymbol(); + void toObjFile(); // compile to .obj file + int cvMember(unsigned char *p); + + // Eliminate need for dynamic_cast + VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } + + // LLVMDC + bool needsStorage; +}; + +/**************************************************************/ + +// This is a shell around a back end symbol + +struct SymbolDeclaration : Declaration +{ + Symbol *sym; + StructDeclaration *dsym; + + SymbolDeclaration(Loc loc, Symbol *s, StructDeclaration *dsym); + + Symbol *toSymbol(); + + // Eliminate need for dynamic_cast + SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; } +}; + +struct ClassInfoDeclaration : VarDeclaration +{ + ClassDeclaration *cd; + + ClassInfoDeclaration(ClassDeclaration *cd); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + + void emitComment(Scope *sc); + + Symbol *toSymbol(); + + ClassInfoDeclaration* isClassInfoDeclaration() { return this; } +}; + +struct ModuleInfoDeclaration : VarDeclaration +{ + Module *mod; + + ModuleInfoDeclaration(Module *mod); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + + void emitComment(Scope *sc); + + Symbol *toSymbol(); +}; + +struct TypeInfoDeclaration : VarDeclaration +{ + Type *tinfo; + + TypeInfoDeclaration(Type *tinfo, int internal); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + + void emitComment(Scope *sc); + + Symbol *toSymbol(); + void toObjFile(); // compile to .obj file + virtual void toDt(dt_t **pdt); + + virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } + + // LLVMDC + virtual void llvmDeclare(); + virtual void llvmDefine(); +}; + +struct TypeInfoStructDeclaration : TypeInfoDeclaration +{ + TypeInfoStructDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct TypeInfoClassDeclaration : TypeInfoDeclaration +{ + TypeInfoClassDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration +{ + TypeInfoInterfaceDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct TypeInfoTypedefDeclaration : TypeInfoDeclaration +{ + TypeInfoTypedefDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct TypeInfoPointerDeclaration : TypeInfoDeclaration +{ + TypeInfoPointerDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct TypeInfoArrayDeclaration : TypeInfoDeclaration +{ + TypeInfoArrayDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration +{ + TypeInfoStaticArrayDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration +{ + TypeInfoAssociativeArrayDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct TypeInfoEnumDeclaration : TypeInfoDeclaration +{ + TypeInfoEnumDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct TypeInfoFunctionDeclaration : TypeInfoDeclaration +{ + TypeInfoFunctionDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct TypeInfoDelegateDeclaration : TypeInfoDeclaration +{ + TypeInfoDelegateDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct TypeInfoTupleDeclaration : TypeInfoDeclaration +{ + TypeInfoTupleDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct ThisDeclaration : VarDeclaration +{ + ThisDeclaration(Type *t); + Dsymbol *syntaxCopy(Dsymbol *); +}; + +enum ILS +{ + ILSuninitialized, // not computed yet + ILSno, // cannot inline + ILSyes, // can inline +}; + +/**************************************************************/ + +#if V2 + +enum BUILTIN +{ + BUILTINunknown = -1, // not known if this is a builtin + BUILTINnot, // this is not a builtin + BUILTINsin, // std.math.sin + BUILTINcos, // std.math.cos + BUILTINtan, // std.math.tan + BUILTINsqrt, // std.math.sqrt + BUILTINfabs, // std.math.fabs +}; + +Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments); + +#endif + +struct FuncDeclaration : Declaration +{ + Array *fthrows; // Array of Type's of exceptions (not used) + Statement *frequire; + Statement *fensure; + Statement *fbody; + + Identifier *outId; // identifier for out statement + VarDeclaration *vresult; // variable corresponding to outId + LabelDsymbol *returnLabel; // where the return goes + + DsymbolTable *localsymtab; // used to prevent symbols in different + // scopes from having the same name + VarDeclaration *vthis; // 'this' parameter (member and nested) + VarDeclaration *v_arguments; // '_arguments' parameter +#if IN_GCC + VarDeclaration *v_argptr; // '_argptr' variable +#endif + Dsymbols *parameters; // Array of VarDeclaration's for parameters + DsymbolTable *labtab; // statement label symbol table + Declaration *overnext; // next in overload list + Loc endloc; // location of closing curly bracket + int vtblIndex; // for member functions, index into vtbl[] + int naked; // !=0 if naked + int inlineAsm; // !=0 if has inline assembler + ILS inlineStatus; + int inlineNest; // !=0 if nested inline + int cantInterpret; // !=0 if cannot interpret function + int semanticRun; // !=0 if semantic3() had been run + // this function's frame ptr + ForeachStatement *fes; // if foreach body, this is the foreach + int introducing; // !=0 if 'introducing' function + Type *tintro; // if !=NULL, then this is the type + // of the 'introducing' function + // this one is overriding + int inferRetType; // !=0 if return type is to be inferred + Scope *scope; // !=NULL means context to use + + // 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 + Symbol *shidden; // hidden pointer passed to function + +#if V2 + enum BUILTIN builtin; // set if this is a known, builtin + // function we can evaluate at compile + // time + + int tookAddressOf; // set if someone took the address of + // this function + Dsymbols closureVars; // local variables in this function + // which are referenced by nested + // functions +#else + int nestedFrameRef; // !=0 if nested variables referenced +#endif + + FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); + int overrides(FuncDeclaration *fd); + int findVtblIndex(Array *vtbl, int dim); + int overloadInsert(Dsymbol *s); + FuncDeclaration *overloadExactMatch(Type *t); + FuncDeclaration *overloadResolve(Loc loc, Expressions *arguments); + 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(); + int isMain(); + int isWinMain(); + int isDllMain(); + int isExport(); + int isImportedSymbol(); + int isAbstract(); + int isCodeseg(); + virtual int isNested(); + int needThis(); + virtual int isVirtual(); + virtual int addPreInvariant(); + virtual int addPostInvariant(); + Expression *interpret(InterState *istate, Expressions *arguments); + void inlineScan(); + int canInline(int hasthis, int hdrscan = 0); + Expression *doInline(InlineScanState *iss, Expression *ethis, Array *arguments); + char *kind(); + void toDocBuffer(OutBuffer *buf); + + static FuncDeclaration *genCfunc(Type *treturn, char *name); + static FuncDeclaration *genCfunc(Type *treturn, Identifier *id); + + Symbol *toSymbol(); + Symbol *toThunkSymbol(int offset); // thunk version + void toObjFile(); // compile to .obj file + int cvMember(unsigned char *p); + + FuncDeclaration *isFuncDeclaration() { return this; } + + // llvmdc stuff + bool runTimeHack; + std::set nestedVars; +}; + +struct FuncAliasDeclaration : FuncDeclaration +{ + FuncDeclaration *funcalias; + + FuncAliasDeclaration(FuncDeclaration *funcalias); + + FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } + char *kind(); + Symbol *toSymbol(); +}; + +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(); + + FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } + char *kind(); +}; + +struct CtorDeclaration : FuncDeclaration +{ Arguments *arguments; + int varargs; + + CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + char *kind(); + char *toChars(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void toDocBuffer(OutBuffer *buf); + + CtorDeclaration *isCtorDeclaration() { return this; } +}; + +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); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + int overloadInsert(Dsymbol *s); + void emitComment(Scope *sc); + + DtorDeclaration *isDtorDeclaration() { return this; } +}; + +struct StaticCtorDeclaration : FuncDeclaration +{ + StaticCtorDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + AggregateDeclaration *isThis(); + int isStaticConstructor(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void emitComment(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } +}; + +struct StaticDtorDeclaration : FuncDeclaration +{ + StaticDtorDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + AggregateDeclaration *isThis(); + int isStaticDestructor(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void emitComment(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } +}; + +struct InvariantDeclaration : FuncDeclaration +{ + InvariantDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void emitComment(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + InvariantDeclaration *isInvariantDeclaration() { return this; } +}; + + +struct UnitTestDeclaration : FuncDeclaration +{ + UnitTestDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + AggregateDeclaration *isThis(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + UnitTestDeclaration *isUnitTestDeclaration() { return this; } +}; + +struct NewDeclaration : FuncDeclaration +{ Arguments *arguments; + int varargs; + + NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + char *kind(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + + NewDeclaration *isNewDeclaration() { return this; } +}; + + +struct DeleteDeclaration : FuncDeclaration +{ Arguments *arguments; + + DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + char *kind(); + int isDelete(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); +#ifdef _DH + DeleteDeclaration *isDeleteDeclaration() { return this; } +#endif +}; + +#endif /* DMD_DECLARATION_H */ diff --git a/dmd/doc.c b/dmd/doc.c index 41ce5675..657614bf 100644 --- a/dmd/doc.c +++ b/dmd/doc.c @@ -1,1932 +1,2002 @@ - -// 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. - -// This implements the Ddoc capability. - -#include -#include -#include -#include -#include - -#if IN_GCC || IN_LLVM -#include "mem.h" -#else -#if _WIN32 -#include "..\root\mem.h" -#elif linux -#include "../root/mem.h" -#else -#error "fix this" -#endif -#endif - -#include "root.h" - -#include "mars.h" -#include "dsymbol.h" -#include "macro.h" -#include "template.h" -#include "lexer.h" -#include "aggregate.h" -#include "declaration.h" -#include "enum.h" -#include "id.h" -#include "module.h" -#include "scope.h" -#include "hdrgen.h" -#include "doc.h" -#include "mtype.h" - -struct Escape -{ - char *strings[256]; - - static 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); -}; - -struct DocComment -{ - Array sections; // Section*[] - - Section *summary; - Section *copyright; - Section *macros; - Macro **pmacrotable; - Escape **pescapetable; - - DocComment(); - - static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); - static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen); - static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen); - - void parseSections(unsigned char *comment); - void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - - -int cmp(char *stringz, void *s, size_t slen); -int icmp(char *stringz, void *s, size_t slen); -int isDitto(unsigned char *comment); -unsigned char *skipwhitespace(unsigned char *p); -unsigned skiptoident(OutBuffer *buf, unsigned i); -unsigned skippastident(OutBuffer *buf, unsigned i); -void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); - -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/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\ -\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 (int i = 0; i < global.params.ddocfiles->dim; i++) - { - FileName f((char *)global.params.ddocfiles->data[i], 0); - File file(&f); - file.readv(); - // BUG: convert file contents to UTF-8 before use - - //printf("file: '%.*s'\n", file.len, file.buffer); - mbuf.write(file.buffer, file.len); - } - } - 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 - { char *p = toPrettyChars(); - Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); - } - - time_t t; - time(&t); - char *p = ctime(&t); - p = mem.strdup(p); - Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); - Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); - - char *docfilename = docfile->toChars(); - Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); - - if (dc->copyright) - { - dc->copyright->nooutput = 1; - Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); - } - - buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); - if (isDocFile) - { - size_t commentlen = strlen((char *)comment); - if (dc->macros) - { - commentlen = dc->macros->name - comment; - dc->macros->write(dc, sc, this, sc->docbuf); - } - sc->docbuf->write(comment, commentlen); - highlightText(NULL, this, sc->docbuf, 0); - } - else - { - dc->writeSections(sc, this, sc->docbuf); - emitMemberComments(sc); - } - - //printf("BODY= '%.*s'\n", buf.offset, buf.data); - Macro::define(¯otable, (unsigned char *)"BODY", 4, buf.data, buf.offset); - - OutBuffer buf2; - buf2.writestring("$(DDOC)\n"); - unsigned end = buf2.offset; - macrotable->expand(&buf2, 0, &end, NULL, 0); - -#if 1 - /* Remove all the escape sequences from buf2, - * and make CR-LF the newline. - */ - { - buf.setsize(0); - buf.reserve(buf2.offset); - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - unsigned char c = p[j]; - if (c == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - if (c == '\n') - buf.writeByte('\r'); - else if (c == '\r') - { - buf.writestring("\r\n"); - if (j + 1 < buf2.offset && p[j + 1] == '\n') - { - j++; - } - continue; - } - buf.writeByte(c); - } - } - - // Transfer image to file - assert(docfile); - docfile->setbuffer(buf.data, buf.offset); - docfile->ref = 1; - char *pt = FileName::path(docfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - docfile->writev(); -#else - /* Remove all the escape sequences from buf2 - */ - { unsigned i = 0; - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - if (p[j] == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - p[i] = p[j]; - i++; - } - buf2.setsize(i); - } - - // Transfer image to file - docfile->setbuffer(buf2.data, buf2.offset); - docfile->ref = 1; - char *pt = FileName::path(docfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - docfile->writev(); -#endif -} - -/******************************* emitComment **********************************/ - -/* - * Emit doc comment to documentation file - */ - -void Dsymbol::emitDitto(Scope *sc) -{ - OutBuffer *buf = sc->docbuf; - unsigned o; - OutBuffer b; - - b.writestring("$(DDOC_DITTO "); - o = b.offset; - toDocBuffer(&b); - 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()\n"); - OutBuffer *buf = sc->docbuf; - - if (members) - { 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"; - - // BUG: if no members are actually printed, we should not emit DDOC_MEMBERS - buf->writestring(m); - sc = sc->push(this); - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - //printf("\ts = '%s'\n", s->toChars()); - s->emitComment(sc); - } - sc->pop(); - buf->writestring(")\n"); - } -} - -void emitProtection(OutBuffer *buf, PROT prot) -{ - 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) { } -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; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - unsigned o; - int hasmembers = 1; - - Dsymbol *ss = this; - - if (onemember) - { - ss = onemember->isAggregateDeclaration(); - if (!ss) - { - ss = onemember->isFuncDeclaration(); - if (ss) - hasmembers = 0; - else - ss = this; - } - } - - 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 (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[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; - - 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 V2 - if (d->isInvariant()) - buf->writestring("invariant "); -#endif - if (d->isFinal()) - buf->writestring("final "); - if (d->isSynchronized()) - buf->writestring("synchronized "); - } -} - -void Declaration::toDocBuffer(OutBuffer *buf) -{ - //printf("Declaration::toDocbuffer() %s, originalType = %p\n", toChars(), originalType); - if (ident) - { - prefix(buf, this); - - if (type) - { HdrGenState hgs; - hgs.ddoc = 1; - if (originalType) - { //originalType->print(); - originalType->toCBuffer(buf, ident, &hgs); - } - else - type->toCBuffer(buf, ident, &hgs); - } - else - buf->writestring(ident->toChars()); - buf->writestring(";\n"); - } -} - - -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) - { HdrGenState hgs; - unsigned o = buf->offset; - TypeFunction *tf = (TypeFunction *)type; - - hgs.ddoc = 1; - prefix(buf, td); - tf->next->toCBuffer(buf, NULL, &hgs); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - buf->writeByte('('); - for (int i = 0; i < td->parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)td->parameters->data[i]; - if (i) - buf->writeByte(','); - tp->toCBuffer(buf, &hgs); - } - buf->writeByte(')'); - Argument::argsToCBuffer(buf, &hgs, tf->parameters, tf->varargs); - buf->writestring(";\n"); - - highlightCode(NULL, this, buf, o); - } - else - { - Declaration::toDocBuffer(buf); - } - } -} - -void CtorDeclaration::toDocBuffer(OutBuffer *buf) -{ - HdrGenState hgs; - - buf->writestring("this"); - Argument::argsToCBuffer(buf, &hgs, arguments, varargs); - buf->writestring(";\n"); -} - - -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 - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - int any = 0; - for (int i = 0; i < baseclasses.dim; i++) - { BaseClass *bc = (BaseClass *)baseclasses.data[i]; - - if (bc->protection == PROTprivate) - continue; - if (bc->base && bc->base->ident == Id::Object) - continue; - - if (any) - buf->writestring(", "); - else - { buf->writestring(": "); - any = 1; - } - emitProtection(buf, bc->protection); - if (bc->base) - { - buf->writestring(bc->base->toPrettyChars()); - } - else - { - HdrGenState hgs; - bc->type->toCBuffer(buf, NULL, &hgs); - } - } - buf->writestring(";\n"); - } -} - - -void EnumDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); - } -} - -void EnumMember::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - buf->writestring(toChars()); - } -} - - -/********************************* DocComment *********************************/ - -DocComment::DocComment() -{ - memset(this, 0, sizeof(DocComment)); -} - -DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) -{ unsigned idlen; - - if (sc->lastdc && isDitto(comment)) - return NULL; - - DocComment *dc = new DocComment(); - if (!comment) - return dc; - - dc->parseSections(comment); - - for (int i = 0; i < dc->sections.dim; i++) - { Section *s = (Section *)dc->sections.data[i]; - - if (icmp("copyright", s->name, s->namelen) == 0) - { - dc->copyright = s; - } - if (icmp("macros", s->name, s->namelen) == 0) - { - dc->macros = s; - } - } - - 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 *q; - unsigned char *idstart; - unsigned idlen; - - unsigned char *name = NULL; - unsigned namelen = 0; - - p = comment; - while (*p) - { - p = skipwhitespace(p); - pstart = p; - - /* Find end of section, which is ended by one of: - * 'identifier:' - * '\0' - */ - idlen = 0; - while (1) - { - if (isalpha(*p) || *p == '_') - { - q = p + 1; - while (isalnum(*q) || *q == '_') - q++; - if (*q == ':') // identifier: ends it - { idlen = q - p; - idstart = p; - for (pend = p; pend > pstart; pend--) - { if (pend[-1] == '\n') - break; - } - p = q + 1; - break; - } - } - while (1) - { - if (!*p) - { pend = p; - goto L1; - } - if (*p == '\n') - { p++; - if (*p == '\n' && !summary && !namelen) - { - pend = p; - p++; - goto L1; - } - break; - } - p++; - } - p = skipwhitespace(p); - } - 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 (int i = 0; i < sections.dim; i++) - { Section *sec = (Section *)sections.data[i]; - - if (sec->nooutput) - continue; - //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); - if (sec->namelen || i) - sec->write(this, sc, s, buf); - else - { - buf->writestring("$(DDOC_SUMMARY "); - unsigned o = buf->offset; - buf->write(sec->body, sec->bodylen); - highlightText(sc, s, buf, o); - buf->writestring(")\n"); - } - } - buf->writestring(")\n"); - } - else - { - buf->writestring("$(DDOC_BLANKLINE)\n"); - } -} - -/*************************************************** - */ - -void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - if (namelen) - { - static 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 "); - for (unsigned u = 0; u < namelen; u++) - { unsigned char c = name[u]; - buf->writeByte((c == '_') ? ' ' : c); - } - buf->writestring(":)\n"); - } - else - { - buf->writestring("$(DDOC_DESCRIPTION "); - } - L1: - unsigned o = buf->offset; - buf->write(body, bodylen); - 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; - Argument *arg; - - buf->writestring("$(DDOC_PARAMS \n"); - while (p < pend) - { - // Skip to start of macro - for (; 1; p++) - { - switch (*p) - { - case ' ': - case '\t': - continue; - - case '\n': - p++; - goto Lcont; - - default: - if (!(isalpha(*p) || *p == '_')) - { - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - break; - } - tempstart = p; - - while (isalnum(*p) || *p == '_') - 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); - highlightCode(sc, s, buf, o); - buf->writestring(")\n"); - - buf->writestring("$(DDOC_PARAM_DESC "); - o = buf->offset; - buf->write(textstart, textlen); - highlightText(sc, s, buf, o); - buf->writestring(")"); - buf->writestring(")\n"); - namelen = 0; - if (p >= pend) - break; - } - - 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 - for (; 1; p++) - { - if (p >= pend) - goto Ldone; - switch (*p) - { - case ' ': - case '\t': - continue; - - case '\n': - p++; - goto Lcont; - - default: - if (!(isalpha(*p) || *p == '_')) - { - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - break; - } - tempstart = p; - - while (1) - { - if (p >= pend) - goto Ldone; - if (!(isalnum(*p) || *p == '_')) - break; - p++; - } - templen = p - tempstart; - - while (1) - { - if (p >= pend) - goto Ldone; - if (!(*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(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(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, unsigned i) -{ - for (; i < buf->offset; i++) - { - // BUG: handle unicode alpha's - unsigned char c = buf->data[i]; - if (isalpha(c) || c == '_') - break; - if (c == '\n') - break; - } - return i; -} - -/************************************************ - * Scan forward past end of identifier. - */ - -unsigned skippastident(OutBuffer *buf, unsigned i) -{ - for (; i < buf->offset; i++) - { - // BUG: handle unicode alpha's - unsigned char c = buf->data[i]; - if (!(isalnum(c) || c == '_')) - break; - } - return i; -} - - -/**************************************************** - */ - -int isKeyword(unsigned char *p, unsigned len) -{ - static 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; -} - -/**************************************************** - */ - -Argument *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 = (TypeFunction *)f->type; - - if (tf->parameters) - { - for (size_t k = 0; k < tf->parameters->dim; k++) - { Argument *arg = (Argument *)tf->parameters->data[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"); - char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - unsigned char *p; - 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) - { - 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 > - } - } - break; - - default: - leadingBlank = 0; - if (sc && !inCode && (isalpha(c) || c == '_')) - { unsigned j; - - j = skippastident(buf, i); - if (j > i) - { - if (buf->data[i] == '_') // leading '_' means no highlight - { - buf->remove(i, 1); - i = j - 1; - } - else - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - break; - } - else if (isKeyword(buf->data + i, j - i)) - { - i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; - break; - } - else - { - if (f && isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - break; - } - } - i = j - 1; - } - } - } - break; - } - } - Ldone: - ; -} - -/************************************************** - * 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]; - char *se; - - se = Escape::escapeChar(c); - if (se) - { - size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - else if (isalpha(c) || c == '_') - { unsigned j; - - 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++) - { 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; - 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. - */ - -char *Escape::escapeChar(unsigned c) -{ char *s; - - switch (c) - { - case '<': - s = "<"; - break; - case '>': - s = ">"; - break; - case '&': - s = "&"; - break; - default: - s = NULL; - break; - } - return s; -} - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +// This implements the Ddoc capability. + +#include +#include +#include +#include +#include + +#if IN_GCC || IN_LLVM +#include "mem.h" +#else +#if _WIN32 +#include "..\root\mem.h" +#elif linux +#include "../root/mem.h" +#else +#error "fix this" +#endif +#endif + +#include "root.h" + +#include "mars.h" +#include "dsymbol.h" +#include "macro.h" +#include "template.h" +#include "lexer.h" +#include "aggregate.h" +#include "declaration.h" +#include "enum.h" +#include "id.h" +#include "module.h" +#include "scope.h" +#include "hdrgen.h" +#include "doc.h" +#include "mtype.h" + +struct Escape +{ + char *strings[256]; + + static 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); +}; + +struct DocComment +{ + Array sections; // Section*[] + + Section *summary; + Section *copyright; + Section *macros; + Macro **pmacrotable; + Escape **pescapetable; + + DocComment(); + + static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); + static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen); + static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen); + + void parseSections(unsigned char *comment); + void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + + +int cmp(char *stringz, void *s, size_t slen); +int icmp(char *stringz, void *s, size_t slen); +int isDitto(unsigned char *comment); +unsigned char *skipwhitespace(unsigned char *p); +unsigned skiptoident(OutBuffer *buf, unsigned i); +unsigned skippastident(OutBuffer *buf, unsigned i); +unsigned skippastURL(OutBuffer *buf, unsigned i); +void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); + +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\ +\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 (int i = 0; i < global.params.ddocfiles->dim; i++) + { + FileName f((char *)global.params.ddocfiles->data[i], 0); + File file(&f); + file.readv(); + // BUG: convert file contents to UTF-8 before use + + //printf("file: '%.*s'\n", file.len, file.buffer); + mbuf.write(file.buffer, file.len); + } + } + 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 + { char *p = toPrettyChars(); + Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); + } + + time_t t; + time(&t); + char *p = ctime(&t); + p = mem.strdup(p); + Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); + Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); + + char *docfilename = docfile->toChars(); + Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); + + if (dc->copyright) + { + dc->copyright->nooutput = 1; + Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); + } + + buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); + if (isDocFile) + { + size_t commentlen = strlen((char *)comment); + if (dc->macros) + { + commentlen = dc->macros->name - comment; + dc->macros->write(dc, sc, this, sc->docbuf); + } + sc->docbuf->write(comment, commentlen); + highlightText(NULL, this, sc->docbuf, 0); + } + else + { + dc->writeSections(sc, this, sc->docbuf); + emitMemberComments(sc); + } + + //printf("BODY= '%.*s'\n", buf.offset, buf.data); + Macro::define(¯otable, (unsigned char *)"BODY", 4, buf.data, buf.offset); + + OutBuffer buf2; + buf2.writestring("$(DDOC)\n"); + unsigned end = buf2.offset; + macrotable->expand(&buf2, 0, &end, NULL, 0); + +#if 1 + /* Remove all the escape sequences from buf2, + * and make CR-LF the newline. + */ + { + buf.setsize(0); + buf.reserve(buf2.offset); + unsigned char *p = buf2.data; + for (unsigned j = 0; j < buf2.offset; j++) + { + unsigned char c = p[j]; + if (c == 0xFF && j + 1 < buf2.offset) + { + j++; + continue; + } + if (c == '\n') + buf.writeByte('\r'); + else if (c == '\r') + { + buf.writestring("\r\n"); + if (j + 1 < buf2.offset && p[j + 1] == '\n') + { + j++; + } + continue; + } + buf.writeByte(c); + } + } + + // Transfer image to file + assert(docfile); + docfile->setbuffer(buf.data, buf.offset); + docfile->ref = 1; + char *pt = FileName::path(docfile->toChars()); + if (*pt) + FileName::ensurePathExists(pt); + mem.free(pt); + docfile->writev(); +#else + /* Remove all the escape sequences from buf2 + */ + { unsigned i = 0; + unsigned char *p = buf2.data; + for (unsigned j = 0; j < buf2.offset; j++) + { + if (p[j] == 0xFF && j + 1 < buf2.offset) + { + j++; + continue; + } + p[i] = p[j]; + i++; + } + buf2.setsize(i); + } + + // Transfer image to file + docfile->setbuffer(buf2.data, buf2.offset); + docfile->ref = 1; + char *pt = FileName::path(docfile->toChars()); + if (*pt) + FileName::ensurePathExists(pt); + mem.free(pt); + docfile->writev(); +#endif +} + +/******************************* 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()\n"); + OutBuffer *buf = sc->docbuf; + + if (members) + { 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"; + + // BUG: if no members are actually printed, we should not emit DDOC_MEMBERS + buf->writestring(m); + sc = sc->push(this); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + //printf("\ts = '%s'\n", s->toChars()); + s->emitComment(sc); + } + sc->pop(); + buf->writestring(")\n"); + } +} + +void emitProtection(OutBuffer *buf, PROT prot) +{ + 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) { } +//void PostBlitDeclaration::emitComment(Scope *sc) { } +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; + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + unsigned o; + int hasmembers = 1; + + Dsymbol *ss = this; + + if (onemember) + { + ss = onemember->isAggregateDeclaration(); + if (!ss) + { + ss = onemember->isFuncDeclaration(); + if (ss) + hasmembers = 0; + else + ss = this; + } + } + + 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 (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[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 V2 + if (d->isInvariant()) + buf->writestring("invariant "); +#endif + if (d->isFinal()) + buf->writestring("final "); + if (d->isSynchronized()) + buf->writestring("synchronized "); + } +} + +void Declaration::toDocBuffer(OutBuffer *buf) +{ + //printf("Declaration::toDocbuffer() %s, originalType = %p\n", toChars(), originalType); + if (ident) + { + prefix(buf, this); + + if (type) + { HdrGenState hgs; + hgs.ddoc = 1; + if (originalType) + { //originalType->print(); + originalType->toCBuffer(buf, ident, &hgs); + } + else + type->toCBuffer(buf, ident, &hgs); + } + else + buf->writestring(ident->toChars()); + buf->writestring(";\n"); + } +} + + +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) + { HdrGenState hgs; + unsigned o = buf->offset; + TypeFunction *tf = (TypeFunction *)type; + + hgs.ddoc = 1; + prefix(buf, td); + tf->next->toCBuffer(buf, NULL, &hgs); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + buf->writeByte('('); + for (int i = 0; i < td->origParameters->dim; i++) + { + TemplateParameter *tp = (TemplateParameter *)td->origParameters->data[i]; + if (i) + buf->writeByte(','); + tp->toCBuffer(buf, &hgs); + } + buf->writeByte(')'); + Argument::argsToCBuffer(buf, &hgs, tf->parameters, tf->varargs); + buf->writestring(";\n"); + + highlightCode(NULL, this, buf, o); + } + else + { + Declaration::toDocBuffer(buf); + } + } +} + +void CtorDeclaration::toDocBuffer(OutBuffer *buf) +{ + HdrGenState hgs; + + buf->writestring("this"); + Argument::argsToCBuffer(buf, &hgs, arguments, varargs); + buf->writestring(";\n"); +} + + +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 + { + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + } + int any = 0; + for (int i = 0; i < baseclasses.dim; i++) + { BaseClass *bc = (BaseClass *)baseclasses.data[i]; + + if (bc->protection == PROTprivate) + continue; + if (bc->base && bc->base->ident == Id::Object) + continue; + + if (any) + buf->writestring(", "); + else + { buf->writestring(": "); + any = 1; + } + emitProtection(buf, bc->protection); + if (bc->base) + { + buf->writestring(bc->base->toPrettyChars()); + } + else + { + HdrGenState hgs; + bc->type->toCBuffer(buf, NULL, &hgs); + } + } + buf->writestring(";\n"); + } +} + + +void EnumDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + buf->writestring(";\n"); + } +} + +void EnumMember::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + buf->writestring(toChars()); + } +} + + +/********************************* DocComment *********************************/ + +DocComment::DocComment() +{ + memset(this, 0, sizeof(DocComment)); +} + +DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) +{ unsigned idlen; + + if (sc->lastdc && isDitto(comment)) + return NULL; + + DocComment *dc = new DocComment(); + if (!comment) + return dc; + + dc->parseSections(comment); + + for (int i = 0; i < dc->sections.dim; i++) + { Section *s = (Section *)dc->sections.data[i]; + + if (icmp("copyright", s->name, s->namelen) == 0) + { + dc->copyright = s; + } + if (icmp("macros", s->name, s->namelen) == 0) + { + dc->macros = s; + } + } + + 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 *q; + unsigned char *idstart; + unsigned idlen; + + unsigned char *name = NULL; + unsigned namelen = 0; + + p = comment; + while (*p) + { + p = skipwhitespace(p); + pstart = p; + + /* Find end of section, which is ended by one of: + * 'identifier:' + * '\0' + */ + idlen = 0; + while (1) + { + if (isalpha(*p) || *p == '_') + { + q = p + 1; + while (isalnum(*q) || *q == '_') + q++; + if (*q == ':') // identifier: ends it + { idlen = q - p; + idstart = p; + for (pend = p; pend > pstart; pend--) + { if (pend[-1] == '\n') + break; + } + p = q + 1; + break; + } + } + while (1) + { + if (!*p) + { pend = p; + goto L1; + } + if (*p == '\n') + { p++; + if (*p == '\n' && !summary && !namelen) + { + pend = p; + p++; + goto L1; + } + break; + } + p++; + } + p = skipwhitespace(p); + } + 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 (int i = 0; i < sections.dim; i++) + { Section *sec = (Section *)sections.data[i]; + + if (sec->nooutput) + continue; + //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); + if (sec->namelen || i) + sec->write(this, sc, s, buf); + else + { + buf->writestring("$(DDOC_SUMMARY "); + unsigned o = buf->offset; + buf->write(sec->body, sec->bodylen); + highlightText(sc, s, buf, o); + buf->writestring(")\n"); + } + } + buf->writestring(")\n"); + } + else + { + buf->writestring("$(DDOC_BLANKLINE)\n"); + } +} + +/*************************************************** + */ + +void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + if (namelen) + { + static 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 "); + for (unsigned u = 0; u < namelen; u++) + { unsigned char c = name[u]; + buf->writeByte((c == '_') ? ' ' : c); + } + buf->writestring(":)\n"); + } + else + { + buf->writestring("$(DDOC_DESCRIPTION "); + } + L1: + unsigned o = buf->offset; + buf->write(body, bodylen); + 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; + Argument *arg; + + buf->writestring("$(DDOC_PARAMS \n"); + while (p < pend) + { + // Skip to start of macro + for (; 1; p++) + { + switch (*p) + { + case ' ': + case '\t': + continue; + + case '\n': + p++; + goto Lcont; + + default: + if (!(isalpha(*p) || *p == '_')) + { + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + break; + } + break; + } + tempstart = p; + + while (isalnum(*p) || *p == '_') + 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); + highlightCode(sc, s, buf, o); + buf->writestring(")\n"); + + buf->writestring("$(DDOC_PARAM_DESC "); + o = buf->offset; + buf->write(textstart, textlen); + highlightText(sc, s, buf, o); + buf->writestring(")"); + buf->writestring(")\n"); + namelen = 0; + if (p >= pend) + break; + } + + 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 + for (; 1; p++) + { + if (p >= pend) + goto Ldone; + switch (*p) + { + case ' ': + case '\t': + continue; + + case '\n': + p++; + goto Lcont; + + default: + if (!(isalpha(*p) || *p == '_')) + { + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + break; + } + break; + } + tempstart = p; + + while (1) + { + if (p >= pend) + goto Ldone; + if (!(isalnum(*p) || *p == '_')) + break; + p++; + } + templen = p - tempstart; + + while (1) + { + if (p >= pend) + goto Ldone; + if (!(*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(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(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, unsigned i) +{ + for (; i < buf->offset; i++) + { + // BUG: handle unicode alpha's + unsigned char c = buf->data[i]; + if (isalpha(c) || c == '_') + break; + if (c == '\n') + break; + } + return i; +} + +/************************************************ + * Scan forward past end of identifier. + */ + +unsigned skippastident(OutBuffer *buf, unsigned i) +{ + for (; i < buf->offset; i++) + { + // BUG: handle unicode alpha's + unsigned char c = buf->data[i]; + if (!(isalnum(c) || c == '_')) + 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, unsigned 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 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; +} + +/**************************************************** + */ + +Argument *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 = (TypeFunction *)f->type; + + if (tf->parameters) + { + for (size_t k = 0; k < tf->parameters->dim; k++) + { Argument *arg = (Argument *)tf->parameters->data[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"); + char *sid = s->ident->toChars(); + FuncDeclaration *f = s->isFuncDeclaration(); + unsigned char *p; + 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) + { + 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 > + } + } + break; + + default: + leadingBlank = 0; + if (sc && !inCode && (isalpha(c) || c == '_')) + { 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; + } + } + Ldone: + ; +} + +/************************************************** + * 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]; + char *se; + + se = Escape::escapeChar(c); + if (se) + { + size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + else if (isalpha(c) || c == '_') + { unsigned j; + + 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++) + { 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; + 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. + */ + +char *Escape::escapeChar(unsigned c) +{ char *s; + + switch (c) + { + case '<': + s = "<"; + break; + case '>': + s = ">"; + break; + case '&': + s = "&"; + break; + default: + s = NULL; + break; + } + return s; +} + diff --git a/dmd/dsymbol.c b/dmd/dsymbol.c index 41ad40ac..ef847d69 100644 --- a/dmd/dsymbol.c +++ b/dmd/dsymbol.c @@ -1,1007 +1,1007 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "mem.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 "../gen/enums.h" - -/****************************** Dsymbol ******************************/ - -Dsymbol::Dsymbol() -{ - //printf("Dsymbol::Dsymbol(%p)\n", this); - this->ident = NULL; - this->c_ident = NULL; - this->parent = NULL; - this->csym = NULL; - this->isym = NULL; - this->loc = 0; - this->comment = NULL; - - this->llvmInternal = LLVMnone; - this->llvmInternal1 = NULL; - this->llvmInternal2 = NULL; -} - -Dsymbol::Dsymbol(Identifier *ident) -{ - //printf("Dsymbol::Dsymbol(%p, ident)\n", this); - this->ident = ident; - this->c_ident = NULL; - this->parent = NULL; - this->csym = NULL; - this->isym = NULL; - this->loc = 0; - this->comment = NULL; - - this->llvmInternal = LLVMnone; - this->llvmInternal1 = NULL; - this->llvmInternal2 = NULL; -} - -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(Array *members, Dsymbol **ps) -{ - //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); - Dsymbol *s = NULL; - - if (members) - { - for (int i = 0; i < members->dim; i++) - { Dsymbol *sx = (Dsymbol *)members->data[i]; - - int x = sx->oneMember(ps); - //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); - if (!x) - { - //printf("\tfalse 1\n"); - assert(*ps == NULL); - return FALSE; - } - if (*ps) - { - if (s) // more than one symbol - { *ps = NULL; - //printf("\tfalse 2\n"); - return FALSE; - } - s = *ps; - } - } - } - *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; -} - -char *Dsymbol::toChars() -{ - return ident ? ident->toChars() : (char *)"__anonymous"; -} - -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--; - *q = '.'; - } - return s; -} - -char *Dsymbol::locToChars() -{ - OutBuffer buf; - char *p; - - Module *m = getModule(); - - if (m && m->srcfile) - loc.filename = m->srcfile->toChars(); - return loc.toChars(); -} - -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; -} - - -int Dsymbol::isAnonymous() -{ - return ident ? 0 : 1; -} - -void Dsymbol::semantic(Scope *sc) -{ - error("%p has no semantic routine", this); -} - -void Dsymbol::semantic2(Scope *sc) -{ - // Most Dsymbols have no further semantic analysis needed -} - -void Dsymbol::semantic3(Scope *sc) -{ - // Most Dsymbols have no further semantic analysis needed -} - -void Dsymbol::inlineScan() -{ - // Most Dsymbols have no further semantic analysis needed -} - -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 identifier id as a member of 'this'. - * id may be a template instance. - * Returns: - * symbol found, NULL if not - */ - -Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) -{ - //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); - Dsymbol *s = toAlias(); - Dsymbol *sm; - - switch (id->dyncast()) - { - case DYNCAST_IDENTIFIER: - sm = s->search(loc, id, 0); - break; - - case DYNCAST_DSYMBOL: - { // It's a template instance - //printf("\ttemplate instance id\n"); - Dsymbol *st = (Dsymbol *)id; - TemplateInstance *ti = st->isTemplateInstance(); - id = ti->name; - sm = s->search(loc, id, 0); - if (!sm) - { error("template identifier %s is not a member of %s %s", - id->toChars(), s->kind(), s->toChars()); - return NULL; - } - sm = sm->toAlias(); - TemplateDeclaration *td = sm->isTemplateDeclaration(); - if (!td) - { - error("%s is not a template, it is a %s", id->toChars(), sm->kind()); - return NULL; - } - ti->tempdecl = td; - if (!ti->semanticdone) - 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; -} - -LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? -{ - return NULL; -} - -AggregateDeclaration *Dsymbol::isMember() // is this a member of an AggregateDeclaration? -{ - Dsymbol *parent = toParent(); - return parent ? parent->isAggregateDeclaration() : NULL; -} - -Type *Dsymbol::getType() -{ - return NULL; -} - -int Dsymbol::needThis() -{ - return FALSE; -} - -int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("Dsymbol::addMember('%s')\n", toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab); - parent = sd; - if (!isAnonymous()) // no name, so can't add it to symbol table - { - if (!sd->symtab->insert(this)) // if name is already defined - { - Dsymbol *s2; - - s2 = sd->symtab->lookup(ident); - if (!s2->overloadInsert(this)) - { - sd->multiplyDefined(0, this, s2); - } - } - if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) - { - if (ident == Id::__sizeof || ident == Id::alignof || ident == Id::mangleof) - error(".%s property cannot be redefined", ident->toChars()); - } - return 1; - } - return 0; -} - -void Dsymbol::error(const char *format, ...) -{ - //printf("Dsymbol::error()\n"); - if (!global.gag) - { - char *p = locToChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - if (isAnonymous()) - fprintf(stdmsg, "%s ", kind()); - else - fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); - - va_list ap; - va_start(ap, format); - vfprintf(stdmsg, format, ap); - va_end(ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - } - global.errors++; - - //fatal(); -} - -void Dsymbol::error(Loc loc, const char *format, ...) -{ - if (!global.gag) - { - char *p = loc.toChars(); - if (!*p) - p = locToChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); - - va_list ap; - va_start(ap, format); - vfprintf(stdmsg, format, ap); - va_end(ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - } - - global.errors++; - - //fatal(); -} - -void Dsymbol::checkDeprecated(Loc loc, Scope *sc) -{ - if (!global.params.useDeprecated && isDeprecated()) - { - // Don't complain if we're inside a deprecated symbol's scope - for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) - { if (sp->isDeprecated()) - return; - } - - for (; sc; sc = sc->enclosing) - { - if (sc->scopesym && sc->scopesym->isDeprecated()) - return; - } - - error(loc, "is deprecated"); - } -} - -/********************************** - * Determine which Module a Dsymbol is in. - */ - -Module *Dsymbol::getModule() -{ - Module *m; - Dsymbol *s; - - //printf("Dsymbol::getModule()\n"); - s = this; - while (s) - { - //printf("\ts = '%s'\n", s->toChars()); - m = s->isModule(); - if (m) - return m; - s = s->parent; - } - return NULL; -} - -/************************************* - */ - -enum PROT Dsymbol::prot() -{ - return PROTpublic; -} - -/************************************* - * Do syntax copy of an array of Dsymbol's. - */ - - -Array *Dsymbol::arraySyntaxCopy(Array *a) -{ - - Array *b = NULL; - if (a) - { - b = a->copy(); - for (int i = 0; i < b->dim; i++) - { - Dsymbol *s = (Dsymbol *)b->data[i]; - - s = s->syntaxCopy(NULL); - b->data[i] = (void *)s; - } - } - 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 -} - - -/********************************* 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) -{ Dsymbol *s; - int i; - - //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); - // Look in symbols declared in this module - s = symtab ? symtab->lookup(ident) : NULL; - if (s) - { - //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); - } - else if (imports) - { - // Look in imported modules - for (i = 0; i < imports->dim; i++) - { ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i]; - Dsymbol *s2; - - // If private import, don't search it - if (flags & 1 && prots[i] == PROTprivate) - continue; - - //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); - s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); - if (!s) - s = s2; - else if (s2 && s != s2) - { - if (s->toAlias() == s2->toAlias()) - { - 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)) - ) - ) - ) - { - ss->multiplyDefined(loc, s, s2); - break; - } - } - } - } - if (s) - { - Declaration *d = s->isDeclaration(); - if (d && d->protection == PROTprivate && !d->parent->isTemplateMixin()) - error("%s is private", d->toPrettyChars()); - } - } - return s; -} - -void ScopeDsymbol::importScope(ScopeDsymbol *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 Array(); - else - { - for (int i = 0; i < imports->dim; i++) - { ScopeDsymbol *ss; - - ss = (ScopeDsymbol *) imports->data[i]; - if (ss == s) - { - 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; -} - -char *ScopeDsymbol::kind() -{ - return "ScopeDsymbol"; -} - - -/******************************************* - * Look for member of the form: - * const(MemberInfo)[] getMembers(string); - * Returns NULL if not found - */ - -#if V2 -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; - Arguments *arguments = new Arguments; - Arguments *arg = new Argument(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) - { - 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) - { - 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) - { - IndexExp *ie = (IndexExp *)exp; - - pvar = &ie->lengthVar; - ce = ie->e1; - } - else if (exp->op == TOKslice) - { - SliceExp *se = (SliceExp *)exp; - - pvar = &se->lengthVar; - ce = se->e1; - } - else - return NULL; - - if (ce->op == TOKtype) - { - Type *t = ((TypeExp *)ce)->type; - if (t->ty == Ttuple) - { type = (TypeTuple *)t; - goto L1; - } - } - - if (!*pvar) - { - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - - if (ce->op == TOKstring) - { /* It is for a string literal, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((StringExp *)ce)->len, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCconst; - } - else if (ce->op == TOKarrayliteral) - { /* It is for an array literal, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((ArrayLiteralExp *)ce)->elements->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCconst; - } - else if (ce->op == TOKtuple) - { /* It is for an expression tuple, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCconst; - } - *pvar = v; - } - return (*pvar); - } - return NULL; -} - - -/****************************** DsymbolTable ******************************/ - -DsymbolTable::DsymbolTable() -{ - tab = new StringTable; -} - -DsymbolTable::~DsymbolTable() -{ - delete tab; -} - -Dsymbol *DsymbolTable::lookup(Identifier *ident) -{ StringValue *sv; - -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - sv = tab->lookup((char*)ident->string, ident->len); - return (Dsymbol *)(sv ? sv->ptrvalue : NULL); -} - -Dsymbol *DsymbolTable::insert(Dsymbol *s) -{ StringValue *sv; - Identifier *ident; - - //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); - ident = s->ident; -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -} - -Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) -{ StringValue *sv; - - //printf("DsymbolTable::insert()\n"); - sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -} - -Dsymbol *DsymbolTable::update(Dsymbol *s) -{ StringValue *sv; - Identifier *ident; - - ident = s->ident; - sv = tab->update(ident->toChars(), ident->len); - sv->ptrvalue = s; - return s; -} - - - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include + +#include "mem.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 "../gen/enums.h" + +/****************************** Dsymbol ******************************/ + +Dsymbol::Dsymbol() +{ + //printf("Dsymbol::Dsymbol(%p)\n", this); + this->ident = NULL; + this->c_ident = NULL; + this->parent = NULL; + this->csym = NULL; + this->isym = NULL; + this->loc = 0; + this->comment = NULL; + + this->llvmInternal = LLVMnone; + this->llvmInternal1 = NULL; + this->llvmInternal2 = NULL; +} + +Dsymbol::Dsymbol(Identifier *ident) +{ + //printf("Dsymbol::Dsymbol(%p, ident)\n", this); + this->ident = ident; + this->c_ident = NULL; + this->parent = NULL; + this->csym = NULL; + this->isym = NULL; + this->loc = 0; + this->comment = NULL; + + this->llvmInternal = LLVMnone; + this->llvmInternal1 = NULL; + this->llvmInternal2 = NULL; +} + +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(Array *members, Dsymbol **ps) +{ + //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); + Dsymbol *s = NULL; + + if (members) + { + for (int i = 0; i < members->dim; i++) + { Dsymbol *sx = (Dsymbol *)members->data[i]; + + int x = sx->oneMember(ps); + //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); + if (!x) + { + //printf("\tfalse 1\n"); + assert(*ps == NULL); + return FALSE; + } + if (*ps) + { + if (s) // more than one symbol + { *ps = NULL; + //printf("\tfalse 2\n"); + return FALSE; + } + s = *ps; + } + } + } + *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; +} + +char *Dsymbol::toChars() +{ + return ident ? ident->toChars() : (char *)"__anonymous"; +} + +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--; + *q = '.'; + } + return s; +} + +char *Dsymbol::locToChars() +{ + OutBuffer buf; + char *p; + + Module *m = getModule(); + + if (m && m->srcfile) + loc.filename = m->srcfile->toChars(); + return loc.toChars(); +} + +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; +} + + +int Dsymbol::isAnonymous() +{ + return ident ? 0 : 1; +} + +void Dsymbol::semantic(Scope *sc) +{ + error("%p has no semantic routine", this); +} + +void Dsymbol::semantic2(Scope *sc) +{ + // Most Dsymbols have no further semantic analysis needed +} + +void Dsymbol::semantic3(Scope *sc) +{ + // Most Dsymbols have no further semantic analysis needed +} + +void Dsymbol::inlineScan() +{ + // Most Dsymbols have no further semantic analysis needed +} + +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 identifier id as a member of 'this'. + * id may be a template instance. + * Returns: + * symbol found, NULL if not + */ + +Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) +{ + //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); + Dsymbol *s = toAlias(); + Dsymbol *sm; + + switch (id->dyncast()) + { + case DYNCAST_IDENTIFIER: + sm = s->search(loc, id, 0); + break; + + case DYNCAST_DSYMBOL: + { // It's a template instance + //printf("\ttemplate instance id\n"); + Dsymbol *st = (Dsymbol *)id; + TemplateInstance *ti = st->isTemplateInstance(); + id = ti->name; + sm = s->search(loc, id, 0); + if (!sm) + { error("template identifier %s is not a member of %s %s", + id->toChars(), s->kind(), s->toChars()); + return NULL; + } + sm = sm->toAlias(); + TemplateDeclaration *td = sm->isTemplateDeclaration(); + if (!td) + { + error("%s is not a template, it is a %s", id->toChars(), sm->kind()); + return NULL; + } + ti->tempdecl = td; + if (!ti->semanticdone) + 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; +} + +LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? +{ + return NULL; +} + +AggregateDeclaration *Dsymbol::isMember() // is this a member of an AggregateDeclaration? +{ + Dsymbol *parent = toParent(); + return parent ? parent->isAggregateDeclaration() : NULL; +} + +Type *Dsymbol::getType() +{ + return NULL; +} + +int Dsymbol::needThis() +{ + return FALSE; +} + +int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("Dsymbol::addMember('%s')\n", toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab); + parent = sd; + if (!isAnonymous()) // no name, so can't add it to symbol table + { + if (!sd->symtab->insert(this)) // if name is already defined + { + Dsymbol *s2; + + s2 = sd->symtab->lookup(ident); + if (!s2->overloadInsert(this)) + { + sd->multiplyDefined(0, this, s2); + } + } + if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) + { + if (ident == Id::__sizeof || ident == Id::alignof || ident == Id::mangleof) + error(".%s property cannot be redefined", ident->toChars()); + } + return 1; + } + return 0; +} + +void Dsymbol::error(const char *format, ...) +{ + //printf("Dsymbol::error()\n"); + if (!global.gag) + { + char *p = locToChars(); + + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + if (isAnonymous()) + fprintf(stdmsg, "%s ", kind()); + else + fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); + + va_list ap; + va_start(ap, format); + vfprintf(stdmsg, format, ap); + va_end(ap); + + fprintf(stdmsg, "\n"); + fflush(stdmsg); + } + global.errors++; + + //fatal(); +} + +void Dsymbol::error(Loc loc, const char *format, ...) +{ + if (!global.gag) + { + char *p = loc.toChars(); + if (!*p) + p = locToChars(); + + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); + + va_list ap; + va_start(ap, format); + vfprintf(stdmsg, format, ap); + va_end(ap); + + fprintf(stdmsg, "\n"); + fflush(stdmsg); + } + + global.errors++; + + //fatal(); +} + +void Dsymbol::checkDeprecated(Loc loc, Scope *sc) +{ + if (!global.params.useDeprecated && isDeprecated()) + { + // Don't complain if we're inside a deprecated symbol's scope + for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) + { if (sp->isDeprecated()) + return; + } + + for (; sc; sc = sc->enclosing) + { + if (sc->scopesym && sc->scopesym->isDeprecated()) + return; + } + + error(loc, "is deprecated"); + } +} + +/********************************** + * Determine which Module a Dsymbol is in. + */ + +Module *Dsymbol::getModule() +{ + Module *m; + Dsymbol *s; + + //printf("Dsymbol::getModule()\n"); + s = this; + while (s) + { + //printf("\ts = '%s'\n", s->toChars()); + m = s->isModule(); + if (m) + return m; + s = s->parent; + } + return NULL; +} + +/************************************* + */ + +enum PROT Dsymbol::prot() +{ + return PROTpublic; +} + +/************************************* + * Do syntax copy of an array of Dsymbol's. + */ + + +Array *Dsymbol::arraySyntaxCopy(Array *a) +{ + + Array *b = NULL; + if (a) + { + b = a->copy(); + for (int i = 0; i < b->dim; i++) + { + Dsymbol *s = (Dsymbol *)b->data[i]; + + s = s->syntaxCopy(NULL); + b->data[i] = (void *)s; + } + } + 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 +} + + +/********************************* 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) +{ Dsymbol *s; + int i; + + //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); + // Look in symbols declared in this module + s = symtab ? symtab->lookup(ident) : NULL; + if (s) + { + //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); + } + else if (imports) + { + // Look in imported modules + for (i = 0; i < imports->dim; i++) + { ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i]; + Dsymbol *s2; + + // If private import, don't search it + if (flags & 1 && prots[i] == PROTprivate) + continue; + + //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); + s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); + if (!s) + s = s2; + else if (s2 && s != s2) + { + if (s->toAlias() == s2->toAlias()) + { + 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)) + ) + ) + ) + { + ss->multiplyDefined(loc, s, s2); + break; + } + } + } + } + if (s) + { + Declaration *d = s->isDeclaration(); + if (d && d->protection == PROTprivate && !d->parent->isTemplateMixin()) + error("%s is private", d->toPrettyChars()); + } + } + return s; +} + +void ScopeDsymbol::importScope(ScopeDsymbol *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 Array(); + else + { + for (int i = 0; i < imports->dim; i++) + { ScopeDsymbol *ss; + + ss = (ScopeDsymbol *) imports->data[i]; + if (ss == s) + { + 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; +} + +char *ScopeDsymbol::kind() +{ + return "ScopeDsymbol"; +} + + +/******************************************* + * Look for member of the form: + * const(MemberInfo)[] getMembers(string); + * Returns NULL if not found + */ + +#if V2 +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; + Arguments *arguments = new Arguments; + Arguments *arg = new Argument(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) + { + 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) + { + 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) + { + IndexExp *ie = (IndexExp *)exp; + + pvar = &ie->lengthVar; + ce = ie->e1; + } + else if (exp->op == TOKslice) + { + SliceExp *se = (SliceExp *)exp; + + pvar = &se->lengthVar; + ce = se->e1; + } + else + return NULL; + + if (ce->op == TOKtype) + { + Type *t = ((TypeExp *)ce)->type; + if (t->ty == Ttuple) + { type = (TypeTuple *)t; + goto L1; + } + } + + if (!*pvar) + { + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + + if (ce->op == TOKstring) + { /* It is for a string literal, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((StringExp *)ce)->len, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCconst; + } + else if (ce->op == TOKarrayliteral) + { /* It is for an array literal, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((ArrayLiteralExp *)ce)->elements->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCconst; + } + else if (ce->op == TOKtuple) + { /* It is for an expression tuple, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCconst; + } + *pvar = v; + } + return (*pvar); + } + return NULL; +} + + +/****************************** DsymbolTable ******************************/ + +DsymbolTable::DsymbolTable() +{ + tab = new StringTable; +} + +DsymbolTable::~DsymbolTable() +{ + delete tab; +} + +Dsymbol *DsymbolTable::lookup(Identifier *ident) +{ StringValue *sv; + +#ifdef DEBUG + assert(ident); + assert(tab); +#endif + sv = tab->lookup((char*)ident->string, ident->len); + return (Dsymbol *)(sv ? sv->ptrvalue : NULL); +} + +Dsymbol *DsymbolTable::insert(Dsymbol *s) +{ StringValue *sv; + Identifier *ident; + + //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); + ident = s->ident; +#ifdef DEBUG + assert(ident); + assert(tab); +#endif + sv = tab->insert(ident->toChars(), ident->len); + if (!sv) + return NULL; // already in table + sv->ptrvalue = s; + return s; +} + +Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) +{ StringValue *sv; + + //printf("DsymbolTable::insert()\n"); + sv = tab->insert(ident->toChars(), ident->len); + if (!sv) + return NULL; // already in table + sv->ptrvalue = s; + return s; +} + +Dsymbol *DsymbolTable::update(Dsymbol *s) +{ StringValue *sv; + Identifier *ident; + + ident = s->ident; + sv = tab->update(ident->toChars(), ident->len); + sv->ptrvalue = s; + return s; +} + + + + diff --git a/dmd/dsymbol.h b/dmd/dsymbol.h index b6691d32..541d299f 100644 --- a/dmd/dsymbol.h +++ b/dmd/dsymbol.h @@ -1,298 +1,299 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_DSYMBOL_H -#define DMD_DSYMBOL_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "stringtable.h" - -#include "mars.h" -#include "arraytypes.h" - -struct Identifier; -struct Scope; -struct DsymbolTable; -struct Declaration; -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 DtorDeclaration; -struct StaticCtorDeclaration; -struct StaticDtorDeclaration; -struct InvariantDeclaration; -struct UnitTestDeclaration; -struct NewDeclaration; -struct VarDeclaration; -struct AttribDeclaration; -struct Symbol; -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 SymbolDeclaration; -struct Expression; -struct DeleteDeclaration; -struct HdrGenState; -struct TypeInfoDeclaration; -struct ClassInfoDeclaration; - -#if IN_GCC -union tree_node; -typedef union tree_node TYPE; -#else -struct TYPE; -#endif - -#if IN_LLVM -namespace llvm -{ - class Value; -} -#endif - -enum PROT -{ - PROTundefined, - PROTnone, // no access - PROTprivate, - PROTpackage, - PROTprotected, - PROTpublic, - PROTexport, -}; - -struct Dsymbol : Object -{ - Identifier *ident; - Identifier *c_ident; - Dsymbol *parent; - Symbol *csym; // symbol for code generator - Symbol *isym; // import version of csym - unsigned char *comment; // documentation comment for this Dsymbol - Loc loc; // where defined - - Dsymbol(); - Dsymbol(Identifier *); - char *toChars(); - char *toPrettyChars(); - char *locToChars(); - int equals(Object *o); - int isAnonymous(); - void error(Loc loc, const char *format, ...); - void error(const char *format, ...); - void checkDeprecated(Loc loc, Scope *sc); - Module *getModule(); - Dsymbol *pastMixin(); - Dsymbol *toParent(); - Dsymbol *toParent2(); - - int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() - - static Array *arraySyntaxCopy(Array *a); - - virtual char *kind(); - virtual Dsymbol *toAlias(); // resolve real symbol - virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - 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 *searchX(Loc loc, Scope *sc, Identifier *id); - virtual int overloadInsert(Dsymbol *s); -#ifdef _DH - char *toHChars(); - virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs); -#endif - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toDocBuffer(OutBuffer *buf); - virtual unsigned size(Loc loc); - virtual int isforwardRef(); - virtual void defineRef(Dsymbol *s); - virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member - virtual ClassDeclaration *isClassMember(); // are we a member of a class? - virtual int isExport(); // is Dsymbol exported? - virtual int isImportedSymbol(); // is Dsymbol imported? - virtual int isDeprecated(); // is Dsymbol deprecated? - virtual 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(Array *members, Dsymbol **ps); - virtual int hasPointers(); - virtual void addLocalClass(ClassDeclarations *) { } - virtual void checkCtorConstInit() { } - - virtual void addComment(unsigned char *comment); - virtual void emitComment(Scope *sc); - void emitDitto(Scope *sc); - - // Backend - - virtual Symbol *toSymbol(); // to backend symbol - virtual void toObjFile(); // 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 - - // 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 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 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; } -#ifdef _DH - virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } -#endif - virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; } - virtual AttribDeclaration *isAttribDeclaration() { return NULL; } - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } - virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } - - // llvm stuff - int llvmInternal; - char* llvmInternal1; - char* llvmInternal2; -}; - -// Dsymbol that generates a scope - -struct ScopeDsymbol : Dsymbol -{ - Array *members; // all Dsymbol's in this scope - DsymbolTable *symtab; // members[] sorted into table - - Array *imports; // imported ScopeDsymbol's - unsigned char *prots; // PROT for each import - - ScopeDsymbol(); - ScopeDsymbol(Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - void importScope(ScopeDsymbol *s, enum PROT protection); - int isforwardRef(); - void defineRef(Dsymbol *s); - static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); - Dsymbol *nameCollision(Dsymbol *s); - char *kind(); - - void emitMemberComments(Scope *sc); - - 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 - - ArrayScopeSymbol(Expression *e); - ArrayScopeSymbol(TypeTuple *t); - ArrayScopeSymbol(TupleDeclaration *td); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - - ArrayScopeSymbol *isArrayScopeSymbol() { return this; } -}; - -// Table of Dsymbol's - -struct DsymbolTable : Object -{ - StringTable *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 */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_DSYMBOL_H +#define DMD_DSYMBOL_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "stringtable.h" + +#include "mars.h" +#include "arraytypes.h" + +struct Identifier; +struct Scope; +struct DsymbolTable; +struct Declaration; +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 DtorDeclaration; +struct StaticCtorDeclaration; +struct StaticDtorDeclaration; +struct InvariantDeclaration; +struct UnitTestDeclaration; +struct NewDeclaration; +struct VarDeclaration; +struct AttribDeclaration; +struct Symbol; +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 SymbolDeclaration; +struct Expression; +struct DeleteDeclaration; +struct HdrGenState; +struct TypeInfoDeclaration; +struct ClassInfoDeclaration; + +#if IN_GCC +union tree_node; +typedef union tree_node TYPE; +#else +struct TYPE; +#endif + +#if IN_LLVM +namespace llvm +{ + class Value; +} +#endif + +enum PROT +{ + PROTundefined, + PROTnone, // no access + PROTprivate, + PROTpackage, + PROTprotected, + PROTpublic, + PROTexport, +}; + + +struct Dsymbol : Object +{ + Identifier *ident; + Identifier *c_ident; + Dsymbol *parent; + Symbol *csym; // symbol for code generator + Symbol *isym; // import version of csym + unsigned char *comment; // documentation comment for this Dsymbol + Loc loc; // where defined + + Dsymbol(); + Dsymbol(Identifier *); + char *toChars(); + char *toPrettyChars(); + char *locToChars(); + int equals(Object *o); + int isAnonymous(); + void error(Loc loc, const char *format, ...); + void error(const char *format, ...); + void checkDeprecated(Loc loc, Scope *sc); + Module *getModule(); + Dsymbol *pastMixin(); + Dsymbol *toParent(); + Dsymbol *toParent2(); + + int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() + + static Array *arraySyntaxCopy(Array *a); + + virtual char *kind(); + virtual Dsymbol *toAlias(); // resolve real symbol + virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + 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 *searchX(Loc loc, Scope *sc, Identifier *id); + virtual int overloadInsert(Dsymbol *s); +#ifdef _DH + char *toHChars(); + virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs); +#endif + virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual void toDocBuffer(OutBuffer *buf); + virtual unsigned size(Loc loc); + virtual int isforwardRef(); + virtual void defineRef(Dsymbol *s); + virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member + virtual ClassDeclaration *isClassMember(); // are we a member of a class? + virtual int isExport(); // is Dsymbol exported? + virtual int isImportedSymbol(); // is Dsymbol imported? + virtual int isDeprecated(); // is Dsymbol deprecated? + virtual 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(Array *members, Dsymbol **ps); + virtual int hasPointers(); + virtual void addLocalClass(ClassDeclarations *) { } + virtual void checkCtorConstInit() { } + + virtual void addComment(unsigned char *comment); + virtual void emitComment(Scope *sc); + void emitDitto(Scope *sc); + + // Backend + + virtual Symbol *toSymbol(); // to backend symbol + virtual void toObjFile(); // 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 + + // 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 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 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; } +#ifdef _DH + virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } +#endif + virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; } + virtual AttribDeclaration *isAttribDeclaration() { return NULL; } + virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } + virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } + + // llvm stuff + int llvmInternal; + char* llvmInternal1; + char* llvmInternal2; +}; + +// Dsymbol that generates a scope + +struct ScopeDsymbol : Dsymbol +{ + Array *members; // all Dsymbol's in this scope + DsymbolTable *symtab; // members[] sorted into table + + Array *imports; // imported ScopeDsymbol's + unsigned char *prots; // PROT for each import + + ScopeDsymbol(); + ScopeDsymbol(Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *s); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + void importScope(ScopeDsymbol *s, enum PROT protection); + int isforwardRef(); + void defineRef(Dsymbol *s); + static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); + Dsymbol *nameCollision(Dsymbol *s); + char *kind(); + + void emitMemberComments(Scope *sc); + + 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 + + ArrayScopeSymbol(Expression *e); + ArrayScopeSymbol(TypeTuple *t); + ArrayScopeSymbol(TupleDeclaration *td); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + + ArrayScopeSymbol *isArrayScopeSymbol() { return this; } +}; + +// Table of Dsymbol's + +struct DsymbolTable : Object +{ + StringTable *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/expression.c b/dmd/expression.c index 49268cfe..2ba77b18 100644 --- a/dmd/expression.c +++ b/dmd/expression.c @@ -1,8663 +1,8689 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include -#include - -#if _WIN32 && __DMC__ -extern "C" char * __cdecl __locale_decpoint; -#endif - -#if IN_GCC -// Issues with using -include total.h (defines integer_t) and then complex.h fails... -#undef integer_t -#endif - -#ifdef __APPLE__ -#define integer_t dmd_integer_t -#endif - -#if IN_GCC || IN_LLVM -#include "mem.h" -#elif _WIN32 -#include "..\root\mem.h" -#elif linux -#include "../root/mem.h" -#endif - -//#include "port.h" -#include "mtype.h" -#include "init.h" -#include "expression.h" -#include "template.h" -#include "utf.h" -#include "enum.h" -#include "scope.h" -#include "statement.h" -#include "declaration.h" -#include "aggregate.h" -#include "import.h" -#include "id.h" -#include "dsymbol.h" -#include "module.h" -#include "attrib.h" -#include "hdrgen.h" -#include "parse.h" - -Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim); - -#define LOGSEMANTIC 0 - -/********************************** - * Set operator precedence for each operator. - */ - -// Operator precedence - greater values are higher precedence - -enum PREC -{ - PREC_zero, - PREC_expr, - PREC_assign, - PREC_cond, - PREC_oror, - PREC_andand, - PREC_or, - PREC_xor, - PREC_and, - PREC_equal, - PREC_rel, - PREC_shift, - PREC_add, - PREC_mul, - PREC_unary, - PREC_primary, -}; - -enum PREC precedence[TOKMAX]; - -void initPrecedence() -{ - precedence[TOKimport] = PREC_primary; - precedence[TOKidentifier] = PREC_primary; - precedence[TOKthis] = PREC_primary; - precedence[TOKsuper] = PREC_primary; - precedence[TOKint64] = PREC_primary; - precedence[TOKfloat64] = PREC_primary; - precedence[TOKnull] = PREC_primary; - precedence[TOKstring] = PREC_primary; - precedence[TOKarrayliteral] = PREC_primary; - precedence[TOKtypedot] = PREC_primary; - precedence[TOKtypeid] = PREC_primary; - precedence[TOKis] = PREC_primary; - precedence[TOKassert] = PREC_primary; - precedence[TOKfunction] = PREC_primary; - precedence[TOKvar] = PREC_primary; - - // post - precedence[TOKdotti] = PREC_primary; - precedence[TOKdot] = PREC_primary; -// precedence[TOKarrow] = PREC_primary; - precedence[TOKplusplus] = PREC_primary; - precedence[TOKminusminus] = PREC_primary; - precedence[TOKcall] = PREC_primary; - precedence[TOKslice] = PREC_primary; - precedence[TOKarray] = PREC_primary; - - precedence[TOKaddress] = PREC_unary; - precedence[TOKstar] = PREC_unary; - precedence[TOKneg] = PREC_unary; - precedence[TOKuadd] = PREC_unary; - precedence[TOKnot] = PREC_unary; - precedence[TOKtobool] = PREC_add; - precedence[TOKtilde] = PREC_unary; - precedence[TOKdelete] = PREC_unary; - precedence[TOKnew] = PREC_unary; - precedence[TOKcast] = PREC_unary; - - precedence[TOKmul] = PREC_mul; - precedence[TOKdiv] = PREC_mul; - precedence[TOKmod] = PREC_mul; - - precedence[TOKadd] = PREC_add; - precedence[TOKmin] = PREC_add; - precedence[TOKcat] = PREC_add; - - precedence[TOKshl] = PREC_shift; - precedence[TOKshr] = PREC_shift; - precedence[TOKushr] = PREC_shift; - - precedence[TOKlt] = PREC_rel; - precedence[TOKle] = PREC_rel; - precedence[TOKgt] = PREC_rel; - precedence[TOKge] = PREC_rel; - precedence[TOKunord] = PREC_rel; - precedence[TOKlg] = PREC_rel; - precedence[TOKleg] = PREC_rel; - precedence[TOKule] = PREC_rel; - precedence[TOKul] = PREC_rel; - precedence[TOKuge] = PREC_rel; - precedence[TOKug] = PREC_rel; - precedence[TOKue] = PREC_rel; - precedence[TOKin] = PREC_rel; - - precedence[TOKequal] = PREC_equal; - precedence[TOKnotequal] = PREC_equal; - precedence[TOKidentity] = PREC_equal; - precedence[TOKnotidentity] = PREC_equal; - - 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[TOKaddass] = PREC_assign; - precedence[TOKminass] = PREC_assign; - precedence[TOKcatass] = PREC_assign; - precedence[TOKmulass] = PREC_assign; - precedence[TOKdivass] = PREC_assign; - precedence[TOKmodass] = PREC_assign; - precedence[TOKshlass] = PREC_assign; - precedence[TOKshrass] = PREC_assign; - precedence[TOKushrass] = PREC_assign; - precedence[TOKandass] = PREC_assign; - precedence[TOKorass] = PREC_assign; - precedence[TOKxorass] = PREC_assign; - - precedence[TOKcomma] = PREC_expr; -} - -/***************************************** - * Determine if 'this' is available. - * If it is, return the FuncDeclaration that has it. - */ - -FuncDeclaration *hasThis(Scope *sc) -{ FuncDeclaration *fd; - FuncDeclaration *fdthis; - - //printf("hasThis()\n"); - fdthis = sc->parent->isFuncDeclaration(); - //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : ""); - - // Go upwards until we find the enclosing member function - fd = fdthis; - while (1) - { - if (!fd) - { - goto Lno; - } - if (!fd->isNested()) - break; - - Dsymbol *parent = fd->parent; - while (parent) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - parent = ti->parent; - else - break; - } - - fd = fd->parent->isFuncDeclaration(); - } - - if (!fd->isThis()) - { //printf("test '%s'\n", fd->toChars()); - goto Lno; - } - - assert(fd->vthis); - return fd; - -Lno: - return NULL; // don't have 'this' available -} - - -/*************************************** - * Pull out any properties. - */ - -Expression *resolveProperties(Scope *sc, Expression *e) -{ - //printf("resolveProperties(%s)\n", e->toChars()); - if (e->type) - { - Type *t = e->type->toBasetype(); - - if (t->ty == Tfunction) - { - e = 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 e; -} - -/****************************** - * Perform semantic() on an array of Expressions. - */ - -void arrayExpressionSemantic(Expressions *exps, Scope *sc) -{ - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - e = e->semantic(sc); - exps->data[i] = (void *)e; - } - } -} - -/**************************************** - * Expand tuples. - */ - -void expandTuples(Expressions *exps) -{ - //printf("expandTuples()\n"); - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *arg = (Expression *)exps->data[i]; - if (!arg) - continue; - - // Look for tuple with 0 members - if (arg->op == TOKtype) - { TypeExp *e = (TypeExp *)arg; - if (e->type->toBasetype()->ty == Ttuple) - { TypeTuple *tt = (TypeTuple *)e->type->toBasetype(); - - if (!tt->arguments || tt->arguments->dim == 0) - { - exps->remove(i); - if (i == exps->dim) - return; - i--; - continue; - } - } - } - - // Inline expand all the tuples - while (arg->op == TOKtuple) - { TupleExp *te = (TupleExp *)arg; - - exps->remove(i); // remove arg - exps->insert(i, te->exps); // replace with tuple contents - if (i == exps->dim) - return; // empty tuple, no more arguments - arg = (Expression *)exps->data[i]; - } - } - } -} - -/**************************************** - * Preprocess arguments to function. - */ - -void preFunctionArguments(Loc loc, Scope *sc, Expressions *exps) -{ - if (exps) - { - expandTuples(exps); - - for (size_t i = 0; i < exps->dim; i++) - { Expression *arg = (Expression *)exps->data[i]; - - if (!arg->type) - { -#ifdef DEBUG - if (!global.gag) - printf("1: \n"); -#endif - arg->error("%s is not an expression", arg->toChars()); - arg = new IntegerExp(arg->loc, 0, Type::tint32); - } - - arg = resolveProperties(sc, arg); - exps->data[i] = (void *) arg; - - //arg->rvalue(); -#if 0 - if (arg->type->ty == Tfunction) - { - arg = new AddrExp(arg->loc, arg); - arg = arg->semantic(sc); - exps->data[i] = (void *) arg; - } -#endif - } - } -} - - -/**************************************** - * 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 functionArguments(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments) -{ - unsigned n; - int done; - Type *tb; - - //printf("functionArguments()\n"); - assert(arguments); - size_t nargs = arguments ? arguments->dim : 0; - size_t nparams = Argument::dim(tf->parameters); - - if (nargs > nparams && tf->varargs == 0) - error(loc, "expected %zu arguments, not %zu", nparams, nargs); - - n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) - - done = 0; - for (size_t i = 0; i < n; i++) - { - Expression *arg; - - if (i < nargs) - arg = (Expression *)arguments->data[i]; - else - arg = NULL; - - if (i < nparams) - { - Argument *p = Argument::getNth(tf->parameters, i); - - if (!arg) - { - if (!p->defaultArg) - { - if (tf->varargs == 2 && i + 1 == nparams) - goto L2; - error(loc, "expected %zu arguments, not %zu", nparams, nargs); - break; - } - arg = p->defaultArg->copy(); - arguments->push(arg); - nargs++; - } - - if (tf->varargs == 2 && i + 1 == nparams) - { - //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars()); - if (arg->implicitConvTo(p->type)) - { - if (nargs != nparams) - error(loc, "expected %zu arguments, not %zu", nparams, nargs); - goto L1; - } - L2: - Type *tb = p->type->toBasetype(); - Type *tret = p->isLazyArray(); - switch (tb->ty) - { - case Tsarray: - case Tarray: - { // Create a static array variable v of type arg->type -#ifdef IN_GCC - /* GCC 4.0 does not like zero length arrays used like - this; pass a null array value instead. Could also - just make a one-element array. */ - if (nargs - i == 0) - { - arg = new NullExp(loc); - break; - } -#endif - static int idn; - char name[10 + sizeof(idn)*3 + 1]; - sprintf(name, "__arrayArg%d", ++idn); - Identifier *id = Lexer::idPool(name); - Type *t = new TypeSArray(tb->next, new IntegerExp(nargs - i)); - t = t->semantic(loc, sc); - VarDeclaration *v = new VarDeclaration(loc, t, id, new VoidInitializer(loc)); - v->semantic(sc); - v->parent = sc->parent; - //sc->insert(v); - - Expression *c = new DeclarationExp(0, v); - c->type = v->type; - - for (size_t u = i; u < nargs; u++) - { Expression *a = (Expression *)arguments->data[u]; - if (tret && !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)); - e = new AssignExp(loc, e, a); - if (c) - c = new CommaExp(loc, c, e); - else - c = e; - } - 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)) - arg = arg->implicitCastTo(sc, p->type); - 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()); - } - - // Convert static arrays to pointers - tb = arg->type->toBasetype(); - if (tb->ty == Tsarray) - { - arg = arg->checkToPointer(); - } - - // Convert lazy argument to a delegate - if (p->storageClass & STClazy) - { - arg = arg->toDelegate(sc, p->type); - } - } - else - { - - // If not D linkage, do promotions - if (tf->linkage != LINKd) - { - // Promote bytes, words, etc., to ints - arg = arg->integralPromotions(sc); - - // Promote floats to doubles - switch (arg->type->ty) - { - case Tfloat32: - arg = arg->castTo(sc, Type::tfloat64); - break; - - case Timaginary32: - arg = arg->castTo(sc, Type::timaginary64); - break; - } - } - - // Convert static arrays to dynamic arrays - tb = arg->type->toBasetype(); - if (tb->ty == Tsarray) - { TypeSArray *ts = (TypeSArray *)tb; - Type *ta = tb->next->arrayOf(); - if (ts->size(arg->loc) == 0) - { arg = new NullExp(arg->loc); - arg->type = ta; - } - else - arg = arg->castTo(sc, ta); - } - - arg->rvalue(); - } - arg = arg->optimize(WANTvalue); - arguments->data[i] = (void *) arg; - if (done) - break; - } - -#if !IN_LLVM - // If D linkage and variadic, add _arguments[] as first argument - if (tf->linkage == LINKd && tf->varargs == 1) - { - Expression *e; - - e = createTypeInfoArray(sc, (Expression **)&arguments->data[nparams], - arguments->dim - nparams); - arguments->insert(0, e); - } -#endif -} - -/************************************************** - * Write expression out to buf, but wrap it - * in ( ) if its precedence is less than pr. - */ - -void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) -{ - if (precedence[e->op] < 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, NULL, hgs); - buf->write(&argbuf); - } - } -} - -/******************************** Expression **************************/ - -Expression::Expression(Loc loc, enum TOK op, int size) - : loc(loc) -{ - this->loc = loc; - this->op = op; - this->size = size; - type = NULL; -} - -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); - return (Expression *)memcpy(e, this, size); -} - -/************************** - * Semantically analyze Expression. - * Determine types, fold constants, etc. - */ - -Expression *Expression::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("Expression::semantic()\n"); -#endif - if (type) - type = type->semantic(loc, sc); - else - type = Type::tvoid; - return this; -} - -void Expression::print() -{ - fprintf(stdmsg, "%s\n", toChars()); - fflush(stdmsg); -} - -char *Expression::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - memset(&hgs, 0, sizeof(hgs)); - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); -} - -void Expression::error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); -} - -void Expression::rvalue() -{ - if (type && type->toBasetype()->ty == Tvoid) - { error("expression %s is void and has no value", toChars()); -#if 0 - dump(0); - halt(); -#endif - } -} - -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; -} - -integer_t Expression::toInteger() -{ - //printf("Expression %s\n", Token::toChars(op)); - error("Integer constant expression expected instead of %s", toChars()); - return 0; -} - -uinteger_t Expression::toUInteger() -{ - //printf("Expression %s\n", Token::toChars(op)); - return (uinteger_t)toInteger(); -} - -real_t Expression::toReal() -{ - error("Floating point constant expression expected instead of %s", toChars()); - return 0; -} - -real_t Expression::toImaginary() -{ - error("Floating point constant expression expected instead of %s", toChars()); - return 0; -} - -complex_t Expression::toComplex() -{ - error("Floating point constant expression expected instead of %s", toChars()); -#ifdef IN_GCC - return complex_t(real_t(0)); // %% nicer -#else - return 0; -#endif -} - -void Expression::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); -} - -void Expression::toMangleBuffer(OutBuffer *buf) -{ - error("expression %s is not a valid template value argument", toChars()); -} - -/******************************* - * Give error if we're not an lvalue. - * If we can, convert expression to be an lvalue. - */ - -Expression *Expression::toLvalue(Scope *sc, Expression *e) -{ - if (!e) - e = this; - else if (!loc.filename) - loc = e->loc; - error("%s is not an lvalue", e->toChars()); - return this; -} - -Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) -{ - // See if this expression is a modifiable lvalue (i.e. not const) - return toLvalue(sc, e); -} - -/************************************ - * Detect cases where pointers to the stack can 'escape' the - * lifetime of the stack frame. - */ - -void Expression::checkEscape() -{ -} - -void Expression::checkScalar() -{ - if (!type->isscalar()) - error("'%s' is not a scalar, it is a %s", toChars(), type->toChars()); -} - -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 IntegerExp(0); - } - return this; -} - -Expression *Expression::checkArithmetic() -{ - if (!type->isintegral() && !type->isfloating()) - { error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars()); - return new IntegerExp(0); - } - return this; -} - -void Expression::checkDeprecated(Scope *sc, Dsymbol *s) -{ - s->checkDeprecated(loc, sc); -} - -/******************************** - * 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 = tb->next->pointerTo(); - } - return e; -} - -/****************************** - * Take address of expression. - */ - -Expression *Expression::addressOf(Scope *sc) -{ - Expression *e; - - //printf("Expression::addressOf()\n"); - e = toLvalue(sc, NULL); - e = new AddrExp(loc, e); - e->type = type->pointerTo(); - return e; -} - -/****************************** - * If this is a reference, dereference it. - */ - -Expression *Expression::deref() -{ - //printf("Expression::deref()\n"); - if (type->ty == Treference) - { Expression *e; - - e = new PtrExp(loc, this); - e->type = 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; -} - -Expressions *Expression::arraySyntaxCopy(Expressions *exps) -{ Expressions *a = NULL; - - if (exps) - { - a = new Expressions(); - a->setDim(exps->dim); - for (int i = 0; i < a->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - e = e->syntaxCopy(); - a->data[i] = e; - } - } - return a; -} - -/******************************** IntegerExp **************************/ - -IntegerExp::IntegerExp(Loc loc, integer_t value, Type *type) - : Expression(loc, TOKint64, sizeof(IntegerExp)) -{ - //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : ""); - if (type && !type->isscalar()) - { - error("integral constant must be scalar type, not %s", type->toChars()); - type = Type::terror; - } - this->type = type; - this->value = value; -} - -IntegerExp::IntegerExp(integer_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 -} - -integer_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 Tpointer: - case Tdchar: - case Tuns32: value = (d_uns32) value; break; - case Tint64: value = (d_int64) value; break; - case Tuns64: value = (d_uns64) value; break; - - case Tenum: - { - TypeEnum *te = (TypeEnum *)t; - t = te->sym->memtype; - continue; - } - - case Ttypedef: - { - TypeTypedef *tt = (TypeTypedef *)t; - t = tt->sym->basetype; - continue; - } - - default: - print(); - type->print(); - assert(0); - break; - } - break; - } - return value; -} - -real_t IntegerExp::toReal() -{ - Type *t; - - toInteger(); - t = type->toBasetype(); - if (t->ty == Tuns64) - return (real_t)(d_uns64)value; - else - return (real_t)(d_int64)value; -} - -real_t IntegerExp::toImaginary() -{ - return (real_t) 0; -} - -complex_t IntegerExp::toComplex() -{ - return toReal(); -} - -int IntegerExp::isBool(int result) -{ - return result ? value != 0 : value == 0; -} - -Expression *IntegerExp::semantic(Scope *sc) -{ - if (!type) - { - // Determine what the type of this number is - integer_t number = value; - - if (number & 0x8000000000000000LL) - type = Type::tuns64; - else if (number & 0xFFFFFFFF80000000LL) - type = Type::tint64; - else - type = Type::tint32; - } - else - { 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) -{ - integer_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'", v); - break; - } - case Tchar: - if (v == '\'') - buf->writestring("'\\''"); - else if (isprint(v) && v != '\\') - buf->printf("'%c'", (int)v); - else - buf->printf("'\\x%02x'", (int)v); - break; - - case Tint8: - buf->writestring("cast(byte)"); - goto L2; - - case Tint16: - buf->writestring("cast(short)"); - goto L2; - - case Tint32: - L2: - buf->printf("%d", (int)v); - break; - - case Tuns8: - buf->writestring("cast(ubyte)"); - goto L3; - - case Tuns16: - buf->writestring("cast(ushort)"); - goto L3; - - case Tuns32: - L3: - buf->printf("%du", (unsigned)v); - break; - - case Tint64: - buf->printf("%jdL", v); - break; - - case Tuns64: - 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(')'); - goto L3; - - default: -#ifdef DEBUG - t->print(); -#endif - assert(0); - } - } - else if (v & 0x8000000000000000LL) - buf->printf("0x%jx", v); - else - buf->printf("%jd", v); -} - -void IntegerExp::toMangleBuffer(OutBuffer *buf) -{ - if ((sinteger_t)value < 0) - buf->printf("N%jd", -value); - else - buf->printf("%jd", value); -} - -/******************************** 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); -} - -integer_t RealExp::toInteger() -{ -#ifdef IN_GCC - return toReal().toInt(); -#else - return (sinteger_t) toReal(); -#endif -} - -uinteger_t RealExp::toUInteger() -{ -#ifdef IN_GCC - return (uinteger_t) toReal().toInt(); -#else - return (uinteger_t) toReal(); -#endif -} - -real_t RealExp::toReal() -{ - return type->isreal() ? value : 0; -} - -real_t RealExp::toImaginary() -{ - return type->isreal() ? 0 : value; -} - -complex_t RealExp::toComplex() -{ -#ifdef __DMC__ - return toReal() + toImaginary() * I; -#else - return complex_t(toReal(), toImaginary()); -#endif -} - -/******************************** - * Test to see if two reals are the same. - * Regard NaN's as equivalent. - * Regard +0 and -0 as different. - */ - -int RealEquals(real_t x1, real_t x2) -{ - return (isnan(x1) && 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 - buf->printf("%La", value); // ensure exact duplication - - if (type) - { - Type *t = type->toBasetype(); - switch (t->ty) - { - case Tfloat32: - case Timaginary32: - case Tcomplex32: - buf->writeByte('F'); - break; - - case Tfloat80: - case Timaginary80: - case Tcomplex80: - buf->writeByte('L'); - break; - - default: - break; - } - if (t->isimaginary()) - buf->writeByte('i'); - } -} - -void RealExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - floatToBuffer(buf, type, value); -} - -void realToMangleBuffer(OutBuffer *buf, real_t value) -{ - /* Rely on %A to get portable mangling. - * Must munge result to get only identifier characters. - * - * Possible values from %A => mangled result - * NAN => NAN - * -INF => NINF - * INF => INF - * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79 - * 0X1.9P+2 => 19P2 - */ - - if (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]; - -#ifdef IN_GCC - char buf1[sizeof(value) * 3 + 8 + 1]; - char buf2[sizeof(value) * 3 + 8 + 1]; - creall(value).format(buf1, sizeof(buf1)); - cimagl(value).format(buf2, sizeof(buf2)); - sprintf(buffer, "(%s+%si)", buf1, buf2); -#else - sprintf(buffer, "(%Lg+%Lgi)", creall(value), cimagl(value)); - assert(strlen(buffer) < sizeof(buffer)); -#endif - return mem.strdup(buffer); -} - -integer_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 it was a with class - 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 = t->next; - e = new 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); - } - // Look to see if f is really a function template - FuncDeclaration *f = s->isFuncDeclaration(); - if (f && f->parent) - { TemplateInstance *ti = f->parent->isTemplateInstance(); - - if (ti && - !ti->isTemplateMixin() && - (ti->name == f->ident || - ti->toAlias()->ident == f->ident) - && - ti->tempdecl && ti->tempdecl->onemember) - { - TemplateDeclaration *tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - e = new TemplateExp(loc, tempdecl); - e = e->semantic(sc); - return e; - } - } - e = new DsymbolExp(loc, s); - } - return e->semantic(sc); - } - error("undefined identifier %s", ident->toChars()); - type = Type::terror; - return this; -} - -char *IdentifierExp::toChars() -{ - return ident->toChars(); -} - -void IdentifierExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - buf->writestring(ident->toHChars2()); - else - buf->writestring(ident->toChars()); -} - -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; - Declaration *d; - ClassDeclaration *cd; - ClassDeclaration *thiscd = NULL; - Import *imp; - Package *pkg; - Type *t; - - //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); - //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind()); - if (type) - return this; - if (!s->isFuncDeclaration()) // functions are checked after overloading - checkDeprecated(sc, s); - s = s->toAlias(); - //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis()); - if (!s->isFuncDeclaration()) - checkDeprecated(sc, s); - - if (sc->func) - thiscd = sc->func->parent->isClassDeclaration(); - - // BUG: This should happen after overload resolution for functions, not before - if (s->needThis()) - { - if (hasThis(sc) /*&& !s->isFuncDeclaration()*/) - { - // 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 = e->semantic(sc); - return e; - } - v = s->isVarDeclaration(); - if (v) - { - //printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); - if (!type) - { type = v->type; - if (!v->type) - { error("forward reference of %s", v->toChars()); - type = Type::terror; - } - } - if (v->isConst() && type->toBasetype()->ty != Tsarray) - { - if (v->init) - { - if (v->inuse) - { - error("circular reference to '%s'", v->toChars()); - type = Type::tint32; - return this; - } - 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()); - 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) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, imp->pkg); - return ie->semantic(sc); - } - pkg = s->isPackage(); - if (pkg) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, pkg); - return ie->semantic(sc); - } - Module *mod = s->isModule(); - if (mod) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, mod); - return ie->semantic(sc); - } - - t = s->getType(); - if (t) - { - return new TypeExp(loc, t); - } - - TupleDeclaration *tup = s->isTupleDeclaration(); - if (tup) - { - e = new TupleExp(loc, tup); - e = e->semantic(sc); - return e; - } - - TemplateInstance *ti = s->isTemplateInstance(); - if (ti && !global.errors) - { if (!ti->semanticdone) - ti->semantic(sc); - s = ti->inst->toAlias(); - if (!s->isTemplateInstance()) - goto Lagain; - e = new ScopeExp(loc, ti); - e = e->semantic(sc); - return e; - } - - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td) - { - e = new TemplateExp(loc, td); - e = e->semantic(sc); - return e; - } - -Lerr: - error("%s '%s' is not a variable", s->kind(), s->toChars()); - type = Type::terror; - return this; -} - -char *DsymbolExp::toChars() -{ - return s->toChars(); -} - -void DsymbolExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(s->toChars()); -} - -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)) -{ - var = NULL; -} - -Expression *ThisExp::semantic(Scope *sc) -{ FuncDeclaration *fd; - FuncDeclaration *fdthis; - int nested = 0; - -#if LOGSEMANTIC - printf("ThisExp::semantic()\n"); -#endif - if (type) - { //assert(global.errors || var); - return this; - } - - /* Special case for typeof(this) and typeof(super) since both - * should work even if they are not inside a non-static member function - */ - if (sc->intypeof) - { - // Find enclosing struct or class - for (Dsymbol *s = sc->parent; 1; s = s->parent) - { - ClassDeclaration *cd; - StructDeclaration *sd; - - if (!s) - { - error("%s is not in a struct or class scope", toChars()); - goto Lerr; - } - cd = s->isClassDeclaration(); - if (cd) - { - type = cd->type; - return this; - } - sd = s->isStructDeclaration(); - if (sd) - { - type = sd->type->pointerTo(); - return this; - } - } - } - - fdthis = sc->parent->isFuncDeclaration(); - fd = hasThis(sc); // fd is the uplevel function with the 'this' variable - if (!fd) - goto Lerr; - - assert(fd->vthis); - var = fd->vthis; - assert(var->parent); - type = var->type; - var->isVarDeclaration()->checkNestedReference(sc, loc); -#if 0 - if (fd != fdthis) // if nested - { - fdthis->getLevel(loc, fd); - fd->vthis->nestedref = 1; - fd->nestedFrameRef = 1; - } -#endif - sc->callSuper |= CSXthis; - return this; - -Lerr: - error("'this' is only allowed in non-static member functions, not %s", sc->parent->toChars()); - type = Type::tint32; - return this; -} - -int ThisExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - -void ThisExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this"); -} - -Expression *ThisExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - -/******************************** SuperExp **************************/ - -SuperExp::SuperExp(Loc loc) - : ThisExp(loc) -{ - op = TOKsuper; -} - -Expression *SuperExp::semantic(Scope *sc) -{ FuncDeclaration *fd; - FuncDeclaration *fdthis; - ClassDeclaration *cd; - Dsymbol *s; - -#if LOGSEMANTIC - printf("SuperExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - /* Special case for typeof(this) and typeof(super) since both - * should work even if they are not inside a non-static member function - */ - if (sc->intypeof) - { - // Find enclosing class - for (Dsymbol *s = sc->parent; 1; s = s->parent) - { - ClassDeclaration *cd; - - if (!s) - { - error("%s is not in a class scope", toChars()); - goto Lerr; - } - cd = s->isClassDeclaration(); - if (cd) - { - cd = cd->baseClass; - if (!cd) - { error("class %s has no 'super'", s->toChars()); - goto Lerr; - } - type = cd->type; - return this; - } - } - } - - fdthis = sc->parent->isFuncDeclaration(); - fd = hasThis(sc); - if (!fd) - goto Lerr; - assert(fd->vthis); - var = fd->vthis; - assert(var->parent); - - s = fd->toParent(); - while (s && s->isTemplateInstance()) - s = s->toParent(); - assert(s); - cd = s->isClassDeclaration(); -//printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars()); - if (!cd) - goto Lerr; - if (!cd->baseClass) - { - error("no base class for %s", cd->toChars()); - type = fd->vthis->type; - } - else - { - type = cd->baseClass->type; - } - - var->isVarDeclaration()->checkNestedReference(sc, loc); -#if 0 - if (fd != fdthis) - { - fdthis->getLevel(loc, fd); - fd->vthis->nestedref = 1; - fd->nestedFrameRef = 1; - } -#endif - - sc->callSuper |= CSXsuper; - return this; - - -Lerr: - error("'super' is only allowed in non-static class member functions"); - type = Type::tint32; - return this; -} - -void SuperExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("super"); -} - - -/******************************** NullExp **************************/ - -NullExp::NullExp(Loc loc) - : Expression(loc, TOKnull, sizeof(NullExp)) -{ - committed = 0; -} - -Expression *NullExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("NullExp::semantic('%s')\n", toChars()); -#endif - // NULL is the same as (void *)0 - if (!type) - type = Type::tvoid->pointerTo(); - return this; -} - -int NullExp::isBool(int result) -{ - return result ? FALSE : TRUE; -} - -void NullExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("null"); -} - -void NullExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('n'); -} - -/******************************** StringExp **************************/ - -StringExp::StringExp(Loc loc, char *string) - : Expression(loc, TOKstring, sizeof(StringExp)) -{ - this->string = string; - this->len = strlen(string); - this->sz = 1; - this->committed = 0; - this->postfix = 0; -} - -StringExp::StringExp(Loc loc, void *string, size_t len) - : Expression(loc, TOKstring, sizeof(StringExp)) -{ - this->string = string; - this->len = len; - this->sz = 1; - this->committed = 0; - this->postfix = 0; -} - -StringExp::StringExp(Loc loc, void *string, size_t len, unsigned char postfix) - : Expression(loc, TOKstring, sizeof(StringExp)) -{ - this->string = string; - this->len = len; - this->sz = 1; - this->committed = 0; - this->postfix = postfix; -} - -#if 0 -Expression *StringExp::syntaxCopy() -{ - printf("StringExp::syntaxCopy() %s\n", toChars()); - return copy(); -} -#endif - -int StringExp::equals(Object *o) -{ - //printf("StringExp::equals('%s')\n", o->toChars()); - if (o && o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - - if (e->op == TOKstring) - { - return compare(o) == 0; - } - } - return FALSE; -} - -char *StringExp::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *p; - - memset(&hgs, 0, sizeof(hgs)); - toCBuffer(&buf, &hgs); - buf.writeByte(0); - p = (char *)buf.data; - buf.data = NULL; - return p; -} - -Expression *StringExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("StringExp::semantic() %s\n", toChars()); -#endif - if (!type) - { OutBuffer buffer; - size_t newlen = 0; - char *p; - size_t u; - unsigned c; - - switch (postfix) - { - case 'd': - for (u = 0; u < len;) - { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); - if (p) - { error("%s", p); - break; - } - else - { buffer.write4(c); - newlen++; - } - } - buffer.write4(0); - string = buffer.extractData(); - len = newlen; - sz = 4; - type = new TypeSArray(Type::tdchar, new IntegerExp(loc, len, Type::tindex)); - committed = 1; - break; - - case 'w': - for (u = 0; u < len;) - { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); - if (p) - { error("%s", p); - break; - } - else - { buffer.writeUTF16(c); - newlen++; - if (c >= 0x10000) - newlen++; - } - } - buffer.writeUTF16(0); - string = buffer.extractData(); - len = newlen; - sz = 2; - type = new TypeSArray(Type::twchar, new IntegerExp(loc, len, Type::tindex)); - 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; -} - -/**************************************** - * Convert string to char[]. - */ - -StringExp *StringExp::toUTF8(Scope *sc) -{ - if (sz != 1) - { // Convert to UTF-8 string - committed = 0; - Expression *e = castTo(sc, Type::tchar->arrayOf()); - e = e->optimize(WANTvalue); - assert(e->op == TOKstring); - StringExp *se = (StringExp *)e; - assert(se->sz == 1); - return se; - } - return this; -} - -int StringExp::compare(Object *obj) -{ - // Used to sort case statement expressions so we can do an efficient lookup - StringExp *se2 = (StringExp *)(obj); - - // This is a kludge so isExpression() in template.c will return 5 - // for StringExp's. - if (!se2) - return 5; - - assert(se2->op == TOKstring); - - int len1 = len; - int len2 = se2->len; - - if (len1 == len2) - { - switch (sz) - { - case 1: - return strcmp((char *)string, (char *)se2->string); - - case 2: - { unsigned u; - d_wchar *s1 = (d_wchar *)string; - d_wchar *s2 = (d_wchar *)se2->string; - - for (u = 0; u < len; u++) - { - if (s1[u] != s2[u]) - return s1[u] - s2[u]; - } - } - - case 4: - { unsigned u; - d_dchar *s1 = (d_dchar *)string; - d_dchar *s2 = (d_dchar *)se2->string; - - for (u = 0; u < len; u++) - { - if (s1[u] != s2[u]) - return s1[u] - s2[u]; - } - } - break; - - default: - assert(0); - } - } - return len1 - len2; -} - -int StringExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - -unsigned StringExp::charAt(size_t i) -{ unsigned value; - - switch (sz) - { - case 1: - value = ((unsigned char *)string)[i]; - break; - - case 2: - value = ((unsigned short *)string)[i]; - break; - - case 4: - value = ((unsigned int *)string)[i]; - break; - - default: - assert(0); - break; - } - return value; -} - -void StringExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('"'); - for (size_t i = 0; i < len; i++) - { unsigned c = charAt(i); - - switch (c) - { - case '"': - case '\\': - if (!hgs->console) - buf->writeByte('\\'); - default: - if (c <= 0xFF) - { if (c <= 0x7F && (isprint(c) || hgs->console)) - buf->writeByte(c); - else - buf->printf("\\x%02x", c); - } - else if (c <= 0xFFFF) - buf->printf("\\x%02x\\x%02x", c & 0xFF, c >> 8); - else - buf->printf("\\x%02x\\x%02x\\x%02x\\x%02x", - c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24); - break; - } - } - buf->writeByte('"'); - if (postfix) - buf->writeByte(postfix); -} - -void StringExp::toMangleBuffer(OutBuffer *buf) -{ char m; - OutBuffer tmp; - char *p; - unsigned c; - size_t u; - unsigned char *q; - unsigned qlen; - - /* Write string in UTF-8 format - */ - switch (sz) - { case 1: - m = 'a'; - q = (unsigned char *)string; - qlen = len; - break; - case 2: - m = 'w'; - for (u = 0; u < len; ) - { - p = utf_decodeWchar((unsigned short *)string, len, &u, &c); - if (p) - error("%s", p); - else - tmp.writeUTF8(c); - } - q = tmp.data; - qlen = tmp.offset; - break; - case 4: - m = 'd'; - for (u = 0; u < len; u++) - { - c = ((unsigned *)string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - tmp.writeUTF8(c); - } - q = tmp.data; - qlen = tmp.offset; - break; - default: - assert(0); - } - buf->writeByte(m); - buf->printf("%d_", qlen); - for (size_t i = 0; i < qlen; i++) - buf->printf("%02x", q[i]); -} - -/************************ ArrayLiteralExp ************************************/ - -// [ e1, e2, e3, ... ] - -ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements) - : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) -{ - this->elements = elements; -} - -ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e) - : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) -{ - elements = new Expressions; - elements->push(e); -} - -Expression *ArrayLiteralExp::syntaxCopy() -{ - return new ArrayLiteralExp(loc, arraySyntaxCopy(elements)); -} - -Expression *ArrayLiteralExp::semantic(Scope *sc) -{ Expression *e; - Type *t0 = NULL; - -#if LOGSEMANTIC - printf("ArrayLiteralExp::semantic('%s')\n", toChars()); -#endif - - // Run semantic() on each element - for (int i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - e = e->semantic(sc); - elements->data[i] = (void *)e; - } - expandTuples(elements); - for (int i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - - if (!e->type) - error("%s has no value", e->toChars()); - e = resolveProperties(sc, e); - - unsigned char committed = 1; - if (e->op == TOKstring) - committed = ((StringExp *)e)->committed; - - if (!t0) - { t0 = e->type; - // Convert any static arrays to dynamic arrays - if (t0->ty == Tsarray) - { - t0 = t0->next->arrayOf(); - e = e->implicitCastTo(sc, t0); - } - } - else - e = e->implicitCastTo(sc, t0); - if (!committed && e->op == TOKstring) - { StringExp *se = (StringExp *)e; - se->committed = 0; - } - elements->data[i] = (void *)e; - } - - if (!t0) - t0 = Type::tvoid; - type = new TypeSArray(t0, new IntegerExp(elements->dim)); - type = type->semantic(loc, sc); - return this; -} - -int ArrayLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - - f |= e->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -int ArrayLiteralExp::isBool(int result) -{ - size_t dim = elements ? elements->dim : 0; - return result ? (dim != 0) : (dim == 0); -} - -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 = (Expression *)elements->data[i]; - e->toMangleBuffer(buf); - } -} - -/************************ AssocArrayLiteralExp ************************************/ - -// [ key0 : value0, key1 : value1, ... ] - -AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc, - Expressions *keys, Expressions *values) - : Expression(loc, TOKassocarrayliteral, sizeof(AssocArrayLiteralExp)) -{ - assert(keys->dim == values->dim); - this->keys = keys; - this->values = values; -} - -Expression *AssocArrayLiteralExp::syntaxCopy() -{ - return new AssocArrayLiteralExp(loc, - arraySyntaxCopy(keys), arraySyntaxCopy(values)); -} - -Expression *AssocArrayLiteralExp::semantic(Scope *sc) -{ Expression *e; - Type *tkey = NULL; - Type *tvalue = NULL; - -#if LOGSEMANTIC - printf("AssocArrayLiteralExp::semantic('%s')\n", toChars()); -#endif - - // Run semantic() on each element - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - key = key->semantic(sc); - value = value->semantic(sc); - - keys->data[i] = (void *)key; - values->data[i] = (void *)value; - } - expandTuples(keys); - expandTuples(values); - if (keys->dim != values->dim) - { - error("number of keys is %u, must match number of values %u", keys->dim, values->dim); - keys->setDim(0); - values->setDim(0); - } - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - if (!key->type) - error("%s has no value", key->toChars()); - if (!value->type) - error("%s has no value", value->toChars()); - key = resolveProperties(sc, key); - value = resolveProperties(sc, value); - - if (!tkey) - tkey = key->type; - else - key = key->implicitCastTo(sc, tkey); - keys->data[i] = (void *)key; - - if (!tvalue) - tvalue = value->type; - else - value = value->implicitCastTo(sc, tvalue); - values->data[i] = (void *)value; - } - - if (!tkey) - tkey = Type::tvoid; - if (!tvalue) - tvalue = Type::tvoid; - type = new TypeAArray(tvalue, tkey); - type = type->semantic(loc, sc); - return this; -} - -int AssocArrayLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - f |= key->checkSideEffect(2); - f |= value->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -int AssocArrayLiteralExp::isBool(int result) -{ - size_t dim = keys->dim; - return result ? (dim != 0) : (dim == 0); -} - -void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('['); - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - if (i) - buf->writeByte(','); - expToCBuffer(buf, hgs, key, PREC_assign); - buf->writeByte(':'); - expToCBuffer(buf, hgs, value, PREC_assign); - } - buf->writeByte(']'); -} - -void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = keys->dim; - buf->printf("A%u", dim); - for (size_t i = 0; i < dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - key->toMangleBuffer(buf); - value->toMangleBuffer(buf); - } -} - -/************************ StructLiteralExp ************************************/ - -// sd( e1, e2, e3, ... ) - -StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements) - : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp)) -{ - this->sd = sd; - this->elements = elements; - this->sym = NULL; - this->soffset = 0; - this->fillHoles = 1; -} - -Expression *StructLiteralExp::syntaxCopy() -{ - return new StructLiteralExp(loc, sd, arraySyntaxCopy(elements)); -} - -Expression *StructLiteralExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("StructLiteralExp::semantic('%s')\n", toChars()); -#endif - - // Run semantic() on each element - for (size_t i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - if (!e) - continue; - e = e->semantic(sc); - elements->data[i] = (void *)e; - } - expandTuples(elements); - size_t offset = 0; - for (size_t i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - if (!e) - continue; - - if (!e->type) - error("%s has no value", e->toChars()); - e = resolveProperties(sc, e); - if (i >= 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) - { e = v->init->toExpression(); - if (!e) - error("cannot make expression out of initializer for %s", v->toChars()); - } - else - { e = v->type->defaultInit(); - e->loc = loc; - } - offset = v->offset + v->type->size(); - } - elements->push(e); - } - - type = sd->type; - return this; -} - -/************************************** - * Gets expression at offset of type. - * Returns NULL if not found. - */ - -Expression *StructLiteralExp::getField(Type *type, unsigned offset) -{ Expression *e = NULL; - int i = getFieldIndex(type, offset); - - if (i != -1) - { e = (Expression *)elements->data[i]; - if (e) - { - e = e->copy(); - e->type = type; - } - } - return e; -} - -/************************************ - * Get index of field. - * Returns -1 if not found. - */ - -int StructLiteralExp::getFieldIndex(Type *type, unsigned offset) -{ - /* Find which field offset is by looking at the field offsets - */ - 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; -} - - -Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - - -int StructLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - if (!e) - continue; - - f |= e->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -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 = (Expression *)elements->data[i]; - if (e) - e->toMangleBuffer(buf); - else - buf->writeByte('v'); // 'v' for void - } -} - -/************************ TypeDotIdExp ************************************/ - -/* Things like: - * int.size - * foo.size - * (foo).size - * cast(foo).size - */ - -TypeDotIdExp::TypeDotIdExp(Loc loc, Type *type, Identifier *ident) - : Expression(loc, TOKtypedot, sizeof(TypeDotIdExp)) -{ - this->type = type; - this->ident = ident; -} - -Expression *TypeDotIdExp::syntaxCopy() -{ - TypeDotIdExp *te = new TypeDotIdExp(loc, type->syntaxCopy(), ident); - return te; -} - -Expression *TypeDotIdExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("TypeDotIdExp::semantic()\n"); -#endif - e = new DotIdExp(loc, new TypeExp(loc, type), ident); - e = e->semantic(sc); - return e; -} - -void TypeDotIdExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('('); - type->toCBuffer(buf, NULL, hgs); - buf->writeByte(')'); - buf->writeByte('.'); - buf->writestring(ident->toChars()); -} - -/************************************************************/ - -// 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::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 && !global.errors) - { Dsymbol *s; - if (!ti->semanticdone) - ti->semantic(sc); - s = ti->inst->toAlias(); - sds2 = s->isScopeDsymbol(); - if (!sds2) - { Expression *e; - - //printf("s = %s, '%s'\n", s->kind(), s->toChars()); - if (ti->withsym) - { - // Same as wthis.s - e = new VarExp(loc, ti->withsym->withstate->wthis); - e = new DotVarExp(loc, e, s->isDeclaration()); - } - else - e = new DsymbolExp(loc, s); - e = e->semantic(sc); - //printf("-1ScopeExp::semantic()\n"); - return e; - } - if (sds2 != sds) - { - sds = sds2; - goto Lagain; - } - //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); - } - else - { - //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); - //printf("\tparent = '%s'\n", sds->parent->toChars()); - sds->semantic(sc); - } - type = Type::tvoid; - //printf("-2ScopeExp::semantic() %s\n", toChars()); - return this; -} - -void ScopeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (sds->isTemplateInstance()) - { - sds->toCBuffer(buf, hgs); - } - else - { - buf->writestring(sds->kind()); - buf->writestring(" "); - buf->writestring(sds->toChars()); - } -} - -/********************** TemplateExp **************************************/ - -// Mainly just a placeholder - -TemplateExp::TemplateExp(Loc loc, TemplateDeclaration *td) - : Expression(loc, TOKtemplate, sizeof(TemplateExp)) -{ - //printf("TemplateExp(): %s\n", td->toChars()); - this->td = td; -} - -void TemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(td->toChars()); -} - -void TemplateExp::rvalue() -{ - error("template %s has no value", toChars()); -} - -/********************** NewExp **************************************/ - -NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs, - Type *newtype, Expressions *arguments) - : Expression(loc, TOKnew, sizeof(NewExp)) -{ - this->thisexp = thisexp; - this->newargs = newargs; - this->newtype = newtype; - this->arguments = arguments; - member = NULL; - allocator = NULL; - onstack = 0; -} - -Expression *NewExp::syntaxCopy() -{ - return new NewExp(loc, - thisexp ? thisexp->syntaxCopy() : NULL, - arraySyntaxCopy(newargs), - newtype->syntaxCopy(), arraySyntaxCopy(arguments)); -} - - -Expression *NewExp::semantic(Scope *sc) -{ int i; - Type *tb; - ClassDeclaration *cdthis = NULL; - -#if LOGSEMANTIC - printf("NewExp::semantic() %s\n", toChars()); - if (thisexp) - printf("\tthisexp = %s\n", thisexp->toChars()); - printf("\tnewtype: %s\n", newtype->toChars()); -#endif - if (type) // if semantic() already run - return this; - -Lagain: - if (thisexp) - { thisexp = thisexp->semantic(sc); - cdthis = thisexp->type->isClassHandle(); - if (cdthis) - { - sc = sc->push(cdthis); - type = newtype->semantic(loc, sc); - sc = sc->pop(); - } - else - { - error("'this' for nested class must be a class type, not %s", thisexp->type->toChars()); - type = newtype->semantic(loc, sc); - } - } - else - type = newtype->semantic(loc, sc); - newtype = type; // in case type gets cast to something else - tb = type->toBasetype(); - //printf("tb: %s, deco = %s\n", tb->toChars(), tb->deco); - - arrayExpressionSemantic(newargs, sc); - preFunctionArguments(loc, sc, newargs); - arrayExpressionSemantic(arguments, sc); - preFunctionArguments(loc, sc, arguments); - - if (thisexp && tb->ty != Tclass) - error("e.new is only for allocating nested classes, not %s", tb->toChars()); - - if (tb->ty == Tclass) - { TypeFunction *tf; - - TypeClass *tc = (TypeClass *)(tb); - ClassDeclaration *cd = tc->sym->isClassDeclaration(); - if (cd->isInterfaceDeclaration()) - error("cannot create instance of interface %s", cd->toChars()); - else if (cd->isAbstract()) - { error("cannot create instance of abstract class %s", cd->toChars()); - for (int i = 0; i < cd->vtbl.dim; i++) - { FuncDeclaration *fd = ((Dsymbol *)cd->vtbl.data[i])->isFuncDeclaration(); - if (fd && fd->isAbstract()) - error("function %s is abstract", fd->toChars()); - } - } - checkDeprecated(sc, cd); - if (cd->isNested()) - { /* We need a 'this' pointer for the nested class. - * Ensure we have the right one. - */ - Dsymbol *s = cd->toParent2(); - ClassDeclaration *cdn = s->isClassDeclaration(); - - //printf("isNested, cdn = %s\n", cdn ? cdn->toChars() : "null"); - if (cdn) - { - if (!cdthis) - { - // Supply an implicit 'this' and try again - thisexp = new ThisExp(loc); - for (Dsymbol *sp = sc->parent; 1; sp = sp->parent) - { if (!sp) - { - error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); - break; - } - ClassDeclaration *cdp = sp->isClassDeclaration(); - if (!cdp) - continue; - if (cdp == cdn || cdn->isBaseOf(cdp, NULL)) - break; - // Add a '.outer' and try again - thisexp = new DotIdExp(loc, thisexp, Id::outer); - } - if (!global.errors) - goto Lagain; - } - if (cdthis) - { - //printf("cdthis = %s\n", cdthis->toChars()); - if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL)) - error("'this' for nested class must be of type %s, not %s", cdn->toChars(), thisexp->type->toChars()); - } -#if 0 - else - { - for (Dsymbol *sf = sc->func; 1; sf= sf->toParent2()->isFuncDeclaration()) - { - if (!sf) - { - error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); - break; - } - printf("sf = %s\n", sf->toChars()); - AggregateDeclaration *ad = sf->isThis(); - if (ad && (ad == cdn || cdn->isBaseOf(ad->isClassDeclaration(), NULL))) - break; - } - } -#endif - } - else if (thisexp) - error("e.new is only for allocating nested classes"); - } - else if (thisexp) - error("e.new is only for allocating nested classes"); - - FuncDeclaration *f = cd->ctor; - if (f) - { - assert(f); - f = f->overloadResolve(loc, arguments); - 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(); - functionArguments(loc, sc, tf, arguments); - } - else - { - if (arguments && arguments->dim) - error("no constructor for %s", cd->toChars()); - } - - if (cd->aggNew) - { Expression *e; - - f = cd->aggNew; - - // Prepend the uint size argument to newargs[] - e = new IntegerExp(loc, cd->size(loc), Type::tuns32); - if (!newargs) - newargs = new Expressions(); - newargs->shift(e); - - f = f->overloadResolve(loc, newargs); - allocator = f->isNewDeclaration(); - assert(allocator); - - tf = (TypeFunction *)f->type; - functionArguments(loc, sc, tf, newargs); - } - else - { - if (newargs && newargs->dim) - error("no allocator for %s", cd->toChars()); - } - - } - else if (tb->ty == Tstruct) - { - TypeStruct *ts = (TypeStruct *)tb; - StructDeclaration *sd = ts->sym; - 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, newargs); - allocator = f->isNewDeclaration(); - assert(allocator); - - tf = (TypeFunction *)f->type; - functionArguments(loc, sc, tf, newargs); - - 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"); - arguments->dim = i; - break; - } - - Expression *arg = (Expression *)arguments->data[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()); - arguments->data[i] = (void *) arg; - tb = tb->next->toBasetype(); - } - } - else if (tb->isscalar()) - { - if (arguments && arguments->dim) - error("no constructor for %s", type->toChars()); - - type = type->pointerTo(); - } - else - { - error("new can only create structs, dynamic arrays or class objects, not %s's", type->toChars()); - type = type->pointerTo(); - } - -//printf("NewExp: '%s'\n", toChars()); -//printf("NewExp:type '%s'\n", type->toChars()); - - return this; -} - -int NewExp::checkSideEffect(int flag) -{ - return 1; -} - -void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - if (thisexp) - { expToCBuffer(buf, hgs, thisexp, PREC_primary); - buf->writeByte('.'); - } - buf->writestring("new "); - if (newargs && newargs->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, newargs, hgs); - buf->writeByte(')'); - } - newtype->toCBuffer(buf, NULL, hgs); - if (arguments && arguments->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); - } -} - -/********************** NewAnonClassExp **************************************/ - -NewAnonClassExp::NewAnonClassExp(Loc loc, Expression *thisexp, - Expressions *newargs, ClassDeclaration *cd, Expressions *arguments) - : Expression(loc, TOKnewanonclass, sizeof(NewAnonClassExp)) -{ - this->thisexp = thisexp; - this->newargs = newargs; - this->cd = cd; - this->arguments = arguments; -} - -Expression *NewAnonClassExp::syntaxCopy() -{ - return new NewAnonClassExp(loc, - thisexp ? thisexp->syntaxCopy() : NULL, - arraySyntaxCopy(newargs), - (ClassDeclaration *)cd->syntaxCopy(NULL), - arraySyntaxCopy(arguments)); -} - - -Expression *NewAnonClassExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("NewAnonClassExp::semantic() %s\n", toChars()); - //printf("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; -} - -void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - if (thisexp) - { expToCBuffer(buf, hgs, thisexp, PREC_primary); - buf->writeByte('.'); - } - buf->writestring("new"); - if (newargs && newargs->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, newargs, hgs); - buf->writeByte(')'); - } - buf->writestring(" class "); - if (arguments && arguments->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); - } - //buf->writestring(" { }"); - if (cd) - { - cd->toCBuffer(buf, hgs); - } -} - -/********************** SymOffExp **************************************/ - -SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset) - : Expression(loc, TOKsymoff, sizeof(SymOffExp)) -{ - assert(var); - this->var = var; - this->offset = offset; - 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); - if (!type) - type = var->type->pointerTo(); - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { - v->checkNestedReference(sc, loc); - v->needsStorage = true; - } - return this; -} - -int SymOffExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - -void SymOffExp::checkEscape() -{ - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg()) - error("escaping reference to local variable %s", v->toChars()); - } -} - -void SymOffExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (offset) - buf->printf("(& %s+%u)", var->toChars(), offset); - else - buf->printf("& %s", var->toChars()); -} - -/******************************** VarExp **************************/ - -VarExp::VarExp(Loc loc, Declaration *var) - : 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) -{ FuncLiteralDeclaration *fd; - -#if LOGSEMANTIC - printf("VarExp::semantic(%s)\n", toChars()); -#endif - if (!type) - { type = var->type; -#if 0 - if (var->storage_class & STClazy) - { - TypeFunction *tf = new TypeFunction(NULL, type, 0, LINKd); - type = new TypeDelegate(tf); - type = type->semantic(loc, sc); - } -#endif - } - - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { - if (v->isConst() && type->toBasetype()->ty != Tsarray && v->init) - { - ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { - //ei->exp->implicitCastTo(sc, type)->print(); - return ei->exp->implicitCastTo(sc, type); - } - } - v->checkNestedReference(sc, loc); - } -#if 0 - else if ((fd = var->isFuncLiteralDeclaration()) != NULL) - { Expression *e; - e = new FuncExp(loc, fd); - e->type = type; - return e; - } -#endif - return this; -} - -char *VarExp::toChars() -{ - return var->toChars(); -} - -void VarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(var->toChars()); -} - -void VarExp::checkEscape() -{ - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { Type *tb = v->type->toBasetype(); - // if reference type - if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass) - { - if ((v->isAuto() || v->isScope()) && !v->noauto) - error("escaping reference to auto local %s", v->toChars()); - else if (v->storage_class & STCvariadic) - error("escaping reference to variadic parameter %s", v->toChars()); - } - } -} - -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()); - v->needsStorage = true; - - 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); -} - - -/******************************** TupleExp **************************/ - -TupleExp::TupleExp(Loc loc, Expressions *exps) - : Expression(loc, TOKtuple, sizeof(TupleExp)) -{ - //printf("TupleExp(this = %p)\n", this); - this->exps = exps; - this->type = NULL; -} - - -TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) - : Expression(loc, TOKtuple, sizeof(TupleExp)) -{ - exps = new Expressions(); - type = NULL; - - exps->reserve(tup->objects->dim); - for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = (Object *)tup->objects->data[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { - Expression *e = (Expression *)o; - e = e->syntaxCopy(); - exps->push(e); - } - else if (o->dyncast() == DYNCAST_DSYMBOL) - { - Dsymbol *s = (Dsymbol *)o; - Expression *e = new DsymbolExp(loc, s); - exps->push(e); - } - else if (o->dyncast() == DYNCAST_TYPE) - { - Type *t = (Type *)o; - Expression *e = new TypeExp(loc, t); - exps->push(e); - } - else - { - error("%s is not an expression", o->toChars()); - } - } -} - -int TupleExp::equals(Object *o) -{ TupleExp *ne; - - if (this == o) - return 1; - if (((Expression *)o)->op == TOKtuple) - { - TupleExp *te = (TupleExp *)o; - if (exps->dim != te->exps->dim) - return 0; - for (size_t i = 0; i < exps->dim; i++) - { Expression *e1 = (Expression *)exps->data[i]; - Expression *e2 = (Expression *)te->exps->data[i]; - - if (!e1->equals(e2)) - return 0; - } - return 1; - } - return 0; -} - -Expression *TupleExp::syntaxCopy() -{ - return new TupleExp(loc, arraySyntaxCopy(exps)); -} - -Expression *TupleExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("+TupleExp::semantic(%s)\n", toChars()); -#endif - if (type) - return this; - - // Run semantic() on each argument - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - e = e->semantic(sc); - if (!e->type) - { error("%s has no value", e->toChars()); - e->type = Type::terror; - } - exps->data[i] = (void *)e; - } - - expandTuples(exps); - if (0 && exps->dim == 1) - { - return (Expression *)exps->data[0]; - } - type = new TypeTuple(exps); - //printf("-TupleExp::semantic(%s)\n", toChars()); - return this; -} - -void TupleExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("tuple("); - argsToCBuffer(buf, exps, hgs); - buf->writeByte(')'); -} - -int TupleExp::checkSideEffect(int flag) -{ int f = 0; - - for (int i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - f |= e->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -void TupleExp::checkEscape() -{ - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - e->checkEscape(); - } -} - -/******************************** FuncExp *********************************/ - -FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd) - : Expression(loc, TOKfunction, sizeof(FuncExp)) -{ - this->fd = fd; -} - -Expression *FuncExp::syntaxCopy() -{ - return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL)); -} - -Expression *FuncExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("FuncExp::semantic(%s)\n", toChars()); -#endif - if (!type) - { - fd->semantic(sc); - fd->parent = sc->parent; - if (global.errors) - { - if (!fd->type->next) - fd->type->next = Type::terror; - } - else - { - fd->semantic2(sc); - if (!global.errors) - { - fd->semantic3(sc); - - if (!global.errors && global.params.useInline) - fd->inlineScan(); - } - } - - // 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) -{ - buf->writestring(fd->toChars()); -} - - -/******************************** DeclarationExp **************************/ - -DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration) - : Expression(loc, TOKdeclaration, sizeof(DeclarationExp)) -{ - this->declaration = declaration; -} - -Expression *DeclarationExp::syntaxCopy() -{ - return new DeclarationExp(loc, declaration->syntaxCopy(NULL)); -} - -Expression *DeclarationExp::semantic(Scope *sc) -{ - if (type) - return this; - -#if LOGSEMANTIC - printf("DeclarationExp::semantic() %s\n", toChars()); -#endif - - /* This is here to support extern(linkage) declaration, - * where the extern(linkage) winds up being an AttribDeclaration - * wrapper. - */ - Dsymbol *s = declaration; - - AttribDeclaration *ad = declaration->isAttribDeclaration(); - if (ad) - { - if (ad->decl && ad->decl->dim == 1) - s = (Dsymbol *)ad->decl->data[0]; - } - - if (s->isVarDeclaration()) - { // Do semantic() on initializer first, so: - // int a = a; - // will be illegal. - declaration->semantic(sc); - s->parent = sc->parent; - } - - //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc); - // Insert into both local scope and function scope. - // Must be unique in both. - if (s->ident) - { - if (!sc->insert(s)) - error("declaration %s is already defined", s->toPrettyChars()); - else if (sc->func) - { VarDeclaration *v = s->isVarDeclaration(); - if ((s->isFuncDeclaration() /*|| v && v->storage_class & STCstatic*/) && - !sc->func->localsymtab->insert(s)) - error("declaration %s is already defined in another scope in %s", s->toPrettyChars(), sc->func->toChars()); - else if (!global.params.useDeprecated) - { // Disallow shadowing - - for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing) - { Dsymbol *s2; - - if (scx->scopesym && scx->scopesym->symtab && - (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL && - s != s2) - { - error("shadowing declaration %s is deprecated", s->toPrettyChars()); - } - } - } - } - } - if (!s->isVarDeclaration()) - { - declaration->semantic(sc); - s->parent = sc->parent; - } - if (!global.errors) - { - declaration->semantic2(sc); - if (!global.errors) - { - declaration->semantic3(sc); - - if (!global.errors && global.params.useInline) - declaration->inlineScan(); - } - } - - type = Type::tvoid; - return this; -} - -int DeclarationExp::checkSideEffect(int flag) -{ - return 1; -} - -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); - return e; -} - -void TypeidExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typeid("); - typeidType->toCBuffer(buf, NULL, hgs); - buf->writeByte(')'); -} - -/************************************************************/ - -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; - - //printf("IsExp::semantic()\n"); - if (id && !(sc->flags & SCOPEstaticif)) - error("can only declare type aliases within static if conditionals"); - - unsigned errors_save = global.errors; - global.errors = 0; - global.gag++; // suppress printing of error messages - targ = targ->semantic(loc, sc); - global.gag--; - unsigned gerrors = global.errors; - global.errors = errors_save; - - if (gerrors) // 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; - - case TOKsuper: - // If class or interface, get the base class and interfaces - if (targ->ty != Tclass) - goto Lno; - else - { ClassDeclaration *cd = ((TypeClass *)targ)->sym; - Arguments *args = new Arguments; - args->reserve(cd->baseclasses.dim); - for (size_t i = 0; i < cd->baseclasses.dim; i++) - { BaseClass *b = (BaseClass *)cd->baseclasses.data[i]; - args->push(new Argument(STCin, b->type, NULL, NULL)); - } - tded = new TypeTuple(args); - } - break; - - case TOKenum: - if (targ->ty != Tenum) - goto Lno; - tded = ((TypeEnum *)targ)->sym->memtype; - break; - - case TOKdelegate: - if (targ->ty != Tdelegate) - goto Lno; - tded = targ->next; // the underlying function type - break; - - case TOKfunction: - { if (targ->ty != Tfunction) - goto Lno; - tded = targ; - - /* Generate tuple from function parameter types. - */ - assert(tded->ty == Tfunction); - Arguments *params = ((TypeFunction *)tded)->parameters; - size_t dim = Argument::dim(params); - Arguments *args = new Arguments; - args->reserve(dim); - for (size_t i = 0; i < dim; i++) - { Argument *arg = Argument::getNth(params, i); - assert(arg && arg->type); - args->push(new Argument(arg->storageClass, arg->type, NULL, NULL)); - } - tded = new TypeTuple(args); - break; - } - case TOKreturn: - /* Get the 'return type' for the function, - * delegate, or pointer to function. - */ - if (targ->ty == Tfunction) - tded = 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; - - default: - assert(0); - } - goto Lyes; - } - else if (id && tspec) - { - /* Evaluate to TRUE if targ matches tspec. - * If TRUE, declare id as an alias for the specialized type. - */ - - MATCH m; - TemplateTypeParameter tp(loc, id, NULL, NULL); - - TemplateParameters parameters; - parameters.setDim(1); - parameters.data[0] = (void *)&tp; - - Objects dedtypes; - dedtypes.setDim(1); - dedtypes.data[0] = NULL; - - m = targ->deduceType(NULL, 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; - 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 - */ - tspec = tspec->semantic(loc, sc); - //printf("targ = %s\n", targ->toChars()); - //printf("tspec = %s\n", tspec->toChars()); - if (tok == TOKcolon) - { if (targ->implicitConvTo(tspec)) - goto Lyes; - else - goto Lno; - } - else /* == */ - { if (targ->equals(tspec)) - goto Lyes; - else - goto Lno; - } - } - -Lyes: - if (id) - { - Dsymbol *s = new AliasDeclaration(loc, id, tded); - s->semantic(sc); - sc->insert(s); - 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 V2 - if (parameters) - { // First parameter is already output, so start with second - for (int i = 1; i < parameters->dim; i++) - { - buf->writeByte(','); - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - tp->toCBuffer(buf, hgs); - } - } -#endif - buf->writeByte(')'); -} - - -/************************************************************/ - -UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1) - : Expression(loc, op, size) -{ - this->e1 = e1; -} - -Expression *UnaExp::syntaxCopy() -{ UnaExp *e; - - e = (UnaExp *)copy(); - e->type = NULL; - e->e1 = e->e1->syntaxCopy(); - return e; -} - -Expression *UnaExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("UnaExp::semantic('%s')\n", toChars()); -#endif - e1 = e1->semantic(sc); -// if (!e1->type) -// error("%s has no value", e1->toChars()); - return this; -} - -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) - { - error("%s has no value", e1->toChars()); - e1->type = Type::terror; - } - e2 = e2->semantic(sc); - if (!e2->type) - { - error("%s has no value", e2->toChars()); - e2->type = Type::terror; - } - assert(e1->type); - 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; - - 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 IntegerExp(0); - } - } - 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; - - 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 == TOKaddass || - op == TOKminass || - op == TOKcatass || - op == TOKmulass || - op == TOKdivass || - op == TOKmodass || - op == TOKshlass || - op == TOKshrass || - op == TOKushrass || - op == TOKandass || - op == TOKorass || - op == TOKxorass || - op == TOKin || - op == TOKremove) - return 1; - return Expression::checkSideEffect(flag); -} - -void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte(' '); - buf->writestring(Token::toChars(op)); - buf->writeByte(' '); - expToCBuffer(buf, hgs, e2, (enum PREC)(precedence[op] + 1)); -} - -int BinExp::isunsigned() -{ - return e1->type->isunsigned() || e2->type->isunsigned(); -} - -void BinExp::incompatibleTypes() -{ - error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", - e1->toChars(), Token::toChars(op), e2->toChars(), - e1->type->toChars(), e2->type->toChars()); -} - -/************************************************************/ - -CompileExp::CompileExp(Loc loc, Expression *e) - : UnaExp(loc, TOKmixin, sizeof(CompileExp), e) -{ -} - -Expression *CompileExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("CompileExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->optimize(WANTvalue | WANTinterpret); - if (e1->op != TOKstring) - { error("argument to mixin must be a string, not (%s)", e1->toChars()); - type = Type::terror; - return this; - } - StringExp *se = (StringExp *)e1; - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - Expression *e = p.parseExpression(); - if (p.token.value != TOKeof) - error("incomplete mixin expression (%s)", se->toChars()); - return e->semantic(sc); -} - -void CompileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - expToCBuffer(buf, hgs, e1, PREC_assign); - buf->writeByte(')'); -} - -/************************************************************/ - -FileExp::FileExp(Loc loc, Expression *e) - : UnaExp(loc, TOKmixin, sizeof(FileExp), e) -{ -} - -Expression *FileExp::semantic(Scope *sc) -{ char *name; - StringExp *se; - -#if LOGSEMANTIC - printf("FileExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->optimize(WANTvalue); - if (e1->op != TOKstring) - { error("file name argument must be a string, not (%s)", e1->toChars()); - goto Lerror; - } - se = (StringExp *)e1; - se = se->toUTF8(sc); - name = (char *)se->string; - - if (!global.params.fileImppath) - { error("need -Jpath switch to import text file %s", name); - goto Lerror; - } - - if (name != FileName::name(name)) - { error("use -Jpath switch to provide path for filename %s", name); - goto Lerror; - } - - name = FileName::searchPath(global.filePath, name, 0); - if (!name) - { error("file %s cannot be found, check -Jpath", se->toChars()); - goto Lerror; - } - - if (global.params.verbose) - printf("file %s\t(%s)\n", se->string, name); - - { File f(name); - if (f.read()) - { error("cannot read file %s", f.toChars()); - goto Lerror; - } - else - { - f.ref = 1; - se = new StringExp(loc, f.buffer, f.len); - } - } - Lret: - return se->semantic(sc); - - Lerror: - se = new StringExp(loc, ""); - goto Lret; -} - -void FileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("import("); - expToCBuffer(buf, hgs, e1, PREC_assign); - buf->writeByte(')'); -} - -/************************************************************/ - -AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg) - : UnaExp(loc, TOKassert, sizeof(AssertExp), e) -{ - this->msg = msg; -} - -Expression *AssertExp::syntaxCopy() -{ - AssertExp *ae = new AssertExp(loc, e1->syntaxCopy(), - msg ? msg->syntaxCopy() : NULL); - return ae; -} - -Expression *AssertExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AssertExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - // BUG: see if we can do compile time elimination of the Assert - e1 = e1->optimize(WANTvalue); - e1 = e1->checkToBoolean(); - if (msg) - { - msg = msg->semantic(sc); - msg = resolveProperties(sc, msg); - msg = msg->implicitCastTo(sc, Type::tchar->arrayOf()); - msg = msg->optimize(WANTvalue); - } - if (e1->isBool(FALSE)) - { - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - fd->hasReturnExp |= 4; - - if (!global.params.useAssert) - { Expression *e = new HaltExp(loc); - e = e->semantic(sc); - return e; - } - } - type = Type::tvoid; - return this; -} - -int AssertExp::checkSideEffect(int flag) -{ - return 1; -} - -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 = new TypeDotIdExp(loc, cd->type, ident); - return e->semantic(sc); - } - else if (cd->baseClass && e1->op == TOKsuper) - { - e = new TypeDotIdExp(loc, cd->baseClass->type, ident); - return e->semantic(sc); - } - } - else - { - sd = ad->isStructDeclaration(); - if (sd) - { - if (e1->op == TOKthis) - { - e = new TypeDotIdExp(loc, sd->type, ident); - return e->semantic(sc); - } - } - } - } - } - - UnaExp::semantic(sc); - - if (e1->op == TOKdotexp) - { - DotExp *de = (DotExp *)e1; - eleft = de->e1; - eright = de->e2; - } - else - { - e1 = resolveProperties(sc, e1); - eleft = NULL; - eright = e1; - } - - if (e1->op == TOKtuple && ident == Id::length) - { - TupleExp *te = (TupleExp *)e1; - e = new IntegerExp(loc, te->exps->dim, Type::tsize_t); - return e; - } - - if (eright->op == TOKimport) // also used for template alias's - { - Dsymbol *s; - ScopeExp *ie = (ScopeExp *)eright; - - s = ie->sds->search(loc, ident, 0); - if (s) - { - s = s->toAlias(); - checkDeprecated(sc, s); - - EnumMember *em = s->isEnumMember(); - if (em) - { - e = em->value; - e = e->semantic(sc); - return e; - } - - VarDeclaration *v = s->isVarDeclaration(); - if (v) - { - //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); - if (v->inuse) - { - error("circular reference to '%s'", v->toChars()); - type = Type::tint32; - return this; - } - type = v->type; - if (v->isConst()) - { - 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; - } - } - return e->deref(); - } - - FuncDeclaration *f = s->isFuncDeclaration(); - if (f) - { - //printf("it's a function\n"); - if (f->needThis()) - { - if (!eleft) - eleft = new ThisExp(loc); - e = new DotVarExp(loc, eleft, f); - e = e->semantic(sc); - } - else - { - e = new VarExp(loc, f); - if (eleft) - { e = new CommaExp(loc, eleft, e); - e->type = f->type; - } - } - return e; - } - - Type *t = s->getType(); - if (t) - { - return new TypeExp(loc, t); - } - - ScopeDsymbol *sds = s->isScopeDsymbol(); - if (sds) - { - //printf("it's a ScopeDsymbol\n"); - e = new ScopeExp(loc, sds); - e = e->semantic(sc); - if (eleft) - e = new DotExp(loc, eleft, e); - return e; - } - - Import *imp = s->isImport(); - if (imp) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, imp->pkg); - return ie->semantic(sc); - } - - // BUG: handle other cases like in IdentifierExp::semantic() -#ifdef DEBUG - printf("s = '%s', kind = '%s'\n", s->toChars(), s->kind()); -#endif - assert(0); - } - else if (ident == Id::stringof) - { char *s = ie->toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } - error("undefined identifier %s", toChars()); - type = Type::tvoid; - return this; - } - else if (e1->type->ty == Tpointer && - ident != Id::init && ident != Id::__sizeof && - ident != Id::alignof && ident != Id::offsetof && - ident != Id::mangleof && ident != Id::stringof) - { - e = new PtrExp(loc, e1); - e->type = e1->type->next; - return e->type->dotExp(sc, e, ident); - } - 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 IntegerExp(0); - } - assert(type); - - if (!var->isFuncDeclaration()) // for functions, do checks after overload resolution - { - AggregateDeclaration *ad = var->toParent()->isAggregateDeclaration(); - L1: - Type *t = e1->type->toBasetype(); - - if (ad && - !(t->ty == Tpointer && t->next->ty == Tstruct && - ((TypeStruct *)t->next)->sym == ad) - && - !(t->ty == Tstruct && - ((TypeStruct *)t)->sym == ad) - ) - { - ClassDeclaration *cd = ad->isClassDeclaration(); - ClassDeclaration *tcd = t->isClassHandle(); - - if (!cd || !tcd || - !(tcd == cd || cd->isBaseOf(tcd, NULL)) - ) - { - if (tcd && tcd->isNested()) - { // Try again with outer scope - - e1 = new DotVarExp(loc, e1, tcd->vthis); - e1 = e1->semantic(sc); - - // Skip over nested functions, and get the enclosing - // class type. - Dsymbol *s = tcd->toParent(); - while (s && s->isFuncDeclaration()) - { FuncDeclaration *f = s->isFuncDeclaration(); - if (f->vthis) - { - e1 = new VarExp(loc, f->vthis); - } - s = s->toParent(); - } - if (s && s->isClassDeclaration()) - e1->type = s->isClassDeclaration()->type; - - goto L1; - } -#ifdef DEBUG - printf("2: "); -#endif - error("this for %s needs to be type %s not type %s", - var->toChars(), ad->toChars(), t->toChars()); - } - } - accessCheck(loc, sc, e1, var); - } - } - //printf("-DotVarExp::semantic('%s')\n", toChars()); - return this; -} - -Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) -{ - //printf("DotVarExp::toLvalue(%s)\n", toChars()); - return this; -} - -Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("DotVarExp::modifiableLvalue(%s)\n", 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() && - 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; - } - } - return this; -} - -void DotVarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(var->toChars()); -} - -/************************************************************/ - -/* Things like: - * foo.bar!(args) - */ - -DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti) - : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e) -{ - //printf("DotTemplateInstanceExp()\n"); - this->ti = ti; -} - -Expression *DotTemplateInstanceExp::syntaxCopy() -{ - DotTemplateInstanceExp *de = new DotTemplateInstanceExp(loc, - e1->syntaxCopy(), - (TemplateInstance *)ti->syntaxCopy(NULL)); - return de; -} - -Expression *DotTemplateInstanceExp::semantic(Scope *sc) -{ Dsymbol *s; - Dsymbol *s2; - TemplateDeclaration *td; - Expression *e; - Identifier *id; - Type *t1; - Expression *eleft = NULL; - Expression *eright; - -#if LOGSEMANTIC - printf("DotTemplateInstanceExp::semantic('%s')\n", toChars()); -#endif - //e1->print(); - //print(); - e1 = e1->semantic(sc); - t1 = e1->type; - if (t1) - t1 = t1->toBasetype(); - //t1->print(); - 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 = 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) - { 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(0); -} - -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; -} - -Expression *DelegateExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DelegateExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - e1 = e1->semantic(sc); - type = new TypeDelegate(func->type); - type = type->semantic(loc, sc); -//----------------- - /* For func, we need to get the - * right 'this' pointer if func is in an outer class, but our - * existing 'this' pointer is in an inner class. - * This code is analogous to that used for variables - * in DotVarExp::semantic(). - */ - AggregateDeclaration *ad = func->toParent()->isAggregateDeclaration(); - L10: - Type *t = e1->type; - if (func->needThis() && ad && - !(t->ty == Tpointer && t->next->ty == Tstruct && - ((TypeStruct *)t->next)->sym == ad) && - !(t->ty == Tstruct && ((TypeStruct *)t)->sym == ad) - ) - { - ClassDeclaration *cd = ad->isClassDeclaration(); - ClassDeclaration *tcd = t->isClassHandle(); - - if (!cd || !tcd || - !(tcd == cd || cd->isBaseOf(tcd, NULL)) - ) - { - if (tcd && tcd->isNested()) - { // Try again with outer scope - - e1 = new DotVarExp(loc, e1, tcd->vthis); - e1 = e1->semantic(sc); - goto L10; - } -#ifdef DEBUG - printf("3: "); -#endif - error("this for %s needs to be type %s not type %s", - func->toChars(), ad->toChars(), t->toChars()); - } - } -//----------------- - } - return this; -} - -void DelegateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('&'); - if (!func->isNested()) - { - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - } - buf->writestring(func->toChars()); -} - -/************************************************************/ - -DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s) - : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e) -{ - this->sym = s; - this->type = s->getType(); -} - -Expression *DotTypeExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotTypeExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - return this; -} - -void DotTypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(sym->toChars()); -} - -/************************************************************/ - -CallExp::CallExp(Loc loc, Expression *e, Expressions *exps) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - this->arguments = exps; -} - -CallExp::CallExp(Loc loc, Expression *e) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - this->arguments = NULL; -} - -CallExp::CallExp(Loc loc, Expression *e, Expression *earg1) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - Expressions *arguments = new Expressions(); - arguments->setDim(1); - arguments->data[0] = (void *)earg1; - - this->arguments = arguments; -} - -CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - Expressions *arguments = new Expressions(); - arguments->setDim(2); - arguments->data[0] = (void *)earg1; - arguments->data[1] = (void *)earg2; - - this->arguments = arguments; -} - -Expression *CallExp::syntaxCopy() -{ - return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); -} - - -Expression *CallExp::semantic(Scope *sc) -{ - TypeFunction *tf; - FuncDeclaration *f; - int i; - Type *t1; - int istemp; - -#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); - e1 = new IdentifierExp(dotid->loc, dotid->ident); - } - } - } - - istemp = 0; -Lagain: - f = NULL; - if (e1->op == TOKthis || e1->op == TOKsuper) - { - // semantic() run later for these - } - else - { - UnaExp::semantic(sc); - - /* Look for e1 being a lazy parameter - */ - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - - if (ve->var->storage_class & STClazy) - { - TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd); - TypeDelegate *t = new TypeDelegate(tf); - ve->type = t->semantic(loc, sc); - } - } - - if (e1->op == TOKimport) - { // Perhaps this should be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)e1; - e1 = new DsymbolExp(loc, se->sds); - e1 = e1->semantic(sc); - } -#if 1 // patch for #540 by Oskar Linde - else if (e1->op == TOKdotexp) - { - DotExp *de = (DotExp *) e1; - - if (de->e2->op == TOKimport) - { // This should *really* be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)de->e2; - de->e2 = new DsymbolExp(loc, se->sds); - de->e2 = de->e2->semantic(sc); - } - - if (de->e2->op == TOKtemplate) - { TemplateExp *te = (TemplateExp *) de->e2; - e1 = new DotTemplateExp(loc,de->e1,te->td); - } - } -#endif - } - - if (e1->op == TOKcomma) - { - CommaExp *ce = (CommaExp *)e1; - - e1 = ce->e2; - e1->type = ce->type; - ce->e2 = this; - ce->type = NULL; - return ce->semantic(sc); - } - - t1 = NULL; - if (e1->type) - t1 = e1->type->toBasetype(); - - // Check for call operator overload - if (t1) - { AggregateDeclaration *ad; - - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - if (search_function(ad, Id::call)) - goto L1; // overload of opCall, therefore it's a call - - if (e1->op != TOKtype) - error("%s %s does not overload ()", ad->kind(), ad->toChars()); - /* It's a struct literal - */ - Expression *e = new StructLiteralExp(loc, (StructDeclaration *)ad, arguments); - e = e->semantic(sc); - e->type = e1->type; // in case e1->type was a typedef - return e; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - goto L1; - L1: - // Rewrite as e1.call(arguments) - Expression *e = new DotIdExp(loc, e1, Id::call); - e = new CallExp(loc, e, arguments); - e = e->semantic(sc); - return e; - } - } - - arrayExpressionSemantic(arguments, sc); - preFunctionArguments(loc, sc, arguments); - - if (e1->op == TOKdotvar && t1->ty == Tfunction || - e1->op == TOKdottd) - { - DotVarExp *dve; - DotTemplateExp *dte; - AggregateDeclaration *ad; - UnaExp *ue = (UnaExp *)(e1); - - if (e1->op == TOKdotvar) - { // Do overload resolution - dve = (DotVarExp *)(e1); - - f = dve->var->isFuncDeclaration(); - assert(f); - f = f->overloadResolve(loc, arguments); - - ad = f->toParent()->isAggregateDeclaration(); - } - else - { dte = (DotTemplateExp *)(e1); - TemplateDeclaration *td = dte->td; - assert(td); - if (!arguments) - // Should fix deduceFunctionTemplate() so it works on NULL argument - arguments = new Expressions(); - f = td->deduceFunctionTemplate(sc, loc, NULL, arguments); - if (!f) - { type = Type::terror; - return this; - } - ad = td->toParent()->isAggregateDeclaration(); - } - /* Now that we have the right function f, we need to get the - * right 'this' pointer if f is in an outer class, but our - * existing 'this' pointer is in an inner class. - * This code is analogous to that used for variables - * in DotVarExp::semantic(). - */ - L10: - Type *t = ue->e1->type->toBasetype(); - if (f->needThis() && ad && - !(t->ty == Tpointer && t->next->ty == Tstruct && - ((TypeStruct *)t->next)->sym == ad) && - !(t->ty == Tstruct && ((TypeStruct *)t)->sym == ad) - ) - { - ClassDeclaration *cd = ad->isClassDeclaration(); - ClassDeclaration *tcd = t->isClassHandle(); - - if (!cd || !tcd || - !(tcd == cd || cd->isBaseOf(tcd, NULL)) - ) - { - if (tcd && tcd->isNested()) - { // Try again with outer scope - - ue->e1 = new DotVarExp(loc, ue->e1, tcd->vthis); - ue->e1 = ue->e1->semantic(sc); - goto L10; - } -#ifdef DEBUG - printf("1: "); -#endif - error("this for %s needs to be type %s not type %s", - f->toChars(), ad->toChars(), t->toChars()); - } - } - - checkDeprecated(sc, f); - accessCheck(loc, sc, ue->e1, f); - if (!f->needThis()) - { - VarExp *ve = new VarExp(loc, f); - e1 = new CommaExp(loc, ue->e1, ve); - e1->type = f->type; - } - else - { - if (e1->op == TOKdotvar) - dve->var = f; - else - e1 = new DotVarExp(loc, dte->e1, f); - e1->type = f->type; - - // See if we need to adjust the 'this' pointer - AggregateDeclaration *ad = f->isThis(); - ClassDeclaration *cd = ue->e1->type->isClassHandle(); - if (ad && cd && ad->isClassDeclaration() && ad != cd && - ue->e1->op != TOKsuper) - { - ue->e1 = ue->e1->castTo(sc, ad->type); //new CastExp(loc, ue->e1, ad->type); - ue->e1 = ue->e1->semantic(sc); - } - } - t1 = e1->type; - } - else if (e1->op == TOKsuper) - { - // Base class constructor call - ClassDeclaration *cd = NULL; - - if (sc->func) - cd = sc->func->toParent()->isClassDeclaration(); - if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration()) - { - error("super class constructor call must be in a constructor"); - type = Type::terror; - return this; - } - else - { - f = cd->baseClass->ctor; - if (!f) - { error("no super class constructor for %s", cd->baseClass->toChars()); - type = Type::terror; - return this; - } - else - { -#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, arguments); - checkDeprecated(sc, f); - 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"); - type = Type::terror; - return this; - } - else - { -#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, arguments); - checkDeprecated(sc, f); - e1 = new DotVarExp(e1->loc, e1, f); - e1 = e1->semantic(sc); - t1 = e1->type; - - // BUG: this should really be done by checking the static - // call graph - if (f == sc->func) - error("cyclic constructor call"); - } - } - else if (!t1) - { - error("function expected before (), not '%s'", e1->toChars()); - type = Type::terror; - return this; - } - else if (t1->ty != Tfunction) - { - if (t1->ty == Tdelegate) - { - assert(t1->next->ty == Tfunction); - tf = (TypeFunction *)(t1->next); - goto Lcheckargs; - } - else if (t1->ty == Tpointer && t1->next->ty == Tfunction) - { Expression *e; - - e = new PtrExp(loc, e1); - t1 = t1->next; - e->type = t1; - e1 = e; - } - else if (e1->op == TOKtemplate) - { - TemplateExp *te = (TemplateExp *)e1; - f = te->td->deduceFunctionTemplate(sc, loc, NULL, arguments); - if (!f) - { type = Type::terror; - return this; - } - if (f->needThis() && hasThis(sc)) - { - // Supply an implicit 'this', as in - // this.ident - - e1 = new DotTemplateExp(loc, (new ThisExp(loc))->semantic(sc), te->td); - goto Lagain; - } - - e1 = new VarExp(loc, f); - goto Lagain; - } - else - { error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars()); - type = Type::terror; - return this; - } - } - else if (e1->op == TOKvar) - { - // Do overload resolution - VarExp *ve = (VarExp *)e1; - - f = ve->var->isFuncDeclaration(); - assert(f); - - // 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, arguments); - checkDeprecated(sc, f); - - 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(); - functionArguments(loc, sc, tf, arguments); - - assert(type); - - if (f && f->tintro) - { - Type *t = type; - int offset = 0; - - if (f->tintro->next->isBaseOf(t, &offset) && offset) - { - type = f->tintro->next; - return castTo(sc, t); - } - } - - return this; -} - -int CallExp::checkSideEffect(int flag) -{ - return 1; -} - -Expression *CallExp::toLvalue(Scope *sc, Expression *e) -{ - if (type->toBasetype()->ty == Tstruct) - return this; - else - return Expression::toLvalue(sc, e); -} - -void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); -} - - -/************************************************************/ - -AddrExp::AddrExp(Loc loc, Expression *e) - : UnaExp(loc, TOKaddress, sizeof(AddrExp), e) -{ -} - -Expression *AddrExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AddrExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = e1->toLvalue(sc, NULL); - if (!e1->type) - { - error("cannot take address of %s", e1->toChars()); - type = Type::tint32; - return this; - } - 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; - - 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(); - - if (f && f->isNested()) - { Expression *e; - - e = new DelegateExp(loc, e1, f); - e = e->semantic(sc); - return e; - } - else if (v) - { - v->needsStorage = true; - } - } - else if (e1->op == TOKarray) - { - if (e1->type->toBasetype()->ty == Tbit) - error("cannot take address of bit in array"); - } - return optimize(WANTvalue); - } - return this; -} - -/************************************************************/ - -PtrExp::PtrExp(Loc loc, Expression *e) - : UnaExp(loc, TOKstar, sizeof(PtrExp), e) -{ - if (e->type) - type = e->type->next; -} - -PtrExp::PtrExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKstar, sizeof(PtrExp), e) -{ - type = t; -} - -Expression *PtrExp::semantic(Scope *sc) -{ Type *tb; - -#if LOGSEMANTIC - printf("PtrExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - if (type) - return this; - if (!e1->type) - printf("PtrExp::semantic('%s')\n", toChars()); - tb = e1->type->toBasetype(); - switch (tb->ty) - { - case Tpointer: - type = tb->next; - if (type->isbit()) - { Expression *e; - - // Rewrite *p as p[0] - e = new IndexExp(loc, e1, new IntegerExp(0)); - return e->semantic(sc); - } - break; - - case Tsarray: - case Tarray: - type = tb->next; - e1 = e1->castTo(sc, type->pointerTo()); - break; - - default: - error("can only * a pointer, not a '%s'", e1->type->toChars()); - type = Type::tint32; - break; - } - rvalue(); - return this; -} - -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; -} - -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(); - 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(); - e1 = e1->checkIntegral(); - type = e1->type; - } - return this; -} - -/************************************************************/ - -NotExp::NotExp(Loc loc, Expression *e) - : UnaExp(loc, TOKnot, sizeof(NotExp), e) -{ -} - -Expression *NotExp::semantic(Scope *sc) -{ - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToBoolean(); - type = Type::tboolean; - return this; -} - -int NotExp::isBit() -{ - return TRUE; -} - - - -/************************************************************/ - -BoolExp::BoolExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKtobool, sizeof(BoolExp), e) -{ - type = t; -} - -Expression *BoolExp::semantic(Scope *sc) -{ - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToBoolean(); - type = Type::tboolean; - return this; -} - -int BoolExp::isBit() -{ - return TRUE; -} - -/************************************************************/ - -DeleteExp::DeleteExp(Loc loc, Expression *e) - : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e) -{ -} - -Expression *DeleteExp::semantic(Scope *sc) -{ - Type *tb; - - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->toLvalue(sc, NULL); - type = Type::tvoid; - - tb = e1->type->toBasetype(); - switch (tb->ty) - { case Tclass: - { TypeClass *tc = (TypeClass *)tb; - ClassDeclaration *cd = tc->sym; - - if (cd->isCOMinterface()) - { /* Because COM classes are deleted by IUnknown.Release() - */ - error("cannot delete instance of COM interface %s", cd->toChars()); - } - break; - } - case Tpointer: - tb = tb->next->toBasetype(); - if (tb->ty == Tstruct) - { - TypeStruct *ts = (TypeStruct *)tb; - StructDeclaration *sd = ts->sym; - FuncDeclaration *f = sd->aggDelete; - - if (f) - { - Expression *e; - Expression *ec; - Type *tpv = Type::tvoid->pointerTo(); - - e = e1; - e->type = tpv; - 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()); - break; - } - - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - { if (!global.params.useDeprecated) - error("delete aa[key] deprecated, use aa.remove(key)"); - } - } - - return this; -} - -int DeleteExp::checkSideEffect(int flag) -{ - return 1; -} - -Expression *DeleteExp::checkToBoolean() -{ - error("delete does not give a boolean result"); - return this; -} - -void DeleteExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("delete "); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -CastExp::CastExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKcast, sizeof(CastExp), e) -{ - to = t; -} - -Expression *CastExp::syntaxCopy() -{ - return new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy()); -} - - -Expression *CastExp::semantic(Scope *sc) -{ Expression *e; - BinExp *b; - UnaExp *u; - -#if LOGSEMANTIC - printf("CastExp::semantic('%s')\n", toChars()); -#endif - -//static int x; assert(++x < 10); - - if (type) - return this; - UnaExp::semantic(sc); - if (e1->type) // if not a tuple - { - e1 = resolveProperties(sc, e1); - to = to->semantic(loc, sc); - - e = op_overload(sc); - if (e) - { - return e->implicitCastTo(sc, to); - } - - Type *tob = to->toBasetype(); - if (tob->ty == Tstruct && !tob->equals(e1->type->toBasetype())) - { - /* 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; - } - } - 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("); - to->toCBuffer(buf, NULL, hgs); - buf->writeByte(')'); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - - -/************************************************************/ - -SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr) - : UnaExp(loc, TOKslice, sizeof(SliceExp), e1) -{ - this->upr = upr; - this->lwr = lwr; - lengthVar = NULL; -} - -Expression *SliceExp::syntaxCopy() -{ - Expression *lwr = NULL; - if (this->lwr) - lwr = this->lwr->syntaxCopy(); - - Expression *upr = NULL; - if (this->upr) - upr = this->upr->syntaxCopy(); - - return new SliceExp(loc, e1->syntaxCopy(), lwr, upr); -} - -Expression *SliceExp::semantic(Scope *sc) -{ Expression *e; - AggregateDeclaration *ad; - //FuncDeclaration *fd; - ScopeDsymbol *sym; - -#if LOGSEMANTIC - printf("SliceExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - e = this; - - Type *t = e1->type->toBasetype(); - if (t->ty == Tpointer) - { - if (!lwr || !upr) - error("need upper and lower bound to slice pointer"); - } - else if (t->ty == Tarray) - { - } - else if (t->ty == Tsarray) - { - } - else if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - goto L1; - } - else if (t->ty == Tstruct) - { - ad = ((TypeStruct *)t)->sym; - - L1: - if (search_function(ad, Id::slice)) - { - // Rewrite as e1.slice(lwr, upr) - e = new DotIdExp(loc, e1, Id::slice); - - if (lwr) - { - assert(upr); - e = new CallExp(loc, e, lwr, upr); - } - else - { assert(!upr); - e = new CallExp(loc, e); - } - e = e->semantic(sc); - return e; - } - goto Lerror; - } - else if (t->ty == Ttuple) - { - if (!lwr && !upr) - return e1; - if (!lwr || !upr) - { error("need upper and lower bound to slice tuple"); - goto Lerror; - } - } - else - goto Lerror; - - if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) - { - sym = new ArrayScopeSymbol(this); - sym->loc = loc; - sym->parent = sc->scopesym; - sc = sc->push(sym); - } - - if (lwr) - { lwr = lwr->semantic(sc); - lwr = resolveProperties(sc, lwr); - lwr = lwr->implicitCastTo(sc, Type::tsize_t); - } - if (upr) - { upr = upr->semantic(sc); - upr = resolveProperties(sc, upr); - upr = upr->implicitCastTo(sc, Type::tsize_t); - } - - if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) - sc->pop(); - - if (t->ty == Ttuple) - { - lwr = lwr->optimize(WANTvalue); - upr = upr->optimize(WANTvalue); - uinteger_t i1 = lwr->toUInteger(); - uinteger_t i2 = upr->toUInteger(); - - size_t length; - TupleExp *te; - TypeTuple *tup; - - if (e1->op == TOKtuple) // slicing an expression tuple - { te = (TupleExp *)e1; - length = te->exps->dim; - } - else if (e1->op == TOKtype) // slicing a type tuple - { tup = (TypeTuple *)t; - length = Argument::dim(tup->arguments); - } - else - assert(0); - - if (i1 <= i2 && i2 <= length) - { size_t j1 = (size_t) i1; - size_t j2 = (size_t) i2; - - if (e1->op == TOKtuple) - { Expressions *exps = new Expressions; - exps->setDim(j2 - j1); - for (size_t i = 0; i < j2 - j1; i++) - { Expression *e = (Expression *)te->exps->data[j1 + i]; - exps->data[i] = (void *)e; - } - e = new TupleExp(loc, exps); - } - else - { Arguments *args = new Arguments; - args->reserve(j2 - j1); - for (size_t i = j1; i < j2; i++) - { Argument *arg = Argument::getNth(tup->arguments, i); - args->push(arg); - } - e = new TypeExp(e1->loc, new TypeTuple(args)); - } - e = e->semantic(sc); - } - else - { - error("string slice [%ju .. %ju] is out of bounds", i1, i2); - e = e1; - } - return e; - } - - type = t->next->arrayOf(); - return e; - -Lerror: - char *s; - if (t->ty == Tvoid) - s = e1->toChars(); - else - s = t->toChars(); - error("%s cannot be sliced with []", s); - type = Type::terror; - return e; -} - -void SliceExp::checkEscape() -{ - e1->checkEscape(); -} - -Expression *SliceExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - -Expression *SliceExp::modifiableLvalue(Scope *sc, Expression *e) -{ - error("slice expression %s is not a modifiable lvalue", toChars()); - return this; -} - -void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte('['); - if (upr || lwr) - { - if (lwr) - expToCBuffer(buf, hgs, lwr, PREC_assign); - else - buf->writeByte('0'); - buf->writestring(".."); - if (upr) - expToCBuffer(buf, hgs, upr, PREC_assign); - else - buf->writestring("length"); // BUG: should be array.length - } - buf->writeByte(']'); -} - -/********************** ArrayLength **************************************/ - -ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1) - : UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1) -{ -} - -Expression *ArrayLengthExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("ArrayLengthExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - type = Type::tsize_t; - } - return this; -} - -void ArrayLengthExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writestring(".length"); -} - -/*********************** ArrayExp *************************************/ - -// e1 [ i1, i2, i3, ... ] - -ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args) - : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1) -{ - arguments = args; -} - -Expression *ArrayExp::syntaxCopy() -{ - return new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); -} - -Expression *ArrayExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - -#if LOGSEMANTIC - printf("ArrayExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - t1 = e1->type->toBasetype(); - if (t1->ty != Tclass && t1->ty != Tstruct) - { // Convert to IndexExp - if (arguments->dim != 1) - error("only one index allowed to index %s", t1->toChars()); - e = new IndexExp(loc, e1, (Expression *)arguments->data[0]); - return e->semantic(sc); - } - - // Run semantic() on each argument - for (size_t i = 0; i < arguments->dim; i++) - { e = (Expression *)arguments->data[i]; - - e = e->semantic(sc); - if (!e->type) - error("%s has no value", e->toChars()); - arguments->data[i] = (void *)e; - } - - expandTuples(arguments); - assert(arguments && arguments->dim); - - e = op_overload(sc); - if (!e) - { error("no [] operator overload for type %s", e1->type->toChars()); - e = e1; - } - return e; -} - - -Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) -{ - if (type && type->toBasetype()->ty == Tvoid) - error("voids have no value"); - return this; -} - - -void ArrayExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('['); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(']'); -} - -/************************* DotExp ***********************************/ - -DotExp::DotExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdotexp, sizeof(DotExp), e1, e2) -{ -} - -Expression *DotExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotExp::semantic('%s')\n", toChars()); - if (type) printf("\ttype = %s\n", type->toChars()); -#endif - e1 = e1->semantic(sc); - e2 = e2->semantic(sc); - if (e2->op == TOKimport) - { - ScopeExp *se = (ScopeExp *)e2; - TemplateDeclaration *td = se->sds->isTemplateDeclaration(); - if (td) - { Expression *e = new DotTemplateExp(loc, e1, td); - e = e->semantic(sc); - return e; - } - } - if (!type) - type = e2->type; - return this; -} - - -/************************* CommaExp ***********************************/ - -CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2) -{ -} - -Expression *CommaExp::semantic(Scope *sc) -{ - if (!type) - { BinExp::semanticp(sc); - type = e2->type; - } - return this; -} - -void CommaExp::checkEscape() -{ - e2->checkEscape(); -} - -Expression *CommaExp::toLvalue(Scope *sc, Expression *e) -{ - e2 = e2->toLvalue(sc, NULL); - return this; -} - -Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e) -{ - e2 = e2->modifiableLvalue(sc, e); - return this; -} - -int CommaExp::isBool(int result) -{ - return e2->isBool(result); -} - -int CommaExp::checkSideEffect(int flag) -{ - if (flag == 2) - return e1->checkSideEffect(2) || e2->checkSideEffect(2); - else - { - // Don't check e1 until we cast(void) the a,b code generation - return e2->checkSideEffect(flag); - } -} - -/************************** IndexExp **********************************/ - -// e1 [ e2 ] - -IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2) -{ - //printf("IndexExp::IndexExp('%s')\n", toChars()); - lengthVar = NULL; - modifiable = 0; // assume it is an rvalue -} - -Expression *IndexExp::semantic(Scope *sc) -{ Expression *e; - BinExp *b; - UnaExp *u; - Type *t1; - ScopeDsymbol *sym; - -#if LOGSEMANTIC - printf("IndexExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - if (!e1->type) - e1 = e1->semantic(sc); - assert(e1->type); // semantic() should already be run on it - e = this; - - // Note that unlike C we do not implement the int[ptr] - - t1 = e1->type->toBasetype(); - - if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) - { // Create scope for 'length' variable - sym = new ArrayScopeSymbol(this); - sym->loc = loc; - sym->parent = sc->scopesym; - sc = sc->push(sym); - } - - e2 = e2->semantic(sc); - if (!e2->type) - { - error("%s has no value", e2->toChars()); - e2->type = Type::terror; - } - e2 = resolveProperties(sc, e2); - - if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) - sc = sc->pop(); - - switch (t1->ty) - { - case Tpointer: - case Tarray: - e2 = e2->implicitCastTo(sc, Type::tsize_t); - e->type = 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) - { - integer_t index = e2->toInteger(); - integer_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->next; - 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 = Argument::dim(tup->arguments); - } - else - assert(0); - - if (index < length) - { - - if (e1->op == TOKtuple) - e = (Expression *)te->exps->data[(size_t)index]; - else - e = new TypeExp(e1->loc, Argument::getNth(tup->arguments, (size_t)index)->type); - } - else - { - error("array index [%ju] is outside array bounds [0 .. %zu]", - index, length); - e = e1; - } - break; - } - - default: - error("%s must be an array or pointer type, not %s", - e1->toChars(), e1->type->toChars()); - type = Type::tint32; - break; - } - return e; -} - -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 *)"--"); -} - -/************************************************************/ - -/* Can be TOKconstruct too */ - -AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2) -{ - ismemset = 0; -} - -Expression *AssignExp::semantic(Scope *sc) -{ Type *t1; - Expression *e1old = e1; - -#if LOGSEMANTIC - printf("AssignExp::semantic('%s')\n", toChars()); -#endif - //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); - - /* 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) - { Type *t1; - ArrayExp *ae = (ArrayExp *)e1; - AggregateDeclaration *ad; - Identifier *id = Id::index; - - ae->e1 = ae->e1->semantic(sc); - t1 = ae->e1->type->toBasetype(); - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - goto L1; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - L1: - // Rewrite (a[i] = value) to (a.opIndexAssign(value, i)) - if (search_function(ad, Id::indexass)) - { Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); - Expressions *a = (Expressions *)ae->arguments->copy(); - - a->insert(0, e2); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - else - { - // Rewrite (a[i] = value) to (a.opIndex(i, value)) - if (search_function(ad, id)) - { Expression *e = new DotIdExp(loc, ae->e1, id); - - if (1 || !global.params.useDeprecated) - error("operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i)"); - - e = new CallExp(loc, e, (Expression *)ae->arguments->data[0], e2); - e = e->semantic(sc); - return e; - } - } - } - } - /* Look for operator overloading of a[i..j]=value. - * Do it before semantic() otherwise the a[i..j] will have been - * converted to a.opSlice() already. - */ - if (e1->op == TOKslice) - { Type *t1; - SliceExp *ae = (SliceExp *)e1; - AggregateDeclaration *ad; - Identifier *id = Id::index; - - ae->e1 = ae->e1->semantic(sc); - ae->e1 = resolveProperties(sc, ae->e1); - t1 = ae->e1->type->toBasetype(); - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - goto L2; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - L2: - // Rewrite (a[i..j] = value) to (a.opIndexAssign(value, i, j)) - if (search_function(ad, Id::sliceass)) - { Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass); - Expressions *a = new Expressions(); - - a->push(e2); - if (ae->lwr) - { a->push(ae->lwr); - assert(ae->upr); - a->push(ae->upr); - } - else - assert(!ae->upr); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - } - } - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - assert(e1->type); - - /* Rewrite tuple assignment as a tuple of assignments. - */ - if (e1->op == TOKtuple && e2->op == TOKtuple) - { TupleExp *tup1 = (TupleExp *)e1; - TupleExp *tup2 = (TupleExp *)e2; - size_t dim = tup1->exps->dim; - if (dim != tup2->exps->dim) - { - error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim); - } - else - { Expressions *exps = new Expressions; - exps->setDim(dim); - - for (int i = 0; i < dim; i++) - { Expression *ex1 = (Expression *)tup1->exps->data[i]; - Expression *ex2 = (Expression *)tup2->exps->data[i]; - exps->data[i] = (void *) new AssignExp(loc, ex1, ex2); - } - Expression *e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } - } - - t1 = e1->type->toBasetype(); - - if (t1->ty == Tfunction) - { // Rewrite f=value to f(value) - Expression *e; - - 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) - { - if (!e2->type->implicitConvTo(e1->type)) - { - Expression *e = op_overload(sc); - if (e) - return e; - } - } - - e2->rvalue(); - - if (e1->op == TOKarraylength) - { - // e1 is not an lvalue, but we let code generator handle it - ArrayLengthExp *ale = (ArrayLengthExp *)e1; - - ale->e1 = ale->e1->modifiableLvalue(sc, e1); - } - else if (e1->op == TOKslice) - ; - else - { // Try to do a decent error message with the expression - // before it got constant folded - e1 = e1->modifiableLvalue(sc, e1old); - } - - if (e1->op == TOKslice && - t1->nextOf() && - 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) - { - error("cannot assign to static array %s", e1->toChars()); - } - else - { - e2 = e2->implicitCastTo(sc, e1->type); - } - type = e1->type; - assert(type); - return this; -} - -Expression *AssignExp::checkToBoolean() -{ - // Things like: - // if (a = b) ... - // are usually mistakes. - - error("'=' does not give a boolean result"); - return this; -} - -/************************************************************/ - -AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2) -{ -} - -Expression *AddAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if ((tb1->ty == Tarray || tb1->ty == Tsarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - tb1->next->equals(tb2->next) - ) - { - 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; - - char name[6+6+1]; - Identifier *id; - static int idn; - sprintf(name, "__name%d", ++idn); - id = Lexer::idPool(name); - - v = new VarDeclaration(loc, tb1->pointerTo(), id, NULL); - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - - ea = new AddrExp(loc, e1); - ea = new AssignExp(loc, new VarExp(loc, v), ea); - - ex = new VarExp(loc, v); - ex = new PtrExp(loc, ex); - e = new AddExp(loc, ex, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, ex->syntaxCopy(), e); - - e = new CommaExp(loc, ea, e); - } - else -#endif - { // Rewrite e1+=e2 to e1=e1+e2 - // BUG: doesn't account for side effects in e1 - // BUG: other assignment operators for bits aren't handled at all - e = new AddExp(loc, e1, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, e1->syntaxCopy(), e); - } - e = e->semantic(sc); - } - else - { - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - if (type->isreal() || type->isimaginary()) - { - assert(global.errors || e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - } - } - return e; -} - -/************************************************************/ - -MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2) -{ -} - -Expression *MinAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - if (e1->type->ty == Tpointer && e2->type->isintegral()) - e = scaleFactor(sc); - else - { - e1 = e1->checkArithmetic(); - e2 = e2->checkArithmetic(); - type = e1->type; - typeCombine(sc); - if (type->isreal() || type->isimaginary()) - { - assert(e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - } - return e; -} - -/************************************************************/ - -CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2) -{ -} - -Expression *CatAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { SliceExp *se = (SliceExp *)e1; - - if (se->e1->type->toBasetype()->ty == Tsarray) - error("cannot append to static array %s", se->e1->type->toChars()); - } - - e1 = e1->modifiableLvalue(sc, e1); - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if ((tb1->ty == Tarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - e2->implicitConvTo(e1->type) - //e1->type->next->equals(e2->type->next) - ) - { // Append array - e2 = e2->castTo(sc, e1->type); - type = e1->type; - e = this; - } - else if ((tb1->ty == Tarray) && - e2->implicitConvTo(tb1->next) - ) - { // Append element - e2 = e2->castTo(sc, tb1->next); - type = e1->type; - e = this; - } - else - { - error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars()); - type = Type::tint32; - e = this; - } - return e; -} - -/************************************************************/ - -MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2) -{ -} - -Expression *MulAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - if (e2->type->isfloating()) - { Type *t1; - Type *t2; - - t1 = e1->type; - t2 = e2->type; - if (t1->isreal()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - e2 = e2->castTo(sc, t1); - } - } - else if (t1->isimaginary()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - } - } - } - return this; -} - -/************************************************************/ - -DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2) -{ -} - -Expression *DivAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - if (e2->type->isimaginary()) - { Type *t1; - Type *t2; - - t1 = e1->type; - if (t1->isreal()) - { // x/iv = i(-x/v) - // Therefore, the result is 0 - e2 = new CommaExp(loc, e2, new RealExp(loc, 0, t1)); - e2->type = t1; - e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - else if (t1->isimaginary()) - { Expression *e; - - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - } - return this; -} - -/************************************************************/ - -ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2) -{ -} - -Expression *ModAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssign(sc); -} - -/************************************************************/ - -ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2) -{ -} - -Expression *ShlAssignExp::semantic(Scope *sc) -{ Expression *e; - - //printf("ShlAssignExp::semantic()\n"); - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LLVMDC - return this; -} - -/************************************************************/ - -ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2) -{ -} - -Expression *ShrAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LLVMDC - return this; -} - -/************************************************************/ - -UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2) -{ -} - -Expression *UshrAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LLVMDC - return this; -} - -/************************************************************/ - -AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2) -{ -} - -Expression *AndAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************************************************/ - -OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2) -{ -} - -Expression *OrAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************************************************/ - -XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2) -{ -} - -Expression *XorAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************* AddExp *****************************/ - -AddExp::AddExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2) -{ - llvmFieldIndex = false; -} - -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->next->equals(tb2->next) - ) - { - 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->next->size(); - e = new DivExp(loc, this, new IntegerExp(0, stride, Type::tptrdiff_t)); - e->type = Type::tptrdiff_t; - return e; - } - else if (t2->isintegral()) - e = scaleFactor(sc); - else - { error("incompatible types for -"); - return new IntegerExp(0); - } - } - else if (t2->ty == Tpointer) - { - type = e2->type; - error("can't subtract pointer from %s", e1->type->toChars()); - return new IntegerExp(0); - } - 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->next->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->next->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 - { - 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); - e1->checkArithmetic(); - e2->checkArithmetic(); - if (type->isfloating()) - { Type *t1 = e1->type; - Type *t2 = e2->type; - - if (t1->isreal()) - { - type = t2; - } - else if (t2->isreal()) - { - type = t1; - } - else if (t1->isimaginary()) - { - if (t2->isimaginary()) - { Expression *e; - - switch (t1->ty) - { - case Timaginary32: type = Type::tfloat32; break; - case Timaginary64: type = Type::tfloat64; break; - case Timaginary80: type = Type::tfloat80; break; - default: assert(0); - } - - // iy * iv = -yv - e1->type = type; - e2->type = type; - e = new NegExp(loc, this); - e = e->semantic(sc); - return e; - } - else - type = t2; // t2 is complex - } - else if (t2->isimaginary()) - { - type = t1; // t1 is complex - } - } - return this; -} - -/************************************************************/ - -DivExp::DivExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2) -{ -} - -Expression *DivExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - if (type->isfloating()) - { Type *t1 = e1->type; - Type *t2 = e2->type; - - if (t1->isreal()) - { - type = t2; - if (t2->isimaginary()) - { Expression *e; - - // x/iv = i(-x/v) - e2->type = t1; - e = new NegExp(loc, this); - e = e->semantic(sc); - return e; - } - } - else if (t2->isreal()) - { - type = t1; - } - else if (t1->isimaginary()) - { - if (t2->isimaginary()) - { - switch (t1->ty) - { - case Timaginary32: type = Type::tfloat32; break; - case Timaginary64: type = Type::tfloat64; break; - case Timaginary80: type = Type::tfloat80; break; - default: assert(0); - } - } - else - type = t2; // t2 is complex - } - else if (t2->isimaginary()) - { - type = t1; // t1 is complex - } - } - return this; -} - -/************************************************************/ - -ModExp::ModExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2) -{ -} - -Expression *ModExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - e1->checkArithmetic(); - 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); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LLVMDC - type = e1->type; - } - return this; -} - -/************************************************************/ - -ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2) -{ -} - -Expression *ShrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LLVMDC - type = e1->type; - } - return this; -} - -/************************************************************/ - -UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2) -{ -} - -Expression *UshrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LLVMDC - 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); - e1->checkIntegral(); - e2->checkIntegral(); - } - } - return this; -} - -/************************************************************/ - -OrExp::OrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKor, sizeof(OrExp), e1, e2) -{ -} - -Expression *OrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - e1->checkIntegral(); - e2->checkIntegral(); - } - } - return this; -} - -/************************************************************/ - -XorExp::XorExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKxor, sizeof(XorExp), e1, e2) -{ -} - -Expression *XorExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - e1->checkIntegral(); - e2->checkIntegral(); - } - } - return this; -} - - -/************************************************************/ - -OrOrExp::OrOrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKoror, sizeof(OrOrExp), e1, e2) -{ -} - -Expression *OrOrExp::semantic(Scope *sc) -{ - unsigned cs1; - - // same as for AndAnd - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToPointer(); - e1 = e1->checkToBoolean(); - cs1 = sc->callSuper; - - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate e2 if we don't have to. - */ - e1 = e1->optimize(WANTflags); - if (e1->isBool(TRUE)) - { - return new IntegerExp(loc, 1, Type::tboolean); - } - } - - e2 = e2->semantic(sc); - sc->mergeCallSuper(loc, cs1); - e2 = resolveProperties(sc, e2); - e2 = e2->checkToPointer(); - - type = Type::tboolean; - if (e1->type->ty == Tvoid) - type = Type::tvoid; - if (e2->op == TOKtype || e2->op == TOKimport) - error("%s is not an expression", e2->toChars()); - return this; -} - -Expression *OrOrExp::checkToBoolean() -{ - e2 = e2->checkToBoolean(); - return this; -} - -int OrOrExp::isBit() -{ - return TRUE; -} - -int OrOrExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return e1->checkSideEffect(2) || e2->checkSideEffect(2); - } - else - { e1->checkSideEffect(1); - return e2->checkSideEffect(flag); - } -} - -/************************************************************/ - -AndAndExp::AndAndExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKandand, sizeof(AndAndExp), e1, e2) -{ -} - -Expression *AndAndExp::semantic(Scope *sc) -{ - unsigned cs1; - - // same as for OrOr - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToPointer(); - e1 = e1->checkToBoolean(); - cs1 = sc->callSuper; - - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate e2 if we don't have to. - */ - e1 = e1->optimize(WANTflags); - if (e1->isBool(FALSE)) - { - return new IntegerExp(loc, 0, Type::tboolean); - } - } - - e2 = e2->semantic(sc); - sc->mergeCallSuper(loc, cs1); - e2 = resolveProperties(sc, e2); - e2 = e2->checkToPointer(); - - type = Type::tboolean; - if (e1->type->ty == Tvoid) - type = Type::tvoid; - if (e2->op == TOKtype || e2->op == TOKimport) - error("%s is not an expression", e2->toChars()); - return this; -} - -Expression *AndAndExp::checkToBoolean() -{ - e2 = e2->checkToBoolean(); - return this; -} - -int AndAndExp::isBit() -{ - return TRUE; -} - -int AndAndExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return e1->checkSideEffect(2) || e2->checkSideEffect(2); - } - else - { - e1->checkSideEffect(1); - return e2->checkSideEffect(flag); - } -} - -/************************************************************/ - -InExp::InExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKin, sizeof(InExp), e1, e2) -{ -} - -Expression *InExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - //type = Type::tboolean; - Type *t2b = e2->type->toBasetype(); - if (t2b->ty != Taarray) - { - error("rvalue of in expression must be an associative array, not %s", e2->type->toChars()); - type = Type::terror; - } - else - { - TypeAArray *ta = (TypeAArray *)t2b; - - // Convert key to type of key - e1 = e1->implicitCastTo(sc, ta->index); - - // Return type is pointer to value - type = ta->next->pointerTo(); - } - return this; -} - -int InExp::isBit() -{ - return FALSE; -} - - -/************************************************************/ - -/* This deletes the key e1 from the associative array e2 - */ - -RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2) -{ - type = Type::tvoid; -} - -/************************************************************/ - -CmpExp::CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(CmpExp), e1, e2) -{ -} - -Expression *CmpExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - Type *t2; - -#if LOGSEMANTIC - printf("CmpExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - { - e = new CmpExp(op, loc, e, new IntegerExp(loc, 0, Type::tint32)); - e = e->semantic(sc); - return e; - } - - typeCombine(sc); - type = Type::tboolean; - - // Special handling for array comparisons - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if ((t1->ty == Tarray || t1->ty == Tsarray) && - (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; - 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) -{ -} - -Expression *EqualExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - Type *t2; - - //printf("EqualExp::semantic('%s')\n", toChars()); - if (type) - return this; - - BinExp::semanticp(sc); - - /* Before checking for operator overloading, check to see if we're - * comparing the addresses of two statics. If so, we can just see - * if they are the same symbol. - */ - if (e1->op == TOKaddress && e2->op == TOKaddress) - { AddrExp *ae1 = (AddrExp *)e1; - AddrExp *ae2 = (AddrExp *)e2; - - if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar) - { VarExp *ve1 = (VarExp *)ae1->e1; - VarExp *ve2 = (VarExp *)ae2->e1; - - if (ve1->var == ve2->var /*|| ve1->var->toSymbol() == ve2->var->toSymbol()*/) - { - // They are the same, result is 'true' for ==, 'false' for != - e = new IntegerExp(loc, (op == TOKequal), Type::tboolean); - return e; - } - } - } - - //if (e2->op != TOKnull) - { - e = op_overload(sc); - if (e) - { - if (op == TOKnotequal) - { - e = new NotExp(e->loc, e); - e = e->semantic(sc); - } - return e; - } - } - - e = typeCombine(sc); - type = Type::tboolean; - - // Special handling for array comparisons - 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; - } - } - return this; -} - -Expression *CondExp::toLvalue(Scope *sc, Expression *ex) -{ - PtrExp *e; - - // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) - e = new PtrExp(loc, this, type); - - e1 = e1->addressOf(sc); - //e1 = e1->toLvalue(sc, NULL); - - e2 = e2->addressOf(sc); - //e2 = e2->toLvalue(sc, NULL); - - typeCombine(sc); - - type = e2->type; - return e; -} - -Expression *CondExp::modifiableLvalue(Scope *sc, Expression *e) -{ - error("conditional expression %s is not a modifiable lvalue", toChars()); - return this; -} - -void CondExp::checkEscape() -{ - e1->checkEscape(); - e2->checkEscape(); -} - - -Expression *CondExp::checkToBoolean() -{ - e1 = e1->checkToBoolean(); - e2 = e2->checkToBoolean(); - return this; -} - -int CondExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return econd->checkSideEffect(2) || - e1->checkSideEffect(2) || - e2->checkSideEffect(2); - } - else - { - econd->checkSideEffect(1); - e1->checkSideEffect(flag); - return e2->checkSideEffect(flag); - } -} - -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); -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include +#include +#include +#include + +#if _WIN32 && __DMC__ +extern "C" char * __cdecl __locale_decpoint; +#endif + +#if IN_GCC +// Issues with using -include total.h (defines integer_t) and then complex.h fails... +#undef integer_t +#endif + +#ifdef __APPLE__ +#define integer_t dmd_integer_t +#endif + +#if IN_GCC || IN_LLVM +#include "mem.h" +#elif _WIN32 +#include "..\root\mem.h" +#elif linux +#include "../root/mem.h" +#endif + +//#include "port.h" +#include "mtype.h" +#include "init.h" +#include "expression.h" +#include "template.h" +#include "utf.h" +#include "enum.h" +#include "scope.h" +#include "statement.h" +#include "declaration.h" +#include "aggregate.h" +#include "import.h" +#include "id.h" +#include "dsymbol.h" +#include "module.h" +#include "attrib.h" +#include "hdrgen.h" +#include "parse.h" + +Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim); + +#define LOGSEMANTIC 0 + +/********************************** + * Set operator precedence for each operator. + */ + +// Operator precedence - greater values are higher precedence + +enum PREC +{ + PREC_zero, + PREC_expr, + PREC_assign, + PREC_cond, + PREC_oror, + PREC_andand, + PREC_or, + PREC_xor, + PREC_and, + PREC_equal, + PREC_rel, + PREC_shift, + PREC_add, + PREC_mul, + PREC_unary, + PREC_primary, +}; + +enum PREC precedence[TOKMAX]; + +void initPrecedence() +{ + precedence[TOKdotvar] = PREC_primary; + precedence[TOKimport] = PREC_primary; + precedence[TOKidentifier] = PREC_primary; + precedence[TOKthis] = PREC_primary; + precedence[TOKsuper] = PREC_primary; + precedence[TOKint64] = PREC_primary; + precedence[TOKfloat64] = PREC_primary; + precedence[TOKnull] = PREC_primary; + precedence[TOKstring] = PREC_primary; + precedence[TOKarrayliteral] = PREC_primary; + precedence[TOKtypedot] = PREC_primary; + precedence[TOKtypeid] = PREC_primary; + precedence[TOKis] = PREC_primary; + precedence[TOKassert] = PREC_primary; + precedence[TOKfunction] = PREC_primary; + precedence[TOKvar] = PREC_primary; + + // post + precedence[TOKdotti] = PREC_primary; + precedence[TOKdot] = PREC_primary; +// precedence[TOKarrow] = PREC_primary; + precedence[TOKplusplus] = PREC_primary; + precedence[TOKminusminus] = PREC_primary; + precedence[TOKcall] = PREC_primary; + precedence[TOKslice] = PREC_primary; + precedence[TOKarray] = PREC_primary; + + precedence[TOKaddress] = PREC_unary; + precedence[TOKstar] = PREC_unary; + precedence[TOKneg] = PREC_unary; + precedence[TOKuadd] = PREC_unary; + precedence[TOKnot] = PREC_unary; + precedence[TOKtobool] = PREC_add; + precedence[TOKtilde] = PREC_unary; + precedence[TOKdelete] = PREC_unary; + precedence[TOKnew] = PREC_unary; + precedence[TOKcast] = PREC_unary; + + precedence[TOKmul] = PREC_mul; + precedence[TOKdiv] = PREC_mul; + precedence[TOKmod] = PREC_mul; + + precedence[TOKadd] = PREC_add; + precedence[TOKmin] = PREC_add; + precedence[TOKcat] = PREC_add; + + precedence[TOKshl] = PREC_shift; + precedence[TOKshr] = PREC_shift; + precedence[TOKushr] = PREC_shift; + + precedence[TOKlt] = PREC_rel; + precedence[TOKle] = PREC_rel; + precedence[TOKgt] = PREC_rel; + precedence[TOKge] = PREC_rel; + precedence[TOKunord] = PREC_rel; + precedence[TOKlg] = PREC_rel; + precedence[TOKleg] = PREC_rel; + precedence[TOKule] = PREC_rel; + precedence[TOKul] = PREC_rel; + precedence[TOKuge] = PREC_rel; + precedence[TOKug] = PREC_rel; + precedence[TOKue] = PREC_rel; + precedence[TOKin] = PREC_rel; + + precedence[TOKequal] = PREC_equal; + precedence[TOKnotequal] = PREC_equal; + precedence[TOKidentity] = PREC_equal; + precedence[TOKnotidentity] = PREC_equal; + + precedence[TOKand] = PREC_and; + + precedence[TOKxor] = PREC_xor; + + precedence[TOKor] = PREC_or; + + precedence[TOKandand] = PREC_andand; + + precedence[TOKoror] = PREC_oror; + + precedence[TOKquestion] = PREC_cond; + + precedence[TOKassign] = PREC_assign; + precedence[TOKconstruct] = PREC_assign; + precedence[TOKblit] = PREC_assign; + precedence[TOKaddass] = PREC_assign; + precedence[TOKminass] = PREC_assign; + precedence[TOKcatass] = PREC_assign; + precedence[TOKmulass] = PREC_assign; + precedence[TOKdivass] = PREC_assign; + precedence[TOKmodass] = PREC_assign; + precedence[TOKshlass] = PREC_assign; + precedence[TOKshrass] = PREC_assign; + precedence[TOKushrass] = PREC_assign; + precedence[TOKandass] = PREC_assign; + precedence[TOKorass] = PREC_assign; + precedence[TOKxorass] = PREC_assign; + + precedence[TOKcomma] = PREC_expr; +} + +/***************************************** + * Determine if 'this' is available. + * If it is, return the FuncDeclaration that has it. + */ + +FuncDeclaration *hasThis(Scope *sc) +{ FuncDeclaration *fd; + FuncDeclaration *fdthis; + + //printf("hasThis()\n"); + fdthis = sc->parent->isFuncDeclaration(); + //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : ""); + + // Go upwards until we find the enclosing member function + fd = fdthis; + while (1) + { + if (!fd) + { + goto Lno; + } + if (!fd->isNested()) + break; + + Dsymbol *parent = fd->parent; + while (parent) + { + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + parent = ti->parent; + else + break; + } + + fd = fd->parent->isFuncDeclaration(); + } + + if (!fd->isThis()) + { //printf("test '%s'\n", fd->toChars()); + goto Lno; + } + + assert(fd->vthis); + return fd; + +Lno: + return NULL; // don't have 'this' available +} + + +/*************************************** + * Pull out any properties. + */ + +Expression *resolveProperties(Scope *sc, Expression *e) +{ + //printf("resolveProperties(%s)\n", e->toChars()); + if (e->type) + { + Type *t = e->type->toBasetype(); + + if (t->ty == Tfunction) + { + e = 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 e; +} + +/****************************** + * Perform semantic() on an array of Expressions. + */ + +void arrayExpressionSemantic(Expressions *exps, Scope *sc) +{ + if (exps) + { + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + e = e->semantic(sc); + exps->data[i] = (void *)e; + } + } +} + +/**************************************** + * Expand tuples. + */ + +void expandTuples(Expressions *exps) +{ + //printf("expandTuples()\n"); + if (exps) + { + for (size_t i = 0; i < exps->dim; i++) + { Expression *arg = (Expression *)exps->data[i]; + if (!arg) + continue; + + // Look for tuple with 0 members + if (arg->op == TOKtype) + { TypeExp *e = (TypeExp *)arg; + if (e->type->toBasetype()->ty == Ttuple) + { TypeTuple *tt = (TypeTuple *)e->type->toBasetype(); + + if (!tt->arguments || tt->arguments->dim == 0) + { + exps->remove(i); + if (i == exps->dim) + return; + i--; + continue; + } + } + } + + // Inline expand all the tuples + while (arg->op == TOKtuple) + { TupleExp *te = (TupleExp *)arg; + + exps->remove(i); // remove arg + exps->insert(i, te->exps); // replace with tuple contents + if (i == exps->dim) + return; // empty tuple, no more arguments + arg = (Expression *)exps->data[i]; + } + } + } +} + +/**************************************** + * Preprocess arguments to function. + */ + +void preFunctionArguments(Loc loc, Scope *sc, Expressions *exps) +{ + if (exps) + { + expandTuples(exps); + + for (size_t i = 0; i < exps->dim; i++) + { Expression *arg = (Expression *)exps->data[i]; + + if (!arg->type) + { +#ifdef DEBUG + if (!global.gag) + printf("1: \n"); +#endif + arg->error("%s is not an expression", arg->toChars()); + arg = new IntegerExp(arg->loc, 0, Type::tint32); + } + + arg = resolveProperties(sc, arg); + exps->data[i] = (void *) arg; + + //arg->rvalue(); +#if 0 + if (arg->type->ty == Tfunction) + { + arg = new AddrExp(arg->loc, arg); + arg = arg->semantic(sc); + exps->data[i] = (void *) arg; + } +#endif + } + } +} + + +/**************************************** + * 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 functionArguments(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments) +{ + unsigned n; + int done; + Type *tb; + + //printf("functionArguments()\n"); + assert(arguments); + size_t nargs = arguments ? arguments->dim : 0; + size_t nparams = Argument::dim(tf->parameters); + + if (nargs > nparams && tf->varargs == 0) + error(loc, "expected %zu arguments, not %zu", nparams, nargs); + + n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) + + done = 0; + for (size_t i = 0; i < n; i++) + { + Expression *arg; + + if (i < nargs) + arg = (Expression *)arguments->data[i]; + else + arg = NULL; + + if (i < nparams) + { + Argument *p = Argument::getNth(tf->parameters, i); + + if (!arg) + { + if (!p->defaultArg) + { + if (tf->varargs == 2 && i + 1 == nparams) + goto L2; + error(loc, "expected %zu arguments, not %zu", nparams, nargs); + break; + } + arg = p->defaultArg->copy(); + arguments->push(arg); + nargs++; + } + + if (tf->varargs == 2 && i + 1 == nparams) + { + //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars()); + if (arg->implicitConvTo(p->type)) + { + if (nargs != nparams) + error(loc, "expected %zu arguments, not %zu", nparams, nargs); + goto L1; + } + L2: + Type *tb = p->type->toBasetype(); + Type *tret = p->isLazyArray(); + switch (tb->ty) + { + case Tsarray: + case Tarray: + { // Create a static array variable v of type arg->type +#ifdef IN_GCC + /* GCC 4.0 does not like zero length arrays used like + this; pass a null array value instead. Could also + just make a one-element array. */ + if (nargs - i == 0) + { + arg = new NullExp(loc); + break; + } +#endif + static int idn; + char name[10 + sizeof(idn)*3 + 1]; + sprintf(name, "__arrayArg%d", ++idn); + Identifier *id = Lexer::idPool(name); + Type *t = new TypeSArray(tb->next, new IntegerExp(nargs - i)); + t = t->semantic(loc, sc); + VarDeclaration *v = new VarDeclaration(loc, t, id, new VoidInitializer(loc)); + v->semantic(sc); + v->parent = sc->parent; + //sc->insert(v); + + Expression *c = new DeclarationExp(0, v); + c->type = v->type; + + for (size_t u = i; u < nargs; u++) + { Expression *a = (Expression *)arguments->data[u]; + if (tret && !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)); + e = new AssignExp(loc, e, a); + if (c) + c = new CommaExp(loc, c, e); + else + c = e; + } + 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)) + arg = arg->implicitCastTo(sc, p->type); + 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()); + } + + // Convert static arrays to pointers + tb = arg->type->toBasetype(); + if (tb->ty == Tsarray) + { + arg = arg->checkToPointer(); + } + + // Convert lazy argument to a delegate + if (p->storageClass & STClazy) + { + arg = arg->toDelegate(sc, p->type); + } + } + else + { + + // If not D linkage, do promotions + if (tf->linkage != LINKd) + { + // Promote bytes, words, etc., to ints + arg = arg->integralPromotions(sc); + + // Promote floats to doubles + switch (arg->type->ty) + { + case Tfloat32: + arg = arg->castTo(sc, Type::tfloat64); + break; + + case Timaginary32: + arg = arg->castTo(sc, Type::timaginary64); + break; + } + } + + // Convert static arrays to dynamic arrays + tb = arg->type->toBasetype(); + if (tb->ty == Tsarray) + { TypeSArray *ts = (TypeSArray *)tb; + Type *ta = tb->next->arrayOf(); + if (ts->size(arg->loc) == 0) + { arg = new NullExp(arg->loc); + arg->type = ta; + } + else + arg = arg->castTo(sc, ta); + } + + arg->rvalue(); + } + arg = arg->optimize(WANTvalue); + arguments->data[i] = (void *) arg; + if (done) + break; + } + +#if !IN_LLVM + // If D linkage and variadic, add _arguments[] as first argument + if (tf->linkage == LINKd && tf->varargs == 1) + { + Expression *e; + + e = createTypeInfoArray(sc, (Expression **)&arguments->data[nparams], + arguments->dim - nparams); + arguments->insert(0, e); + } +#endif +} + +/************************************************** + * Write expression out to buf, but wrap it + * in ( ) if its precedence is less than pr. + */ + +void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) +{ + if (precedence[e->op] < 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) +{ + this->loc = loc; + this->op = op; + this->size = size; + type = NULL; +} + +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); + return (Expression *)memcpy(e, this, size); +} + +/************************** + * Semantically analyze Expression. + * Determine types, fold constants, etc. + */ + +Expression *Expression::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("Expression::semantic()\n"); +#endif + if (type) + type = type->semantic(loc, sc); + else + type = Type::tvoid; + return this; +} + +void Expression::print() +{ + fprintf(stdmsg, "%s\n", toChars()); + fflush(stdmsg); +} + +char *Expression::toChars() +{ OutBuffer *buf; + HdrGenState hgs; + + memset(&hgs, 0, sizeof(hgs)); + buf = new OutBuffer(); + toCBuffer(buf, &hgs); + return buf->toChars(); +} + +void Expression::error(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + ::verror(loc, format, ap); + va_end( ap ); +} + +void Expression::rvalue() +{ + if (type && type->toBasetype()->ty == Tvoid) + { error("expression %s is void and has no value", toChars()); +#if 0 + dump(0); + halt(); +#endif + } +} + +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; +} + +integer_t Expression::toInteger() +{ + //printf("Expression %s\n", Token::toChars(op)); + error("Integer constant expression expected instead of %s", toChars()); + return 0; +} + +uinteger_t Expression::toUInteger() +{ + //printf("Expression %s\n", Token::toChars(op)); + return (uinteger_t)toInteger(); +} + +real_t Expression::toReal() +{ + error("Floating point constant expression expected instead of %s", toChars()); + return 0; +} + +real_t Expression::toImaginary() +{ + error("Floating point constant expression expected instead of %s", toChars()); + return 0; +} + +complex_t Expression::toComplex() +{ + error("Floating point constant expression expected instead of %s", toChars()); +#ifdef IN_GCC + return complex_t(real_t(0)); // %% nicer +#else + return 0; +#endif +} + +void Expression::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(op)); +} + +void Expression::toMangleBuffer(OutBuffer *buf) +{ + error("expression %s is not a valid template value argument", toChars()); +} + +/******************************* + * Give error if we're not an lvalue. + * If we can, convert expression to be an lvalue. + */ + +Expression *Expression::toLvalue(Scope *sc, Expression *e) +{ + if (!e) + e = this; + else if (!loc.filename) + loc = e->loc; + error("%s is not an lvalue", e->toChars()); + return this; +} + +Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) +{ + // See if this expression is a modifiable lvalue (i.e. not const) + return toLvalue(sc, e); +} + +/************************************ + * Detect cases where pointers to the stack can 'escape' the + * lifetime of the stack frame. + */ + +void Expression::checkEscape() +{ +} + +void Expression::checkScalar() +{ + if (!type->isscalar()) + error("'%s' is not a scalar, it is a %s", toChars(), type->toChars()); +} + +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 IntegerExp(0); + } + return this; +} + +Expression *Expression::checkArithmetic() +{ + if (!type->isintegral() && !type->isfloating()) + { error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars()); + return new IntegerExp(0); + } + return this; +} + +void Expression::checkDeprecated(Scope *sc, Dsymbol *s) +{ + s->checkDeprecated(loc, sc); +} + +/******************************** + * 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 = tb->next->pointerTo(); + } + return e; +} + +/****************************** + * Take address of expression. + */ + +Expression *Expression::addressOf(Scope *sc) +{ + Expression *e; + + //printf("Expression::addressOf()\n"); + e = toLvalue(sc, NULL); + e = new AddrExp(loc, e); + e->type = type->pointerTo(); + return e; +} + +/****************************** + * If this is a reference, dereference it. + */ + +Expression *Expression::deref() +{ + //printf("Expression::deref()\n"); + if (type->ty == Treference) + { Expression *e; + + e = new PtrExp(loc, this); + e->type = 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; +} + +Expressions *Expression::arraySyntaxCopy(Expressions *exps) +{ Expressions *a = NULL; + + if (exps) + { + a = new Expressions(); + a->setDim(exps->dim); + for (int i = 0; i < a->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + e = e->syntaxCopy(); + a->data[i] = e; + } + } + return a; +} + +/******************************** IntegerExp **************************/ + +IntegerExp::IntegerExp(Loc loc, integer_t value, Type *type) + : Expression(loc, TOKint64, sizeof(IntegerExp)) +{ + //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : ""); + if (type && !type->isscalar()) + { + error("integral constant must be scalar type, not %s", type->toChars()); + type = Type::terror; + } + this->type = type; + this->value = value; +} + +IntegerExp::IntegerExp(integer_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 +} + +integer_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 Tpointer: + case Tdchar: + case Tuns32: value = (d_uns32) value; break; + case Tint64: value = (d_int64) value; break; + case Tuns64: value = (d_uns64) value; break; + + case Tenum: + { + TypeEnum *te = (TypeEnum *)t; + t = te->sym->memtype; + continue; + } + + case Ttypedef: + { + TypeTypedef *tt = (TypeTypedef *)t; + t = tt->sym->basetype; + continue; + } + + default: + print(); + type->print(); + assert(0); + break; + } + break; + } + return value; +} + +real_t IntegerExp::toReal() +{ + Type *t; + + toInteger(); + t = type->toBasetype(); + if (t->ty == Tuns64) + return (real_t)(d_uns64)value; + else + return (real_t)(d_int64)value; +} + +real_t IntegerExp::toImaginary() +{ + return (real_t) 0; +} + +complex_t IntegerExp::toComplex() +{ + return toReal(); +} + +int IntegerExp::isBool(int result) +{ + return result ? value != 0 : value == 0; +} + +Expression *IntegerExp::semantic(Scope *sc) +{ + if (!type) + { + // Determine what the type of this number is + integer_t number = value; + + if (number & 0x8000000000000000LL) + type = Type::tuns64; + else if (number & 0xFFFFFFFF80000000LL) + type = Type::tint64; + else + type = Type::tint32; + } + else + { 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) +{ + integer_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'", v); + break; + } + case Tchar: + if (v == '\'') + buf->writestring("'\\''"); + else if (isprint(v) && v != '\\') + buf->printf("'%c'", (int)v); + else + buf->printf("'\\x%02x'", (int)v); + break; + + case Tint8: + buf->writestring("cast(byte)"); + goto L2; + + case Tint16: + buf->writestring("cast(short)"); + goto L2; + + case Tint32: + L2: + buf->printf("%d", (int)v); + break; + + case Tuns8: + buf->writestring("cast(ubyte)"); + goto L3; + + case Tuns16: + buf->writestring("cast(ushort)"); + goto L3; + + case Tuns32: + L3: + buf->printf("%du", (unsigned)v); + break; + + case Tint64: + buf->printf("%jdL", v); + break; + + case Tuns64: + 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(')'); + goto L3; + + default: +#ifdef DEBUG + t->print(); +#endif + assert(0); + } + } + else if (v & 0x8000000000000000LL) + buf->printf("0x%jx", v); + else + buf->printf("%jd", v); +} + +void IntegerExp::toMangleBuffer(OutBuffer *buf) +{ + if ((sinteger_t)value < 0) + buf->printf("N%jd", -value); + else + buf->printf("%jd", value); +} + +/******************************** 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); +} + +integer_t RealExp::toInteger() +{ +#ifdef IN_GCC + return toReal().toInt(); +#else + return (sinteger_t) toReal(); +#endif +} + +uinteger_t RealExp::toUInteger() +{ +#ifdef IN_GCC + return (uinteger_t) toReal().toInt(); +#else + return (uinteger_t) toReal(); +#endif +} + +real_t RealExp::toReal() +{ + return type->isreal() ? value : 0; +} + +real_t RealExp::toImaginary() +{ + return type->isreal() ? 0 : value; +} + +complex_t RealExp::toComplex() +{ +#ifdef __DMC__ + return toReal() + toImaginary() * I; +#else + return complex_t(toReal(), toImaginary()); +#endif +} + +/******************************** + * Test to see if two reals are the same. + * Regard NaN's as equivalent. + * Regard +0 and -0 as different. + */ + +int RealEquals(real_t x1, real_t x2) +{ + return (isnan(x1) && 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 + buf->printf("%La", value); // ensure exact duplication + + if (type) + { + Type *t = type->toBasetype(); + switch (t->ty) + { + case Tfloat32: + case Timaginary32: + case Tcomplex32: + buf->writeByte('F'); + break; + + case Tfloat80: + case Timaginary80: + case Tcomplex80: + buf->writeByte('L'); + break; + + default: + break; + } + if (t->isimaginary()) + buf->writeByte('i'); + } +} + +void RealExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + floatToBuffer(buf, type, value); +} + +void realToMangleBuffer(OutBuffer *buf, real_t value) +{ + /* Rely on %A to get portable mangling. + * Must munge result to get only identifier characters. + * + * Possible values from %A => mangled result + * NAN => NAN + * -INF => NINF + * INF => INF + * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79 + * 0X1.9P+2 => 19P2 + */ + + if (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]; + +#ifdef IN_GCC + char buf1[sizeof(value) * 3 + 8 + 1]; + char buf2[sizeof(value) * 3 + 8 + 1]; + creall(value).format(buf1, sizeof(buf1)); + cimagl(value).format(buf2, sizeof(buf2)); + sprintf(buffer, "(%s+%si)", buf1, buf2); +#else + sprintf(buffer, "(%Lg+%Lgi)", creall(value), cimagl(value)); + assert(strlen(buffer) < sizeof(buffer)); +#endif + return mem.strdup(buffer); +} + +integer_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 it was a with class + 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 = t->next; + e = new 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); + } + // Look to see if f is really a function template + FuncDeclaration *f = s->isFuncDeclaration(); + if (f && f->parent) + { TemplateInstance *ti = f->parent->isTemplateInstance(); + + if (ti && + !ti->isTemplateMixin() && + (ti->name == f->ident || + ti->toAlias()->ident == f->ident) + && + ti->tempdecl && ti->tempdecl->onemember) + { + TemplateDeclaration *tempdecl = ti->tempdecl; + if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's + tempdecl = tempdecl->overroot; // then get the start + e = new TemplateExp(loc, tempdecl); + e = e->semantic(sc); + return e; + } + } + e = new DsymbolExp(loc, s); + } + return e->semantic(sc); + } + error("undefined identifier %s", ident->toChars()); + type = Type::terror; + return this; +} + +char *IdentifierExp::toChars() +{ + return ident->toChars(); +} + +void IdentifierExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + buf->writestring(ident->toHChars2()); + else + buf->writestring(ident->toChars()); +} + +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; + Declaration *d; + ClassDeclaration *cd; + ClassDeclaration *thiscd = NULL; + Import *imp; + Package *pkg; + Type *t; + + //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); + //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind()); + if (type) + return this; + if (!s->isFuncDeclaration()) // functions are checked after overloading + checkDeprecated(sc, s); + s = s->toAlias(); + //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis()); + if (!s->isFuncDeclaration()) + checkDeprecated(sc, s); + + if (sc->func) + thiscd = sc->func->parent->isClassDeclaration(); + + // BUG: This should happen after overload resolution for functions, not before + if (s->needThis()) + { + if (hasThis(sc) /*&& !s->isFuncDeclaration()*/) + { + // 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 = e->semantic(sc); + return e; + } + v = s->isVarDeclaration(); + if (v) + { + //printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); + if (!type) + { type = v->type; + if (!v->type) + { error("forward reference of %s", v->toChars()); + type = Type::terror; + } + } + if (v->isConst() && type->toBasetype()->ty != Tsarray) + { + if (v->init) + { + if (v->inuse) + { + error("circular reference to '%s'", v->toChars()); + type = Type::tint32; + return this; + } + 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()); + 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) + { + ScopeExp *ie; + + ie = new ScopeExp(loc, imp->pkg); + return ie->semantic(sc); + } + pkg = s->isPackage(); + if (pkg) + { + ScopeExp *ie; + + ie = new ScopeExp(loc, pkg); + return ie->semantic(sc); + } + Module *mod = s->isModule(); + if (mod) + { + ScopeExp *ie; + + ie = new ScopeExp(loc, mod); + return ie->semantic(sc); + } + + t = s->getType(); + if (t) + { + return new TypeExp(loc, t); + } + + TupleDeclaration *tup = s->isTupleDeclaration(); + if (tup) + { + e = new TupleExp(loc, tup); + e = e->semantic(sc); + return e; + } + + TemplateInstance *ti = s->isTemplateInstance(); + if (ti && !global.errors) + { if (!ti->semanticdone) + ti->semantic(sc); + s = ti->inst->toAlias(); + if (!s->isTemplateInstance()) + goto Lagain; + e = new ScopeExp(loc, ti); + e = e->semantic(sc); + return e; + } + + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (td) + { + e = new TemplateExp(loc, td); + e = e->semantic(sc); + return e; + } + +Lerr: + error("%s '%s' is not a variable", s->kind(), s->toChars()); + type = Type::terror; + return this; +} + +char *DsymbolExp::toChars() +{ + return s->toChars(); +} + +void DsymbolExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(s->toChars()); +} + +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)) +{ + var = NULL; +} + +Expression *ThisExp::semantic(Scope *sc) +{ FuncDeclaration *fd; + FuncDeclaration *fdthis; + int nested = 0; + +#if LOGSEMANTIC + printf("ThisExp::semantic()\n"); +#endif + if (type) + { //assert(global.errors || var); + return this; + } + + /* Special case for typeof(this) and typeof(super) since both + * should work even if they are not inside a non-static member function + */ + if (sc->intypeof) + { + // Find enclosing struct or class + for (Dsymbol *s = sc->parent; 1; s = s->parent) + { + ClassDeclaration *cd; + StructDeclaration *sd; + + if (!s) + { + error("%s is not in a struct or class scope", toChars()); + goto Lerr; + } + cd = s->isClassDeclaration(); + if (cd) + { + type = cd->type; + return this; + } + sd = s->isStructDeclaration(); + if (sd) + { + type = sd->type->pointerTo(); + return this; + } + } + } + + fdthis = sc->parent->isFuncDeclaration(); + fd = hasThis(sc); // fd is the uplevel function with the 'this' variable + if (!fd) + goto Lerr; + + assert(fd->vthis); + var = fd->vthis; + assert(var->parent); + type = var->type; + var->isVarDeclaration()->checkNestedReference(sc, loc); +#if 0 + if (fd != fdthis) // if nested + { + fdthis->getLevel(loc, fd); + fd->vthis->nestedref = 1; + fd->nestedFrameRef = 1; + } +#endif + sc->callSuper |= CSXthis; + return this; + +Lerr: + error("'this' is only allowed in non-static member functions, not %s", sc->parent->toChars()); + type = Type::tint32; + return this; +} + +int ThisExp::isBool(int result) +{ + return result ? TRUE : FALSE; +} + +void ThisExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("this"); +} + +Expression *ThisExp::toLvalue(Scope *sc, Expression *e) +{ + return this; +} + +/******************************** SuperExp **************************/ + +SuperExp::SuperExp(Loc loc) + : ThisExp(loc) +{ + op = TOKsuper; +} + +Expression *SuperExp::semantic(Scope *sc) +{ FuncDeclaration *fd; + FuncDeclaration *fdthis; + ClassDeclaration *cd; + Dsymbol *s; + +#if LOGSEMANTIC + printf("SuperExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + /* Special case for typeof(this) and typeof(super) since both + * should work even if they are not inside a non-static member function + */ + if (sc->intypeof) + { + // Find enclosing class + for (Dsymbol *s = sc->parent; 1; s = s->parent) + { + ClassDeclaration *cd; + + if (!s) + { + error("%s is not in a class scope", toChars()); + goto Lerr; + } + cd = s->isClassDeclaration(); + if (cd) + { + cd = cd->baseClass; + if (!cd) + { error("class %s has no 'super'", s->toChars()); + goto Lerr; + } + type = cd->type; + return this; + } + } + } + + fdthis = sc->parent->isFuncDeclaration(); + fd = hasThis(sc); + if (!fd) + goto Lerr; + assert(fd->vthis); + var = fd->vthis; + assert(var->parent); + + s = fd->toParent(); + while (s && s->isTemplateInstance()) + s = s->toParent(); + assert(s); + cd = s->isClassDeclaration(); +//printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars()); + if (!cd) + goto Lerr; + if (!cd->baseClass) + { + error("no base class for %s", cd->toChars()); + type = fd->vthis->type; + } + else + { + type = cd->baseClass->type; + } + + var->isVarDeclaration()->checkNestedReference(sc, loc); +#if 0 + if (fd != fdthis) + { + fdthis->getLevel(loc, fd); + fd->vthis->nestedref = 1; + fd->nestedFrameRef = 1; + } +#endif + + sc->callSuper |= CSXsuper; + return this; + + +Lerr: + error("'super' is only allowed in non-static class member functions"); + type = Type::tint32; + return this; +} + +void SuperExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("super"); +} + + +/******************************** NullExp **************************/ + +NullExp::NullExp(Loc loc) + : Expression(loc, TOKnull, sizeof(NullExp)) +{ + committed = 0; +} + +Expression *NullExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("NullExp::semantic('%s')\n", toChars()); +#endif + // NULL is the same as (void *)0 + if (!type) + type = Type::tvoid->pointerTo(); + return this; +} + +int NullExp::isBool(int result) +{ + return result ? FALSE : TRUE; +} + +void NullExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("null"); +} + +void NullExp::toMangleBuffer(OutBuffer *buf) +{ + buf->writeByte('n'); +} + +/******************************** StringExp **************************/ + +StringExp::StringExp(Loc loc, char *string) + : Expression(loc, TOKstring, sizeof(StringExp)) +{ + this->string = string; + this->len = strlen(string); + this->sz = 1; + this->committed = 0; + this->postfix = 0; +} + +StringExp::StringExp(Loc loc, void *string, size_t len) + : Expression(loc, TOKstring, sizeof(StringExp)) +{ + this->string = string; + this->len = len; + this->sz = 1; + this->committed = 0; + this->postfix = 0; +} + +StringExp::StringExp(Loc loc, void *string, size_t len, unsigned char postfix) + : Expression(loc, TOKstring, sizeof(StringExp)) +{ + this->string = string; + this->len = len; + this->sz = 1; + this->committed = 0; + this->postfix = postfix; +} + +#if 0 +Expression *StringExp::syntaxCopy() +{ + printf("StringExp::syntaxCopy() %s\n", toChars()); + return copy(); +} +#endif + +int StringExp::equals(Object *o) +{ + //printf("StringExp::equals('%s')\n", o->toChars()); + if (o && o->dyncast() == DYNCAST_EXPRESSION) + { Expression *e = (Expression *)o; + + if (e->op == TOKstring) + { + return compare(o) == 0; + } + } + return FALSE; +} + +char *StringExp::toChars() +{ + OutBuffer buf; + HdrGenState hgs; + char *p; + + memset(&hgs, 0, sizeof(hgs)); + toCBuffer(&buf, &hgs); + buf.writeByte(0); + p = (char *)buf.data; + buf.data = NULL; + return p; +} + +Expression *StringExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("StringExp::semantic() %s\n", toChars()); +#endif + if (!type) + { OutBuffer buffer; + size_t newlen = 0; + char *p; + size_t u; + unsigned c; + + switch (postfix) + { + case 'd': + for (u = 0; u < len;) + { + p = utf_decodeChar((unsigned char *)string, len, &u, &c); + if (p) + { error("%s", p); + break; + } + else + { buffer.write4(c); + newlen++; + } + } + buffer.write4(0); + string = buffer.extractData(); + len = newlen; + sz = 4; + type = new TypeSArray(Type::tdchar, new IntegerExp(loc, len, Type::tindex)); + committed = 1; + break; + + case 'w': + for (u = 0; u < len;) + { + p = utf_decodeChar((unsigned char *)string, len, &u, &c); + if (p) + { error("%s", p); + break; + } + else + { buffer.writeUTF16(c); + newlen++; + if (c >= 0x10000) + newlen++; + } + } + buffer.writeUTF16(0); + string = buffer.extractData(); + len = newlen; + sz = 2; + type = new TypeSArray(Type::twchar, new IntegerExp(loc, len, Type::tindex)); + 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; +} + +/**************************************** + * Convert string to char[]. + */ + +StringExp *StringExp::toUTF8(Scope *sc) +{ + if (sz != 1) + { // Convert to UTF-8 string + committed = 0; + Expression *e = castTo(sc, Type::tchar->arrayOf()); + e = e->optimize(WANTvalue); + assert(e->op == TOKstring); + StringExp *se = (StringExp *)e; + assert(se->sz == 1); + return se; + } + return this; +} + +int StringExp::compare(Object *obj) +{ + // Used to sort case statement expressions so we can do an efficient lookup + StringExp *se2 = (StringExp *)(obj); + + // This is a kludge so isExpression() in template.c will return 5 + // for StringExp's. + if (!se2) + return 5; + + assert(se2->op == TOKstring); + + int len1 = len; + int len2 = se2->len; + + if (len1 == len2) + { + switch (sz) + { + case 1: + return strcmp((char *)string, (char *)se2->string); + + case 2: + { unsigned u; + d_wchar *s1 = (d_wchar *)string; + d_wchar *s2 = (d_wchar *)se2->string; + + for (u = 0; u < len; u++) + { + if (s1[u] != s2[u]) + return s1[u] - s2[u]; + } + } + + case 4: + { unsigned u; + d_dchar *s1 = (d_dchar *)string; + d_dchar *s2 = (d_dchar *)se2->string; + + for (u = 0; u < len; u++) + { + if (s1[u] != s2[u]) + return s1[u] - s2[u]; + } + } + break; + + default: + assert(0); + } + } + return len1 - len2; +} + +int StringExp::isBool(int result) +{ + return result ? TRUE : FALSE; +} + +unsigned StringExp::charAt(size_t i) +{ unsigned value; + + switch (sz) + { + case 1: + value = ((unsigned char *)string)[i]; + break; + + case 2: + value = ((unsigned short *)string)[i]; + break; + + case 4: + value = ((unsigned int *)string)[i]; + break; + + default: + assert(0); + break; + } + return value; +} + +void StringExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('"'); + for (size_t i = 0; i < len; i++) + { unsigned c = charAt(i); + + switch (c) + { + case '"': + case '\\': + if (!hgs->console) + buf->writeByte('\\'); + default: + if (c <= 0xFF) + { if (c <= 0x7F && (isprint(c) || hgs->console)) + buf->writeByte(c); + else + buf->printf("\\x%02x", c); + } + else if (c <= 0xFFFF) + buf->printf("\\x%02x\\x%02x", c & 0xFF, c >> 8); + else + buf->printf("\\x%02x\\x%02x\\x%02x\\x%02x", + c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24); + break; + } + } + buf->writeByte('"'); + if (postfix) + buf->writeByte(postfix); +} + +void StringExp::toMangleBuffer(OutBuffer *buf) +{ char m; + OutBuffer tmp; + char *p; + unsigned c; + size_t u; + unsigned char *q; + unsigned qlen; + + /* Write string in UTF-8 format + */ + switch (sz) + { case 1: + m = 'a'; + q = (unsigned char *)string; + qlen = len; + break; + case 2: + m = 'w'; + for (u = 0; u < len; ) + { + p = utf_decodeWchar((unsigned short *)string, len, &u, &c); + if (p) + error("%s", p); + else + tmp.writeUTF8(c); + } + q = tmp.data; + qlen = tmp.offset; + break; + case 4: + m = 'd'; + for (u = 0; u < len; u++) + { + c = ((unsigned *)string)[u]; + if (!utf_isValidDchar(c)) + error("invalid UCS-32 char \\U%08x", c); + else + tmp.writeUTF8(c); + } + q = tmp.data; + qlen = tmp.offset; + break; + default: + assert(0); + } + buf->writeByte(m); + buf->printf("%d_", qlen); + for (size_t i = 0; i < qlen; i++) + buf->printf("%02x", q[i]); +} + +/************************ ArrayLiteralExp ************************************/ + +// [ e1, e2, e3, ... ] + +ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements) + : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) +{ + this->elements = elements; +} + +ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e) + : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) +{ + elements = new Expressions; + elements->push(e); +} + +Expression *ArrayLiteralExp::syntaxCopy() +{ + return new ArrayLiteralExp(loc, arraySyntaxCopy(elements)); +} + +Expression *ArrayLiteralExp::semantic(Scope *sc) +{ Expression *e; + Type *t0 = NULL; + +#if LOGSEMANTIC + printf("ArrayLiteralExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + // Run semantic() on each element + for (int i = 0; i < elements->dim; i++) + { e = (Expression *)elements->data[i]; + e = e->semantic(sc); + elements->data[i] = (void *)e; + } + expandTuples(elements); + for (int i = 0; i < elements->dim; i++) + { e = (Expression *)elements->data[i]; + + if (!e->type) + error("%s has no value", e->toChars()); + e = resolveProperties(sc, e); + + unsigned char committed = 1; + if (e->op == TOKstring) + committed = ((StringExp *)e)->committed; + + if (!t0) + { t0 = e->type; + // Convert any static arrays to dynamic arrays + if (t0->ty == Tsarray) + { + t0 = t0->next->arrayOf(); + e = e->implicitCastTo(sc, t0); + } + } + else + e = e->implicitCastTo(sc, t0); + if (!committed && e->op == TOKstring) + { StringExp *se = (StringExp *)e; + se->committed = 0; + } + elements->data[i] = (void *)e; + } + + if (!t0) + t0 = Type::tvoid; + type = new TypeSArray(t0, new IntegerExp(elements->dim)); + type = type->semantic(loc, sc); + return this; +} + +int ArrayLiteralExp::checkSideEffect(int flag) +{ int f = 0; + + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + + f |= e->checkSideEffect(2); + } + if (flag == 0 && f == 0) + Expression::checkSideEffect(0); + return f; +} + +int ArrayLiteralExp::isBool(int result) +{ + size_t dim = elements ? elements->dim : 0; + return result ? (dim != 0) : (dim == 0); +} + +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 = (Expression *)elements->data[i]; + e->toMangleBuffer(buf); + } +} + +/************************ AssocArrayLiteralExp ************************************/ + +// [ key0 : value0, key1 : value1, ... ] + +AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc, + Expressions *keys, Expressions *values) + : Expression(loc, TOKassocarrayliteral, sizeof(AssocArrayLiteralExp)) +{ + assert(keys->dim == values->dim); + this->keys = keys; + this->values = values; +} + +Expression *AssocArrayLiteralExp::syntaxCopy() +{ + return new AssocArrayLiteralExp(loc, + arraySyntaxCopy(keys), arraySyntaxCopy(values)); +} + +Expression *AssocArrayLiteralExp::semantic(Scope *sc) +{ Expression *e; + Type *tkey = NULL; + Type *tvalue = NULL; + +#if LOGSEMANTIC + printf("AssocArrayLiteralExp::semantic('%s')\n", toChars()); +#endif + + // Run semantic() on each element + for (size_t i = 0; i < keys->dim; i++) + { Expression *key = (Expression *)keys->data[i]; + Expression *value = (Expression *)values->data[i]; + + key = key->semantic(sc); + value = value->semantic(sc); + + keys->data[i] = (void *)key; + values->data[i] = (void *)value; + } + expandTuples(keys); + expandTuples(values); + if (keys->dim != values->dim) + { + error("number of keys is %u, must match number of values %u", keys->dim, values->dim); + keys->setDim(0); + values->setDim(0); + } + for (size_t i = 0; i < keys->dim; i++) + { Expression *key = (Expression *)keys->data[i]; + Expression *value = (Expression *)values->data[i]; + + if (!key->type) + error("%s has no value", key->toChars()); + if (!value->type) + error("%s has no value", value->toChars()); + key = resolveProperties(sc, key); + value = resolveProperties(sc, value); + + if (!tkey) + tkey = key->type; + else + key = key->implicitCastTo(sc, tkey); + keys->data[i] = (void *)key; + + if (!tvalue) + tvalue = value->type; + else + value = value->implicitCastTo(sc, tvalue); + values->data[i] = (void *)value; + } + + if (!tkey) + tkey = Type::tvoid; + if (!tvalue) + tvalue = Type::tvoid; + type = new TypeAArray(tvalue, tkey); + type = type->semantic(loc, sc); + return this; +} + +int AssocArrayLiteralExp::checkSideEffect(int flag) +{ int f = 0; + + for (size_t i = 0; i < keys->dim; i++) + { Expression *key = (Expression *)keys->data[i]; + Expression *value = (Expression *)values->data[i]; + + f |= key->checkSideEffect(2); + f |= value->checkSideEffect(2); + } + if (flag == 0 && f == 0) + Expression::checkSideEffect(0); + return f; +} + +int AssocArrayLiteralExp::isBool(int result) +{ + size_t dim = keys->dim; + return result ? (dim != 0) : (dim == 0); +} + +void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('['); + for (size_t i = 0; i < keys->dim; i++) + { Expression *key = (Expression *)keys->data[i]; + Expression *value = (Expression *)values->data[i]; + + if (i) + buf->writeByte(','); + expToCBuffer(buf, hgs, key, PREC_assign); + buf->writeByte(':'); + expToCBuffer(buf, hgs, value, PREC_assign); + } + buf->writeByte(']'); +} + +void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf) +{ + size_t dim = keys->dim; + buf->printf("A%u", dim); + for (size_t i = 0; i < dim; i++) + { Expression *key = (Expression *)keys->data[i]; + Expression *value = (Expression *)values->data[i]; + + key->toMangleBuffer(buf); + value->toMangleBuffer(buf); + } +} + +/************************ StructLiteralExp ************************************/ + +// sd( e1, e2, e3, ... ) + +StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements) + : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp)) +{ + this->sd = sd; + this->elements = elements; + this->sym = NULL; + this->soffset = 0; + this->fillHoles = 1; +} + +Expression *StructLiteralExp::syntaxCopy() +{ + return new StructLiteralExp(loc, sd, arraySyntaxCopy(elements)); +} + +Expression *StructLiteralExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("StructLiteralExp::semantic('%s')\n", toChars()); +#endif + + // Run semantic() on each element + for (size_t i = 0; i < elements->dim; i++) + { e = (Expression *)elements->data[i]; + if (!e) + continue; + e = e->semantic(sc); + elements->data[i] = (void *)e; + } + expandTuples(elements); + size_t offset = 0; + for (size_t i = 0; i < elements->dim; i++) + { e = (Expression *)elements->data[i]; + if (!e) + continue; + + if (!e->type) + error("%s has no value", e->toChars()); + e = resolveProperties(sc, e); + if (i >= 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) + { e = v->init->toExpression(); + if (!e) + error("cannot make expression out of initializer for %s", v->toChars()); + } + else + { e = v->type->defaultInit(); + e->loc = loc; + } + offset = v->offset + v->type->size(); + } + elements->push(e); + } + + type = sd->type; + return this; +} + +/************************************** + * Gets expression at offset of type. + * Returns NULL if not found. + */ + +Expression *StructLiteralExp::getField(Type *type, unsigned offset) +{ Expression *e = NULL; + int i = getFieldIndex(type, offset); + + if (i != -1) + { e = (Expression *)elements->data[i]; + if (e) + { + e = e->copy(); + e->type = type; + } + } + return e; +} + +/************************************ + * Get index of field. + * Returns -1 if not found. + */ + +int StructLiteralExp::getFieldIndex(Type *type, unsigned offset) +{ + /* Find which field offset is by looking at the field offsets + */ + 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; +} + + +Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e) +{ + return this; +} + + +int StructLiteralExp::checkSideEffect(int flag) +{ int f = 0; + + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + if (!e) + continue; + + f |= e->checkSideEffect(2); + } + if (flag == 0 && f == 0) + Expression::checkSideEffect(0); + return f; +} + +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 = (Expression *)elements->data[i]; + if (e) + e->toMangleBuffer(buf); + else + buf->writeByte('v'); // 'v' for void + } +} + +/************************ TypeDotIdExp ************************************/ + +/* Things like: + * int.size + * foo.size + * (foo).size + * cast(foo).size + */ + +TypeDotIdExp::TypeDotIdExp(Loc loc, Type *type, Identifier *ident) + : Expression(loc, TOKtypedot, sizeof(TypeDotIdExp)) +{ + this->type = type; + this->ident = ident; +} + +Expression *TypeDotIdExp::syntaxCopy() +{ + TypeDotIdExp *te = new TypeDotIdExp(loc, type->syntaxCopy(), ident); + return te; +} + +Expression *TypeDotIdExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("TypeDotIdExp::semantic()\n"); +#endif + e = new DotIdExp(loc, new TypeExp(loc, type), ident); + e = e->semantic(sc); + return e; +} + +void TypeDotIdExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('('); + type->toCBuffer(buf, NULL, hgs); + buf->writeByte(')'); + buf->writeByte('.'); + buf->writestring(ident->toChars()); +} + +/************************************************************/ + +// 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::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 && !global.errors) + { Dsymbol *s; + if (!ti->semanticdone) + ti->semantic(sc); + s = ti->inst->toAlias(); + sds2 = s->isScopeDsymbol(); + if (!sds2) + { Expression *e; + + //printf("s = %s, '%s'\n", s->kind(), s->toChars()); + if (ti->withsym) + { + // Same as wthis.s + e = new VarExp(loc, ti->withsym->withstate->wthis); + e = new DotVarExp(loc, e, s->isDeclaration()); + } + else + e = new DsymbolExp(loc, s); + e = e->semantic(sc); + //printf("-1ScopeExp::semantic()\n"); + return e; + } + if (sds2 != sds) + { + sds = sds2; + goto Lagain; + } + //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); + } + else + { + //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); + //printf("\tparent = '%s'\n", sds->parent->toChars()); + sds->semantic(sc); + } + type = Type::tvoid; + //printf("-2ScopeExp::semantic() %s\n", toChars()); + return this; +} + +void ScopeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (sds->isTemplateInstance()) + { + sds->toCBuffer(buf, hgs); + } + else + { + buf->writestring(sds->kind()); + buf->writestring(" "); + buf->writestring(sds->toChars()); + } +} + +/********************** TemplateExp **************************************/ + +// Mainly just a placeholder + +TemplateExp::TemplateExp(Loc loc, TemplateDeclaration *td) + : Expression(loc, TOKtemplate, sizeof(TemplateExp)) +{ + //printf("TemplateExp(): %s\n", td->toChars()); + this->td = td; +} + +void TemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(td->toChars()); +} + +void TemplateExp::rvalue() +{ + error("template %s has no value", toChars()); +} + +/********************** NewExp **************************************/ + +NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs, + Type *newtype, Expressions *arguments) + : Expression(loc, TOKnew, sizeof(NewExp)) +{ + this->thisexp = thisexp; + this->newargs = newargs; + this->newtype = newtype; + this->arguments = arguments; + member = NULL; + allocator = NULL; + onstack = 0; +} + +Expression *NewExp::syntaxCopy() +{ + return new NewExp(loc, + thisexp ? thisexp->syntaxCopy() : NULL, + arraySyntaxCopy(newargs), + newtype->syntaxCopy(), arraySyntaxCopy(arguments)); +} + + +Expression *NewExp::semantic(Scope *sc) +{ int i; + Type *tb; + ClassDeclaration *cdthis = NULL; + +#if LOGSEMANTIC + printf("NewExp::semantic() %s\n", toChars()); + if (thisexp) + printf("\tthisexp = %s\n", thisexp->toChars()); + printf("\tnewtype: %s\n", newtype->toChars()); +#endif + if (type) // if semantic() already run + return this; + +Lagain: + if (thisexp) + { thisexp = thisexp->semantic(sc); + cdthis = thisexp->type->isClassHandle(); + if (cdthis) + { + sc = sc->push(cdthis); + type = newtype->semantic(loc, sc); + sc = sc->pop(); + } + else + { + error("'this' for nested class must be a class type, not %s", thisexp->type->toChars()); + type = newtype->semantic(loc, sc); + } + } + else + type = newtype->semantic(loc, sc); + newtype = type; // in case type gets cast to something else + tb = type->toBasetype(); + //printf("tb: %s, deco = %s\n", tb->toChars(), tb->deco); + + arrayExpressionSemantic(newargs, sc); + preFunctionArguments(loc, sc, newargs); + arrayExpressionSemantic(arguments, sc); + preFunctionArguments(loc, sc, arguments); + + if (thisexp && tb->ty != Tclass) + error("e.new is only for allocating nested classes, not %s", tb->toChars()); + + if (tb->ty == Tclass) + { TypeFunction *tf; + + TypeClass *tc = (TypeClass *)(tb); + ClassDeclaration *cd = tc->sym->isClassDeclaration(); + if (cd->isInterfaceDeclaration()) + error("cannot create instance of interface %s", cd->toChars()); + else if (cd->isAbstract()) + { error("cannot create instance of abstract class %s", cd->toChars()); + for (int i = 0; i < cd->vtbl.dim; i++) + { FuncDeclaration *fd = ((Dsymbol *)cd->vtbl.data[i])->isFuncDeclaration(); + if (fd && fd->isAbstract()) + error("function %s is abstract", fd->toChars()); + } + } + checkDeprecated(sc, cd); + if (cd->isNested()) + { /* We need a 'this' pointer for the nested class. + * Ensure we have the right one. + */ + Dsymbol *s = cd->toParent2(); + ClassDeclaration *cdn = s->isClassDeclaration(); + + //printf("isNested, cdn = %s\n", cdn ? cdn->toChars() : "null"); + if (cdn) + { + if (!cdthis) + { + // Supply an implicit 'this' and try again + thisexp = new ThisExp(loc); + for (Dsymbol *sp = sc->parent; 1; sp = sp->parent) + { if (!sp) + { + error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); + break; + } + ClassDeclaration *cdp = sp->isClassDeclaration(); + if (!cdp) + continue; + if (cdp == cdn || cdn->isBaseOf(cdp, NULL)) + break; + // Add a '.outer' and try again + thisexp = new DotIdExp(loc, thisexp, Id::outer); + } + if (!global.errors) + goto Lagain; + } + if (cdthis) + { + //printf("cdthis = %s\n", cdthis->toChars()); + if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL)) + error("'this' for nested class must be of type %s, not %s", cdn->toChars(), thisexp->type->toChars()); + } +#if 0 + else + { + for (Dsymbol *sf = sc->func; 1; sf= sf->toParent2()->isFuncDeclaration()) + { + if (!sf) + { + error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); + break; + } + printf("sf = %s\n", sf->toChars()); + AggregateDeclaration *ad = sf->isThis(); + if (ad && (ad == cdn || cdn->isBaseOf(ad->isClassDeclaration(), NULL))) + break; + } + } +#endif + } + else if (thisexp) + error("e.new is only for allocating nested classes"); + } + else if (thisexp) + error("e.new is only for allocating nested classes"); + + FuncDeclaration *f = cd->ctor; + if (f) + { + assert(f); + f = f->overloadResolve(loc, arguments); + 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(); + functionArguments(loc, sc, tf, arguments); + } + else + { + if (arguments && arguments->dim) + error("no constructor for %s", cd->toChars()); + } + + if (cd->aggNew) + { Expression *e; + + f = cd->aggNew; + + // Prepend the uint size argument to newargs[] + e = new IntegerExp(loc, cd->size(loc), Type::tuns32); + if (!newargs) + newargs = new Expressions(); + newargs->shift(e); + + f = f->overloadResolve(loc, newargs); + allocator = f->isNewDeclaration(); + assert(allocator); + + tf = (TypeFunction *)f->type; + functionArguments(loc, sc, tf, newargs); + } + else + { + if (newargs && newargs->dim) + error("no allocator for %s", cd->toChars()); + } + + } + else if (tb->ty == Tstruct) + { + TypeStruct *ts = (TypeStruct *)tb; + StructDeclaration *sd = ts->sym; + 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, newargs); + allocator = f->isNewDeclaration(); + assert(allocator); + + tf = (TypeFunction *)f->type; + functionArguments(loc, sc, tf, newargs); + + 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"); + arguments->dim = i; + break; + } + + Expression *arg = (Expression *)arguments->data[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()); + arguments->data[i] = (void *) arg; + tb = tb->next->toBasetype(); + } + } + else if (tb->isscalar()) + { + if (arguments && arguments->dim) + error("no constructor for %s", type->toChars()); + + type = type->pointerTo(); + } + else + { + error("new can only create structs, dynamic arrays or class objects, not %s's", type->toChars()); + type = type->pointerTo(); + } + +//printf("NewExp: '%s'\n", toChars()); +//printf("NewExp:type '%s'\n", type->toChars()); + + return this; +} + +int NewExp::checkSideEffect(int flag) +{ + return 1; +} + +void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + if (thisexp) + { expToCBuffer(buf, hgs, thisexp, PREC_primary); + buf->writeByte('.'); + } + buf->writestring("new "); + if (newargs && newargs->dim) + { + buf->writeByte('('); + argsToCBuffer(buf, newargs, hgs); + buf->writeByte(')'); + } + newtype->toCBuffer(buf, NULL, hgs); + if (arguments && arguments->dim) + { + buf->writeByte('('); + argsToCBuffer(buf, arguments, hgs); + buf->writeByte(')'); + } +} + +/********************** NewAnonClassExp **************************************/ + +NewAnonClassExp::NewAnonClassExp(Loc loc, Expression *thisexp, + Expressions *newargs, ClassDeclaration *cd, Expressions *arguments) + : Expression(loc, TOKnewanonclass, sizeof(NewAnonClassExp)) +{ + this->thisexp = thisexp; + this->newargs = newargs; + this->cd = cd; + this->arguments = arguments; +} + +Expression *NewAnonClassExp::syntaxCopy() +{ + return new NewAnonClassExp(loc, + thisexp ? thisexp->syntaxCopy() : NULL, + arraySyntaxCopy(newargs), + (ClassDeclaration *)cd->syntaxCopy(NULL), + arraySyntaxCopy(arguments)); +} + + +Expression *NewAnonClassExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("NewAnonClassExp::semantic() %s\n", toChars()); + //printf("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; +} + +void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + if (thisexp) + { expToCBuffer(buf, hgs, thisexp, PREC_primary); + buf->writeByte('.'); + } + buf->writestring("new"); + if (newargs && newargs->dim) + { + buf->writeByte('('); + argsToCBuffer(buf, newargs, hgs); + buf->writeByte(')'); + } + buf->writestring(" class "); + if (arguments && arguments->dim) + { + buf->writeByte('('); + argsToCBuffer(buf, arguments, hgs); + buf->writeByte(')'); + } + //buf->writestring(" { }"); + if (cd) + { + cd->toCBuffer(buf, hgs); + } +} + +/********************** SymOffExp **************************************/ + +SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset) + : Expression(loc, TOKsymoff, sizeof(SymOffExp)) +{ + assert(var); + this->var = var; + this->offset = offset; + 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); + if (!type) + type = var->type->pointerTo(); + VarDeclaration *v = var->isVarDeclaration(); + if (v) + { + v->checkNestedReference(sc, loc); + v->needsStorage = true; + } + return this; +} + +int SymOffExp::isBool(int result) +{ + return result ? TRUE : FALSE; +} + +void SymOffExp::checkEscape() +{ + VarDeclaration *v = var->isVarDeclaration(); + if (v) + { + if (!v->isDataseg()) + error("escaping reference to local variable %s", v->toChars()); + } +} + +void SymOffExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (offset) + buf->printf("(& %s+%u)", var->toChars(), offset); + else + buf->printf("& %s", var->toChars()); +} + +/******************************** VarExp **************************/ + +VarExp::VarExp(Loc loc, Declaration *var) + : 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) +{ FuncLiteralDeclaration *fd; + +#if LOGSEMANTIC + printf("VarExp::semantic(%s)\n", toChars()); +#endif + if (!type) + { type = var->type; +#if 0 + if (var->storage_class & STClazy) + { + TypeFunction *tf = new TypeFunction(NULL, type, 0, LINKd); + type = new TypeDelegate(tf); + type = type->semantic(loc, sc); + } +#endif + } + + VarDeclaration *v = var->isVarDeclaration(); + if (v) + { + if (v->isConst() && type->toBasetype()->ty != Tsarray && v->init) + { + ExpInitializer *ei = v->init->isExpInitializer(); + if (ei) + { + //ei->exp->implicitCastTo(sc, type)->print(); + return ei->exp->implicitCastTo(sc, type); + } + } + v->checkNestedReference(sc, loc); + } +#if 0 + else if ((fd = var->isFuncLiteralDeclaration()) != NULL) + { Expression *e; + e = new FuncExp(loc, fd); + e->type = type; + return e; + } +#endif + return this; +} + +char *VarExp::toChars() +{ + return var->toChars(); +} + +void VarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(var->toChars()); +} + +void VarExp::checkEscape() +{ + VarDeclaration *v = var->isVarDeclaration(); + if (v) + { Type *tb = v->type->toBasetype(); + // if reference type + if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass) + { + if ((v->isAuto() || v->isScope()) && !v->noauto) + error("escaping reference to auto local %s", v->toChars()); + else if (v->storage_class & STCvariadic) + error("escaping reference to variadic parameter %s", v->toChars()); + } + } +} + +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()); + v->needsStorage = true; + + 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); +} + + +/******************************** TupleExp **************************/ + +TupleExp::TupleExp(Loc loc, Expressions *exps) + : Expression(loc, TOKtuple, sizeof(TupleExp)) +{ + //printf("TupleExp(this = %p)\n", this); + this->exps = exps; + this->type = NULL; +} + + +TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) + : Expression(loc, TOKtuple, sizeof(TupleExp)) +{ + exps = new Expressions(); + type = NULL; + + exps->reserve(tup->objects->dim); + for (size_t i = 0; i < tup->objects->dim; i++) + { Object *o = (Object *)tup->objects->data[i]; + if (o->dyncast() == DYNCAST_EXPRESSION) + { + Expression *e = (Expression *)o; + e = e->syntaxCopy(); + exps->push(e); + } + else if (o->dyncast() == DYNCAST_DSYMBOL) + { + Dsymbol *s = (Dsymbol *)o; + Expression *e = new DsymbolExp(loc, s); + exps->push(e); + } + else if (o->dyncast() == DYNCAST_TYPE) + { + Type *t = (Type *)o; + Expression *e = new TypeExp(loc, t); + exps->push(e); + } + else + { + error("%s is not an expression", o->toChars()); + } + } +} + +int TupleExp::equals(Object *o) +{ TupleExp *ne; + + if (this == o) + return 1; + if (((Expression *)o)->op == TOKtuple) + { + TupleExp *te = (TupleExp *)o; + if (exps->dim != te->exps->dim) + return 0; + for (size_t i = 0; i < exps->dim; i++) + { Expression *e1 = (Expression *)exps->data[i]; + Expression *e2 = (Expression *)te->exps->data[i]; + + if (!e1->equals(e2)) + return 0; + } + return 1; + } + return 0; +} + +Expression *TupleExp::syntaxCopy() +{ + return new TupleExp(loc, arraySyntaxCopy(exps)); +} + +Expression *TupleExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("+TupleExp::semantic(%s)\n", toChars()); +#endif + if (type) + return this; + + // Run semantic() on each argument + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + e = e->semantic(sc); + if (!e->type) + { error("%s has no value", e->toChars()); + e->type = Type::terror; + } + exps->data[i] = (void *)e; + } + + expandTuples(exps); + if (0 && exps->dim == 1) + { + return (Expression *)exps->data[0]; + } + type = new TypeTuple(exps); + //printf("-TupleExp::semantic(%s)\n", toChars()); + return this; +} + +void TupleExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("tuple("); + argsToCBuffer(buf, exps, hgs); + buf->writeByte(')'); +} + +int TupleExp::checkSideEffect(int flag) +{ int f = 0; + + for (int i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + f |= e->checkSideEffect(2); + } + if (flag == 0 && f == 0) + Expression::checkSideEffect(0); + return f; +} + +void TupleExp::checkEscape() +{ + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + e->checkEscape(); + } +} + +/******************************** FuncExp *********************************/ + +FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd) + : Expression(loc, TOKfunction, sizeof(FuncExp)) +{ + this->fd = fd; +} + +Expression *FuncExp::syntaxCopy() +{ + return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL)); +} + +Expression *FuncExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("FuncExp::semantic(%s)\n", toChars()); +#endif + if (!type) + { + fd->semantic(sc); + fd->parent = sc->parent; + if (global.errors) + { + if (!fd->type->next) + fd->type->next = Type::terror; + } + else + { + fd->semantic2(sc); + if (!global.errors) + { + fd->semantic3(sc); + + if (!global.errors && global.params.useInline) + fd->inlineScan(); + } + } + + // 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) +{ + buf->writestring(fd->toChars()); +} + + +/******************************** DeclarationExp **************************/ + +DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration) + : Expression(loc, TOKdeclaration, sizeof(DeclarationExp)) +{ + this->declaration = declaration; +} + +Expression *DeclarationExp::syntaxCopy() +{ + return new DeclarationExp(loc, declaration->syntaxCopy(NULL)); +} + +Expression *DeclarationExp::semantic(Scope *sc) +{ + if (type) + return this; + +#if LOGSEMANTIC + printf("DeclarationExp::semantic() %s\n", toChars()); +#endif + + /* This is here to support extern(linkage) declaration, + * where the extern(linkage) winds up being an AttribDeclaration + * wrapper. + */ + Dsymbol *s = declaration; + + AttribDeclaration *ad = declaration->isAttribDeclaration(); + if (ad) + { + if (ad->decl && ad->decl->dim == 1) + s = (Dsymbol *)ad->decl->data[0]; + } + + if (s->isVarDeclaration()) + { // Do semantic() on initializer first, so: + // int a = a; + // will be illegal. + declaration->semantic(sc); + s->parent = sc->parent; + } + + //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc); + // Insert into both local scope and function scope. + // Must be unique in both. + if (s->ident) + { + if (!sc->insert(s)) + error("declaration %s is already defined", s->toPrettyChars()); + else if (sc->func) + { VarDeclaration *v = s->isVarDeclaration(); + if ((s->isFuncDeclaration() /*|| v && v->storage_class & STCstatic*/) && + !sc->func->localsymtab->insert(s)) + error("declaration %s is already defined in another scope in %s", s->toPrettyChars(), sc->func->toChars()); + else if (!global.params.useDeprecated) + { // Disallow shadowing + + for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing) + { Dsymbol *s2; + + if (scx->scopesym && scx->scopesym->symtab && + (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL && + s != s2) + { + error("shadowing declaration %s is deprecated", s->toPrettyChars()); + } + } + } + } + } + if (!s->isVarDeclaration()) + { + declaration->semantic(sc); + s->parent = sc->parent; + } + if (!global.errors) + { + declaration->semantic2(sc); + if (!global.errors) + { + declaration->semantic3(sc); + + if (!global.errors && global.params.useInline) + declaration->inlineScan(); + } + } + + type = Type::tvoid; + return this; +} + +int DeclarationExp::checkSideEffect(int flag) +{ + return 1; +} + +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); + return e; +} + +void TypeidExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("typeid("); + typeidType->toCBuffer(buf, NULL, hgs); + buf->writeByte(')'); +} + +/************************************************************/ + +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; + + //printf("IsExp::semantic()\n"); + if (id && !(sc->flags & SCOPEstaticif)) + error("can only declare type aliases within static if conditionals"); + + unsigned errors_save = global.errors; + global.errors = 0; + global.gag++; // suppress printing of error messages + targ = targ->semantic(loc, sc); + global.gag--; + unsigned gerrors = global.errors; + global.errors = errors_save; + + if (gerrors) // 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; + + case TOKsuper: + // If class or interface, get the base class and interfaces + if (targ->ty != Tclass) + goto Lno; + else + { ClassDeclaration *cd = ((TypeClass *)targ)->sym; + Arguments *args = new Arguments; + args->reserve(cd->baseclasses.dim); + for (size_t i = 0; i < cd->baseclasses.dim; i++) + { BaseClass *b = (BaseClass *)cd->baseclasses.data[i]; + args->push(new Argument(STCin, b->type, NULL, NULL)); + } + tded = new TypeTuple(args); + } + break; + + case TOKenum: + if (targ->ty != Tenum) + goto Lno; + tded = ((TypeEnum *)targ)->sym->memtype; + break; + + case TOKdelegate: + if (targ->ty != Tdelegate) + goto Lno; + tded = targ->next; // the underlying function type + break; + + case TOKfunction: + { if (targ->ty != Tfunction) + goto Lno; + tded = targ; + + /* Generate tuple from function parameter types. + */ + assert(tded->ty == Tfunction); + Arguments *params = ((TypeFunction *)tded)->parameters; + size_t dim = Argument::dim(params); + Arguments *args = new Arguments; + args->reserve(dim); + for (size_t i = 0; i < dim; i++) + { Argument *arg = Argument::getNth(params, i); + assert(arg && arg->type); + args->push(new Argument(arg->storageClass, arg->type, NULL, NULL)); + } + tded = new TypeTuple(args); + break; + } + case TOKreturn: + /* Get the 'return type' for the function, + * delegate, or pointer to function. + */ + if (targ->ty == Tfunction) + tded = 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; + + default: + assert(0); + } + goto Lyes; + } + else if (id && tspec) + { + /* Evaluate to TRUE if targ matches tspec. + * If TRUE, declare id as an alias for the specialized type. + */ + + MATCH m; + TemplateTypeParameter tp(loc, id, NULL, NULL); + + TemplateParameters parameters; + parameters.setDim(1); + parameters.data[0] = (void *)&tp; + + Objects dedtypes; + dedtypes.setDim(1); + dedtypes.data[0] = NULL; + + m = targ->deduceType(NULL, 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; + 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 + */ + tspec = tspec->semantic(loc, sc); + //printf("targ = %s\n", targ->toChars()); + //printf("tspec = %s\n", tspec->toChars()); + if (tok == TOKcolon) + { if (targ->implicitConvTo(tspec)) + goto Lyes; + else + goto Lno; + } + else /* == */ + { if (targ->equals(tspec)) + goto Lyes; + else + goto Lno; + } + } + +Lyes: + if (id) + { + Dsymbol *s = new AliasDeclaration(loc, id, tded); + s->semantic(sc); + sc->insert(s); + 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 V2 + if (parameters) + { // First parameter is already output, so start with second + for (int i = 1; i < parameters->dim; i++) + { + buf->writeByte(','); + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + tp->toCBuffer(buf, hgs); + } + } +#endif + buf->writeByte(')'); +} + + +/************************************************************/ + +UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1) + : Expression(loc, op, size) +{ + this->e1 = e1; +} + +Expression *UnaExp::syntaxCopy() +{ UnaExp *e; + + e = (UnaExp *)copy(); + e->type = NULL; + e->e1 = e->e1->syntaxCopy(); + return e; +} + +Expression *UnaExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("UnaExp::semantic('%s')\n", toChars()); +#endif + e1 = e1->semantic(sc); +// if (!e1->type) +// error("%s has no value", e1->toChars()); + return this; +} + +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) + { + error("%s has no value", e1->toChars()); + e1->type = Type::terror; + } + e2 = e2->semantic(sc); + if (!e2->type) + { + error("%s has no value", e2->toChars()); + e2->type = Type::terror; + } + assert(e1->type); + 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; + + 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 IntegerExp(0); + } + } + 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; + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + type = e1->type; + if (type->toBasetype()->ty == Tbool) + { + e2 = e2->implicitCastTo(sc, type); + } + + typeCombine(sc); + e1->checkIntegral(); + e2->checkIntegral(); + } + return this; +} + +int BinExp::checkSideEffect(int flag) +{ + if (op == TOKplusplus || + op == TOKminusminus || + op == TOKassign || + op == TOKconstruct || + op == TOKblit || + op == TOKaddass || + op == TOKminass || + op == TOKcatass || + op == TOKmulass || + op == TOKdivass || + op == TOKmodass || + op == TOKshlass || + op == TOKshrass || + op == TOKushrass || + op == TOKandass || + op == TOKorass || + op == TOKxorass || + op == TOKin || + op == TOKremove) + return 1; + return Expression::checkSideEffect(flag); +} + +void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, precedence[op]); + buf->writeByte(' '); + buf->writestring(Token::toChars(op)); + buf->writeByte(' '); + expToCBuffer(buf, hgs, e2, (enum PREC)(precedence[op] + 1)); +} + +int BinExp::isunsigned() +{ + return e1->type->isunsigned() || e2->type->isunsigned(); +} + +void BinExp::incompatibleTypes() +{ + error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", + e1->toChars(), Token::toChars(op), e2->toChars(), + e1->type->toChars(), e2->type->toChars()); +} + +/************************************************************/ + +CompileExp::CompileExp(Loc loc, Expression *e) + : UnaExp(loc, TOKmixin, sizeof(CompileExp), e) +{ +} + +Expression *CompileExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("CompileExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->optimize(WANTvalue | WANTinterpret); + if (e1->op != TOKstring) + { error("argument to mixin must be a string, not (%s)", e1->toChars()); + type = Type::terror; + return this; + } + StringExp *se = (StringExp *)e1; + se = se->toUTF8(sc); + Parser p(sc->module, (unsigned char *)se->string, se->len, 0); + p.loc = loc; + p.nextToken(); + Expression *e = p.parseExpression(); + if (p.token.value != TOKeof) + error("incomplete mixin expression (%s)", se->toChars()); + return e->semantic(sc); +} + +void CompileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("mixin("); + expToCBuffer(buf, hgs, e1, PREC_assign); + buf->writeByte(')'); +} + +/************************************************************/ + +FileExp::FileExp(Loc loc, Expression *e) + : UnaExp(loc, TOKmixin, sizeof(FileExp), e) +{ +} + +Expression *FileExp::semantic(Scope *sc) +{ char *name; + StringExp *se; + +#if LOGSEMANTIC + printf("FileExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->optimize(WANTvalue); + if (e1->op != TOKstring) + { error("file name argument must be a string, not (%s)", e1->toChars()); + goto Lerror; + } + se = (StringExp *)e1; + se = se->toUTF8(sc); + name = (char *)se->string; + + if (!global.params.fileImppath) + { error("need -Jpath switch to import text file %s", name); + goto Lerror; + } + + if (name != FileName::name(name)) + { error("use -Jpath switch to provide path for filename %s", name); + goto Lerror; + } + + name = FileName::searchPath(global.filePath, name, 0); + if (!name) + { error("file %s cannot be found, check -Jpath", se->toChars()); + goto Lerror; + } + + if (global.params.verbose) + printf("file %s\t(%s)\n", se->string, name); + + { File f(name); + if (f.read()) + { error("cannot read file %s", f.toChars()); + goto Lerror; + } + else + { + f.ref = 1; + se = new StringExp(loc, f.buffer, f.len); + } + } + Lret: + return se->semantic(sc); + + Lerror: + se = new StringExp(loc, ""); + goto Lret; +} + +void FileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("import("); + expToCBuffer(buf, hgs, e1, PREC_assign); + buf->writeByte(')'); +} + +/************************************************************/ + +AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg) + : UnaExp(loc, TOKassert, sizeof(AssertExp), e) +{ + this->msg = msg; +} + +Expression *AssertExp::syntaxCopy() +{ + AssertExp *ae = new AssertExp(loc, e1->syntaxCopy(), + msg ? msg->syntaxCopy() : NULL); + return ae; +} + +Expression *AssertExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("AssertExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + // BUG: see if we can do compile time elimination of the Assert + e1 = e1->optimize(WANTvalue); + e1 = e1->checkToBoolean(); + if (msg) + { + msg = msg->semantic(sc); + msg = resolveProperties(sc, msg); + msg = msg->implicitCastTo(sc, Type::tchar->arrayOf()); + msg = msg->optimize(WANTvalue); + } + if (e1->isBool(FALSE)) + { + FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + fd->hasReturnExp |= 4; + + if (!global.params.useAssert) + { Expression *e = new HaltExp(loc); + e = e->semantic(sc); + return e; + } + } + type = Type::tvoid; + return this; +} + +int AssertExp::checkSideEffect(int flag) +{ + return 1; +} + +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 = new TypeDotIdExp(loc, cd->type, ident); + return e->semantic(sc); + } + else if (cd->baseClass && e1->op == TOKsuper) + { + e = new TypeDotIdExp(loc, cd->baseClass->type, ident); + return e->semantic(sc); + } + } + else + { + sd = ad->isStructDeclaration(); + if (sd) + { + if (e1->op == TOKthis) + { + e = new TypeDotIdExp(loc, sd->type, ident); + return e->semantic(sc); + } + } + } + } + } + + UnaExp::semantic(sc); + + if (e1->op == TOKdotexp) + { + DotExp *de = (DotExp *)e1; + eleft = de->e1; + eright = de->e2; + } + else + { + e1 = resolveProperties(sc, e1); + eleft = NULL; + eright = e1; + } + + if (e1->op == TOKtuple && ident == Id::length) + { + TupleExp *te = (TupleExp *)e1; + e = new IntegerExp(loc, te->exps->dim, Type::tsize_t); + return e; + } + + if (eright->op == TOKimport) // also used for template alias's + { + Dsymbol *s; + ScopeExp *ie = (ScopeExp *)eright; + + s = ie->sds->search(loc, ident, 0); + if (s) + { + s = s->toAlias(); + checkDeprecated(sc, s); + + EnumMember *em = s->isEnumMember(); + if (em) + { + e = em->value; + e = e->semantic(sc); + return e; + } + + VarDeclaration *v = s->isVarDeclaration(); + if (v) + { + //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); + if (v->inuse) + { + error("circular reference to '%s'", v->toChars()); + type = Type::tint32; + return this; + } + type = v->type; + if (v->isConst()) + { + 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; + } + } + return e->deref(); + } + + FuncDeclaration *f = s->isFuncDeclaration(); + if (f) + { + //printf("it's a function\n"); + if (f->needThis()) + { + if (!eleft) + eleft = new ThisExp(loc); + e = new DotVarExp(loc, eleft, f); + e = e->semantic(sc); + } + else + { + e = new VarExp(loc, f); + if (eleft) + { e = new CommaExp(loc, eleft, e); + e->type = f->type; + } + } + return e; + } + + Type *t = s->getType(); + if (t) + { + return new TypeExp(loc, t); + } + + ScopeDsymbol *sds = s->isScopeDsymbol(); + if (sds) + { + //printf("it's a ScopeDsymbol\n"); + e = new ScopeExp(loc, sds); + e = e->semantic(sc); + if (eleft) + e = new DotExp(loc, eleft, e); + return e; + } + + Import *imp = s->isImport(); + if (imp) + { + ScopeExp *ie; + + ie = new ScopeExp(loc, imp->pkg); + return ie->semantic(sc); + } + + // BUG: handle other cases like in IdentifierExp::semantic() +#ifdef DEBUG + printf("s = '%s', kind = '%s'\n", s->toChars(), s->kind()); +#endif + assert(0); + } + else if (ident == Id::stringof) + { char *s = ie->toChars(); + e = new StringExp(loc, s, strlen(s), 'c'); + e = e->semantic(sc); + return e; + } + error("undefined identifier %s", toChars()); + type = Type::tvoid; + return this; + } + else if (e1->type->ty == Tpointer && + ident != Id::init && ident != Id::__sizeof && + ident != Id::alignof && ident != Id::offsetof && + ident != Id::mangleof && ident != Id::stringof) + { + e = new PtrExp(loc, e1); + e->type = e1->type->next; + return e->type->dotExp(sc, e, ident); + } + 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 IntegerExp(0); + } + assert(type); + + if (!var->isFuncDeclaration()) // for functions, do checks after overload resolution + { + AggregateDeclaration *ad = var->toParent()->isAggregateDeclaration(); + L1: + Type *t = e1->type->toBasetype(); + + if (ad && + !(t->ty == Tpointer && t->next->ty == Tstruct && + ((TypeStruct *)t->next)->sym == ad) + && + !(t->ty == Tstruct && + ((TypeStruct *)t)->sym == ad) + ) + { + ClassDeclaration *cd = ad->isClassDeclaration(); + ClassDeclaration *tcd = t->isClassHandle(); + + if (!cd || !tcd || + !(tcd == cd || cd->isBaseOf(tcd, NULL)) + ) + { + if (tcd && tcd->isNested()) + { // Try again with outer scope + + e1 = new DotVarExp(loc, e1, tcd->vthis); + e1 = e1->semantic(sc); + + // Skip over nested functions, and get the enclosing + // class type. + Dsymbol *s = tcd->toParent(); + while (s && s->isFuncDeclaration()) + { FuncDeclaration *f = s->isFuncDeclaration(); + if (f->vthis) + { + e1 = new VarExp(loc, f->vthis); + } + s = s->toParent(); + } + if (s && s->isClassDeclaration()) + e1->type = s->isClassDeclaration()->type; + + e1 = e1->semantic(sc); + goto L1; + } +#ifdef DEBUG + printf("2: "); +#endif + error("this for %s needs to be type %s not type %s", + var->toChars(), ad->toChars(), t->toChars()); + } + } + accessCheck(loc, sc, e1, var); + } + } + //printf("-DotVarExp::semantic('%s')\n", toChars()); + return this; +} + +Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) +{ + //printf("DotVarExp::toLvalue(%s)\n", toChars()); + return this; +} + +Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) +{ + //printf("DotVarExp::modifiableLvalue(%s)\n", 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() && + 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; + } + } + return this; +} + +void DotVarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + buf->writestring(var->toChars()); +} + +/************************************************************/ + +/* Things like: + * foo.bar!(args) + */ + +DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti) + : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e) +{ + //printf("DotTemplateInstanceExp()\n"); + this->ti = ti; +} + +Expression *DotTemplateInstanceExp::syntaxCopy() +{ + DotTemplateInstanceExp *de = new DotTemplateInstanceExp(loc, + e1->syntaxCopy(), + (TemplateInstance *)ti->syntaxCopy(NULL)); + return de; +} + +Expression *DotTemplateInstanceExp::semantic(Scope *sc) +{ Dsymbol *s; + Dsymbol *s2; + TemplateDeclaration *td; + Expression *e; + Identifier *id; + Type *t1; + Expression *eleft = NULL; + Expression *eright; + +#if LOGSEMANTIC + printf("DotTemplateInstanceExp::semantic('%s')\n", toChars()); +#endif + //e1->print(); + //print(); + e1 = e1->semantic(sc); + t1 = e1->type; + if (t1) + t1 = t1->toBasetype(); + //t1->print(); + 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 = 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) + { 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(0); +} + +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; +} + +Expression *DelegateExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DelegateExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + e1 = e1->semantic(sc); + type = new TypeDelegate(func->type); + type = type->semantic(loc, sc); +//----------------- + /* For func, we need to get the + * right 'this' pointer if func is in an outer class, but our + * existing 'this' pointer is in an inner class. + * This code is analogous to that used for variables + * in DotVarExp::semantic(). + */ + AggregateDeclaration *ad = func->toParent()->isAggregateDeclaration(); + L10: + Type *t = e1->type; + if (func->needThis() && ad && + !(t->ty == Tpointer && t->next->ty == Tstruct && + ((TypeStruct *)t->next)->sym == ad) && + !(t->ty == Tstruct && ((TypeStruct *)t)->sym == ad) + ) + { + ClassDeclaration *cd = ad->isClassDeclaration(); + ClassDeclaration *tcd = t->isClassHandle(); + + if (!cd || !tcd || + !(tcd == cd || cd->isBaseOf(tcd, NULL)) + ) + { + if (tcd && tcd->isNested()) + { // Try again with outer scope + + e1 = new DotVarExp(loc, e1, tcd->vthis); + e1 = e1->semantic(sc); + goto L10; + } +#ifdef DEBUG + printf("3: "); +#endif + error("this for %s needs to be type %s not type %s", + func->toChars(), ad->toChars(), t->toChars()); + } + } +//----------------- + } + return this; +} + +void DelegateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('&'); + if (!func->isNested()) + { + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + } + buf->writestring(func->toChars()); +} + +/************************************************************/ + +DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s) + : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e) +{ + this->sym = s; + this->type = s->getType(); +} + +Expression *DotTypeExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DotTypeExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + return this; +} + +void DotTypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + buf->writestring(sym->toChars()); +} + +/************************************************************/ + +CallExp::CallExp(Loc loc, Expression *e, Expressions *exps) + : UnaExp(loc, TOKcall, sizeof(CallExp), e) +{ + this->arguments = exps; +} + +CallExp::CallExp(Loc loc, Expression *e) + : UnaExp(loc, TOKcall, sizeof(CallExp), e) +{ + this->arguments = NULL; +} + +CallExp::CallExp(Loc loc, Expression *e, Expression *earg1) + : UnaExp(loc, TOKcall, sizeof(CallExp), e) +{ + Expressions *arguments = new Expressions(); + arguments->setDim(1); + arguments->data[0] = (void *)earg1; + + this->arguments = arguments; +} + +CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2) + : UnaExp(loc, TOKcall, sizeof(CallExp), e) +{ + Expressions *arguments = new Expressions(); + arguments->setDim(2); + arguments->data[0] = (void *)earg1; + arguments->data[1] = (void *)earg2; + + this->arguments = arguments; +} + +Expression *CallExp::syntaxCopy() +{ + return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); +} + + +Expression *CallExp::semantic(Scope *sc) +{ + TypeFunction *tf; + FuncDeclaration *f; + int i; + Type *t1; + int istemp; + +#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); + e1 = new IdentifierExp(dotid->loc, dotid->ident); + } + } + } + + istemp = 0; +Lagain: + f = NULL; + if (e1->op == TOKthis || e1->op == TOKsuper) + { + // semantic() run later for these + } + else + { + UnaExp::semantic(sc); + + /* Look for e1 being a lazy parameter + */ + if (e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + + if (ve->var->storage_class & STClazy) + { + TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd); + TypeDelegate *t = new TypeDelegate(tf); + ve->type = t->semantic(loc, sc); + } + } + + if (e1->op == TOKimport) + { // Perhaps this should be moved to ScopeExp::semantic() + ScopeExp *se = (ScopeExp *)e1; + e1 = new DsymbolExp(loc, se->sds); + e1 = e1->semantic(sc); + } +#if 1 // patch for #540 by Oskar Linde + else if (e1->op == TOKdotexp) + { + DotExp *de = (DotExp *) e1; + + if (de->e2->op == TOKimport) + { // This should *really* be moved to ScopeExp::semantic() + ScopeExp *se = (ScopeExp *)de->e2; + de->e2 = new DsymbolExp(loc, se->sds); + de->e2 = de->e2->semantic(sc); + } + + if (de->e2->op == TOKtemplate) + { TemplateExp *te = (TemplateExp *) de->e2; + e1 = new DotTemplateExp(loc,de->e1,te->td); + } + } +#endif + } + + if (e1->op == TOKcomma) + { + CommaExp *ce = (CommaExp *)e1; + + e1 = ce->e2; + e1->type = ce->type; + ce->e2 = this; + ce->type = NULL; + return ce->semantic(sc); + } + + t1 = NULL; + if (e1->type) + t1 = e1->type->toBasetype(); + + // Check for call operator overload + if (t1) + { AggregateDeclaration *ad; + + if (t1->ty == Tstruct) + { + ad = ((TypeStruct *)t1)->sym; + if (search_function(ad, Id::call)) + goto L1; // overload of opCall, therefore it's a call + + if (e1->op != TOKtype) + error("%s %s does not overload ()", ad->kind(), ad->toChars()); + /* It's a struct literal + */ + Expression *e = new StructLiteralExp(loc, (StructDeclaration *)ad, arguments); + e = e->semantic(sc); + e->type = e1->type; // in case e1->type was a typedef + return e; + } + else if (t1->ty == Tclass) + { + ad = ((TypeClass *)t1)->sym; + goto L1; + L1: + // Rewrite as e1.call(arguments) + Expression *e = new DotIdExp(loc, e1, Id::call); + e = new CallExp(loc, e, arguments); + e = e->semantic(sc); + return e; + } + } + + arrayExpressionSemantic(arguments, sc); + preFunctionArguments(loc, sc, arguments); + + if (e1->op == TOKdotvar && t1->ty == Tfunction || + e1->op == TOKdottd) + { + DotVarExp *dve; + DotTemplateExp *dte; + AggregateDeclaration *ad; + UnaExp *ue = (UnaExp *)(e1); + + if (e1->op == TOKdotvar) + { // Do overload resolution + dve = (DotVarExp *)(e1); + + f = dve->var->isFuncDeclaration(); + assert(f); + f = f->overloadResolve(loc, arguments); + + ad = f->toParent()->isAggregateDeclaration(); + } + else + { dte = (DotTemplateExp *)(e1); + TemplateDeclaration *td = dte->td; + assert(td); + if (!arguments) + // Should fix deduceFunctionTemplate() so it works on NULL argument + arguments = new Expressions(); + f = td->deduceFunctionTemplate(sc, loc, NULL, arguments); + if (!f) + { type = Type::terror; + return this; + } + ad = td->toParent()->isAggregateDeclaration(); + } + /* Now that we have the right function f, we need to get the + * right 'this' pointer if f is in an outer class, but our + * existing 'this' pointer is in an inner class. + * This code is analogous to that used for variables + * in DotVarExp::semantic(). + */ + L10: + Type *t = ue->e1->type->toBasetype(); + if (f->needThis() && ad && + !(t->ty == Tpointer && t->next->ty == Tstruct && + ((TypeStruct *)t->next)->sym == ad) && + !(t->ty == Tstruct && ((TypeStruct *)t)->sym == ad) + ) + { + ClassDeclaration *cd = ad->isClassDeclaration(); + ClassDeclaration *tcd = t->isClassHandle(); + + if (!cd || !tcd || + !(tcd == cd || cd->isBaseOf(tcd, NULL)) + ) + { + if (tcd && tcd->isNested()) + { // Try again with outer scope + + ue->e1 = new DotVarExp(loc, ue->e1, tcd->vthis); + ue->e1 = ue->e1->semantic(sc); + goto L10; + } +#ifdef DEBUG + printf("1: "); +#endif + error("this for %s needs to be type %s not type %s", + f->toChars(), ad->toChars(), t->toChars()); + } + } + + checkDeprecated(sc, f); + accessCheck(loc, sc, ue->e1, f); + if (!f->needThis()) + { + VarExp *ve = new VarExp(loc, f); + e1 = new CommaExp(loc, ue->e1, ve); + e1->type = f->type; + } + else + { + if (e1->op == TOKdotvar) + dve->var = f; + else + e1 = new DotVarExp(loc, dte->e1, f); + e1->type = f->type; + + // See if we need to adjust the 'this' pointer + AggregateDeclaration *ad = f->isThis(); + ClassDeclaration *cd = ue->e1->type->isClassHandle(); + if (ad && cd && ad->isClassDeclaration() && ad != cd && + ue->e1->op != TOKsuper) + { + ue->e1 = ue->e1->castTo(sc, ad->type); //new CastExp(loc, ue->e1, ad->type); + ue->e1 = ue->e1->semantic(sc); + } + } + t1 = e1->type; + } + else if (e1->op == TOKsuper) + { + // Base class constructor call + ClassDeclaration *cd = NULL; + + if (sc->func) + cd = sc->func->toParent()->isClassDeclaration(); + if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration()) + { + error("super class constructor call must be in a constructor"); + type = Type::terror; + return this; + } + else + { + f = cd->baseClass->ctor; + if (!f) + { error("no super class constructor for %s", cd->baseClass->toChars()); + type = Type::terror; + return this; + } + else + { +#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, arguments); + checkDeprecated(sc, f); + 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"); + type = Type::terror; + return this; + } + else + { +#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, arguments); + checkDeprecated(sc, f); + e1 = new DotVarExp(e1->loc, e1, f); + e1 = e1->semantic(sc); + t1 = e1->type; + + // BUG: this should really be done by checking the static + // call graph + if (f == sc->func) + error("cyclic constructor call"); + } + } + else if (!t1) + { + error("function expected before (), not '%s'", e1->toChars()); + type = Type::terror; + return this; + } + else if (t1->ty != Tfunction) + { + if (t1->ty == Tdelegate) + { + assert(t1->next->ty == Tfunction); + tf = (TypeFunction *)(t1->next); + goto Lcheckargs; + } + else if (t1->ty == Tpointer && t1->next->ty == Tfunction) + { Expression *e; + + e = new PtrExp(loc, e1); + t1 = t1->next; + e->type = t1; + e1 = e; + } + else if (e1->op == TOKtemplate) + { + TemplateExp *te = (TemplateExp *)e1; + f = te->td->deduceFunctionTemplate(sc, loc, NULL, arguments); + if (!f) + { type = Type::terror; + return this; + } + if (f->needThis() && hasThis(sc)) + { + // Supply an implicit 'this', as in + // this.ident + + e1 = new DotTemplateExp(loc, (new ThisExp(loc))->semantic(sc), te->td); + goto Lagain; + } + + e1 = new VarExp(loc, f); + goto Lagain; + } + else + { error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars()); + type = Type::terror; + return this; + } + } + else if (e1->op == TOKvar) + { + // Do overload resolution + VarExp *ve = (VarExp *)e1; + + f = ve->var->isFuncDeclaration(); + assert(f); + + // 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, arguments); + checkDeprecated(sc, f); + + 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(); + functionArguments(loc, sc, tf, arguments); + + assert(type); + + if (f && f->tintro) + { + Type *t = type; + int offset = 0; + + if (f->tintro->next->isBaseOf(t, &offset) && offset) + { + type = f->tintro->next; + return castTo(sc, t); + } + } + + return this; +} + +int CallExp::checkSideEffect(int flag) +{ + return 1; +} + +Expression *CallExp::toLvalue(Scope *sc, Expression *e) +{ + if (type->toBasetype()->ty == Tstruct) + return this; + else + return Expression::toLvalue(sc, e); +} + +void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + expToCBuffer(buf, hgs, e1, precedence[op]); + buf->writeByte('('); + argsToCBuffer(buf, arguments, hgs); + buf->writeByte(')'); +} + + +/************************************************************/ + +AddrExp::AddrExp(Loc loc, Expression *e) + : UnaExp(loc, TOKaddress, sizeof(AddrExp), e) +{ +} + +Expression *AddrExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("AddrExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + UnaExp::semantic(sc); + e1 = e1->toLvalue(sc, NULL); + if (!e1->type) + { + error("cannot take address of %s", e1->toChars()); + type = Type::tint32; + return this; + } + 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; + + 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(); + + if (f && f->isNested()) + { Expression *e; + + e = new DelegateExp(loc, e1, f); + e = e->semantic(sc); + return e; + } + else if (v) + { + v->needsStorage = true; + } + } + else if (e1->op == TOKarray) + { + if (e1->type->toBasetype()->ty == Tbit) + error("cannot take address of bit in array"); + } + return optimize(WANTvalue); + } + return this; +} + +/************************************************************/ + +PtrExp::PtrExp(Loc loc, Expression *e) + : UnaExp(loc, TOKstar, sizeof(PtrExp), e) +{ + if (e->type) + type = e->type->next; +} + +PtrExp::PtrExp(Loc loc, Expression *e, Type *t) + : UnaExp(loc, TOKstar, sizeof(PtrExp), e) +{ + type = t; +} + +Expression *PtrExp::semantic(Scope *sc) +{ Type *tb; + +#if LOGSEMANTIC + printf("PtrExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + if (type) + return this; + if (!e1->type) + printf("PtrExp::semantic('%s')\n", toChars()); + tb = e1->type->toBasetype(); + switch (tb->ty) + { + case Tpointer: + type = tb->next; + if (type->isbit()) + { Expression *e; + + // Rewrite *p as p[0] + e = new IndexExp(loc, e1, new IntegerExp(0)); + return e->semantic(sc); + } + break; + + case Tsarray: + case Tarray: + type = tb->next; + e1 = e1->castTo(sc, type->pointerTo()); + break; + + default: + error("can only * a pointer, not a '%s'", e1->type->toChars()); + type = Type::tint32; + break; + } + rvalue(); + return this; +} + +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; +} + +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(); + 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(); + e1 = e1->checkIntegral(); + type = e1->type; + } + return this; +} + +/************************************************************/ + +NotExp::NotExp(Loc loc, Expression *e) + : UnaExp(loc, TOKnot, sizeof(NotExp), e) +{ +} + +Expression *NotExp::semantic(Scope *sc) +{ + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->checkToBoolean(); + type = Type::tboolean; + return this; +} + +int NotExp::isBit() +{ + return TRUE; +} + + + +/************************************************************/ + +BoolExp::BoolExp(Loc loc, Expression *e, Type *t) + : UnaExp(loc, TOKtobool, sizeof(BoolExp), e) +{ + type = t; +} + +Expression *BoolExp::semantic(Scope *sc) +{ + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->checkToBoolean(); + type = Type::tboolean; + return this; +} + +int BoolExp::isBit() +{ + return TRUE; +} + +/************************************************************/ + +DeleteExp::DeleteExp(Loc loc, Expression *e) + : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e) +{ +} + +Expression *DeleteExp::semantic(Scope *sc) +{ + Type *tb; + + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->toLvalue(sc, NULL); + type = Type::tvoid; + + tb = e1->type->toBasetype(); + switch (tb->ty) + { case Tclass: + { TypeClass *tc = (TypeClass *)tb; + ClassDeclaration *cd = tc->sym; + + if (cd->isCOMinterface()) + { /* Because COM classes are deleted by IUnknown.Release() + */ + error("cannot delete instance of COM interface %s", cd->toChars()); + } + break; + } + case Tpointer: + tb = 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()); + break; + } + + if (e1->op == TOKindex) + { + IndexExp *ae = (IndexExp *)(e1); + Type *tb1 = ae->e1->type->toBasetype(); + if (tb1->ty == Taarray) + { if (!global.params.useDeprecated) + error("delete aa[key] deprecated, use aa.remove(key)"); + } + } + + return this; +} + +int DeleteExp::checkSideEffect(int flag) +{ + return 1; +} + +Expression *DeleteExp::checkToBoolean() +{ + error("delete does not give a boolean result"); + return this; +} + +void DeleteExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("delete "); + expToCBuffer(buf, hgs, e1, precedence[op]); +} + +/************************************************************/ + +CastExp::CastExp(Loc loc, Expression *e, Type *t) + : UnaExp(loc, TOKcast, sizeof(CastExp), e) +{ + to = t; +} + +Expression *CastExp::syntaxCopy() +{ + return new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy()); +} + + +Expression *CastExp::semantic(Scope *sc) +{ Expression *e; + BinExp *b; + UnaExp *u; + +#if LOGSEMANTIC + printf("CastExp::semantic('%s')\n", toChars()); +#endif + +//static int x; assert(++x < 10); + + if (type) + return this; + UnaExp::semantic(sc); + if (e1->type) // if not a tuple + { + e1 = resolveProperties(sc, e1); + to = to->semantic(loc, sc); + + e = op_overload(sc); + if (e) + { + return e->implicitCastTo(sc, to); + } + + Type *tob = to->toBasetype(); + if (tob->ty == Tstruct && + !tob->equals(e1->type->toBasetype()) && + ((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; + } + } + 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("); + to->toCBuffer(buf, NULL, hgs); + buf->writeByte(')'); + expToCBuffer(buf, hgs, e1, precedence[op]); +} + + +/************************************************************/ + +SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr) + : UnaExp(loc, TOKslice, sizeof(SliceExp), e1) +{ + this->upr = upr; + this->lwr = lwr; + lengthVar = NULL; +} + +Expression *SliceExp::syntaxCopy() +{ + Expression *lwr = NULL; + if (this->lwr) + lwr = this->lwr->syntaxCopy(); + + Expression *upr = NULL; + if (this->upr) + upr = this->upr->syntaxCopy(); + + return new SliceExp(loc, e1->syntaxCopy(), lwr, upr); +} + +Expression *SliceExp::semantic(Scope *sc) +{ Expression *e; + AggregateDeclaration *ad; + //FuncDeclaration *fd; + ScopeDsymbol *sym; + +#if LOGSEMANTIC + printf("SliceExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + + e = this; + + Type *t = e1->type->toBasetype(); + if (t->ty == Tpointer) + { + if (!lwr || !upr) + error("need upper and lower bound to slice pointer"); + } + else if (t->ty == Tarray) + { + } + else if (t->ty == Tsarray) + { + } + else if (t->ty == Tclass) + { + ad = ((TypeClass *)t)->sym; + goto L1; + } + else if (t->ty == Tstruct) + { + ad = ((TypeStruct *)t)->sym; + + L1: + if (search_function(ad, Id::slice)) + { + // Rewrite as e1.slice(lwr, upr) + e = new DotIdExp(loc, e1, Id::slice); + + if (lwr) + { + assert(upr); + e = new CallExp(loc, e, lwr, upr); + } + else + { assert(!upr); + e = new CallExp(loc, e); + } + e = e->semantic(sc); + return e; + } + goto Lerror; + } + else if (t->ty == Ttuple) + { + if (!lwr && !upr) + return e1; + if (!lwr || !upr) + { error("need upper and lower bound to slice tuple"); + goto Lerror; + } + } + else + goto Lerror; + + if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) + { + sym = new ArrayScopeSymbol(this); + sym->loc = loc; + sym->parent = sc->scopesym; + sc = sc->push(sym); + } + + if (lwr) + { lwr = lwr->semantic(sc); + lwr = resolveProperties(sc, lwr); + lwr = lwr->implicitCastTo(sc, Type::tsize_t); + } + if (upr) + { upr = upr->semantic(sc); + upr = resolveProperties(sc, upr); + upr = upr->implicitCastTo(sc, Type::tsize_t); + } + + if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) + sc->pop(); + + if (t->ty == Ttuple) + { + lwr = lwr->optimize(WANTvalue); + upr = upr->optimize(WANTvalue); + uinteger_t i1 = lwr->toUInteger(); + uinteger_t i2 = upr->toUInteger(); + + size_t length; + TupleExp *te; + TypeTuple *tup; + + if (e1->op == TOKtuple) // slicing an expression tuple + { te = (TupleExp *)e1; + length = te->exps->dim; + } + else if (e1->op == TOKtype) // slicing a type tuple + { tup = (TypeTuple *)t; + length = Argument::dim(tup->arguments); + } + else + assert(0); + + if (i1 <= i2 && i2 <= length) + { size_t j1 = (size_t) i1; + size_t j2 = (size_t) i2; + + if (e1->op == TOKtuple) + { Expressions *exps = new Expressions; + exps->setDim(j2 - j1); + for (size_t i = 0; i < j2 - j1; i++) + { Expression *e = (Expression *)te->exps->data[j1 + i]; + exps->data[i] = (void *)e; + } + e = new TupleExp(loc, exps); + } + else + { Arguments *args = new Arguments; + args->reserve(j2 - j1); + for (size_t i = j1; i < j2; i++) + { Argument *arg = Argument::getNth(tup->arguments, i); + args->push(arg); + } + e = new TypeExp(e1->loc, new TypeTuple(args)); + } + e = e->semantic(sc); + } + else + { + error("string slice [%ju .. %ju] is out of bounds", i1, i2); + e = e1; + } + return e; + } + + type = t->next->arrayOf(); + return e; + +Lerror: + char *s; + if (t->ty == Tvoid) + s = e1->toChars(); + else + s = t->toChars(); + error("%s cannot be sliced with []", s); + type = Type::terror; + return e; +} + +void SliceExp::checkEscape() +{ + e1->checkEscape(); +} + +Expression *SliceExp::toLvalue(Scope *sc, Expression *e) +{ + return this; +} + +Expression *SliceExp::modifiableLvalue(Scope *sc, Expression *e) +{ + error("slice expression %s is not a modifiable lvalue", toChars()); + return this; +} + +void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, precedence[op]); + buf->writeByte('['); + if (upr || lwr) + { + if (lwr) + expToCBuffer(buf, hgs, lwr, PREC_assign); + else + buf->writeByte('0'); + buf->writestring(".."); + if (upr) + expToCBuffer(buf, hgs, upr, PREC_assign); + else + buf->writestring("length"); // BUG: should be array.length + } + buf->writeByte(']'); +} + +/********************** ArrayLength **************************************/ + +ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1) + : UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1) +{ +} + +Expression *ArrayLengthExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("ArrayLengthExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + + type = Type::tsize_t; + } + return this; +} + +void ArrayLengthExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writestring(".length"); +} + +/*********************** ArrayExp *************************************/ + +// e1 [ i1, i2, i3, ... ] + +ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args) + : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1) +{ + arguments = args; +} + +Expression *ArrayExp::syntaxCopy() +{ + return new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); +} + +Expression *ArrayExp::semantic(Scope *sc) +{ Expression *e; + Type *t1; + +#if LOGSEMANTIC + printf("ArrayExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + + t1 = e1->type->toBasetype(); + if (t1->ty != Tclass && t1->ty != Tstruct) + { // Convert to IndexExp + if (arguments->dim != 1) + error("only one index allowed to index %s", t1->toChars()); + e = new IndexExp(loc, e1, (Expression *)arguments->data[0]); + return e->semantic(sc); + } + + // Run semantic() on each argument + for (size_t i = 0; i < arguments->dim; i++) + { e = (Expression *)arguments->data[i]; + + e = e->semantic(sc); + if (!e->type) + error("%s has no value", e->toChars()); + arguments->data[i] = (void *)e; + } + + expandTuples(arguments); + assert(arguments && arguments->dim); + + e = op_overload(sc); + if (!e) + { error("no [] operator overload for type %s", e1->type->toChars()); + e = e1; + } + return e; +} + + +Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) +{ + if (type && type->toBasetype()->ty == Tvoid) + error("voids have no value"); + return this; +} + + +void ArrayExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('['); + argsToCBuffer(buf, arguments, hgs); + buf->writeByte(']'); +} + +/************************* DotExp ***********************************/ + +DotExp::DotExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKdotexp, sizeof(DotExp), e1, e2) +{ +} + +Expression *DotExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DotExp::semantic('%s')\n", toChars()); + if (type) printf("\ttype = %s\n", type->toChars()); +#endif + e1 = e1->semantic(sc); + e2 = e2->semantic(sc); + if (e2->op == TOKimport) + { + ScopeExp *se = (ScopeExp *)e2; + TemplateDeclaration *td = se->sds->isTemplateDeclaration(); + if (td) + { Expression *e = new DotTemplateExp(loc, e1, td); + e = e->semantic(sc); + return e; + } + } + if (!type) + type = e2->type; + return this; +} + + +/************************* CommaExp ***********************************/ + +CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2) +{ +} + +Expression *CommaExp::semantic(Scope *sc) +{ + if (!type) + { BinExp::semanticp(sc); + type = e2->type; + } + return this; +} + +void CommaExp::checkEscape() +{ + e2->checkEscape(); +} + +Expression *CommaExp::toLvalue(Scope *sc, Expression *e) +{ + e2 = e2->toLvalue(sc, NULL); + return this; +} + +Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e) +{ + e2 = e2->modifiableLvalue(sc, e); + return this; +} + +int CommaExp::isBool(int result) +{ + return e2->isBool(result); +} + +int CommaExp::checkSideEffect(int flag) +{ + if (flag == 2) + return e1->checkSideEffect(2) || e2->checkSideEffect(2); + else + { + // Don't check e1 until we cast(void) the a,b code generation + return e2->checkSideEffect(flag); + } +} + +/************************** IndexExp **********************************/ + +// e1 [ e2 ] + +IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2) +{ + //printf("IndexExp::IndexExp('%s')\n", toChars()); + lengthVar = NULL; + modifiable = 0; // assume it is an rvalue +} + +Expression *IndexExp::semantic(Scope *sc) +{ Expression *e; + BinExp *b; + UnaExp *u; + Type *t1; + ScopeDsymbol *sym; + +#if LOGSEMANTIC + printf("IndexExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + if (!e1->type) + e1 = e1->semantic(sc); + assert(e1->type); // semantic() should already be run on it + e = this; + + // Note that unlike C we do not implement the int[ptr] + + t1 = e1->type->toBasetype(); + + if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) + { // Create scope for 'length' variable + sym = new ArrayScopeSymbol(this); + sym->loc = loc; + sym->parent = sc->scopesym; + sc = sc->push(sym); + } + + e2 = e2->semantic(sc); + if (!e2->type) + { + error("%s has no value", e2->toChars()); + e2->type = Type::terror; + } + e2 = resolveProperties(sc, e2); + + if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) + sc = sc->pop(); + + switch (t1->ty) + { + case Tpointer: + case Tarray: + e2 = e2->implicitCastTo(sc, Type::tsize_t); + e->type = 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) + { + integer_t index = e2->toInteger(); + integer_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->next; + 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 = Argument::dim(tup->arguments); + } + else + assert(0); + + if (index < length) + { + + if (e1->op == TOKtuple) + e = (Expression *)te->exps->data[(size_t)index]; + else + e = new TypeExp(e1->loc, Argument::getNth(tup->arguments, (size_t)index)->type); + } + else + { + error("array index [%ju] is outside array bounds [0 .. %zu]", + index, length); + e = e1; + } + break; + } + + default: + error("%s must be an array or pointer type, not %s", + e1->toChars(), e1->type->toChars()); + type = Type::tint32; + break; + } + return e; +} + +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 *)"--"); +} + +/************************************************************/ + +/* Can be TOKconstruct too */ + +AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2) +{ + ismemset = 0; +} + +Expression *AssignExp::semantic(Scope *sc) +{ Type *t1; + Expression *e1old = e1; + +#if LOGSEMANTIC + printf("AssignExp::semantic('%s')\n", toChars()); +#endif + //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); + + /* 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) + { Type *t1; + ArrayExp *ae = (ArrayExp *)e1; + AggregateDeclaration *ad; + Identifier *id = Id::index; + + ae->e1 = ae->e1->semantic(sc); + t1 = ae->e1->type->toBasetype(); + if (t1->ty == Tstruct) + { + ad = ((TypeStruct *)t1)->sym; + goto L1; + } + else if (t1->ty == Tclass) + { + ad = ((TypeClass *)t1)->sym; + L1: + // Rewrite (a[i] = value) to (a.opIndexAssign(value, i)) + if (search_function(ad, Id::indexass)) + { Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); + Expressions *a = (Expressions *)ae->arguments->copy(); + + a->insert(0, e2); + e = new CallExp(loc, e, a); + e = e->semantic(sc); + return e; + } + else + { + // Rewrite (a[i] = value) to (a.opIndex(i, value)) + if (search_function(ad, id)) + { Expression *e = new DotIdExp(loc, ae->e1, id); + + if (1 || !global.params.useDeprecated) + error("operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i)"); + + e = new CallExp(loc, e, (Expression *)ae->arguments->data[0], e2); + e = e->semantic(sc); + return e; + } + } + } + } + /* Look for operator overloading of a[i..j]=value. + * Do it before semantic() otherwise the a[i..j] will have been + * converted to a.opSlice() already. + */ + if (e1->op == TOKslice) + { Type *t1; + SliceExp *ae = (SliceExp *)e1; + AggregateDeclaration *ad; + Identifier *id = Id::index; + + ae->e1 = ae->e1->semantic(sc); + ae->e1 = resolveProperties(sc, ae->e1); + t1 = ae->e1->type->toBasetype(); + if (t1->ty == Tstruct) + { + ad = ((TypeStruct *)t1)->sym; + goto L2; + } + else if (t1->ty == Tclass) + { + ad = ((TypeClass *)t1)->sym; + L2: + // Rewrite (a[i..j] = value) to (a.opIndexAssign(value, i, j)) + if (search_function(ad, Id::sliceass)) + { Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass); + Expressions *a = new Expressions(); + + a->push(e2); + if (ae->lwr) + { a->push(ae->lwr); + assert(ae->upr); + a->push(ae->upr); + } + else + assert(!ae->upr); + e = new CallExp(loc, e, a); + e = e->semantic(sc); + return e; + } + } + } + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + assert(e1->type); + + /* Rewrite tuple assignment as a tuple of assignments. + */ + if (e1->op == TOKtuple && e2->op == TOKtuple) + { TupleExp *tup1 = (TupleExp *)e1; + TupleExp *tup2 = (TupleExp *)e2; + size_t dim = tup1->exps->dim; + if (dim != tup2->exps->dim) + { + error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim); + } + else + { Expressions *exps = new Expressions; + exps->setDim(dim); + + for (int i = 0; i < dim; i++) + { Expression *ex1 = (Expression *)tup1->exps->data[i]; + Expression *ex2 = (Expression *)tup2->exps->data[i]; + exps->data[i] = (void *) new AssignExp(loc, ex1, ex2); + } + Expression *e = new TupleExp(loc, exps); + e = e->semantic(sc); + return e; + } + } + + t1 = e1->type->toBasetype(); + + if (t1->ty == Tfunction) + { // Rewrite f=value to f(value) + Expression *e; + + 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) + { + if (!e2->type->implicitConvTo(e1->type)) + { + Expression *e = op_overload(sc); + if (e) + return e; + } + } + + e2->rvalue(); + + if (e1->op == TOKarraylength) + { + // e1 is not an lvalue, but we let code generator handle it + ArrayLengthExp *ale = (ArrayLengthExp *)e1; + + ale->e1 = ale->e1->modifiableLvalue(sc, e1); + } + else if (e1->op == TOKslice) + ; + else + { // Try to do a decent error message with the expression + // before it got constant folded + e1 = e1->modifiableLvalue(sc, e1old); + } + + if (e1->op == TOKslice && + t1->nextOf() && + 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) + { + error("cannot assign to static array %s", e1->toChars()); + } + else + { + e2 = e2->implicitCastTo(sc, e1->type); + } + type = e1->type; + assert(type); + return this; +} + +Expression *AssignExp::checkToBoolean() +{ + // Things like: + // if (a = b) ... + // are usually mistakes. + + error("'=' does not give a boolean result"); + return this; +} + +/************************************************************/ + +AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2) +{ +} + +Expression *AddAssignExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1->modifiableLvalue(sc, e1); + + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + if ((tb1->ty == Tarray || tb1->ty == Tsarray) && + (tb2->ty == Tarray || tb2->ty == Tsarray) && + tb1->next->equals(tb2->next) + ) + { + 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; + + char name[6+6+1]; + Identifier *id; + static int idn; + sprintf(name, "__name%d", ++idn); + id = Lexer::idPool(name); + + v = new VarDeclaration(loc, tb1->pointerTo(), id, NULL); + v->semantic(sc); + if (!sc->insert(v)) + assert(0); + v->parent = sc->func; + + ea = new AddrExp(loc, e1); + ea = new AssignExp(loc, new VarExp(loc, v), ea); + + ex = new VarExp(loc, v); + ex = new PtrExp(loc, ex); + e = new AddExp(loc, ex, e2); + e = new CastExp(loc, e, e1->type); + e = new AssignExp(loc, ex->syntaxCopy(), e); + + e = new CommaExp(loc, ea, e); + } + else +#endif + { // Rewrite e1+=e2 to e1=e1+e2 + // BUG: doesn't account for side effects in e1 + // BUG: other assignment operators for bits aren't handled at all + e = new AddExp(loc, e1, e2); + e = new CastExp(loc, e, e1->type); + e = new AssignExp(loc, e1->syntaxCopy(), e); + } + e = e->semantic(sc); + } + else + { + type = e1->type; + typeCombine(sc); + e1->checkArithmetic(); + e2->checkArithmetic(); + if (type->isreal() || type->isimaginary()) + { + assert(global.errors || e2->type->isfloating()); + e2 = e2->castTo(sc, e1->type); + } + e = this; + } + } + return e; +} + +/************************************************************/ + +MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2) +{ +} + +Expression *MinAssignExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + if (e1->type->ty == Tpointer && e2->type->isintegral()) + e = scaleFactor(sc); + else + { + e1 = e1->checkArithmetic(); + e2 = e2->checkArithmetic(); + type = e1->type; + typeCombine(sc); + if (type->isreal() || type->isimaginary()) + { + assert(e2->type->isfloating()); + e2 = e2->castTo(sc, e1->type); + } + e = this; + } + return e; +} + +/************************************************************/ + +CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2) +{ +} + +Expression *CatAssignExp::semantic(Scope *sc) +{ Expression *e; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKslice) + { SliceExp *se = (SliceExp *)e1; + + if (se->e1->type->toBasetype()->ty == Tsarray) + error("cannot append to static array %s", se->e1->type->toChars()); + } + + e1 = e1->modifiableLvalue(sc, e1); + + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + e2->rvalue(); + + if ((tb1->ty == Tarray) && + (tb2->ty == Tarray || tb2->ty == Tsarray) && + e2->implicitConvTo(e1->type) + //e1->type->next->equals(e2->type->next) + ) + { // Append array + e2 = e2->castTo(sc, e1->type); + type = e1->type; + e = this; + } + else if ((tb1->ty == Tarray) && + e2->implicitConvTo(tb1->next) + ) + { // Append element + e2 = e2->castTo(sc, tb1->next); + type = e1->type; + e = this; + } + else + { + error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars()); + type = Type::tint32; + e = this; + } + return e; +} + +/************************************************************/ + +MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2) +{ +} + +Expression *MulAssignExp::semantic(Scope *sc) +{ Expression *e; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkArithmetic(); + e2->checkArithmetic(); + if (e2->type->isfloating()) + { Type *t1; + Type *t2; + + t1 = e1->type; + t2 = e2->type; + if (t1->isreal()) + { + if (t2->isimaginary() || t2->iscomplex()) + { + e2 = e2->castTo(sc, t1); + } + } + else if (t1->isimaginary()) + { + if (t2->isimaginary() || t2->iscomplex()) + { + switch (t1->ty) + { + case Timaginary32: t2 = Type::tfloat32; break; + case Timaginary64: t2 = Type::tfloat64; break; + case Timaginary80: t2 = Type::tfloat80; break; + default: + assert(0); + } + e2 = e2->castTo(sc, t2); + } + } + } + return this; +} + +/************************************************************/ + +DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2) +{ +} + +Expression *DivAssignExp::semantic(Scope *sc) +{ Expression *e; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkArithmetic(); + e2->checkArithmetic(); + if (e2->type->isimaginary()) + { Type *t1; + Type *t2; + + t1 = e1->type; + if (t1->isreal()) + { // x/iv = i(-x/v) + // Therefore, the result is 0 + e2 = new CommaExp(loc, e2, new RealExp(loc, 0, t1)); + e2->type = t1; + e = new AssignExp(loc, e1, e2); + e->type = t1; + return e; + } + else if (t1->isimaginary()) + { Expression *e; + + switch (t1->ty) + { + case Timaginary32: t2 = Type::tfloat32; break; + case Timaginary64: t2 = Type::tfloat64; break; + case Timaginary80: t2 = Type::tfloat80; break; + default: + assert(0); + } + e2 = e2->castTo(sc, t2); + e = new AssignExp(loc, e1, e2); + e->type = t1; + return e; + } + } + return this; +} + +/************************************************************/ + +ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2) +{ +} + +Expression *ModAssignExp::semantic(Scope *sc) +{ + return commonSemanticAssign(sc); +} + +/************************************************************/ + +ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2) +{ +} + +Expression *ShlAssignExp::semantic(Scope *sc) +{ Expression *e; + + //printf("ShlAssignExp::semantic()\n"); + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkIntegral(); + e2 = e2->checkIntegral(); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LLVMDC + return this; +} + +/************************************************************/ + +ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2) +{ +} + +Expression *ShrAssignExp::semantic(Scope *sc) +{ Expression *e; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkIntegral(); + e2 = e2->checkIntegral(); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LLVMDC + return this; +} + +/************************************************************/ + +UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2) +{ +} + +Expression *UshrAssignExp::semantic(Scope *sc) +{ Expression *e; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkIntegral(); + e2 = e2->checkIntegral(); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LLVMDC + return this; +} + +/************************************************************/ + +AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2) +{ +} + +Expression *AndAssignExp::semantic(Scope *sc) +{ + return commonSemanticAssignIntegral(sc); +} + +/************************************************************/ + +OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2) +{ +} + +Expression *OrAssignExp::semantic(Scope *sc) +{ + return commonSemanticAssignIntegral(sc); +} + +/************************************************************/ + +XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2) +{ +} + +Expression *XorAssignExp::semantic(Scope *sc) +{ + return commonSemanticAssignIntegral(sc); +} + +/************************* AddExp *****************************/ + +AddExp::AddExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2) +{ + llvmFieldIndex = false; +} + +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->next->equals(tb2->next) + ) + { + 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->next->size(); + e = new DivExp(loc, this, new IntegerExp(0, stride, Type::tptrdiff_t)); + e->type = Type::tptrdiff_t; + return e; + } + else if (t2->isintegral()) + e = scaleFactor(sc); + else + { error("incompatible types for -"); + return new IntegerExp(0); + } + } + else if (t2->ty == Tpointer) + { + type = e2->type; + error("can't subtract pointer from %s", e1->type->toChars()); + return new IntegerExp(0); + } + 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->next->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->next->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 + { + 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); + e1->checkArithmetic(); + e2->checkArithmetic(); + if (type->isfloating()) + { Type *t1 = e1->type; + Type *t2 = e2->type; + + if (t1->isreal()) + { + type = t2; + } + else if (t2->isreal()) + { + type = t1; + } + else if (t1->isimaginary()) + { + if (t2->isimaginary()) + { Expression *e; + + switch (t1->ty) + { + case Timaginary32: type = Type::tfloat32; break; + case Timaginary64: type = Type::tfloat64; break; + case Timaginary80: type = Type::tfloat80; break; + default: assert(0); + } + + // iy * iv = -yv + e1->type = type; + e2->type = type; + e = new NegExp(loc, this); + e = e->semantic(sc); + return e; + } + else + type = t2; // t2 is complex + } + else if (t2->isimaginary()) + { + type = t1; // t1 is complex + } + } + return this; +} + +/************************************************************/ + +DivExp::DivExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2) +{ +} + +Expression *DivExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + typeCombine(sc); + e1->checkArithmetic(); + e2->checkArithmetic(); + if (type->isfloating()) + { Type *t1 = e1->type; + Type *t2 = e2->type; + + if (t1->isreal()) + { + type = t2; + if (t2->isimaginary()) + { Expression *e; + + // x/iv = i(-x/v) + e2->type = t1; + e = new NegExp(loc, this); + e = e->semantic(sc); + return e; + } + } + else if (t2->isreal()) + { + type = t1; + } + else if (t1->isimaginary()) + { + if (t2->isimaginary()) + { + switch (t1->ty) + { + case Timaginary32: type = Type::tfloat32; break; + case Timaginary64: type = Type::tfloat64; break; + case Timaginary80: type = Type::tfloat80; break; + default: assert(0); + } + } + else + type = t2; // t2 is complex + } + else if (t2->isimaginary()) + { + type = t1; // t1 is complex + } + } + return this; +} + +/************************************************************/ + +ModExp::ModExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2) +{ +} + +Expression *ModExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + typeCombine(sc); + e1->checkArithmetic(); + 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); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LLVMDC + type = e1->type; + } + return this; +} + +/************************************************************/ + +ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2) +{ +} + +Expression *ShrExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + e1 = e1->checkIntegral(); + e2 = e2->checkIntegral(); + e1 = e1->integralPromotions(sc); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LLVMDC + type = e1->type; + } + return this; +} + +/************************************************************/ + +UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2) +{ +} + +Expression *UshrExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + e1 = e1->checkIntegral(); + e2 = e2->checkIntegral(); + e1 = e1->integralPromotions(sc); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LLVMDC + 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); + e1->checkIntegral(); + e2->checkIntegral(); + } + } + return this; +} + +/************************************************************/ + +OrExp::OrExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKor, sizeof(OrExp), e1, e2) +{ +} + +Expression *OrExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + if (e1->type->toBasetype()->ty == Tbool && + e2->type->toBasetype()->ty == Tbool) + { + type = e1->type; + e = this; + } + else + { + typeCombine(sc); + e1->checkIntegral(); + e2->checkIntegral(); + } + } + return this; +} + +/************************************************************/ + +XorExp::XorExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKxor, sizeof(XorExp), e1, e2) +{ +} + +Expression *XorExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + if (e1->type->toBasetype()->ty == Tbool && + e2->type->toBasetype()->ty == Tbool) + { + type = e1->type; + e = this; + } + else + { + typeCombine(sc); + e1->checkIntegral(); + e2->checkIntegral(); + } + } + return this; +} + + +/************************************************************/ + +OrOrExp::OrOrExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKoror, sizeof(OrOrExp), e1, e2) +{ +} + +Expression *OrOrExp::semantic(Scope *sc) +{ + unsigned cs1; + + // same as for AndAnd + e1 = e1->semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->checkToPointer(); + e1 = e1->checkToBoolean(); + cs1 = sc->callSuper; + + if (sc->flags & SCOPEstaticif) + { + /* If in static if, don't evaluate e2 if we don't have to. + */ + e1 = e1->optimize(WANTflags); + if (e1->isBool(TRUE)) + { + return new IntegerExp(loc, 1, Type::tboolean); + } + } + + e2 = e2->semantic(sc); + sc->mergeCallSuper(loc, cs1); + e2 = resolveProperties(sc, e2); + e2 = e2->checkToPointer(); + + type = Type::tboolean; + if (e1->type->ty == Tvoid) + type = Type::tvoid; + if (e2->op == TOKtype || e2->op == TOKimport) + error("%s is not an expression", e2->toChars()); + return this; +} + +Expression *OrOrExp::checkToBoolean() +{ + e2 = e2->checkToBoolean(); + return this; +} + +int OrOrExp::isBit() +{ + return TRUE; +} + +int OrOrExp::checkSideEffect(int flag) +{ + if (flag == 2) + { + return e1->checkSideEffect(2) || e2->checkSideEffect(2); + } + else + { e1->checkSideEffect(1); + return e2->checkSideEffect(flag); + } +} + +/************************************************************/ + +AndAndExp::AndAndExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKandand, sizeof(AndAndExp), e1, e2) +{ +} + +Expression *AndAndExp::semantic(Scope *sc) +{ + unsigned cs1; + + // same as for OrOr + e1 = e1->semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->checkToPointer(); + e1 = e1->checkToBoolean(); + cs1 = sc->callSuper; + + if (sc->flags & SCOPEstaticif) + { + /* If in static if, don't evaluate e2 if we don't have to. + */ + e1 = e1->optimize(WANTflags); + if (e1->isBool(FALSE)) + { + return new IntegerExp(loc, 0, Type::tboolean); + } + } + + e2 = e2->semantic(sc); + sc->mergeCallSuper(loc, cs1); + e2 = resolveProperties(sc, e2); + e2 = e2->checkToPointer(); + + type = Type::tboolean; + if (e1->type->ty == Tvoid) + type = Type::tvoid; + if (e2->op == TOKtype || e2->op == TOKimport) + error("%s is not an expression", e2->toChars()); + return this; +} + +Expression *AndAndExp::checkToBoolean() +{ + e2 = e2->checkToBoolean(); + return this; +} + +int AndAndExp::isBit() +{ + return TRUE; +} + +int AndAndExp::checkSideEffect(int flag) +{ + if (flag == 2) + { + return e1->checkSideEffect(2) || e2->checkSideEffect(2); + } + else + { + e1->checkSideEffect(1); + return e2->checkSideEffect(flag); + } +} + +/************************************************************/ + +InExp::InExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKin, sizeof(InExp), e1, e2) +{ +} + +Expression *InExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + //type = Type::tboolean; + Type *t2b = e2->type->toBasetype(); + if (t2b->ty != Taarray) + { + error("rvalue of in expression must be an associative array, not %s", e2->type->toChars()); + type = Type::terror; + } + else + { + TypeAArray *ta = (TypeAArray *)t2b; + + // Convert key to type of key + e1 = e1->implicitCastTo(sc, ta->index); + + // Return type is pointer to value + type = ta->next->pointerTo(); + } + return this; +} + +int InExp::isBit() +{ + return FALSE; +} + + +/************************************************************/ + +/* This deletes the key e1 from the associative array e2 + */ + +RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2) +{ + type = Type::tvoid; +} + +/************************************************************/ + +CmpExp::CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, op, sizeof(CmpExp), e1, e2) +{ +} + +Expression *CmpExp::semantic(Scope *sc) +{ Expression *e; + Type *t1; + Type *t2; + +#if LOGSEMANTIC + printf("CmpExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + BinExp::semanticp(sc); + + if (e1->type->toBasetype()->ty == Tclass && e2->op == TOKnull || + e2->type->toBasetype()->ty == Tclass && e1->op == TOKnull) + { + error("do not use null when comparing class types"); + } + + e = op_overload(sc); + if (e) + { + e = new CmpExp(op, loc, e, new IntegerExp(loc, 0, Type::tint32)); + e = e->semantic(sc); + return e; + } + + typeCombine(sc); + type = Type::tboolean; + + // Special handling for array comparisons + t1 = e1->type->toBasetype(); + t2 = e2->type->toBasetype(); + if ((t1->ty == Tarray || t1->ty == Tsarray) && + (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; + return e; +} + +int CmpExp::isBit() +{ + return TRUE; +} + + +/************************************************************/ + +EqualExp::EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, op, sizeof(EqualExp), e1, e2) +{ + assert(op == TOKequal || op == TOKnotequal); +} + +Expression *EqualExp::semantic(Scope *sc) +{ Expression *e; + Type *t1; + Type *t2; + + //printf("EqualExp::semantic('%s')\n", toChars()); + if (type) + return this; + + BinExp::semanticp(sc); + + /* Before checking for operator overloading, check to see if we're + * comparing the addresses of two statics. If so, we can just see + * if they are the same symbol. + */ + if (e1->op == TOKaddress && e2->op == TOKaddress) + { AddrExp *ae1 = (AddrExp *)e1; + AddrExp *ae2 = (AddrExp *)e2; + + if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar) + { VarExp *ve1 = (VarExp *)ae1->e1; + VarExp *ve2 = (VarExp *)ae2->e1; + + if (ve1->var == ve2->var /*|| ve1->var->toSymbol() == ve2->var->toSymbol()*/) + { + // They are the same, result is 'true' for ==, 'false' for != + e = new IntegerExp(loc, (op == TOKequal), Type::tboolean); + return e; + } + } + } + + if (e1->type->toBasetype()->ty == Tclass && e2->op == TOKnull || + e2->type->toBasetype()->ty == Tclass && e1->op == TOKnull) + { + error("use '%s' instead of '%s' when comparing with null", + Token::toChars(op == TOKequal ? TOKidentity : TOKnotidentity), + Token::toChars(op)); + } + + //if (e2->op != TOKnull) + { + e = op_overload(sc); + if (e) + { + if (op == TOKnotequal) + { + e = new NotExp(e->loc, e); + e = e->semantic(sc); + } + return e; + } + } + + e = typeCombine(sc); + type = Type::tboolean; + + // Special handling for array comparisons + 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; + } + } + return this; +} + +Expression *CondExp::toLvalue(Scope *sc, Expression *ex) +{ + PtrExp *e; + + // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) + e = new PtrExp(loc, this, type); + + e1 = e1->addressOf(sc); + //e1 = e1->toLvalue(sc, NULL); + + e2 = e2->addressOf(sc); + //e2 = e2->toLvalue(sc, NULL); + + typeCombine(sc); + + type = e2->type; + return e; +} + +Expression *CondExp::modifiableLvalue(Scope *sc, Expression *e) +{ + error("conditional expression %s is not a modifiable lvalue", toChars()); + return this; +} + +void CondExp::checkEscape() +{ + e1->checkEscape(); + e2->checkEscape(); +} + + +Expression *CondExp::checkToBoolean() +{ + e1 = e1->checkToBoolean(); + e2 = e2->checkToBoolean(); + return this; +} + +int CondExp::checkSideEffect(int flag) +{ + if (flag == 2) + { + return econd->checkSideEffect(2) || + e1->checkSideEffect(2) || + e2->checkSideEffect(2); + } + else + { + econd->checkSideEffect(1); + e1->checkSideEffect(flag); + return e2->checkSideEffect(flag); + } +} + +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); +} + + diff --git a/dmd/expression.h b/dmd/expression.h index 506daed9..425038b1 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -1,1443 +1,1443 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_EXPRESSION_H -#define DMD_EXPRESSION_H - -#include "mars.h" -#include "identifier.h" -#include "lexer.h" -#include "arraytypes.h" - -struct Type; -struct Scope; -struct TupleDeclaration; -struct VarDeclaration; -struct FuncDeclaration; -struct FuncLiteralDeclaration; -struct Declaration; -struct CtorDeclaration; -struct NewDeclaration; -struct Dsymbol; -struct Import; -struct Module; -struct ScopeDsymbol; -struct InlineCostState; -struct InlineDoState; -struct InlineScanState; -struct Expression; -struct Declaration; -struct AggregateDeclaration; -struct StructDeclaration; -struct TemplateInstance; -struct TemplateDeclaration; -struct ClassDeclaration; -struct HdrGenState; -struct BinExp; -struct InterState; -struct Symbol; // back end symbol - -namespace llvm -{ - class Constant; - class ConstantInt; -} - -enum TOK; - -// Back end -struct IRState; -struct dt_t; - -#if IN_LLVM -struct DValue; -typedef DValue elem; -#else -#ifdef IN_GCC -union tree_node; typedef union tree_node elem; -#else -struct elem; -#endif -#endif - -void initPrecedence(); - -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, Arguments *arguments, Expression *aggr); -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); - -struct Expression : Object -{ - Loc loc; // file location - enum TOK op; // handy to minimize use of dynamic_cast - Type *type; // !=NULL means that semantic() has been run - int size; // # of bytes in Expression so we can copy() it - - Expression(Loc loc, enum TOK op, int size); - Expression *copy(); - virtual Expression *syntaxCopy(); - virtual Expression *semantic(Scope *sc); - - int dyncast() { return DYNCAST_EXPRESSION; } // kludge for template.isExpression() - - void print(); - char *toChars(); - virtual void dump(int indent); - void error(const char *format, ...); - virtual void rvalue(); - - static Expression *combine(Expression *e1, Expression *e2); - static Expressions *arraySyntaxCopy(Expressions *exps); - - virtual integer_t toInteger(); - virtual uinteger_t toUInteger(); - virtual real_t toReal(); - virtual real_t toImaginary(); - virtual complex_t toComplex(); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toMangleBuffer(OutBuffer *buf); - virtual Expression *toLvalue(Scope *sc, Expression *e); - virtual Expression *modifiableLvalue(Scope *sc, Expression *e); - Expression *implicitCastTo(Scope *sc, Type *t); - virtual MATCH implicitConvTo(Type *t); - virtual Expression *castTo(Scope *sc, Type *t); - virtual void checkEscape(); - 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 void scanForNestedRef(Scope *sc); - - virtual Expression *optimize(int result); - #define WANTflags 1 - #define WANTvalue 2 - #define WANTinterpret 4 - - virtual Expression *interpret(InterState *istate); - - virtual int isConst(); - virtual int isBool(int result); - virtual int isBit(); - virtual int checkSideEffect(int flag); - - virtual int inlineCost(InlineCostState *ics); - virtual Expression *doInline(InlineDoState *ids); - virtual Expression *inlineScan(InlineScanState *iss); - - // For operator overloading - virtual int isCommutative(); - virtual Identifier *opId(); - virtual Identifier *opId_r(); - - // Back end - virtual elem *toElem(IRState *irs); - virtual dt_t **toDt(dt_t **pdt); - // LLVMDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct IntegerExp : Expression -{ - integer_t value; - - IntegerExp(Loc loc, integer_t value, Type *type); - IntegerExp(integer_t value); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - char *toChars(); - void dump(int indent); - integer_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); - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); - // LLVMDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct RealExp : Expression -{ - real_t value; - - RealExp(Loc loc, real_t value, Type *type); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - char *toChars(); - integer_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); - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); - // LLVMDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct ComplexExp : Expression -{ - complex_t value; - - ComplexExp(Loc loc, complex_t value, Type *type); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - char *toChars(); - integer_t toInteger(); - uinteger_t toUInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - Expression *castTo(Scope *sc, Type *t); - int isConst(); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); -#ifdef _DH - OutBuffer hexp; -#endif - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); - // LLVMDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -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); - Expression *toLvalue(Scope *sc, Expression *e); -}; - -struct DollarExp : IdentifierExp -{ - DollarExp(Loc loc); -}; - -struct DsymbolExp : Expression -{ - Dsymbol *s; - - DsymbolExp(Loc loc, Dsymbol *s); - Expression *semantic(Scope *sc); - char *toChars(); - void dump(int indent); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *toLvalue(Scope *sc, Expression *e); -}; - -struct ThisExp : Expression -{ - Declaration *var; - - ThisExp(Loc loc); - Expression *semantic(Scope *sc); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *toLvalue(Scope *sc, Expression *e); - void scanForNestedRef(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - - elem *toElem(IRState *irs); -}; - -struct SuperExp : ThisExp -{ - SuperExp(Loc loc); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); -}; - -struct NullExp : Expression -{ - unsigned char committed; // !=0 if type is committed - - NullExp(Loc loc); - Expression *semantic(Scope *sc); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *interpret(InterState *istate); - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); - // LLVMDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct StringExp : Expression -{ - void *string; // char, wchar, or dchar data - size_t len; // number of chars, wchars, or dchars - unsigned char sz; // 1: char, 2: wchar, 4: dchar - unsigned char committed; // !=0 if type is committed - unsigned char postfix; // 'c', 'w', 'd' - - StringExp(Loc loc, char *s); - StringExp(Loc loc, void *s, size_t len); - StringExp(Loc loc, void *s, size_t len, unsigned char postfix); - //Expression *syntaxCopy(); - int equals(Object *o); - char *toChars(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - StringExp *toUTF8(Scope *sc); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - int compare(Object *obj); - int isBool(int result); - unsigned charAt(size_t i); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); - // LLVMDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -// Tuple - -struct TupleExp : Expression -{ - Expressions *exps; - - TupleExp(Loc loc, Expressions *exps); - TupleExp(Loc loc, TupleDeclaration *tup); - Expression *syntaxCopy(); - int equals(Object *o); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - void checkEscape(); - int checkSideEffect(int flag); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - Expression *castTo(Scope *sc, Type *t); - elem *toElem(IRState *irs); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); -}; - -struct ArrayLiteralExp : Expression -{ - Expressions *elements; - - ArrayLiteralExp(Loc loc, Expressions *elements); - ArrayLiteralExp(Loc loc, Expression *e); - - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - int isBool(int result); - elem *toElem(IRState *irs); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - void scanForNestedRef(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - dt_t **toDt(dt_t **pdt); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - // LLVMDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct AssocArrayLiteralExp : Expression -{ - Expressions *keys; - Expressions *values; - - AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values); - - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - int isBool(int result); - elem *toElem(IRState *irs); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - void scanForNestedRef(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - // LLVMDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct StructLiteralExp : Expression -{ - StructDeclaration *sd; // which aggregate this is for - Expressions *elements; // parallels sd->fields[] with - // NULL entries for fields to skip - - Symbol *sym; // back end symbol to initialize with literal - size_t soffset; // offset from start of s - int fillHoles; // fill alignment 'holes' with zero - - StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements); - - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *getField(Type *type, unsigned offset); - int getFieldIndex(Type *type, unsigned offset); - elem *toElem(IRState *irs); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - void scanForNestedRef(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - dt_t **toDt(dt_t **pdt); - Expression *toLvalue(Scope *sc, Expression *e); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - // LLVMDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct TypeDotIdExp : Expression -{ - Identifier *ident; - - TypeDotIdExp(Loc loc, Type *type, Identifier *ident); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); -}; - -struct TypeExp : Expression -{ - TypeExp(Loc loc, Type *type); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - elem *toElem(IRState *irs); -}; - -struct ScopeExp : Expression -{ - ScopeDsymbol *sds; - - ScopeExp(Loc loc, ScopeDsymbol *sds); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - elem *toElem(IRState *irs); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct TemplateExp : Expression -{ - TemplateDeclaration *td; - - TemplateExp(Loc loc, TemplateDeclaration *td); - void rvalue(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct NewExp : Expression -{ - /* thisexp.new(newargs) newtype(arguments) - */ - Expression *thisexp; // if !NULL, 'this' for class being allocated - Expressions *newargs; // Array of Expression's to call new operator - Type *newtype; - Expressions *arguments; // Array of Expression's - - CtorDeclaration *member; // constructor function - NewDeclaration *allocator; // allocator function - int onstack; // allocate on stack - - NewExp(Loc loc, Expression *thisexp, Expressions *newargs, - Type *newtype, Expressions *arguments); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - elem *toElem(IRState *irs); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - - //int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); -}; - -struct NewAnonClassExp : Expression -{ - /* thisexp.new(newargs) class baseclasses { } (arguments) - */ - Expression *thisexp; // if !NULL, 'this' for class being allocated - Expressions *newargs; // Array of Expression's to call new operator - ClassDeclaration *cd; // class being instantiated - Expressions *arguments; // Array of Expression's to call class constructor - - NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs, - ClassDeclaration *cd, Expressions *arguments); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -// Offset from symbol - -struct SymOffExp : Expression -{ - Declaration *var; - unsigned offset; - - SymOffExp(Loc loc, Declaration *var, unsigned offset); - Expression *semantic(Scope *sc); - void checkEscape(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isConst(); - int isBool(int result); - Expression *doInline(InlineDoState *ids); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - void scanForNestedRef(Scope *sc); - - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -}; - -// 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); - void dump(int indent); - char *toChars(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void checkEscape(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); - void scanForNestedRef(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - // LLVMDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -// Function/Delegate literal - -struct FuncExp : Expression -{ - FuncLiteralDeclaration *fd; - - FuncExp(Loc loc, FuncLiteralDeclaration *fd); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void scanForNestedRef(Scope *sc); - char *toChars(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); - - int inlineCost(InlineCostState *ics); - //Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); -}; - -// Declaration of a symbol - -struct DeclarationExp : Expression -{ - Dsymbol *declaration; - - DeclarationExp(Loc loc, Dsymbol *declaration); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); - void scanForNestedRef(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); -}; - -struct TypeidExp : Expression -{ - Type *typeidType; - - TypeidExp(Loc loc, Type *typeidType); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct HaltExp : Expression -{ - HaltExp(Loc loc); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int checkSideEffect(int flag); - - elem *toElem(IRState *irs); -}; - -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(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - void dump(int indent); - void scanForNestedRef(Scope *sc); - Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - Expression *op_overload(Scope *sc); // doesn't need to be virtual -}; - -struct BinExp : Expression -{ - Expression *e1; - Expression *e2; - - BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *semanticp(Scope *sc); - Expression *commonSemanticAssign(Scope *sc); - Expression *commonSemanticAssignIntegral(Scope *sc); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *scaleFactor(Scope *sc); - Expression *typeCombine(Scope *sc); - Expression *optimize(int result); - int isunsigned(); - void incompatibleTypes(); - void dump(int indent); - void scanForNestedRef(Scope *sc); - Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *)); - Expression *interpretCommon2(InterState *istate, Expression *(*fp)(TOK, Type *, Expression *, Expression *)); - Expression *interpretAssignCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - Expression *op_overload(Scope *sc); - - elem *toElemBin(IRState *irs, int op); -}; - -struct BinAssignExp : BinExp -{ - BinAssignExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); - int checkSideEffect(int flag); -}; - -/****************************************************************/ - -struct CompileExp : UnaExp -{ - CompileExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct FileExp : UnaExp -{ - FileExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct AssertExp : UnaExp -{ - Expression *msg; - - AssertExp(Loc loc, Expression *e, Expression *msg = NULL); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - elem *toElem(IRState *irs); -}; - -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); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); - elem *toElem(IRState *irs); -}; - -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; - - DelegateExp(Loc loc, Expression *e, FuncDeclaration *func); - Expression *semantic(Scope *sc); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); - - int inlineCost(InlineCostState *ics); - elem *toElem(IRState *irs); -}; - -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); - elem *toElem(IRState *irs); -}; - -struct CallExp : UnaExp -{ - Expressions *arguments; // function arguments - - CallExp(Loc loc, Expression *e, Expressions *exps); - CallExp(Loc loc, Expression *e); - CallExp(Loc loc, Expression *e, Expression *earg1); - CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2); - - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); - elem *toElem(IRState *irs); - void scanForNestedRef(Scope *sc); - Expression *toLvalue(Scope *sc, Expression *e); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); -}; - -struct AddrExp : UnaExp -{ - AddrExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - elem *toElem(IRState *irs); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *optimize(int result); -}; - -struct PtrExp : UnaExp -{ - PtrExp(Loc loc, Expression *e); - PtrExp(Loc loc, Expression *e, Type *t); - Expression *semantic(Scope *sc); - Expression *toLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); - Expression *optimize(int result); - Expression *interpret(InterState *istate); -}; - -struct NegExp : UnaExp -{ - NegExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - - elem *toElem(IRState *irs); -}; - -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); - - // For operator overloading - Identifier *opId(); - - elem *toElem(IRState *irs); -}; - -struct NotExp : UnaExp -{ - NotExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isBit(); - elem *toElem(IRState *irs); -}; - -struct BoolExp : UnaExp -{ - BoolExp(Loc loc, Expression *e, Type *type); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isBit(); - elem *toElem(IRState *irs); -}; - -struct DeleteExp : UnaExp -{ - DeleteExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); -}; - -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); - int checkSideEffect(int flag); - void checkEscape(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); - - // For operator overloading - Identifier *opId(); -}; - - -struct SliceExp : UnaExp -{ - Expression *upr; // NULL if implicit 0 - Expression *lwr; // NULL if implicit [length - 1] - VarDeclaration *lengthVar; - - SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void checkEscape(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void dump(int indent); - elem *toElem(IRState *irs); - void scanForNestedRef(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); -}; - -struct ArrayLengthExp : UnaExp -{ - ArrayLengthExp(Loc loc, Expression *e1); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); -}; - -// e1[a0,a1,a2,a3,...] - -struct ArrayExp : UnaExp -{ - Expressions *arguments; // Array of Expression's - - ArrayExp(Loc loc, Expression *e1, Expressions *arguments); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *toLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - - // For operator overloading - Identifier *opId(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); -}; - -/****************************************************************/ - -struct DotExp : BinExp -{ - DotExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); -}; - -struct CommaExp : BinExp -{ - CommaExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - void checkEscape(); - 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); - elem *toElem(IRState *irs); -}; - -struct IndexExp : BinExp -{ - VarDeclaration *lengthVar; - int modifiable; - - IndexExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - Expression *doInline(InlineDoState *ids); - void scanForNestedRef(Scope *sc); - - elem *toElem(IRState *irs); -}; - -/* For both i++ and i-- - */ -struct PostExp : BinExp -{ - PostExp(enum TOK op, Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Identifier *opId(); // For operator overloading - elem *toElem(IRState *irs); -}; - -struct AssignExp : BinExp -{ int ismemset; // !=0 if setting the contents of an array - - AssignExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - Expression *interpret(InterState *istate); - Identifier *opId(); // For operator overloading - elem *toElem(IRState *irs); -}; - -#define ASSIGNEXP(op) \ -struct op##AssignExp : BinExp \ -{ \ - op##AssignExp(Loc loc, Expression *e1, Expression *e2); \ - Expression *semantic(Scope *sc); \ - Expression *interpret(InterState *istate); \ - \ - Identifier *opId(); /* For operator overloading */ \ - \ - elem *toElem(IRState *irs); \ -}; - -ASSIGNEXP(Add) -ASSIGNEXP(Min) -ASSIGNEXP(Cat) -ASSIGNEXP(Mul) -ASSIGNEXP(Div) -ASSIGNEXP(Mod) -ASSIGNEXP(Shl) -ASSIGNEXP(Shr) -ASSIGNEXP(Ushr) -ASSIGNEXP(And) -ASSIGNEXP(Or) -ASSIGNEXP(Xor) - -#undef ASSIGNEXP - -struct AddExp : BinExp -{ - AddExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); - - // LLVMDC - bool llvmFieldIndex; -}; - -struct MinExp : BinExp -{ - MinExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct CatExp : BinExp -{ - CatExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct MulExp : BinExp -{ - MulExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct DivExp : BinExp -{ - DivExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct ModExp : BinExp -{ - ModExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct ShlExp : BinExp -{ - ShlExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct ShrExp : BinExp -{ - ShrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct UshrExp : BinExp -{ - UshrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct AndExp : BinExp -{ - AndExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct OrExp : BinExp -{ - OrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct XorExp : BinExp -{ - XorExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct OrOrExp : BinExp -{ - OrOrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - elem *toElem(IRState *irs); -}; - -struct AndAndExp : BinExp -{ - AndAndExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - elem *toElem(IRState *irs); -}; - -struct CmpExp : BinExp -{ - CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isBit(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - - elem *toElem(IRState *irs); -}; - -struct InExp : BinExp -{ - InExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - int isBit(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct RemoveExp : BinExp -{ - RemoveExp(Loc loc, Expression *e1, Expression *e2); - elem *toElem(IRState *irs); -}; - -// == and != - -struct EqualExp : BinExp -{ - EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isBit(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - - elem *toElem(IRState *irs); -}; - -// === 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); - elem *toElem(IRState *irs); -}; - -/****************************************************************/ - -struct CondExp : BinExp -{ - Expression *econd; - - CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void checkEscape(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - Expression *checkToBoolean(); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - void scanForNestedRef(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - elem *toElem(IRState *irs); -}; - - -/****************************************************************/ - -/* Special values used by the interpreter - */ -#define EXP_CANT_INTERPRET ((Expression *)1) -#define EXP_CONTINUE_INTERPRET ((Expression *)2) -#define EXP_BREAK_INTERPRET ((Expression *)3) -#define EXP_GOTO_INTERPRET ((Expression *)4) -#define EXP_VOID_INTERPRET ((Expression *)5) - -Expression *expType(Type *type, Expression *e); - -Expression *Neg(Type *type, Expression *e1); -Expression *Com(Type *type, Expression *e1); -Expression *Not(Type *type, Expression *e1); -Expression *Bool(Type *type, Expression *e1); -Expression *Cast(Type *type, Type *to, Expression *e1); -Expression *ArrayLength(Type *type, Expression *e1); -Expression *Ptr(Type *type, Expression *e1); - -Expression *Add(Type *type, Expression *e1, Expression *e2); -Expression *Min(Type *type, Expression *e1, Expression *e2); -Expression *Mul(Type *type, Expression *e1, Expression *e2); -Expression *Div(Type *type, Expression *e1, Expression *e2); -Expression *Mod(Type *type, Expression *e1, Expression *e2); -Expression *Shl(Type *type, Expression *e1, Expression *e2); -Expression *Shr(Type *type, Expression *e1, Expression *e2); -Expression *Ushr(Type *type, Expression *e1, Expression *e2); -Expression *And(Type *type, Expression *e1, Expression *e2); -Expression *Or(Type *type, Expression *e1, Expression *e2); -Expression *Xor(Type *type, Expression *e1, Expression *e2); -Expression *Index(Type *type, Expression *e1, Expression *e2); -Expression *Cat(Type *type, Expression *e1, Expression *e2); - -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2); - -Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr); - -#endif /* DMD_EXPRESSION_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-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_EXPRESSION_H +#define DMD_EXPRESSION_H + +#include "mars.h" +#include "identifier.h" +#include "lexer.h" +#include "arraytypes.h" + +struct Type; +struct Scope; +struct TupleDeclaration; +struct VarDeclaration; +struct FuncDeclaration; +struct FuncLiteralDeclaration; +struct Declaration; +struct CtorDeclaration; +struct NewDeclaration; +struct Dsymbol; +struct Import; +struct Module; +struct ScopeDsymbol; +struct InlineCostState; +struct InlineDoState; +struct InlineScanState; +struct Expression; +struct Declaration; +struct AggregateDeclaration; +struct StructDeclaration; +struct TemplateInstance; +struct TemplateDeclaration; +struct ClassDeclaration; +struct HdrGenState; +struct BinExp; +struct InterState; +struct Symbol; // back end symbol + +namespace llvm +{ + class Constant; + class ConstantInt; +} + +enum TOK; + +// Back end +struct IRState; +struct dt_t; + +#if IN_LLVM +struct DValue; +typedef DValue elem; +#else +#ifdef IN_GCC +union tree_node; typedef union tree_node elem; +#else +struct elem; +#endif +#endif + +void initPrecedence(); + +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, Arguments *arguments, Expression *aggr); +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); + +struct Expression : Object +{ + Loc loc; // file location + enum TOK op; // handy to minimize use of dynamic_cast + Type *type; // !=NULL means that semantic() has been run + int size; // # of bytes in Expression so we can copy() it + + Expression(Loc loc, enum TOK op, int size); + Expression *copy(); + virtual Expression *syntaxCopy(); + virtual Expression *semantic(Scope *sc); + + int dyncast() { return DYNCAST_EXPRESSION; } // kludge for template.isExpression() + + void print(); + char *toChars(); + virtual void dump(int indent); + void error(const char *format, ...); + virtual void rvalue(); + + static Expression *combine(Expression *e1, Expression *e2); + static Expressions *arraySyntaxCopy(Expressions *exps); + + virtual integer_t toInteger(); + virtual uinteger_t toUInteger(); + virtual real_t toReal(); + virtual real_t toImaginary(); + virtual complex_t toComplex(); + virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual void toMangleBuffer(OutBuffer *buf); + virtual Expression *toLvalue(Scope *sc, Expression *e); + virtual Expression *modifiableLvalue(Scope *sc, Expression *e); + Expression *implicitCastTo(Scope *sc, Type *t); + virtual MATCH implicitConvTo(Type *t); + virtual Expression *castTo(Scope *sc, Type *t); + virtual void checkEscape(); + 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 void scanForNestedRef(Scope *sc); + + virtual Expression *optimize(int result); + #define WANTflags 1 + #define WANTvalue 2 + #define WANTinterpret 4 + + virtual Expression *interpret(InterState *istate); + + virtual int isConst(); + virtual int isBool(int result); + virtual int isBit(); + virtual int checkSideEffect(int flag); + + virtual int inlineCost(InlineCostState *ics); + virtual Expression *doInline(InlineDoState *ids); + virtual Expression *inlineScan(InlineScanState *iss); + + // For operator overloading + virtual int isCommutative(); + virtual Identifier *opId(); + virtual Identifier *opId_r(); + + // Back end + virtual elem *toElem(IRState *irs); + virtual dt_t **toDt(dt_t **pdt); + // LLVMDC + virtual llvm::Constant *toConstElem(IRState *irs); +}; + +struct IntegerExp : Expression +{ + integer_t value; + + IntegerExp(Loc loc, integer_t value, Type *type); + IntegerExp(integer_t value); + int equals(Object *o); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + char *toChars(); + void dump(int indent); + integer_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); + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); + // LLVMDC + virtual llvm::Constant *toConstElem(IRState *irs); +}; + +struct RealExp : Expression +{ + real_t value; + + RealExp(Loc loc, real_t value, Type *type); + int equals(Object *o); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + char *toChars(); + integer_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); + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); + // LLVMDC + virtual llvm::Constant *toConstElem(IRState *irs); +}; + +struct ComplexExp : Expression +{ + complex_t value; + + ComplexExp(Loc loc, complex_t value, Type *type); + int equals(Object *o); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + char *toChars(); + integer_t toInteger(); + uinteger_t toUInteger(); + real_t toReal(); + real_t toImaginary(); + complex_t toComplex(); + Expression *castTo(Scope *sc, Type *t); + int isConst(); + int isBool(int result); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); +#ifdef _DH + OutBuffer hexp; +#endif + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); + // LLVMDC + virtual llvm::Constant *toConstElem(IRState *irs); +}; + +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); + Expression *toLvalue(Scope *sc, Expression *e); +}; + +struct DollarExp : IdentifierExp +{ + DollarExp(Loc loc); +}; + +struct DsymbolExp : Expression +{ + Dsymbol *s; + + DsymbolExp(Loc loc, Dsymbol *s); + Expression *semantic(Scope *sc); + char *toChars(); + void dump(int indent); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *toLvalue(Scope *sc, Expression *e); +}; + +struct ThisExp : Expression +{ + Declaration *var; + + ThisExp(Loc loc); + Expression *semantic(Scope *sc); + int isBool(int result); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *toLvalue(Scope *sc, Expression *e); + void scanForNestedRef(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); + + elem *toElem(IRState *irs); +}; + +struct SuperExp : ThisExp +{ + SuperExp(Loc loc); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); +}; + +struct NullExp : Expression +{ + unsigned char committed; // !=0 if type is committed + + NullExp(Loc loc); + Expression *semantic(Scope *sc); + int isBool(int result); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + Expression *interpret(InterState *istate); + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); + // LLVMDC + virtual llvm::Constant *toConstElem(IRState *irs); +}; + +struct StringExp : Expression +{ + void *string; // char, wchar, or dchar data + size_t len; // number of chars, wchars, or dchars + unsigned char sz; // 1: char, 2: wchar, 4: dchar + unsigned char committed; // !=0 if type is committed + unsigned char postfix; // 'c', 'w', 'd' + + StringExp(Loc loc, char *s); + StringExp(Loc loc, void *s, size_t len); + StringExp(Loc loc, void *s, size_t len, unsigned char postfix); + //Expression *syntaxCopy(); + int equals(Object *o); + char *toChars(); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + StringExp *toUTF8(Scope *sc); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + int compare(Object *obj); + int isBool(int result); + unsigned charAt(size_t i); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); + // LLVMDC + virtual llvm::Constant *toConstElem(IRState *irs); +}; + +// Tuple + +struct TupleExp : Expression +{ + Expressions *exps; + + TupleExp(Loc loc, Expressions *exps); + TupleExp(Loc loc, TupleDeclaration *tup); + Expression *syntaxCopy(); + int equals(Object *o); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + void checkEscape(); + int checkSideEffect(int flag); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + Expression *castTo(Scope *sc, Type *t); + elem *toElem(IRState *irs); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); +}; + +struct ArrayLiteralExp : Expression +{ + Expressions *elements; + + ArrayLiteralExp(Loc loc, Expressions *elements); + ArrayLiteralExp(Loc loc, Expression *e); + + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + int isBool(int result); + elem *toElem(IRState *irs); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + void scanForNestedRef(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + dt_t **toDt(dt_t **pdt); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + // LLVMDC + virtual llvm::Constant *toConstElem(IRState *irs); +}; + +struct AssocArrayLiteralExp : Expression +{ + Expressions *keys; + Expressions *values; + + AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values); + + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + int isBool(int result); + elem *toElem(IRState *irs); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + void scanForNestedRef(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + // LLVMDC + virtual llvm::Constant *toConstElem(IRState *irs); +}; + +struct StructLiteralExp : Expression +{ + StructDeclaration *sd; // which aggregate this is for + Expressions *elements; // parallels sd->fields[] with + // NULL entries for fields to skip + + Symbol *sym; // back end symbol to initialize with literal + size_t soffset; // offset from start of s + int fillHoles; // fill alignment 'holes' with zero + + StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements); + + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *getField(Type *type, unsigned offset); + int getFieldIndex(Type *type, unsigned offset); + elem *toElem(IRState *irs); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + void scanForNestedRef(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + dt_t **toDt(dt_t **pdt); + Expression *toLvalue(Scope *sc, Expression *e); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + // LLVMDC + virtual llvm::Constant *toConstElem(IRState *irs); +}; + +struct TypeDotIdExp : Expression +{ + Identifier *ident; + + TypeDotIdExp(Loc loc, Type *type, Identifier *ident); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + elem *toElem(IRState *irs); +}; + +struct TypeExp : Expression +{ + TypeExp(Loc loc, Type *type); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *optimize(int result); + elem *toElem(IRState *irs); +}; + +struct ScopeExp : Expression +{ + ScopeDsymbol *sds; + + ScopeExp(Loc loc, ScopeDsymbol *sds); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + elem *toElem(IRState *irs); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct TemplateExp : Expression +{ + TemplateDeclaration *td; + + TemplateExp(Loc loc, TemplateDeclaration *td); + void rvalue(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct NewExp : Expression +{ + /* thisexp.new(newargs) newtype(arguments) + */ + Expression *thisexp; // if !NULL, 'this' for class being allocated + Expressions *newargs; // Array of Expression's to call new operator + Type *newtype; + Expressions *arguments; // Array of Expression's + + CtorDeclaration *member; // constructor function + NewDeclaration *allocator; // allocator function + int onstack; // allocate on stack + + NewExp(Loc loc, Expression *thisexp, Expressions *newargs, + Type *newtype, Expressions *arguments); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + elem *toElem(IRState *irs); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + + //int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); +}; + +struct NewAnonClassExp : Expression +{ + /* thisexp.new(newargs) class baseclasses { } (arguments) + */ + Expression *thisexp; // if !NULL, 'this' for class being allocated + Expressions *newargs; // Array of Expression's to call new operator + ClassDeclaration *cd; // class being instantiated + Expressions *arguments; // Array of Expression's to call class constructor + + NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs, + ClassDeclaration *cd, Expressions *arguments); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +// Offset from symbol + +struct SymOffExp : Expression +{ + Declaration *var; + unsigned offset; + + SymOffExp(Loc loc, Declaration *var, unsigned offset); + Expression *semantic(Scope *sc); + void checkEscape(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isConst(); + int isBool(int result); + Expression *doInline(InlineDoState *ids); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + void scanForNestedRef(Scope *sc); + + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +}; + +// 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); + void dump(int indent); + char *toChars(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void checkEscape(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); + void scanForNestedRef(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); + // LLVMDC + virtual llvm::Constant *toConstElem(IRState *irs); +}; + +// Function/Delegate literal + +struct FuncExp : Expression +{ + FuncLiteralDeclaration *fd; + + FuncExp(Loc loc, FuncLiteralDeclaration *fd); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void scanForNestedRef(Scope *sc); + char *toChars(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + elem *toElem(IRState *irs); + + int inlineCost(InlineCostState *ics); + //Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); +}; + +// Declaration of a symbol + +struct DeclarationExp : Expression +{ + Dsymbol *declaration; + + DeclarationExp(Loc loc, Dsymbol *declaration); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + elem *toElem(IRState *irs); + void scanForNestedRef(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); +}; + +struct TypeidExp : Expression +{ + Type *typeidType; + + TypeidExp(Loc loc, Type *typeidType); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct HaltExp : Expression +{ + HaltExp(Loc loc); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int checkSideEffect(int flag); + + elem *toElem(IRState *irs); +}; + +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(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *optimize(int result); + void dump(int indent); + void scanForNestedRef(Scope *sc); + Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + + Expression *op_overload(Scope *sc); // doesn't need to be virtual +}; + +struct BinExp : Expression +{ + Expression *e1; + Expression *e2; + + BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *semanticp(Scope *sc); + Expression *commonSemanticAssign(Scope *sc); + Expression *commonSemanticAssignIntegral(Scope *sc); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *scaleFactor(Scope *sc); + Expression *typeCombine(Scope *sc); + Expression *optimize(int result); + int isunsigned(); + void incompatibleTypes(); + void dump(int indent); + void scanForNestedRef(Scope *sc); + Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *)); + Expression *interpretCommon2(InterState *istate, Expression *(*fp)(TOK, Type *, Expression *, Expression *)); + Expression *interpretAssignCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + + Expression *op_overload(Scope *sc); + + elem *toElemBin(IRState *irs, int op); +}; + +struct BinAssignExp : BinExp +{ + BinAssignExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); + int checkSideEffect(int flag); +}; + +/****************************************************************/ + +struct CompileExp : UnaExp +{ + CompileExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct FileExp : UnaExp +{ + FileExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct AssertExp : UnaExp +{ + Expression *msg; + + AssertExp(Loc loc, Expression *e, Expression *msg = NULL); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + + elem *toElem(IRState *irs); +}; + +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); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int indent); + elem *toElem(IRState *irs); +}; + +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; + + DelegateExp(Loc loc, Expression *e, FuncDeclaration *func); + Expression *semantic(Scope *sc); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int indent); + + int inlineCost(InlineCostState *ics); + elem *toElem(IRState *irs); +}; + +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); + elem *toElem(IRState *irs); +}; + +struct CallExp : UnaExp +{ + Expressions *arguments; // function arguments + + CallExp(Loc loc, Expression *e, Expressions *exps); + CallExp(Loc loc, Expression *e); + CallExp(Loc loc, Expression *e, Expression *earg1); + CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2); + + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int indent); + elem *toElem(IRState *irs); + void scanForNestedRef(Scope *sc); + Expression *toLvalue(Scope *sc, Expression *e); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); +}; + +struct AddrExp : UnaExp +{ + AddrExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + elem *toElem(IRState *irs); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + Expression *optimize(int result); +}; + +struct PtrExp : UnaExp +{ + PtrExp(Loc loc, Expression *e); + PtrExp(Loc loc, Expression *e, Type *t); + Expression *semantic(Scope *sc); + Expression *toLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + elem *toElem(IRState *irs); + Expression *optimize(int result); + Expression *interpret(InterState *istate); +}; + +struct NegExp : UnaExp +{ + NegExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + + elem *toElem(IRState *irs); +}; + +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); + + // For operator overloading + Identifier *opId(); + + elem *toElem(IRState *irs); +}; + +struct NotExp : UnaExp +{ + NotExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isBit(); + elem *toElem(IRState *irs); +}; + +struct BoolExp : UnaExp +{ + BoolExp(Loc loc, Expression *e, Type *type); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isBit(); + elem *toElem(IRState *irs); +}; + +struct DeleteExp : UnaExp +{ + DeleteExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *checkToBoolean(); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + elem *toElem(IRState *irs); +}; + +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); + int checkSideEffect(int flag); + void checkEscape(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + elem *toElem(IRState *irs); + + // For operator overloading + Identifier *opId(); +}; + + +struct SliceExp : UnaExp +{ + Expression *upr; // NULL if implicit 0 + Expression *lwr; // NULL if implicit [length - 1] + VarDeclaration *lengthVar; + + SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void checkEscape(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void dump(int indent); + elem *toElem(IRState *irs); + void scanForNestedRef(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); +}; + +struct ArrayLengthExp : UnaExp +{ + ArrayLengthExp(Loc loc, Expression *e1); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + elem *toElem(IRState *irs); +}; + +// e1[a0,a1,a2,a3,...] + +struct ArrayExp : UnaExp +{ + Expressions *arguments; // Array of Expression's + + ArrayExp(Loc loc, Expression *e1, Expressions *arguments); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *toLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + + // For operator overloading + Identifier *opId(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); +}; + +/****************************************************************/ + +struct DotExp : BinExp +{ + DotExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); +}; + +struct CommaExp : BinExp +{ + CommaExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + void checkEscape(); + 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); + elem *toElem(IRState *irs); +}; + +struct IndexExp : BinExp +{ + VarDeclaration *lengthVar; + int modifiable; + + IndexExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + Expression *doInline(InlineDoState *ids); + void scanForNestedRef(Scope *sc); + + elem *toElem(IRState *irs); +}; + +/* For both i++ and i-- + */ +struct PostExp : BinExp +{ + PostExp(enum TOK op, Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Identifier *opId(); // For operator overloading + elem *toElem(IRState *irs); +}; + +struct AssignExp : BinExp +{ int ismemset; // !=0 if setting the contents of an array + + AssignExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *checkToBoolean(); + Expression *interpret(InterState *istate); + Identifier *opId(); // For operator overloading + elem *toElem(IRState *irs); +}; + +#define ASSIGNEXP(op) \ +struct op##AssignExp : BinExp \ +{ \ + op##AssignExp(Loc loc, Expression *e1, Expression *e2); \ + Expression *semantic(Scope *sc); \ + Expression *interpret(InterState *istate); \ + \ + Identifier *opId(); /* For operator overloading */ \ + \ + elem *toElem(IRState *irs); \ +}; + +ASSIGNEXP(Add) +ASSIGNEXP(Min) +ASSIGNEXP(Cat) +ASSIGNEXP(Mul) +ASSIGNEXP(Div) +ASSIGNEXP(Mod) +ASSIGNEXP(Shl) +ASSIGNEXP(Shr) +ASSIGNEXP(Ushr) +ASSIGNEXP(And) +ASSIGNEXP(Or) +ASSIGNEXP(Xor) + +#undef ASSIGNEXP + +struct AddExp : BinExp +{ + AddExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); + + // LLVMDC + bool llvmFieldIndex; +}; + +struct MinExp : BinExp +{ + MinExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); +}; + +struct CatExp : BinExp +{ + CatExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); +}; + +struct MulExp : BinExp +{ + MulExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); +}; + +struct DivExp : BinExp +{ + DivExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); +}; + +struct ModExp : BinExp +{ + ModExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); +}; + +struct ShlExp : BinExp +{ + ShlExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); +}; + +struct ShrExp : BinExp +{ + ShrExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); +}; + +struct UshrExp : BinExp +{ + UshrExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); +}; + +struct AndExp : BinExp +{ + AndExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); +}; + +struct OrExp : BinExp +{ + OrExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); +}; + +struct XorExp : BinExp +{ + XorExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); +}; + +struct OrOrExp : BinExp +{ + OrOrExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *checkToBoolean(); + int isBit(); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + elem *toElem(IRState *irs); +}; + +struct AndAndExp : BinExp +{ + AndAndExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *checkToBoolean(); + int isBit(); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + elem *toElem(IRState *irs); +}; + +struct CmpExp : BinExp +{ + CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isBit(); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + + elem *toElem(IRState *irs); +}; + +struct InExp : BinExp +{ + InExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + int isBit(); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + + elem *toElem(IRState *irs); +}; + +struct RemoveExp : BinExp +{ + RemoveExp(Loc loc, Expression *e1, Expression *e2); + elem *toElem(IRState *irs); +}; + +// == and != + +struct EqualExp : BinExp +{ + EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isBit(); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + + elem *toElem(IRState *irs); +}; + +// === 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); + elem *toElem(IRState *irs); +}; + +/****************************************************************/ + +struct CondExp : BinExp +{ + Expression *econd; + + CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void checkEscape(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + Expression *checkToBoolean(); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + void scanForNestedRef(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + + elem *toElem(IRState *irs); +}; + + +/****************************************************************/ + +/* Special values used by the interpreter + */ +#define EXP_CANT_INTERPRET ((Expression *)1) +#define EXP_CONTINUE_INTERPRET ((Expression *)2) +#define EXP_BREAK_INTERPRET ((Expression *)3) +#define EXP_GOTO_INTERPRET ((Expression *)4) +#define EXP_VOID_INTERPRET ((Expression *)5) + +Expression *expType(Type *type, Expression *e); + +Expression *Neg(Type *type, Expression *e1); +Expression *Com(Type *type, Expression *e1); +Expression *Not(Type *type, Expression *e1); +Expression *Bool(Type *type, Expression *e1); +Expression *Cast(Type *type, Type *to, Expression *e1); +Expression *ArrayLength(Type *type, Expression *e1); +Expression *Ptr(Type *type, Expression *e1); + +Expression *Add(Type *type, Expression *e1, Expression *e2); +Expression *Min(Type *type, Expression *e1, Expression *e2); +Expression *Mul(Type *type, Expression *e1, Expression *e2); +Expression *Div(Type *type, Expression *e1, Expression *e2); +Expression *Mod(Type *type, Expression *e1, Expression *e2); +Expression *Shl(Type *type, Expression *e1, Expression *e2); +Expression *Shr(Type *type, Expression *e1, Expression *e2); +Expression *Ushr(Type *type, Expression *e1, Expression *e2); +Expression *And(Type *type, Expression *e1, Expression *e2); +Expression *Or(Type *type, Expression *e1, Expression *e2); +Expression *Xor(Type *type, Expression *e1, Expression *e2); +Expression *Index(Type *type, Expression *e1, Expression *e2); +Expression *Cat(Type *type, Expression *e1, Expression *e2); + +Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2); +Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2); +Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2); + +Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr); + +#endif /* DMD_EXPRESSION_H */ diff --git a/dmd/func.c b/dmd/func.c index 91bd5bbc..be2561a2 100644 --- a/dmd/func.c +++ b/dmd/func.c @@ -1,2680 +1,2830 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "expression.h" -#include "scope.h" -#include "mtype.h" -#include "aggregate.h" -#include "identifier.h" -#include "id.h" -#include "module.h" -#include "statement.h" -#include "template.h" -#include "hdrgen.h" - -#ifdef IN_GCC -#include "d-dmd-gcc.h" -#endif - -/********************************* FuncDeclaration ****************************/ - -FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type) - : Declaration(id) -{ - this->storage_class = storage_class; - this->type = type; - this->loc = loc; - this->endloc = endloc; - fthrows = NULL; - frequire = NULL; - outId = NULL; - vresult = NULL; - returnLabel = NULL; - fensure = NULL; - fbody = NULL; - localsymtab = NULL; - vthis = NULL; - v_arguments = NULL; -#if IN_GCC - v_argptr = NULL; -#endif - parameters = NULL; - labtab = NULL; - overnext = NULL; - vtblIndex = -1; - hasReturnExp = 0; - naked = 0; - inlineStatus = ILSuninitialized; - inlineNest = 0; - inlineAsm = 0; - cantInterpret = 0; - semanticRun = 0; - nestedFrameRef = 0; - fes = NULL; - introducing = 0; - tintro = NULL; - inferRetType = (type && type->nextOf() == NULL); - scope = NULL; - hasReturnExp = 0; - nrvo_can = 1; - nrvo_var = NULL; - shidden = NULL; - // llvmdc - runTimeHack = false; -} - -Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) -{ - FuncDeclaration *f; - - //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncDeclaration *)s; - else - f = new FuncDeclaration(loc, endloc, ident, (enum STC) storage_class, type->syntaxCopy()); - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - return f; -} - - -// Do the semantic analysis on the external interface to the function. - -void FuncDeclaration::semantic(Scope *sc) -{ TypeFunction *f; - StructDeclaration *sd; - ClassDeclaration *cd; - InterfaceDeclaration *id; - -#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\n", sc->parent->toChars()); - printf("type: %s\n", type->toChars()); -#endif - - if (type->nextOf()) - 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 = Argument::dim(f->parameters); - - linkage = sc->linkage; -// if (!parent) - { - //parent = sc->scopesym; - parent = sc->parent; - } - protection = sc->protection; - storage_class |= sc->stc; - //printf("function storage_class = x%x\n", storage_class); - Dsymbol *parent = toParent(); - - if (isConst() || isAuto() || isScope()) - error("functions cannot be const or auto"); - - if (isAbstract() && !isVirtual()) - error("non-virtual functions cannot be abstract"); - - if (isAbstract() && isFinal()) - error("cannot be both final and abstract"); -#if 0 - if (isAbstract() && fbody) - error("abstract functions cannot have bodies"); -#endif - -#if 0 - if (isStaticConstructor() || isStaticDestructor()) - { - if (!isStatic() || type->nextOf()->ty != Tvoid) - error("static constructors / destructors must be static void"); - if (f->arguments && f->arguments->dim) - error("static constructors / destructors must have empty parameter list"); - // BUG: check for invalid storage classes - } -#endif - -#ifdef IN_GCC - AggregateDeclaration *ad; - - ad = parent->isAggregateDeclaration(); - if (ad) - ad->methods.push(this); -#endif - sd = parent->isStructDeclaration(); - if (sd) - { - // 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() || - isDtorDeclaration() || - isInvariantDeclaration() || - isUnitTestDeclaration() || isNewDeclaration() || isDelete()) - error("special function not allowed in interface %s", id->toChars()); - if (fbody) - error("function body is not abstract in interface %s", id->toChars()); - } - - cd = parent->isClassDeclaration(); - if (cd) - { int vi; - CtorDeclaration *ctor; - DtorDeclaration *dtor; - InvariantDeclaration *inv; - - if (isCtorDeclaration()) - { -// ctor = (CtorDeclaration *)this; -// if (!cd->ctor) -// cd->ctor = ctor; - return; - } - -#if 0 - dtor = isDtorDeclaration(); - if (dtor) - { - if (cd->dtor) - error("multiple destructors for class %s", cd->toChars()); - cd->dtor = dtor; - } - - inv = isInvariantDeclaration(); - if (inv) - { - cd->inv = inv; - } - - if (isNewDeclaration()) - { - if (!cd->aggNew) - cd->aggNew = (NewDeclaration *)(this); - } - - if (isDelete()) - { - if (cd->aggDelete) - error("multiple delete's for class %s", cd->toChars()); - cd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - - if (storage_class & STCabstract) - cd->isabstract = 1; - - // if static function, do not put in vtbl[] - if (!isVirtual()) - { - //printf("\tnot virtual\n"); - goto Ldone; - } - - // Find index of existing function in vtbl[] to override - if (cd->baseClass) - { - for (vi = 0; vi < cd->baseClass->vtbl.dim; vi++) - { - FuncDeclaration *fdv = ((Dsymbol *)cd->vtbl.data[vi])->isFuncDeclaration(); - - // BUG: should give error if argument types match, - // but return type does not? - - //printf("\tvtbl[%d] = '%s'\n", vi, fdv ? fdv->ident->toChars() : ""); - if (fdv && fdv->ident == ident) - { - int cov = type->covariant(fdv->type); - //printf("\tbaseclass cov = %d\n", cov); - if (cov == 2) - { - //type->print(); - //fdv->type->print(); - //printf("%s %s\n", type->deco, fdv->type->deco); - error("of type %s overrides but is not covariant with %s of type %s", - type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); - } - if (cov == 1) - { - if (fdv->isFinal()) - error("cannot override final function %s", fdv->toPrettyChars()); - if (fdv->toParent() == parent) - { - // If both are mixins, then error. - // If either is not, the one that is not overrides - // the other. - if (fdv->parent->isClassDeclaration()) - goto L1; - if (!this->parent->isClassDeclaration() -#if !BREAKABI - && !isDtorDeclaration() -#endif - ) - error("multiple overrides of same function"); - } - cd->vtbl.data[vi] = (void *)this; - vtblIndex = vi; - - /* This works by whenever this function is called, - * it actually returns tintro, which gets dynamically - * cast to type. But we know that tintro is a base - * of type, so we could optimize it by not doing a - * dynamic cast, but just subtracting the isBaseOf() - * offset if the value is != null. - */ - - if (fdv->tintro) - tintro = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) - { - tintro = fdv->type; - } - } - goto L1; - } - if (cov == 3) - { - cd->sizeok = 2; // can't finish due to forward reference - return; - } - } - } - } - - // This is an 'introducing' function. - - // 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); - if (f && f->isFinal() && f->prot() != PROTprivate) - error("cannot override final function %s", f->toPrettyChars()); - } - } - - if (isFinal()) - { - 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; - } - - L1: ; - - /* 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]; - for (vi = 0; vi < b->base->vtbl.dim; vi++) - { - Dsymbol *s = (Dsymbol *)b->base->vtbl.data[vi]; - //printf("interface %d vtbl[%d] %p %s\n", i, vi, s, s->toChars()); - FuncDeclaration *fdv = s->isFuncDeclaration(); - if (fdv && fdv->ident == ident) - { - int cov = type->covariant(fdv->type); - //printf("\tcov = %d\n", cov); - if (cov == 2) - { - //type->print(); - //fdv->type->print(); - //printf("%s %s\n", type->deco, fdv->type->deco); - error("of type %s overrides but is not covariant with %s of type %s", - type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); - } - if (cov == 1) - { Type *ti = NULL; - - if (fdv->tintro) - ti = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) - { - ti = fdv->type; -#if 0 - if (offset) - ti = fdv->type; - else if (type->nextOf()->ty == Tclass) - { ClassDeclaration *cdn = ((TypeClass *)type->nextOf())->sym; - if (cdn && cdn->sizeok != 1) - ti = fdv->type; - } -#endif - } - } - if (ti) - { - if (tintro && !tintro->equals(ti)) - { - error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); - } - tintro = ti; - } - goto L2; - } - if (cov == 3) - { - cd->sizeok = 2; // can't finish due to forward reference - return; - } - } - } - } - - if (introducing && isOverride()) - { - error("function %s does not override any", toChars()); - } - - L2: ; - } - else if (isOverride() && !parent->isTemplateInstance()) - error("override only applies to class member functions"); - - /* Do not allow template instances to add virtual functions - * to a class. - */ - if (isVirtual()) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - ClassDeclaration *cd = ti->tempdecl->isClassMember(); - if (cd) - { - error("cannot use template to add virtual function to class '%s'", cd->toChars()); - } - } - } - - if (isMain()) - { - // Check parameters to see if they are either () or (char[][] args) - switch (nparams) - { - case 0: - break; - - case 1: - { - Argument *arg0 = Argument::getNth(f->parameters, 0); - if (arg0->type->ty != Tarray || - arg0->type->nextOf()->ty != Tarray || - arg0->type->nextOf()->nextOf()->ty != Tchar || - arg0->storageClass & (STCout | STCref | STClazy)) - goto Lmainerr; - break; - } - - default: - goto Lmainerr; - } - - if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) - error("must return int or void, not %s", f->nextOf()->toChars()); - if (f->varargs) - { - Lmainerr: - error("parameters must be main() or main(char[][] args)"); - } - } - - if (ident == Id::assign && (sd || cd)) - { // Disallow identity assignment operator. - - // opAssign(...) - if (nparams == 0) - { if (f->varargs == 1) - goto Lassignerr; - } - else - { - Argument *arg0 = Argument::getNth(f->parameters, 0); - Type *t0 = arg0->type->toBasetype(); - Type *tb = sd ? sd->type : cd->type; - if (arg0->type->implicitConvTo(tb) || - (sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb)) - ) - { - if (nparams == 1) - goto Lassignerr; - Argument *arg1 = Argument::getNth(f->parameters, 1); - if (arg1->defaultArg) - goto Lassignerr; - } - } - } - -Ldone: - /* Save scope for possible later use (if we need the - * function internals) - */ - scope = new Scope(*sc); - scope->setNoFree(); - return; - -Lassignerr: - 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; - AggregateDeclaration *ad; - VarDeclaration *argptr = NULL; - VarDeclaration *_arguments = NULL; - - if (!parent) - { - if (global.errors) - return; - printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); - assert(0); - } - //printf("FuncDeclaration::semantic3('%s.%s', sc = %p)\n", parent->toChars(), toChars(), sc); - //fflush(stdout); - //{ static int x; if (++x == 2) *(char*)0=0; } - //printf("\tlinkage = %d\n", sc->linkage); - - //printf(" sc->incontract = %d\n", sc->incontract); - if (semanticRun) - return; - semanticRun = 1; - - if (!type || type->ty != Tfunction) - return; - f = (TypeFunction *)(type); - size_t nparams = Argument::dim(f->parameters); - - // Check the 'throws' clause - if (fthrows) - { int i; - - for (i = 0; i < fthrows->dim; i++) - { - Type *t = (Type *)fthrows->data[i]; - - t = t->semantic(loc, sc); - if (!t->isClassHandle()) - error("can only throw classes, not %s", t->toChars()); - } - } - - if (fbody || frequire) - { - // Establish function scope - ScopeDsymbol *ss; - Scope *sc2; - - localsymtab = new DsymbolTable(); - - ss = new ScopeDsymbol(); - ss->parent = sc->scopesym; - 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); - sc2->protection = PROTpublic; - sc2->explicitProtection = 0; - sc2->structalign = 8; - sc2->incontract = 0; - sc2->tf = NULL; - sc2->noctor = 0; - - // Declare 'this' - ad = isThis(); - if (ad) - { VarDeclaration *v; - - if (isFuncLiteralDeclaration() && isNested()) - { - error("literals cannot be class members"); - return; - } - else - { - assert(!isNested()); // can't be both member and nested - assert(ad->handle); - v = new ThisDeclaration(ad->handle); - v->storage_class |= STCparameter | STCin; - v->semantic(sc2); - if (!sc2->insert(v)) - assert(0); - v->parent = this; - vthis = v; - } - } - else if (isNested()) - { - VarDeclaration *v; - - v = new ThisDeclaration(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) - { Type *t; - - if (f->linkage == LINKd) - { // Declare _arguments[] -#if BREAKABI - v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); - v_arguments->storage_class = STCparameter | 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; -#else - t = Type::typeinfo->type->arrayOf(); - v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - v_arguments->storage_class = STCparameter | STCin; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; -#endif - } - if (f->linkage == LINKd || (parameters && parameters->dim)) - { // Declare _argptr -#if IN_GCC - t = d_gcc_builtin_va_list_d_type; -#else - t = Type::tvoid->pointerTo(); -#endif - argptr = new VarDeclaration(0, t, Id::_argptr, NULL); - argptr->semantic(sc2); - sc2->insert(argptr); - argptr->parent = this; - } - } - - // Propagate storage class from tuple arguments to their sub-arguments. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Argument *arg = (Argument *)f->parameters->data[i]; - - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Argument::dim(t->arguments); - for (size_t j = 0; j < dim; j++) - { Argument *narg = Argument::getNth(t->arguments, j); - narg->storageClass = arg->storageClass; - } - } - } - } - - // Declare all the function parameters as variables - if (nparams) - { // parameters[] has all the tuples removed, as the back end - // doesn't know about tuples - parameters = new Dsymbols(); - parameters->reserve(nparams); - for (size_t i = 0; i < nparams; i++) - { - Argument *arg = Argument::getNth(f->parameters, i); - Identifier *id = arg->ident; - if (!id) - { - //error("no identifier for parameter %d of %s", i + 1, toChars()); - OutBuffer buf; - buf.printf("_param_%zu", i); - char *name = (char *)buf.extractData(); - id = new Identifier(name, TOKidentifier); - arg->ident = id; - } - VarDeclaration *v = new VarDeclaration(0, arg->type, 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; - // for llvm d - arg->vardecl = v; - } - } - - // Declare the tuple symbols and put them in the symbol table, - // but not in parameters[]. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Argument *arg = (Argument *)f->parameters->data[i]; - - if (!arg->ident) - continue; // never used, so ignore - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Argument::dim(t->arguments); - Objects *exps = new Objects(); - exps->setDim(dim); - for (size_t j = 0; j < dim; j++) - { Argument *narg = Argument::getNth(t->arguments, j); - assert(narg->ident); - VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); - assert(v); - Expression *e = new VarExp(0, v); - exps->data[j] = (void *)e; - } - assert(arg->ident); - TupleDeclaration *v = new TupleDeclaration(0, 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; - } - } - } - - sc2->incontract++; - - if (frequire) - { - // BUG: need to error if accessing out parameters - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - // BUG: verify that all in and ref parameters are read - frequire = frequire->semantic(sc2); - labtab = NULL; // so body can't refer to labels - } - - if (fensure || addPostInvariant()) - { - ScopeDsymbol *sym; - - sym = new ScopeDsymbol(); - sym->parent = sc2->scopesym; - sc2 = sc2->push(sym); - - assert(type->nextOf()); - if (type->nextOf()->ty == Tvoid) - { - if (outId) - error("void functions have no result"); - } - else - { - if (!outId) - outId = Id::result; // provide a default - } - - if (outId) - { // Declare result variable - VarDeclaration *v; - Loc loc = this->loc; - - if (fensure) - loc = fensure->loc; - - v = new VarDeclaration(loc, type->nextOf(), outId, NULL); - v->noauto = 1; - sc2->incontract--; - v->semantic(sc2); - sc2->incontract++; - if (!sc2->insert(v)) - error("out result %s is already defined", v->toChars()); - v->parent = this; - vresult = v; - - // vresult gets initialized with the function return value - // in ReturnStatement::semantic() - } - - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - if (fensure) - { fensure = fensure->semantic(sc2); - labtab = NULL; // so body can't refer to labels - } - - if (!global.params.useOut) - { fensure = NULL; // discard - vresult = NULL; - } - - // Postcondition invariant - if (addPostInvariant()) - { - Expression *e = NULL; - if (isCtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - ThisExp *v = new ThisExp(0); - v->type = vthis->type; - e = new AssertExp(0, v); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - if (fensure) - fensure = new CompoundStatement(0, s, fensure); - else - fensure = s; - } - } - - if (fensure) - { returnLabel = new LabelDsymbol(Id::returnLabel); - LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure); - ls->isReturnLabel = 1; - returnLabel->statement = ls; - } - sc2 = sc2->pop(); - } - - sc2->incontract--; - - if (fbody) - { ClassDeclaration *cd = isClassMember(); - - if (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()) - { - type->next = Type::tvoid; - type = type->semantic(loc, sc); - } - f = (TypeFunction *)type; - } - - int offend = fbody ? fbody->fallOffEnd() : 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 (int i = 0; i < ad->members->dim; i++) - { Dsymbol *s = (Dsymbol *)ad->members->data[i]; - - s->checkCtorConstInit(); - } - } - } - - if (isCtorDeclaration() && cd) - { - //printf("callSuper = x%x\n", sc2->callSuper); - - // Verify that all the ctorinit fields got initialized - if (!(sc2->callSuper & CSXthis_ctor)) - { - for (int i = 0; i < cd->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - - if (v->ctorinit == 0 && v->isCtorinit()) - error("missing initializer for 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); - - unsigned errors = global.errors; - global.gag++; - e = e->semantic(sc2); - global.gag--; - if (errors != global.errors) - error("no match for implicit super() call in constructor"); - - 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 (type->nextOf()->ty == Tvoid) - { - if (offend && isMain()) - { // Add a return 0; statement - Statement *s = new ReturnStatement(0, new IntegerExp(0)); - fbody = new CompoundStatement(0, fbody, s); - } - } - else - { - if (offend) - { Expression *e; - - if (global.params.warnings) - { fprintf(stdmsg, "warning - "); - error("no return at end of function"); - } - - 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, "missing return expression") - ); - } - else - e = new HaltExp(endloc); - e = new CommaExp(0, e, type->nextOf()->defaultInit()); - e = e->semantic(sc2); - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - } - } - } - } - - { - Statements *a = new Statements(); - - // Merge in initialization of 'out' parameters - if (parameters) - { for (size_t i = 0; i < parameters->dim; i++) - { VarDeclaration *v; - - v = (VarDeclaration *)parameters->data[i]; - if (v->storage_class & STCout) - { - assert(v->init); - ExpInitializer *ie = v->init->isExpInitializer(); - assert(ie); - a->push(new ExpStatement(0, ie->exp)); - } - } - } - -// we'll handle variadics ourselves -#if !IN_LLVM - if (argptr) - { // Initialize _argptr to point past non-variadic arg -#if IN_GCC - // Handled in FuncDeclaration::toObjFile - v_argptr = argptr; - v_argptr->init = new VoidInitializer(loc); -#else - Expression *e1; - Expression *e; - Type *t = argptr->type; - VarDeclaration *p; - unsigned offset; - - e1 = new VarExp(0, argptr); - if (parameters && parameters->dim) - p = (VarDeclaration *)parameters->data[parameters->dim - 1]; - else - p = v_arguments; // last parameter is _arguments[] - offset = p->type->size(); - offset = (offset + 3) & ~3; // assume stack aligns on 4 - e = new SymOffExp(0, p, offset); - e = new AssignExp(0, e1, e); - e->type = t; - a->push(new ExpStatement(0, e)); -#endif // IN_GCC - } - - if (_arguments) - { - /* Advance to elements[] member of TypeInfo_Tuple with: - * _arguments = v_arguments.elements; - */ - Expression *e = new VarExp(0, v_arguments); - e = new DotIdExp(0, e, Id::elements); - Expression *e1 = new VarExp(0, _arguments); - e = new AssignExp(0, e1, e); - e = e->semantic(sc); - a->push(new ExpStatement(0, e)); - } - -#endif // !IN_LLVM - - // Merge contracts together with body into one compound statement - -#ifdef _DH - if (frequire && global.params.useIn) - { frequire->incontract = 1; - a->push(frequire); - } -#else - if (frequire && global.params.useIn) - a->push(frequire); -#endif - - // Precondition invariant - if (addPreInvariant()) - { - Expression *e = NULL; - if (isDtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - ThisExp *v = new ThisExp(0); - v->type = vthis->type; - Expression *se = new StringExp(0, "null this"); - se = se->semantic(sc); - se->type = Type::tchar->arrayOf(); - e = new AssertExp(loc, v, se); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - a->push(s); - } - } - - if (fbody) - a->push(fbody); - - if (fensure) - { - a->push(returnLabel->statement); - - if (type->nextOf()->ty != Tvoid) - { - // Create: return vresult; - assert(vresult); - Expression *e = new VarExp(0, vresult); - if (tintro) - { e = e->implicitCastTo(sc, tintro->nextOf()); - e = e->semantic(sc); - } - ReturnStatement *s = new ReturnStatement(0, e); - a->push(s); - } - } - - fbody = new CompoundStatement(0, a); - } - - sc2->callSuper = 0; - sc2->pop(); - } - semanticRun = 2; -} - -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)) - ) - { buf->writenl(); - - // in{} - if (frequire) - { buf->writestring("in"); - buf->writenl(); - frequire->toCBuffer(buf, hgs); - } - - // out{} - if (fensure) - { buf->writestring("out"); - if (outId) - { buf->writebyte('('); - buf->writestring(outId->toChars()); - buf->writebyte(')'); - } - buf->writenl(); - fensure->toCBuffer(buf, hgs); - } - - if (frequire || fensure) - { buf->writestring("body"); - buf->writenl(); - } - - buf->writebyte('{'); - buf->writenl(); - fbody->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); - } - else - { buf->writeByte(';'); - buf->writenl(); - } -} - -/**************************************************** - * Determine if 'this' overrides fd. - * Return !=0 if it does. - */ - -int FuncDeclaration::overrides(FuncDeclaration *fd) -{ int result = 0; - - if (fd->ident == ident) - { - int cov = type->covariant(fd->type); - if (cov) - { ClassDeclaration *cd1 = toParent()->isClassDeclaration(); - ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration(); - - if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL)) - result = 1; - } - } - return result; -} - -/**************************************************** - * 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(FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param) -{ - FuncDeclaration *f; - Declaration *d; - Declaration *next; - - for (d = fstart; d; d = next) - { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); - - if (fa) - { - if (overloadApply(fa->funcalias, fp, param)) - return 1; - next = fa->overnext; - } - else - { - AliasDeclaration *a = d->isAliasDeclaration(); - - if (a) - { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - if (next == fstart) - break; - } - else - { - f = d->isFuncDeclaration(); - if (!f) - { d->error("is aliased to a function"); - break; // BUG: should print error message? - } - if ((*fp)(param, f)) - return 1; - - next = f->overnext; - } - } - } - return 0; -} - -/******************************************** - * 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 V2 - /* 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) -{ - Param1 p; - p.t = t; - p.f = NULL; - overloadApply(this, &fp1, &p); - return p.f; -} - -#if 0 -FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t) -{ - FuncDeclaration *f; - Declaration *d; - Declaration *next; - - for (d = this; d; d = next) - { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); - - if (fa) - { - FuncDeclaration *f2 = fa->funcalias->overloadExactMatch(t); - if (f2) - return f2; - next = fa->overnext; - } - else - { - AliasDeclaration *a = d->isAliasDeclaration(); - - if (a) - { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - } - else - { - f = d->isFuncDeclaration(); - if (!f) - break; // BUG: should print error message? - if (t->equals(d->type)) - return f; - next = f->overnext; - } - } - } - return NULL; -} -#endif - -/******************************************** - * Decide which function matches the arguments best. - */ - -struct Param2 -{ - Match *m; - 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 - { - TypeFunction *tf; - - m->anyf = f; - tf = (TypeFunction *)f->type; - match = (MATCH) tf->callMatch(arguments); - //printf("match = %d\n", match); - if (match != MATCHnomatch) - { - if (match > m->last) - goto LfIsBetter; - - if (match < m->last) - goto LlastIsBetter; - - /* See if one of the matches overrides the other. - */ - if (m->lastf->overrides(f)) - goto LlastIsBetter; - else if (f->overrides(m->lastf)) - goto LfIsBetter; - - 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, Expressions *arguments) -{ - Param2 p; - p.m = m; - p.arguments = arguments; - overloadApply(fstart, &fp2, &p); -} - -#if 0 -// Recursive helper function - -void overloadResolveX(Match *m, FuncDeclaration *fstart, Expressions *arguments) -{ - MATCH match; - Declaration *d; - Declaration *next; - - for (d = fstart; d; d = next) - { - FuncDeclaration *f; - FuncAliasDeclaration *fa; - AliasDeclaration *a; - - fa = d->isFuncAliasDeclaration(); - if (fa) - { - overloadResolveX(m, fa->funcalias, arguments); - next = fa->overnext; - } - else if ((f = d->isFuncDeclaration()) != NULL) - { - next = f->overnext; - if (f == m->lastf) - continue; // skip duplicates - else - { - TypeFunction *tf; - - m->anyf = f; - tf = (TypeFunction *)f->type; - match = (MATCH) tf->callMatch(arguments); - //printf("match = %d\n", match); - if (match != MATCHnomatch) - { - if (match > m->last) - goto LfIsBetter; - - if (match < m->last) - goto LlastIsBetter; - - /* See if one of the matches overrides the other. - */ - if (m->lastf->overrides(f)) - goto LlastIsBetter; - else if (f->overrides(m->lastf)) - goto LfIsBetter; - - Lambiguous: - m->nextf = f; - m->count++; - continue; - - LfIsBetter: - m->last = match; - m->lastf = f; - m->count = 1; - continue; - - LlastIsBetter: - continue; - } - } - } - 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 - -FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expressions *arguments) -{ - 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, arguments); - - 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)", - Argument::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(), Argument::argsTypesToChars(t1->parameters, t1->varargs), - m.nextf->toPrettyChars(), Argument::argsTypesToChars(t2->parameters, t2->varargs)); -#else - error(loc, "overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); -#endif - return m.lastf; - } - } -} - -/******************************** - * 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; -} - -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) -{ CompoundStatement *cs; - - if (!fbody) - { Statements *a; - - a = new Statements(); - fbody = new CompoundStatement(0, a); - } - cs = fbody->isCompoundStatement(); - cs->statements->push(s); -} - - -int FuncDeclaration::isMain() -{ - return ident == Id::main && - linkage != LINKc && !isMember() && !isNested(); -} - -int FuncDeclaration::isWinMain() -{ - return ident == Id::WinMain && - linkage != LINKc && !isMember(); -} - -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("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); - printf("result is %d\n", - isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration()); -#endif - return isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration(); -} - -int FuncDeclaration::isAbstract() -{ - return storage_class & STCabstract; -} - -int FuncDeclaration::isCodeseg() -{ - return TRUE; // functions are always in the code segment -} - -// 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("\ttoParent() = '%s'\n", toParent()->toChars()); - return ((storage_class & STCstatic) == 0) && - (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. - */ - -FuncDeclaration *FuncDeclaration::genCfunc(Type *treturn, char *name) -{ - return genCfunc(treturn, Lexer::idPool(name)); -} - -FuncDeclaration *FuncDeclaration::genCfunc(Type *treturn, Identifier *id) -{ - FuncDeclaration *fd; - TypeFunction *tf; - Dsymbol *s; - static DsymbolTable *st = NULL; - - //printf("genCfunc(name = '%s')\n", id->toChars()); - //printf("treturn\n\t"); treturn->print(); - - // See if already in table - if (!st) - st = new DsymbolTable(); - s = st->lookup(id); - if (s) - { - fd = s->isFuncDeclaration(); - assert(fd); - assert(fd->type->nextOf()->equals(treturn)); - } - else - { - tf = new TypeFunction(NULL, treturn, 0, LINKc); - fd = new FuncDeclaration(0, 0, id, STCstatic, tf); - fd->protection = PROTpublic; - fd->linkage = LINKc; - - st->insert(fd); - } - return fd; -} - -char *FuncDeclaration::kind() -{ - return "function"; -} - -/****************************** 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; -} - -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) -{ - char *id; - - if (fes) - id = "__foreachbody"; - else if (tok == TOKdelegate) - id = "__dgliteral"; - else - id = "__funcliteral"; - this->ident = Identifier::generateId(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); - FuncDeclaration::syntaxCopy(f); - return f; -} - -int FuncLiteralDeclaration::isNested() -{ - //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); - return (tok == TOKdelegate); -} - -char *FuncLiteralDeclaration::kind() -{ - // GCC requires the (char*) casts - return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; -} - -void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - static Identifier *idfunc; - static Identifier *iddel; - - if (!idfunc) - idfunc = new Identifier("function", 0); - if (!iddel) - iddel = new Identifier("delegate", 0); - - type->toCBuffer(buf, ((tok == TOKdelegate) ? iddel : idfunc), hgs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* CtorDeclaration ****************************/ - -CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::ctor, STCundefined, NULL) -{ - this->arguments = arguments; - this->varargs = varargs; - //printf("CtorDeclaration() %s\n", toChars()); -} - -Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) -{ - CtorDeclaration *f; - - f = new CtorDeclaration(loc, endloc, NULL, varargs); - - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - - f->arguments = Argument::arraySyntaxCopy(arguments); - return f; -} - - -void CtorDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - Type *tret; - - //printf("CtorDeclaration::semantic()\n"); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static constructor - - parent = sc->parent; - Dsymbol *parent = toParent(); - cd = parent->isClassDeclaration(); - if (!cd) - { - error("constructors only are for class definitions"); - tret = Type::tvoid; - } - else - tret = cd->type; //->referenceTo(); - type = new TypeFunction(arguments, tret, varargs, LINKd); - - sc->flags |= SCOPEctor; - type = type->semantic(loc, sc); - sc->flags &= ~SCOPEctor; - - // Append: - // return this; - // to the function body - if (fbody) - { Expression *e; - Statement *s; - - e = new ThisExp(0); - s = new ReturnStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - } - - FuncDeclaration::semantic(sc); - - sc->pop(); - - // See if it's the default constructor - if (cd && varargs == 0 && Argument::dim(arguments) == 0) - cd->defaultCtor = this; -} - -char *CtorDeclaration::kind() -{ - return "constructor"; -} - -char *CtorDeclaration::toChars() -{ - return "this"; -} - -int CtorDeclaration::isVirtual() -{ - return FALSE; -} - -int CtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int CtorDeclaration::addPostInvariant() -{ - return (vthis && global.params.useInvariants); -} - - -void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this"); - Argument::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - -/********************************* DtorDeclaration ****************************/ - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) -{ -} - -Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s) -{ - DtorDeclaration *dd; - - assert(!s); - dd = new DtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(dd); -} - - -void DtorDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - - parent = sc->parent; - Dsymbol *parent = toParent(); - cd = parent->isClassDeclaration(); - if (!cd) - { - error("destructors only are for class definitions"); - } - else - cd->dtors.push(this); - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static destructor - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int DtorDeclaration::overloadInsert(Dsymbol *s) -{ - return FALSE; // cannot overload destructors -} - -int DtorDeclaration::addPreInvariant() -{ - return (vthis && global.params.useInvariants); -} - -int DtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -int DtorDeclaration::isVirtual() -{ - /* This should be FALSE so that dtor's don't get put into the vtbl[], - * but doing so will require recompiling everything. - */ -#if BREAKABI - return FALSE; -#else - return FuncDeclaration::isVirtual(); -#endif -} - -void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticCtorDeclaration ****************************/ - -StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticCtor"), STCstatic, NULL) -{ -} - -Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticCtorDeclaration *scd; - - assert(!s); - scd = new StaticCtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(scd); -} - - -void StaticCtorDeclaration::semantic(Scope *sc) -{ - //printf("StaticCtorDeclaration::semantic()\n"); - - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - FuncDeclaration::semantic(sc); - - // We're going to need ModuleInfo - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { m->needmoduleinfo = 1; -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif - } -} - -AggregateDeclaration *StaticCtorDeclaration::isThis() -{ - return NULL; -} - -int StaticCtorDeclaration::isStaticConstructor() -{ - return TRUE; -} - -int StaticCtorDeclaration::isVirtual() -{ - return FALSE; -} - -int StaticCtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int StaticCtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - { buf->writestring("static this();\n"); - return; - } - buf->writestring("static this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticDtorDeclaration ****************************/ - -StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticDtor"), STCstatic, NULL) -{ -} - -Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticDtorDeclaration *sdd; - - assert(!s); - sdd = new StaticDtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(sdd); -} - - -void StaticDtorDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - Type *tret; - - cd = sc->scopesym->isClassDeclaration(); - if (!cd) - { - } - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - FuncDeclaration::semantic(sc); - - // We're going to need ModuleInfo - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { m->needmoduleinfo = 1; -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif - } -} - -AggregateDeclaration *StaticDtorDeclaration::isThis() -{ - return NULL; -} - -int StaticDtorDeclaration::isStaticDestructor() -{ - return TRUE; -} - -int StaticDtorDeclaration::isVirtual() -{ - return FALSE; -} - -int StaticDtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int StaticDtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("static ~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* InvariantDeclaration ****************************/ - -InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL) -{ -} - -Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) -{ - InvariantDeclaration *id; - - assert(!s); - id = new InvariantDeclaration(loc, endloc); - FuncDeclaration::syntaxCopy(id); - return id; -} - - -void InvariantDeclaration::semantic(Scope *sc) -{ - AggregateDeclaration *ad; - Type *tret; - - parent = sc->parent; - Dsymbol *parent = toParent(); - ad = parent->isAggregateDeclaration(); - if (!ad) - { - error("invariants only are for struct/union/class definitions"); - return; - } - else if (ad->inv && ad->inv != this) - { - error("more than one invariant for %s", ad->toChars()); - } - ad->inv = this; - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static invariant - sc->incontract++; - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int InvariantDeclaration::isVirtual() -{ - return FALSE; -} - -int InvariantDeclaration::addPreInvariant() -{ - return FALSE; -} - -int InvariantDeclaration::addPostInvariant() -{ - return FALSE; -} - -void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("invariant"); - bodyToCBuffer(buf, hgs); -} - - -/********************************* UnitTestDeclaration ****************************/ - -/******************************* - * Generate unique unittest function Id so we can have multiple - * instances per module. - */ - -static Identifier *unitTestId() -{ - static int n; - char buffer[10 + sizeof(n)*3 + 1]; - - sprintf(buffer,"__unittest%d", n); - n++; - return Lexer::idPool(buffer); -} - -UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL) -{ -} - -Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) -{ - UnitTestDeclaration *utd; - - assert(!s); - utd = new UnitTestDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(utd); -} - - -void UnitTestDeclaration::semantic(Scope *sc) -{ - if (global.params.useUnitTests) - { - Type *tret; - - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - FuncDeclaration::semantic(sc); - } - - // We're going to need ModuleInfo even if the unit tests are not - // compiled in, because other modules may import this module and refer - // to this ModuleInfo. - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - m->needmoduleinfo = 1; -} - -AggregateDeclaration *UnitTestDeclaration::isThis() -{ - return NULL; -} - -int UnitTestDeclaration::isVirtual() -{ - return FALSE; -} - -int UnitTestDeclaration::addPreInvariant() -{ - return FALSE; -} - -int UnitTestDeclaration::addPostInvariant() -{ - return FALSE; -} - -void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("unittest"); - bodyToCBuffer(buf, hgs); -} - -/********************************* NewDeclaration ****************************/ - -NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) -{ - this->arguments = arguments; - this->varargs = varargs; -} - -Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) -{ - NewDeclaration *f; - - f = new NewDeclaration(loc, endloc, NULL, varargs); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Argument::arraySyntaxCopy(arguments); - - return f; -} - - -void NewDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - Type *tret; - - //printf("NewDeclaration::semantic()\n"); - - parent = sc->parent; - Dsymbol *parent = toParent(); - cd = parent->isClassDeclaration(); - if (!cd && !parent->isStructDeclaration()) - { - error("new allocators only are for class or struct definitions"); - } - tret = Type::tvoid->pointerTo(); - type = new TypeFunction(arguments, tret, varargs, LINKd); - - type = type->semantic(loc, sc); - assert(type->ty == Tfunction); - - // Check that there is at least one argument of type uint - TypeFunction *tf = (TypeFunction *)type; - if (Argument::dim(tf->parameters) < 1) - { - error("at least one argument of type uint expected"); - } - else - { - Argument *a = Argument::getNth(tf->parameters, 0); - if (!a->type->equals(Type::tuns32)) - error("first argument must be type uint, not %s", a->type->toChars()); - } - - FuncDeclaration::semantic(sc); -} - -char *NewDeclaration::kind() -{ - return "allocator"; -} - -int NewDeclaration::isVirtual() -{ - return FALSE; -} - -int NewDeclaration::addPreInvariant() -{ - return FALSE; -} - -int NewDeclaration::addPostInvariant() -{ - return FALSE; -} - -void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("new"); - Argument::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* DeleteDeclaration ****************************/ - -DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments) - : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) -{ - this->arguments = arguments; -} - -Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) -{ - DeleteDeclaration *f; - - f = new DeleteDeclaration(loc, endloc, NULL); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Argument::arraySyntaxCopy(arguments); - - return f; -} - - -void DeleteDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - - //printf("DeleteDeclaration::semantic()\n"); - - parent = sc->parent; - Dsymbol *parent = toParent(); - cd = parent->isClassDeclaration(); - if (!cd && !parent->isStructDeclaration()) - { - error("new allocators only are for class or struct definitions"); - } - type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); - - type = type->semantic(loc, sc); - assert(type->ty == Tfunction); - - // Check that there is only one argument of type void* - TypeFunction *tf = (TypeFunction *)type; - if (Argument::dim(tf->parameters) != 1) - { - error("one argument of type void* expected"); - } - else - { - Argument *a = Argument::getNth(tf->parameters, 0); - if (!a->type->equals(Type::tvoid->pointerTo())) - error("one argument of type void* expected, not %s", a->type->toChars()); - } - - FuncDeclaration::semantic(sc); -} - -char *DeleteDeclaration::kind() -{ - return "deallocator"; -} - -int DeleteDeclaration::isDelete() -{ - return TRUE; -} - -int DeleteDeclaration::isVirtual() -{ - return FALSE; -} - -int DeleteDeclaration::addPreInvariant() -{ - return FALSE; -} - -int DeleteDeclaration::addPostInvariant() -{ - return FALSE; -} - -void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("delete"); - Argument::argsToCBuffer(buf, hgs, arguments, 0); - bodyToCBuffer(buf, hgs); -} - - - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include + +#include "mars.h" +#include "init.h" +#include "declaration.h" +#include "attrib.h" +#include "expression.h" +#include "scope.h" +#include "mtype.h" +#include "aggregate.h" +#include "identifier.h" +#include "id.h" +#include "module.h" +#include "statement.h" +#include "template.h" +#include "hdrgen.h" + +#ifdef IN_GCC +#include "d-dmd-gcc.h" +#endif + +/********************************* FuncDeclaration ****************************/ + +FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type) + : Declaration(id) +{ + //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); + this->storage_class = storage_class; + this->type = type; + this->loc = loc; + this->endloc = endloc; + fthrows = NULL; + frequire = NULL; + outId = NULL; + vresult = NULL; + returnLabel = NULL; + fensure = NULL; + fbody = NULL; + localsymtab = NULL; + vthis = NULL; + v_arguments = NULL; +#if IN_GCC + v_argptr = NULL; +#endif + parameters = NULL; + labtab = NULL; + overnext = NULL; + vtblIndex = -1; + hasReturnExp = 0; + naked = 0; + inlineStatus = ILSuninitialized; + inlineNest = 0; + inlineAsm = 0; + cantInterpret = 0; + semanticRun = 0; + nestedFrameRef = 0; + fes = NULL; + introducing = 0; + tintro = NULL; + inferRetType = (type && type->nextOf() == NULL); + scope = NULL; + hasReturnExp = 0; + nrvo_can = 1; + nrvo_var = NULL; + shidden = NULL; + // llvmdc + runTimeHack = false; +} + +Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) +{ + FuncDeclaration *f; + + //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); + if (s) + f = (FuncDeclaration *)s; + else + f = new FuncDeclaration(loc, endloc, ident, (enum STC) storage_class, type->syntaxCopy()); + f->outId = outId; + f->frequire = frequire ? frequire->syntaxCopy() : NULL; + f->fensure = fensure ? fensure->syntaxCopy() : NULL; + f->fbody = fbody ? fbody->syntaxCopy() : NULL; + assert(!fthrows); // deprecated + return f; +} + + +// Do the semantic analysis on the external interface to the function. + +void FuncDeclaration::semantic(Scope *sc) +{ TypeFunction *f; + StructDeclaration *sd; + ClassDeclaration *cd; + InterfaceDeclaration *id; + +#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\n", sc->parent->toChars()); + printf("type: %s\n", type->toChars()); +#endif + + if (type->nextOf()) + 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 = Argument::dim(f->parameters); + + linkage = sc->linkage; +// if (!parent) + { + //parent = sc->scopesym; + parent = sc->parent; + } + protection = sc->protection; + storage_class |= sc->stc; + //printf("function storage_class = x%x\n", storage_class); + Dsymbol *parent = toParent(); + + if (isConst() || isAuto() || isScope()) + error("functions cannot be const or auto"); + + if (isAbstract() && !isVirtual()) + error("non-virtual functions cannot be abstract"); + + if (isAbstract() && isFinal()) + error("cannot be both final and abstract"); +#if 0 + if (isAbstract() && fbody) + error("abstract functions cannot have bodies"); +#endif + +#if 0 + if (isStaticConstructor() || isStaticDestructor()) + { + if (!isStatic() || type->nextOf()->ty != Tvoid) + error("static constructors / destructors must be static void"); + if (f->arguments && f->arguments->dim) + error("static constructors / destructors must have empty parameter list"); + // BUG: check for invalid storage classes + } +#endif + +#ifdef IN_GCC + AggregateDeclaration *ad; + + ad = parent->isAggregateDeclaration(); + if (ad) + ad->methods.push(this); +#endif + sd = parent->isStructDeclaration(); + if (sd) + { + // 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() || + isDtorDeclaration() || + isInvariantDeclaration() || + isUnitTestDeclaration() || isNewDeclaration() || isDelete()) + error("special function not allowed in interface %s", id->toChars()); + if (fbody) + error("function body is not abstract in interface %s", id->toChars()); + } + + cd = parent->isClassDeclaration(); + if (cd) + { int vi; + CtorDeclaration *ctor; + DtorDeclaration *dtor; + InvariantDeclaration *inv; + + if (isCtorDeclaration()) + { +// ctor = (CtorDeclaration *)this; +// if (!cd->ctor) +// cd->ctor = ctor; + return; + } + +#if 0 + dtor = isDtorDeclaration(); + if (dtor) + { + if (cd->dtor) + error("multiple destructors for class %s", cd->toChars()); + cd->dtor = dtor; + } + + inv = isInvariantDeclaration(); + if (inv) + { + cd->inv = inv; + } + + if (isNewDeclaration()) + { + if (!cd->aggNew) + cd->aggNew = (NewDeclaration *)(this); + } + + if (isDelete()) + { + if (cd->aggDelete) + error("multiple delete's for class %s", cd->toChars()); + cd->aggDelete = (DeleteDeclaration *)(this); + } +#endif + + if (storage_class & STCabstract) + cd->isabstract = 1; + + // if static function, do not put in vtbl[] + if (!isVirtual()) + { + //printf("\tnot virtual\n"); + goto Ldone; + } + + // Find index of existing function in vtbl[] to override + vi = findVtblIndex(&cd->vtbl, cd->baseClass ? cd->baseClass->vtbl.dim : 0); + switch (vi) + { + case -1: // didn't find one + // This is an 'introducing' function. + + // 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); + if (f && f->isFinal() && f->prot() != PROTprivate) + error("cannot override final function %s", f->toPrettyChars()); + } + } + + if (isFinal()) + { + cd->vtblFinal.push(this); + } + else + { + // Append to end of vtbl[] + //printf("\tintroducing function\n"); + introducing = 1; + vi = cd->vtbl.dim; + cd->vtbl.push(this); + vtblIndex = vi; + } + break; + + case -2: // can't determine because of fwd refs + cd->sizeok = 2; // can't finish due to forward reference + return; + + default: + { FuncDeclaration *fdv = (FuncDeclaration *)cd->vtbl.data[vi]; + // This function is covariant with fdv + if (fdv->isFinal()) + error("cannot override final function %s", fdv->toPrettyChars()); + +#if V2 + if (!isOverride() && global.params.warnings) + error("overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); +#endif + + if (fdv->toParent() == parent) + { + // If both are mixins, then error. + // If either is not, the one that is not overrides + // the other. + if (fdv->parent->isClassDeclaration()) + break; + if (!this->parent->isClassDeclaration() +#if !BREAKABI + && !isDtorDeclaration() +#endif +#if V2 + && !isPostBlitDeclaration() +#endif + ) + error("multiple overrides of same function"); + } + cd->vtbl.data[vi] = (void *)this; + vtblIndex = vi; + + /* This works by whenever this function is called, + * it actually returns tintro, which gets dynamically + * cast to type. But we know that tintro is a base + * of type, so we could optimize it by not doing a + * dynamic cast, but just subtracting the isBaseOf() + * offset if the value is != null. + */ + + if (fdv->tintro) + tintro = fdv->tintro; + else if (!type->equals(fdv->type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) + { + tintro = fdv->type; + } + } + break; + } + } + + /* Go through all the interface bases. + * If this function is covariant with any members of those interface + * functions, set the tintro. + */ + for (int i = 0; i < cd->interfaces_dim; i++) + { +#if 1 + BaseClass *b = cd->interfaces[i]; + vi = findVtblIndex(&b->base->vtbl, b->base->vtbl.dim); + switch (vi) + { + case -1: + break; + + case -2: + cd->sizeok = 2; // can't finish due to forward reference + return; + + default: + { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.data[vi]; + Type *ti = NULL; + + if (fdv->tintro) + ti = fdv->tintro; + else if (!type->equals(fdv->type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) + { + ti = fdv->type; +#if 0 + if (offset) + ti = fdv->type; + else if (type->nextOf()->ty == Tclass) + { ClassDeclaration *cdn = ((TypeClass *)type->nextOf())->sym; + if (cdn && cdn->sizeok != 1) + ti = fdv->type; + } +#endif + } + } + if (ti) + { + if (tintro && !tintro->equals(ti)) + { + error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); + } + tintro = ti; + } + goto L2; + } + } +#else + BaseClass *b = cd->interfaces[i]; + for (vi = 0; vi < b->base->vtbl.dim; vi++) + { + Dsymbol *s = (Dsymbol *)b->base->vtbl.data[vi]; + //printf("interface %d vtbl[%d] %p %s\n", i, vi, s, s->toChars()); + FuncDeclaration *fdv = s->isFuncDeclaration(); + if (fdv && fdv->ident == ident) + { + int cov = type->covariant(fdv->type); + //printf("\tcov = %d\n", cov); + if (cov == 2) + { + //type->print(); + //fdv->type->print(); + //printf("%s %s\n", type->deco, fdv->type->deco); + error("of type %s overrides but is not covariant with %s of type %s", + type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); + } + if (cov == 1) + { Type *ti = NULL; + + if (fdv->tintro) + ti = fdv->tintro; + else if (!type->equals(fdv->type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) + { + ti = fdv->type; +#if 0 + if (offset) + ti = fdv->type; + else if (type->nextOf()->ty == Tclass) + { ClassDeclaration *cdn = ((TypeClass *)type->nextOf())->sym; + if (cdn && cdn->sizeok != 1) + ti = fdv->type; + } +#endif + } + } + if (ti) + { + if (tintro && !tintro->equals(ti)) + { + error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); + } + tintro = ti; + } + goto L2; + } + if (cov == 3) + { + cd->sizeok = 2; // can't finish due to forward reference + return; + } + } + } +#endif + } + + if (introducing && isOverride()) + { + error("does not override any function"); + } + + L2: ; + } + else if (isOverride() && !parent->isTemplateInstance()) + error("override only applies to class member functions"); + + /* Do not allow template instances to add virtual functions + * to a class. + */ + if (isVirtual()) + { + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + { + // Take care of nested templates + while (1) + { + TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); + if (!ti2) + break; + ti = ti2; + } + + // If it's a member template + ClassDeclaration *cd = ti->tempdecl->isClassMember(); + if (cd) + { + error("cannot use template to add virtual function to class '%s'", cd->toChars()); + } + } + } + + if (isMain()) + { + // Check parameters to see if they are either () or (char[][] args) + switch (nparams) + { + case 0: + break; + + case 1: + { + Argument *arg0 = Argument::getNth(f->parameters, 0); + if (arg0->type->ty != Tarray || + arg0->type->nextOf()->ty != Tarray || + arg0->type->nextOf()->nextOf()->ty != Tchar || + arg0->storageClass & (STCout | STCref | STClazy)) + goto Lmainerr; + break; + } + + default: + goto Lmainerr; + } + + if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) + error("must return int or void, not %s", f->nextOf()->toChars()); + if (f->varargs) + { + Lmainerr: + error("parameters must be main() or main(char[][] args)"); + } + } + + if (ident == Id::assign && (sd || cd)) + { // Disallow identity assignment operator. + + // opAssign(...) + if (nparams == 0) + { if (f->varargs == 1) + goto Lassignerr; + } + else + { + Argument *arg0 = Argument::getNth(f->parameters, 0); + Type *t0 = arg0->type->toBasetype(); + Type *tb = sd ? sd->type : cd->type; + if (arg0->type->implicitConvTo(tb) || + (sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb)) + ) + { + if (nparams == 1) + goto Lassignerr; + Argument *arg1 = Argument::getNth(f->parameters, 1); + if (arg1->defaultArg) + goto Lassignerr; + } + } + } + +Ldone: + /* Save scope for possible later use (if we need the + * function internals) + */ + scope = new Scope(*sc); + scope->setNoFree(); + return; + +Lassignerr: + 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; + AggregateDeclaration *ad; + VarDeclaration *argptr = NULL; + VarDeclaration *_arguments = NULL; + + if (!parent) + { + if (global.errors) + return; + //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); + assert(0); + } + //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); + //fflush(stdout); + //{ static int x; if (++x == 2) *(char*)0=0; } + //printf("\tlinkage = %d\n", sc->linkage); + + //printf(" sc->incontract = %d\n", sc->incontract); + if (semanticRun) + return; + semanticRun = 1; + + if (!type || type->ty != Tfunction) + return; + f = (TypeFunction *)(type); + size_t nparams = Argument::dim(f->parameters); + + // Check the 'throws' clause + if (fthrows) + { int i; + + for (i = 0; i < fthrows->dim; i++) + { + Type *t = (Type *)fthrows->data[i]; + + t = t->semantic(loc, sc); + if (!t->isClassHandle()) + error("can only throw classes, not %s", t->toChars()); + } + } + + if (fbody || frequire) + { + /* Symbol table into which we place parameters and nested functions, + * solely to diagnose name collisions. + */ + localsymtab = new DsymbolTable(); + + // Establish function scope + ScopeDsymbol *ss = new ScopeDsymbol(); + ss->parent = sc->scopesym; + Scope *sc2 = sc->push(ss); + sc2->func = this; + sc2->parent = this; + sc2->callSuper = 0; + sc2->sbreak = NULL; + sc2->scontinue = NULL; + sc2->sw = NULL; + sc2->fes = fes; + sc2->linkage = LINKd; + sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STCfinal); + sc2->protection = PROTpublic; + sc2->explicitProtection = 0; + sc2->structalign = 8; + sc2->incontract = 0; + sc2->tf = NULL; + sc2->noctor = 0; + + // Declare 'this' + ad = isThis(); + if (ad) + { VarDeclaration *v; + + if (isFuncLiteralDeclaration() && isNested()) + { + error("literals cannot be class members"); + return; + } + else + { + assert(!isNested()); // can't be both member and nested + assert(ad->handle); + v = new ThisDeclaration(ad->handle); + v->storage_class |= STCparameter | STCin; + v->semantic(sc2); + if (!sc2->insert(v)) + assert(0); + v->parent = this; + vthis = v; + } + } + else if (isNested()) + { + VarDeclaration *v; + + v = new ThisDeclaration(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) + { Type *t; + + if (f->linkage == LINKd) + { // Declare _arguments[] +#if BREAKABI + v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); + v_arguments->storage_class = STCparameter | 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; +#else + t = Type::typeinfo->type->arrayOf(); + v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL); + v_arguments->storage_class = STCparameter | STCin; + v_arguments->semantic(sc2); + sc2->insert(v_arguments); + v_arguments->parent = this; +#endif + } + if (f->linkage == LINKd || (parameters && parameters->dim)) + { // Declare _argptr +#if IN_GCC + t = d_gcc_builtin_va_list_d_type; +#else + t = Type::tvoid->pointerTo(); +#endif + argptr = new VarDeclaration(0, t, Id::_argptr, NULL); + argptr->semantic(sc2); + sc2->insert(argptr); + argptr->parent = this; + } + } + + // Propagate storage class from tuple parameters to their element-parameters. + if (f->parameters) + { + for (size_t i = 0; i < f->parameters->dim; i++) + { Argument *arg = (Argument *)f->parameters->data[i]; + + if (arg->type->ty == Ttuple) + { TypeTuple *t = (TypeTuple *)arg->type; + size_t dim = Argument::dim(t->arguments); + for (size_t j = 0; j < dim; j++) + { Argument *narg = Argument::getNth(t->arguments, j); + narg->storageClass = arg->storageClass; + } + } + } + } + + // Declare all the function parameters as variables + if (nparams) + { /* parameters[] has all the tuples removed, as the back end + * doesn't know about tuples + */ + parameters = new Dsymbols(); + parameters->reserve(nparams); + for (size_t i = 0; i < nparams; i++) + { + Argument *arg = Argument::getNth(f->parameters, i); + Identifier *id = arg->ident; + if (!id) + { + /* Generate identifier for un-named parameter, + * because we need it later on. + */ + OutBuffer buf; + buf.printf("_param_%zu", i); + char *name = (char *)buf.extractData(); + id = new Identifier(name, TOKidentifier); + arg->ident = id; + } + VarDeclaration *v = new VarDeclaration(loc, arg->type, 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; + // for llvm d + arg->vardecl = v; + } + } + + // Declare the tuple symbols and put them in the symbol table, + // but not in parameters[]. + if (f->parameters) + { + for (size_t i = 0; i < f->parameters->dim; i++) + { Argument *arg = (Argument *)f->parameters->data[i]; + + if (!arg->ident) + continue; // never used, so ignore + if (arg->type->ty == Ttuple) + { TypeTuple *t = (TypeTuple *)arg->type; + size_t dim = Argument::dim(t->arguments); + Objects *exps = new Objects(); + exps->setDim(dim); + for (size_t j = 0; j < dim; j++) + { Argument *narg = Argument::getNth(t->arguments, j); + assert(narg->ident); + VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); + assert(v); + Expression *e = new VarExp(0, v); + exps->data[j] = (void *)e; + } + assert(arg->ident); + TupleDeclaration *v = new TupleDeclaration(0, arg->ident, exps); + //printf("declaring tuple %s\n", v->toChars()); + v->isexp = 1; + if (!sc2->insert(v)) + error("parameter %s.%s is already defined", toChars(), v->toChars()); + localsymtab->insert(v); + v->parent = this; + } + } + } + + /* Do the semantic analysis on the [in] preconditions and + * [out] postconditions. + */ + sc2->incontract++; + + if (frequire) + { /* frequire is composed of the [in] contracts + */ + // BUG: need to error if accessing out parameters + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + // BUG: verify that all in and ref parameters are read + frequire = frequire->semantic(sc2); + labtab = NULL; // so body can't refer to labels + } + + if (fensure || addPostInvariant()) + { /* fensure is composed of the [out] contracts + */ + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc2->scopesym; + sc2 = sc2->push(sym); + + assert(type->nextOf()); + if (type->nextOf()->ty == Tvoid) + { + if (outId) + error("void functions have no result"); + } + else + { + if (!outId) + outId = Id::result; // provide a default + } + + if (outId) + { // Declare result variable + VarDeclaration *v; + Loc loc = this->loc; + + if (fensure) + loc = fensure->loc; + + v = new VarDeclaration(loc, type->nextOf(), outId, NULL); + v->noauto = 1; + sc2->incontract--; + v->semantic(sc2); + sc2->incontract++; + if (!sc2->insert(v)) + error("out result %s is already defined", v->toChars()); + v->parent = this; + vresult = v; + + // vresult gets initialized with the function return value + // in ReturnStatement::semantic() + } + + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + if (fensure) + { fensure = fensure->semantic(sc2); + labtab = NULL; // so body can't refer to labels + } + + if (!global.params.useOut) + { fensure = NULL; // discard + vresult = NULL; + } + + // Postcondition invariant + if (addPostInvariant()) + { + Expression *e = NULL; + if (isCtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); + + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + e = new DsymbolExp(0, inv); + e = new CallExp(0, e); + e = e->semantic(sc2); + } + } + else + { // Call invariant virtually + ThisExp *v = new ThisExp(0); + v->type = vthis->type; + e = new AssertExp(0, v); + } + if (e) + { + ExpStatement *s = new ExpStatement(0, e); + if (fensure) + fensure = new CompoundStatement(0, s, fensure); + else + fensure = s; + } + } + + if (fensure) + { returnLabel = new LabelDsymbol(Id::returnLabel); + LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure); + ls->isReturnLabel = 1; + returnLabel->statement = ls; + } + sc2 = sc2->pop(); + } + + sc2->incontract--; + + if (fbody) + { ClassDeclaration *cd = isClassMember(); + + /* If this is a class constructor + */ + if (isCtorDeclaration() && cd) + { + for (int i = 0; i < cd->fields.dim; i++) + { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; + + v->ctorinit = 0; + } + } + + if (inferRetType || f->retStyle() != RETstack) + nrvo_can = 0; + + fbody = fbody->semantic(sc2); + + if (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->fallOffEnd() : 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 (int i = 0; i < ad->members->dim; i++) + { Dsymbol *s = (Dsymbol *)ad->members->data[i]; + + s->checkCtorConstInit(); + } + } + } + + if (isCtorDeclaration() && cd) + { + //printf("callSuper = x%x\n", sc2->callSuper); + + // Verify that all the ctorinit fields got initialized + if (!(sc2->callSuper & CSXthis_ctor)) + { + for (int i = 0; i < cd->fields.dim; i++) + { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; + + if (v->ctorinit == 0 && v->isCtorinit()) + error("missing initializer for 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); + + unsigned errors = global.errors; + global.gag++; + e = e->semantic(sc2); + global.gag--; + if (errors != global.errors) + error("no match for implicit super() call in constructor"); + + 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 (type->nextOf()->ty == Tvoid) + { + if (offend && isMain()) + { // Add a return 0; statement + Statement *s = new ReturnStatement(0, new IntegerExp(0)); + fbody = new CompoundStatement(0, fbody, s); + } + } + else + { + if (offend) + { Expression *e; + + if (global.params.warnings) + { fprintf(stdmsg, "warning - "); + error("no return at end of function"); + } + + 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, "missing return expression") + ); + } + else + e = new HaltExp(endloc); + e = new CommaExp(0, e, type->nextOf()->defaultInit()); + e = e->semantic(sc2); + Statement *s = new ExpStatement(0, e); + fbody = new CompoundStatement(0, fbody, s); + } + } + } + } + + { + Statements *a = new Statements(); + + // Merge in initialization of 'out' parameters + if (parameters) + { for (size_t i = 0; i < parameters->dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + if (v->storage_class & STCout) + { + assert(v->init); + ExpInitializer *ie = v->init->isExpInitializer(); + assert(ie); + a->push(new ExpStatement(0, ie->exp)); + } + } + } + +// we'll handle variadics ourselves +#if !IN_LLVM + if (argptr) + { // Initialize _argptr to point past non-variadic arg +#if IN_GCC + // Handled in FuncDeclaration::toObjFile + v_argptr = argptr; + v_argptr->init = new VoidInitializer(loc); +#else + Expression *e1; + Expression *e; + Type *t = argptr->type; + VarDeclaration *p; + unsigned offset; + + e1 = new VarExp(0, argptr); + if (parameters && parameters->dim) + p = (VarDeclaration *)parameters->data[parameters->dim - 1]; + else + p = v_arguments; // last parameter is _arguments[] + offset = p->type->size(); + offset = (offset + 3) & ~3; // assume stack aligns on 4 + e = new SymOffExp(0, p, offset); + e = new AssignExp(0, e1, e); + e->type = t; + a->push(new ExpStatement(0, e)); +#endif // IN_GCC + } + + if (_arguments) + { + /* Advance to elements[] member of TypeInfo_Tuple with: + * _arguments = v_arguments.elements; + */ + Expression *e = new VarExp(0, v_arguments); + e = new DotIdExp(0, e, Id::elements); + Expression *e1 = new VarExp(0, _arguments); + e = new AssignExp(0, e1, e); + e = e->semantic(sc); + a->push(new ExpStatement(0, e)); + } + +#endif // !IN_LLVM + + // Merge contracts together with body into one compound statement + +#ifdef _DH + if (frequire && global.params.useIn) + { frequire->incontract = 1; + a->push(frequire); + } +#else + if (frequire && global.params.useIn) + a->push(frequire); +#endif + + // Precondition invariant + if (addPreInvariant()) + { + Expression *e = NULL; + if (isDtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); + + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + e = new DsymbolExp(0, inv); + e = new CallExp(0, e); + e = e->semantic(sc2); + } + } + else + { // Call invariant virtually + ThisExp *v = new ThisExp(0); + v->type = vthis->type; + Expression *se = new StringExp(0, "null this"); + se = se->semantic(sc); + se->type = Type::tchar->arrayOf(); + e = new AssertExp(loc, v, se); + } + if (e) + { + ExpStatement *s = new ExpStatement(0, e); + a->push(s); + } + } + + if (fbody) + a->push(fbody); + + if (fensure) + { + a->push(returnLabel->statement); + + if (type->nextOf()->ty != Tvoid) + { + // Create: return vresult; + assert(vresult); + Expression *e = new VarExp(0, vresult); + if (tintro) + { e = e->implicitCastTo(sc, tintro->nextOf()); + e = e->semantic(sc); + } + ReturnStatement *s = new ReturnStatement(0, e); + a->push(s); + } + } + + fbody = new CompoundStatement(0, a); + } + + sc2->callSuper = 0; + sc2->pop(); + } + semanticRun = 2; +} + +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)) + ) + { buf->writenl(); + + // in{} + if (frequire) + { buf->writestring("in"); + buf->writenl(); + frequire->toCBuffer(buf, hgs); + } + + // out{} + if (fensure) + { buf->writestring("out"); + if (outId) + { buf->writebyte('('); + buf->writestring(outId->toChars()); + buf->writebyte(')'); + } + buf->writenl(); + fensure->toCBuffer(buf, hgs); + } + + if (frequire || fensure) + { buf->writestring("body"); + buf->writenl(); + } + + buf->writebyte('{'); + buf->writenl(); + fbody->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); + } + else + { buf->writeByte(';'); + buf->writenl(); + } +} + +/**************************************************** + * Determine if 'this' overrides fd. + * Return !=0 if it does. + */ + +int FuncDeclaration::overrides(FuncDeclaration *fd) +{ int result = 0; + + if (fd->ident == ident) + { + int cov = type->covariant(fd->type); + if (cov) + { ClassDeclaration *cd1 = toParent()->isClassDeclaration(); + ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration(); + + if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL)) + result = 1; + } + } + return result; +} + +/************************************************* + * Find index of function in vtbl[0..dim] that + * this function overrides. + * Returns: + * -1 didn't find one + * -2 can't determine because of forward references + */ + +int FuncDeclaration::findVtblIndex(Array *vtbl, int dim) +{ + for (int vi = 0; vi < dim; vi++) + { + FuncDeclaration *fdv = ((Dsymbol *)vtbl->data[vi])->isFuncDeclaration(); + if (fdv && fdv->ident == ident) + { + int cov = type->covariant(fdv->type); + //printf("\tbaseclass cov = %d\n", cov); + switch (cov) + { + case 0: // types are distinct + break; + + case 1: + return vi; + + case 2: + //type->print(); + //fdv->type->print(); + //printf("%s %s\n", type->deco, fdv->type->deco); + error("of type %s overrides but is not covariant with %s of type %s", + type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); + break; + + case 3: + return -2; // forward references + + default: + assert(0); + } + } + } + return -1; +} + +/**************************************************** + * Overload this FuncDeclaration with the new one f. + * Return !=0 if successful; i.e. no conflict. + */ + +int FuncDeclaration::overloadInsert(Dsymbol *s) +{ + FuncDeclaration *f; + AliasDeclaration *a; + + //printf("FuncDeclaration::overloadInsert(%s)\n", s->toChars()); + a = s->isAliasDeclaration(); + if (a) + { + if (overnext) + return overnext->overloadInsert(a); + if (!a->aliassym && a->type->ty != Tident && a->type->ty != Tinstance) + { + //printf("\ta = '%s'\n", a->type->toChars()); + return FALSE; + } + overnext = a; + //printf("\ttrue: no conflict\n"); + return TRUE; + } + f = s->isFuncDeclaration(); + if (!f) + return FALSE; + + if (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(FuncDeclaration *fstart, + int (*fp)(void *, FuncDeclaration *), + void *param) +{ + FuncDeclaration *f; + Declaration *d; + Declaration *next; + + for (d = fstart; d; d = next) + { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); + + if (fa) + { + if (overloadApply(fa->funcalias, fp, param)) + return 1; + next = fa->overnext; + } + else + { + AliasDeclaration *a = d->isAliasDeclaration(); + + if (a) + { + Dsymbol *s = a->toAlias(); + next = s->isDeclaration(); + if (next == a) + break; + if (next == fstart) + break; + } + else + { + f = d->isFuncDeclaration(); + if (!f) + { d->error("is aliased to a function"); + break; // BUG: should print error message? + } + if ((*fp)(param, f)) + return 1; + + next = f->overnext; + } + } + } + return 0; +} + +/******************************************** + * 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 V2 + /* 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) +{ + Param1 p; + p.t = t; + p.f = NULL; + overloadApply(this, &fp1, &p); + return p.f; +} + +#if 0 +FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t) +{ + FuncDeclaration *f; + Declaration *d; + Declaration *next; + + for (d = this; d; d = next) + { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); + + if (fa) + { + FuncDeclaration *f2 = fa->funcalias->overloadExactMatch(t); + if (f2) + return f2; + next = fa->overnext; + } + else + { + AliasDeclaration *a = d->isAliasDeclaration(); + + if (a) + { + Dsymbol *s = a->toAlias(); + next = s->isDeclaration(); + if (next == a) + break; + } + else + { + f = d->isFuncDeclaration(); + if (!f) + break; // BUG: should print error message? + if (t->equals(d->type)) + return f; + next = f->overnext; + } + } + } + return NULL; +} +#endif + +/******************************************** + * Decide which function matches the arguments best. + */ + +struct Param2 +{ + Match *m; + 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 + { + TypeFunction *tf; + + m->anyf = f; + tf = (TypeFunction *)f->type; + match = (MATCH) tf->callMatch(arguments); + //printf("match = %d\n", match); + if (match != MATCHnomatch) + { + if (match > m->last) + goto LfIsBetter; + + if (match < m->last) + goto LlastIsBetter; + + /* See if one of the matches overrides the other. + */ + if (m->lastf->overrides(f)) + goto LlastIsBetter; + else if (f->overrides(m->lastf)) + goto LfIsBetter; + + 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, Expressions *arguments) +{ + Param2 p; + p.m = m; + p.arguments = arguments; + overloadApply(fstart, &fp2, &p); +} + +#if 0 +// Recursive helper function + +void overloadResolveX(Match *m, FuncDeclaration *fstart, Expressions *arguments) +{ + MATCH match; + Declaration *d; + Declaration *next; + + for (d = fstart; d; d = next) + { + FuncDeclaration *f; + FuncAliasDeclaration *fa; + AliasDeclaration *a; + + fa = d->isFuncAliasDeclaration(); + if (fa) + { + overloadResolveX(m, fa->funcalias, arguments); + next = fa->overnext; + } + else if ((f = d->isFuncDeclaration()) != NULL) + { + next = f->overnext; + if (f == m->lastf) + continue; // skip duplicates + else + { + TypeFunction *tf; + + m->anyf = f; + tf = (TypeFunction *)f->type; + match = (MATCH) tf->callMatch(arguments); + //printf("match = %d\n", match); + if (match != MATCHnomatch) + { + if (match > m->last) + goto LfIsBetter; + + if (match < m->last) + goto LlastIsBetter; + + /* See if one of the matches overrides the other. + */ + if (m->lastf->overrides(f)) + goto LlastIsBetter; + else if (f->overrides(m->lastf)) + goto LfIsBetter; + + Lambiguous: + m->nextf = f; + m->count++; + continue; + + LfIsBetter: + m->last = match; + m->lastf = f; + m->count = 1; + continue; + + LlastIsBetter: + continue; + } + } + } + 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 + +FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expressions *arguments) +{ + 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, arguments); + + 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)", + Argument::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(), Argument::argsTypesToChars(t1->parameters, t1->varargs), + m.nextf->toPrettyChars(), Argument::argsTypesToChars(t2->parameters, t2->varargs)); +#else + error(loc, "overloads %s and %s both match argument list for %s", + m.lastf->type->toChars(), + m.nextf->type->toChars(), + m.lastf->toChars()); +#endif + return m.lastf; + } + } +} + +/******************************** + * 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) +{ CompoundStatement *cs; + + if (!fbody) + { Statements *a; + + a = new Statements(); + fbody = new CompoundStatement(0, a); + } + cs = fbody->isCompoundStatement(); + cs->statements->push(s); +} + + +int FuncDeclaration::isMain() +{ + return ident == Id::main && + linkage != LINKc && !isMember() && !isNested(); +} + +int FuncDeclaration::isWinMain() +{ + return ident == Id::WinMain && + linkage != LINKc && !isMember(); +} + +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("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); + printf("result is %d\n", + isMember() && + !(isStatic() || protection == PROTprivate || protection == PROTpackage) && + toParent()->isClassDeclaration()); +#endif + return isMember() && + !(isStatic() || protection == PROTprivate || protection == PROTpackage) && + toParent()->isClassDeclaration(); +} + +int FuncDeclaration::isAbstract() +{ + return storage_class & STCabstract; +} + +int FuncDeclaration::isCodeseg() +{ + return TRUE; // functions are always in the code segment +} + +// 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("\ttoParent() = '%s'\n", toParent()->toChars()); + return ((storage_class & STCstatic) == 0) && + (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. + */ + +FuncDeclaration *FuncDeclaration::genCfunc(Type *treturn, char *name) +{ + return genCfunc(treturn, Lexer::idPool(name)); +} + +FuncDeclaration *FuncDeclaration::genCfunc(Type *treturn, Identifier *id) +{ + FuncDeclaration *fd; + TypeFunction *tf; + Dsymbol *s; + static DsymbolTable *st = NULL; + + //printf("genCfunc(name = '%s')\n", id->toChars()); + //printf("treturn\n\t"); treturn->print(); + + // See if already in table + if (!st) + st = new DsymbolTable(); + s = st->lookup(id); + if (s) + { + fd = s->isFuncDeclaration(); + assert(fd); + assert(fd->type->nextOf()->equals(treturn)); + } + else + { + tf = new TypeFunction(NULL, treturn, 0, LINKc); + fd = new FuncDeclaration(0, 0, id, STCstatic, tf); + fd->protection = PROTpublic; + fd->linkage = LINKc; + + st->insert(fd); + } + return fd; +} + +char *FuncDeclaration::kind() +{ + return "function"; +} +/******************************* + * Look at all the variables in this function that are referenced + * by nested functions, and determine if a closure needs to be + * created for them. + */ + +#if V2 +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 + * escapes. + */ + + //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, %d\n", f->toChars(), f->isVirtual(), f->tookAddressOf); + if (f->isVirtual() || f->tookAddressOf) + goto Lyes; // assume f escapes this function's scope + + // Look to see if any parents of f that are below this escape + for (Dsymbol *s = f->parent; s != this; s = s->parent) + { + f = s->isFuncDeclaration(); + if (f && (f->isVirtual() || f->tookAddressOf)) + goto Lyes; + } + } + } + return 0; + +Lyes: + //printf("\tneeds closure\n"); + return 1; +} +#endif + +/****************************** FuncAliasDeclaration ************************/ + +// Used as a way to import a set of functions from another scope into this one. + +FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) + : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, + (enum STC)funcalias->storage_class, funcalias->type) +{ + assert(funcalias != this); + this->funcalias = funcalias; +} + +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) +{ + char *id; + + if (fes) + id = "__foreachbody"; + else if (tok == TOKdelegate) + id = "__dgliteral"; + else + id = "__funcliteral"; + this->ident = Identifier::generateId(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); + FuncDeclaration::syntaxCopy(f); + return f; +} + +int FuncLiteralDeclaration::isNested() +{ + //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); + return (tok == TOKdelegate); +} + +char *FuncLiteralDeclaration::kind() +{ + // GCC requires the (char*) casts + return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; +} + +void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + static Identifier *idfunc; + static Identifier *iddel; + + if (!idfunc) + idfunc = new Identifier("function", 0); + if (!iddel) + iddel = new Identifier("delegate", 0); + + type->toCBuffer(buf, ((tok == TOKdelegate) ? iddel : idfunc), hgs); + bodyToCBuffer(buf, hgs); +} + + +/********************************* CtorDeclaration ****************************/ + +CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) + : FuncDeclaration(loc, endloc, Id::ctor, STCundefined, NULL) +{ + this->arguments = arguments; + this->varargs = varargs; + //printf("CtorDeclaration() %s\n", toChars()); +} + +Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) +{ + CtorDeclaration *f; + + f = new CtorDeclaration(loc, endloc, NULL, varargs); + + f->outId = outId; + f->frequire = frequire ? frequire->syntaxCopy() : NULL; + f->fensure = fensure ? fensure->syntaxCopy() : NULL; + f->fbody = fbody ? fbody->syntaxCopy() : NULL; + assert(!fthrows); // deprecated + + f->arguments = Argument::arraySyntaxCopy(arguments); + return f; +} + + +void CtorDeclaration::semantic(Scope *sc) +{ + ClassDeclaration *cd; + Type *tret; + + //printf("CtorDeclaration::semantic()\n"); + if (type) + return; + + sc = sc->push(); + sc->stc &= ~STCstatic; // not a static constructor + + parent = sc->parent; + Dsymbol *parent = toParent(); + cd = parent->isClassDeclaration(); + if (!cd) + { + error("constructors are only for class definitions"); + tret = Type::tvoid; + } + else + tret = cd->type; //->referenceTo(); + type = new TypeFunction(arguments, tret, varargs, LINKd); + + sc->flags |= SCOPEctor; + type = type->semantic(loc, sc); + sc->flags &= ~SCOPEctor; + + // Append: + // return this; + // to the function body + if (fbody) + { Expression *e; + Statement *s; + + e = new ThisExp(0); + s = new ReturnStatement(0, e); + fbody = new CompoundStatement(0, fbody, s); + } + + FuncDeclaration::semantic(sc); + + sc->pop(); + + // See if it's the default constructor + if (cd && varargs == 0 && Argument::dim(arguments) == 0) + cd->defaultCtor = this; +} + +char *CtorDeclaration::kind() +{ + return "constructor"; +} + +char *CtorDeclaration::toChars() +{ + return "this"; +} + +int CtorDeclaration::isVirtual() +{ + return FALSE; +} + +int CtorDeclaration::addPreInvariant() +{ + return FALSE; +} + +int CtorDeclaration::addPostInvariant() +{ + return (vthis && global.params.useInvariants); +} + + +void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("this"); + Argument::argsToCBuffer(buf, hgs, arguments, varargs); + bodyToCBuffer(buf, hgs); +} + +/********************************* 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) +{ + ClassDeclaration *cd; + + parent = sc->parent; + Dsymbol *parent = toParent(); + cd = parent->isClassDeclaration(); + if (!cd) + { + error("destructors only are for class definitions"); + } + else + cd->dtors.push(this); + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + sc = sc->push(); + sc->stc &= ~STCstatic; // not a static destructor + sc->linkage = LINKd; + + FuncDeclaration::semantic(sc); + + sc->pop(); +} + +int DtorDeclaration::overloadInsert(Dsymbol *s) +{ + return FALSE; // cannot overload destructors +} + +int DtorDeclaration::addPreInvariant() +{ + return (vthis && global.params.useInvariants); +} + +int DtorDeclaration::addPostInvariant() +{ + return FALSE; +} + +int DtorDeclaration::isVirtual() +{ + /* This should be FALSE so that dtor's don't get put into the vtbl[], + * but doing so will require recompiling everything. + */ +#if BREAKABI + return FALSE; +#else + return FuncDeclaration::isVirtual(); +#endif +} + +void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("~this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* StaticCtorDeclaration ****************************/ + +StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, + Identifier::generateId("_staticCtor"), STCstatic, NULL) +{ +} + +Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) +{ + StaticCtorDeclaration *scd; + + assert(!s); + scd = new StaticCtorDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(scd); +} + + +void StaticCtorDeclaration::semantic(Scope *sc) +{ + //printf("StaticCtorDeclaration::semantic()\n"); + + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + FuncDeclaration::semantic(sc); + + // We're going to need ModuleInfo + Module *m = getModule(); + if (!m) + m = sc->module; + if (m) + { m->needmoduleinfo = 1; +#ifdef IN_GCC + m->strictlyneedmoduleinfo = 1; +#endif + } +} + +AggregateDeclaration *StaticCtorDeclaration::isThis() +{ + return NULL; +} + +int StaticCtorDeclaration::isStaticConstructor() +{ + return TRUE; +} + +int StaticCtorDeclaration::isVirtual() +{ + return FALSE; +} + +int StaticCtorDeclaration::addPreInvariant() +{ + return FALSE; +} + +int StaticCtorDeclaration::addPostInvariant() +{ + return FALSE; +} + +void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + { buf->writestring("static this();\n"); + return; + } + buf->writestring("static this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* StaticDtorDeclaration ****************************/ + +StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, + Identifier::generateId("_staticDtor"), STCstatic, NULL) +{ +} + +Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) +{ + StaticDtorDeclaration *sdd; + + assert(!s); + sdd = new StaticDtorDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(sdd); +} + + +void StaticDtorDeclaration::semantic(Scope *sc) +{ + ClassDeclaration *cd; + Type *tret; + + cd = sc->scopesym->isClassDeclaration(); + if (!cd) + { + } + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + FuncDeclaration::semantic(sc); + + // We're going to need ModuleInfo + Module *m = getModule(); + if (!m) + m = sc->module; + if (m) + { m->needmoduleinfo = 1; +#ifdef IN_GCC + m->strictlyneedmoduleinfo = 1; +#endif + } +} + +AggregateDeclaration *StaticDtorDeclaration::isThis() +{ + return NULL; +} + +int StaticDtorDeclaration::isStaticDestructor() +{ + return TRUE; +} + +int StaticDtorDeclaration::isVirtual() +{ + return FALSE; +} + +int StaticDtorDeclaration::addPreInvariant() +{ + return FALSE; +} + +int StaticDtorDeclaration::addPostInvariant() +{ + return FALSE; +} + +void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("static ~this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* InvariantDeclaration ****************************/ + +InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL) +{ +} + +Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) +{ + InvariantDeclaration *id; + + assert(!s); + id = new InvariantDeclaration(loc, endloc); + FuncDeclaration::syntaxCopy(id); + return id; +} + + +void InvariantDeclaration::semantic(Scope *sc) +{ + AggregateDeclaration *ad; + Type *tret; + + parent = sc->parent; + Dsymbol *parent = toParent(); + ad = parent->isAggregateDeclaration(); + if (!ad) + { + error("invariants only are for struct/union/class definitions"); + return; + } + else if (ad->inv && ad->inv != this) + { + error("more than one invariant for %s", ad->toChars()); + } + ad->inv = this; + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + sc = sc->push(); + sc->stc &= ~STCstatic; // not a static invariant + sc->incontract++; + sc->linkage = LINKd; + + FuncDeclaration::semantic(sc); + + sc->pop(); +} + +int InvariantDeclaration::isVirtual() +{ + return FALSE; +} + +int InvariantDeclaration::addPreInvariant() +{ + return FALSE; +} + +int InvariantDeclaration::addPostInvariant() +{ + return FALSE; +} + +void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("invariant"); + bodyToCBuffer(buf, hgs); +} + + +/********************************* UnitTestDeclaration ****************************/ + +/******************************* + * Generate unique unittest function Id so we can have multiple + * instances per module. + */ + +static Identifier *unitTestId() +{ + static int n; + char buffer[10 + sizeof(n)*3 + 1]; + + sprintf(buffer,"__unittest%d", n); + n++; + return Lexer::idPool(buffer); +} + +UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL) +{ +} + +Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) +{ + UnitTestDeclaration *utd; + + assert(!s); + utd = new UnitTestDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(utd); +} + + +void UnitTestDeclaration::semantic(Scope *sc) +{ + if (global.params.useUnitTests) + { + Type *tret; + + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + FuncDeclaration::semantic(sc); + } + + // We're going to need ModuleInfo even if the unit tests are not + // compiled in, because other modules may import this module and refer + // to this ModuleInfo. + Module *m = getModule(); + if (!m) + m = sc->module; + if (m) + m->needmoduleinfo = 1; +} + +AggregateDeclaration *UnitTestDeclaration::isThis() +{ + return NULL; +} + +int UnitTestDeclaration::isVirtual() +{ + return FALSE; +} + +int UnitTestDeclaration::addPreInvariant() +{ + return FALSE; +} + +int UnitTestDeclaration::addPostInvariant() +{ + return FALSE; +} + +void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("unittest"); + bodyToCBuffer(buf, hgs); +} + +/********************************* NewDeclaration ****************************/ + +NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) + : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) +{ + this->arguments = arguments; + this->varargs = varargs; +} + +Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) +{ + NewDeclaration *f; + + f = new NewDeclaration(loc, endloc, NULL, varargs); + + FuncDeclaration::syntaxCopy(f); + + f->arguments = Argument::arraySyntaxCopy(arguments); + + return f; +} + + +void NewDeclaration::semantic(Scope *sc) +{ + ClassDeclaration *cd; + Type *tret; + + //printf("NewDeclaration::semantic()\n"); + + parent = sc->parent; + Dsymbol *parent = toParent(); + cd = parent->isClassDeclaration(); + if (!cd && !parent->isStructDeclaration()) + { + error("new allocators only are for class or struct definitions"); + } + tret = Type::tvoid->pointerTo(); + type = new TypeFunction(arguments, tret, varargs, LINKd); + + type = type->semantic(loc, sc); + assert(type->ty == Tfunction); + + // Check that there is at least one argument of type uint + TypeFunction *tf = (TypeFunction *)type; + if (Argument::dim(tf->parameters) < 1) + { + error("at least one argument of type uint expected"); + } + else + { + Argument *a = Argument::getNth(tf->parameters, 0); + if (!a->type->equals(Type::tuns32)) + error("first argument must be type uint, not %s", a->type->toChars()); + } + + FuncDeclaration::semantic(sc); +} + +char *NewDeclaration::kind() +{ + return "allocator"; +} + +int NewDeclaration::isVirtual() +{ + return FALSE; +} + +int NewDeclaration::addPreInvariant() +{ + return FALSE; +} + +int NewDeclaration::addPostInvariant() +{ + return FALSE; +} + +void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("new"); + Argument::argsToCBuffer(buf, hgs, arguments, varargs); + bodyToCBuffer(buf, hgs); +} + + +/********************************* DeleteDeclaration ****************************/ + +DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments) + : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) +{ + this->arguments = arguments; +} + +Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) +{ + DeleteDeclaration *f; + + f = new DeleteDeclaration(loc, endloc, NULL); + + FuncDeclaration::syntaxCopy(f); + + f->arguments = Argument::arraySyntaxCopy(arguments); + + return f; +} + + +void DeleteDeclaration::semantic(Scope *sc) +{ + ClassDeclaration *cd; + + //printf("DeleteDeclaration::semantic()\n"); + + parent = sc->parent; + Dsymbol *parent = toParent(); + cd = parent->isClassDeclaration(); + if (!cd && !parent->isStructDeclaration()) + { + error("new allocators only are for class or struct definitions"); + } + type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); + + type = type->semantic(loc, sc); + assert(type->ty == Tfunction); + + // Check that there is only one argument of type void* + TypeFunction *tf = (TypeFunction *)type; + if (Argument::dim(tf->parameters) != 1) + { + error("one argument of type void* expected"); + } + else + { + Argument *a = Argument::getNth(tf->parameters, 0); + if (!a->type->equals(Type::tvoid->pointerTo())) + error("one argument of type void* expected, not %s", a->type->toChars()); + } + + FuncDeclaration::semantic(sc); +} + +char *DeleteDeclaration::kind() +{ + return "deallocator"; +} + +int DeleteDeclaration::isDelete() +{ + return TRUE; +} + +int DeleteDeclaration::isVirtual() +{ + return FALSE; +} + +int DeleteDeclaration::addPreInvariant() +{ + return FALSE; +} + +int DeleteDeclaration::addPostInvariant() +{ + return FALSE; +} + +void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("delete"); + Argument::argsToCBuffer(buf, hgs, arguments, 0); + bodyToCBuffer(buf, hgs); +} + + + + diff --git a/dmd/interpret.c b/dmd/interpret.c index 970dbace..dd992d3e 100644 --- a/dmd/interpret.c +++ b/dmd/interpret.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -109,7 +109,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument istatex.caller = istate; istatex.fd = this; - Expressions vsave; + Expressions vsave; // place to save previous parameter values size_t dim = 0; if (arguments) { @@ -117,9 +117,40 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument assert(!dim || parameters->dim == dim); vsave.setDim(dim); + /* Evaluate all the arguments to the function, + * store the results in eargs[] + */ + Expressions eargs; + eargs.setDim(dim); + for (size_t i = 0; i < dim; i++) { Expression *earg = (Expression *)arguments->data[i]; Argument *arg = Argument::getNth(tf->parameters, i); + + if (arg->storageClass & (STCout | STCref)) + { + } + else + { /* Value parameters + */ + Type *ta = arg->type->toBasetype(); + if (ta->ty == Tsarray && earg->op == TOKaddress) + { + /* Static arrays are passed by a simple pointer. + * Skip past this to get at the actual arg. + */ + earg = ((AddrExp *)earg)->e1; + } + earg = earg->interpret(istate ? istate : &istatex); + if (earg == EXP_CANT_INTERPRET) + return NULL; + } + eargs.data[i] = earg; + } + + for (size_t i = 0; i < dim; i++) + { Expression *earg = (Expression *)eargs.data[i]; + Argument *arg = Argument::getNth(tf->parameters, i); VarDeclaration *v = (VarDeclaration *)parameters->data[i]; vsave.data[i] = v->value; #if LOG @@ -161,17 +192,6 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument else { /* Value parameters */ - Type *ta = arg->type->toBasetype(); - if (ta->ty == Tsarray && earg->op == TOKaddress) - { - /* Static arrays are passed by a simple pointer. - * Skip past this to get at the actual arg. - */ - earg = ((AddrExp *)earg)->e1; - } - earg = earg->interpret(istate ? istate : &istatex); - if (earg == EXP_CANT_INTERPRET) - return NULL; v->value = earg; } #if LOG @@ -584,6 +604,8 @@ Expression *ForStatement::interpret(InterState *istate) while (1) { + if (!condition) + goto Lhead; e = condition->interpret(istate); if (e == EXP_CANT_INTERPRET) break; @@ -592,7 +614,9 @@ Expression *ForStatement::interpret(InterState *istate) break; } if (e->isBool(TRUE)) - { e = body ? body->interpret(istate) : NULL; + { + Lhead: + e = body ? body->interpret(istate) : NULL; if (e == EXP_CANT_INTERPRET) break; if (e == EXP_BREAK_INTERPRET) @@ -602,9 +626,12 @@ Expression *ForStatement::interpret(InterState *istate) if (e && e != EXP_CONTINUE_INTERPRET) break; Lcontinue: - e = increment->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; + if (increment) + { + e = increment->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + } } else if (e->isBool(FALSE)) { e = NULL; diff --git a/dmd/lexer.c b/dmd/lexer.c index 4b214860..b78d53a4 100644 --- a/dmd/lexer.c +++ b/dmd/lexer.c @@ -1,3019 +1,3064 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -/* Lexical Analyzer */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef IN_GCC - -#include -#include "mem.h" - -#else - -#if __GNUC__ -#include -#endif - -#if IN_LLVM -#include "mem.h" -#elif _WIN32 -#include "..\root\mem.h" -#else -#include "../root/mem.h" -#endif -#endif - -#include "stringtable.h" - -#include "lexer.h" -#include "utf.h" -#include "identifier.h" -#include "id.h" -#include "module.h" - -#if _WIN32 && __DMC__ -// from \dm\src\include\setlocal.h -extern "C" char * __cdecl __locale_decpoint; -#endif - -extern int HtmlNamedEntity(unsigned char *p, int length); - -#define LS 0x2028 // UTF line separator -#define PS 0x2029 // UTF paragraph separator - -/******************************************** - * Do our own char maps - */ - -static unsigned char cmtable[256]; - -const int CMoctal = 0x1; -const int CMhex = 0x2; -const int CMidchar = 0x4; - -inline unsigned char isoctal (unsigned char c) { return cmtable[c] & CMoctal; } -inline unsigned char ishex (unsigned char c) { return cmtable[c] & CMhex; } -inline unsigned char isidchar(unsigned char c) { return cmtable[c] & CMidchar; } - -static void cmtable_init() -{ - for (unsigned c = 0; c < sizeof(cmtable) / sizeof(cmtable[0]); c++) - { - if ('0' <= c && c <= '7') - cmtable[c] |= CMoctal; - if (isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')) - cmtable[c] |= CMhex; - if (isalnum(c) || c == '_') - cmtable[c] |= CMidchar; - } -} - - -/************************* Token **********************************************/ - -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 - -char *Token::toChars() -{ char *p; - static char buffer[3 + 3 * sizeof(value) + 1]; - - p = buffer; - switch (value) - { - case TOKint32v: -#if IN_GCC - sprintf(buffer,"%d",(d_int32)int64value); -#else - sprintf(buffer,"%d",int32value); -#endif - break; - - case TOKuns32v: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: -#if IN_GCC - sprintf(buffer,"%uU",(d_uns32)uns64value); -#else - sprintf(buffer,"%uU",uns32value); -#endif - break; - - case TOKint64v: - sprintf(buffer,"%jdL",int64value); - break; - - case TOKuns64v: - sprintf(buffer,"%juUL",uns64value); - break; - -#if IN_GCC - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - float80value.format(buffer, sizeof(buffer)); - break; - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - float80value.format(buffer, sizeof(buffer)); - // %% buffer - strcat(buffer, "i"); - break; -#else - case TOKfloat32v: - sprintf(buffer,"%Lgf", float80value); - break; - - case TOKfloat64v: - sprintf(buffer,"%Lg", float80value); - break; - - case TOKfloat80v: - sprintf(buffer,"%LgL", float80value); - break; - - case TOKimaginary32v: - sprintf(buffer,"%Lgfi", float80value); - break; - - case TOKimaginary64v: - sprintf(buffer,"%Lgi", float80value); - break; - - case TOKimaginary80v: - sprintf(buffer,"%LgLi", float80value); - break; -#endif - - case TOKstring: -#if CSTRINGS - p = string; -#else - { OutBuffer buf; - - buf.writeByte('"'); - for (size_t i = 0; i < len; ) - { unsigned c; - - utf_decodeChar((unsigned char *)ustring, len, &i, &c); - switch (c) - { - case 0: - break; - - case '"': - case '\\': - buf.writeByte('\\'); - default: - if (isprint(c)) - buf.writeByte(c); - else if (c <= 0x7F) - buf.printf("\\x%02x", c); - else if (c <= 0xFFFF) - buf.printf("\\u%04x", c); - else - buf.printf("\\U%08x", c); - continue; - } - break; - } - buf.writeByte('"'); - if (postfix) - buf.writeByte('"'); - buf.writeByte(0); - p = (char *)buf.extractData(); - } -#endif - break; - - case TOKidentifier: - case TOKenum: - case TOKstruct: - case TOKimport: - CASE_BASIC_TYPES: - p = ident->toChars(); - break; - - default: - p = toChars(value); - break; - } - return p; -} - -char *Token::toChars(enum TOK value) -{ char *p; - static char buffer[3 + 3 * sizeof(value) + 1]; - - p = tochars[value]; - if (!p) - { sprintf(buffer,"TOK%d",value); - p = buffer; - } - return p; -} - -/*************************** Lexer ********************************************/ - -Token *Lexer::freelist = NULL; -StringTable Lexer::stringtable; -OutBuffer Lexer::stringbuffer; - -Lexer::Lexer(Module *mod, - unsigned char *base, unsigned begoffset, unsigned endoffset, - int doDocComment, int commentToken) - : loc(mod, 1) -{ - //printf("Lexer::Lexer(%p,%d)\n",base,length); - //printf("lexer.mod = %p, %p\n", mod, this->loc.mod); - memset(&token,0,sizeof(token)); - this->base = base; - this->end = base + endoffset; - p = base + begoffset; - this->mod = mod; - this->doDocComment = doDocComment; - this->anyToken = 0; - this->commentToken = commentToken; - //initKeywords(); - - /* If first line starts with '#!', ignore the line - */ - - if (p[0] == '#' && p[1] =='!') - { - p += 2; - while (1) - { unsigned char c = *p; - switch (c) - { - case '\n': - p++; - break; - - case '\r': - p++; - if (*p == '\n') - p++; - break; - - case 0: - case 0x1A: - break; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - break; - } - p++; - continue; - } - break; - } - loc.linnum = 2; - } -} - - -void Lexer::error(const char *format, ...) -{ - if (mod && !global.gag) - { - char *p = loc.toChars(); - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - va_list ap; - va_start(ap, format); - vfprintf(stdmsg, format, ap); - va_end(ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - - if (global.errors >= 20) // moderate blizzard of cascading messages - fatal(); - } - global.errors++; -} - -void Lexer::error(Loc loc, const char *format, ...) -{ - if (mod && !global.gag) - { - char *p = loc.toChars(); - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - va_list ap; - va_start(ap, format); - vfprintf(stdmsg, format, ap); - va_end(ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - - if (global.errors >= 20) // moderate blizzard of cascading messages - fatal(); - } - global.errors++; -} - -TOK Lexer::nextToken() -{ Token *t; - - if (token.next) - { - t = token.next; - memcpy(&token,t,sizeof(Token)); - t->next = freelist; - freelist = t; - } - else - { - scan(&token); - } - //token.print(); - return token.value; -} - -Token *Lexer::peek(Token *ct) -{ Token *t; - - if (ct->next) - t = ct->next; - else - { - t = new Token(); - scan(t); - t->next = NULL; - ct->next = t; - } - return t; -} - -/********************************* - * 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; - - 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 V2 - 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; - - case '\\': // escaped string literal - { unsigned c; - - stringbuffer.reset(); - do - { - p++; - c = escapeSequence(); - stringbuffer.writeUTF8(c); - } 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; - return; - } - - 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 V2 - case 'p': /*case 'q': case 'r':*/ case 's': case 't': -#else - case 'p': case 'q': /*case 'r':*/ case 's': case 't': -#endif - case 'u': case 'v': case 'w': /*case 'x':*/ case 'y': - case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': - case 'Z': - case '_': - case_ident: - { unsigned char c; - StringValue *sv; - Identifier *id; - - do - { - c = *++p; - } while (isidchar(c) || (c & 0x80 && isUniAlpha(decodeUTF()))); - sv = stringtable.update((char *)t->ptr, p - t->ptr); - id = (Identifier *) sv->ptrvalue; - if (!id) - { id = new Identifier(sv->lstring.string,TOKidentifier); - sv->ptrvalue = id; - } - t->ident = id; - t->value = (enum TOK) id->value; - anyToken = 1; - if (*t->ptr == '_') // if special identifier token - { - static char date[11+1]; - static char time[8+1]; - static char timestamp[24+1]; - - if (!date[0]) // lazy evaluation - { time_t t; - char *p; - - ::time(&t); - p = ctime(&t); - assert(p); - sprintf(date, "%.6s %.4s", p + 4, p + 20); - sprintf(time, "%.8s", p + 11); - sprintf(timestamp, "%.24s", p); - } - - if (mod && id == Id::FILE) - { - t->ustring = (unsigned char *)(loc.filename ? loc.filename : mod->ident->toChars()); - goto Lstring; - } - else if (mod && id == Id::LINE) - { - t->value = TOKint64v; - t->uns64value = loc.linnum; - } - else if (id == Id::DATE) - { - t->ustring = (unsigned char *)date; - goto Lstring; - } - else if (id == Id::TIME) - { - t->ustring = (unsigned char *)time; - goto Lstring; - } - else if (id == Id::VENDOR) - { - t->ustring = (unsigned char *)"Digital Mars D"; - goto Lstring; - } - else if (id == Id::TIMESTAMP) - { - t->ustring = (unsigned char *)timestamp; - Lstring: - t->value = TOKstring; - Llen: - t->postfix = 0; - t->len = strlen((char *)t->ustring); - } - else if (id == Id::VERSIONX) - { unsigned major = 0; - unsigned minor = 0; - - for (char *p = global.version + 1; 1; p++) - { - char c = *p; - if (isdigit(c)) - minor = minor * 10 + c - '0'; - else if (c == '.') - { major = minor; - minor = 0; - } - else - break; - } - t->value = TOKint64v; - t->uns64value = major * 1000 + minor; - } - } - //printf("t->value = %d\n",t->value); - return; - } - - case '/': - p++; - switch (*p) - { - case '=': - p++; - t->value = TOKdivass; - return; - - case '*': - p++; - linnum = loc.linnum; - while (1) - { - while (1) - { unsigned char c = *p; - switch (c) - { - case '/': - break; - - case '\n': - loc.linnum++; - p++; - continue; - - case '\r': - p++; - if (*p != '\n') - loc.linnum++; - continue; - - case 0: - case 0x1A: - error("unterminated /* */ comment"); - p = end; - t->value = TOKeof; - return; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - loc.linnum++; - } - p++; - continue; - } - break; - } - p++; - if (p[-2] == '*' && p - 3 != t->ptr) - break; - } - if (commentToken) - { - t->value = TOKcomment; - return; - } - else if (doDocComment && t->ptr[2] == '*' && p - 4 != t->ptr) - { // if /** but not /**/ - getDocComment(t, lastLine == linnum); - } - continue; - - case '/': // do // style comments - linnum = loc.linnum; - while (1) - { unsigned char c = *++p; - switch (c) - { - case '\n': - break; - - case '\r': - if (p[1] == '\n') - p++; - break; - - case 0: - case 0x1A: - if (commentToken) - { - p = end; - t->value = TOKcomment; - return; - } - if (doDocComment && t->ptr[2] == '/') - getDocComment(t, lastLine == linnum); - p = end; - t->value = TOKeof; - return; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - break; - } - continue; - } - break; - } - - if (commentToken) - { - p++; - loc.linnum++; - t->value = TOKcomment; - return; - } - if (doDocComment && t->ptr[2] == '/') - getDocComment(t, lastLine == linnum); - - p++; - loc.linnum++; - continue; - - case '+': - { int nest; - - linnum = loc.linnum; - p++; - nest = 1; - while (1) - { unsigned char c = *p; - switch (c) - { - case '/': - p++; - if (*p == '+') - { - p++; - nest++; - } - continue; - - case '+': - p++; - if (*p == '/') - { - p++; - if (--nest == 0) - break; - } - continue; - - case '\r': - p++; - if (*p != '\n') - loc.linnum++; - continue; - - case '\n': - loc.linnum++; - p++; - continue; - - case 0: - case 0x1A: - error("unterminated /+ +/ comment"); - p = end; - t->value = TOKeof; - return; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - loc.linnum++; - } - p++; - continue; - } - break; - } - if (commentToken) - { - t->value = TOKcomment; - return; - } - if (doDocComment && t->ptr[2] == '+' && p - 4 != t->ptr) - { // if /++ but not /++/ - getDocComment(t, lastLine == linnum); - } - continue; - } - } - t->value = TOKdiv; - return; - - case '.': - p++; - if (isdigit(*p)) - { /* Note that we don't allow ._1 and ._ as being - * valid floating point numbers. - */ - p--; - t->value = inreal(t); - } - else if (p[0] == '.') - { - if (p[1] == '.') - { p += 2; - t->value = TOKdotdotdot; - } - else - { p++; - t->value = TOKslice; - } - } - else - t->value = TOKdot; - return; - - case '&': - p++; - if (*p == '=') - { p++; - t->value = TOKandass; - } - else if (*p == '&') - { p++; - t->value = TOKandand; - } - else - t->value = TOKand; - return; - - case '|': - p++; - if (*p == '=') - { p++; - t->value = TOKorass; - } - else if (*p == '|') - { p++; - t->value = TOKoror; - } - else - t->value = TOKor; - return; - - case '-': - p++; - if (*p == '=') - { p++; - t->value = TOKminass; - } -#if 0 - else if (*p == '>') - { p++; - t->value = TOKarrow; - } -#endif - else if (*p == '-') - { p++; - t->value = TOKminusminus; - } - else - t->value = TOKmin; - return; - - case '+': - p++; - if (*p == '=') - { p++; - t->value = TOKaddass; - } - else if (*p == '+') - { p++; - t->value = TOKplusplus; - } - else - t->value = TOKadd; - return; - - case '<': - p++; - if (*p == '=') - { p++; - t->value = TOKle; // <= - } - else if (*p == '<') - { p++; - if (*p == '=') - { p++; - t->value = TOKshlass; // <<= - } - else - t->value = TOKshl; // << - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKleg; // <>= - } - else - t->value = TOKlg; // <> - } - else - t->value = TOKlt; // < - return; - - case '>': - p++; - if (*p == '=') - { p++; - t->value = TOKge; // >= - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKshrass; // >>= - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKushrass; // >>>= - } - else - t->value = TOKushr; // >>> - } - else - t->value = TOKshr; // >> - } - else - t->value = TOKgt; // > - return; - - case '!': - p++; - if (*p == '=') - { p++; - if (*p == '=' && global.params.Dversion == 1) - { p++; - t->value = TOKnotidentity; // !== - } - else - t->value = TOKnotequal; // != - } - else if (*p == '<') - { p++; - if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKunord; // !<>= - } - else - t->value = TOKue; // !<> - } - else if (*p == '=') - { p++; - t->value = TOKug; // !<= - } - else - t->value = TOKuge; // !< - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKul; // !>= - } - else - t->value = TOKule; // !> - } - else - t->value = TOKnot; // ! - return; - - case '=': - p++; - if (*p == '=') - { p++; - if (*p == '=' && global.params.Dversion == 1) - { p++; - t->value = TOKidentity; // === - } - else - t->value = TOKequal; // == - } - else - t->value = TOKassign; // = - return; - - case '~': - p++; - if (*p == '=') - { p++; - t->value = TOKcatass; // ~= - } - else - t->value = TOKtilde; // ~ - return; - -#define SINGLE(c,tok) case c: p++; t->value = tok; return; - - SINGLE('(', TOKlparen) - SINGLE(')', TOKrparen) - SINGLE('[', TOKlbracket) - SINGLE(']', TOKrbracket) - SINGLE('{', TOKlcurly) - SINGLE('}', TOKrcurly) - SINGLE('?', TOKquestion) - SINGLE(',', TOKcomma) - SINGLE(';', TOKsemicolon) - SINGLE(':', TOKcolon) - SINGLE('$', TOKdollar) - -#undef SINGLE - -#define DOUBLE(c1,tok1,c2,tok2) \ - case c1: \ - p++; \ - if (*p == c2) \ - { p++; \ - t->value = tok2; \ - } \ - else \ - t->value = tok1; \ - return; - - DOUBLE('*', TOKmul, '=', TOKmulass) - DOUBLE('%', TOKmod, '=', TOKmodass) - DOUBLE('^', TOKxor, '=', TOKxorass) - -#undef DOUBLE - - case '#': - p++; - pragma(); - continue; - - default: - { unsigned char c = *p; - - if (c & 0x80) - { unsigned u = decodeUTF(); - - // Check for start of unicode identifier - if (isUniAlpha(u)) - goto case_ident; - - if (u == PS || u == LS) - { - loc.linnum++; - p++; - continue; - } - } - if (isprint(c)) - error("unsupported char '%c'", c); - else - error("unsupported char 0x%02x", c); - p++; - continue; - } - } - } -} - -/******************************************* - * Parse escape sequence. - */ - -unsigned Lexer::escapeSequence() -{ unsigned c; - int n; - int ndigits; - - c = *p; - 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); - 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 char v; - - n = 0; - v = 0; - do - { - v = v * 8 + (c - '0'); - c = *++p; - } while (++n < 3 && isoctal(c)); - c = v; - } - else - error("undefined escape sequence \\%c\n",c); - break; - } - return c; -} - -/************************************** - */ - -TOK Lexer::wysiwygStringConstant(Token *t, int tc) -{ unsigned c; - Loc start = loc; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - switch (c) - { - case '\n': - loc.linnum++; - break; - - case '\r': - if (*p == '\n') - continue; // ignore - c = '\n'; // treat EndOfLine as \n character - loc.linnum++; - break; - - case 0: - case 0x1A: - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; - - case '"': - case '`': - if (c == tc) - { - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - } - break; - - default: - if (c & 0x80) - { p--; - unsigned u = decodeUTF(); - p++; - if (u == PS || u == LS) - loc.linnum++; - stringbuffer.writeUTF8(u); - continue; - } - break; - } - stringbuffer.writeByte(c); - } -} - -/************************************** - * Lex hex strings: - * x"0A ae 34FE BD" - */ - -TOK Lexer::hexStringConstant(Token *t) -{ unsigned c; - Loc start = loc; - unsigned n = 0; - unsigned v; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - switch (c) - { - case ' ': - case '\t': - case '\v': - case '\f': - continue; // skip white space - - case '\r': - if (*p == '\n') - continue; // ignore - // Treat isolated '\r' as if it were a '\n' - case '\n': - loc.linnum++; - continue; - - case 0: - case 0x1A: - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; - - case '"': - if (n & 1) - { error("odd number (%d) of hex characters in hex string", n); - stringbuffer.writeByte(v); - } - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - - default: - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'a' && c <= 'f') - c -= 'a' - 10; - else if (c >= 'A' && c <= 'F') - c -= 'A' - 10; - else if (c & 0x80) - { p--; - unsigned u = decodeUTF(); - p++; - if (u == PS || u == LS) - loc.linnum++; - else - error("non-hex character \\u%x", u); - } - else - error("non-hex character '%c'", c); - if (n & 1) - { v = (v << 4) | c; - stringbuffer.writeByte(v); - } - else - v = c; - n++; - break; - } - } -} - - -#if V2 -/************************************** - * 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: -printf("Lnextline\n"); - 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; - } - } - 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)) - { 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 - */ -printf("done\n"); - 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) - { - case '\\': - switch (*p) - { - case 'u': - case 'U': - case '&': - c = escapeSequence(); - stringbuffer.writeUTF8(c); - continue; - - default: - c = escapeSequence(); - break; - } - break; - - 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) - { - 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; - - case '\n': - L1: - loc.linnum++; - case '\r': - case 0: - case 0x1A: - case '\'': - error("unterminated character constant"); - return tk; - - default: - if (c & 0x80) - { - p--; - c = decodeUTF(); - p++; - if (c == LS || c == PS) - goto L1; - if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE)) - tk = TOKwcharv; - else - tk = TOKdcharv; - } - t->uns64value = c; - break; - } - - if (*p != '\'') - { error("unterminated character constant"); - return tk; - } - p++; - return tk; -} - -/*************************************** - * Get postfix of string literal. - */ - -void Lexer::stringPostfix(Token *t) -{ - switch (*p) - { - case 'c': - case 'w': - case 'd': - t->postfix = *p; - p++; - break; - - default: - t->postfix = 0; - break; - } -} - -/*************************************** - * Read \u or \U unicode sequence - * Input: - * u 'u' or 'U' - */ - -#if 0 -unsigned Lexer::wchar(unsigned u) -{ - unsigned value; - unsigned n; - unsigned char c; - unsigned nchars; - - nchars = (u == 'U') ? 8 : 4; - value = 0; - for (n = 0; 1; n++) - { - ++p; - if (n == nchars) - break; - c = *p; - if (!ishex(c)) - { error("\\%c sequence must be followed by %d hex characters", u, nchars); - break; - } - if (isdigit(c)) - c -= '0'; - else if (islower(c)) - c -= 'a' - 10; - else - c -= 'A' - 10; - value <<= 4; - value |= c; - } - return value; -} -#endif - -/************************************** - * Read in a number. - * If it's an integer, store it in tok.TKutok.Vlong. - * integers can be decimal, octal or hex - * Handle the suffixes U, UL, LU, L, etc. - * If it's double, store it in tok.TKutok.Vdouble. - * Returns: - * TKnum - * TKdouble,... - */ - -TOK Lexer::number(Token *t) -{ - // We use a state machine to collect numbers - enum STATE { STATE_initial, STATE_0, STATE_decimal, STATE_octal, STATE_octale, - STATE_hex, STATE_binary, STATE_hex0, STATE_binary0, - STATE_hexh, STATE_error }; - enum STATE state; - - enum FLAGS - { FLAGS_decimal = 1, // decimal - FLAGS_unsigned = 2, // u or U suffix - FLAGS_long = 4, // l or L suffix - }; - enum FLAGS flags = FLAGS_decimal; - - int i; - int base; - unsigned c; - unsigned char *start; - TOK result; - - //printf("Lexer::number()\n"); - state = STATE_initial; - base = 0; - stringbuffer.reset(); - start = p; - while (1) - { - c = *p; - switch (state) - { - case STATE_initial: // opening state - if (c == '0') - state = STATE_0; - else - state = STATE_decimal; - break; - - case STATE_0: - flags = (FLAGS) (flags & ~FLAGS_decimal); - switch (c) - { -#if ZEROH - case 'H': // 0h - case 'h': - goto hexh; -#endif - case 'X': - case 'x': - state = STATE_hex0; - break; - - case '.': - if (p[1] == '.') // .. is a separate token - goto done; - case 'i': - case 'f': - case 'F': - goto real; -#if ZEROH - case 'E': - case 'e': - goto case_hex; -#endif - case 'B': - case 'b': - state = STATE_binary0; - break; - - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - state = STATE_octal; - break; - -#if ZEROH - case '8': case '9': case 'A': - case 'C': case 'D': case 'F': - case 'a': case 'c': case 'd': case 'f': - case_hex: - state = STATE_hexh; - break; -#endif - case '_': - state = STATE_octal; - p++; - continue; - - case 'L': - if (p[1] == 'i') - goto real; - goto done; - - default: - goto done; - } - break; - - case STATE_decimal: // reading decimal number - if (!isdigit(c)) - { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (c == '.' && p[1] != '.') - goto real; - else if (c == 'i' || c == 'f' || c == 'F' || - c == 'e' || c == 'E') - { - real: // It's a real number. Back up and rescan as a real - p = start; - return inreal(t); - } - else if (c == 'L' && p[1] == 'i') - goto real; - goto done; - } - break; - - case STATE_hex0: // reading hex number - case STATE_hex: - if (!ishex(c)) - { - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (c == '.' && p[1] != '.') - goto real; - if (c == 'P' || c == 'p' || c == 'i') - goto real; - if (state == STATE_hex0) - error("Hex digit expected, not '%c'", c); - goto done; - } - state = STATE_hex; - break; - -#if ZEROH - hexh: - state = STATE_hexh; - case STATE_hexh: // parse numbers like 0FFh - if (!ishex(c)) - { - if (c == 'H' || c == 'h') - { - p++; - base = 16; - goto done; - } - else - { - // Check for something like 1E3 or 0E24 - if (memchr((char *)stringbuffer.data, 'E', stringbuffer.offset) || - memchr((char *)stringbuffer.data, 'e', stringbuffer.offset)) - goto real; - error("Hex digit expected, not '%c'", c); - goto done; - } - } - break; -#endif - - case STATE_octal: // reading octal number - case STATE_octale: // reading octal number with non-octal digits - if (!isoctal(c)) - { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (c == '.' && p[1] != '.') - goto real; - if (c == 'i') - goto real; - if (isdigit(c)) - { - state = STATE_octale; - } - else - goto done; - } - break; - - case STATE_binary0: // starting binary number - case STATE_binary: // reading binary number - if (c != '0' && c != '1') - { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (state == STATE_binary0) - { error("binary digit expected"); - state = STATE_error; - break; - } - else - goto done; - } - state = STATE_binary; - break; - - case STATE_error: // for error recovery - if (!isdigit(c)) // scan until non-digit - goto done; - break; - - default: - assert(0); - } - stringbuffer.writeByte(c); - p++; - } -done: - stringbuffer.writeByte(0); // terminate string - if (state == STATE_octale) - error("Octal digit expected"); - - uinteger_t n; // unsigned >=64 bit integer type - - if (stringbuffer.offset == 2 && (state == STATE_decimal || state == STATE_0)) - n = stringbuffer.data[0] - '0'; - else - { - // Convert string to integer -#if __DMC__ - errno = 0; - n = strtoull((char *)stringbuffer.data,NULL,base); - if (errno == ERANGE) - error("integer overflow"); -#else - // Not everybody implements strtoull() - char *p = (char *)stringbuffer.data; - int r = 10, d; - - if (*p == '0') - { - if (p[1] == 'x' || p[1] == 'X') - p += 2, r = 16; - else if (p[1] == 'b' || p[1] == 'B') - p += 2, r = 2; - else if (isdigit(p[1])) - p += 1, r = 8; - } - - n = 0; - while (1) - { - if (*p >= '0' && *p <= '9') - d = *p - '0'; - else if (*p >= 'a' && *p <= 'z') - d = *p - 'a' + 10; - else if (*p >= 'A' && *p <= 'Z') - d = *p - 'A' + 10; - else - break; - if (d >= r) - break; - if (n && n * r + d <= n) - { - error ("integer overflow"); - break; - } - - n = n * r + d; - p++; - } -#endif - if (sizeof(n) > 8 && - n > 0xFFFFFFFFFFFFFFFFULL) // if n needs more than 64 bits - error("integer overflow"); - } - - // Parse trailing 'u', 'U', 'l' or 'L' in any combination - while (1) - { unsigned char f; - - switch (*p) - { case 'U': - case 'u': - f = FLAGS_unsigned; - goto L1; - - case 'l': - if (1 || !global.params.useDeprecated) - error("'l' suffix is deprecated, use 'L' instead"); - case 'L': - f = FLAGS_long; - L1: - p++; - if (flags & f) - error("unrecognized token"); - flags = (FLAGS) (flags | f); - continue; - default: - break; - } - break; - } - - switch (flags) - { - case 0: - /* Octal or Hexadecimal constant. - * First that fits: int, uint, long, ulong - */ - if (n & 0x8000000000000000LL) - result = TOKuns64v; - else if (n & 0xFFFFFFFF00000000LL) - result = TOKint64v; - else if (n & 0x80000000) - result = TOKuns32v; - else - result = TOKint32v; - break; - - case FLAGS_decimal: - /* First that fits: int, long, long long - */ - if (n & 0x8000000000000000LL) - { error("signed integer overflow"); - result = TOKuns64v; - } - else if (n & 0xFFFFFFFF80000000LL) - result = TOKint64v; - else - result = TOKint32v; - break; - - case FLAGS_unsigned: - case FLAGS_decimal | FLAGS_unsigned: - /* First that fits: uint, ulong - */ - if (n & 0xFFFFFFFF00000000LL) - result = TOKuns64v; - else - result = TOKuns32v; - break; - - case FLAGS_decimal | FLAGS_long: - if (n & 0x8000000000000000LL) - { error("signed integer overflow"); - result = TOKuns64v; - } - else - result = TOKint64v; - break; - - case FLAGS_long: - if (n & 0x8000000000000000LL) - result = TOKuns64v; - else - result = TOKint64v; - break; - - case FLAGS_unsigned | FLAGS_long: - case FLAGS_decimal | FLAGS_unsigned | FLAGS_long: - result = TOKuns64v; - break; - - default: - #ifdef DEBUG - printf("%x\n",flags); - #endif - assert(0); - } - t->uns64value = n; - return result; -} - -/************************************** - * Read in characters, converting them to real. - * Bugs: - * Exponent overflow not detected. - * Too much requested precision is not detected. - */ - -TOK Lexer::inreal(Token *t) -#ifdef __DMC__ -__in -{ - assert(*p == '.' || isdigit(*p)); -} -__out (result) -{ - switch (result) - { - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - break; - - default: - assert(0); - } -} -__body -#endif /* __DMC__ */ -{ int dblstate; - unsigned c; - char hex; // is this a hexadecimal-floating-constant? - TOK result; - - //printf("Lexer::inreal()\n"); - stringbuffer.reset(); - dblstate = 0; - hex = 0; -Lnext: - while (1) - { - // Get next char from input - c = *p++; - //printf("dblstate = %d, c = '%c'\n", dblstate, c); - while (1) - { - switch (dblstate) - { - case 0: // opening state - if (c == '0') - dblstate = 9; - else if (c == '.') - dblstate = 3; - else - dblstate = 1; - break; - - case 9: - dblstate = 1; - if (c == 'X' || c == 'x') - { hex++; - break; - } - case 1: // digits to left of . - case 3: // digits to right of . - case 7: // continuing exponent digits - if (!isdigit(c) && !(hex && isxdigit(c))) - { - if (c == '_') - goto Lnext; // ignore embedded '_' - dblstate++; - continue; - } - break; - - case 2: // no more digits to left of . - if (c == '.') - { dblstate++; - break; - } - case 4: // no more digits to right of . - if ((c == 'E' || c == 'e') || - hex && (c == 'P' || c == 'p')) - { dblstate = 5; - hex = 0; // exponent is always decimal - break; - } - if (hex) - error("binary-exponent-part required"); - goto done; - - case 5: // looking immediately to right of E - dblstate++; - if (c == '-' || c == '+') - break; - case 6: // 1st exponent digit expected - if (!isdigit(c)) - error("exponent expected"); - dblstate++; - break; - - case 8: // past end of exponent digits - goto done; - } - break; - } - stringbuffer.writeByte(c); - } -done: - p--; - - stringbuffer.writeByte(0); - -#if _WIN32 && __DMC__ - char *save = __locale_decpoint; - __locale_decpoint = "."; -#endif -#ifdef IN_GCC - t->float80value = real_t::parse((char *)stringbuffer.data, real_t::LongDouble); -#else - t->float80value = strtold((char *)stringbuffer.data, NULL); -#endif - errno = 0; - switch (*p) - { - case 'F': - case 'f': -#ifdef IN_GCC - real_t::parse((char *)stringbuffer.data, real_t::Float); -#else - strtof((char *)stringbuffer.data, NULL); -#endif - result = TOKfloat32v; - p++; - break; - - default: -#ifdef IN_GCC - real_t::parse((char *)stringbuffer.data, real_t::Double); -#else - strtod((char *)stringbuffer.data, NULL); -#endif - result = TOKfloat64v; - break; - - case 'l': - if (!global.params.useDeprecated) - error("'l' suffix is deprecated, use 'L' instead"); - case 'L': - result = TOKfloat80v; - p++; - break; - } - if (*p == 'i' || *p == 'I') - { - if (!global.params.useDeprecated && *p == 'I') - error("'I' suffix is deprecated, use 'i' instead"); - p++; - switch (result) - { - case TOKfloat32v: - result = TOKimaginary32v; - break; - case TOKfloat64v: - result = TOKimaginary64v; - break; - case TOKfloat80v: - result = TOKimaginary80v; - break; - } - } -#if _WIN32 && __DMC__ - __locale_decpoint = save; -#endif - if (errno == ERANGE) - error("number is not representable"); - return result; -} - -/********************************************* - * Do pragma. - * Currently, the only pragma supported is: - * #line linnum [filespec] - */ - -void Lexer::pragma() -{ - Token tok; - int linnum; - char *filespec = NULL; - Loc loc = this->loc; - - scan(&tok); - if (tok.value != TOKidentifier || tok.ident != Id::line) - goto Lerr; - - scan(&tok); - if (tok.value == TOKint32v || tok.value == TOKint64v) - linnum = tok.uns64value - 1; - else - goto Lerr; - - while (1) - { - switch (*p) - { - case 0: - case 0x1A: - case '\n': - Lnewline: - this->loc.linnum = linnum; - if (filespec) - this->loc.filename = filespec; - return; - - case '\r': - p++; - if (*p != '\n') - { p--; - goto Lnewline; - } - continue; - - case ' ': - case '\t': - case '\v': - case '\f': - p++; - continue; // skip white space - - case '_': - if (mod && memcmp(p, "__FILE__", 8) == 0) - { - p += 8; - filespec = mem.strdup(loc.filename ? loc.filename : mod->ident->toChars()); - } - continue; - - case '"': - if (filespec) - goto Lerr; - stringbuffer.reset(); - p++; - while (1) - { unsigned c; - - c = *p; - switch (c) - { - case '\n': - case '\r': - case 0: - case 0x1A: - goto Lerr; - - case '"': - stringbuffer.writeByte(0); - filespec = mem.strdup((char *)stringbuffer.data); - p++; - break; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - goto Lerr; - } - stringbuffer.writeByte(c); - p++; - continue; - } - break; - } - continue; - - default: - if (*p & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - goto Lnewline; - } - goto Lerr; - } - } - -Lerr: - error(loc, "#line integer [\"filespec\"]\\n expected"); -} - - -/******************************************** - * Decode UTF character. - * Issue error messages for invalid sequences. - * Return decoded character, advance p to last character in UTF sequence. - */ - -unsigned Lexer::decodeUTF() -{ - dchar_t u; - unsigned char c; - unsigned char *s = p; - size_t len; - size_t idx; - 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) -{ - OutBuffer buf; - unsigned char ct = t->ptr[2]; - unsigned char *q = t->ptr + 3; // start of comment text - int linestart = 0; - - 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; - } - } - - 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. - */ - -unsigned char *Lexer::combineComments(unsigned char *c1, unsigned char *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); - c[len1] = '\n'; - memcpy(c + len1 + 1, c2, len2); - c[len1 + 1 + len2] = 0; - } - } - return c; -} - -/******************************************** - * Create an identifier in the string table. - */ - -Identifier *Lexer::idPool(const char *s) -{ unsigned len; - Identifier *id; - StringValue *sv; - - len = strlen(s); - sv = stringtable.update(s, len); - id = (Identifier *) sv->ptrvalue; - if (!id) - { - id = new Identifier(sv->lstring.string, TOKidentifier); - sv->ptrvalue = id; - } - return id; -} - -/**************************************** - */ - -struct Keyword -{ 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 }, - - // Added after 1.0 - { "ref", TOKref }, - { "macro", TOKmacro }, -#if V2 - { "__traits", TOKtraits }, -#endif -}; - -int Token::isKeyword() -{ - for (unsigned u = 0; u < sizeof(keywords) / sizeof(keywords[0]); u++) - { - if (keywords[u].value == value) - return 1; - } - return 0; -} - -void Lexer::initKeywords() -{ StringValue *sv; - unsigned u; - enum TOK v; - unsigned nkeywords = sizeof(keywords) / sizeof(keywords[0]); - - if (global.params.Dversion == 1) - nkeywords -= 2; - - cmtable_init(); - - for (u = 0; u < nkeywords; u++) - { char *s; - - //printf("keyword[%d] = '%s'\n",u, keywords[u].name); - s = keywords[u].name; - v = keywords[u].value; - sv = stringtable.insert(s, strlen(s)); - sv->ptrvalue = (void *) new Identifier(sv->lstring.string,v); - - //printf("tochars[%d] = '%s'\n",v, s); - Token::tochars[v] = s; - } - - Token::tochars[TOKeof] = "EOF"; - Token::tochars[TOKlcurly] = "{"; - Token::tochars[TOKrcurly] = "}"; - Token::tochars[TOKlparen] = "("; - Token::tochars[TOKrparen] = ")"; - Token::tochars[TOKlbracket] = "["; - Token::tochars[TOKrbracket] = "]"; - Token::tochars[TOKsemicolon] = ";"; - Token::tochars[TOKcolon] = ":"; - Token::tochars[TOKcomma] = ","; - Token::tochars[TOKdot] = "."; - Token::tochars[TOKxor] = "^"; - Token::tochars[TOKxorass] = "^="; - Token::tochars[TOKassign] = "="; - Token::tochars[TOKconstruct] = "="; - Token::tochars[TOKlt] = "<"; - Token::tochars[TOKgt] = ">"; - Token::tochars[TOKle] = "<="; - Token::tochars[TOKge] = ">="; - Token::tochars[TOKequal] = "=="; - Token::tochars[TOKnotequal] = "!="; - Token::tochars[TOKnotidentity] = "!is"; - Token::tochars[TOKtobool] = "!!"; - - Token::tochars[TOKunord] = "!<>="; - Token::tochars[TOKue] = "!<>"; - Token::tochars[TOKlg] = "<>"; - Token::tochars[TOKleg] = "<>="; - Token::tochars[TOKule] = "!>"; - Token::tochars[TOKul] = "!>="; - Token::tochars[TOKuge] = "!<"; - Token::tochars[TOKug] = "!<="; - - Token::tochars[TOKnot] = "!"; - Token::tochars[TOKtobool] = "!!"; - Token::tochars[TOKshl] = "<<"; - Token::tochars[TOKshr] = ">>"; - Token::tochars[TOKushr] = ">>>"; - Token::tochars[TOKadd] = "+"; - Token::tochars[TOKmin] = "-"; - Token::tochars[TOKmul] = "*"; - Token::tochars[TOKdiv] = "/"; - Token::tochars[TOKmod] = "%"; - Token::tochars[TOKslice] = ".."; - Token::tochars[TOKdotdotdot] = "..."; - Token::tochars[TOKand] = "&"; - Token::tochars[TOKandand] = "&&"; - Token::tochars[TOKor] = "|"; - Token::tochars[TOKoror] = "||"; - Token::tochars[TOKarray] = "[]"; - Token::tochars[TOKindex] = "[i]"; - Token::tochars[TOKaddress] = "&"; - Token::tochars[TOKstar] = "*"; - Token::tochars[TOKtilde] = "~"; - Token::tochars[TOKdollar] = "$"; - Token::tochars[TOKcast] = "cast"; - Token::tochars[TOKplusplus] = "++"; - Token::tochars[TOKminusminus] = "--"; - Token::tochars[TOKtype] = "type"; - Token::tochars[TOKquestion] = "?"; - Token::tochars[TOKneg] = "-"; - Token::tochars[TOKuadd] = "+"; - Token::tochars[TOKvar] = "var"; - Token::tochars[TOKaddass] = "+="; - Token::tochars[TOKminass] = "-="; - Token::tochars[TOKmulass] = "*="; - Token::tochars[TOKdivass] = "/="; - Token::tochars[TOKmodass] = "%="; - Token::tochars[TOKshlass] = "<<="; - Token::tochars[TOKshrass] = ">>="; - Token::tochars[TOKushrass] = ">>>="; - Token::tochars[TOKandass] = "&="; - Token::tochars[TOKorass] = "|="; - Token::tochars[TOKcatass] = "~="; - Token::tochars[TOKcat] = "~"; - Token::tochars[TOKcall] = "call"; - Token::tochars[TOKidentity] = "is"; - Token::tochars[TOKnotidentity] = "!is"; - - Token::tochars[TOKorass] = "|="; - Token::tochars[TOKidentifier] = "identifier"; - - // For debugging - Token::tochars[TOKdotexp] = "dotexp"; - Token::tochars[TOKdotti] = "dotti"; - Token::tochars[TOKdotvar] = "dotvar"; - Token::tochars[TOKdottype] = "dottype"; - Token::tochars[TOKsymoff] = "symoff"; - Token::tochars[TOKtypedot] = "typedot"; - 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"; -} + +// 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. + +/* Lexical Analyzer */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef IN_GCC + +#include +#include "mem.h" + +#else + +#if __GNUC__ +#include +#endif + +#if IN_LLVM +#include "mem.h" +#elif _WIN32 +#include "..\root\mem.h" +#else +#include "../root/mem.h" +#endif +#endif + +#include "stringtable.h" + +#include "lexer.h" +#include "utf.h" +#include "identifier.h" +#include "id.h" +#include "module.h" + +#if _WIN32 && __DMC__ +// from \dm\src\include\setlocal.h +extern "C" char * __cdecl __locale_decpoint; +#endif + +extern int HtmlNamedEntity(unsigned char *p, int length); + +#define LS 0x2028 // UTF line separator +#define PS 0x2029 // UTF paragraph separator + +/******************************************** + * Do our own char maps + */ + +static unsigned char cmtable[256]; + +const int CMoctal = 0x1; +const int CMhex = 0x2; +const int CMidchar = 0x4; + +inline unsigned char isoctal (unsigned char c) { return cmtable[c] & CMoctal; } +inline unsigned char ishex (unsigned char c) { return cmtable[c] & CMhex; } +inline unsigned char isidchar(unsigned char c) { return cmtable[c] & CMidchar; } + +static void cmtable_init() +{ + for (unsigned c = 0; c < sizeof(cmtable) / sizeof(cmtable[0]); c++) + { + if ('0' <= c && c <= '7') + cmtable[c] |= CMoctal; + if (isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')) + cmtable[c] |= CMhex; + if (isalnum(c) || c == '_') + cmtable[c] |= CMidchar; + } +} + + +/************************* Token **********************************************/ + +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 + +char *Token::toChars() +{ char *p; + static char buffer[3 + 3 * sizeof(value) + 1]; + + p = buffer; + switch (value) + { + case TOKint32v: +#if IN_GCC + sprintf(buffer,"%d",(d_int32)int64value); +#else + sprintf(buffer,"%d",int32value); +#endif + break; + + case TOKuns32v: + case TOKcharv: + case TOKwcharv: + case TOKdcharv: +#if IN_GCC + sprintf(buffer,"%uU",(d_uns32)uns64value); +#else + sprintf(buffer,"%uU",uns32value); +#endif + break; + + case TOKint64v: + sprintf(buffer,"%jdL",int64value); + break; + + case TOKuns64v: + sprintf(buffer,"%juUL",uns64value); + break; + +#if IN_GCC + case TOKfloat32v: + case TOKfloat64v: + case TOKfloat80v: + float80value.format(buffer, sizeof(buffer)); + break; + case TOKimaginary32v: + case TOKimaginary64v: + case TOKimaginary80v: + float80value.format(buffer, sizeof(buffer)); + // %% buffer + strcat(buffer, "i"); + break; +#else + case TOKfloat32v: + sprintf(buffer,"%Lgf", float80value); + break; + + case TOKfloat64v: + sprintf(buffer,"%Lg", float80value); + break; + + case TOKfloat80v: + sprintf(buffer,"%LgL", float80value); + break; + + case TOKimaginary32v: + sprintf(buffer,"%Lgfi", float80value); + break; + + case TOKimaginary64v: + sprintf(buffer,"%Lgi", float80value); + break; + + case TOKimaginary80v: + sprintf(buffer,"%LgLi", float80value); + break; +#endif + + case TOKstring: +#if CSTRINGS + p = string; +#else + { OutBuffer buf; + + buf.writeByte('"'); + for (size_t i = 0; i < len; ) + { unsigned c; + + utf_decodeChar((unsigned char *)ustring, len, &i, &c); + switch (c) + { + case 0: + break; + + case '"': + case '\\': + buf.writeByte('\\'); + default: + if (isprint(c)) + buf.writeByte(c); + else if (c <= 0x7F) + buf.printf("\\x%02x", c); + else if (c <= 0xFFFF) + buf.printf("\\u%04x", c); + else + buf.printf("\\U%08x", c); + continue; + } + break; + } + buf.writeByte('"'); + if (postfix) + buf.writeByte('"'); + buf.writeByte(0); + p = (char *)buf.extractData(); + } +#endif + break; + + case TOKidentifier: + case TOKenum: + case TOKstruct: + case TOKimport: + CASE_BASIC_TYPES: + p = ident->toChars(); + break; + + default: + p = toChars(value); + break; + } + return p; +} + +char *Token::toChars(enum TOK value) +{ char *p; + static char buffer[3 + 3 * sizeof(value) + 1]; + + p = tochars[value]; + if (!p) + { sprintf(buffer,"TOK%d",value); + p = buffer; + } + return p; +} + +/*************************** Lexer ********************************************/ + +Token *Lexer::freelist = NULL; +StringTable Lexer::stringtable; +OutBuffer Lexer::stringbuffer; + +Lexer::Lexer(Module *mod, + unsigned char *base, unsigned begoffset, unsigned endoffset, + int doDocComment, int commentToken) + : loc(mod, 1) +{ + //printf("Lexer::Lexer(%p,%d)\n",base,length); + //printf("lexer.mod = %p, %p\n", mod, this->loc.mod); + memset(&token,0,sizeof(token)); + this->base = base; + this->end = base + endoffset; + p = base + begoffset; + this->mod = mod; + this->doDocComment = doDocComment; + this->anyToken = 0; + this->commentToken = commentToken; + //initKeywords(); + + /* If first line starts with '#!', ignore the line + */ + + if (p[0] == '#' && p[1] =='!') + { + p += 2; + while (1) + { unsigned char c = *p; + switch (c) + { + case '\n': + p++; + break; + + case '\r': + p++; + if (*p == '\n') + p++; + break; + + case 0: + case 0x1A: + break; + + default: + if (c & 0x80) + { unsigned u = decodeUTF(); + if (u == PS || u == LS) + break; + } + p++; + continue; + } + break; + } + loc.linnum = 2; + } +} + + +void Lexer::error(const char *format, ...) +{ + if (mod && !global.gag) + { + char *p = loc.toChars(); + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + va_list ap; + va_start(ap, format); + vfprintf(stdmsg, format, ap); + va_end(ap); + + fprintf(stdmsg, "\n"); + fflush(stdmsg); + + if (global.errors >= 20) // moderate blizzard of cascading messages + fatal(); + } + global.errors++; +} + +void Lexer::error(Loc loc, const char *format, ...) +{ + if (mod && !global.gag) + { + char *p = loc.toChars(); + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + va_list ap; + va_start(ap, format); + vfprintf(stdmsg, format, ap); + va_end(ap); + + fprintf(stdmsg, "\n"); + fflush(stdmsg); + + if (global.errors >= 20) // moderate blizzard of cascading messages + fatal(); + } + global.errors++; +} + +TOK Lexer::nextToken() +{ Token *t; + + if (token.next) + { + t = token.next; + memcpy(&token,t,sizeof(Token)); + t->next = freelist; + freelist = t; + } + else + { + scan(&token); + } + //token.print(); + return token.value; +} + +Token *Lexer::peek(Token *ct) +{ Token *t; + + if (ct->next) + t = ct->next; + else + { + t = new Token(); + scan(t); + t->next = NULL; + ct->next = t; + } + return t; +} + +/********************************* + * 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; + + 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 V2 + 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; + + case '\\': // escaped string literal + { unsigned c; + + 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; + return; + } + + 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 V2 + case 'p': /*case 'q': case 'r':*/ case 's': case 't': +#else + case 'p': case 'q': /*case 'r':*/ case 's': case 't': +#endif + case 'u': case 'v': case 'w': /*case 'x':*/ case 'y': + case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + case '_': + case_ident: + { unsigned char c; + StringValue *sv; + Identifier *id; + + do + { + c = *++p; + } while (isidchar(c) || (c & 0x80 && isUniAlpha(decodeUTF()))); + sv = stringtable.update((char *)t->ptr, p - t->ptr); + id = (Identifier *) sv->ptrvalue; + if (!id) + { id = new Identifier(sv->lstring.string,TOKidentifier); + sv->ptrvalue = id; + } + t->ident = id; + t->value = (enum TOK) id->value; + anyToken = 1; + if (*t->ptr == '_') // if special identifier token + { + static char date[11+1]; + static char time[8+1]; + static char timestamp[24+1]; + + if (!date[0]) // lazy evaluation + { time_t t; + char *p; + + ::time(&t); + p = ctime(&t); + assert(p); + sprintf(date, "%.6s %.4s", p + 4, p + 20); + sprintf(time, "%.8s", p + 11); + sprintf(timestamp, "%.24s", p); + } + + if (mod && id == Id::FILE) + { + t->ustring = (unsigned char *)(loc.filename ? loc.filename : mod->ident->toChars()); + goto Lstring; + } + else if (mod && id == Id::LINE) + { + t->value = TOKint64v; + t->uns64value = loc.linnum; + } + else if (id == Id::DATE) + { + t->ustring = (unsigned char *)date; + goto Lstring; + } + else if (id == Id::TIME) + { + t->ustring = (unsigned char *)time; + goto Lstring; + } + else if (id == Id::VENDOR) + { + t->ustring = (unsigned char *)"Digital Mars D"; + goto Lstring; + } + else if (id == Id::TIMESTAMP) + { + t->ustring = (unsigned char *)timestamp; + Lstring: + t->value = TOKstring; + Llen: + t->postfix = 0; + t->len = strlen((char *)t->ustring); + } + else if (id == Id::VERSIONX) + { unsigned major = 0; + unsigned minor = 0; + + for (char *p = global.version + 1; 1; p++) + { + char c = *p; + if (isdigit(c)) + minor = minor * 10 + c - '0'; + else if (c == '.') + { major = minor; + minor = 0; + } + else + break; + } + t->value = TOKint64v; + t->uns64value = major * 1000 + minor; + } +#if V2 + else if (id == Id::EOFX) + { + t->value = TOKeof; + // Advance scanner to end of file + while (!(*p == 0 || *p == 0x1A)) + p++; + } +#endif + } + //printf("t->value = %d\n",t->value); + return; + } + + case '/': + p++; + switch (*p) + { + case '=': + p++; + t->value = TOKdivass; + return; + + case '*': + p++; + linnum = loc.linnum; + while (1) + { + while (1) + { unsigned char c = *p; + switch (c) + { + case '/': + break; + + case '\n': + loc.linnum++; + p++; + continue; + + case '\r': + p++; + if (*p != '\n') + loc.linnum++; + continue; + + case 0: + case 0x1A: + error("unterminated /* */ comment"); + p = end; + t->value = TOKeof; + return; + + default: + if (c & 0x80) + { unsigned u = decodeUTF(); + if (u == PS || u == LS) + loc.linnum++; + } + p++; + continue; + } + break; + } + p++; + if (p[-2] == '*' && p - 3 != t->ptr) + break; + } + if (commentToken) + { + t->value = TOKcomment; + return; + } + else if (doDocComment && t->ptr[2] == '*' && p - 4 != t->ptr) + { // if /** but not /**/ + getDocComment(t, lastLine == linnum); + } + continue; + + case '/': // do // style comments + linnum = loc.linnum; + while (1) + { unsigned char c = *++p; + switch (c) + { + case '\n': + break; + + case '\r': + if (p[1] == '\n') + p++; + break; + + case 0: + case 0x1A: + if (commentToken) + { + p = end; + t->value = TOKcomment; + return; + } + if (doDocComment && t->ptr[2] == '/') + getDocComment(t, lastLine == linnum); + p = end; + t->value = TOKeof; + return; + + default: + if (c & 0x80) + { unsigned u = decodeUTF(); + if (u == PS || u == LS) + break; + } + continue; + } + break; + } + + if (commentToken) + { + p++; + loc.linnum++; + t->value = TOKcomment; + return; + } + if (doDocComment && t->ptr[2] == '/') + getDocComment(t, lastLine == linnum); + + p++; + loc.linnum++; + continue; + + case '+': + { int nest; + + linnum = loc.linnum; + p++; + nest = 1; + while (1) + { unsigned char c = *p; + switch (c) + { + case '/': + p++; + if (*p == '+') + { + p++; + nest++; + } + continue; + + case '+': + p++; + if (*p == '/') + { + p++; + if (--nest == 0) + break; + } + continue; + + case '\r': + p++; + if (*p != '\n') + loc.linnum++; + continue; + + case '\n': + loc.linnum++; + p++; + continue; + + case 0: + case 0x1A: + error("unterminated /+ +/ comment"); + p = end; + t->value = TOKeof; + return; + + default: + if (c & 0x80) + { unsigned u = decodeUTF(); + if (u == PS || u == LS) + loc.linnum++; + } + p++; + continue; + } + break; + } + if (commentToken) + { + t->value = TOKcomment; + return; + } + if (doDocComment && t->ptr[2] == '+' && p - 4 != t->ptr) + { // if /++ but not /++/ + getDocComment(t, lastLine == linnum); + } + continue; + } + } + t->value = TOKdiv; + return; + + case '.': + p++; + if (isdigit(*p)) + { /* Note that we don't allow ._1 and ._ as being + * valid floating point numbers. + */ + p--; + t->value = inreal(t); + } + else if (p[0] == '.') + { + if (p[1] == '.') + { p += 2; + t->value = TOKdotdotdot; + } + else + { p++; + t->value = TOKslice; + } + } + else + t->value = TOKdot; + return; + + case '&': + p++; + if (*p == '=') + { p++; + t->value = TOKandass; + } + else if (*p == '&') + { p++; + t->value = TOKandand; + } + else + t->value = TOKand; + return; + + case '|': + p++; + if (*p == '=') + { p++; + t->value = TOKorass; + } + else if (*p == '|') + { p++; + t->value = TOKoror; + } + else + t->value = TOKor; + return; + + case '-': + p++; + if (*p == '=') + { p++; + t->value = TOKminass; + } +#if 0 + else if (*p == '>') + { p++; + t->value = TOKarrow; + } +#endif + else if (*p == '-') + { p++; + t->value = TOKminusminus; + } + else + t->value = TOKmin; + return; + + case '+': + p++; + if (*p == '=') + { p++; + t->value = TOKaddass; + } + else if (*p == '+') + { p++; + t->value = TOKplusplus; + } + else + t->value = TOKadd; + return; + + case '<': + p++; + if (*p == '=') + { p++; + t->value = TOKle; // <= + } + else if (*p == '<') + { p++; + if (*p == '=') + { p++; + t->value = TOKshlass; // <<= + } + else + t->value = TOKshl; // << + } + else if (*p == '>') + { p++; + if (*p == '=') + { p++; + t->value = TOKleg; // <>= + } + else + t->value = TOKlg; // <> + } + else + t->value = TOKlt; // < + return; + + case '>': + p++; + if (*p == '=') + { p++; + t->value = TOKge; // >= + } + else if (*p == '>') + { p++; + if (*p == '=') + { p++; + t->value = TOKshrass; // >>= + } + else if (*p == '>') + { p++; + if (*p == '=') + { p++; + t->value = TOKushrass; // >>>= + } + else + t->value = TOKushr; // >>> + } + else + t->value = TOKshr; // >> + } + else + t->value = TOKgt; // > + return; + + case '!': + p++; + if (*p == '=') + { p++; + if (*p == '=' && global.params.Dversion == 1) + { p++; + t->value = TOKnotidentity; // !== + } + else + t->value = TOKnotequal; // != + } + else if (*p == '<') + { p++; + if (*p == '>') + { p++; + if (*p == '=') + { p++; + t->value = TOKunord; // !<>= + } + else + t->value = TOKue; // !<> + } + else if (*p == '=') + { p++; + t->value = TOKug; // !<= + } + else + t->value = TOKuge; // !< + } + else if (*p == '>') + { p++; + if (*p == '=') + { p++; + t->value = TOKul; // !>= + } + else + t->value = TOKule; // !> + } + else + t->value = TOKnot; // ! + return; + + case '=': + p++; + if (*p == '=') + { p++; + if (*p == '=' && global.params.Dversion == 1) + { p++; + t->value = TOKidentity; // === + } + else + t->value = TOKequal; // == + } + else + t->value = TOKassign; // = + return; + + case '~': + p++; + if (*p == '=') + { p++; + t->value = TOKcatass; // ~= + } + else + t->value = TOKtilde; // ~ + return; + +#define SINGLE(c,tok) case c: p++; t->value = tok; return; + + SINGLE('(', TOKlparen) + SINGLE(')', TOKrparen) + SINGLE('[', TOKlbracket) + SINGLE(']', TOKrbracket) + SINGLE('{', TOKlcurly) + SINGLE('}', TOKrcurly) + SINGLE('?', TOKquestion) + SINGLE(',', TOKcomma) + SINGLE(';', TOKsemicolon) + SINGLE(':', TOKcolon) + SINGLE('$', TOKdollar) + +#undef SINGLE + +#define DOUBLE(c1,tok1,c2,tok2) \ + case c1: \ + p++; \ + if (*p == c2) \ + { p++; \ + t->value = tok2; \ + } \ + else \ + t->value = tok1; \ + return; + + DOUBLE('*', TOKmul, '=', TOKmulass) + DOUBLE('%', TOKmod, '=', TOKmodass) + DOUBLE('^', TOKxor, '=', TOKxorass) + +#undef DOUBLE + + case '#': + p++; + pragma(); + continue; + + default: + { unsigned char c = *p; + + if (c & 0x80) + { unsigned u = decodeUTF(); + + // Check for start of unicode identifier + if (isUniAlpha(u)) + goto case_ident; + + if (u == PS || u == LS) + { + loc.linnum++; + p++; + continue; + } + } + if (isprint(c)) + error("unsupported char '%c'", c); + else + error("unsupported char 0x%02x", c); + p++; + continue; + } + } + } +} + +/******************************************* + * Parse escape sequence. + */ + +unsigned Lexer::escapeSequence() +{ unsigned c; + int n; + int ndigits; + + c = *p; + 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); + c = v; + } + else + error("undefined escape hex sequence \\%c\n",c); + break; + + case '&': // named character entity + for (unsigned char *idstart = ++p; 1; p++) + { + switch (*p) + { + case ';': + c = HtmlNamedEntity(idstart, p - idstart); + if (c == ~0) + { error("unnamed character entity &%.*s;", (int)(p - idstart), idstart); + c = ' '; + } + p++; + break; + + default: + if (isalpha(*p) || + (p != idstart + 1 && isdigit(*p))) + continue; + error("unterminated named entity"); + break; + } + break; + } + break; + + case 0: + case 0x1A: // end of file + c = '\\'; + break; + + default: + if (isoctal(c)) + { unsigned v; + + n = 0; + v = 0; + do + { + v = v * 8 + (c - '0'); + c = *++p; + } while (++n < 3 && isoctal(c)); + c = v; + if (c > 0xFF) + error("0%03o is larger than a byte", c); + } + else + error("undefined escape sequence \\%c\n",c); + break; + } + return c; +} + +/************************************** + */ + +TOK Lexer::wysiwygStringConstant(Token *t, int tc) +{ unsigned c; + Loc start = loc; + + p++; + stringbuffer.reset(); + while (1) + { + c = *p++; + switch (c) + { + case '\n': + loc.linnum++; + break; + + case '\r': + if (*p == '\n') + continue; // ignore + c = '\n'; // treat EndOfLine as \n character + loc.linnum++; + break; + + case 0: + case 0x1A: + error("unterminated string constant starting at %s", start.toChars()); + t->ustring = (unsigned char *)""; + t->len = 0; + t->postfix = 0; + return TOKstring; + + case '"': + case '`': + if (c == tc) + { + t->len = stringbuffer.offset; + stringbuffer.writeByte(0); + t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); + memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); + stringPostfix(t); + return TOKstring; + } + break; + + default: + if (c & 0x80) + { p--; + unsigned u = decodeUTF(); + p++; + if (u == PS || u == LS) + loc.linnum++; + stringbuffer.writeUTF8(u); + continue; + } + break; + } + stringbuffer.writeByte(c); + } +} + +/************************************** + * Lex hex strings: + * x"0A ae 34FE BD" + */ + +TOK Lexer::hexStringConstant(Token *t) +{ unsigned c; + Loc start = loc; + unsigned n = 0; + unsigned v; + + p++; + stringbuffer.reset(); + while (1) + { + c = *p++; + switch (c) + { + case ' ': + case '\t': + case '\v': + case '\f': + continue; // skip white space + + case '\r': + if (*p == '\n') + continue; // ignore + // Treat isolated '\r' as if it were a '\n' + case '\n': + loc.linnum++; + continue; + + case 0: + case 0x1A: + error("unterminated string constant starting at %s", start.toChars()); + t->ustring = (unsigned char *)""; + t->len = 0; + t->postfix = 0; + return TOKstring; + + case '"': + if (n & 1) + { error("odd number (%d) of hex characters in hex string", n); + stringbuffer.writeByte(v); + } + t->len = stringbuffer.offset; + stringbuffer.writeByte(0); + t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); + memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); + stringPostfix(t); + return TOKstring; + + default: + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'F') + c -= 'A' - 10; + else if (c & 0x80) + { p--; + unsigned u = decodeUTF(); + p++; + if (u == PS || u == LS) + loc.linnum++; + else + error("non-hex character \\u%x", u); + } + else + error("non-hex character '%c'", c); + if (n & 1) + { v = (v << 4) | c; + stringbuffer.writeByte(v); + } + else + v = c; + n++; + break; + } + } +} + + +#if V2 +/************************************** + * 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; + } + } + 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)) + { 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) + { + case '\\': + switch (*p) + { + case 'u': + case 'U': + case '&': + c = escapeSequence(); + stringbuffer.writeUTF8(c); + continue; + + default: + c = escapeSequence(); + break; + } + break; + + 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) + { + 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; + + case '\n': + L1: + loc.linnum++; + case '\r': + case 0: + case 0x1A: + case '\'': + error("unterminated character constant"); + return tk; + + default: + if (c & 0x80) + { + p--; + c = decodeUTF(); + p++; + if (c == LS || c == PS) + goto L1; + if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE)) + tk = TOKwcharv; + else + tk = TOKdcharv; + } + t->uns64value = c; + break; + } + + if (*p != '\'') + { error("unterminated character constant"); + return tk; + } + p++; + return tk; +} + +/*************************************** + * Get postfix of string literal. + */ + +void Lexer::stringPostfix(Token *t) +{ + switch (*p) + { + case 'c': + case 'w': + case 'd': + t->postfix = *p; + p++; + break; + + default: + t->postfix = 0; + break; + } +} + +/*************************************** + * Read \u or \U unicode sequence + * Input: + * u 'u' or 'U' + */ + +#if 0 +unsigned Lexer::wchar(unsigned u) +{ + unsigned value; + unsigned n; + unsigned char c; + unsigned nchars; + + nchars = (u == 'U') ? 8 : 4; + value = 0; + for (n = 0; 1; n++) + { + ++p; + if (n == nchars) + break; + c = *p; + if (!ishex(c)) + { error("\\%c sequence must be followed by %d hex characters", u, nchars); + break; + } + if (isdigit(c)) + c -= '0'; + else if (islower(c)) + c -= 'a' - 10; + else + c -= 'A' - 10; + value <<= 4; + value |= c; + } + return value; +} +#endif + +/************************************** + * Read in a number. + * If it's an integer, store it in tok.TKutok.Vlong. + * integers can be decimal, octal or hex + * Handle the suffixes U, UL, LU, L, etc. + * If it's double, store it in tok.TKutok.Vdouble. + * Returns: + * TKnum + * TKdouble,... + */ + +TOK Lexer::number(Token *t) +{ + // We use a state machine to collect numbers + enum STATE { STATE_initial, STATE_0, STATE_decimal, STATE_octal, STATE_octale, + STATE_hex, STATE_binary, STATE_hex0, STATE_binary0, + STATE_hexh, STATE_error }; + enum STATE state; + + enum FLAGS + { FLAGS_decimal = 1, // decimal + FLAGS_unsigned = 2, // u or U suffix + FLAGS_long = 4, // l or L suffix + }; + enum FLAGS flags = FLAGS_decimal; + + int i; + int base; + unsigned c; + unsigned char *start; + TOK result; + + //printf("Lexer::number()\n"); + state = STATE_initial; + base = 0; + stringbuffer.reset(); + start = p; + while (1) + { + c = *p; + switch (state) + { + case STATE_initial: // opening state + if (c == '0') + state = STATE_0; + else + state = STATE_decimal; + break; + + case STATE_0: + flags = (FLAGS) (flags & ~FLAGS_decimal); + switch (c) + { +#if ZEROH + case 'H': // 0h + case 'h': + goto hexh; +#endif + case 'X': + case 'x': + state = STATE_hex0; + break; + + case '.': + if (p[1] == '.') // .. is a separate token + goto done; + case 'i': + case 'f': + case 'F': + goto real; +#if ZEROH + case 'E': + case 'e': + goto case_hex; +#endif + case 'B': + case 'b': + state = STATE_binary0; + break; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + state = STATE_octal; + break; + +#if ZEROH + case '8': case '9': case 'A': + case 'C': case 'D': case 'F': + case 'a': case 'c': case 'd': case 'f': + case_hex: + state = STATE_hexh; + break; +#endif + case '_': + state = STATE_octal; + p++; + continue; + + case 'L': + if (p[1] == 'i') + goto real; + goto done; + + default: + goto done; + } + break; + + case STATE_decimal: // reading decimal number + if (!isdigit(c)) + { +#if ZEROH + if (ishex(c) + || c == 'H' || c == 'h' + ) + goto hexh; +#endif + if (c == '_') // ignore embedded _ + { p++; + continue; + } + if (c == '.' && p[1] != '.') + goto real; + else if (c == 'i' || c == 'f' || c == 'F' || + c == 'e' || c == 'E') + { + real: // It's a real number. Back up and rescan as a real + p = start; + return inreal(t); + } + else if (c == 'L' && p[1] == 'i') + goto real; + goto done; + } + break; + + case STATE_hex0: // reading hex number + case STATE_hex: + if (!ishex(c)) + { + if (c == '_') // ignore embedded _ + { p++; + continue; + } + if (c == '.' && p[1] != '.') + goto real; + if (c == 'P' || c == 'p' || c == 'i') + goto real; + if (state == STATE_hex0) + error("Hex digit expected, not '%c'", c); + goto done; + } + state = STATE_hex; + break; + +#if ZEROH + hexh: + state = STATE_hexh; + case STATE_hexh: // parse numbers like 0FFh + if (!ishex(c)) + { + if (c == 'H' || c == 'h') + { + p++; + base = 16; + goto done; + } + else + { + // Check for something like 1E3 or 0E24 + if (memchr((char *)stringbuffer.data, 'E', stringbuffer.offset) || + memchr((char *)stringbuffer.data, 'e', stringbuffer.offset)) + goto real; + error("Hex digit expected, not '%c'", c); + goto done; + } + } + break; +#endif + + case STATE_octal: // reading octal number + case STATE_octale: // reading octal number with non-octal digits + if (!isoctal(c)) + { +#if ZEROH + if (ishex(c) + || c == 'H' || c == 'h' + ) + goto hexh; +#endif + if (c == '_') // ignore embedded _ + { p++; + continue; + } + if (c == '.' && p[1] != '.') + goto real; + if (c == 'i') + goto real; + if (isdigit(c)) + { + state = STATE_octale; + } + else + goto done; + } + break; + + case STATE_binary0: // starting binary number + case STATE_binary: // reading binary number + if (c != '0' && c != '1') + { +#if ZEROH + if (ishex(c) + || c == 'H' || c == 'h' + ) + goto hexh; +#endif + if (c == '_') // ignore embedded _ + { p++; + continue; + } + if (state == STATE_binary0) + { error("binary digit expected"); + state = STATE_error; + break; + } + else + goto done; + } + state = STATE_binary; + break; + + case STATE_error: // for error recovery + if (!isdigit(c)) // scan until non-digit + goto done; + break; + + default: + assert(0); + } + stringbuffer.writeByte(c); + p++; + } +done: + stringbuffer.writeByte(0); // terminate string + if (state == STATE_octale) + error("Octal digit expected"); + + uinteger_t n; // unsigned >=64 bit integer type + + if (stringbuffer.offset == 2 && (state == STATE_decimal || state == STATE_0)) + n = stringbuffer.data[0] - '0'; + else + { + // Convert string to integer +#if __DMC__ + errno = 0; + n = strtoull((char *)stringbuffer.data,NULL,base); + if (errno == ERANGE) + error("integer overflow"); +#else + // Not everybody implements strtoull() + char *p = (char *)stringbuffer.data; + int r = 10, d; + + if (*p == '0') + { + if (p[1] == 'x' || p[1] == 'X') + p += 2, r = 16; + else if (p[1] == 'b' || p[1] == 'B') + p += 2, r = 2; + else if (isdigit(p[1])) + p += 1, r = 8; + } + + n = 0; + while (1) + { + if (*p >= '0' && *p <= '9') + d = *p - '0'; + else if (*p >= 'a' && *p <= 'z') + d = *p - 'a' + 10; + else if (*p >= 'A' && *p <= 'Z') + d = *p - 'A' + 10; + else + break; + if (d >= r) + break; + if (n && n * r + d <= n) + { + error ("integer overflow"); + break; + } + + n = n * r + d; + p++; + } +#endif + if (sizeof(n) > 8 && + n > 0xFFFFFFFFFFFFFFFFULL) // if n needs more than 64 bits + error("integer overflow"); + } + + // Parse trailing 'u', 'U', 'l' or 'L' in any combination + while (1) + { unsigned char f; + + switch (*p) + { case 'U': + case 'u': + f = FLAGS_unsigned; + goto L1; + + case 'l': + if (1 || !global.params.useDeprecated) + error("'l' suffix is deprecated, use 'L' instead"); + case 'L': + f = FLAGS_long; + L1: + p++; + if (flags & f) + error("unrecognized token"); + flags = (FLAGS) (flags | f); + continue; + default: + break; + } + break; + } + + switch (flags) + { + case 0: + /* Octal or Hexadecimal constant. + * First that fits: int, uint, long, ulong + */ + if (n & 0x8000000000000000LL) + result = TOKuns64v; + else if (n & 0xFFFFFFFF00000000LL) + result = TOKint64v; + else if (n & 0x80000000) + result = TOKuns32v; + else + result = TOKint32v; + break; + + case FLAGS_decimal: + /* First that fits: int, long, long long + */ + if (n & 0x8000000000000000LL) + { error("signed integer overflow"); + result = TOKuns64v; + } + else if (n & 0xFFFFFFFF80000000LL) + result = TOKint64v; + else + result = TOKint32v; + break; + + case FLAGS_unsigned: + case FLAGS_decimal | FLAGS_unsigned: + /* First that fits: uint, ulong + */ + if (n & 0xFFFFFFFF00000000LL) + result = TOKuns64v; + else + result = TOKuns32v; + break; + + case FLAGS_decimal | FLAGS_long: + if (n & 0x8000000000000000LL) + { error("signed integer overflow"); + result = TOKuns64v; + } + else + result = TOKint64v; + break; + + case FLAGS_long: + if (n & 0x8000000000000000LL) + result = TOKuns64v; + else + result = TOKint64v; + break; + + case FLAGS_unsigned | FLAGS_long: + case FLAGS_decimal | FLAGS_unsigned | FLAGS_long: + result = TOKuns64v; + break; + + default: + #ifdef DEBUG + printf("%x\n",flags); + #endif + assert(0); + } + t->uns64value = n; + return result; +} + +/************************************** + * Read in characters, converting them to real. + * Bugs: + * Exponent overflow not detected. + * Too much requested precision is not detected. + */ + +TOK Lexer::inreal(Token *t) +#ifdef __DMC__ +__in +{ + assert(*p == '.' || isdigit(*p)); +} +__out (result) +{ + switch (result) + { + case TOKfloat32v: + case TOKfloat64v: + case TOKfloat80v: + case TOKimaginary32v: + case TOKimaginary64v: + case TOKimaginary80v: + break; + + default: + assert(0); + } +} +__body +#endif /* __DMC__ */ +{ int dblstate; + unsigned c; + char hex; // is this a hexadecimal-floating-constant? + TOK result; + + //printf("Lexer::inreal()\n"); + stringbuffer.reset(); + dblstate = 0; + hex = 0; +Lnext: + while (1) + { + // Get next char from input + c = *p++; + //printf("dblstate = %d, c = '%c'\n", dblstate, c); + while (1) + { + switch (dblstate) + { + case 0: // opening state + if (c == '0') + dblstate = 9; + else if (c == '.') + dblstate = 3; + else + dblstate = 1; + break; + + case 9: + dblstate = 1; + if (c == 'X' || c == 'x') + { hex++; + break; + } + case 1: // digits to left of . + case 3: // digits to right of . + case 7: // continuing exponent digits + if (!isdigit(c) && !(hex && isxdigit(c))) + { + if (c == '_') + goto Lnext; // ignore embedded '_' + dblstate++; + continue; + } + break; + + case 2: // no more digits to left of . + if (c == '.') + { dblstate++; + break; + } + case 4: // no more digits to right of . + if ((c == 'E' || c == 'e') || + hex && (c == 'P' || c == 'p')) + { dblstate = 5; + hex = 0; // exponent is always decimal + break; + } + if (hex) + error("binary-exponent-part required"); + goto done; + + case 5: // looking immediately to right of E + dblstate++; + if (c == '-' || c == '+') + break; + case 6: // 1st exponent digit expected + if (!isdigit(c)) + error("exponent expected"); + dblstate++; + break; + + case 8: // past end of exponent digits + goto done; + } + break; + } + stringbuffer.writeByte(c); + } +done: + p--; + + stringbuffer.writeByte(0); + +#if _WIN32 && __DMC__ + char *save = __locale_decpoint; + __locale_decpoint = "."; +#endif +#ifdef IN_GCC + t->float80value = real_t::parse((char *)stringbuffer.data, real_t::LongDouble); +#else + t->float80value = strtold((char *)stringbuffer.data, NULL); +#endif + errno = 0; + switch (*p) + { + case 'F': + case 'f': +#ifdef IN_GCC + real_t::parse((char *)stringbuffer.data, real_t::Float); +#else + strtof((char *)stringbuffer.data, NULL); +#endif + result = TOKfloat32v; + p++; + break; + + default: +#ifdef IN_GCC + real_t::parse((char *)stringbuffer.data, real_t::Double); +#else + strtod((char *)stringbuffer.data, NULL); +#endif + result = TOKfloat64v; + break; + + case 'l': + if (!global.params.useDeprecated) + error("'l' suffix is deprecated, use 'L' instead"); + case 'L': + result = TOKfloat80v; + p++; + break; + } + if (*p == 'i' || *p == 'I') + { + if (!global.params.useDeprecated && *p == 'I') + error("'I' suffix is deprecated, use 'i' instead"); + p++; + switch (result) + { + case TOKfloat32v: + result = TOKimaginary32v; + break; + case TOKfloat64v: + result = TOKimaginary64v; + break; + case TOKfloat80v: + result = TOKimaginary80v; + break; + } + } +#if _WIN32 && __DMC__ + __locale_decpoint = save; +#endif + if (errno == ERANGE) + error("number is not representable"); + return result; +} + +/********************************************* + * Do pragma. + * Currently, the only pragma supported is: + * #line linnum [filespec] + */ + +void Lexer::pragma() +{ + Token tok; + int linnum; + char *filespec = NULL; + Loc loc = this->loc; + + scan(&tok); + if (tok.value != TOKidentifier || tok.ident != Id::line) + goto Lerr; + + scan(&tok); + if (tok.value == TOKint32v || tok.value == TOKint64v) + linnum = tok.uns64value - 1; + else + goto Lerr; + + while (1) + { + switch (*p) + { + case 0: + case 0x1A: + case '\n': + Lnewline: + this->loc.linnum = linnum; + if (filespec) + this->loc.filename = filespec; + return; + + case '\r': + p++; + if (*p != '\n') + { p--; + goto Lnewline; + } + continue; + + case ' ': + case '\t': + case '\v': + case '\f': + p++; + continue; // skip white space + + case '_': + if (mod && memcmp(p, "__FILE__", 8) == 0) + { + p += 8; + filespec = mem.strdup(loc.filename ? loc.filename : mod->ident->toChars()); + } + continue; + + case '"': + if (filespec) + goto Lerr; + stringbuffer.reset(); + p++; + while (1) + { unsigned c; + + c = *p; + switch (c) + { + case '\n': + case '\r': + case 0: + case 0x1A: + goto Lerr; + + case '"': + stringbuffer.writeByte(0); + filespec = mem.strdup((char *)stringbuffer.data); + p++; + break; + + default: + if (c & 0x80) + { unsigned u = decodeUTF(); + if (u == PS || u == LS) + goto Lerr; + } + stringbuffer.writeByte(c); + p++; + continue; + } + break; + } + continue; + + default: + if (*p & 0x80) + { unsigned u = decodeUTF(); + if (u == PS || u == LS) + goto Lnewline; + } + goto Lerr; + } + } + +Lerr: + error(loc, "#line integer [\"filespec\"]\\n expected"); +} + + +/******************************************** + * Decode UTF character. + * Issue error messages for invalid sequences. + * Return decoded character, advance p to last character in UTF sequence. + */ + +unsigned Lexer::decodeUTF() +{ + dchar_t u; + unsigned char c; + unsigned char *s = p; + size_t len; + size_t idx; + 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) +{ + OutBuffer buf; + unsigned char ct = t->ptr[2]; + unsigned char *q = t->ptr + 3; // start of comment text + int linestart = 0; + + 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; + } + } + + 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. + */ + +unsigned char *Lexer::combineComments(unsigned char *c1, unsigned char *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); + c[len1] = '\n'; + memcpy(c + len1 + 1, c2, len2); + c[len1 + 1 + len2] = 0; + } + } + return c; +} + +/******************************************** + * Create an identifier in the string table. + */ + +Identifier *Lexer::idPool(const char *s) +{ + size_t len = strlen(s); + StringValue *sv = stringtable.update(s, len); + Identifier *id = (Identifier *) sv->ptrvalue; + if (!id) + { + id = new Identifier(sv->lstring.string, TOKidentifier); + sv->ptrvalue = id; + } + return id; +} + +/********************************************* + * Create a unique identifier using the prefix s. + */ + +Identifier *Lexer::uniqueId(const char *s, int num) +{ char buffer[32]; + size_t slen = strlen(s); + + assert(slen + sizeof(num) * 3 + 1 <= sizeof(buffer)); + sprintf(buffer, "%s%d", s, num); + return idPool(buffer); +} + +Identifier *Lexer::uniqueId(const char *s) +{ + static int num; + return uniqueId(s, ++num); +} + +/**************************************** + */ + +struct Keyword +{ char *name; + enum TOK value; +}; + +static Keyword keywords[] = +{ +// { "", TOK }, + + { "this", TOKthis }, + { "super", TOKsuper }, + { "assert", TOKassert }, + { "null", TOKnull }, + { "true", TOKtrue }, + { "false", TOKfalse }, + { "cast", TOKcast }, + { "new", TOKnew }, + { "delete", TOKdelete }, + { "throw", TOKthrow }, + { "module", TOKmodule }, + { "pragma", TOKpragma }, + { "typeof", TOKtypeof }, + { "typeid", TOKtypeid }, + + { "template", TOKtemplate }, + + { "void", TOKvoid }, + { "byte", TOKint8 }, + { "ubyte", TOKuns8 }, + { "short", TOKint16 }, + { "ushort", TOKuns16 }, + { "int", TOKint32 }, + { "uint", TOKuns32 }, + { "long", TOKint64 }, + { "ulong", TOKuns64 }, + { "cent", TOKcent, }, + { "ucent", TOKucent, }, + { "float", TOKfloat32 }, + { "double", TOKfloat64 }, + { "real", TOKfloat80 }, + + { "bool", TOKbool }, + { "char", TOKchar }, + { "wchar", TOKwchar }, + { "dchar", TOKdchar }, + + { "ifloat", TOKimaginary32 }, + { "idouble", TOKimaginary64 }, + { "ireal", TOKimaginary80 }, + + { "cfloat", TOKcomplex32 }, + { "cdouble", TOKcomplex64 }, + { "creal", TOKcomplex80 }, + + { "delegate", TOKdelegate }, + { "function", TOKfunction }, + + { "is", TOKis }, + { "if", TOKif }, + { "else", TOKelse }, + { "while", TOKwhile }, + { "for", TOKfor }, + { "do", TOKdo }, + { "switch", TOKswitch }, + { "case", TOKcase }, + { "default", TOKdefault }, + { "break", TOKbreak }, + { "continue", TOKcontinue }, + { "synchronized", TOKsynchronized }, + { "return", TOKreturn }, + { "goto", TOKgoto }, + { "try", TOKtry }, + { "catch", TOKcatch }, + { "finally", TOKfinally }, + { "with", TOKwith }, + { "asm", TOKasm }, + { "foreach", TOKforeach }, + { "foreach_reverse", TOKforeach_reverse }, + { "scope", TOKscope }, + + { "struct", TOKstruct }, + { "class", TOKclass }, + { "interface", TOKinterface }, + { "union", TOKunion }, + { "enum", TOKenum }, + { "import", TOKimport }, + { "mixin", TOKmixin }, + { "static", TOKstatic }, + { "final", TOKfinal }, + { "const", TOKconst }, + { "typedef", TOKtypedef }, + { "alias", TOKalias }, + { "override", TOKoverride }, + { "abstract", TOKabstract }, + { "volatile", TOKvolatile }, + { "debug", TOKdebug }, + { "deprecated", TOKdeprecated }, + { "in", TOKin }, + { "out", TOKout }, + { "inout", TOKinout }, + { "lazy", TOKlazy }, + { "auto", TOKauto }, + + { "align", TOKalign }, + { "extern", TOKextern }, + { "private", TOKprivate }, + { "package", TOKpackage }, + { "protected", TOKprotected }, + { "public", TOKpublic }, + { "export", TOKexport }, + + { "body", TOKbody }, + { "invariant", TOKinvariant }, + { "unittest", TOKunittest }, + { "version", TOKversion }, + //{ "manifest", TOKmanifest }, + + // Added after 1.0 + { "ref", TOKref }, + { "macro", TOKmacro }, +#if V2 + { "pure", TOKpure }, + { "nothrow", TOKnothrow }, + { "__traits", TOKtraits }, + { "__overloadset", TOKoverloadset }, +#endif +}; + +int Token::isKeyword() +{ + for (unsigned u = 0; u < sizeof(keywords) / sizeof(keywords[0]); u++) + { + if (keywords[u].value == value) + return 1; + } + return 0; +} + +void Lexer::initKeywords() +{ StringValue *sv; + unsigned u; + enum TOK v; + unsigned nkeywords = sizeof(keywords) / sizeof(keywords[0]); + + if (global.params.Dversion == 1) + nkeywords -= 2; + + cmtable_init(); + + for (u = 0; u < nkeywords; u++) + { char *s; + + //printf("keyword[%d] = '%s'\n",u, keywords[u].name); + s = keywords[u].name; + v = keywords[u].value; + sv = stringtable.insert(s, strlen(s)); + sv->ptrvalue = (void *) new Identifier(sv->lstring.string,v); + + //printf("tochars[%d] = '%s'\n",v, s); + Token::tochars[v] = s; + } + + Token::tochars[TOKeof] = "EOF"; + Token::tochars[TOKlcurly] = "{"; + Token::tochars[TOKrcurly] = "}"; + Token::tochars[TOKlparen] = "("; + Token::tochars[TOKrparen] = ")"; + Token::tochars[TOKlbracket] = "["; + Token::tochars[TOKrbracket] = "]"; + Token::tochars[TOKsemicolon] = ";"; + Token::tochars[TOKcolon] = ":"; + Token::tochars[TOKcomma] = ","; + Token::tochars[TOKdot] = "."; + Token::tochars[TOKxor] = "^"; + Token::tochars[TOKxorass] = "^="; + Token::tochars[TOKassign] = "="; + Token::tochars[TOKconstruct] = "="; +#if V2 + Token::tochars[TOKblit] = "="; +#endif + Token::tochars[TOKlt] = "<"; + Token::tochars[TOKgt] = ">"; + Token::tochars[TOKle] = "<="; + Token::tochars[TOKge] = ">="; + Token::tochars[TOKequal] = "=="; + Token::tochars[TOKnotequal] = "!="; + Token::tochars[TOKnotidentity] = "!is"; + Token::tochars[TOKtobool] = "!!"; + + Token::tochars[TOKunord] = "!<>="; + Token::tochars[TOKue] = "!<>"; + Token::tochars[TOKlg] = "<>"; + Token::tochars[TOKleg] = "<>="; + Token::tochars[TOKule] = "!>"; + Token::tochars[TOKul] = "!>="; + Token::tochars[TOKuge] = "!<"; + Token::tochars[TOKug] = "!<="; + + Token::tochars[TOKnot] = "!"; + Token::tochars[TOKtobool] = "!!"; + Token::tochars[TOKshl] = "<<"; + Token::tochars[TOKshr] = ">>"; + Token::tochars[TOKushr] = ">>>"; + Token::tochars[TOKadd] = "+"; + Token::tochars[TOKmin] = "-"; + Token::tochars[TOKmul] = "*"; + Token::tochars[TOKdiv] = "/"; + Token::tochars[TOKmod] = "%"; + Token::tochars[TOKslice] = ".."; + Token::tochars[TOKdotdotdot] = "..."; + Token::tochars[TOKand] = "&"; + Token::tochars[TOKandand] = "&&"; + Token::tochars[TOKor] = "|"; + Token::tochars[TOKoror] = "||"; + Token::tochars[TOKarray] = "[]"; + Token::tochars[TOKindex] = "[i]"; + Token::tochars[TOKaddress] = "&"; + Token::tochars[TOKstar] = "*"; + Token::tochars[TOKtilde] = "~"; + Token::tochars[TOKdollar] = "$"; + Token::tochars[TOKcast] = "cast"; + Token::tochars[TOKplusplus] = "++"; + Token::tochars[TOKminusminus] = "--"; + Token::tochars[TOKtype] = "type"; + Token::tochars[TOKquestion] = "?"; + Token::tochars[TOKneg] = "-"; + Token::tochars[TOKuadd] = "+"; + Token::tochars[TOKvar] = "var"; + Token::tochars[TOKaddass] = "+="; + Token::tochars[TOKminass] = "-="; + Token::tochars[TOKmulass] = "*="; + Token::tochars[TOKdivass] = "/="; + Token::tochars[TOKmodass] = "%="; + Token::tochars[TOKshlass] = "<<="; + Token::tochars[TOKshrass] = ">>="; + Token::tochars[TOKushrass] = ">>>="; + Token::tochars[TOKandass] = "&="; + Token::tochars[TOKorass] = "|="; + Token::tochars[TOKcatass] = "~="; + Token::tochars[TOKcat] = "~"; + Token::tochars[TOKcall] = "call"; + Token::tochars[TOKidentity] = "is"; + Token::tochars[TOKnotidentity] = "!is"; + + Token::tochars[TOKorass] = "|="; + Token::tochars[TOKidentifier] = "identifier"; + + // For debugging + Token::tochars[TOKdotexp] = "dotexp"; + Token::tochars[TOKdotti] = "dotti"; + Token::tochars[TOKdotvar] = "dotvar"; + Token::tochars[TOKdottype] = "dottype"; + Token::tochars[TOKsymoff] = "symoff"; + Token::tochars[TOKtypedot] = "typedot"; + 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)"; +} diff --git a/dmd/lexer.h b/dmd/lexer.h index a09964a7..6b4a53e8 100644 --- a/dmd/lexer.h +++ b/dmd/lexer.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -92,11 +92,11 @@ enum TOK TOKand, TOKor, TOKxor, TOKandass, TOKorass, TOKxorass, TOKassign, TOKnot, TOKtilde, - TOKplusplus, TOKminusminus, TOKconstruct, + TOKplusplus, TOKminusminus, TOKconstruct, TOKblit, TOKdot, TOKarrow, TOKcomma, TOKquestion, TOKandand, TOKoror, -// 103 +// 104 // Numeric literals TOKint32v, TOKuns32v, TOKint64v, TOKuns64v, @@ -131,7 +131,7 @@ enum TOK TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport, TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile, TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy, - TOKauto, TOKpackage, + TOKauto, TOKpackage, TOKmanifest, // Statements TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch, @@ -152,6 +152,8 @@ enum TOK TOKmacro, #if V2 TOKtraits, + TOKoverloadset, + TOKpure, #endif TOKMAX @@ -261,6 +263,8 @@ struct Lexer 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(); void scan(Token *t); diff --git a/dmd/link.c b/dmd/link.c index 6b66f558..2a2342a9 100644 --- a/dmd/link.c +++ b/dmd/link.c @@ -1,513 +1,513 @@ - - -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#include -#include -#include -#include -#include -#include - -#if _WIN32 -#include -#endif - -#if linux -#include -#include -#include -#endif - -#include "root.h" - -#include "mars.h" - -#include "mem.h" - -int executecmd(char *cmd, char *args, int useenv); -int executearg0(char *cmd, char *args); - -/***************************** - * Run the linker. Return status of execution. - */ - -int runLINK() -{ -#if _WIN32 - assert(0 && "linking not done for win32"); - - char *p; - int i; - int status; - OutBuffer cmdbuf; - - global.params.libfiles->push((void *) "user32"); - global.params.libfiles->push((void *) "kernel32"); - - for (i = 0; i < global.params.objfiles->dim; i++) - { - if (i) - cmdbuf.writeByte('+'); - p = (char *)global.params.objfiles->data[i]; - char *ext = FileName::ext(p); - if (ext) - cmdbuf.write(p, ext - p - 1); - else - cmdbuf.writestring(p); - } - cmdbuf.writeByte(','); - if (global.params.exefile) - cmdbuf.writestring(global.params.exefile); - else - { // Generate exe file name from first obj name - char *n = (char *)global.params.objfiles->data[0]; - char *ex; - - n = FileName::name(n); - FileName *fn = FileName::forceExt(n, "exe"); - global.params.exefile = fn->toChars(); - } - - // Make sure path to exe file exists - { char *p = FileName::path(global.params.exefile); - FileName::ensurePathExists(p); - mem.free(p); - } - - cmdbuf.writeByte(','); - if (global.params.run) - cmdbuf.writestring("nul"); -// if (mapfile) -// cmdbuf.writestring(output); - cmdbuf.writeByte(','); - - for (i = 0; i < global.params.libfiles->dim; i++) - { - if (i) - cmdbuf.writeByte('+'); - cmdbuf.writestring((char *) global.params.libfiles->data[i]); - } - - if (global.params.deffile) - { - cmdbuf.writeByte(','); - cmdbuf.writestring(global.params.deffile); - } - - /* Eliminate unnecessary trailing commas */ - while (1) - { i = cmdbuf.offset; - if (!i || cmdbuf.data[i - 1] != ',') - break; - cmdbuf.offset--; - } - - if (global.params.resfile) - { - cmdbuf.writestring("/RC:"); - cmdbuf.writestring(global.params.resfile); - } - -#if 0 - if (mapfile) - cmdbuf.writestring("/m"); - if (debuginfo) - cmdbuf.writestring("/li"); - if (codeview) - { - cmdbuf.writestring("/co"); - if (codeview3) - cmdbuf.writestring(":3"); - } -#else - if (global.params.symdebug) - cmdbuf.writestring("/co"); -#endif - - cmdbuf.writestring("/noi"); - for (i = 0; i < global.params.linkswitches->dim; i++) - { - cmdbuf.writestring((char *) global.params.linkswitches->data[i]); - } - cmdbuf.writeByte(';'); - - p = cmdbuf.toChars(); - - FileName *lnkfilename = NULL; - size_t plen = strlen(p); - if (plen > 7000) - { - lnkfilename = FileName::forceExt(global.params.exefile, "lnk"); - File flnk(lnkfilename); - flnk.setbuffer(p, plen); - flnk.ref = 1; - if (flnk.write()) - error("error writing file %s", lnkfilename); - if (lnkfilename->len() < plen) - sprintf(p, "@%s", lnkfilename->toChars()); - } - - char *linkcmd = getenv("LINKCMD"); - if (!linkcmd) - linkcmd = "link"; - status = executecmd(linkcmd, p, 1); - if (lnkfilename) - { - remove(lnkfilename->toChars()); - delete lnkfilename; - } - return status; -#elif linux - pid_t childpid; - int i; - int status; - - // Build argv[] - Array argv; - - //char *cc = getenv("CC"); - //if (!cc) - //cc = "gcc"; - char *cc = "llvm-ld"; - argv.push((void *)cc); - - // None of that a.out stuff. Use explicit exe file name, or - // generate one from name of first source file. - OutBuffer* exestr = new OutBuffer; - if (global.params.exefile) - { - exestr->printf("-o=%s", global.params.exefile); - argv.push(exestr->toChars()); - } - else - { // Generate exe file name from first obj name - char *n = (char *)global.params.objfiles->data[0]; - char *e; - char *ex; - - n = FileName::name(n); - e = FileName::ext(n); - if (e) - { - e--; // back up over '.' - ex = (char *)mem.malloc(e - n + 1); - memcpy(ex, n, e - n); - ex[e - n] = 0; - } - else - ex = (char *)"a.out"; // no extension, so give up - exestr->printf("-o=%s", ex); - ex = exestr->toChars(); - argv.push(ex); - global.params.exefile = ex; - } - - // Make sure path to exe file exists - { char *p = FileName::path(global.params.exefile); - FileName::ensurePathExists(p); - mem.free(p); - } - - argv.insert(argv.dim, global.params.libfiles); - - if (!global.params.symdebug) - argv.push((void *)"-strip-debug"); - - //argv.push((void *)"-m32"); - - - if (!global.params.optimize) - argv.push((void *)"-disable-opt"); - else { - const char* s = 0; - switch(global.params.optimizeLevel) { - case 0: - s = "-O0"; break; - case 1: - s = "-O1"; break; - case 2: - s = "-O2"; break; - case 3: - s = "-O3"; break; - case 4: - s = "-O4"; break; - case 5: - s = "-O5"; break; - default: - assert(0); - } - argv.push((void*)s); - } - - if (!(global.params.useInline || global.params.llvmInline)) { - argv.push((void *)"-disable-inlining"); - } - -#if 0 - if (0 && global.params.exefile) - { - /* This switch enables what is known as 'smart linking' - * in the Windows world, where unreferenced sections - * are removed from the executable. It eliminates unreferenced - * functions, essentially making a 'library' out of a module. - * Although it is documented to work with ld version 2.13, - * in practice it does not, but just seems to be ignored. - * Thomas Kuehne has verified that it works with ld 2.16.1. - * BUG: disabled because it causes exception handling to fail - */ - argv.push((void *)"-Xlinker"); - argv.push((void *)"--gc-sections"); - } -#endif - - for (i = 0; i < global.params.linkswitches->dim; i++) - { char *p = (char *)global.params.linkswitches->data[i]; - //if (!p || !p[0] || !(p[0] == '-' && p[1] == 'l')) - //{ // Don't need -Xlinker if switch starts with -l - // argv.push((void *)"-Xlinker"); - //} - argv.push((void *) p); - } - - argv.push((void*)"-native"); - - /* Standard libraries must go after user specified libraries - * passed with -l. - */ - - argv.push((void*)"-ltango-base-c-llvmdc"); - argv.push((void*)"-lpthread"); - argv.push((void*)"-ldl"); - argv.push((void*)"-lm"); - - argv.append(global.params.objfiles); - - std::string runtime_path(global.params.runtimePath); - if (*runtime_path.rbegin() != '/') - runtime_path.append("/"); - runtime_path.append("libtango-base-llvmdc.a"); - argv.push((void*)runtime_path.c_str()); - - if (!global.params.quiet) - { - // Print it - for (i = 0; i < argv.dim; i++) - printf("%s ", (char *)argv.data[i]); - printf("\n"); - fflush(stdout); - } - - argv.push(NULL); - childpid = fork(); - if (childpid == 0) - { - execvp((char *)argv.data[0], (char **)argv.data); - perror((char *)argv.data[0]); // failed to execute - return -1; - } - - waitpid(childpid, &status, 0); - - status=WEXITSTATUS(status); - if (status) - printf("--- errorlevel %d\n", status); - return status; -#else - printf ("Linking is not yet supported for this version of LLVMDMD.\n"); - return -1; -#endif -} - -/********************************** - * Delete generated EXE file. - */ - -void deleteExeFile() -{ - if (global.params.exefile) - { - //printf("deleteExeFile() %s\n", global.params.exefile); - remove(global.params.exefile); - } -} - -/****************************** - * Execute a rule. Return the status. - * cmd program to run - * args arguments to cmd, as a string - * useenv if cmd knows about _CMDLINE environment variable - */ - -#if _WIN32 -int executecmd(char *cmd, char *args, int useenv) -{ - int status; - char *buff; - size_t len; - - if (!global.params.quiet || global.params.verbose) - { - printf("%s %s\n", cmd, args); - fflush(stdout); - } - - if ((len = strlen(args)) > 255) - { char *q; - static char envname[] = "@_CMDLINE"; - - envname[0] = '@'; - switch (useenv) - { case 0: goto L1; - case 2: envname[0] = '%'; break; - } - q = (char *) alloca(sizeof(envname) + len + 1); - sprintf(q,"%s=%s", envname + 1, args); - status = putenv(q); - if (status == 0) - args = envname; - else - { - L1: - error("command line length of %d is too long",len); - } - } - - status = executearg0(cmd,args); -#if _WIN32 - if (status == -1) - status = spawnlp(0,cmd,cmd,args,NULL); -#endif -// if (global.params.verbose) -// printf("\n"); - if (status) - { - if (status == -1) - printf("Can't run '%s', check PATH\n", cmd); - else - printf("--- errorlevel %d\n", status); - } - return status; -} -#endif - -/************************************** - * Attempt to find command to execute by first looking in the directory - * where DMD was run from. - * Returns: - * -1 did not find command there - * !=-1 exit status from command - */ - -#if _WIN32 -int executearg0(char *cmd, char *args) -{ - char *file; - char *argv0 = global.params.argv0; - - //printf("argv0='%s', cmd='%s', args='%s'\n",argv0,cmd,args); - - // If cmd is fully qualified, we don't do this - if (FileName::absolute(cmd)) - return -1; - - file = FileName::replaceName(argv0, cmd); - - //printf("spawning '%s'\n",file); -#if _WIN32 - return spawnl(0,file,file,args,NULL); -#elif linux - char *full; - int cmdl = strlen(cmd); - - full = (char*) mem.malloc(cmdl + strlen(args) + 2); - if (full == NULL) - return 1; - strcpy(full, cmd); - full [cmdl] = ' '; - strcpy(full + cmdl + 1, args); - - int result = system(full); - - mem.free(full); - return result; -#else - assert(0); -#endif -} -#endif - -/*************************************** - * Run the compiled program. - * Return exit status. - */ - -int runProgram() -{ - //printf("runProgram()\n"); - if (global.params.verbose) - { - printf("%s", global.params.exefile); - for (size_t i = 0; i < global.params.runargs_length; i++) - printf(" %s", (char *)global.params.runargs[i]); - printf("\n"); - } - - // Build argv[] - Array argv; - - argv.push((void *)global.params.exefile); - for (size_t i = 0; i < global.params.runargs_length; i++) - { char *a = global.params.runargs[i]; - -#if _WIN32 - // BUG: what about " appearing in the string? - if (strchr(a, ' ')) - { char *b = (char *)mem.malloc(3 + strlen(a)); - sprintf(b, "\"%s\"", a); - a = b; - } -#endif - argv.push((void *)a); - } - argv.push(NULL); - -#if _WIN32 - char *ex = FileName::name(global.params.exefile); - if (ex == global.params.exefile) - ex = FileName::combine(".", ex); - else - ex = global.params.exefile; - return spawnv(0,ex,(char **)argv.data); -#elif linux - pid_t childpid; - int status; - - childpid = fork(); - if (childpid == 0) - { - char *fn = (char *)argv.data[0]; - if (!FileName::absolute(fn)) - { // Make it "./fn" - fn = FileName::combine(".", fn); - } - execv(fn, (char **)argv.data); - perror(fn); // failed to execute - return -1; - } - - waitpid(childpid, &status, 0); - - status = WEXITSTATUS(status); - return status; -#else - assert(0); -#endif -} + + +// Copyright (c) 1999-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + + +#include +#include +#include +#include +#include +#include + +#if _WIN32 +#include +#endif + +#if linux +#include +#include +#include +#endif + +#include "root.h" + +#include "mars.h" + +#include "mem.h" + +int executecmd(char *cmd, char *args, int useenv); +int executearg0(char *cmd, char *args); + +/***************************** + * Run the linker. Return status of execution. + */ + +int runLINK() +{ +#if _WIN32 + assert(0 && "linking not done for win32"); + + char *p; + int i; + int status; + OutBuffer cmdbuf; + + global.params.libfiles->push((void *) "user32"); + global.params.libfiles->push((void *) "kernel32"); + + for (i = 0; i < global.params.objfiles->dim; i++) + { + if (i) + cmdbuf.writeByte('+'); + p = (char *)global.params.objfiles->data[i]; + char *ext = FileName::ext(p); + if (ext) + cmdbuf.write(p, ext - p - 1); + else + cmdbuf.writestring(p); + } + cmdbuf.writeByte(','); + if (global.params.exefile) + cmdbuf.writestring(global.params.exefile); + else + { // Generate exe file name from first obj name + char *n = (char *)global.params.objfiles->data[0]; + char *ex; + + n = FileName::name(n); + FileName *fn = FileName::forceExt(n, "exe"); + global.params.exefile = fn->toChars(); + } + + // Make sure path to exe file exists + { char *p = FileName::path(global.params.exefile); + FileName::ensurePathExists(p); + mem.free(p); + } + + cmdbuf.writeByte(','); + if (global.params.run) + cmdbuf.writestring("nul"); +// if (mapfile) +// cmdbuf.writestring(output); + cmdbuf.writeByte(','); + + for (i = 0; i < global.params.libfiles->dim; i++) + { + if (i) + cmdbuf.writeByte('+'); + cmdbuf.writestring((char *) global.params.libfiles->data[i]); + } + + if (global.params.deffile) + { + cmdbuf.writeByte(','); + cmdbuf.writestring(global.params.deffile); + } + + /* Eliminate unnecessary trailing commas */ + while (1) + { i = cmdbuf.offset; + if (!i || cmdbuf.data[i - 1] != ',') + break; + cmdbuf.offset--; + } + + if (global.params.resfile) + { + cmdbuf.writestring("/RC:"); + cmdbuf.writestring(global.params.resfile); + } + +#if 0 + if (mapfile) + cmdbuf.writestring("/m"); + if (debuginfo) + cmdbuf.writestring("/li"); + if (codeview) + { + cmdbuf.writestring("/co"); + if (codeview3) + cmdbuf.writestring(":3"); + } +#else + if (global.params.symdebug) + cmdbuf.writestring("/co"); +#endif + + cmdbuf.writestring("/noi"); + for (i = 0; i < global.params.linkswitches->dim; i++) + { + cmdbuf.writestring((char *) global.params.linkswitches->data[i]); + } + cmdbuf.writeByte(';'); + + p = cmdbuf.toChars(); + + FileName *lnkfilename = NULL; + size_t plen = strlen(p); + if (plen > 7000) + { + lnkfilename = FileName::forceExt(global.params.exefile, "lnk"); + File flnk(lnkfilename); + flnk.setbuffer(p, plen); + flnk.ref = 1; + if (flnk.write()) + error("error writing file %s", lnkfilename); + if (lnkfilename->len() < plen) + sprintf(p, "@%s", lnkfilename->toChars()); + } + + char *linkcmd = getenv("LINKCMD"); + if (!linkcmd) + linkcmd = "link"; + status = executecmd(linkcmd, p, 1); + if (lnkfilename) + { + remove(lnkfilename->toChars()); + delete lnkfilename; + } + return status; +#elif linux + pid_t childpid; + int i; + int status; + + // Build argv[] + Array argv; + + //char *cc = getenv("CC"); + //if (!cc) + //cc = "gcc"; + char *cc = "llvm-ld"; + argv.push((void *)cc); + + // None of that a.out stuff. Use explicit exe file name, or + // generate one from name of first source file. + OutBuffer* exestr = new OutBuffer; + if (global.params.exefile) + { + exestr->printf("-o=%s", global.params.exefile); + argv.push(exestr->toChars()); + } + else + { // Generate exe file name from first obj name + char *n = (char *)global.params.objfiles->data[0]; + char *e; + char *ex; + + n = FileName::name(n); + e = FileName::ext(n); + if (e) + { + e--; // back up over '.' + ex = (char *)mem.malloc(e - n + 1); + memcpy(ex, n, e - n); + ex[e - n] = 0; + } + else + ex = (char *)"a.out"; // no extension, so give up + exestr->printf("-o=%s", ex); + ex = exestr->toChars(); + argv.push(ex); + global.params.exefile = ex; + } + + // Make sure path to exe file exists + { char *p = FileName::path(global.params.exefile); + FileName::ensurePathExists(p); + mem.free(p); + } + + argv.insert(argv.dim, global.params.libfiles); + + if (!global.params.symdebug) + argv.push((void *)"-strip-debug"); + + //argv.push((void *)"-m32"); + + + if (!global.params.optimize) + argv.push((void *)"-disable-opt"); + else { + const char* s = 0; + switch(global.params.optimizeLevel) { + case 0: + s = "-O0"; break; + case 1: + s = "-O1"; break; + case 2: + s = "-O2"; break; + case 3: + s = "-O3"; break; + case 4: + s = "-O4"; break; + case 5: + s = "-O5"; break; + default: + assert(0); + } + argv.push((void*)s); + } + + if (!(global.params.useInline || global.params.llvmInline)) { + argv.push((void *)"-disable-inlining"); + } + +#if 0 + if (0 && global.params.exefile) + { + /* This switch enables what is known as 'smart linking' + * in the Windows world, where unreferenced sections + * are removed from the executable. It eliminates unreferenced + * functions, essentially making a 'library' out of a module. + * Although it is documented to work with ld version 2.13, + * in practice it does not, but just seems to be ignored. + * Thomas Kuehne has verified that it works with ld 2.16.1. + * BUG: disabled because it causes exception handling to fail + */ + argv.push((void *)"-Xlinker"); + argv.push((void *)"--gc-sections"); + } +#endif + + for (i = 0; i < global.params.linkswitches->dim; i++) + { char *p = (char *)global.params.linkswitches->data[i]; + //if (!p || !p[0] || !(p[0] == '-' && p[1] == 'l')) + //{ // Don't need -Xlinker if switch starts with -l + // argv.push((void *)"-Xlinker"); + //} + argv.push((void *) p); + } + + argv.push((void*)"-native"); + + /* Standard libraries must go after user specified libraries + * passed with -l. + */ + + argv.push((void*)"-ltango-base-c-llvmdc"); + argv.push((void*)"-lpthread"); + argv.push((void*)"-ldl"); + argv.push((void*)"-lm"); + + argv.append(global.params.objfiles); + + std::string runtime_path(global.params.runtimePath); + if (*runtime_path.rbegin() != '/') + runtime_path.append("/"); + runtime_path.append("libtango-base-llvmdc.a"); + argv.push((void*)runtime_path.c_str()); + + if (!global.params.quiet || global.params.verbose) + { + // Print it + for (i = 0; i < argv.dim; i++) + printf("%s ", (char *)argv.data[i]); + printf("\n"); + fflush(stdout); + } + + argv.push(NULL); + childpid = fork(); + if (childpid == 0) + { + execvp((char *)argv.data[0], (char **)argv.data); + perror((char *)argv.data[0]); // failed to execute + return -1; + } + + waitpid(childpid, &status, 0); + + status=WEXITSTATUS(status); + if (status) + printf("--- errorlevel %d\n", status); + return status; +#else + printf ("Linking is not yet supported for this version of LLVMDMD.\n"); + return -1; +#endif +} + +/********************************** + * Delete generated EXE file. + */ + +void deleteExeFile() +{ + if (global.params.exefile) + { + //printf("deleteExeFile() %s\n", global.params.exefile); + remove(global.params.exefile); + } +} + +/****************************** + * Execute a rule. Return the status. + * cmd program to run + * args arguments to cmd, as a string + * useenv if cmd knows about _CMDLINE environment variable + */ + +#if _WIN32 +int executecmd(char *cmd, char *args, int useenv) +{ + int status; + char *buff; + size_t len; + + if (!global.params.quiet || global.params.verbose) + { + printf("%s %s\n", cmd, args); + fflush(stdout); + } + + if ((len = strlen(args)) > 255) + { char *q; + static char envname[] = "@_CMDLINE"; + + envname[0] = '@'; + switch (useenv) + { case 0: goto L1; + case 2: envname[0] = '%'; break; + } + q = (char *) alloca(sizeof(envname) + len + 1); + sprintf(q,"%s=%s", envname + 1, args); + status = putenv(q); + if (status == 0) + args = envname; + else + { + L1: + error("command line length of %d is too long",len); + } + } + + status = executearg0(cmd,args); +#if _WIN32 + if (status == -1) + status = spawnlp(0,cmd,cmd,args,NULL); +#endif +// if (global.params.verbose) +// printf("\n"); + if (status) + { + if (status == -1) + printf("Can't run '%s', check PATH\n", cmd); + else + printf("--- errorlevel %d\n", status); + } + return status; +} +#endif + +/************************************** + * Attempt to find command to execute by first looking in the directory + * where DMD was run from. + * Returns: + * -1 did not find command there + * !=-1 exit status from command + */ + +#if _WIN32 +int executearg0(char *cmd, char *args) +{ + char *file; + char *argv0 = global.params.argv0; + + //printf("argv0='%s', cmd='%s', args='%s'\n",argv0,cmd,args); + + // If cmd is fully qualified, we don't do this + if (FileName::absolute(cmd)) + return -1; + + file = FileName::replaceName(argv0, cmd); + + //printf("spawning '%s'\n",file); +#if _WIN32 + return spawnl(0,file,file,args,NULL); +#elif linux + char *full; + int cmdl = strlen(cmd); + + full = (char*) mem.malloc(cmdl + strlen(args) + 2); + if (full == NULL) + return 1; + strcpy(full, cmd); + full [cmdl] = ' '; + strcpy(full + cmdl + 1, args); + + int result = system(full); + + mem.free(full); + return result; +#else + assert(0); +#endif +} +#endif + +/*************************************** + * Run the compiled program. + * Return exit status. + */ + +int runProgram() +{ + //printf("runProgram()\n"); + if (global.params.verbose) + { + printf("%s", global.params.exefile); + for (size_t i = 0; i < global.params.runargs_length; i++) + printf(" %s", (char *)global.params.runargs[i]); + printf("\n"); + } + + // Build argv[] + Array argv; + + argv.push((void *)global.params.exefile); + for (size_t i = 0; i < global.params.runargs_length; i++) + { char *a = global.params.runargs[i]; + +#if _WIN32 + // BUG: what about " appearing in the string? + if (strchr(a, ' ')) + { char *b = (char *)mem.malloc(3 + strlen(a)); + sprintf(b, "\"%s\"", a); + a = b; + } +#endif + argv.push((void *)a); + } + argv.push(NULL); + +#if _WIN32 + char *ex = FileName::name(global.params.exefile); + if (ex == global.params.exefile) + ex = FileName::combine(".", ex); + else + ex = global.params.exefile; + return spawnv(0,ex,(char **)argv.data); +#elif linux + pid_t childpid; + int status; + + childpid = fork(); + if (childpid == 0) + { + char *fn = (char *)argv.data[0]; + if (!FileName::absolute(fn)) + { // Make it "./fn" + fn = FileName::combine(".", fn); + } + execv(fn, (char **)argv.data); + perror(fn); // failed to execute + return -1; + } + + waitpid(childpid, &status, 0); + + status = WEXITSTATUS(status); + return status; +#else + assert(0); +#endif +} diff --git a/dmd/mars.c b/dmd/mars.c index 53beb484..1e7152c2 100644 --- a/dmd/mars.c +++ b/dmd/mars.c @@ -1,1215 +1,1219 @@ -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include "llvm/Target/TargetMachineRegistry.h" - -#include -#include -#include -#include -#include -#include -#include - -#if _WIN32 -#include -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); -#endif - -#if __DMC__ -#include -#endif - -#if linux -#include -#endif - -#include "mem.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 "gen/logger.h" - -void getenv_setargv(const char *envvar, int *pargc, char** *pargv); - -Global global; - -Global::Global() -{ - mars_ext = "d"; - sym_ext = "d"; - hdr_ext = "di"; - doc_ext = "html"; - ddoc_ext = "ddoc"; - -#if IN_LLVM - obj_ext = "bc"; - ll_ext = "ll"; - bc_ext = "bc"; - nativeobj_ext = "o"; -#elif _WIN32 - obj_ext = "obj"; -#elif linux - obj_ext = "o"; -#else -#error "fix this" -#endif - - copyright = "Copyright (c) 1999-2008 by Digital Mars and Tomas Lindquist Olsen"; - written = "written by Walter Bright and Tomas Lindquist Olsen"; - llvmdc_version = "0.1"; - version = "v1.026"; - global.structalign = 8; - - memset(¶ms, 0, sizeof(Param)); -} - -char *Loc::toChars() const -{ - OutBuffer buf; - char *p; - - 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; -} - -/************************************** - * Print error message and exit. - */ - -void error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end( ap ); -} - -void verror(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - { - char *p = loc.toChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Error: "); - vfprintf(stdmsg, format, ap); - fprintf(stdmsg, "\n"); - fflush(stdmsg); - } - global.errors++; -} - -/*************************************** - * 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 - *(char*)0=0; -#endif -} - -extern void backend_init(); -extern void backend_term(); - -void usage() -{ - printf("LLVM D Compiler %s (based on DMD %s and LLVM 2.2)\n%s\n%s\n", - global.llvmdc_version, global.version, global.copyright, global.written); - printf("\ -D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n\ -LLVMDC Homepage: http://www.dsource.org/projects/llvmdc\n\ -Usage:\n\ - dmd files.d ... { -switch }\n\ -\n\ - files.d D source files\n%s\ - -annotate annotate the bitcode with human readable source code\n\ - -c do not link\n\ - -cov do code coverage analysis\n\ - -D generate documentation\n\ - -Dd write documentation file to directory\n\ - -Df write documentation file to \n\ - -d allow deprecated features\n\ - -debug compile in debug code\n\ - -debug=level compile in debug code <= level\n\ - -debug=ident compile in debug code identified by ident\n\ - -debuglib=name set symbolic debug library to name\n\ - -defaultlib=name set default library to name\n\ - -dis disassemble module after compiling\n\ - -g add symbolic debug info\n\ - -gc add symbolic debug info, pretend to be C\n\ - -H generate 'header' file\n\ - -Hd write 'header' file to directory\n\ - -Hf write 'header' file to \n\ - --help print help\n\ - -I where to look for imports\n\ - -J where to look for string imports\n\ - -inline do function inlining\n\ - -Llinkerflag pass linkerflag to link\n\ - -m emit code specific to \n\ - x86 x86-64 ppc32 ppc64\n\ - -nofloat do not emit reference to floating point\n\ - -noruntime do not allow code that generates implicit runtime calls\n\ - -noverify do not run the validation pass before writing bitcode\n\ - -O optimize, same as -O2\n\ - -O optimize at level (0-5)\n\ - -o- do not write object file\n\ - -od write object files to directory \n\ - -of name output file to \n\ - -op do not strip paths from source file\n\ - -profile profile runtime performance of generated code\n\ - -quiet suppress unnecessary messages\n\ - -release compile release version\n\ - -run srcfile args... run resulting program, passing args\n\ - -R provide path to the directory containing the runtime library\n\ - -unittest compile in unit tests\n\ - -v verbose\n\ - -vv very verbose (does not include -v)\n\ - -v1 D language version 1\n\ - -version=level compile in version code >= level\n\ - -version=ident compile in version code identified by ident\n\ - -w enable warnings\n\ -", -#if WIN32 -" @cmdfile read arguments from cmdfile\n" -#else -"" -#endif -); -} - -int main(int argc, char *argv[]) -{ - int i; - Array files; - char *p; - Module *m; - int status = EXIT_SUCCESS; - int argcstart = argc; - char* tt_arch = 0; - char* tt_os = 0; - char* data_layout = 0; - bool very_verbose = false; - - // Check for malformed input - if (argc < 1 || !argv) - { - Largs: - error("missing or null command line arguments"); - fatal(); - } - for (i = 0; i < argc; i++) - { - if (!argv[i]) - goto Largs; - } - -#if __DMC__ // DMC unique support for response files - if (response_expand(&argc,&argv)) // expand response files - error("can't open response file"); -#endif - - files.reserve(argc - 1); - - // Set default values - global.params.argv0 = argv[0]; - global.params.link = 1; - global.params.useAssert = 0; - global.params.useInvariants = 0; - global.params.useIn = 1; - global.params.useOut = 1; - global.params.useArrayBounds = 0; - global.params.useSwitchError = 0; - global.params.useInline = 0; // this one messes things up to a point where codegen breaks - global.params.llvmInline = 0; // use this one instead to know if inline passes should be run - global.params.obj = 1; - global.params.Dversion = 2; - - global.params.linkswitches = new Array(); - global.params.libfiles = new Array(); - global.params.objfiles = new Array(); - global.params.ddocfiles = new Array(); - - global.params.is64bit = sizeof(void*) == 8 ? 1 : 0; - - uint16_t endiantest = 0xFF00; - uint8_t endianres = ((uint8_t*)&endiantest)[0]; - if (endianres == 0x00) - global.params.isLE = true; - else if (endianres == 0xFF) - global.params.isLE = false; - else { - error("Endian test is broken"); - fatal(); - } - - global.params.llvmArch = 0; - global.params.forceBE = 0; - global.params.noruntime = 0; - global.params.novalidate = 0; - global.params.optimizeLevel = -1; - global.params.runtimeImppath = 0; - - global.params.defaultlibname = "phobos"; - global.params.debuglibname = global.params.defaultlibname; - - // Predefine version identifiers -#if IN_LLVM - VersionCondition::addPredefinedGlobalIdent("LLVM"); - VersionCondition::addPredefinedGlobalIdent("LLVMDC"); - VersionCondition::addPredefinedGlobalIdent("Posix"); -#endif -#if _WIN32 - VersionCondition::addPredefinedGlobalIdent("Windows"); - VersionCondition::addPredefinedGlobalIdent("Win32"); - global.params.isWindows = 1; -#elif linux - VersionCondition::addPredefinedGlobalIdent("linux"); - global.params.isLinux = 1; - tt_os = "-unknown-linux-gnu"; -#else -#error -#endif /* linux */ - - //VersionCondition::addPredefinedGlobalIdent("D_Bits"); - //VersionCondition::addPredefinedGlobalIdent("D_InlineAsm"); - //VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86"); - VersionCondition::addPredefinedGlobalIdent("all"); - -#if _WIN32 - inifile(argv[0], "llvmdc.ini"); -#endif -#if linux - inifile(argv[0], "llvmdc.conf"); -#else -#error -#endif - getenv_setargv("DFLAGS", &argc, &argv); - -#if 0 - for (i = 0; i < argc; i++) - { - printf("argv[%d] = '%s'\n", i, argv[i]); - } -#endif - - for (i = 1; i < argc; i++) - { - p = argv[i]; - if (*p == '-') - { - if (strcmp(p + 1, "d") == 0) - global.params.useDeprecated = 1; - else if (strcmp(p + 1, "c") == 0) - global.params.link = 0; - else if (strcmp(p + 1, "cov") == 0) - global.params.cov = 1; - else if (strcmp(p + 1, "fPIC") == 0) - global.params.pic = 1; - else if (strcmp(p + 1, "g") == 0) - global.params.symdebug = 1; - else if (strcmp(p + 1, "gc") == 0) - global.params.symdebug = 2; - else if (strcmp(p + 1, "gt") == 0) - { error("use -profile instead of -gt\n"); - global.params.trace = 1; - } - else if (strcmp(p + 1, "profile") == 0) - global.params.trace = 1; - else if (strcmp(p + 1, "v") == 0) - global.params.verbose = 1; - else if (strcmp(p + 1, "vv") == 0) { - Logger::enable(); - very_verbose = true; - } - else if (strcmp(p + 1, "v1") == 0) - global.params.Dversion = 1; - else if (strcmp(p + 1, "w") == 0) - global.params.warnings = 1; - else if (p[1] == 'O') - { - global.params.optimize = 1; - global.params.optimizeLevel = 2; - if (p[2] != 0) { - int optlevel = atoi(p+2); - if (optlevel < 0 || optlevel > 5) { - error("Optimization level must be between 0 and 5. Using default (%d)", - global.params.optimizeLevel); - } - else { - global.params.optimizeLevel = optlevel; - } - } - } - else if (strcmp(p + 1, "forcebe") == 0) - global.params.forceBE = 1; - else if (strcmp(p + 1, "noruntime") == 0) - global.params.noruntime = 1; - else if (strcmp(p + 1, "noverify") == 0) - global.params.novalidate = 1; - else if (strcmp(p + 1, "dis") == 0) - global.params.disassemble = 1; - else if (strcmp(p + 1, "annotate") == 0) - global.params.llvmAnnotate = 1; - else if (p[1] == 'o') - { - switch (p[2]) - { - case '-': - global.params.obj = 0; - break; - - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.objdir = p + 3; - break; - - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.objname = p + 3; - break; - - case 'p': - if (p[3]) - goto Lerror; - global.params.preservePaths = 1; - break; - - case 0: - error("-o no longer supported, use -of or -od"); - break; - - default: - goto Lerror; - } - } - else if (p[1] == 'D') - { global.params.doDocComments = 1; - switch (p[2]) - { - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.docdir = p + 3; - break; - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.docname = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } -#ifdef _DH - else if (p[1] == 'H') - { global.params.doHdrGeneration = 1; - switch (p[2]) - { - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.hdrdir = p + 3; - break; - - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.hdrname = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } -#endif - else if (strcmp(p + 1, "inline") == 0) { - // TODO - // the ast rewrites dmd does for inlining messes up the ast. - // someday maybe we can support it, for now llvm does an excellent job at inlining - global.params.useInline = 0; //1 - global.params.llvmInline = 1; - } - else if (strcmp(p + 1, "nofloat") == 0) - global.params.nofloat = 1; - else if (strcmp(p + 1, "quiet") == 0) - global.params.quiet = 1; - else if (strcmp(p + 1, "release") == 0) - global.params.release = 1; - else if (strcmp(p + 1, "unittest") == 0) - global.params.useUnitTests = 1; - else if (p[1] == 'I') - { - if (!global.params.imppath) - global.params.imppath = new Array(); - global.params.imppath->push(p + 2); - } - else if (p[1] == 'J') - { - if (!global.params.fileImppath) - global.params.fileImppath = new Array(); - global.params.fileImppath->push(p + 2); - } - else if (p[1] == 'R') - { - global.params.runtimePath = p+2; - } - else if (memcmp(p + 1, "debug", 5) == 0 && p[6] != 'l') - { - // Parse: - // -debug - // -debug=number - // -debug=identifier - if (p[6] == '=') - { - if (isdigit(p[7])) - { long level; - - errno = 0; - level = strtol(p + 7, &p, 10); - if (*p || errno || level > INT_MAX) - goto Lerror; - DebugCondition::setGlobalLevel((int)level); - } - else if (Lexer::isValidIdentifier(p + 7)) - DebugCondition::addGlobalIdent(p + 7); - else - goto Lerror; - } - else if (p[6]) - goto Lerror; - else - global.params.debuglevel = 1; - } - else if (memcmp(p + 1, "version", 5) == 0) - { - // Parse: - // -version=number - // -version=identifier - if (p[8] == '=') - { - if (isdigit(p[9])) - { long level; - - errno = 0; - level = strtol(p + 9, &p, 10); - if (*p || errno || level > INT_MAX) - goto Lerror; - VersionCondition::setGlobalLevel((int)level); - } - else if (Lexer::isValidIdentifier(p + 9)) - VersionCondition::addGlobalIdent(p + 9); - else - goto Lerror; - } - else - goto Lerror; - } - else if (strcmp(p + 1, "-b") == 0) - global.params.debugb = 1; - else if (strcmp(p + 1, "-c") == 0) - global.params.debugc = 1; - else if (strcmp(p + 1, "-f") == 0) - global.params.debugf = 1; - else if (strcmp(p + 1, "-help") == 0) - { usage(); - exit(EXIT_SUCCESS); - } - else if (strcmp(p + 1, "-r") == 0) - global.params.debugr = 1; - else if (strcmp(p + 1, "-x") == 0) - global.params.debugx = 1; - else if (strcmp(p + 1, "-y") == 0) - global.params.debugy = 1; - else if (p[1] == 'L') - { - global.params.linkswitches->push(p + 2); - } - else if (memcmp(p + 1, "defaultlib=", 11) == 0) - { - global.params.defaultlibname = p + 1 + 11; - } - else if (memcmp(p + 1, "debuglib=", 9) == 0) - { - global.params.debuglibname = p + 1 + 9; - } - else if (strcmp(p + 1, "run") == 0) - { global.params.run = 1; - global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1; - if (global.params.runargs_length) - { - files.push(argv[i + 1]); - global.params.runargs = &argv[i + 2]; - i += global.params.runargs_length; - global.params.runargs_length--; - } - else - { global.params.run = 0; - goto Lnoarg; - } - } - else if (p[1] == 'm') - { - global.params.llvmArch = p+2; - } - else - { - Lerror: - error("unrecognized switch '%s'", argv[i]); - continue; - - Lnoarg: - error("argument expected for switch '%s'", argv[i]); - continue; - } - } - else - files.push(p); - } - if (global.errors) - { - fatal(); - } - if (files.dim == 0) - { usage(); - return EXIT_FAILURE; - } - - if (global.params.release) - { global.params.useInvariants = 0; - global.params.useIn = 0; - global.params.useOut = 0; - global.params.useAssert = 0; - global.params.useArrayBounds = 0; - global.params.useSwitchError = 0; - } - - if (global.params.run) - global.params.quiet = 1; - - if (global.params.useUnitTests) - global.params.useAssert = 1; - - if (!global.params.obj) - global.params.link = 0; - - if (global.params.link) - { - global.params.exefile = global.params.objname; - global.params.objname = NULL; - } - else if (global.params.run) - { - error("flags conflict with -run"); - fatal(); - } - else - { - if (global.params.objname && files.dim > 1) - { - error("multiple source files, but only one .obj name"); - fatal(); - } - } - if (global.params.cov) - VersionCondition::addPredefinedGlobalIdent("D_Coverage"); - - bool allowForceEndianness = false; - - if (global.params.llvmArch == 0) { - std::string err_str; - const llvm::TargetMachineRegistry::entry* e = llvm::TargetMachineRegistry::getClosestTargetForJIT(err_str); - if (e == 0) { - error("Failed to find a default target machine: %s", err_str.c_str()); - fatal(); - } - else { - global.params.llvmArch = const_cast(e->Name); - if (global.params.verbose || very_verbose) - printf("Default target found: %s\n", global.params.llvmArch); - if (very_verbose) { - int X = sizeof(va_list); - printf("valist.sizeof = %d\n", X); - } - } - } - - if (strcmp(global.params.llvmArch,"x86")==0) { - VersionCondition::addPredefinedGlobalIdent("X86"); - //VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86"); - global.params.isLE = true; - global.params.is64bit = false; - tt_arch = "i686"; - data_layout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:8"; - } - else if (strcmp(global.params.llvmArch,"x86-64")==0) { - VersionCondition::addPredefinedGlobalIdent("X86_64"); - //VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86_64"); - global.params.isLE = true; - global.params.is64bit = true; - tt_arch = "x86_64"; - data_layout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:8"; - } - else if (strcmp(global.params.llvmArch,"ppc32")==0) { - VersionCondition::addPredefinedGlobalIdent("PPC"); - global.params.isLE = false; - global.params.is64bit = false; - tt_arch = "powerpc"; - data_layout = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:8"; - } - else if (strcmp(global.params.llvmArch,"ppc64")==0) { - VersionCondition::addPredefinedGlobalIdent("PPC64"); - global.params.isLE = false; - global.params.is64bit = true; - tt_arch = "powerpc64"; - data_layout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:8"; - } - else { - assert(0 && "Invalid arch"); - } - - if (allowForceEndianness && global.params.forceBE) { - VersionCondition::addPredefinedGlobalIdent("BigEndian"); - global.params.isLE = false; - } - else if (global.params.isLE) { - VersionCondition::addPredefinedGlobalIdent("LittleEndian"); - } - else { - VersionCondition::addPredefinedGlobalIdent("BigEndian"); - } - - if (global.params.is64bit) { - VersionCondition::addPredefinedGlobalIdent("LLVM64"); - } - - assert(tt_arch != 0); - assert(tt_os != 0); - assert(data_layout != 0); - global.params.tt_arch = tt_arch; - global.params.tt_os = tt_os; - global.params.data_layout = data_layout; - - // Initialization - Type::init(); - Id::initialize(); - Module::init(); - initPrecedence(); - - backend_init(); - - //printf("%d source files\n",files.dim); - - // Build import search path - if (global.params.imppath) - { - for (i = 0; i < global.params.imppath->dim; i++) - { - char *path = (char *)global.params.imppath->data[i]; - Array *a = FileName::splitPath(path); - - if (a) - { - if (!global.path) - global.path = new Array(); - global.path->append(a); - } - } - } - - // Build string import search path - if (global.params.fileImppath) - { - for (i = 0; i < global.params.fileImppath->dim; i++) - { - char *path = (char *)global.params.fileImppath->data[i]; - Array *a = FileName::splitPath(path); - - if (a) - { - if (!global.filePath) - global.filePath = new Array(); - global.filePath->append(a); - } - } - } - - // Create Modules - Array modules; - modules.reserve(files.dim); - for (i = 0; i < files.dim; i++) - { Identifier *id; - char *ext; - char *name; - - p = (char *) files.data[i]; - -#if _WIN32 - // Convert / to \ so linker will work - for (int i = 0; p[i]; i++) - { - if (p[i] == '/') - p[i] = '\\'; - } -#endif - - p = FileName::name(p); // strip path - ext = FileName::ext(p); - if (ext) - { -#if IN_LLVM - if (strcmp(ext, global.nativeobj_ext) == 0 || - strcmp(ext, global.obj_ext) == 0) -#elif TARGET_LINUX - if (strcmp(ext, global.obj_ext) == 0) -#else - if (stricmp(ext, global.obj_ext) == 0) -#endif - { - global.params.objfiles->push(files.data[i]); - continue; - } - -#if TARGET_LINUX - if (strcmp(ext, "a") == 0) -#else - if (stricmp(ext, "lib") == 0) -#endif - { - global.params.libfiles->push(files.data[i]); - continue; - } - - if (strcmp(ext, global.ddoc_ext) == 0) - { - global.params.ddocfiles->push(files.data[i]); - continue; - } - -#if !TARGET_LINUX - if (stricmp(ext, "res") == 0) - { - global.params.resfile = (char *)files.data[i]; - continue; - } - - if (stricmp(ext, "def") == 0) - { - global.params.deffile = (char *)files.data[i]; - continue; - } - - if (stricmp(ext, "exe") == 0) - { - global.params.exefile = (char *)files.data[i]; - continue; - } -#endif - - if (stricmp(ext, global.mars_ext) == 0 || - stricmp(ext, "htm") == 0 || - stricmp(ext, "html") == 0 || - stricmp(ext, "xhtml") == 0) - { - ext--; // skip onto '.' - assert(*ext == '.'); - name = (char *)mem.malloc((ext - p) + 1); - memcpy(name, p, ext - p); - name[ext - p] = 0; // strip extension - - if (name[0] == 0 || - strcmp(name, "..") == 0 || - strcmp(name, ".") == 0) - { - Linvalid: - error("invalid file name '%s'", (char *)files.data[i]); - fatal(); - } - } - else - { error("unrecognized file extension %s\n", ext); - fatal(); - } - } - else - { name = p; - if (!*name) - goto Linvalid; - } - - id = new Identifier(name, 0); - m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration); - modules.push(m); - - global.params.objfiles->push(m->objfile->name->str); - } - -#if _WIN32 - __try - { -#endif - // Read files, parse them - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("parse %s\n", m->toChars()); - if (!Module::rootModule) - Module::rootModule = m; - m->importedFrom = m; - m->deleteObjFile(); - m->read(0); - m->parse(); - if (m->isDocFile) - { - m->gendocfile(); - - // Remove m from list of modules - modules.remove(i); - i--; - - // Remove m's object file from list of object files - for (int j = 0; j < global.params.objfiles->dim; j++) - { - if (m->objfile->name->str == global.params.objfiles->data[j]) - { - global.params.objfiles->remove(j); - break; - } - } - - if (global.params.objfiles->dim == 0) - global.params.link = 0; - } - } - if (global.errors) - fatal(); -#ifdef _DH - if (global.params.doHdrGeneration) - { - /* Generate 'header' import files. - * Since 'header' import files must be independent of command - * line switches and what else is imported, they are generated - * before any semantic analysis. - */ - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("import %s\n", m->toChars()); - m->genhdrfile(); - } - } - if (global.errors) - fatal(); -#endif - - // Do semantic analysis - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("semantic %s\n", m->toChars()); - m->semantic(); - } - if (global.errors) - fatal(); - - // Do pass 2 semantic analysis - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("semantic2 %s\n", m->toChars()); - m->semantic2(); - } - if (global.errors) - fatal(); - - // Do pass 3 semantic analysis - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); - m->semantic3(); - } - if (global.errors) - fatal(); - -#if !IN_LLVM - // Scan for functions to inline - if (global.params.useInline) - { - /* The problem with useArrayBounds and useAssert is that the - * module being linked to may not have generated them, so if - * we inline functions from those modules, the symbols for them will - * not be found at link time. - */ - if (!global.params.useArrayBounds && !global.params.useAssert) - { -#endif - // Do pass 3 semantic analysis on all imported modules, - // since otherwise functions in them cannot be inlined - for (i = 0; i < Module::amodules.dim; i++) - { - m = (Module *)Module::amodules.data[i]; - if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); - m->semantic3(); - } - if (global.errors) - fatal(); -#if !IN_LLVM - } - - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("inline scan %s\n", m->toChars()); - m->inlineScan(); - } - } - if (global.errors) - fatal(); -#endif - - // Generate output files - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("code %s\n", m->toChars()); - if (global.params.obj) - m->genobjfile(); - if (global.errors) - m->deleteObjFile(); - else - { - if (global.params.doDocComments) - m->gendocfile(); - } - } -#if _WIN32 - } - __except (__ehfilter(GetExceptionInformation())) - { - printf("Stack overflow\n"); - fatal(); - } -#endif - backend_term(); - if (global.errors) - fatal(); - - if (!global.params.objfiles->dim) - { - if (global.params.link) - error("no object files to link"); - } - else - { - if (global.params.link) - status = runLINK(); - - if (global.params.run) - { - if (!status) - { - status = runProgram(); - - /* Delete .obj files and .exe file - */ - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - m->deleteObjFile(); - } - deleteExeFile(); - } - } - } - - return status; -} - - - -/*********************************** - * 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 *env; - char *p; - Array *argv; - int argc; - - int wildcard; // do wildcard expansion - int instring; - int slash; - char c; - int j; - - env = getenv(envvar); - if (!env) - return; - - env = mem.strdup(env); // create our own writable copy - - argc = *pargc; - argv = new Array(); - argv->setDim(argc); - - for (int i = 0; i < argc; i++) - argv->data[i] = (void *)(*pargv)[i]; - - j = 1; // leave argv[0] alone - while (1) - { - wildcard = 1; - 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: - *pargc = argc; - *pargv = (char **)argv->data; -} - -#if _WIN32 - -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep) -{ - //printf("%x\n", ep->ExceptionRecord->ExceptionCode); - if (ep->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) - { -#ifndef DEBUG - return EXCEPTION_EXECUTE_HANDLER; -#endif - } - return EXCEPTION_CONTINUE_SEARCH; -} - -#endif +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include "llvm/Target/TargetMachineRegistry.h" + +#include +#include +#include +#include +#include +#include +#include + +#if _WIN32 +#include +long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); +#endif + +#if __DMC__ +#include +#endif + +#if linux +#include +#endif + +#include "mem.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 "gen/logger.h" + +void getenv_setargv(const char *envvar, int *pargc, char** *pargv); + +Global global; + +Global::Global() +{ + mars_ext = "d"; + sym_ext = "d"; + hdr_ext = "di"; + doc_ext = "html"; + ddoc_ext = "ddoc"; + +#if IN_LLVM + obj_ext = "bc"; + ll_ext = "ll"; + bc_ext = "bc"; + nativeobj_ext = "o"; +#elif _WIN32 + obj_ext = "obj"; +#elif linux + obj_ext = "o"; +#else +#error "fix this" +#endif + + copyright = "Copyright (c) 1999-2008 by Digital Mars and Tomas Lindquist Olsen"; + written = "written by Walter Bright and Tomas Lindquist Olsen"; + version = "v1.029"; + llvmdc_version = "0.1"; + global.structalign = 8; + + memset(¶ms, 0, sizeof(Param)); +} + +char *Loc::toChars() const +{ + OutBuffer buf; + char *p; + + 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; +} + +/************************************** + * Print error message and exit. + */ + +void error(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + verror(loc, format, ap); + va_end( ap ); +} + +void verror(Loc loc, const char *format, va_list ap) +{ + if (!global.gag) + { + char *p = loc.toChars(); + + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + fprintf(stdmsg, "Error: "); + vfprintf(stdmsg, format, ap); + fprintf(stdmsg, "\n"); + fflush(stdmsg); + } + global.errors++; +} + +/*************************************** + * 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 + *(char*)0=0; +#endif +} + +extern void backend_init(); +extern void backend_term(); + +void usage() +{ + printf("LLVM D Compiler %s (based on DMD %s and LLVM 2.2)\n%s\n%s\n", + global.llvmdc_version, global.version, global.copyright, global.written); + printf("\ +D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n\ +LLVMDC Homepage: http://www.dsource.org/projects/llvmdc\n\ +Usage:\n\ + dmd files.d ... { -switch }\n\ +\n\ + files.d D source files\n%s\ + -annotate annotate the bitcode with human readable source code\n\ + -c do not link\n\ + -cov do code coverage analysis\n\ + -D generate documentation\n\ + -Dd write documentation file to directory\n\ + -Df write documentation file to \n\ + -d allow deprecated features\n\ + -debug compile in debug code\n\ + -debug=level compile in debug code <= level\n\ + -debug=ident compile in debug code identified by ident\n\ + -debuglib=name set symbolic debug library to name\n\ + -defaultlib=name set default library to name\n\ + -dis disassemble module after compiling\n\ + -g add symbolic debug info\n\ + -gc add symbolic debug info, pretend to be C\n\ + -H generate 'header' file\n\ + -Hd write 'header' file to directory\n\ + -Hf write 'header' file to \n\ + --help print help\n\ + -I where to look for imports\n\ + -J where to look for string imports\n\ + -ignore ignore unsupported pragmas\n\ + -inline do function inlining\n\ + -Llinkerflag pass linkerflag to link\n\ + -m emit code specific to \n\ + x86 x86-64 ppc32 ppc64\n\ + -nofloat do not emit reference to floating point\n\ + -noruntime do not allow code that generates implicit runtime calls\n\ + -noverify do not run the validation pass before writing bitcode\n\ + -O optimize, same as -O2\n\ + -O optimize at level (0-5)\n\ + -o- do not write object file\n\ + -od write object files to directory \n\ + -of name output file to \n\ + -op do not strip paths from source file\n\ + -profile profile runtime performance of generated code\n\ + -quiet suppress unnecessary messages\n\ + -release compile release version\n\ + -run srcfile args... run resulting program, passing args\n\ + -R provide path to the directory containing the runtime library\n\ + -unittest compile in unit tests\n\ + -v verbose\n\ + -vv very verbose (does not include -v)\n\ + -v1 D language version 1\n\ + -version=level compile in version code >= level\n\ + -version=ident compile in version code identified by ident\n\ + -w enable warnings\n\ +", +#if WIN32 +" @cmdfile read arguments from cmdfile\n" +#else +"" +#endif +); +} + +int main(int argc, char *argv[]) +{ + int i; + Array files; + char *p; + Module *m; + int status = EXIT_SUCCESS; + int argcstart = argc; + char* tt_arch = 0; + char* tt_os = 0; + char* data_layout = 0; + bool very_verbose = false; + + // Check for malformed input + if (argc < 1 || !argv) + { + Largs: + error("missing or null command line arguments"); + fatal(); + } + for (i = 0; i < argc; i++) + { + if (!argv[i]) + goto Largs; + } + +#if __DMC__ // DMC unique support for response files + if (response_expand(&argc,&argv)) // expand response files + error("can't open response file"); +#endif + + files.reserve(argc - 1); + + // Set default values + global.params.argv0 = argv[0]; + global.params.link = 1; + global.params.useAssert = 0; + global.params.useInvariants = 0; + global.params.useIn = 1; + global.params.useOut = 1; + global.params.useArrayBounds = 0; + global.params.useSwitchError = 0; + global.params.useInline = 0; // this one messes things up to a point where codegen breaks + global.params.llvmInline = 0; // use this one instead to know if inline passes should be run + global.params.obj = 1; + global.params.Dversion = 2; + global.params.quiet = 1; + + global.params.linkswitches = new Array(); + global.params.libfiles = new Array(); + global.params.objfiles = new Array(); + global.params.ddocfiles = new Array(); + + global.params.is64bit = sizeof(void*) == 8 ? 1 : 0; + + uint16_t endiantest = 0xFF00; + uint8_t endianres = ((uint8_t*)&endiantest)[0]; + if (endianres == 0x00) + global.params.isLE = true; + else if (endianres == 0xFF) + global.params.isLE = false; + else { + error("Endian test is broken"); + fatal(); + } + + global.params.llvmArch = 0; + global.params.forceBE = 0; + global.params.noruntime = 0; + global.params.novalidate = 0; + global.params.optimizeLevel = -1; + global.params.runtimeImppath = 0; + + global.params.defaultlibname = "phobos"; + global.params.debuglibname = global.params.defaultlibname; + + // Predefine version identifiers +#if IN_LLVM + VersionCondition::addPredefinedGlobalIdent("LLVM"); + VersionCondition::addPredefinedGlobalIdent("LLVMDC"); + VersionCondition::addPredefinedGlobalIdent("Posix"); +#endif +#if _WIN32 + VersionCondition::addPredefinedGlobalIdent("Windows"); + VersionCondition::addPredefinedGlobalIdent("Win32"); + global.params.isWindows = 1; +#elif linux + VersionCondition::addPredefinedGlobalIdent("linux"); + global.params.isLinux = 1; + tt_os = "-unknown-linux-gnu"; +#else +#error +#endif /* linux */ + + //VersionCondition::addPredefinedGlobalIdent("D_Bits"); + //VersionCondition::addPredefinedGlobalIdent("D_InlineAsm"); + //VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86"); + VersionCondition::addPredefinedGlobalIdent("all"); + +#if _WIN32 + inifile(argv[0], "llvmdc.ini"); +#endif +#if linux + inifile(argv[0], "llvmdc.conf"); +#else +#error +#endif + getenv_setargv("DFLAGS", &argc, &argv); + +#if 0 + for (i = 0; i < argc; i++) + { + printf("argv[%d] = '%s'\n", i, argv[i]); + } +#endif + + for (i = 1; i < argc; i++) + { + p = argv[i]; + if (*p == '-') + { + if (strcmp(p + 1, "d") == 0) + global.params.useDeprecated = 1; + else if (strcmp(p + 1, "c") == 0) + global.params.link = 0; + else if (strcmp(p + 1, "cov") == 0) + global.params.cov = 1; + else if (strcmp(p + 1, "fPIC") == 0) + global.params.pic = 1; + else if (strcmp(p + 1, "g") == 0) + global.params.symdebug = 1; + else if (strcmp(p + 1, "gc") == 0) + global.params.symdebug = 2; + else if (strcmp(p + 1, "gt") == 0) + { error("use -profile instead of -gt\n"); + global.params.trace = 1; + } + else if (strcmp(p + 1, "profile") == 0) + global.params.trace = 1; + else if (strcmp(p + 1, "v") == 0) + global.params.verbose = 1; + else if (strcmp(p + 1, "vv") == 0) { + Logger::enable(); + very_verbose = true; + } + else if (strcmp(p + 1, "v1") == 0) + global.params.Dversion = 1; + else if (strcmp(p + 1, "w") == 0) + global.params.warnings = 1; + else if (p[1] == 'O') + { + global.params.optimize = 1; + global.params.optimizeLevel = 2; + if (p[2] != 0) { + int optlevel = atoi(p+2); + if (optlevel < 0 || optlevel > 5) { + error("Optimization level must be between 0 and 5. Using default (%d)", + global.params.optimizeLevel); + } + else { + global.params.optimizeLevel = optlevel; + } + } + } + else if (strcmp(p + 1, "forcebe") == 0) + global.params.forceBE = 1; + else if (strcmp(p + 1, "noruntime") == 0) + global.params.noruntime = 1; + else if (strcmp(p + 1, "noverify") == 0) + global.params.novalidate = 1; + else if (strcmp(p + 1, "dis") == 0) + global.params.disassemble = 1; + else if (strcmp(p + 1, "annotate") == 0) + global.params.llvmAnnotate = 1; + else if (p[1] == 'o') + { + switch (p[2]) + { + case '-': + global.params.obj = 0; + break; + + case 'd': + if (!p[3]) + goto Lnoarg; + global.params.objdir = p + 3; + break; + + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.objname = p + 3; + break; + + case 'p': + if (p[3]) + goto Lerror; + global.params.preservePaths = 1; + break; + + case 0: + error("-o no longer supported, use -of or -od"); + break; + + default: + goto Lerror; + } + } + else if (p[1] == 'D') + { global.params.doDocComments = 1; + switch (p[2]) + { + case 'd': + if (!p[3]) + goto Lnoarg; + global.params.docdir = p + 3; + break; + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.docname = p + 3; + break; + + case 0: + break; + + default: + goto Lerror; + } + } +#ifdef _DH + else if (p[1] == 'H') + { global.params.doHdrGeneration = 1; + switch (p[2]) + { + case 'd': + if (!p[3]) + goto Lnoarg; + global.params.hdrdir = p + 3; + break; + + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.hdrname = p + 3; + break; + + case 0: + break; + + default: + goto Lerror; + } + } +#endif + else if (strcmp(p + 1, "ignore") == 0) + global.params.ignoreUnsupportedPragmas = 1; + else if (strcmp(p + 1, "inline") == 0) { + // TODO + // the ast rewrites dmd does for inlining messes up the ast. + // someday maybe we can support it, for now llvm does an excellent job at inlining + global.params.useInline = 0; //1 + global.params.llvmInline = 1; + } + else if (strcmp(p + 1, "nofloat") == 0) + global.params.nofloat = 1; + else if (strcmp(p + 1, "quiet") == 0) + global.params.quiet = 1; + else if (strcmp(p + 1, "release") == 0) + global.params.release = 1; + else if (strcmp(p + 1, "unittest") == 0) + global.params.useUnitTests = 1; + else if (p[1] == 'I') + { + if (!global.params.imppath) + global.params.imppath = new Array(); + global.params.imppath->push(p + 2); + } + else if (p[1] == 'J') + { + if (!global.params.fileImppath) + global.params.fileImppath = new Array(); + global.params.fileImppath->push(p + 2); + } + else if (p[1] == 'R') + { + global.params.runtimePath = p+2; + } + else if (memcmp(p + 1, "debug", 5) == 0 && p[6] != 'l') + { + // Parse: + // -debug + // -debug=number + // -debug=identifier + if (p[6] == '=') + { + if (isdigit(p[7])) + { long level; + + errno = 0; + level = strtol(p + 7, &p, 10); + if (*p || errno || level > INT_MAX) + goto Lerror; + DebugCondition::setGlobalLevel((int)level); + } + else if (Lexer::isValidIdentifier(p + 7)) + DebugCondition::addGlobalIdent(p + 7); + else + goto Lerror; + } + else if (p[6]) + goto Lerror; + else + global.params.debuglevel = 1; + } + else if (memcmp(p + 1, "version", 5) == 0) + { + // Parse: + // -version=number + // -version=identifier + if (p[8] == '=') + { + if (isdigit(p[9])) + { long level; + + errno = 0; + level = strtol(p + 9, &p, 10); + if (*p || errno || level > INT_MAX) + goto Lerror; + VersionCondition::setGlobalLevel((int)level); + } + else if (Lexer::isValidIdentifier(p + 9)) + VersionCondition::addGlobalIdent(p + 9); + else + goto Lerror; + } + else + goto Lerror; + } + else if (strcmp(p + 1, "-b") == 0) + global.params.debugb = 1; + else if (strcmp(p + 1, "-c") == 0) + global.params.debugc = 1; + else if (strcmp(p + 1, "-f") == 0) + global.params.debugf = 1; + else if (strcmp(p + 1, "-help") == 0) + { usage(); + exit(EXIT_SUCCESS); + } + else if (strcmp(p + 1, "-r") == 0) + global.params.debugr = 1; + else if (strcmp(p + 1, "-x") == 0) + global.params.debugx = 1; + else if (strcmp(p + 1, "-y") == 0) + global.params.debugy = 1; + else if (p[1] == 'L') + { + global.params.linkswitches->push(p + 2); + } + else if (memcmp(p + 1, "defaultlib=", 11) == 0) + { + global.params.defaultlibname = p + 1 + 11; + } + else if (memcmp(p + 1, "debuglib=", 9) == 0) + { + global.params.debuglibname = p + 1 + 9; + } + else if (strcmp(p + 1, "run") == 0) + { global.params.run = 1; + global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1; + if (global.params.runargs_length) + { + files.push(argv[i + 1]); + global.params.runargs = &argv[i + 2]; + i += global.params.runargs_length; + global.params.runargs_length--; + } + else + { global.params.run = 0; + goto Lnoarg; + } + } + else if (p[1] == 'm') + { + global.params.llvmArch = p+2; + } + else + { + Lerror: + error("unrecognized switch '%s'", argv[i]); + continue; + + Lnoarg: + error("argument expected for switch '%s'", argv[i]); + continue; + } + } + else + files.push(p); + } + if (global.errors) + { + fatal(); + } + if (files.dim == 0) + { usage(); + return EXIT_FAILURE; + } + + if (global.params.release) + { global.params.useInvariants = 0; + global.params.useIn = 0; + global.params.useOut = 0; + global.params.useAssert = 0; + global.params.useArrayBounds = 0; + global.params.useSwitchError = 0; + } + + if (global.params.run) + global.params.quiet = 1; + + if (global.params.useUnitTests) + global.params.useAssert = 1; + + if (!global.params.obj) + global.params.link = 0; + + if (global.params.link) + { + global.params.exefile = global.params.objname; + global.params.objname = NULL; + } + else if (global.params.run) + { + error("flags conflict with -run"); + fatal(); + } + else + { + if (global.params.objname && files.dim > 1) + { + error("multiple source files, but only one .obj name"); + fatal(); + } + } + if (global.params.cov) + VersionCondition::addPredefinedGlobalIdent("D_Coverage"); + + bool allowForceEndianness = false; + + if (global.params.llvmArch == 0) { + std::string err_str; + const llvm::TargetMachineRegistry::entry* e = llvm::TargetMachineRegistry::getClosestTargetForJIT(err_str); + if (e == 0) { + error("Failed to find a default target machine: %s", err_str.c_str()); + fatal(); + } + else { + global.params.llvmArch = const_cast(e->Name); + if (global.params.verbose || very_verbose) + printf("Default target found: %s\n", global.params.llvmArch); + if (very_verbose) { + int X = sizeof(va_list); + printf("valist.sizeof = %d\n", X); + } + } + } + + if (strcmp(global.params.llvmArch,"x86")==0) { + VersionCondition::addPredefinedGlobalIdent("X86"); + //VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86"); + global.params.isLE = true; + global.params.is64bit = false; + tt_arch = "i686"; + data_layout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:8"; + } + else if (strcmp(global.params.llvmArch,"x86-64")==0) { + VersionCondition::addPredefinedGlobalIdent("X86_64"); + //VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86_64"); + global.params.isLE = true; + global.params.is64bit = true; + tt_arch = "x86_64"; + data_layout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:8"; + } + else if (strcmp(global.params.llvmArch,"ppc32")==0) { + VersionCondition::addPredefinedGlobalIdent("PPC"); + global.params.isLE = false; + global.params.is64bit = false; + tt_arch = "powerpc"; + data_layout = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:8"; + } + else if (strcmp(global.params.llvmArch,"ppc64")==0) { + VersionCondition::addPredefinedGlobalIdent("PPC64"); + global.params.isLE = false; + global.params.is64bit = true; + tt_arch = "powerpc64"; + data_layout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:8"; + } + else { + assert(0 && "Invalid arch"); + } + + if (allowForceEndianness && global.params.forceBE) { + VersionCondition::addPredefinedGlobalIdent("BigEndian"); + global.params.isLE = false; + } + else if (global.params.isLE) { + VersionCondition::addPredefinedGlobalIdent("LittleEndian"); + } + else { + VersionCondition::addPredefinedGlobalIdent("BigEndian"); + } + + if (global.params.is64bit) { + VersionCondition::addPredefinedGlobalIdent("LLVM64"); + } + + assert(tt_arch != 0); + assert(tt_os != 0); + assert(data_layout != 0); + global.params.tt_arch = tt_arch; + global.params.tt_os = tt_os; + global.params.data_layout = data_layout; + + // Initialization + Type::init(); + Id::initialize(); + Module::init(); + initPrecedence(); + + backend_init(); + + //printf("%d source files\n",files.dim); + + // Build import search path + if (global.params.imppath) + { + for (i = 0; i < global.params.imppath->dim; i++) + { + char *path = (char *)global.params.imppath->data[i]; + Array *a = FileName::splitPath(path); + + if (a) + { + if (!global.path) + global.path = new Array(); + global.path->append(a); + } + } + } + + // Build string import search path + if (global.params.fileImppath) + { + for (i = 0; i < global.params.fileImppath->dim; i++) + { + char *path = (char *)global.params.fileImppath->data[i]; + Array *a = FileName::splitPath(path); + + if (a) + { + if (!global.filePath) + global.filePath = new Array(); + global.filePath->append(a); + } + } + } + + // Create Modules + Array modules; + modules.reserve(files.dim); + for (i = 0; i < files.dim; i++) + { Identifier *id; + char *ext; + char *name; + + p = (char *) files.data[i]; + +#if _WIN32 + // Convert / to \ so linker will work + for (int i = 0; p[i]; i++) + { + if (p[i] == '/') + p[i] = '\\'; + } +#endif + + p = FileName::name(p); // strip path + ext = FileName::ext(p); + if (ext) + { +#if IN_LLVM + if (strcmp(ext, global.nativeobj_ext) == 0 || + strcmp(ext, global.obj_ext) == 0) +#elif TARGET_LINUX + if (strcmp(ext, global.obj_ext) == 0) +#else + if (stricmp(ext, global.obj_ext) == 0) +#endif + { + global.params.objfiles->push(files.data[i]); + continue; + } + +#if TARGET_LINUX + if (strcmp(ext, "a") == 0) +#else + if (stricmp(ext, "lib") == 0) +#endif + { + global.params.libfiles->push(files.data[i]); + continue; + } + + if (strcmp(ext, global.ddoc_ext) == 0) + { + global.params.ddocfiles->push(files.data[i]); + continue; + } + +#if !TARGET_LINUX + if (stricmp(ext, "res") == 0) + { + global.params.resfile = (char *)files.data[i]; + continue; + } + + if (stricmp(ext, "def") == 0) + { + global.params.deffile = (char *)files.data[i]; + continue; + } + + if (stricmp(ext, "exe") == 0) + { + global.params.exefile = (char *)files.data[i]; + continue; + } +#endif + + if (stricmp(ext, global.mars_ext) == 0 || + stricmp(ext, "htm") == 0 || + stricmp(ext, "html") == 0 || + stricmp(ext, "xhtml") == 0) + { + ext--; // skip onto '.' + assert(*ext == '.'); + name = (char *)mem.malloc((ext - p) + 1); + memcpy(name, p, ext - p); + name[ext - p] = 0; // strip extension + + if (name[0] == 0 || + strcmp(name, "..") == 0 || + strcmp(name, ".") == 0) + { + Linvalid: + error("invalid file name '%s'", (char *)files.data[i]); + fatal(); + } + } + else + { error("unrecognized file extension %s\n", ext); + fatal(); + } + } + else + { name = p; + if (!*name) + goto Linvalid; + } + + id = new Identifier(name, 0); + m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration); + modules.push(m); + + global.params.objfiles->push(m->objfile->name->str); + } + +#if _WIN32 + __try + { +#endif + // Read files, parse them + for (i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("parse %s\n", m->toChars()); + if (!Module::rootModule) + Module::rootModule = m; + m->importedFrom = m; + m->deleteObjFile(); + m->read(0); + m->parse(); + if (m->isDocFile) + { + m->gendocfile(); + + // Remove m from list of modules + modules.remove(i); + i--; + + // Remove m's object file from list of object files + for (int j = 0; j < global.params.objfiles->dim; j++) + { + if (m->objfile->name->str == global.params.objfiles->data[j]) + { + global.params.objfiles->remove(j); + break; + } + } + + if (global.params.objfiles->dim == 0) + global.params.link = 0; + } + } + if (global.errors) + fatal(); +#ifdef _DH + if (global.params.doHdrGeneration) + { + /* Generate 'header' import files. + * Since 'header' import files must be independent of command + * line switches and what else is imported, they are generated + * before any semantic analysis. + */ + for (i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("import %s\n", m->toChars()); + m->genhdrfile(); + } + } + if (global.errors) + fatal(); +#endif + + // Do semantic analysis + for (i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("semantic %s\n", m->toChars()); + m->semantic(); + } + if (global.errors) + fatal(); + + // Do pass 2 semantic analysis + for (i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("semantic2 %s\n", m->toChars()); + m->semantic2(); + } + if (global.errors) + fatal(); + + // Do pass 3 semantic analysis + for (i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("semantic3 %s\n", m->toChars()); + m->semantic3(); + } + if (global.errors) + fatal(); + +#if !IN_LLVM + // Scan for functions to inline + if (global.params.useInline) + { + /* The problem with useArrayBounds and useAssert is that the + * module being linked to may not have generated them, so if + * we inline functions from those modules, the symbols for them will + * not be found at link time. + */ + if (!global.params.useArrayBounds && !global.params.useAssert) + { +#endif + // Do pass 3 semantic analysis on all imported modules, + // since otherwise functions in them cannot be inlined + for (i = 0; i < Module::amodules.dim; i++) + { + m = (Module *)Module::amodules.data[i]; + if (global.params.verbose) + printf("semantic3 %s\n", m->toChars()); + m->semantic3(); + } + if (global.errors) + fatal(); +#if !IN_LLVM + } + + for (i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("inline scan %s\n", m->toChars()); + m->inlineScan(); + } + } + if (global.errors) + fatal(); +#endif + + // Generate output files + for (i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("code %s\n", m->toChars()); + if (global.params.obj) + m->genobjfile(); + if (global.errors) + m->deleteObjFile(); + else + { + if (global.params.doDocComments) + m->gendocfile(); + } + } +#if _WIN32 + } + __except (__ehfilter(GetExceptionInformation())) + { + printf("Stack overflow\n"); + fatal(); + } +#endif + backend_term(); + if (global.errors) + fatal(); + + if (!global.params.objfiles->dim) + { + if (global.params.link) + error("no object files to link"); + } + else + { + if (global.params.link) + status = runLINK(); + + if (global.params.run) + { + if (!status) + { + status = runProgram(); + + /* Delete .obj files and .exe file + */ + for (i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + m->deleteObjFile(); + } + deleteExeFile(); + } + } + } + + return status; +} + + + +/*********************************** + * 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 *env; + char *p; + Array *argv; + int argc; + + int wildcard; // do wildcard expansion + int instring; + int slash; + char c; + int j; + + env = getenv(envvar); + if (!env) + return; + + env = mem.strdup(env); // create our own writable copy + + argc = *pargc; + argv = new Array(); + argv->setDim(argc); + + for (int i = 0; i < argc; i++) + argv->data[i] = (void *)(*pargv)[i]; + + j = 1; // leave argv[0] alone + while (1) + { + wildcard = 1; + 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: + *pargc = argc; + *pargv = (char **)argv->data; +} + +#if _WIN32 + +long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep) +{ + //printf("%x\n", ep->ExceptionRecord->ExceptionCode); + if (ep->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) + { +#ifndef DEBUG + return EXCEPTION_EXECUTE_HANDLER; +#endif + } + return EXCEPTION_CONTINUE_SEARCH; +} + +#endif diff --git a/dmd/mars.h b/dmd/mars.h index 182e32d0..717ba337 100644 --- a/dmd/mars.h +++ b/dmd/mars.h @@ -1,307 +1,308 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_MARS_H -#define DMD_MARS_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include -#include -#include - -#ifdef __DMC__ -#ifdef DEBUG -#undef assert -#define assert(e) (static_cast((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt()))) -#endif -#endif - -#ifdef IN_GCC -/* Changes for the GDC compiler by David Friedman */ -#endif - -#define V2 0 // Version 2.0 features -#define BREAKABI 1 // 0 if not ready to break the ABI just yet - -struct Array; - -// Put command line switches in here -struct Param -{ - char obj; // write object file - char link; // perform link - char trace; // insert profiling hooks - char quiet; // suppress non-error messages - char verbose; // verbose compile - char symdebug; // insert debug symbolic information - char optimize; // run optimizer - char optimizeLevel; // optimization level - char cpu; // target CPU - char is64bit; // generate 64 bit code - char isLE; // generate little endian code - char isLinux; // generate code for linux - char isWindows; // generate code for Windows - 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; // generate array bounds checks - 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; // enable warnings - char pic; // generate position-independent-code for shared libs - char cov; // generate code coverage data - char nofloat; // code should not pull in floating point support - char noruntime; // code is not allowed to make implicit calls to the runtime - char novalidate;// no bitcode validation - char Dversion; // D version number - - char *argv0; // program name - Array *imppath; // array of char*'s of where to look for import modules - Array *fileImppath; // array of char*'s of where to look for file import modules - char *runtimeImppath; // char* of where to look for the core runtime - char *objdir; // .obj file output directory - char *objname; // .obj file output name - - char doDocComments; // process embedded documentation comments - char *docdir; // write documentation file to docdir directory - char *docname; // write documentation file to docname - Array *ddocfiles; // macro include files for Ddoc - - char doHdrGeneration; // process embedded documentation comments - char *hdrdir; // write 'header' file to docdir directory - char *hdrname; // write 'header' file to docname - - unsigned debuglevel; // debug level - Array *debugids; // debug identifiers - - unsigned versionlevel; // version level - Array *versionids; // version identifiers - - bool dump_source; - - char *defaultlibname; // default library for non-debug builds - char *debuglibname; // default library for debug builds - - char *xmlname; // filename for XML output - - // Hidden debug switches - char debuga; - char debugb; - char debugc; - char debugf; - char debugr; - char debugw; - char debugx; - char debugy; - - char run; // run resulting executable - size_t runargs_length; - char** runargs; // arguments for executable - - // Linker stuff - Array *objfiles; - Array *linkswitches; - Array *libfiles; - char *deffile; - char *resfile; - char *exefile; - - // LLVM stuff - char *llvmArch; - char forceBE; - char *tt_arch; - char *tt_os; - char *data_layout; - char disassemble; - char llvmInline; - char llvmAnnotate; - char *runtimePath; -}; - -struct Global -{ - char *mars_ext; - char *sym_ext; - char *obj_ext; - char *ll_ext; - char *bc_ext; - char *nativeobj_ext; - char *doc_ext; // for Ddoc generated files - char *ddoc_ext; // for Ddoc macro include files - char *hdr_ext; // for D 'header' import files - char *copyright; - char *written; - Array *path; // Array of char*'s which form the import lookup path - Array *filePath; // Array of char*'s which form the file import lookup path - int structalign; - char *version; - char *llvmdc_version; - - Param params; - unsigned errors; // number of errors reported so far - unsigned gag; // !=0 means gag reporting of errors - - Global(); -}; - -extern Global global; - -#if __GNUC__ -//#define memicmp strncasecmp -//#define stricmp strcasecmp -#endif - -#ifdef __DMC__ - typedef _Complex long double complex_t; -#else - #ifndef IN_GCC - #include "complex_t.h" - #endif - #ifdef __APPLE__ - //#include "complex.h"//This causes problems with include the c++ and not the C "complex.h" - #define integer_t dmd_integer_t - #endif -#endif - -// Be careful not to care about sign when using integer_t -typedef uint64_t integer_t; - -// Signed and unsigned variants -typedef int64_t sinteger_t; -typedef uint64_t uinteger_t; - -typedef int8_t d_int8; -typedef uint8_t d_uns8; -typedef int16_t d_int16; -typedef uint16_t d_uns16; -typedef int32_t d_int32; -typedef uint32_t d_uns32; -typedef int64_t d_int64; -typedef uint64_t d_uns64; - -typedef float d_float32; -typedef double d_float64; -typedef long double d_float80; - -typedef d_uns8 d_char; -typedef d_uns16 d_wchar; -typedef d_uns32 d_dchar; - -#ifdef IN_GCC -#include "d-gcc-real.h" -#else -typedef long double real_t; -#endif - -// Modify OutBuffer::writewchar to write the correct size of wchar -#if _WIN32 -#define writewchar writeword -#else -// This needs a configuration test... -#define writewchar write4 -#endif - -#ifdef IN_GCC -#include "d-gcc-complex_t.h" -#endif - -struct Module; - -//typedef unsigned Loc; // file location -struct Loc -{ - char *filename; - unsigned linnum; - - Loc() - { - linnum = 0; - filename = NULL; - } - - Loc(int x) - { - linnum = x; - filename = NULL; - } - - Loc(Module *mod, unsigned linnum); - - char *toChars() const; -}; - -#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, -}; - -enum DYNCAST -{ - DYNCAST_OBJECT, - DYNCAST_EXPRESSION, - DYNCAST_DSYMBOL, - DYNCAST_TYPE, - DYNCAST_IDENTIFIER, - DYNCAST_TUPLE, -}; - -enum MATCH -{ - MATCHnomatch, // no match - MATCHconvert, // match with conversions -#if V2 - MATCHconst, // match with conversion to const -#endif - MATCHexact // exact match -}; - -void error(Loc loc, const char *format, ...); -void verror(Loc loc, const char *format, va_list); -void fatal(); -void err_nomem(); -int runLINK(); -void deleteExeFile(); -int runProgram(); -void inifile(char *argv0, char *inifile); -void halt(); - -/*** Where to send error messages ***/ -#if IN_GCC -#define stdmsg stderr -#else -#define stdmsg stdout -#endif - -#endif /* DMD_MARS_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_MARS_H +#define DMD_MARS_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include +#include +#include + +#ifdef __DMC__ +#ifdef DEBUG +#undef assert +#define assert(e) (static_cast((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt()))) +#endif +#endif + +#ifdef IN_GCC +/* Changes for the GDC compiler by David Friedman */ +#endif + +#define V2 0 // Version 2.0 features +#define BREAKABI 1 // 0 if not ready to break the ABI just yet + +struct Array; + +// Put command line switches in here +struct Param +{ + char obj; // write object file + char link; // perform link + char trace; // insert profiling hooks + char quiet; // suppress non-error messages + char verbose; // verbose compile + char symdebug; // insert debug symbolic information + char optimize; // run optimizer + char optimizeLevel; // optimization level + char cpu; // target CPU + char is64bit; // generate 64 bit code + char isLE; // generate little endian code + char isLinux; // generate code for linux + char isWindows; // generate code for Windows + 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; // generate array bounds checks + 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; // enable warnings + char pic; // generate position-independent-code for shared libs + char cov; // generate code coverage data + char nofloat; // code should not pull in floating point support + char noruntime; // code is not allowed to make implicit calls to the runtime + char novalidate;// no bitcode validation + char Dversion; // D version number + char ignoreUnsupportedPragmas; // rather than error on them + + char *argv0; // program name + Array *imppath; // array of char*'s of where to look for import modules + Array *fileImppath; // array of char*'s of where to look for file import modules + char *runtimeImppath; // char* of where to look for the core runtime + char *objdir; // .obj file output directory + char *objname; // .obj file output name + + char doDocComments; // process embedded documentation comments + char *docdir; // write documentation file to docdir directory + char *docname; // write documentation file to docname + Array *ddocfiles; // macro include files for Ddoc + + char doHdrGeneration; // process embedded documentation comments + char *hdrdir; // write 'header' file to docdir directory + char *hdrname; // write 'header' file to docname + + unsigned debuglevel; // debug level + Array *debugids; // debug identifiers + + unsigned versionlevel; // version level + Array *versionids; // version identifiers + + bool dump_source; + + char *defaultlibname; // default library for non-debug builds + char *debuglibname; // default library for debug builds + + char *xmlname; // filename for XML output + + // Hidden debug switches + char debuga; + char debugb; + char debugc; + char debugf; + char debugr; + char debugw; + char debugx; + char debugy; + + char run; // run resulting executable + size_t runargs_length; + char** runargs; // arguments for executable + + // Linker stuff + Array *objfiles; + Array *linkswitches; + Array *libfiles; + char *deffile; + char *resfile; + char *exefile; + + // LLVM stuff + char *llvmArch; + char forceBE; + char *tt_arch; + char *tt_os; + char *data_layout; + char disassemble; + char llvmInline; + char llvmAnnotate; + char *runtimePath; +}; + +struct Global +{ + char *mars_ext; + char *sym_ext; + char *obj_ext; + char *ll_ext; + char *bc_ext; + char *nativeobj_ext; + char *doc_ext; // for Ddoc generated files + char *ddoc_ext; // for Ddoc macro include files + char *hdr_ext; // for D 'header' import files + char *copyright; + char *written; + Array *path; // Array of char*'s which form the import lookup path + Array *filePath; // Array of char*'s which form the file import lookup path + int structalign; + char *version; + char *llvmdc_version; + + Param params; + unsigned errors; // number of errors reported so far + unsigned gag; // !=0 means gag reporting of errors + + Global(); +}; + +extern Global global; + +#if __GNUC__ +//#define memicmp strncasecmp +//#define stricmp strcasecmp +#endif + +#ifdef __DMC__ + typedef _Complex long double complex_t; +#else + #ifndef IN_GCC + #include "complex_t.h" + #endif + #ifdef __APPLE__ + //#include "complex.h"//This causes problems with include the c++ and not the C "complex.h" + #define integer_t dmd_integer_t + #endif +#endif + +// Be careful not to care about sign when using integer_t +typedef uint64_t integer_t; + +// Signed and unsigned variants +typedef int64_t sinteger_t; +typedef uint64_t uinteger_t; + +typedef int8_t d_int8; +typedef uint8_t d_uns8; +typedef int16_t d_int16; +typedef uint16_t d_uns16; +typedef int32_t d_int32; +typedef uint32_t d_uns32; +typedef int64_t d_int64; +typedef uint64_t d_uns64; + +typedef float d_float32; +typedef double d_float64; +typedef long double d_float80; + +typedef d_uns8 d_char; +typedef d_uns16 d_wchar; +typedef d_uns32 d_dchar; + +#ifdef IN_GCC +#include "d-gcc-real.h" +#else +typedef long double real_t; +#endif + +// Modify OutBuffer::writewchar to write the correct size of wchar +#if _WIN32 +#define writewchar writeword +#else +// This needs a configuration test... +#define writewchar write4 +#endif + +#ifdef IN_GCC +#include "d-gcc-complex_t.h" +#endif + +struct Module; + +//typedef unsigned Loc; // file location +struct Loc +{ + char *filename; + unsigned linnum; + + Loc() + { + linnum = 0; + filename = NULL; + } + + Loc(int x) + { + linnum = x; + filename = NULL; + } + + Loc(Module *mod, unsigned linnum); + + char *toChars() const; +}; + +#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, +}; + +enum DYNCAST +{ + DYNCAST_OBJECT, + DYNCAST_EXPRESSION, + DYNCAST_DSYMBOL, + DYNCAST_TYPE, + DYNCAST_IDENTIFIER, + DYNCAST_TUPLE, +}; + +enum MATCH +{ + MATCHnomatch, // no match + MATCHconvert, // match with conversions +#if V2 + MATCHconst, // match with conversion to const +#endif + MATCHexact // exact match +}; + +void error(Loc loc, const char *format, ...); +void verror(Loc loc, const char *format, va_list); +void fatal(); +void err_nomem(); +int runLINK(); +void deleteExeFile(); +int runProgram(); +void inifile(char *argv0, char *inifile); +void halt(); + +/*** Where to send error messages ***/ +#if IN_GCC +#define stdmsg stderr +#else +#define stdmsg stdout +#endif + +#endif /* DMD_MARS_H */ diff --git a/dmd/mtype.c b/dmd/mtype.c index 86d9ad94..d7657e3f 100644 --- a/dmd/mtype.c +++ b/dmd/mtype.c @@ -1,5339 +1,5288 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#define __USE_ISOC99 1 // so signbit() gets defined -#include - -#include -#include -#include - -#ifdef __DMC__ -#include -#endif - -#if _MSC_VER -#include -#include -#include -#elif __DMC__ -#include -#else -//#define signbit 56 -#endif - -#if __APPLE__ -#include -static double zero = 0; -#elif __GNUC__ -#include -#include -#include -static double zero = 0; -#endif - -#include "mem.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" - -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; -#if IN_LLVM -int REALSIZE = 8; -int REALPAD = 0; -#elif TARGET_LINUX -int REALSIZE = 12; -int REALPAD = 2; -#else -int REALSIZE = 10; -int REALPAD = 0; -#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::basic[TMAX]; -unsigned char Type::mangleChar[TMAX]; -StringTable Type::stringtable; - - -Type::Type(TY ty, Type *next) -{ - this->ty = ty; - this->next = next; - this->deco = NULL; - this->pto = NULL; - this->rto = NULL; - this->arrayof = NULL; - this->vtinfo = NULL; - this->ctype = NULL; -} - -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' -} - -void Type::init() -{ int i; - int j; - - 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'; - - mangleChar[Tbit] = '@'; - mangleChar[Tinstance] = '@'; - mangleChar[Terror] = '@'; - mangleChar[Ttypeof] = '@'; - mangleChar[Ttuple] = 'B'; - mangleChar[Tslice] = '@'; - - for (i = 0; i < TMAX; i++) - { if (!mangleChar[i]) - fprintf(stdmsg, "ty = %d\n", i); - assert(mangleChar[i]); - } - - // Set basic types - static TY basetab[] = - { Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64, - Tfloat32, Tfloat64, Tfloat80, - Timaginary32, Timaginary64, Timaginary80, - Tcomplex32, Tcomplex64, Tcomplex80, - Tbit, Tbool, - Tascii, Twchar, Tdchar }; - - for (i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++) - basic[basetab[i]] = new TypeBasic(basetab[i]); - basic[Terror] = basic[Tint32]; - - tvoidptr = tvoid->pointerTo(); - - if (global.params.is64bit) - { - PTRSIZE = 8; -#if !IN_LLVM - if (global.params.isLinux) - REALSIZE = 10; - else - REALSIZE = 8; -#else - REALSIZE = 8; - REALPAD = 0; -#endif - Tsize_t = Tuns64; - Tptrdiff_t = Tint64; - } - else - { - PTRSIZE = 4; -#if IN_LLVM - REALSIZE = 8; - REALPAD = 0; -#elif TARGET_LINUX - REALSIZE = 12; - REALPAD = 2; -#else - REALSIZE = 10; - REALPAD = 0; -#endif - Tsize_t = Tuns32; - Tptrdiff_t = Tint32; - } -} - -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::pointerTo() -{ - if (!pto) - { Type *t; - - t = new TypePointer(this); - pto = t->merge(); - } - return pto; -} - -Type *Type::referenceTo() -{ - if (!rto) - { Type *t; - - t = new TypeReference(this); - rto = t->merge(); - } - return rto; -} - -Type *Type::arrayOf() -{ - 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) -{ - 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); - } -} - -/******************************** - * Name mangling. - */ - -void Type::toTypeInfoBuffer(OutBuffer *buf) -{ - assert(0); - buf->writeByte(mangleChar[ty]); -} - -/******************************** - * For pretty-printing a type. - */ - -char *Type::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - buf = new OutBuffer(); - toCBuffer2(buf, NULL, &hgs); - return buf->toChars(); -} - -void Type::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - OutBuffer tbuf; - - toCBuffer2(&tbuf, ident, hgs); - buf->write(&tbuf); -} - -void Type::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->prependstring(toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -/************************************ - */ - -Type *Type::merge() -{ Type *t; - - //printf("merge(%s)\n", toChars()); - t = this; - assert(t); - if (!deco) - { - OutBuffer buf; - StringValue *sv; - - if (next) - next = next->merge(); - toDecoBuffer(&buf); - 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; - deco = sv->lstring.string; - //printf("new value, deco = '%s' %p\n", t->deco, t->deco); - } - } - 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::isauto() -{ - 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) -{ - Type *t; - Dsymbol *s; - - for (t = this; t; t = t->next) - { - 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; -} - -int Type::isZeroInit() -{ - 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 IntegerExp(loc, size(loc), Type::tsize_t); - } - else if (ident == Id::alignof) - { - 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"); - e = defaultInit(loc); - } - else if (ident == Id::mangleof) - { - assert(deco); - e = new StringExp(loc, deco, strlen(deco), '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 - { - error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars()); - e = new IntegerExp(loc, 1, Type::tint32); - } - 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->optimize(WANTvalue | WANTinterpret); -// 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); -} - -unsigned Type::memalign(unsigned salign) -{ - return salign; -} - -void Type::error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); -} - -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[next->ty]); - } - else - toDecoBuffer(&buf); - 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); - 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) -{ - Type *t; - - 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; -} - -/* ============================= TypeBasic =========================== */ - -TypeBasic::TypeBasic(TY ty) - : Type(ty, NULL) -{ char *c; - 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 Tbit: d = Token::toChars(TOKbit); - c = "bit"; - flags |= TFLAGSintegral | TFLAGSunsigned; - 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 dstring; -} - -void TypeBasic::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->prependstring(cstring); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -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 Tbit: 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() -{ unsigned sz; - - switch (ty) - { - case Tfloat80: - case Timaginary80: - case Tcomplex80: - sz = REALSIZE; - break; - - default: - sz = size(0); - break; - } - return sz; -} - - -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 Tbit: ivalue = 1; goto Livalue; - case Tbool: ivalue = 1; goto Livalue; - case Tchar: ivalue = 0xFF; goto Livalue; - case Twchar: ivalue = 0xFFFFUL; goto Livalue; - case Tdchar: ivalue = 0x10FFFFUL; goto Livalue; - - case Tcomplex32: - case Timaginary32: - case Tfloat32: fvalue = FLT_MAX; goto Lfvalue; - case Tcomplex64: - case Timaginary64: - case Tfloat64: fvalue = DBL_MAX; goto Lfvalue; - case Tcomplex80: - case Timaginary80: - case Tfloat80: fvalue = LDBL_MAX; goto Lfvalue; - } - } - 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 Tbit: 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: - { -#if IN_GCC - // mode doesn't matter, will be converted in RealExp anyway - fvalue = real_t::getnan(real_t::LongDouble); -#elif __GNUC__ - // 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 d_float80 foo; - foo = NAN; - if (signbit(foo)) // signbit sometimes, not always, set - foo = -foo; // turn off sign bit - fvalue = foo; -#elif _MSC_VER - unsigned long nan[2]= { 0xFFFFFFFF, 0x7FFFFFFF }; - fvalue = *(double*)nan; -#else - fvalue = NAN; -#endif - 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: -#if IN_GCC - fvalue = real_t::getinfinity(); -#elif __GNUC__ - fvalue = 1 / zero; -#elif _MSC_VER - fvalue = std::numeric_limits::infinity(); -#else - fvalue = INFINITY; -#endif - 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 (int i = 0; i < 20; i++) - // printf("%02x ", ((unsigned char *)&cvalue)[i]); - //printf("\n"); - e = new ComplexExp(loc, cvalue, this); - } - return e; - -Lint: - e = new IntegerExp(loc, ivalue, Type::tint32); - return e; -} - -Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - Type *t; - - if (ident == Id::re) - { - switch (ty) - { - case Tcomplex32: t = tfloat32; goto L1; - case Tcomplex64: t = tfloat64; goto L1; - case Tcomplex80: t = tfloat80; goto L1; - L1: - e = e->castTo(sc, t); - break; - - case Tfloat32: - case Tfloat64: - case Tfloat80: - break; - - case Timaginary32: t = tfloat32; goto L2; - case Timaginary64: t = tfloat64; goto L2; - case Timaginary80: t = tfloat80; goto L2; - L2: - e = new RealExp(0, 0.0, t); - break; - - default: - 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(0, 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) -{ integer_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); - } - return new IntegerExp(loc, value, this); -} - -int TypeBasic::isZeroInit() -{ - 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 (ty == Tbit); -} - -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 (ty == Tvoid || to->ty == Tvoid) - return MATCHnomatch; - if (1 || global.params.Dversion == 1) - { - if (to->ty == Tbool) - return MATCHnomatch; - } - else - { - if (ty == Tbool || 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 converting to integral - if (0 && global.params.Dversion > 1 && tob->flags & TFLAGSintegral) - { d_uns64 sz = size(0); - d_uns64 tosz = tob->size(0); - - /* Can't convert to smaller size or, if same size, change sign - */ - if (sz > tosz) - return MATCHnomatch; - - /*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned) - return MATCHnomatch;*/ - } - } - 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; - FuncDeclaration *fd; - Expressions *arguments; - char *nm; - static char *name[2] = { "_adReverseChar", "_adReverseWchar" }; - - nm = name[n->ty == Twchar]; - fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), nm); - fd->runTimeHack = true; - ec = new VarExp(0, 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; - FuncDeclaration *fd; - Expressions *arguments; - char *nm; - static char *name[2] = { "_adSortChar", "_adSortWchar" }; - - nm = name[n->ty == Twchar]; - fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), nm); - fd->runTimeHack = true; - ec = new VarExp(0, 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; - FuncDeclaration *fd; - Expressions *arguments; - int size = next->size(e->loc); - int dup; - - assert(size); - dup = (ident == Id::dup); - fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), dup ? Id::adDup : Id::adReverse); - fd->runTimeHack = true; - ec = new VarExp(0, fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - if (dup) - arguments->push(getTypeInfo(sc)); - arguments->push(e); - if (!dup) - arguments->push(new IntegerExp(0, size, Type::tint32)); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else if (ident == Id::sort) - { - Expression *ec; - FuncDeclaration *fd; - Expressions *arguments; - - fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), - (char*)(n->ty == Tbit ? "_adSortBit" : "_adSort")); - fd->runTimeHack = true; - ec = new VarExp(0, fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - arguments->push(e); - if (next->ty != Tbit) - arguments->push(n->ty == Tsarray - ? n->getTypeInfo(sc) // don't convert to dynamic array - : n->getInternalTypeInfo(sc)); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else - { - e = Type::dotExp(sc, e, ident); - } - return e; -} - -void TypeArray::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ -#if 1 - OutBuffer buf2; - toPrettyBracket(&buf2, hgs); - buf->prependstring(buf2.toChars()); - if (ident) - { - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - next->toCBuffer2(buf, NULL, hgs); -#elif 1 - // The D way - Type *t; - OutBuffer buf2; - for (t = this; 1; t = t->next) - { TypeArray *ta; - - ta = dynamic_cast(t); - if (!ta) - break; - ta->toPrettyBracket(&buf2, hgs); - } - buf->prependstring(buf2.toChars()); - if (ident) - { - buf2.writestring(ident->toChars()); - } - t->toCBuffer2(buf, NULL, hgs); -#else - // The C way - if (buf->offset) - { buf->bracket('(', ')'); - assert(!ident); - } - else if (ident) - buf->writestring(ident->toChars()); - Type *t = this; - do - { Expression *dim; - buf->writeByte('['); - dim = ((TypeSArray *)t)->dim; - if (dim) - buf->printf("%lld", dim->toInteger()); - buf->writeByte(']'); - t = t->next; - } while (t->ty == Tsarray); - t->toCBuffer2(buf, NULL, hgs); -#endif -} - - -/***************************** 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) -{ integer_t sz; - - if (!dim) - return Type::size(loc); - sz = dim->toInteger(); - if (next->toBasetype()->ty == Tbit) // if array of bits - { - if (sz + 31 < sz) - goto Loverflow; - sz = ((sz + 31) & ~31) / 8; // size in bytes, rounded up to 32 bit dwords - } - else - { integer_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->optimize(WANTvalue | WANTinterpret); - uinteger_t d = dim->toUInteger(); - - sc = sc->pop(); - - if (d >= td->objects->dim) - { error(loc, "tuple index %ju exceeds %u", d, td->objects->dim); - goto Ldefault; - } - Object *o = (Object *)td->objects->data[(size_t)d]; - if (o->dyncast() == DYNCAST_DSYMBOL) - { - *ps = (Dsymbol *)o; - return; - } - if (o->dyncast() == DYNCAST_EXPRESSION) - { - *ps = NULL; - *pe = (Expression *)o; - return; - } - - /* 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->optimize(WANTvalue | WANTinterpret); - uinteger_t d = dim->toUInteger(); - - if (d >= sd->objects->dim) - { error(loc, "tuple index %ju exceeds %u", d, sd->objects->dim); - return Type::terror; - } - Object *o = (Object *)sd->objects->data[(size_t)d]; - if (o->dyncast() != DYNCAST_TYPE) - { error(loc, "%s is not a type", toChars()); - return Type::terror; - } - t = (Type *)o; - return t; - } - - next = next->semantic(loc,sc); - Type *tbn = next->toBasetype(); - - if (dim) - { integer_t n, n2; - - dim = semanticLength(sc, tbn, dim); - - dim = dim->optimize(WANTvalue | WANTinterpret); - if (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; - } - integer_t d1 = dim->toInteger(); - dim = dim->castTo(sc, tsize_t); - dim = dim->optimize(WANTvalue); - integer_t d2 = dim->toInteger(); - - if (d1 != d2) - goto Loverflow; - - if (tbn->isintegral() || - tbn->isfloating() || - tbn->ty == Tpointer || - tbn->ty == Tarray || - tbn->ty == Tsarray || - tbn->ty == Taarray || - tbn->ty == Tclass) - { - /* Only do this for types that don't need to have semantic() - * run on them for the size, since they may be forward referenced. - */ - n = tbn->size(loc); - n2 = n * d2; - if ((int)n2 < 0) - goto Loverflow; - if (n2 >= 0x1000000) // put a 'reasonable' limit on it - goto Loverflow; - if (n && n2 / n != d2) - { - Loverflow: - error(loc, "index %jd overflow for static array", d1); - dim = new IntegerExp(0, 1, tsize_t); - } - } - } - 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); - return Type::terror; - } - Argument *arg = (Argument *)tt->arguments->data[(size_t)d]; - return arg->type; - } - case Tfunction: - case Tnone: - error(loc, "can't have array of %s", tbn->toChars()); - tbn = next = tint32; - break; - } - if (tbn->isauto()) - error(loc, "cannot have array of auto %s", tbn->toChars()); - return merge(); -} - -void TypeSArray::toDecoBuffer(OutBuffer *buf) -{ - buf->writeByte(mangleChar[ty]); - if (dim) - buf->printf("%ju", dim->toInteger()); - if (next) - next->toDecoBuffer(buf); -} - -void TypeSArray::toTypeInfoBuffer(OutBuffer *buf) -{ - buf->writeByte(mangleChar[Tarray]); - if (next) - next->toTypeInfoBuffer(buf); -} - -void TypeSArray::toPrettyBracket(OutBuffer *buf, HdrGenState *hgs) -{ - 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; -} - -unsigned TypeSArray::memalign(unsigned 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() -{ - return next->isZeroInit(); -} - - -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() -{ - 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->isauto()) - error(loc, "cannot have array of auto %s", tn->toChars()); - if (next != tn) - //deco = NULL; // redo - return tn->arrayOf(); - return merge(); -} - -void TypeDArray::toDecoBuffer(OutBuffer *buf) -{ - buf->writeByte(mangleChar[ty]); - if (next) - next->toDecoBuffer(buf); -} - -void TypeDArray::toTypeInfoBuffer(OutBuffer *buf) -{ - buf->writeByte(mangleChar[ty]); - if (next) - next->toTypeInfoBuffer(buf); -} - -void TypeDArray::toPrettyBracket(OutBuffer *buf, HdrGenState *hgs) -{ - 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); - } - 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 - Expression *e; - e = new NullExp(loc); - e->type = this; - return e; -} - -int TypeDArray::isZeroInit() -{ - 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 Tbit: - case Tbool: - case Tfunction: - case Tvoid: - case Tnone: - 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 Tnone: - error(loc, "can't have associative array of %s", next->toChars()); - break; - } - if (next->isauto()) - error(loc, "cannot have array of auto %s", next->toChars()); - - return merge(); -} - -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; - FuncDeclaration *fd; - Expressions *arguments; - - fd = FuncDeclaration::genCfunc(Type::tsize_t, Id::aaLen); - fd->runTimeHack = true; - ec = new VarExp(0, fd); - arguments = new Expressions(); - arguments->push(e); - e = new CallExp(e->loc, ec, arguments); - e->type = fd->type->next; - } - else if (ident == Id::keys) - { - Expression *ec; - FuncDeclaration *fd; - Expressions *arguments; - int size = key->size(e->loc); - - assert(size); - fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), Id::aaKeys); - fd->runTimeHack = true; - ec = new VarExp(0, 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; - FuncDeclaration *fd; - Expressions *arguments; - - fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), Id::aaValues); - fd->runTimeHack = true; - ec = new VarExp(0, fd); - arguments = new Expressions(); - arguments->push(e); - size_t keysize = key->size(e->loc); - keysize = (keysize + 4 - 1) & ~(4 - 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; - FuncDeclaration *fd; - Expressions *arguments; - - fd = FuncDeclaration::genCfunc(Type::tvoid->pointerTo(), Id::aaRehash); - fd->runTimeHack = true; - ec = new VarExp(0, fd); - arguments = new Expressions(); - arguments->push(e->addressOf(sc)); - arguments->push(key->getInternalTypeInfo(sc)); - e = new CallExp(e->loc, ec, arguments); - e->type = this; - } - else - { - e = Type::dotExp(sc, e, ident); - } - return e; -} - -void TypeAArray::toDecoBuffer(OutBuffer *buf) -{ - buf->writeByte(mangleChar[ty]); - index->toDecoBuffer(buf); - next->toDecoBuffer(buf); -} - -void TypeAArray::toPrettyBracket(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('['); - { OutBuffer ibuf; - - index->toCBuffer2(&ibuf, NULL, hgs); - buf->write(&ibuf); - } - buf->writeByte(']'); -} - -Expression *TypeAArray::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeAArray::defaultInit() '%s'\n", toChars()); -#endif - Expression *e; - e = new NullExp(loc); - e->type = this; - return e; -} - -int TypeAArray::checkBoolean() -{ - return TRUE; -} - -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) -{ - //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, Identifier *ident, HdrGenState *hgs) -{ - //printf("TypePointer::toCBuffer2() next = %d\n", next->ty); - buf->prependstring("*"); - if (ident) - { - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - next->toCBuffer2(buf, NULL, hgs); -} - -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 - Expression *e; - e = new NullExp(loc); - e->type = this; - return e; -} - -int TypePointer::isZeroInit() -{ - return 1; -} - -int TypePointer::hasPointers() -{ - return TRUE; -} - - -/***************************** TypeReference *****************************/ - -TypeReference::TypeReference(Type *t) - : Type(Treference, t) -{ - if (t->ty == Tbit) - error(0,"cannot make reference to a bit"); - // 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, Identifier *ident, HdrGenState *hgs) -{ - buf->prependstring("&"); - if (ident) - { - buf->writestring(ident->toChars()); - } - next->toCBuffer2(buf, NULL, hgs); -} - -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 - Expression *e; - e = new NullExp(loc); - e->type = this; - return e; -} - -int TypeReference::isZeroInit() -{ - return 1; -} - - -/***************************** TypeFunction *****************************/ - -TypeFunction::TypeFunction(Arguments *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; - this->llvmRetInPtr = false; - this->llvmUsesThis = false; -} - -Type *TypeFunction::syntaxCopy() -{ - Type *treturn = next ? next->syntaxCopy() : NULL; - Arguments *params = Argument::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 = Argument::dim(t1->parameters); - if (dim != Argument::dim(t2->parameters)) - goto Ldistinct; - - for (size_t i = 0; i < dim; i++) - { Argument *arg1 = Argument::getNth(t1->parameters, i); - Argument *arg2 = Argument::getNth(t2->parameters, i); - - if (!arg1->type->equals(arg2->type)) - goto Ldistinct; - if (arg1->storageClass != arg2->storageClass) - inoutmismatch = 1; - } - } - else if (t1->parameters != t2->parameters) - goto Ldistinct; - - // The argument lists match - if (inoutmismatch) - goto Lnotcovariant; - if (t1->linkage != t2->linkage) - goto Lnotcovariant; - - Type *t1n = t1->next; - Type *t2n = t2->next; - - if (t1n->equals(t2n)) - goto Lcovariant; - if (t1n->ty != Tclass || t2n->ty != Tclass) - goto Lnotcovariant; - - // If t1n is forward referenced: - ClassDeclaration *cd = ((TypeClass *)t1n)->sym; - if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration()) - { - return 3; - } - - 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) -{ 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; - default: - assert(0); - } - buf->writeByte(mc); - // Write argument types - Argument::argsToDecoBuffer(buf, parameters); - //if (buf->data[buf->offset - 1] == '@') halt(); - buf->writeByte('Z' - varargs); // mark end of arg list - next->toDecoBuffer(buf); - inuse--; -} - -void TypeFunction::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - 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; - default: - assert(0); - } - } - - if (buf->offset) - { - if (!hgs->hdrgen && p) - buf->prependstring(p); - buf->bracket('(', ')'); - assert(!ident); - } - else - { - if (!hgs->hdrgen && p) - buf->writestring(p); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toHChars2()); - } - } - Argument::argsToCBuffer(buf, hgs, parameters, varargs); - if (next && (!ident || ident->toHChars2() == ident->toChars())) - next->toCBuffer2(buf, NULL, hgs); - 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); - - TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction)); - memcpy(tf, this, sizeof(TypeFunction)); - if (parameters) - { tf->parameters = (Arguments *)parameters->copy(); - for (size_t i = 0; i < parameters->dim; i++) - { Argument *arg = (Argument *)parameters->data[i]; - Argument *cpy = (Argument *)mem.malloc(sizeof(Argument)); - memcpy(cpy, arg, sizeof(Argument)); - tf->parameters->data[i] = (void *)cpy; - } - } - - tf->linkage = sc->linkage; - if (!tf->next) - { - assert(global.errors); - tf->next = tvoid; - } - tf->next = tf->next->semantic(loc,sc); - if (tf->next->toBasetype()->ty == Tsarray) - { error(loc, "functions cannot return static array %s", tf->next->toChars()); - tf->next = Type::terror; - } - if (tf->next->toBasetype()->ty == Tfunction) - { error(loc, "functions cannot return a function"); - tf->next = Type::terror; - } - if (tf->next->toBasetype()->ty == Ttuple) - { error(loc, "functions cannot return a tuple"); - tf->next = Type::terror; - } - if (tf->next->isauto() && !(sc->flags & SCOPEctor)) - error(loc, "functions cannot return auto %s", tf->next->toChars()); - - if (tf->parameters) - { size_t dim = Argument::dim(tf->parameters); - - for (size_t i = 0; i < dim; i++) - { Argument *arg = Argument::getNth(tf->parameters, i); - Type *t; - - tf->inuse++; - arg->type = arg->type->semantic(loc,sc); - if (tf->inuse == 1) tf->inuse--; - t = arg->type->toBasetype(); - - if (arg->storageClass & (STCout | STCref | STClazy)) - { - if (t->ty == Tsarray) - error(loc, "cannot have out or ref parameter of type %s", t->toChars()); - } - if (!(arg->storageClass & STClazy) && t->ty == Tvoid) - error(loc, "cannot have parameter of type %s", arg->type->toChars()); - - if (arg->defaultArg) - { - arg->defaultArg = arg->defaultArg->semantic(sc); - arg->defaultArg = resolveProperties(sc, arg->defaultArg); - arg->defaultArg = arg->defaultArg->implicitCastTo(sc, arg->type); - } - - /* If arg turns out to be a tuple, the number of parameters may - * change. - */ - if (t->ty == Ttuple) - { dim = Argument::dim(tf->parameters); - i--; - } - } - } - tf->deco = tf->merge()->deco; - - if (tf->inuse) - { error(loc, "recursive type"); - tf->inuse = 0; - return terror; - } - - if (tf->varargs == 1 && tf->linkage != LINKd && Argument::dim(tf->parameters) == 0) - error(loc, "variadic functions with non-D linkage must have at least one parameter"); - - /* 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 = Argument::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? - - Argument *p = Argument::getNth(parameters, u); - assert(p); - if (u >= nargs) - { - if (p->defaultArg) - continue; - if (varargs == 2 && u + 1 == nparams) - goto L1; - goto Nomatch; // not enough arguments - } - arg = (Expression *)args->data[u]; - assert(arg); - if (p->storageClass & STClazy && p->type->ty == Tvoid && arg->type->ty != Tvoid) - m = MATCHconvert; - else - m = arg->implicitConvTo(p->type); - //printf("\tm = %d\n", m); - if (m == MATCHnomatch) // if no match - { - L1: - if (varargs == 2 && u + 1 == nparams) // if last varargs param - { Type *tb = p->type->toBasetype(); - TypeSArray *tsa; - integer_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 = (Expression *)args->data[u]; - assert(arg); -#if 1 - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type *tret = p->isLazyArray(); - if (tret) - { - if (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++) - { Argument *arg = (Argument *)parameters->data[i]; - Type *t = arg->type->reliesOnTident(); - if (t) - return t; - } - } - return next->reliesOnTident(); -} - -/***************************** 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; -} - -void TypeDelegate::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ -#if 1 - OutBuffer args; - TypeFunction *tf = (TypeFunction *)next; - - Argument::argsToCBuffer(&args, hgs, tf->parameters, tf->varargs); - buf->prependstring(args.toChars()); - buf->prependstring(" delegate"); - if (ident) - { - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - next->next->toCBuffer2(buf, NULL, hgs); -#else - next->toCBuffer2(buf, Id::delegate, hgs); - if (ident) - { - buf->writestring(ident->toChars()); - } -#endif -} - -Expression *TypeDelegate::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeDelegate::defaultInit() '%s'\n", toChars()); -#endif - Expression *e; - e = new NullExp(loc); - e->type = this; - return e; -} - -int TypeDelegate::isZeroInit() -{ - return 1; -} - -int TypeDelegate::checkBoolean() -{ - return TRUE; -} - -Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (ident == Id::ptr) - { - e->type = tvoidptr; - return e; - } - else if (ident == Id::funcptr) - { - 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); - 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 (int i = 0; i < idents.dim; i++) - { - Identifier *id = (Identifier *)t->idents.data[i]; - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; - - ti = (TemplateInstance *)ti->syntaxCopy(NULL); - id = (Identifier *)ti; - } - idents.data[i] = id; - } -} - - -void TypeQualified::addIdent(Identifier *ident) -{ - idents.push(ident); -} - -void TypeQualified::toCBuffer2Helper(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - int i; - - for (i = 0; i < idents.dim; i++) - { Identifier *id = (Identifier *)idents.data[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) -{ - Identifier *id = NULL; - int i; - 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 = s->toAlias(); - //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - for (i = 0; i < idents.dim; i++) - { Dsymbol *sm; - - id = (Identifier *)idents.data[i]; - 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->isConst() && v->getExpInitializer()) - { e = v->getExpInitializer()->exp; - } - else - e = new VarExp(loc, v); - t = e->type; - if (!t) - goto Lerror; - goto L3; - } - t = s->getType(); - if (!t && s->isDeclaration()) - t = s->isDeclaration()->type; - if (t) - { - sm = t->toDsymbol(sc); - if (sm) - { sm = sm->search(loc, id, 0); - if (sm) - goto L2; - } - //e = t->getProperty(loc, id); - e = new TypeExp(loc, t); - e = t->dotExp(sc, e, id); - i++; - L3: - for (; i < idents.dim; i++) - { - id = (Identifier *)idents.data[i]; - //printf("e: '%s', id: '%s', type = %p\n", e->toChars(), id->toChars(), e->type); - e = e->type->dotExp(sc, e, id); - } - *pe = e; - } - else - Lerror: - error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars()); - return; - } - L2: - s = sm->toAlias(); - } - - v = s->isVarDeclaration(); - if (v) - { - // It's not a type, it's an expression - if (v->isConst() && 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()) - { - Scope *scx; - - for (scx = sc; 1; scx = scx->enclosing) - { - if (!scx) - { error(loc, "forward reference to '%s'", t->toChars()); - return; - } - if (scx->scopesym == scopesym) - break; - } - t = t->semantic(loc, scx); - //((TypeIdentifier *)t)->resolve(loc, scx, pe, &t, ps); - } - } - if (t->ty == Ttuple) - *pt = t; - else - *pt = t->merge(); - } - if (!s) - { - error(loc, "identifier '%s' is not defined", toChars()); - } -} - -/***************************** 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) -{ 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, Identifier *ident, HdrGenState *hgs) -{ - OutBuffer tmp; - - tmp.writestring(this->ident->toChars()); - toCBuffer2Helper(&tmp, NULL, hgs); - buf->prependstring(tmp.toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -/************************************* - * 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 (int i = 0; i < idents.dim; i++) - { - Identifier *id = (Identifier *)idents.data[i]; - s = s->searchX(loc, sc, id); - if (!s) // failed to find a symbol - { //printf("\tdidn't find a symbol\n"); - break; - } - } - } - return s; -} - -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 (int 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, Identifier *ident, HdrGenState *hgs) -{ - OutBuffer tmp; - - tempinst->toCBuffer(&tmp, hgs); - toCBuffer2Helper(&tmp, NULL, hgs); - buf->prependstring(tmp.toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -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.errors; - global.gag++; - - resolve(loc, sc, &e, &t, &s); - - global.gag--; - if (errors != global.errors) - { if (global.gag == 0) - global.errors = errors; - return this; - } - } - else - resolve(loc, sc, &e, &t, &s); - - if (!t) - { -#ifdef DEBUG - printf("2: "); -#endif - error(loc, "%s is used as a type", toChars()); - t = tvoid; - } - return t; -} - - -/***************************** TypeTypeof *****************************/ - -TypeTypeof::TypeTypeof(Loc loc, Expression *exp) - : TypeQualified(Ttypeof, loc) -{ - this->exp = exp; -} - -Type *TypeTypeof::syntaxCopy() -{ - TypeTypeof *t; - - t = new TypeTypeof(loc, exp->syntaxCopy()); - t->syntaxCopyHelper(this); - return t; -} - -Dsymbol *TypeTypeof::toDsymbol(Scope *sc) -{ - Type *t; - - t = semantic(0, sc); - if (t == this) - return NULL; - return t->toDsymbol(sc); -} - -void TypeTypeof::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - OutBuffer tmp; - - tmp.writestring("typeof("); - exp->toCBuffer(&tmp, hgs); - tmp.writeByte(')'); - toCBuffer2Helper(&tmp, NULL, hgs); - buf->prependstring(tmp.toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -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 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 - { - sc->intypeof++; - exp = exp->semantic(sc); - sc->intypeof--; - t = exp->type; - if (!t) - { - error(loc, "expression (%s) has no type", exp->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; - } - } - return t; - -Lerr: - return tvoid; -} - -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::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->memtype) - { -#ifdef DEBUG - printf("2: "); -#endif - error(sym->loc, "enum %s is forward referenced", sym->toChars()); - return tint32; - } - return sym->memtype->toBasetype(); -} - -void TypeEnum::toDecoBuffer(OutBuffer *buf) -{ char *name; - - name = sym->mangle(); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - buf->printf("%c%s", mangleChar[ty], name); -} - -void TypeEnum::toTypeInfoBuffer(OutBuffer *buf) -{ - toBasetype()->toTypeInfoBuffer(buf); -} - -void TypeEnum::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->prependstring(sym->toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->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) - { - return getProperty(e->loc, ident); - } - m = s->isEnumMember(); - em = m->value->copy(); - em->loc = e->loc; - return em; - -Lfwd: - error(e->loc, "forward reference of %s.%s", toChars(), ident->toChars()); - return new IntegerExp(0, 0, this); -} - -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 (!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() -{ - 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); - sym->semantic(sc); - 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) -{ 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::toTypeInfoBuffer(OutBuffer *buf) -{ - sym->basetype->toTypeInfoBuffer(buf); -} - -void TypeTypedef::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - //printf("TypeTypedef::toCBuffer2() '%s'\n", sym->toChars()); - buf->prependstring(sym->toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->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() -{ - 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(); - sym->inuse = 0; - return result; -} - -int TypeTypedef::hasPointers() -{ - return toBasetype()->hasPointers(); -} - -/***************************** TypeStruct *****************************/ - -TypeStruct::TypeStruct(StructDeclaration *sym) - : Type(Tstruct, NULL) -{ - this->sym = sym; -} - -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 (sz > sym->structalign) - sz = sym->structalign; - return sz; -} - -Dsymbol *TypeStruct::toDsymbol(Scope *sc) -{ - return sym; -} - -void TypeStruct::toDecoBuffer(OutBuffer *buf) -{ 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::toTypeInfoBuffer(OutBuffer *buf) -{ - toDecoBuffer(buf); -} - - -void TypeStruct::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->prependbyte(' '); - buf->prependstring(toChars()); - if (ident) - buf->writestring(ident->toChars()); -} - -Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ unsigned offset; - - 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 IntegerExp(e->loc, 0, Type::tint32); - } - - if (ident == Id::tupleof) - { - /* Create a TupleExp - */ - Expressions *exps = new Expressions; - exps->reserve(sym->fields.dim); - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)sym->fields.data[i]; - Expression *fe = new DotVarExp(e->loc, e, v); - exps->push(fe); - } - e = new TupleExp(e->loc, exps); - e = e->semantic(sc); - 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); - } - s = s->toAlias(); - - v = s->isVarDeclaration(); - if (v && v->isConst()) - { 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; - - 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->semanticdone) - 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; - } - - 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) - { - 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->type = d->type; - 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); - 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)); -#if IN_LLVM - // LLVMDC modification - // this is *essential* - ((AddExp*)b)->llvmFieldIndex = true; -#endif - b->type = v->type->pointerTo(); - e = new PtrExp(e->loc, b); - e->type = v->type; - return e; - } - - de = new DotVarExp(e->loc, e, d); - return de->semantic(sc); -} - -unsigned TypeStruct::memalign(unsigned salign) -{ - sym->size(0); // give error for forward references - return sym->structalign; -} - -Expression *TypeStruct::defaultInit(Loc loc) -{ Symbol *s; - Declaration *d; - -#if LOGDEFAULTINIT - printf("TypeStruct::defaultInit() '%s'\n", toChars()); -#endif - s = sym->toInitializer(); - d = new SymbolDeclaration(sym->loc, s, sym); - assert(d); - d->type = this; - return new VarExp(sym->loc, d); -} - -int TypeStruct::isZeroInit() -{ - 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 sym->toPrettyChars(); -} - -Type *TypeClass::syntaxCopy() -{ - return this; -} - -Type *TypeClass::semantic(Loc loc, Scope *sc) -{ - //printf("TypeClass::semantic(%s)\n", sym->toChars()); - if (sym->scope) - sym->semantic(sym->scope); - return merge(); -} - -d_uns64 TypeClass::size(Loc loc) -{ - return PTRSIZE; -} - -Dsymbol *TypeClass::toDsymbol(Scope *sc) -{ - return sym; -} - -void TypeClass::toDecoBuffer(OutBuffer *buf) -{ 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, Identifier *ident, HdrGenState *hgs) -{ - buf->prependstring(sym->toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ unsigned offset; - - Expression *b; - VarDeclaration *v; - Dsymbol *s; - DotVarExp *de; - Declaration *d; - -#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 - */ - Expressions *exps = new Expressions; - exps->reserve(sym->fields.dim); - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)sym->fields.data[i]; - Expression *fe = new DotVarExp(e->loc, e, v); - exps->push(fe); - } - e = new TupleExp(e->loc, exps); - e = e->semantic(sc); - return e; - } - - s = sym->search(e->loc, ident, 0); -L1: - if (!s) - { - // See if it's a base class - ClassDeclaration *cbase; - for (cbase = sym->baseClass; cbase; cbase = cbase->baseClass) - { - if (cbase->ident->equals(ident)) - { - e = new DotTypeExp(0, e, cbase); - return e; - } - } - - if (ident == Id::classinfo) - { - Type *t; - - assert(ClassDeclaration::classinfo); - 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 - } - 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); - } - } - s = s->toAlias(); - v = s->isVarDeclaration(); - if (v && v->isConst()) - { 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; - - 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->semanticdone) - 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; - } - - d = s->isDeclaration(); - if (!d) - { - e->error("%s.%s is not a declaration", e->toChars(), ident->toChars()); - return new IntegerExp(e->loc, 1, Type::tint32); - } - - if (e->op == TOKtype) - { - VarExp *ve; - - if (d->needThis() && (hasThis(sc) || !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); - 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()); - } - } - - de = new DotVarExp(e->loc, new ThisExp(e->loc), d); - e = de->semantic(sc); - return e; - } - else if (d->isTupleDeclaration()) - { - e = new TupleExp(e->loc, d->isTupleDeclaration()); - e = e->semantic(sc); - return e; - } - else - 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->type = d->type; - return e; - } - - if (d->parent && d->toParent()->isModule()) - { - // (e, d) - VarExp *ve; - - 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::isauto() -{ - return sym->isauto; -} - -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("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 - Expression *e; - e = new NullExp(loc); - e->type = this; - return e; -} - -int TypeClass::isZeroInit() -{ - return 1; -} - -int TypeClass::checkBoolean() -{ - return TRUE; -} - -int TypeClass::hasPointers() -{ - return TRUE; -} - -/***************************** TypeTuple *****************************/ - -TypeTuple::TypeTuple(Arguments *arguments) - : Type(Ttuple, NULL) -{ - //printf("TypeTuple(this = %p)\n", this); - this->arguments = arguments; -#ifdef DEBUG - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { - Argument *arg = (Argument *)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) -{ - Arguments *arguments = new Arguments; - if (exps) - { - arguments->setDim(exps->dim); - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - if (e->type->ty == Ttuple) - e->error("cannot form tuple of tuples"); - Argument *arg = new Argument(STCin, e->type, NULL, NULL); - arguments->data[i] = (void *)arg; - } - } - this->arguments = arguments; -} - -Type *TypeTuple::syntaxCopy() -{ - Arguments *args = Argument::arraySyntaxCopy(arguments); - Type *t = new TypeTuple(args); - return t; -} - -Type *TypeTuple::semantic(Loc loc, Scope *sc) -{ - //printf("TypeTuple::semantic(this = %p)\n", this); - 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++) - { Argument *arg1 = (Argument *)arguments->data[i]; - Argument *arg2 = (Argument *)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++) - { - Argument *arg = (Argument *)arguments->data[i]; - Type *t = arg->type->reliesOnTident(); - if (t) - return t; - } - } - return NULL; -} - -void TypeTuple::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - OutBuffer buf2; - Argument::argsToCBuffer(&buf2, hgs, arguments, 0); - buf->prependstring(buf2.toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -void TypeTuple::toDecoBuffer(OutBuffer *buf) -{ - //printf("TypeTuple::toDecoBuffer() this = %p\n", this); - OutBuffer buf2; - Argument::argsToDecoBuffer(&buf2, arguments); - 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->optimize(WANTvalue); - uinteger_t i1 = lwr->toUInteger(); - - upr = semanticLength(sc, tbn, upr); - upr = upr->optimize(WANTvalue); - 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; - } - - Arguments *args = new Arguments; - args->reserve(i2 - i1); - for (size_t i = i1; i < i2; i++) - { Argument *arg = (Argument *)tt->arguments->data[i]; - args->push(arg); - } - - return new TypeTuple(args); -} - -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->optimize(WANTvalue); - uinteger_t i1 = lwr->toUInteger(); - - upr = upr->semantic(sc); - upr = upr->optimize(WANTvalue); - 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, Identifier *ident, HdrGenState *hgs) -{ - OutBuffer buf2; - - buf2.printf("[%s .. ", lwr->toChars()); - buf2.printf("%s]", upr->toChars()); - - buf->prependstring(buf2.toChars()); - if (ident) - { - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - next->toCBuffer2(buf, NULL, hgs); -} - -/***************************** Argument *****************************/ - -Argument::Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg) -{ - this->type = type; - this->ident = ident; - this->storageClass = storageClass; - this->defaultArg = defaultArg; - this->vardecl = 0; -} - -Argument *Argument::syntaxCopy() -{ - Argument *a = new Argument(storageClass, - type ? type->syntaxCopy() : NULL, - ident, - defaultArg ? defaultArg->syntaxCopy() : NULL); - return a; -} - -Arguments *Argument::arraySyntaxCopy(Arguments *args) -{ Arguments *a = NULL; - - if (args) - { - a = new Arguments(); - a->setDim(args->dim); - for (size_t i = 0; i < a->dim; i++) - { Argument *arg = (Argument *)args->data[i]; - - arg = arg->syntaxCopy(); - a->data[i] = (void *)arg; - } - } - return a; -} - -char *Argument::argsTypesToChars(Arguments *args, int varargs) -{ OutBuffer *buf; - - buf = new OutBuffer(); - - buf->writeByte('('); - if (args) - { int i; - OutBuffer argbuf; - HdrGenState hgs; - - for (i = 0; i < args->dim; i++) - { Argument *arg; - - if (i) - buf->writeByte(','); - arg = (Argument *)args->data[i]; - argbuf.reset(); - arg->type->toCBuffer2(&argbuf, NULL, &hgs); - buf->write(&argbuf); - } - if (varargs) - { - if (i && varargs == 1) - buf->writeByte(','); - buf->writestring("..."); - } - } - buf->writeByte(')'); - - return buf->toChars(); -} - -void Argument::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs) -{ - buf->writeByte('('); - if (arguments) - { int i; - OutBuffer argbuf; - - for (i = 0; i < arguments->dim; i++) - { Argument *arg; - - if (i) - buf->writestring(", "); - arg = (Argument *)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->toCBuffer2(&argbuf, arg->ident, hgs); - if (arg->defaultArg) - { - argbuf.writestring(" = "); - arg->defaultArg->toCBuffer(&argbuf, hgs); - } - buf->write(&argbuf); - } - if (varargs) - { - if (i && varargs == 1) - buf->writeByte(','); - buf->writestring("..."); - } - } - buf->writeByte(')'); -} - - -void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments) -{ - //printf("Argument::argsToDecoBuffer()\n"); - - // Write argument types - if (arguments) - { - size_t dim = Argument::dim(arguments); - for (size_t i = 0; i < dim; i++) - { - Argument *arg = Argument::getNth(arguments, i); - arg->toDecoBuffer(buf); - } - } -} - -/**************************************************** - * Determine if parameter is a lazy array of delegates. - * If so, return the return type of those delegates. - * If not, return NULL. - */ - -Type *Argument::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 && Argument::dim(tf->parameters) == 0) - { - return tf->next; // return type of delegate - } - } - } - } - return NULL; -} - -void Argument::toDecoBuffer(OutBuffer *buf) -{ - 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 - halt(); -#endif - assert(0); - } - type->toDecoBuffer(buf); -} - -/*************************************** - * Determine number of arguments, folding in tuples. - */ - -size_t Argument::dim(Arguments *args) -{ - size_t n = 0; - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { Argument *arg = (Argument *)args->data[i]; - Type *t = arg->type->toBasetype(); - - if (t->ty == Ttuple) - { TypeTuple *tu = (TypeTuple *)t; - n += dim(tu->arguments); - } - else - n++; - } - } - return n; -} - -/*************************************** - * Get nth Argument, folding in tuples. - * Returns: - * Argument* nth Argument - * NULL not found, *pn gets incremented by the number - * of Arguments - */ - -Argument *Argument::getNth(Arguments *args, size_t nth, size_t *pn) -{ - if (!args) - return NULL; - - size_t n = 0; - for (size_t i = 0; i < args->dim; i++) - { Argument *arg = (Argument *)args->data[i]; - Type *t = arg->type->toBasetype(); - - if (t->ty == Ttuple) - { TypeTuple *tu = (TypeTuple *)t; - arg = getNth(tu->arguments, nth - n, &n); - if (arg) - return arg; - } - else if (n == nth) - return arg; - else - n++; - } - - if (pn) - *pn += n; - return NULL; -} + +// 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. + +#define __USE_ISOC99 1 // so signbit() gets defined +#include + +#include +#include +#include + +#ifdef __DMC__ +#include +#endif + +#if _MSC_VER +#include +#include +#include +#elif __DMC__ +#include +#else +//#define signbit 56 +#endif + +#if __APPLE__ +#include +static double zero = 0; +#elif __GNUC__ +#include +#include +#include +static double zero = 0; +#endif + +#include "mem.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" + +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; +#if IN_LLVM +int REALSIZE = 8; +int REALPAD = 0; +#elif TARGET_LINUX +int REALSIZE = 12; +int REALPAD = 2; +#else +int REALSIZE = 10; +int REALPAD = 0; +#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::basic[TMAX]; +unsigned char Type::mangleChar[TMAX]; +StringTable Type::stringtable; + + +Type::Type(TY ty, Type *next) +{ + this->ty = ty; + this->mod = 0; + this->next = next; + this->deco = NULL; +#if V2 + this->cto = NULL; + this->ito = NULL; +#endif + this->pto = NULL; + this->rto = NULL; + this->arrayof = NULL; + this->vtinfo = NULL; + this->ctype = NULL; +} + +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' +} + +void Type::init() +{ int i; + int j; + + 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'; + + mangleChar[Tbit] = '@'; + mangleChar[Tinstance] = '@'; + mangleChar[Terror] = '@'; + mangleChar[Ttypeof] = '@'; + mangleChar[Ttuple] = 'B'; + mangleChar[Tslice] = '@'; + + for (i = 0; i < TMAX; i++) + { if (!mangleChar[i]) + fprintf(stdmsg, "ty = %d\n", i); + assert(mangleChar[i]); + } + + // Set basic types + static TY basetab[] = + { Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64, + Tfloat32, Tfloat64, Tfloat80, + Timaginary32, Timaginary64, Timaginary80, + Tcomplex32, Tcomplex64, Tcomplex80, + Tbit, Tbool, + Tascii, Twchar, Tdchar }; + + for (i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++) + basic[basetab[i]] = new TypeBasic(basetab[i]); + basic[Terror] = basic[Tint32]; + + tvoidptr = tvoid->pointerTo(); + + if (global.params.is64bit) + { + PTRSIZE = 8; +#if !IN_LLVM + if (global.params.isLinux) + REALSIZE = 10; + else + REALSIZE = 8; +#else + REALSIZE = 8; + REALPAD = 0; +#endif + Tsize_t = Tuns64; + Tptrdiff_t = Tint64; + } + else + { + PTRSIZE = 4; +#if IN_LLVM + REALSIZE = 8; + REALPAD = 0; +#elif TARGET_LINUX + REALSIZE = 12; + REALPAD = 2; +#else + REALSIZE = 10; + REALPAD = 0; +#endif + Tsize_t = Tuns32; + Tptrdiff_t = Tint32; + } +} + +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::pointerTo() +{ + if (!pto) + { Type *t; + + t = new TypePointer(this); + pto = t->merge(); + } + return pto; +} + +Type *Type::referenceTo() +{ + if (!rto) + { Type *t; + + t = new TypeReference(this); + rto = t->merge(); + } + return rto; +} + +Type *Type::arrayOf() +{ + 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) +{ + 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); + } +} + +/******************************** + * 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) + { char *p; + + switch (this->mod) + { + case 0: + toCBuffer2(buf, hgs, this->mod); + break; + case MODconst: + p = "const("; + goto L1; + case MODinvariant: + p = "invariant("; + L1: buf->writestring(p); + toCBuffer2(buf, hgs, this->mod); + buf->writeByte(')'); + break; + default: + assert(0); + } + } +} + + +/************************************ + */ + +Type *Type::merge() +{ Type *t; + + //printf("merge(%s)\n", toChars()); + t = this; + assert(t); + if (!deco) + { + OutBuffer buf; + StringValue *sv; + + if (next) + next = next->merge(); + toDecoBuffer(&buf); + 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; + deco = sv->lstring.string; + //printf("new value, deco = '%s' %p\n", t->deco, t->deco); + } + } + 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::isauto() +{ + 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) +{ + Type *t; + Dsymbol *s; + + for (t = this; t; t = t->next) + { + 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; +} + +int Type::isZeroInit() +{ + 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 IntegerExp(loc, size(loc), Type::tsize_t); + } + else if (ident == Id::alignof) + { + 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"); + e = defaultInit(loc); + } + else if (ident == Id::mangleof) + { + assert(deco); + e = new StringExp(loc, deco, strlen(deco), '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 + { + error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars()); + e = new IntegerExp(loc, 1, Type::tint32); + } + 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->optimize(WANTvalue | WANTinterpret); +// 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); +} + +unsigned Type::memalign(unsigned salign) +{ + return salign; +} + +void Type::error(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + ::verror(loc, format, ap); + va_end( ap ); +} + +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[next->ty]); + } + else + toDecoBuffer(&buf); + 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); + 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) +{ + Type *t; + + 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; +} + +/* ============================= TypeBasic =========================== */ + +TypeBasic::TypeBasic(TY ty) + : Type(ty, NULL) +{ char *c; + 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 Tbit: d = Token::toChars(TOKbit); + c = "bit"; + flags |= TFLAGSintegral | TFLAGSunsigned; + 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 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 Tbit: 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() +{ unsigned sz; + + switch (ty) + { + case Tfloat80: + case Timaginary80: + case Tcomplex80: + sz = REALSIZE; + break; + + default: + sz = size(0); + break; + } + return sz; +} + + +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 Tbit: ivalue = 1; goto Livalue; + case Tbool: ivalue = 1; goto Livalue; + case Tchar: ivalue = 0xFF; goto Livalue; + case Twchar: ivalue = 0xFFFFUL; goto Livalue; + case Tdchar: ivalue = 0x10FFFFUL; goto Livalue; + + case Tcomplex32: + case Timaginary32: + case Tfloat32: fvalue = FLT_MAX; goto Lfvalue; + case Tcomplex64: + case Timaginary64: + case Tfloat64: fvalue = DBL_MAX; goto Lfvalue; + case Tcomplex80: + case Timaginary80: + case Tfloat80: fvalue = LDBL_MAX; goto Lfvalue; + } + } + 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 Tbit: 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: + { +#if IN_GCC + // mode doesn't matter, will be converted in RealExp anyway + fvalue = real_t::getnan(real_t::LongDouble); +#elif __GNUC__ + // 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 d_float80 foo; + foo = NAN; + if (signbit(foo)) // signbit sometimes, not always, set + foo = -foo; // turn off sign bit + fvalue = foo; +#elif _MSC_VER + unsigned long nan[2]= { 0xFFFFFFFF, 0x7FFFFFFF }; + fvalue = *(double*)nan; +#else + fvalue = NAN; +#endif + 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: +#if IN_GCC + fvalue = real_t::getinfinity(); +#elif __GNUC__ + fvalue = 1 / zero; +#elif _MSC_VER + fvalue = std::numeric_limits::infinity(); +#else + fvalue = INFINITY; +#endif + 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 (int i = 0; i < 20; i++) + // printf("%02x ", ((unsigned char *)&cvalue)[i]); + //printf("\n"); + e = new ComplexExp(loc, cvalue, this); + } + return e; + +Lint: + e = new IntegerExp(loc, ivalue, Type::tint32); + return e; +} + +Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident) +{ +#if LOGDOTEXP + printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); +#endif + Type *t; + + if (ident == Id::re) + { + switch (ty) + { + case Tcomplex32: t = tfloat32; goto L1; + case Tcomplex64: t = tfloat64; goto L1; + case Tcomplex80: t = tfloat80; goto L1; + L1: + e = e->castTo(sc, t); + break; + + case Tfloat32: + case Tfloat64: + case Tfloat80: + break; + + case Timaginary32: t = tfloat32; goto L2; + case Timaginary64: t = tfloat64; goto L2; + case Timaginary80: t = tfloat80; goto L2; + L2: + e = new RealExp(0, 0.0, t); + break; + + default: + 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(0, 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) +{ integer_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); + } + return new IntegerExp(loc, value, this); +} + +int TypeBasic::isZeroInit() +{ + 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 (ty == Tbit); +} + +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 (ty == Tvoid || to->ty == Tvoid) + return MATCHnomatch; + if (1 || global.params.Dversion == 1) + { + if (to->ty == Tbool) + return MATCHnomatch; + } + else + { + if (ty == Tbool || 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 converting to integral + if (0 && global.params.Dversion > 1 && tob->flags & TFLAGSintegral) + { d_uns64 sz = size(0); + d_uns64 tosz = tob->size(0); + + /* Can't convert to smaller size or, if same size, change sign + */ + if (sz > tosz) + return MATCHnomatch; + + /*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned) + return MATCHnomatch;*/ + } + } + 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; + FuncDeclaration *fd; + Expressions *arguments; + char *nm; + static char *name[2] = { "_adReverseChar", "_adReverseWchar" }; + + nm = name[n->ty == Twchar]; + fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), nm); + fd->runTimeHack = true; + ec = new VarExp(0, 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; + FuncDeclaration *fd; + Expressions *arguments; + char *nm; + static char *name[2] = { "_adSortChar", "_adSortWchar" }; + + nm = name[n->ty == Twchar]; + fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), nm); + fd->runTimeHack = true; + ec = new VarExp(0, 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; + FuncDeclaration *fd; + Expressions *arguments; + int size = next->size(e->loc); + int dup; + + assert(size); + dup = (ident == Id::dup); + fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), dup ? Id::adDup : Id::adReverse); + fd->runTimeHack = true; + ec = new VarExp(0, fd); + e = e->castTo(sc, n->arrayOf()); // convert to dynamic array + arguments = new Expressions(); + if (dup) + arguments->push(getTypeInfo(sc)); + arguments->push(e); + if (!dup) + arguments->push(new IntegerExp(0, size, Type::tint32)); + e = new CallExp(e->loc, ec, arguments); + e->type = next->arrayOf(); + } + else if (ident == Id::sort) + { + Expression *ec; + FuncDeclaration *fd; + Expressions *arguments; + + fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), + (char*)(n->ty == Tbit ? "_adSortBit" : "_adSort")); + fd->runTimeHack = true; + ec = new VarExp(0, fd); + e = e->castTo(sc, n->arrayOf()); // convert to dynamic array + arguments = new Expressions(); + arguments->push(e); + if (next->ty != Tbit) + arguments->push(n->ty == Tsarray + ? n->getTypeInfo(sc) // don't convert to dynamic array + : n->getInternalTypeInfo(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) +{ integer_t sz; + + if (!dim) + return Type::size(loc); + sz = dim->toInteger(); + if (next->toBasetype()->ty == Tbit) // if array of bits + { + if (sz + 31 < sz) + goto Loverflow; + sz = ((sz + 31) & ~31) / 8; // size in bytes, rounded up to 32 bit dwords + } + else + { integer_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->optimize(WANTvalue | WANTinterpret); + uinteger_t d = dim->toUInteger(); + + sc = sc->pop(); + + if (d >= td->objects->dim) + { error(loc, "tuple index %ju exceeds %u", d, td->objects->dim); + goto Ldefault; + } + Object *o = (Object *)td->objects->data[(size_t)d]; + if (o->dyncast() == DYNCAST_DSYMBOL) + { + *ps = (Dsymbol *)o; + return; + } + if (o->dyncast() == DYNCAST_EXPRESSION) + { + *ps = NULL; + *pe = (Expression *)o; + return; + } + + /* 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->optimize(WANTvalue | WANTinterpret); + uinteger_t d = dim->toUInteger(); + + if (d >= sd->objects->dim) + { error(loc, "tuple index %ju exceeds %u", d, sd->objects->dim); + return Type::terror; + } + Object *o = (Object *)sd->objects->data[(size_t)d]; + if (o->dyncast() != DYNCAST_TYPE) + { error(loc, "%s is not a type", toChars()); + return Type::terror; + } + t = (Type *)o; + return t; + } + + next = next->semantic(loc,sc); + Type *tbn = next->toBasetype(); + + if (dim) + { integer_t n, n2; + + dim = semanticLength(sc, tbn, dim); + + dim = dim->optimize(WANTvalue | WANTinterpret); + if (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; + } + integer_t d1 = dim->toInteger(); + dim = dim->castTo(sc, tsize_t); + dim = dim->optimize(WANTvalue); + integer_t d2 = dim->toInteger(); + + if (d1 != d2) + goto Loverflow; + + if (tbn->isintegral() || + tbn->isfloating() || + tbn->ty == Tpointer || + tbn->ty == Tarray || + tbn->ty == Tsarray || + tbn->ty == Taarray || + tbn->ty == Tclass) + { + /* Only do this for types that don't need to have semantic() + * run on them for the size, since they may be forward referenced. + */ + n = tbn->size(loc); + n2 = n * d2; + if ((int)n2 < 0) + goto Loverflow; + if (n2 >= 0x1000000) // put a 'reasonable' limit on it + goto Loverflow; + if (n && n2 / n != d2) + { + Loverflow: + error(loc, "index %jd overflow for static array", d1); + dim = new IntegerExp(0, 1, tsize_t); + } + } + } + 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); + return Type::terror; + } + Argument *arg = (Argument *)tt->arguments->data[(size_t)d]; + return arg->type; + } + case Tfunction: + case Tnone: + error(loc, "can't have array of %s", tbn->toChars()); + tbn = next = tint32; + break; + } + if (tbn->isauto()) + error(loc, "cannot have array of auto %s", tbn->toChars()); + return merge(); +} + +void TypeSArray::toDecoBuffer(OutBuffer *buf) +{ + buf->writeByte(mangleChar[ty]); + if (dim) + buf->printf("%ju", dim->toInteger()); + if (next) + next->toDecoBuffer(buf); +} + +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; +} + +unsigned TypeSArray::memalign(unsigned 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() +{ + return next->isZeroInit(); +} + + +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() +{ + 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->isauto()) + error(loc, "cannot have array of auto %s", tn->toChars()); + if (next != tn) + //deco = NULL; // redo + return tn->arrayOf(); + return merge(); +} + +void TypeDArray::toDecoBuffer(OutBuffer *buf) +{ + buf->writeByte(mangleChar[ty]); + if (next) + next->toDecoBuffer(buf); +} + +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); + } + 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 + Expression *e; + e = new NullExp(loc); + e->type = this; + return e; +} + +int TypeDArray::isZeroInit() +{ + 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 Tbit: + case Tbool: + case Tfunction: + case Tvoid: + case Tnone: + 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 Tnone: + error(loc, "can't have associative array of %s", next->toChars()); + break; + } + if (next->isauto()) + error(loc, "cannot have array of auto %s", next->toChars()); + + return merge(); +} + +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; + FuncDeclaration *fd; + Expressions *arguments; + + fd = FuncDeclaration::genCfunc(Type::tsize_t, Id::aaLen); + fd->runTimeHack = true; + ec = new VarExp(0, fd); + arguments = new Expressions(); + arguments->push(e); + e = new CallExp(e->loc, ec, arguments); + e->type = fd->type->next; + } + else if (ident == Id::keys) + { + Expression *ec; + FuncDeclaration *fd; + Expressions *arguments; + int size = key->size(e->loc); + + assert(size); + fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), Id::aaKeys); + fd->runTimeHack = true; + ec = new VarExp(0, 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; + FuncDeclaration *fd; + Expressions *arguments; + + fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), Id::aaValues); + fd->runTimeHack = true; + ec = new VarExp(0, fd); + arguments = new Expressions(); + arguments->push(e); + size_t keysize = key->size(e->loc); + keysize = (keysize + 4 - 1) & ~(4 - 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; + FuncDeclaration *fd; + Expressions *arguments; + + fd = FuncDeclaration::genCfunc(Type::tvoid->pointerTo(), Id::aaRehash); + fd->runTimeHack = true; + ec = new VarExp(0, fd); + arguments = new Expressions(); + arguments->push(e->addressOf(sc)); + arguments->push(key->getInternalTypeInfo(sc)); + e = new CallExp(e->loc, ec, arguments); + e->type = this; + } + else + { + e = Type::dotExp(sc, e, ident); + } + return e; +} + +void TypeAArray::toDecoBuffer(OutBuffer *buf) +{ + buf->writeByte(mangleChar[ty]); + index->toDecoBuffer(buf); + next->toDecoBuffer(buf); +} + +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 + Expression *e; + e = new NullExp(loc); + e->type = this; + return e; +} + +int TypeAArray::checkBoolean() +{ + return TRUE; +} + +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) +{ + //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 + Expression *e; + e = new NullExp(loc); + e->type = this; + return e; +} + +int TypePointer::isZeroInit() +{ + return 1; +} + +int TypePointer::hasPointers() +{ + return TRUE; +} + + +/***************************** TypeReference *****************************/ + +TypeReference::TypeReference(Type *t) + : Type(Treference, t) +{ + if (t->ty == Tbit) + error(0,"cannot make reference to a bit"); + // 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 + Expression *e; + e = new NullExp(loc); + e->type = this; + return e; +} + +int TypeReference::isZeroInit() +{ + return 1; +} + + +/***************************** TypeFunction *****************************/ + +TypeFunction::TypeFunction(Arguments *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; + this->llvmRetInPtr = false; + this->llvmUsesThis = false; +} + +Type *TypeFunction::syntaxCopy() +{ + Type *treturn = next ? next->syntaxCopy() : NULL; + Arguments *params = Argument::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 = Argument::dim(t1->parameters); + if (dim != Argument::dim(t2->parameters)) + goto Ldistinct; + + for (size_t i = 0; i < dim; i++) + { Argument *arg1 = Argument::getNth(t1->parameters, i); + Argument *arg2 = Argument::getNth(t2->parameters, i); + + if (!arg1->type->equals(arg2->type)) + goto Ldistinct; + if (arg1->storageClass != arg2->storageClass) + inoutmismatch = 1; + } + } + else if (t1->parameters != t2->parameters) + goto Ldistinct; + + // The argument lists match + if (inoutmismatch) + goto Lnotcovariant; + if (t1->linkage != t2->linkage) + goto Lnotcovariant; + + Type *t1n = t1->next; + Type *t2n = t2->next; + + if (t1n->equals(t2n)) + goto Lcovariant; + if (t1n->ty != Tclass || t2n->ty != Tclass) + goto Lnotcovariant; + + // If t1n is forward referenced: + ClassDeclaration *cd = ((TypeClass *)t1n)->sym; + if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration()) + { + return 3; + } + + 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) +{ 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; + default: + assert(0); + } + buf->writeByte(mc); + // Write argument types + Argument::argsToDecoBuffer(buf, parameters); + //if (buf->data[buf->offset - 1] == '@') halt(); + buf->writeByte('Z' - varargs); // mark end of arg list + next->toDecoBuffer(buf); + inuse--; +} + +void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) +{ + char *p = NULL; + + if (inuse) + { inuse = 2; // flag error to caller + return; + } + inuse++; + if (next && (!ident || ident->toHChars2() == ident->toChars())) + next->toCBuffer2(buf, hgs, 0); + if (hgs->ddoc != 1) + { + switch (linkage) + { + case LINKd: p = NULL; break; + case LINKc: p = "C "; break; + case LINKwindows: p = "Windows "; break; + case LINKpascal: p = "Pascal "; break; + case LINKcpp: p = "C++ "; break; + default: + assert(0); + } + } + + if (!hgs->hdrgen && p) + buf->writestring(p); + if (ident) + { buf->writeByte(' '); + buf->writestring(ident->toHChars2()); + } + Argument::argsToCBuffer(buf, hgs, parameters, varargs); + inuse--; +} + +void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +{ + char *p = NULL; + + if (inuse) + { inuse = 2; // flag error to caller + return; + } + inuse++; + if (next) + next->toCBuffer2(buf, hgs, 0); + if (hgs->ddoc != 1) + { + switch (linkage) + { + case LINKd: p = NULL; break; + case LINKc: p = "C "; break; + case LINKwindows: p = "Windows "; break; + case LINKpascal: p = "Pascal "; break; + case LINKcpp: p = "C++ "; break; + default: + assert(0); + } + } + + if (!hgs->hdrgen && p) + buf->writestring(p); + buf->writestring(" function"); + Argument::argsToCBuffer(buf, hgs, parameters, varargs); + 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); + + TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction)); + memcpy(tf, this, sizeof(TypeFunction)); + if (parameters) + { tf->parameters = (Arguments *)parameters->copy(); + for (size_t i = 0; i < parameters->dim; i++) + { Argument *arg = (Argument *)parameters->data[i]; + Argument *cpy = (Argument *)mem.malloc(sizeof(Argument)); + memcpy(cpy, arg, sizeof(Argument)); + tf->parameters->data[i] = (void *)cpy; + } + } + + tf->linkage = sc->linkage; + if (!tf->next) + { + assert(global.errors); + tf->next = tvoid; + } + tf->next = tf->next->semantic(loc,sc); + if (tf->next->toBasetype()->ty == Tsarray) + { error(loc, "functions cannot return static array %s", tf->next->toChars()); + tf->next = Type::terror; + } + if (tf->next->toBasetype()->ty == Tfunction) + { error(loc, "functions cannot return a function"); + tf->next = Type::terror; + } + if (tf->next->toBasetype()->ty == Ttuple) + { error(loc, "functions cannot return a tuple"); + tf->next = Type::terror; + } + if (tf->next->isauto() && !(sc->flags & SCOPEctor)) + error(loc, "functions cannot return auto %s", tf->next->toChars()); + + if (tf->parameters) + { size_t dim = Argument::dim(tf->parameters); + + for (size_t i = 0; i < dim; i++) + { Argument *arg = Argument::getNth(tf->parameters, i); + Type *t; + + tf->inuse++; + arg->type = arg->type->semantic(loc,sc); + if (tf->inuse == 1) tf->inuse--; + t = arg->type->toBasetype(); + + if (arg->storageClass & (STCout | STCref | STClazy)) + { + if (t->ty == Tsarray) + error(loc, "cannot have out or ref parameter of type %s", t->toChars()); + } + if (!(arg->storageClass & STClazy) && t->ty == Tvoid) + error(loc, "cannot have parameter of type %s", arg->type->toChars()); + + if (arg->defaultArg) + { + arg->defaultArg = arg->defaultArg->semantic(sc); + arg->defaultArg = resolveProperties(sc, arg->defaultArg); + arg->defaultArg = arg->defaultArg->implicitCastTo(sc, arg->type); + } + + /* If arg turns out to be a tuple, the number of parameters may + * change. + */ + if (t->ty == Ttuple) + { dim = Argument::dim(tf->parameters); + i--; + } + } + } + tf->deco = tf->merge()->deco; + + if (tf->inuse) + { error(loc, "recursive type"); + tf->inuse = 0; + return terror; + } + + if (tf->varargs == 1 && tf->linkage != LINKd && Argument::dim(tf->parameters) == 0) + error(loc, "variadic functions with non-D linkage must have at least one parameter"); + + /* 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 = Argument::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? + + Argument *p = Argument::getNth(parameters, u); + assert(p); + if (u >= nargs) + { + if (p->defaultArg) + continue; + if (varargs == 2 && u + 1 == nparams) + goto L1; + goto Nomatch; // not enough arguments + } + arg = (Expression *)args->data[u]; + assert(arg); + if (p->storageClass & STClazy && p->type->ty == Tvoid && arg->type->ty != Tvoid) + m = MATCHconvert; + else + m = arg->implicitConvTo(p->type); + //printf("\tm = %d\n", m); + if (m == MATCHnomatch) // if no match + { + L1: + if (varargs == 2 && u + 1 == nparams) // if last varargs param + { Type *tb = p->type->toBasetype(); + TypeSArray *tsa; + integer_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 = (Expression *)args->data[u]; + assert(arg); +#if 1 + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + Type *tret = p->isLazyArray(); + if (tret) + { + if (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++) + { Argument *arg = (Argument *)parameters->data[i]; + Type *t = arg->type->reliesOnTident(); + if (t) + return t; + } + } + return next->reliesOnTident(); +} + +/***************************** 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; +} + +void TypeDelegate::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +{ + if (mod != this->mod) + { toCBuffer3(buf, hgs, mod); + return; + } + TypeFunction *tf = (TypeFunction *)next; + + tf->next->toCBuffer2(buf, hgs, 0); + buf->writestring(" delegate"); + Argument::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs); +} + +Expression *TypeDelegate::defaultInit(Loc loc) +{ +#if LOGDEFAULTINIT + printf("TypeDelegate::defaultInit() '%s'\n", toChars()); +#endif + Expression *e; + e = new NullExp(loc); + e->type = this; + return e; +} + +int TypeDelegate::isZeroInit() +{ + return 1; +} + +int TypeDelegate::checkBoolean() +{ + return TRUE; +} + +Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident) +{ +#if LOGDOTEXP + printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); +#endif + if (ident == Id::ptr) + { + e->type = tvoidptr; + return e; + } + else if (ident == Id::funcptr) + { + 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); + 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 (int i = 0; i < idents.dim; i++) + { + Identifier *id = (Identifier *)t->idents.data[i]; + if (id->dyncast() == DYNCAST_DSYMBOL) + { + TemplateInstance *ti = (TemplateInstance *)id; + + ti = (TemplateInstance *)ti->syntaxCopy(NULL); + id = (Identifier *)ti; + } + idents.data[i] = id; + } +} + + +void TypeQualified::addIdent(Identifier *ident) +{ + idents.push(ident); +} + +void TypeQualified::toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs) +{ + int i; + + for (i = 0; i < idents.dim; i++) + { Identifier *id = (Identifier *)idents.data[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) +{ + Identifier *id = NULL; + int i; + 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 = s->toAlias(); + //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); + for (i = 0; i < idents.dim; i++) + { Dsymbol *sm; + + id = (Identifier *)idents.data[i]; + 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->isConst() && v->getExpInitializer()) + { e = v->getExpInitializer()->exp; + } + else + e = new VarExp(loc, v); + t = e->type; + if (!t) + goto Lerror; + goto L3; + } + t = s->getType(); + if (!t && s->isDeclaration()) + t = s->isDeclaration()->type; + if (t) + { + sm = t->toDsymbol(sc); + if (sm) + { sm = sm->search(loc, id, 0); + if (sm) + goto L2; + } + //e = t->getProperty(loc, id); + e = new TypeExp(loc, t); + e = t->dotExp(sc, e, id); + i++; + L3: + for (; i < idents.dim; i++) + { + id = (Identifier *)idents.data[i]; + //printf("e: '%s', id: '%s', type = %p\n", e->toChars(), id->toChars(), e->type); + e = e->type->dotExp(sc, e, id); + } + *pe = e; + } + else + Lerror: + error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars()); + return; + } + L2: + s = sm->toAlias(); + } + + v = s->isVarDeclaration(); + if (v) + { + // It's not a type, it's an expression + if (v->isConst() && 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()) + { + Scope *scx; + + for (scx = sc; 1; scx = scx->enclosing) + { + if (!scx) + { error(loc, "forward reference to '%s'", t->toChars()); + return; + } + if (scx->scopesym == scopesym) + break; + } + t = t->semantic(loc, scx); + //((TypeIdentifier *)t)->resolve(loc, scx, pe, &t, ps); + } + } + if (t->ty == Ttuple) + *pt = t; + else + *pt = t->merge(); + } + if (!s) + { + error(loc, "identifier '%s' is not defined", toChars()); + } +} + +/***************************** 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) +{ 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 (int i = 0; i < idents.dim; i++) + { + Identifier *id = (Identifier *)idents.data[i]; + s = s->searchX(loc, sc, id); + if (!s) // failed to find a symbol + { //printf("\tdidn't find a symbol\n"); + break; + } + } + } + return s; +} + +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 (int 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.errors; + global.gag++; + + resolve(loc, sc, &e, &t, &s); + + global.gag--; + if (errors != global.errors) + { if (global.gag == 0) + global.errors = errors; + return this; + } + } + else + resolve(loc, sc, &e, &t, &s); + + if (!t) + { +#ifdef DEBUG + printf("2: "); +#endif + error(loc, "%s is used as a type", toChars()); + t = tvoid; + } + return t; +} + + +/***************************** TypeTypeof *****************************/ + +TypeTypeof::TypeTypeof(Loc loc, Expression *exp) + : TypeQualified(Ttypeof, loc) +{ + this->exp = exp; +} + +Type *TypeTypeof::syntaxCopy() +{ + TypeTypeof *t; + + t = new TypeTypeof(loc, exp->syntaxCopy()); + t->syntaxCopyHelper(this); + return t; +} + +Dsymbol *TypeTypeof::toDsymbol(Scope *sc) +{ + Type *t; + + t = semantic(0, sc); + if (t == this) + return NULL; + return t->toDsymbol(sc); +} + +void TypeTypeof::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +{ + if (mod != this->mod) + { toCBuffer3(buf, hgs, mod); + return; + } + buf->writestring("typeof("); + exp->toCBuffer(buf, hgs); + buf->writeByte(')'); + toCBuffer2Helper(buf, hgs); +} + +Type *TypeTypeof::semantic(Loc loc, Scope *sc) +{ Expression *e; + Type *t; + + //printf("TypeTypeof::semantic() %p\n", this); + + //static int nest; if (++nest == 50) *(char*)0=0; + +#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 + { + sc->intypeof++; + exp = exp->semantic(sc); + sc->intypeof--; + t = exp->type; + if (!t) + { + error(loc, "expression (%s) has no type", exp->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; + } + } + return t; + +Lerr: + return tvoid; +} + +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::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->memtype) + { +#ifdef DEBUG + printf("2: "); +#endif + error(sym->loc, "enum %s is forward referenced", sym->toChars()); + return tint32; + } + return sym->memtype->toBasetype(); +} + +void TypeEnum::toDecoBuffer(OutBuffer *buf) +{ 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) + { + return getProperty(e->loc, ident); + } + m = s->isEnumMember(); + em = m->value->copy(); + em->loc = e->loc; + return em; + +Lfwd: + error(e->loc, "forward reference of %s.%s", toChars(), ident->toChars()); + return new IntegerExp(0, 0, this); +} + +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 (!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() +{ + 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); + sym->semantic(sc); + 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) +{ 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() +{ + 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(); + sym->inuse = 0; + return result; +} + +int TypeTypedef::hasPointers() +{ + return toBasetype()->hasPointers(); +} + +/***************************** TypeStruct *****************************/ + +TypeStruct::TypeStruct(StructDeclaration *sym) + : Type(Tstruct, NULL) +{ + this->sym = sym; +} + +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 (sz > sym->structalign) + sz = sym->structalign; + return sz; +} + +Dsymbol *TypeStruct::toDsymbol(Scope *sc) +{ + return sym; +} + +void TypeStruct::toDecoBuffer(OutBuffer *buf) +{ 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) +{ unsigned offset; + + 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 IntegerExp(e->loc, 0, Type::tint32); + } + + if (ident == Id::tupleof) + { + /* Create a TupleExp + */ + Expressions *exps = new Expressions; + exps->reserve(sym->fields.dim); + for (size_t i = 0; i < sym->fields.dim; i++) + { VarDeclaration *v = (VarDeclaration *)sym->fields.data[i]; + Expression *fe = new DotVarExp(e->loc, e, v); + exps->push(fe); + } + e = new TupleExp(e->loc, exps); + e = e->semantic(sc); + 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); + } + s = s->toAlias(); + + v = s->isVarDeclaration(); + if (v && v->isConst()) + { 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; + + 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->semanticdone) + 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; + } + + 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) + { + 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->type = d->type; + 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); + 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)); +#if IN_LLVM + // LLVMDC modification + // this is *essential* + ((AddExp*)b)->llvmFieldIndex = true; +#endif + b->type = v->type->pointerTo(); + e = new PtrExp(e->loc, b); + e->type = v->type; + return e; + } + + de = new DotVarExp(e->loc, e, d); + return de->semantic(sc); +} + +unsigned TypeStruct::memalign(unsigned salign) +{ + sym->size(0); // give error for forward references + return sym->structalign; +} + +Expression *TypeStruct::defaultInit(Loc loc) +{ Symbol *s; + Declaration *d; + +#if LOGDEFAULTINIT + printf("TypeStruct::defaultInit() '%s'\n", toChars()); +#endif + s = sym->toInitializer(); + d = new SymbolDeclaration(sym->loc, s, sym); + assert(d); + d->type = this; + return new VarExp(sym->loc, d); +} + +int TypeStruct::isZeroInit() +{ + 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 sym->toPrettyChars(); +} + +Type *TypeClass::syntaxCopy() +{ + return this; +} + +Type *TypeClass::semantic(Loc loc, Scope *sc) +{ + //printf("TypeClass::semantic(%s)\n", sym->toChars()); + if (sym->scope) + sym->semantic(sym->scope); + return merge(); +} + +d_uns64 TypeClass::size(Loc loc) +{ + return PTRSIZE; +} + +Dsymbol *TypeClass::toDsymbol(Scope *sc) +{ + return sym; +} + +void TypeClass::toDecoBuffer(OutBuffer *buf) +{ 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) +{ unsigned offset; + + Expression *b; + VarDeclaration *v; + Dsymbol *s; + DotVarExp *de; + Declaration *d; + +#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 + */ + Expressions *exps = new Expressions; + exps->reserve(sym->fields.dim); + for (size_t i = 0; i < sym->fields.dim; i++) + { VarDeclaration *v = (VarDeclaration *)sym->fields.data[i]; + Expression *fe = new DotVarExp(e->loc, e, v); + exps->push(fe); + } + e = new TupleExp(e->loc, exps); + e = e->semantic(sc); + return e; + } + + s = sym->search(e->loc, ident, 0); +L1: + if (!s) + { + // See if it's a base class + ClassDeclaration *cbase; + for (cbase = sym->baseClass; cbase; cbase = cbase->baseClass) + { + if (cbase->ident->equals(ident)) + { + e = new DotTypeExp(0, e, cbase); + return e; + } + } + + if (ident == Id::classinfo) + { + Type *t; + + assert(ClassDeclaration::classinfo); + 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 + } + 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); + } + } + s = s->toAlias(); + v = s->isVarDeclaration(); + if (v && v->isConst()) + { 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; + + 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->semanticdone) + 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; + } + + d = s->isDeclaration(); + if (!d) + { + e->error("%s.%s is not a declaration", e->toChars(), ident->toChars()); + return new IntegerExp(e->loc, 1, Type::tint32); + } + + if (e->op == TOKtype) + { + VarExp *ve; + + if (d->needThis() && (hasThis(sc) || !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); + 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()); + } + } + + de = new DotVarExp(e->loc, new ThisExp(e->loc), d); + e = de->semantic(sc); + return e; + } + else if (d->isTupleDeclaration()) + { + e = new TupleExp(e->loc, d->isTupleDeclaration()); + e = e->semantic(sc); + return e; + } + else + 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->type = d->type; + return e; + } + + if (d->parent && d->toParent()->isModule()) + { + // (e, d) + VarExp *ve; + + 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::isauto() +{ + return sym->isauto; +} + +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("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 + Expression *e; + e = new NullExp(loc); + e->type = this; + return e; +} + +int TypeClass::isZeroInit() +{ + return 1; +} + +int TypeClass::checkBoolean() +{ + return TRUE; +} + +int TypeClass::hasPointers() +{ + return TRUE; +} + +/***************************** TypeTuple *****************************/ + +TypeTuple::TypeTuple(Arguments *arguments) + : Type(Ttuple, NULL) +{ + //printf("TypeTuple(this = %p)\n", this); + this->arguments = arguments; +#ifdef DEBUG + if (arguments) + { + for (size_t i = 0; i < arguments->dim; i++) + { + Argument *arg = (Argument *)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) +{ + Arguments *arguments = new Arguments; + if (exps) + { + arguments->setDim(exps->dim); + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + if (e->type->ty == Ttuple) + e->error("cannot form tuple of tuples"); + Argument *arg = new Argument(STCin, e->type, NULL, NULL); + arguments->data[i] = (void *)arg; + } + } + this->arguments = arguments; +} + +Type *TypeTuple::syntaxCopy() +{ + Arguments *args = Argument::arraySyntaxCopy(arguments); + Type *t = new TypeTuple(args); + return t; +} + +Type *TypeTuple::semantic(Loc loc, Scope *sc) +{ + //printf("TypeTuple::semantic(this = %p)\n", this); + 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++) + { Argument *arg1 = (Argument *)arguments->data[i]; + Argument *arg2 = (Argument *)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++) + { + Argument *arg = (Argument *)arguments->data[i]; + Type *t = arg->type->reliesOnTident(); + if (t) + return t; + } + } + return NULL; +} + +void TypeTuple::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +{ + Argument::argsToCBuffer(buf, hgs, arguments, 0); +} + +void TypeTuple::toDecoBuffer(OutBuffer *buf) +{ + //printf("TypeTuple::toDecoBuffer() this = %p\n", this); + OutBuffer buf2; + Argument::argsToDecoBuffer(&buf2, arguments); + 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->optimize(WANTvalue); + uinteger_t i1 = lwr->toUInteger(); + + upr = semanticLength(sc, tbn, upr); + upr = upr->optimize(WANTvalue); + 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; + } + + Arguments *args = new Arguments; + args->reserve(i2 - i1); + for (size_t i = i1; i < i2; i++) + { Argument *arg = (Argument *)tt->arguments->data[i]; + args->push(arg); + } + + return new TypeTuple(args); +} + +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->optimize(WANTvalue); + uinteger_t i1 = lwr->toUInteger(); + + upr = upr->semantic(sc); + upr = upr->optimize(WANTvalue); + 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()); +} + +/***************************** Argument *****************************/ + +Argument::Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg) +{ + this->type = type; + this->ident = ident; + this->storageClass = storageClass; + this->defaultArg = defaultArg; + this->vardecl = 0; +} + +Argument *Argument::syntaxCopy() +{ + Argument *a = new Argument(storageClass, + type ? type->syntaxCopy() : NULL, + ident, + defaultArg ? defaultArg->syntaxCopy() : NULL); + return a; +} + +Arguments *Argument::arraySyntaxCopy(Arguments *args) +{ Arguments *a = NULL; + + if (args) + { + a = new Arguments(); + a->setDim(args->dim); + for (size_t i = 0; i < a->dim; i++) + { Argument *arg = (Argument *)args->data[i]; + + arg = arg->syntaxCopy(); + a->data[i] = (void *)arg; + } + } + return a; +} + +char *Argument::argsTypesToChars(Arguments *args, int varargs) +{ OutBuffer *buf; + + buf = new OutBuffer(); + + buf->writeByte('('); + if (args) + { int i; + OutBuffer argbuf; + HdrGenState hgs; + + for (i = 0; i < args->dim; i++) + { Argument *arg; + + if (i) + buf->writeByte(','); + arg = (Argument *)args->data[i]; + argbuf.reset(); + arg->type->toCBuffer2(&argbuf, &hgs, 0); + buf->write(&argbuf); + } + if (varargs) + { + if (i && varargs == 1) + buf->writeByte(','); + buf->writestring("..."); + } + } + buf->writeByte(')'); + + return buf->toChars(); +} + +void Argument::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs) +{ + buf->writeByte('('); + if (arguments) + { int i; + OutBuffer argbuf; + + for (i = 0; i < arguments->dim; i++) + { Argument *arg; + + if (i) + buf->writestring(", "); + arg = (Argument *)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 (i && varargs == 1) + buf->writeByte(','); + buf->writestring("..."); + } + } + buf->writeByte(')'); +} + + +void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments) +{ + //printf("Argument::argsToDecoBuffer()\n"); + + // Write argument types + if (arguments) + { + size_t dim = Argument::dim(arguments); + for (size_t i = 0; i < dim; i++) + { + Argument *arg = Argument::getNth(arguments, i); + arg->toDecoBuffer(buf); + } + } +} + +/**************************************************** + * Determine if parameter is a lazy array of delegates. + * If so, return the return type of those delegates. + * If not, return NULL. + */ + +Type *Argument::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 && Argument::dim(tf->parameters) == 0) + { + return tf->next; // return type of delegate + } + } + } + } + return NULL; +} + +void Argument::toDecoBuffer(OutBuffer *buf) +{ + 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 + halt(); +#endif + assert(0); + } + type->toDecoBuffer(buf); +} + +/*************************************** + * Determine number of arguments, folding in tuples. + */ + +size_t Argument::dim(Arguments *args) +{ + size_t n = 0; + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { Argument *arg = (Argument *)args->data[i]; + Type *t = arg->type->toBasetype(); + + if (t->ty == Ttuple) + { TypeTuple *tu = (TypeTuple *)t; + n += dim(tu->arguments); + } + else + n++; + } + } + return n; +} + +/*************************************** + * Get nth Argument, folding in tuples. + * Returns: + * Argument* nth Argument + * NULL not found, *pn gets incremented by the number + * of Arguments + */ + +Argument *Argument::getNth(Arguments *args, size_t nth, size_t *pn) +{ + if (!args) + return NULL; + + size_t n = 0; + for (size_t i = 0; i < args->dim; i++) + { Argument *arg = (Argument *)args->data[i]; + Type *t = arg->type->toBasetype(); + + if (t->ty == Ttuple) + { TypeTuple *tu = (TypeTuple *)t; + arg = getNth(tu->arguments, nth - n, &n); + if (arg) + return arg; + } + else if (n == nth) + return arg; + else + n++; + } + + if (pn) + *pn += n; + return NULL; +} diff --git a/dmd/mtype.h b/dmd/mtype.h index aaf9ba07..2b39bdc5 100644 --- a/dmd/mtype.h +++ b/dmd/mtype.h @@ -1,691 +1,688 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_MTYPE_H -#define DMD_MTYPE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "stringtable.h" - -#include "arraytypes.h" -#include "expression.h" - -struct Scope; -struct Identifier; -struct Expression; -struct StructDeclaration; -struct ClassDeclaration; -struct VarDeclaration; -struct EnumDeclaration; -struct TypedefDeclaration; -struct TypeInfoDeclaration; -struct Dsymbol; -struct TemplateInstance; -enum LINK; - -struct TypeBasic; -struct HdrGenState; - -// Back end -#if IN_GCC -union tree_node; typedef union tree_node TYPE; -typedef TYPE type; -#else -typedef struct TYPE type; -#endif -struct Symbol; - -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, - TMAX -}; - -#define Tascii Tchar - -extern int Tsize_t; -extern int Tptrdiff_t; - -struct Type : Object -{ - TY ty; - Type *next; - 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 - - type *ctype; // for back end - - #define tvoid basic[Tvoid] - #define tint8 basic[Tint8] - #define tuns8 basic[Tuns8] - #define tint16 basic[Tint16] - #define tuns16 basic[Tuns16] - #define tint32 basic[Tint32] - #define tuns32 basic[Tuns32] - #define tint64 basic[Tint64] - #define tuns64 basic[Tuns64] - #define tfloat32 basic[Tfloat32] - #define tfloat64 basic[Tfloat64] - #define tfloat80 basic[Tfloat80] - - #define timaginary32 basic[Timaginary32] - #define timaginary64 basic[Timaginary64] - #define timaginary80 basic[Timaginary80] - - #define tcomplex32 basic[Tcomplex32] - #define tcomplex64 basic[Tcomplex64] - #define tcomplex80 basic[Tcomplex80] - - #define tbit basic[Tbit] - #define tbool basic[Tbool] - #define tchar basic[Tchar] - #define twchar basic[Twchar] - #define tdchar basic[Tdchar] - - // Some special types - #define tshiftcnt tint32 // right side of shift expression -// #define tboolean tint32 // result of boolean expression - #define tboolean tbool // result of boolean expression - #define tindex tint32 // array/ptr index - static Type *tvoidptr; // void* - #define terror basic[Terror] // for error recovery - - #define tsize_t basic[Tsize_t] // matches size_t alias - #define tptrdiff_t basic[Tptrdiff_t] // matches ptrdiff_t alias - #define thash_t tsize_t // matches hash_t alias - - static ClassDeclaration *typeinfo; - static ClassDeclaration *typeinfoclass; - static ClassDeclaration *typeinfointerface; - static ClassDeclaration *typeinfostruct; - static ClassDeclaration *typeinfotypedef; - static ClassDeclaration *typeinfopointer; - static ClassDeclaration *typeinfoarray; - static ClassDeclaration *typeinfostaticarray; - static ClassDeclaration *typeinfoassociativearray; - static ClassDeclaration *typeinfoenum; - static ClassDeclaration *typeinfofunction; - static ClassDeclaration *typeinfodelegate; - static ClassDeclaration *typeinfotypelist; - - static Type *basic[TMAX]; - static unsigned char mangleChar[TMAX]; - static StringTable stringtable; - - // 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(); - static void init(); - d_uns64 size(); - virtual d_uns64 size(Loc loc); - virtual unsigned alignsize(); - virtual Type *semantic(Loc loc, Scope *sc); - virtual void toDecoBuffer(OutBuffer *buf); - virtual void toTypeInfoBuffer(OutBuffer *buf); - Type *merge(); - void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - virtual void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - 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 isauto(); - 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 unsigned memalign(unsigned salign); - virtual Expression *defaultInit(Loc loc = 0); - virtual int isZeroInit(); // if initializer is 0 - virtual dt_t **toDt(dt_t **pdt); - Identifier *getTypeInfoIdent(int internal); - virtual MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Expression *getInternalTypeInfo(Scope *sc); - Expression *getTypeInfo(Scope *sc); - virtual TypeInfoDeclaration *getTypeInfoDeclaration(); - virtual int builtinTypeInfo(); - virtual Type *reliesOnTident(); - virtual Expression *toExpression(); - virtual int hasPointers(); - Type *nextOf() { return next; } - - static void error(Loc loc, const char *format, ...); - - // For backend - virtual unsigned totym(); - virtual type *toCtype(); - virtual type *toCParamtype(); - virtual Symbol *toSymbol(); - - // For eliminating dynamic_cast - virtual TypeBasic *isTypeBasic(); -}; - -struct TypeBasic : Type -{ - char *dstring; - char *cstring; - unsigned flags; - - TypeBasic(TY ty); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - Expression *getProperty(Loc loc, Identifier *ident); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - char *toChars(); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - 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(); - int builtinTypeInfo(); - - // For eliminating dynamic_cast - TypeBasic *isTypeBasic(); -}; - -struct TypeArray : Type -{ - TypeArray(TY ty, Type *next); - virtual void toPrettyBracket(OutBuffer *buf, HdrGenState *hgs) = 0; - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - 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); - void toTypeInfoBuffer(OutBuffer *buf); - void toPrettyBracket(OutBuffer *buf, HdrGenState *hgs); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int isString(); - int isZeroInit(); - unsigned memalign(unsigned salign); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - dt_t **toDt(dt_t **pdt); - dt_t **toDtElem(dt_t **pdt, Expression *e); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Expression *toExpression(); - int hasPointers(); - - type *toCtype(); - type *toCParamtype(); -}; - -// 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); - void toTypeInfoBuffer(OutBuffer *buf); - void toPrettyBracket(OutBuffer *buf, HdrGenState *hgs); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int isString(); - int isZeroInit(); - int checkBoolean(); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int builtinTypeInfo(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - - type *toCtype(); -}; - -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 toDecoBuffer(OutBuffer *buf); - void toPrettyBracket(OutBuffer *buf, HdrGenState *hgs); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - - // Back end - Symbol *aaGetSymbol(char *func, int flags); - - type *toCtype(); -}; - -struct TypePointer : Type -{ - TypePointer(Type *t); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - MATCH implicitConvTo(Type *to); - int isscalar(); - Expression *defaultInit(Loc loc); - int isZeroInit(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - - type *toCtype(); -}; - -struct TypeReference : Type -{ - TypeReference(Type *t); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - int isZeroInit(); -}; - -enum RET -{ - RETregs = 1, // returned in registers - RETstack = 2, // returned on stack -}; - -struct TypeFunction : Type -{ - Arguments *parameters; // function parameters - int varargs; // 1: T t, ...) style for variable number of arguments - // 2: T t ...) style for variable number of arguments - enum LINK linkage; // calling convention - - int inuse; - - TypeFunction(Arguments *parameters, Type *treturn, int varargs, enum LINK linkage); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - void toDecoBuffer(OutBuffer *buf); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Type *reliesOnTident(); - - int callMatch(Expressions *toargs); - type *toCtype(); - enum RET retStyle(); - - unsigned totym(); - - bool llvmRetInPtr; - bool llvmUsesThis; -}; - -struct TypeDelegate : Type -{ - TypeDelegate(Type *t); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - Expression *defaultInit(Loc loc); - int isZeroInit(); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int hasPointers(); - - type *toCtype(); -}; - -struct TypeQualified : Type -{ - Loc loc; - Array idents; // array of Identifier's representing ident.ident.ident etc. - - TypeQualified(TY ty, Loc loc); - void syntaxCopyHelper(TypeQualified *t); - void addIdent(Identifier *ident); - void toCBuffer2Helper(OutBuffer *buf, Identifier *ident, 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); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - 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); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Type *semantic(Loc loc, Scope *sc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); -}; - -struct TypeTypeof : TypeQualified -{ - Expression *exp; - - TypeTypeof(Loc loc, Expression *exp); - Type *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - 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); - void toTypeInfoBuffer(OutBuffer *buf); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - unsigned memalign(unsigned salign); - Expression *defaultInit(Loc loc); - int isZeroInit(); - int checkBoolean(); - dt_t **toDt(dt_t **pdt); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - - type *toCtype(); -}; - -struct TypeEnum : Type -{ - EnumDeclaration *sym; - - TypeEnum(EnumDeclaration *sym); - d_uns64 size(Loc loc); - unsigned alignsize(); - char *toChars(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf); - void toTypeInfoBuffer(OutBuffer *buf); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - 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(); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - - type *toCtype(); -}; - -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); - void toTypeInfoBuffer(OutBuffer *buf); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - 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(); - dt_t **toDt(dt_t **pdt); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - - type *toCtype(); - type *toCParamtype(); -}; - -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); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - 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(); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - int isauto(); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - - type *toCtype(); - - Symbol *toSymbol(); -}; - -struct TypeTuple : Type -{ - Arguments *arguments; // types making up the tuple - - TypeTuple(Arguments *arguments); - TypeTuple(Expressions *exps); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - int equals(Object *o); - Type *reliesOnTident(); - void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - void toDecoBuffer(OutBuffer *buf); - 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, Identifier *ident, HdrGenState *hgs); -}; - -/**************************************************************/ - -//enum InOut { None, In, Out, InOut, Lazy }; - -struct Argument : Object -{ - //enum InOut inout; - unsigned storageClass; - Type *type; - Identifier *ident; - Expression *defaultArg; - - Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg); - Argument *syntaxCopy(); - Type *isLazyArray(); - void toDecoBuffer(OutBuffer *buf); - static Arguments *arraySyntaxCopy(Arguments *args); - static char *argsTypesToChars(Arguments *args, int varargs); - static void argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs); - static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments); - static size_t dim(Arguments *arguments); - static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL); - - // backend - VarDeclaration* vardecl; -}; - -extern int PTRSIZE; -extern int REALSIZE; -extern int REALPAD; -extern int Tsize_t; -extern int Tptrdiff_t; - -#endif /* DMD_MTYPE_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_MTYPE_H +#define DMD_MTYPE_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "stringtable.h" + +#include "arraytypes.h" +#include "expression.h" + +struct Scope; +struct Identifier; +struct Expression; +struct StructDeclaration; +struct ClassDeclaration; +struct VarDeclaration; +struct EnumDeclaration; +struct TypedefDeclaration; +struct TypeInfoDeclaration; +struct Dsymbol; +struct TemplateInstance; +enum LINK; + +struct TypeBasic; +struct HdrGenState; + +// Back end +#if IN_GCC +union tree_node; typedef union tree_node TYPE; +typedef TYPE type; +#else +typedef struct TYPE type; +#endif +struct Symbol; + +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, + TMAX +}; + +#define Tascii Tchar + +extern int Tsize_t; +extern int Tptrdiff_t; + +struct Type : Object +{ + TY ty; + unsigned char mod; // modifiers (MODconst, MODinvariant) + #define MODconst 1 // type is const + #define MODinvariant 2 // type is invariant + Type *next; + 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 + + type *ctype; // for back end + + #define tvoid basic[Tvoid] + #define tint8 basic[Tint8] + #define tuns8 basic[Tuns8] + #define tint16 basic[Tint16] + #define tuns16 basic[Tuns16] + #define tint32 basic[Tint32] + #define tuns32 basic[Tuns32] + #define tint64 basic[Tint64] + #define tuns64 basic[Tuns64] + #define tfloat32 basic[Tfloat32] + #define tfloat64 basic[Tfloat64] + #define tfloat80 basic[Tfloat80] + + #define timaginary32 basic[Timaginary32] + #define timaginary64 basic[Timaginary64] + #define timaginary80 basic[Timaginary80] + + #define tcomplex32 basic[Tcomplex32] + #define tcomplex64 basic[Tcomplex64] + #define tcomplex80 basic[Tcomplex80] + + #define tbit basic[Tbit] + #define tbool basic[Tbool] + #define tchar basic[Tchar] + #define twchar basic[Twchar] + #define tdchar basic[Tdchar] + + // Some special types + #define tshiftcnt tint32 // right side of shift expression +// #define tboolean tint32 // result of boolean expression + #define tboolean tbool // result of boolean expression + #define tindex tint32 // array/ptr index + static Type *tvoidptr; // void* + #define terror basic[Terror] // for error recovery + + #define tsize_t basic[Tsize_t] // matches size_t alias + #define tptrdiff_t basic[Tptrdiff_t] // matches ptrdiff_t alias + #define thash_t tsize_t // matches hash_t alias + + static ClassDeclaration *typeinfo; + static ClassDeclaration *typeinfoclass; + static ClassDeclaration *typeinfointerface; + static ClassDeclaration *typeinfostruct; + static ClassDeclaration *typeinfotypedef; + static ClassDeclaration *typeinfopointer; + static ClassDeclaration *typeinfoarray; + static ClassDeclaration *typeinfostaticarray; + static ClassDeclaration *typeinfoassociativearray; + static ClassDeclaration *typeinfoenum; + static ClassDeclaration *typeinfofunction; + static ClassDeclaration *typeinfodelegate; + static ClassDeclaration *typeinfotypelist; + + static Type *basic[TMAX]; + static unsigned char mangleChar[TMAX]; + static StringTable stringtable; + + // 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(); + static void init(); + d_uns64 size(); + virtual d_uns64 size(Loc loc); + virtual unsigned alignsize(); + virtual Type *semantic(Loc loc, Scope *sc); + virtual void toDecoBuffer(OutBuffer *buf); + Type *merge(); + 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 isauto(); + 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 unsigned memalign(unsigned salign); + virtual Expression *defaultInit(Loc loc = 0); + virtual int isZeroInit(); // if initializer is 0 + virtual dt_t **toDt(dt_t **pdt); + Identifier *getTypeInfoIdent(int internal); + virtual MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + Expression *getInternalTypeInfo(Scope *sc); + Expression *getTypeInfo(Scope *sc); + virtual TypeInfoDeclaration *getTypeInfoDeclaration(); + virtual int builtinTypeInfo(); + virtual Type *reliesOnTident(); + virtual Expression *toExpression(); + virtual int hasPointers(); + Type *nextOf() { return next; } + + static void error(Loc loc, const char *format, ...); + + // For backend + virtual unsigned totym(); + virtual type *toCtype(); + virtual type *toCParamtype(); + virtual Symbol *toSymbol(); + + // For eliminating dynamic_cast + virtual TypeBasic *isTypeBasic(); +}; + +struct TypeBasic : Type +{ + char *dstring; + char *cstring; + unsigned flags; + + TypeBasic(TY ty); + Type *syntaxCopy(); + d_uns64 size(Loc loc); + unsigned alignsize(); + Expression *getProperty(Loc loc, Identifier *ident); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + char *toChars(); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + 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(); + int builtinTypeInfo(); + + // 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); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + int isString(); + int isZeroInit(); + unsigned memalign(unsigned salign); + MATCH implicitConvTo(Type *to); + Expression *defaultInit(Loc loc); + dt_t **toDt(dt_t **pdt); + dt_t **toDtElem(dt_t **pdt, Expression *e); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + TypeInfoDeclaration *getTypeInfoDeclaration(); + Expression *toExpression(); + int hasPointers(); + + type *toCtype(); + type *toCParamtype(); +}; + +// 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); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + int isString(); + int isZeroInit(); + int checkBoolean(); + MATCH implicitConvTo(Type *to); + Expression *defaultInit(Loc loc); + int builtinTypeInfo(); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + + type *toCtype(); +}; + +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 toDecoBuffer(OutBuffer *buf); + 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 checkBoolean(); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + + // Back end + Symbol *aaGetSymbol(char *func, int flags); + + type *toCtype(); +}; + +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(); + Expression *defaultInit(Loc loc); + int isZeroInit(); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + + type *toCtype(); +}; + +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(); +}; + +enum RET +{ + RETregs = 1, // returned in registers + RETstack = 2, // returned on stack +}; + +struct TypeFunction : Type +{ + Arguments *parameters; // function parameters + int varargs; // 1: T t, ...) style for variable number of arguments + // 2: T t ...) style for variable number of arguments + enum LINK linkage; // calling convention + + int inuse; + + TypeFunction(Arguments *parameters, Type *treturn, int varargs, enum LINK linkage); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + void toDecoBuffer(OutBuffer *buf); + void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + TypeInfoDeclaration *getTypeInfoDeclaration(); + Type *reliesOnTident(); + + int callMatch(Expressions *toargs); + type *toCtype(); + enum RET retStyle(); + + unsigned totym(); + + bool llvmRetInPtr; + bool llvmUsesThis; +}; + +struct TypeDelegate : Type +{ + TypeDelegate(Type *t); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + d_uns64 size(Loc loc); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *defaultInit(Loc loc); + int isZeroInit(); + int checkBoolean(); + TypeInfoDeclaration *getTypeInfoDeclaration(); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + int hasPointers(); + + type *toCtype(); +}; + +struct TypeQualified : Type +{ + Loc loc; + Array idents; // array of Identifier's representing ident.ident.ident etc. + + TypeQualified(TY ty, Loc loc); + void syntaxCopyHelper(TypeQualified *t); + void addIdent(Identifier *ident); + void toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs); + d_uns64 size(Loc loc); + void resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym, + Expression **pe, Type **pt, Dsymbol **ps); +}; + +struct TypeIdentifier : TypeQualified +{ + Identifier *ident; + + TypeIdentifier(Loc loc, Identifier *ident); + Type *syntaxCopy(); + //char *toChars(); + void toDecoBuffer(OutBuffer *buf); + 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); + 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); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); +}; + +struct TypeTypeof : TypeQualified +{ + Expression *exp; + + TypeTypeof(Loc loc, Expression *exp); + Type *syntaxCopy(); + Dsymbol *toDsymbol(Scope *sc); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Type *semantic(Loc loc, Scope *sc); + d_uns64 size(Loc loc); +}; + +struct 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); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + unsigned memalign(unsigned salign); + Expression *defaultInit(Loc loc); + int isZeroInit(); + int checkBoolean(); + dt_t **toDt(dt_t **pdt); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + + type *toCtype(); +}; + +struct TypeEnum : Type +{ + EnumDeclaration *sym; + + TypeEnum(EnumDeclaration *sym); + d_uns64 size(Loc loc); + unsigned alignsize(); + char *toChars(); + Type *semantic(Loc loc, Scope *sc); + Dsymbol *toDsymbol(Scope *sc); + void toDecoBuffer(OutBuffer *buf); + 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(); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + + type *toCtype(); +}; + +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); + 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(); + dt_t **toDt(dt_t **pdt); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + + type *toCtype(); + type *toCParamtype(); +}; + +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); + 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(); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + int isauto(); + int checkBoolean(); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + + type *toCtype(); + + Symbol *toSymbol(); +}; + +struct TypeTuple : Type +{ + Arguments *arguments; // types making up the tuple + + TypeTuple(Arguments *arguments); + TypeTuple(Expressions *exps); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + int equals(Object *o); + Type *reliesOnTident(); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toDecoBuffer(OutBuffer *buf); + 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 Argument : Object +{ + //enum InOut inout; + unsigned storageClass; + Type *type; + Identifier *ident; + Expression *defaultArg; + + Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg); + Argument *syntaxCopy(); + Type *isLazyArray(); + void toDecoBuffer(OutBuffer *buf); + static Arguments *arraySyntaxCopy(Arguments *args); + static char *argsTypesToChars(Arguments *args, int varargs); + static void argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs); + static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments); + static size_t dim(Arguments *arguments); + static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL); + + // backend + VarDeclaration* vardecl; +}; + +extern int PTRSIZE; +extern int REALSIZE; +extern int REALPAD; +extern int Tsize_t; +extern int Tptrdiff_t; + +#endif /* DMD_MTYPE_H */ diff --git a/dmd/parse.c b/dmd/parse.c index 77e2053b..59f79d7a 100644 --- a/dmd/parse.c +++ b/dmd/parse.c @@ -637,6 +637,14 @@ Condition *Parser::parseVersionCondition() id = token.ident; else if (token.value == TOKint32v) level = (unsigned)token.uns64value; +#if V2 + /* Allow: + * version (unittest) + * even though unittest is a keyword + */ + else if (token.value == TOKunittest) + id = Lexer::idPool(Token::toChars(TOKunittest)); +#endif else error("identifier or integer expected, not %s", token.toChars()); nextToken(); diff --git a/dmd/scope.c b/dmd/scope.c index 1b6f6e08..931782db 100644 --- a/dmd/scope.c +++ b/dmd/scope.c @@ -1,359 +1,361 @@ - -// Copyright (c) 1999-2005 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" - -#include "mars.h" -#include "init.h" -#include "identifier.h" -#include "attrib.h" -#include "dsymbol.h" -#include "scope.h" -#include "declaration.h" -#include "aggregate.h" -#include "module.h" -#include "id.h" - -Scope *Scope::freelist = NULL; - -void *Scope::operator new(size_t size) -{ - if (freelist) - { - Scope *s = freelist; - freelist = s->enclosing; - //printf("freelist %p\n", s); - assert(s->flags & SCOPEfree); - s->flags &= ~SCOPEfree; - return s; - } - - void *p = ::operator new(size); - //printf("new %p\n", p); - return p; -} - -Scope::Scope() -{ // Create root scope - - //printf("Scope::Scope() %p\n", this); - this->module = NULL; - this->scopesym = NULL; - this->sd = NULL; - this->enclosing = NULL; - this->parent = NULL; - this->sw = NULL; - this->tf = NULL; - this->tfOfTry = 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->intypeof = 0; - this->parameterSpecialization = 0; - this->callSuper = 0; - this->flags = 0; - this->anonAgg = NULL; - this->lastdc = NULL; - this->lastoffset = 0; - this->docbuf = NULL; -} - -Scope::Scope(Scope *enclosing) -{ - //printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this); - assert(!(enclosing->flags & SCOPEfree)); - this->module = enclosing->module; - this->func = enclosing->func; - this->parent = enclosing->parent; - this->scopesym = NULL; - this->sd = NULL; - this->sw = enclosing->sw; - this->tf = enclosing->tf; - this->tfOfTry = enclosing->tfOfTry; - 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->intypeof = enclosing->intypeof; - this->parameterSpecialization = enclosing->parameterSpecialization; - this->callSuper = enclosing->callSuper; - this->flags = 0; - this->anonAgg = NULL; - this->lastdc = NULL; - this->lastoffset = 0; - this->docbuf = enclosing->docbuf; - assert(this != enclosing); -} - -Scope *Scope::createGlobal(Module *module) -{ - Scope *sc; - - sc = new Scope(); - sc->module = module; - sc->scopesym = new ScopeDsymbol(); - sc->scopesym->symtab = new DsymbolTable(); - - // Add top level package as member of this global scope - Dsymbol *m = module; - while (m->parent) - m = m->parent; - m->addMember(NULL, sc->scopesym, 1); - m->parent = NULL; // got changed by addMember() - - // Create the module scope underneath the global scope - sc = sc->push(module); - sc->parent = module; - return sc; -} - -Scope *Scope::push() -{ - //printf("Scope::push()\n"); - Scope *s = new Scope(this); - assert(this != s); - return s; -} - -Scope *Scope::push(ScopeDsymbol *ss) -{ - //printf("Scope::push(%s)\n", ss->toChars()); - Scope *s = push(); - s->scopesym = ss; - return s; -} - -Scope *Scope::pop() -{ - //printf("Scope::pop() %p nofree = %d\n", this, nofree); - Scope *enc = enclosing; - - if (enclosing) - enclosing->callSuper |= callSuper; - - if (!nofree) - { enclosing = freelist; - freelist = this; - flags |= SCOPEfree; - } - - return enc; -} - -void Scope::mergeCallSuper(Loc loc, unsigned cs) -{ - // This does a primitive flow analysis to support the restrictions - // regarding when and how constructors can appear. - // It merges the results of two paths. - // The two paths are callSuper and cs; the result is merged into callSuper. - - if (cs != callSuper) - { int a; - int b; - - callSuper |= cs & (CSXany_ctor | CSXlabel); - if (cs & CSXreturn) - { - } - else if (callSuper & CSXreturn) - { - callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel)); - } - else - { - a = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0; - b = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0; - if (a != b) - error(loc, "one path skips constructor"); - callSuper |= cs; - } - } -} - -Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) -{ Dsymbol *s; - Scope *sc; - - //printf("Scope::search(%p, '%s')\n", this, ident->toChars()); - if (ident == Id::empty) - { - // Look for module scope - for (sc = this; sc; sc = sc->enclosing) - { - assert(sc != sc->enclosing); - if (sc->scopesym) - { - s = sc->scopesym->isModule(); - if (s) - { - //printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars()); - if (pscopesym) - *pscopesym = sc->scopesym; - return s; - } - } - } - return NULL; - } - - for (sc = this; sc; sc = sc->enclosing) - { - assert(sc != sc->enclosing); - if (sc->scopesym) - { - //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind()); - s = sc->scopesym->search(loc, ident, 0); - if (s) - { - if ((global.params.warnings || - global.params.Dversion > 1) && - ident == Id::length && - sc->scopesym->isArrayScopeSymbol() && - sc->enclosing && - sc->enclosing->search(loc, ident, NULL)) - { - if (global.params.warnings) - fprintf(stdmsg, "warning - "); - error(s->loc, "array 'length' hides other 'length' name in outer scope"); - } - - //printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind()); - if (pscopesym) - *pscopesym = sc->scopesym; - return s; - } - } - } - - return NULL; -} - -Dsymbol *Scope::insert(Dsymbol *s) -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) - { - //printf("\tsc = %p\n", sc); - if (sc->scopesym) - { - //printf("\t\tsc->scopesym = %p\n", sc->scopesym); - if (!sc->scopesym->symtab) - sc->scopesym->symtab = new DsymbolTable(); - return sc->scopesym->symtab->insert(s); - } - } - assert(0); - return NULL; -} - -/******************************************** - * Search enclosing scopes for ClassDeclaration. - */ - -ClassDeclaration *Scope::getClassScope() -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) - { - ClassDeclaration *cd; - - if (sc->scopesym) - { - cd = sc->scopesym->isClassDeclaration(); - if (cd) - return cd; - } - } - return NULL; -} - -/******************************************** - * Search enclosing scopes for ClassDeclaration. - */ - -AggregateDeclaration *Scope::getStructClassScope() -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) - { - AggregateDeclaration *ad; - - if (sc->scopesym) - { - ad = sc->scopesym->isClassDeclaration(); - if (ad) - return ad; - else - { ad = sc->scopesym->isStructDeclaration(); - if (ad) - return ad; - } - } - } - return NULL; -} - -/******************************************* - * For TemplateDeclarations, we need to remember the Scope - * where it was declared. So mark the Scope as not - * to be free'd. - */ - -void Scope::setNoFree() -{ Scope *sc; - //int i = 0; - - //printf("Scope::setNoFree(this = %p)\n", this); - for (sc = this; sc; sc = sc->enclosing) - { - //printf("\tsc = %p\n", sc); - sc->nofree = 1; - - assert(!(flags & SCOPEfree)); - //assert(sc != sc->enclosing); - //assert(!sc->enclosing || sc != sc->enclosing->enclosing); - //if (++i == 10) - //assert(0); - } -} + +// Copyright (c) 1999-2005 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include + +#include "root.h" + +#include "mars.h" +#include "init.h" +#include "identifier.h" +#include "attrib.h" +#include "dsymbol.h" +#include "scope.h" +#include "declaration.h" +#include "aggregate.h" +#include "module.h" +#include "id.h" + +Scope *Scope::freelist = NULL; + +void *Scope::operator new(size_t size) +{ + if (freelist) + { + Scope *s = freelist; + freelist = s->enclosing; + //printf("freelist %p\n", s); + assert(s->flags & SCOPEfree); + s->flags &= ~SCOPEfree; + return s; + } + + void *p = ::operator new(size); + //printf("new %p\n", p); + return p; +} + +Scope::Scope() +{ // Create root scope + + //printf("Scope::Scope() %p\n", this); + this->module = NULL; + this->scopesym = NULL; + this->sd = NULL; + this->enclosing = NULL; + this->parent = NULL; + this->sw = NULL; + this->tf = NULL; + this->tfOfTry = 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->intypeof = 0; + this->parameterSpecialization = 0; + this->callSuper = 0; + this->flags = 0; + this->anonAgg = NULL; + this->lastdc = NULL; + this->lastoffset = 0; + this->docbuf = NULL; +} + +Scope::Scope(Scope *enclosing) +{ + //printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this); + assert(!(enclosing->flags & SCOPEfree)); + this->module = enclosing->module; + this->func = enclosing->func; + this->parent = enclosing->parent; + this->scopesym = NULL; + this->sd = NULL; + this->sw = enclosing->sw; + this->tf = enclosing->tf; + this->tfOfTry = enclosing->tfOfTry; + 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->intypeof = enclosing->intypeof; + this->parameterSpecialization = enclosing->parameterSpecialization; + this->callSuper = enclosing->callSuper; + this->flags = 0; + this->anonAgg = NULL; + this->lastdc = NULL; + this->lastoffset = 0; + this->docbuf = enclosing->docbuf; + assert(this != enclosing); +} + +Scope *Scope::createGlobal(Module *module) +{ + Scope *sc; + + sc = new Scope(); + sc->module = module; + sc->scopesym = new ScopeDsymbol(); + sc->scopesym->symtab = new DsymbolTable(); + + // Add top level package as member of this global scope + Dsymbol *m = module; + while (m->parent) + m = m->parent; + m->addMember(NULL, sc->scopesym, 1); + m->parent = NULL; // got changed by addMember() + + // Create the module scope underneath the global scope + sc = sc->push(module); + sc->parent = module; + return sc; +} + +Scope *Scope::push() +{ + //printf("Scope::push()\n"); + Scope *s = new Scope(this); + assert(this != s); + return s; +} + +Scope *Scope::push(ScopeDsymbol *ss) +{ + //printf("Scope::push(%s)\n", ss->toChars()); + Scope *s = push(); + s->scopesym = ss; + return s; +} + +Scope *Scope::pop() +{ + //printf("Scope::pop() %p nofree = %d\n", this, nofree); + Scope *enc = enclosing; + + if (enclosing) + enclosing->callSuper |= callSuper; + + if (!nofree) + { enclosing = freelist; + freelist = this; + flags |= SCOPEfree; + } + + return enc; +} + +void Scope::mergeCallSuper(Loc loc, unsigned cs) +{ + // This does a primitive flow analysis to support the restrictions + // regarding when and how constructors can appear. + // It merges the results of two paths. + // The two paths are callSuper and cs; the result is merged into callSuper. + + if (cs != callSuper) + { int a; + int b; + + callSuper |= cs & (CSXany_ctor | CSXlabel); + if (cs & CSXreturn) + { + } + else if (callSuper & CSXreturn) + { + callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel)); + } + else + { + a = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0; + b = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0; + if (a != b) + error(loc, "one path skips constructor"); + callSuper |= cs; + } + } +} + +Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) +{ Dsymbol *s; + Scope *sc; + + //printf("Scope::search(%p, '%s')\n", this, ident->toChars()); + if (ident == Id::empty) + { + // Look for module scope + for (sc = this; sc; sc = sc->enclosing) + { + assert(sc != sc->enclosing); + if (sc->scopesym) + { + s = sc->scopesym->isModule(); + if (s) + { + //printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars()); + if (pscopesym) + *pscopesym = sc->scopesym; + return s; + } + } + } + return NULL; + } + + for (sc = this; sc; sc = sc->enclosing) + { + assert(sc != sc->enclosing); + if (sc->scopesym) + { + //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind()); + s = sc->scopesym->search(loc, ident, 0); + if (s) + { + if ((global.params.warnings || + global.params.Dversion > 1) && + ident == Id::length && + sc->scopesym->isArrayScopeSymbol() && + sc->enclosing && + sc->enclosing->search(loc, ident, NULL)) + { + if (global.params.warnings) + fprintf(stdmsg, "warning - "); + error(s->loc, "array 'length' hides other 'length' name in outer scope"); + } + + //printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind()); + if (pscopesym) + *pscopesym = sc->scopesym; + return s; + } + } + } + + return NULL; +} + +Dsymbol *Scope::insert(Dsymbol *s) +{ Scope *sc; + + for (sc = this; sc; sc = sc->enclosing) + { + //printf("\tsc = %p\n", sc); + if (sc->scopesym) + { + //printf("\t\tsc->scopesym = %p\n", sc->scopesym); + if (!sc->scopesym->symtab) + sc->scopesym->symtab = new DsymbolTable(); + return sc->scopesym->symtab->insert(s); + } + } + assert(0); + return NULL; +} + +/******************************************** + * Search enclosing scopes for ClassDeclaration. + */ + +ClassDeclaration *Scope::getClassScope() +{ Scope *sc; + + for (sc = this; sc; sc = sc->enclosing) + { + ClassDeclaration *cd; + + if (sc->scopesym) + { + cd = sc->scopesym->isClassDeclaration(); + if (cd) + return cd; + } + } + return NULL; +} + +/******************************************** + * Search enclosing scopes for ClassDeclaration. + */ + +AggregateDeclaration *Scope::getStructClassScope() +{ Scope *sc; + + for (sc = this; sc; sc = sc->enclosing) + { + AggregateDeclaration *ad; + + if (sc->scopesym) + { + ad = sc->scopesym->isClassDeclaration(); + if (ad) + return ad; + else + { ad = sc->scopesym->isStructDeclaration(); + if (ad) + return ad; + } + } + } + return NULL; +} + +/******************************************* + * For TemplateDeclarations, we need to remember the Scope + * where it was declared. So mark the Scope as not + * to be free'd. + */ + +void Scope::setNoFree() +{ Scope *sc; + //int i = 0; + + //printf("Scope::setNoFree(this = %p)\n", this); + for (sc = this; sc; sc = sc->enclosing) + { + //printf("\tsc = %p\n", sc); + sc->nofree = 1; + + assert(!(flags & SCOPEfree)); + //assert(sc != sc->enclosing); + //assert(!sc->enclosing || sc != sc->enclosing->enclosing); + //if (++i == 10) + //assert(0); + } +} diff --git a/dmd/scope.h b/dmd/scope.h index e559f9d7..1460d8b2 100644 --- a/dmd/scope.h +++ b/dmd/scope.h @@ -1,110 +1,111 @@ - -// Copyright (c) 1999-2005 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_SCOPE_H -#define DMD_SCOPE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -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; -enum LINK; -enum PROT; - -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 *tf; // enclosing try finally statement; set inside its finally block - TryFinallyStatement *tfOfTry; // enclosing try finally statement; set inside its try block - Statement *sbreak; // enclosing statement that supports "break" - Statement *scontinue; // enclosing statement that supports "continue" - ForeachStatement *fes; // if nested function for ForeachStatement, this is it - unsigned offset; // next offset to use in aggregate - int inunion; // we're processing members of a union - int incontract; // we're inside contract code - int nofree; // set if shouldn't free it - int noctor; // set if constructor calls aren't allowed - int intypeof; // in typeof(exp) - int parameterSpecialization; // if in template parameter specialization - - unsigned callSuper; // primitive flow analysis for constructors -#define CSXthis_ctor 1 // called this() -#define CSXsuper_ctor 2 // called super() -#define CSXthis 4 // referenced this -#define CSXsuper 8 // referenced super -#define CSXlabel 0x10 // seen a label -#define CSXreturn 0x20 // seen a return statement -#define CSXany_ctor 0x40 // either this() or super() was called - - unsigned structalign; // alignment for struct members - enum LINK linkage; // linkage for external functions - - enum PROT protection; // protection for class members - int explicitProtection; // set if in an explicit protection attribute - - unsigned stc; // storage class - - unsigned flags; -#define SCOPEctor 1 // constructor type -#define SCOPEstaticif 2 // inside static if -#define SCOPEfree 4 // is on free list - - AnonymousAggregateDeclaration *anonAgg; // for temporary analysis - - DocComment *lastdc; // documentation comment for last symbol at this scope - unsigned lastoffset; // offset in docbuf of where to insert next dec - OutBuffer *docbuf; // buffer for documentation output - - static Scope *freelist; - static void *operator new(size_t sz); - static Scope *createGlobal(Module *module); - - Scope(); - Scope(Module *module); - Scope(Scope *enclosing); - - Scope *push(); - Scope *push(ScopeDsymbol *ss); - Scope *pop(); - - void mergeCallSuper(Loc loc, unsigned cs); - - Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym); - Dsymbol *insert(Dsymbol *s); - - ClassDeclaration *getClassScope(); - AggregateDeclaration *getStructClassScope(); - void setNoFree(); -}; - -#endif /* DMD_SCOPE_H */ + +// Copyright (c) 1999-2005 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_SCOPE_H +#define DMD_SCOPE_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +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; +enum LINK; +enum PROT; + +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 *tf; // enclosing try finally statement; set inside its finally block + TryFinallyStatement *tfOfTry; // enclosing try finally statement; set inside its try block + Statement *sbreak; // enclosing statement that supports "break" + Statement *scontinue; // enclosing statement that supports "continue" + ForeachStatement *fes; // if nested function for ForeachStatement, this is it + unsigned offset; // next offset to use in aggregate + int inunion; // we're processing members of a union + int incontract; // we're inside contract code + int nofree; // set if shouldn't free it + int noctor; // set if constructor calls aren't allowed + int intypeof; // in typeof(exp) + int parameterSpecialization; // if in template parameter specialization + int noaccesscheck; // don't do access checks + + unsigned callSuper; // primitive flow analysis for constructors +#define CSXthis_ctor 1 // called this() +#define CSXsuper_ctor 2 // called super() +#define CSXthis 4 // referenced this +#define CSXsuper 8 // referenced super +#define CSXlabel 0x10 // seen a label +#define CSXreturn 0x20 // seen a return statement +#define CSXany_ctor 0x40 // either this() or super() was called + + unsigned structalign; // alignment for struct members + enum LINK linkage; // linkage for external functions + + enum PROT protection; // protection for class members + int explicitProtection; // set if in an explicit protection attribute + + unsigned stc; // storage class + + unsigned flags; +#define SCOPEctor 1 // constructor type +#define SCOPEstaticif 2 // inside static if +#define SCOPEfree 4 // is on free list + + AnonymousAggregateDeclaration *anonAgg; // for temporary analysis + + DocComment *lastdc; // documentation comment for last symbol at this scope + unsigned lastoffset; // offset in docbuf of where to insert next dec + OutBuffer *docbuf; // buffer for documentation output + + static Scope *freelist; + static void *operator new(size_t sz); + static Scope *createGlobal(Module *module); + + Scope(); + Scope(Module *module); + Scope(Scope *enclosing); + + Scope *push(); + Scope *push(ScopeDsymbol *ss); + Scope *pop(); + + void mergeCallSuper(Loc loc, unsigned cs); + + Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym); + Dsymbol *insert(Dsymbol *s); + + ClassDeclaration *getClassScope(); + AggregateDeclaration *getStructClassScope(); + void setNoFree(); +}; + +#endif /* DMD_SCOPE_H */ diff --git a/dmd/statement.c b/dmd/statement.c index 5caa25cb..7f5775ba 100644 --- a/dmd/statement.c +++ b/dmd/statement.c @@ -1,3608 +1,3608 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "mem.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" - -/******************************** Statement ***************************/ - -Statement::Statement(Loc loc) - : loc(loc) -{ -#ifdef _DH - // If this is an in{} contract scope statement (skip for determining - // inlineStatus of a function body for header content) - incontract = 0; -#endif -} - -Statement *Statement::syntaxCopy() -{ - assert(0); - return NULL; -} - -void Statement::print() -{ - fprintf(stdmsg, "%s\n", toChars()); - fflush(stdmsg); -} - -char *Statement::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); -} - -void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("Statement::toCBuffer()"); - buf->writenl(); -} - -Statement *Statement::semantic(Scope *sc) -{ - return this; -} - -// Same as semantic(), but do create a new scope - -Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue) -{ Scope *scd; - Statement *s; - - scd = sc->push(); - if (sbreak) - scd->sbreak = sbreak; - if (scontinue) - scd->scontinue = scontinue; - s = semantic(scd); - scd->pop(); - return s; -} - -void Statement::error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); -} - -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; -} - -// TRUE if statement may fall off the end without a throw or return - -int Statement::fallOffEnd() -{ - return TRUE; -} - -// TRUE if statement 'comes from' somewhere else, like a goto - -int Statement::comeFrom() -{ - //printf("Statement::comeFrom()\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(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; -} - - -/******************************** ExpStatement ***************************/ - -ExpStatement::ExpStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *ExpStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - ExpStatement *es = new ExpStatement(loc, e); - return es; -} - -void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (exp) - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - if (!hgs->FLinit.init) - buf->writenl(); -} - -Statement *ExpStatement::semantic(Scope *sc) -{ - if (exp) - { - //printf("ExpStatement::semantic() %s\n", exp->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp->checkSideEffect(0); - exp = exp->optimize(0); - //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0); - } - return this; -} - -int ExpStatement::fallOffEnd() -{ - if (exp) - { - if (exp->op == TOKassert) - { AssertExp *a = (AssertExp *)exp; - - if (a->e1->isBool(FALSE)) // if it's an assert(0) - return FALSE; - } - else if (exp->op == TOKhalt) - return FALSE; - } - return TRUE; -} - -/******************************** 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(); -} - -Statement *CompileStatement::semantic(Scope *sc) -{ - //printf("CompileStatement::semantic() %s\n", exp->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op != TOKstring) - { error("argument to mixin must be a string, not (%s)", exp->toChars()); - return this; - } - StringExp *se = (StringExp *)exp; - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - - Statements *statements = new Statements(); - while (p.token.value != TOKeof) - { - Statement *s = p.parseStatement(PSsemi | PScurlyscope); - statements->push(s); - } - - Statement *s = new CompoundStatement(loc, statements); - return s->semantic(sc); -} - - -/******************************** DeclarationStatement ***************************/ - -DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration) - : ExpStatement(loc, new DeclarationExp(loc, declaration)) -{ -} - -DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp) - : ExpStatement(loc, exp) -{ -} - -Statement *DeclarationStatement::syntaxCopy() -{ - DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy()); - return ds; -} - -void DeclarationStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("DeclarationStatement::scopeCode()\n"); - //print(); - - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - - if (exp) - { - if (exp->op == TOKdeclaration) - { - DeclarationExp *de = (DeclarationExp *)(exp); - VarDeclaration *v = de->declaration->isVarDeclaration(); - if (v) - { Expression *e; - - e = v->callAutoDtor(); - if (e) - { - //printf("dtor is: "); e->print(); - *sfinally = new ExpStatement(loc, e); - } - } - } - } -} - -void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - exp->toCBuffer(buf, hgs); -} - - -/******************************** CompoundStatement ***************************/ - -CompoundStatement::CompoundStatement(Loc loc, Statements *s) - : Statement(loc) -{ - statements = s; -} - -CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2) - : Statement(loc) -{ - statements = new Statements(); - statements->reserve(2); - statements->push(s1); - statements->push(s2); -} - -Statement *CompoundStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - if (s) - s = s->syntaxCopy(); - a->data[i] = s; - } - CompoundStatement *cs = new CompoundStatement(loc, a); - return cs; -} - - -Statement *CompoundStatement::semantic(Scope *sc) -{ Statement *s; - - //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc); - - for (size_t i = 0; i < statements->dim; ) - { - s = (Statement *) statements->data[i]; - if (s) - { Statements *a = s->flatten(sc); - - if (a) - { - statements->remove(i); - statements->insert(i, a); - continue; - } - s = s->semantic(sc); - statements->data[i] = s; - if (s) - { - Statement *sentry; - Statement *sexception; - Statement *sfinally; - - s->scopeCode(&sentry, &sexception, &sfinally); - if (sentry) - { - sentry = sentry->semantic(sc); - statements->data[i] = sentry; - } - if (sexception) - { - if (i + 1 == statements->dim && !sfinally) - { -#if 1 - sexception = sexception->semantic(sc); -#else - statements->push(sexception); - if (sfinally) - // Assume sexception does not throw - statements->push(sfinally); -#endif - } - else - { - /* Rewrite: - * s; s1; s2; - * As: - * s; - * try { s1; s2; } - * catch (Object __o) - * { sexception; throw __o; } - */ - Statement *body; - Statements *a = new Statements(); - - for (int j = i + 1; j < statements->dim; j++) - { - a->push(statements->data[j]); - } - body = new CompoundStatement(0, a); - body = new ScopeStatement(0, body); - - static int num; - char name[3 + sizeof(num) * 3 + 1]; - sprintf(name, "__o%d", ++num); - Identifier *id = Lexer::idPool(name); - - Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id)); - handler = new CompoundStatement(0, sexception, handler); - - Array *catches = new Array(); - Catch *ctch = new Catch(0, NULL, id, handler); - catches->push(ctch); - s = new TryCatchStatement(0, body, catches); - - if (sfinally) - s = new TryFinallyStatement(0, s, sfinally); - s = s->semantic(sc); - statements->setDim(i + 1); - statements->push(s); - break; - } - } - else if (sfinally) - { - if (0 && i + 1 == statements->dim) - { - statements->push(sfinally); - } - else - { - /* Rewrite: - * s; s1; s2; - * As: - * s; try { s1; s2; } finally { sfinally; } - */ - Statement *body; - Statements *a = new Statements(); - - for (int j = i + 1; j < statements->dim; j++) - { - a->push(statements->data[j]); - } - body = new CompoundStatement(0, a); - s = new TryFinallyStatement(0, body, sfinally); - s = s->semantic(sc); - statements->setDim(i + 1); - statements->push(s); - break; - } - } - } - } - i++; - } - if (statements->dim == 1) - return s; - return this; -} - -Statements *CompoundStatement::flatten(Scope *sc) -{ - return statements; -} - -ReturnStatement *CompoundStatement::isReturnStatement() -{ int i; - ReturnStatement *rs = NULL; - - for (i = 0; i < statements->dim; i++) - { Statement *s; - - s = (Statement *) statements->data[i]; - if (s) - { - rs = s->isReturnStatement(); - if (rs) - break; - } - } - return rs; -} - -void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - for (i = 0; i < statements->dim; i++) - { Statement *s; - - s = (Statement *) statements->data[i]; - if (s) - s->toCBuffer(buf, hgs); - } -} - -int CompoundStatement::usesEH() -{ - for (int i = 0; i < statements->dim; i++) - { Statement *s; - - s = (Statement *) statements->data[i]; - if (s && s->usesEH()) - return TRUE; - } - return FALSE; -} - -int CompoundStatement::fallOffEnd() -{ int falloff = TRUE; - - //printf("CompoundStatement::fallOffEnd()\n"); - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (!s) - continue; - - if (!falloff && global.params.warnings && !s->comeFrom()) - { - fprintf(stdmsg, "warning - "); - s->error("statement is not reachable"); - } - falloff = s->fallOffEnd(); - } - return falloff; -} - -int CompoundStatement::comeFrom() -{ int comefrom = FALSE; - - //printf("CompoundStatement::comeFrom()\n"); - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (!s) - continue; - - comefrom |= s->comeFrom(); - } - return comefrom; -} - - -/**************************** UnrolledLoopStatement ***************************/ - -UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s) - : Statement(loc) -{ - statements = s; - enclosingtryfinally = NULL; -} - -Statement *UnrolledLoopStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - if (s) - s = s->syntaxCopy(); - a->data[i] = s; - } - UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); - return cs; -} - - -Statement *UnrolledLoopStatement::semantic(Scope *sc) -{ - //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); - - enclosingtryfinally = sc->tfOfTry; - - sc->noctor++; - Scope *scd = sc->push(); - scd->sbreak = this; - scd->scontinue = this; - - for (size_t i = 0; i < statements->dim; i++) - { - Statement *s = (Statement *) statements->data[i]; - if (s) - { - s = s->semantic(scd); - statements->data[i] = s; - } - } - - scd->pop(); - sc->noctor--; - return this; -} - -void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("unrolled {"); - buf->writenl(); - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s; - - s = (Statement *) statements->data[i]; - if (s) - s->toCBuffer(buf, hgs); - } - - buf->writeByte('}'); - buf->writenl(); -} - -int UnrolledLoopStatement::hasBreak() -{ - return TRUE; -} - -int UnrolledLoopStatement::hasContinue() -{ - return TRUE; -} - -int UnrolledLoopStatement::usesEH() -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s; - - s = (Statement *) statements->data[i]; - if (s && s->usesEH()) - return TRUE; - } - return FALSE; -} - -int UnrolledLoopStatement::fallOffEnd() -{ - //printf("UnrolledLoopStatement::fallOffEnd()\n"); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (s) - s->fallOffEnd(); - } - return TRUE; -} - - -int UnrolledLoopStatement::comeFrom() -{ int comefrom = FALSE; - - //printf("UnrolledLoopStatement::comeFrom()\n"); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (!s) - continue; - - comefrom |= s->comeFrom(); - } - return comefrom; -} - - -/******************************** ScopeStatement ***************************/ - -ScopeStatement::ScopeStatement(Loc loc, Statement *s) - : Statement(loc) -{ - this->statement = s; -} - -Statement *ScopeStatement::syntaxCopy() -{ - Statement *s; - - s = statement ? statement->syntaxCopy() : NULL; - s = new ScopeStatement(loc, s); - return s; -} - - -Statement *ScopeStatement::semantic(Scope *sc) -{ ScopeDsymbol *sym; - - //printf("ScopeStatement::semantic(sc = %p)\n", sc); - if (statement) - { Statements *a; - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - a = statement->flatten(sc); - if (a) - { - statement = new CompoundStatement(loc, a); - } - - statement = statement->semantic(sc); - if (statement) - { - Statement *sentry; - Statement *sexception; - Statement *sfinally; - - statement->scopeCode(&sentry, &sexception, &sfinally); - if (sfinally) - { - //printf("adding sfinally\n"); - statement = new CompoundStatement(loc, statement, sfinally); - } - } - - sc->pop(); - } - return this; -} - -int ScopeStatement::hasBreak() -{ - //printf("ScopeStatement::hasBreak() %s\n", toChars()); - return statement ? statement->hasBreak() : FALSE; -} - -int ScopeStatement::hasContinue() -{ - return statement ? statement->hasContinue() : FALSE; -} - -int ScopeStatement::usesEH() -{ - return statement ? statement->usesEH() : FALSE; -} - -int ScopeStatement::fallOffEnd() -{ - return statement ? statement->fallOffEnd() : TRUE; -} - -int ScopeStatement::comeFrom() -{ - //printf("ScopeStatement::comeFrom()\n"); - return statement ? statement->comeFrom() : FALSE; -} - -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; - enclosingtryfinally = NULL; -} - -Statement *WhileStatement::syntaxCopy() -{ - WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; -} - - -Statement *WhileStatement::semantic(Scope *sc) -{ -#if 0 - if (condition->op == TOKmatch) - { - /* Rewrite while (condition) body as: - * if (condition) - * do - * body - * while ((_match = _match.opNext), _match); - */ - - Expression *ew = new IdentifierExp(0, Id::_match); - ew = new DotIdExp(0, ew, Id::next); - ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew); - ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0)); - Expression *ev = new IdentifierExp(0, Id::_match); - //ev = new CastExp(0, ev, Type::tvoidptr); - ew = new CommaExp(0, ew, ev); - Statement *sw = new DoStatement(loc, body, ew); - Statement *si = new IfStatement(loc, condition, sw, NULL); - return si->semantic(sc); - } -#endif - - enclosingtryfinally = sc->tfOfTry; - - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - condition = condition->checkToBoolean(); - - sc->noctor++; - - Scope *scd = sc->push(); - scd->sbreak = this; - scd->scontinue = this; - if (body) - body = body->semantic(scd); - scd->pop(); - - sc->noctor--; - - return this; -} - -int WhileStatement::hasBreak() -{ - return TRUE; -} - -int WhileStatement::hasContinue() -{ - return TRUE; -} - -int WhileStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int WhileStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - -int WhileStatement::comeFrom() -{ - 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; - enclosingtryfinally = NULL; -} - -Statement *DoStatement::syntaxCopy() -{ - DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy()); - return s; -} - - -Statement *DoStatement::semantic(Scope *sc) -{ - enclosingtryfinally = sc->tfOfTry; - - 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::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - -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; - this->enclosingtryfinally = NULL; -} - -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) -{ - enclosingtryfinally = sc->tfOfTry; - - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - if (init) - init = init->semantic(sc); - if (!condition) - // Use a default value - condition = new IntegerExp(loc, 1, Type::tboolean); - sc->noctor++; - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - condition = condition->checkToBoolean(); - if (increment) - increment = increment->semantic(sc); - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - sc->noctor--; - - sc->pop(); - return this; -} - -void ForStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("ForStatement::scopeCode()\n"); - //print(); - if (init) - init->scopeCode(sentry, sexception, sfinally); - else - Statement::scopeCode(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::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - -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++; - hgs->FLinit.decl = 0; - init->toCBuffer(buf, hgs); - if (hgs->FLinit.decl > 0) - buf->writebyte(';'); - hgs->FLinit.decl = 0; - hgs->FLinit.init--; - } - else - buf->writebyte(';'); - if (condition) - { buf->writebyte(' '); - condition->toCBuffer(buf, hgs); - } - buf->writebyte(';'); - if (increment) - { buf->writebyte(' '); - increment->toCBuffer(buf, hgs); - } - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/******************************** ForeachStatement ***************************/ - -ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, - Expression *aggr, Statement *body) - : Statement(loc) -{ - this->op = op; - this->arguments = arguments; - this->aggr = aggr; - this->body = body; - this->enclosingtryfinally = NULL; - - this->key = NULL; - this->value = NULL; - - this->func = NULL; -} - -Statement *ForeachStatement::syntaxCopy() -{ - Arguments *args = Argument::arraySyntaxCopy(arguments); - Expression *exp = aggr->syntaxCopy(); - ForeachStatement *s = new ForeachStatement(loc, op, args, exp, - body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *ForeachStatement::semantic(Scope *sc) -{ - //printf("ForeachStatement::semantic() %p\n", this); - ScopeDsymbol *sym; - Statement *s = this; - int dim = arguments->dim; - int i; - TypeAArray *taa = NULL; - - Type *tn = NULL; - Type *tnv = NULL; - - enclosingtryfinally = sc->tfOfTry; - - func = sc->func; - if (func->fes) - func = func->fes->func; - - aggr = aggr->semantic(sc); - aggr = resolveProperties(sc, aggr); - if (!aggr->type) - { - error("invalid foreach aggregate %s", aggr->toChars()); - return this; - } - - inferApplyArgTypes(op, arguments, aggr); - - /* Check for inference errors - */ - if (dim != arguments->dim) - { - //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim); - error("cannot uniquely infer foreach argument types"); - return this; - } - - Type *tab = aggr->type->toBasetype(); - - if (tab->ty == Ttuple) // don't generate new scope for tuple loops - { - if (dim < 1 || dim > 2) - { - error("only one (value) or two (key,value) arguments for tuple foreach"); - return s; - } - - TypeTuple *tuple = (TypeTuple *)tab; - Statements *statements = new Statements(); - //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); - size_t n; - TupleExp *te = NULL; - if (aggr->op == TOKtuple) // expression tuple - { te = (TupleExp *)aggr; - n = te->exps->dim; - } - else if (aggr->op == TOKtype) // type tuple - { - n = Argument::dim(tuple->arguments); - } - else - assert(0); - for (size_t j = 0; j < n; j++) - { size_t k = (op == TOKforeach) ? j : n - 1 - j; - Expression *e; - Type *t; - if (te) - e = (Expression *)te->exps->data[k]; - else - t = Argument::getNth(tuple->arguments, k)->type; - Argument *arg = (Argument *)arguments->data[0]; - Statements *st = new Statements(); - - if (dim == 2) - { // Declare key - if (arg->storageClass & (STCout | STCref | STClazy)) - error("no storage class for key %s", arg->ident->toChars()); - TY keyty = arg->type->ty; - if ((keyty != Tint32 && keyty != Tuns32) && - (global.params.is64bit && keyty != Tint64 && keyty != Tuns64) - ) - { - error("foreach: key type must be %s, not %s", global.params.is64bit ? "int, uint, long or ulong" : "int or uint",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 = (Argument *)arguments->data[1]; // value - } - // Declare value - if (arg->storageClass & (STCout | STCref | STClazy)) - error("no storage class for value %s", arg->ident->toChars()); - Dsymbol *var; - if (te) - { - if (e->type->toBasetype()->ty == Tfunction && - e->op == TOKvar) - { VarExp *ve = (VarExp *)e; - var = new AliasDeclaration(loc, arg->ident, ve->var); - } - else - { - arg->type = e->type; - Initializer *ie = new ExpInitializer(0, e); - VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); - if (e->isConst()) - v->storage_class |= STCconst; -#if V2 - else - v->storage_class |= STCfinal; -#endif - 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 (i = 0; i < dim; i++) - { Argument *arg = (Argument *)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) - { Argument *arg; - - i = (dim == 1) ? 0 : 1; // index of value - arg = (Argument *)arguments->data[i]; - arg->type = arg->type->semantic(loc, sc); - tnv = arg->type->toBasetype(); - if (tnv->ty != tn->ty && - (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar)) - { - if (arg->storageClass & STCref) - error("foreach: value of UTF conversion cannot be ref"); - if (dim == 2) - { arg = (Argument *)arguments->data[0]; - if (arg->storageClass & STCref) - error("foreach: key cannot be ref"); - } - goto Lapply; - } - } - - for (i = 0; i < dim; i++) - { // Declare args - Argument *arg = (Argument *)arguments->data[i]; - VarDeclaration *var; - - var = new VarDeclaration(loc, arg->type, arg->ident, NULL); - var->storage_class |= STCforeach; - var->storage_class |= arg->storageClass & (STCin | STCout | STCref); -#if 1 - DeclarationExp *de = new DeclarationExp(loc, var); - de->semantic(sc); -#else - var->semantic(sc); - if (!sc->insert(var)) - error("%s already defined", var->ident->toChars()); -#endif - if (dim == 2 && i == 0) - key = var; - else - value = var; - } - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - - 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 && - ((key->type->ty != Tint32 && key->type->ty != Tuns32) && - (global.params.is64bit && key->type->ty != Tint64 && key->type->ty != Tuns64) - ) - ) - { - error("foreach: key type must be %s, not %s", global.params.is64bit ? "int, uint, long or ulong" : "int or uint", key->type->toChars()); - } - - if (key && key->storage_class & (STCout | STCref)) - error("foreach: key cannot be out or ref"); - break; - - 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: - case Tdelegate: - Lapply: - { FuncDeclaration *fdapply; - Arguments *args; - Expression *ec; - Expression *e; - FuncLiteralDeclaration *fld; - Argument *a; - Type *t; - Expression *flde; - Identifier *id; - Type *tret; - - tret = func->type->nextOf(); - - // Need a variable to hold value from any return statements in body. - if (!sc->func->vresult && tret && tret != Type::tvoid) - { VarDeclaration *v; - - v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noauto = 1; - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - sc->func->vresult = v; - } - - /* Turn body into the function literal: - * int delegate(ref T arg) { body } - */ - args = new Arguments(); - for (i = 0; i < dim; i++) - { Argument *arg = (Argument *)arguments->data[i]; - - arg->type = arg->type->semantic(loc, sc); - if (arg->storageClass & STCref) - id = arg->ident; - else - { // Make a copy of the ref argument so it isn't - // a reference. - VarDeclaration *v; - Initializer *ie; - char applyArg[10 + sizeof(i)*3 + 1]; - - sprintf(applyArg, "__applyArg%d", i); - id = Lexer::idPool(applyArg); - - ie = new ExpInitializer(0, new IdentifierExp(0, id)); - v = new VarDeclaration(0, arg->type, arg->ident, ie); - s = new DeclarationStatement(0, v); - body = new CompoundStatement(loc, s, body); - } - a = new Argument(STCref, arg->type, id, NULL); - args->push(a); - } - t = new TypeFunction(args, Type::tint32, 0, LINKd); - fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this); - fld->fbody = body; - flde = new FuncExp(loc, fld); - flde = flde->semantic(sc); - - // Resolve any forward referenced goto's - for (int i = 0; i < gotos.dim; i++) - { CompoundStatement *cs = (CompoundStatement *)gotos.data[i]; - GotoStatement *gs = (GotoStatement *)cs->statements->data[0]; - - if (!gs->label->statement) - { // 'Promote' it to this scope, and replace with a return - cases.push(gs); - s = new ReturnStatement(0, new IntegerExp(cases.dim + 1)); - cs->statements->data[0] = (void *)s; - } - } - - if (tab->ty == Taarray) - { - // Check types - Argument *arg = (Argument *)arguments->data[0]; - if (dim == 2) - { - if (arg->storageClass & STCref) - error("foreach: index cannot be ref"); - if (!arg->type->equals(taa->index)) - error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars()); - arg = (Argument *)arguments->data[1]; - } - if (!arg->type->equals(taa->nextOf())) - error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars()); - - /* Call: - * _aaApply(aggr, keysize, flde) - */ - if (dim == 2) - fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply2"); - else - fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply"); - fdapply->runTimeHack = true; - ec = new VarExp(0, fdapply); - Expressions *exps = new Expressions(); - exps->push(aggr); - size_t keysize = taa->key->size(); - keysize = (keysize + 3) & ~3; - exps->push(new IntegerExp(0, keysize, Type::tsize_t)); - exps->push(flde); - e = new CallExp(loc, ec, exps); - e->type = Type::tindex; // don't run semantic() on e - } - else if (tab->ty == Tarray || tab->ty == Tsarray) - { - /* Call: - * _aApply(aggr, flde) - */ - static char fntab[9][3] = - { "cc","cw","cd", - "wc","cc","wd", - "dc","dw","dd" - }; - char fdname[7+1+2+ sizeof(dim)*3 + 1]; - int flag; - - switch (tn->ty) - { - case Tchar: flag = 0; break; - case Twchar: flag = 3; break; - case Tdchar: flag = 6; break; - default: assert(0); - } - switch (tnv->ty) - { - case Tchar: flag += 0; break; - case Twchar: flag += 1; break; - case Tdchar: flag += 2; break; - default: assert(0); - } - const char *r = (op == TOKforeach_reverse) ? "R" : ""; - int j = sprintf(fdname, "_aApply%s%.*s%d", r, 2, fntab[flag], dim); - assert(j < sizeof(fdname)); - fdapply = FuncDeclaration::genCfunc(Type::tindex, fdname); - fdapply->runTimeHack = true; - - ec = new VarExp(0, fdapply); - Expressions *exps = new Expressions(); - if (tab->ty == Tsarray) - aggr = aggr->castTo(sc, tn->arrayOf()); - exps->push(aggr); - exps->push(flde); - e = new CallExp(loc, ec, exps); - e->type = Type::tindex; // don't run semantic() on e - } - else if (tab->ty == Tdelegate) - { - /* Call: - * aggr(flde) - */ - Expressions *exps = new Expressions(); - exps->push(flde); - e = new CallExp(loc, aggr, exps); - e = e->semantic(sc); - if (e->type != Type::tint32) - error("opApply() function for %s must return an int", tab->toChars()); - } - else - { - /* 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 (int i = 0; i < cases.dim; i++) - { - s = (Statement *)cases.data[i]; - s = new CaseStatement(0, new IntegerExp(i + 2), s); - a->push(s); - } - - s = new CompoundStatement(loc, a); - s = new SwitchStatement(loc, e, s); - s = s->semantic(sc); - } - break; - } - - default: - error("foreach: %s is not an aggregate type", aggr->type->toChars()); - 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::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - -int ForeachStatement::comeFrom() -{ - if (body) - return body->comeFrom(); - return FALSE; -} - -void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - buf->writestring(" ("); - int i; - for (int i = 0; i < arguments->dim; i++) - { - Argument *a = (Argument *)arguments->data[i]; - if (i) - buf->writestring(", "); - if (a->storageClass & STCref) - buf->writestring((global.params.Dversion == 1) - ? (char*)"inout " : (char*)"ref "); - if (a->type) - a->type->toCBuffer(buf, a->ident, hgs); - else - buf->writestring(a->ident->toChars()); - } - buf->writestring("; "); - aggr->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/******************************** IfStatement ***************************/ - -IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody) - : Statement(loc) -{ - this->arg = arg; - this->condition = condition; - this->ifbody = ifbody; - this->elsebody = elsebody; - this->match = NULL; -} - -Statement *IfStatement::syntaxCopy() -{ - Statement *i = NULL; - if (ifbody) - i = ifbody->syntaxCopy(); - - Statement *e = NULL; - if (elsebody) - e = elsebody->syntaxCopy(); - - Argument *a = arg ? arg->syntaxCopy() : NULL; - IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e); - return s; -} - -Statement *IfStatement::semantic(Scope *sc) -{ - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->checkToBoolean(); - - // If we can short-circuit evaluate the if statement, don't do the - // semantic analysis of the skipped code. - // This feature allows a limited form of conditional compilation. - condition = condition->optimize(WANTflags); - - // Evaluate at runtime - unsigned cs0 = sc->callSuper; - unsigned cs1; - - Scope *scd; - if (arg) - { /* Declare arg, which we will set to be the - * result of condition. - */ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - scd = sc->push(sym); - - Type *t = arg->type ? arg->type : condition->type; - match = new VarDeclaration(loc, t, arg->ident, NULL); - match->noauto = 1; - match->semantic(scd); - if (!scd->insert(match)) - assert(0); - match->parent = sc->func; - - /* Generate: - * (arg = condition) - */ - VarExp *v = new VarExp(0, match); - condition = new AssignExp(loc, v, condition); - condition = condition->semantic(scd); - } - else - scd = sc->push(); - ifbody = ifbody->semantic(scd); - scd->pop(); - - cs1 = sc->callSuper; - sc->callSuper = cs0; - if (elsebody) - elsebody = elsebody->semanticScope(sc, NULL, NULL); - sc->mergeCallSuper(loc, cs1); - - return this; -} - -int IfStatement::usesEH() -{ - return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); -} - -int IfStatement::fallOffEnd() -{ - if (!ifbody || ifbody->fallOffEnd() || - !elsebody || elsebody->fallOffEnd()) - return TRUE; - return FALSE; -} - - -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(arg->ident->toChars()); - buf->writebyte(';'); - } - 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()); -} - -void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - condition->toCBuffer(buf, hgs); - buf->writenl(); - if (ifbody) - ifbody->toCBuffer(buf, hgs); - if (elsebody) - { - buf->writestring("else"); - buf->writenl(); - elsebody->toCBuffer(buf, hgs); - } - buf->writenl(); -} - - -/******************************** PragmaStatement ***************************/ - -PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body) - : Statement(loc) -{ - this->ident = ident; - this->args = args; - this->body = body; -} - -Statement *PragmaStatement::syntaxCopy() -{ - Statement *b = NULL; - if (body) - b = body->syntaxCopy(); - PragmaStatement *s = new PragmaStatement(loc, - ident, Expression::arraySyntaxCopy(args), b); - return s; -} - -Statement *PragmaStatement::semantic(Scope *sc) -{ // Should be merged with PragmaDeclaration - //printf("PragmaStatement::semantic() %s\n", toChars()); - //printf("body = %p\n", body); - if (ident == Id::msg) - { - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (Expression *)args->data[i]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKstring) - { - StringExp *se = (StringExp *)e; - fprintf(stdmsg, "%.*s", (int)se->len, se->string); - } - else - error("string expected for message, not '%s'", e->toChars()); - } - fprintf(stdmsg, "\n"); - } - } - else if (ident == Id::lib) - { - if (!args || args->dim != 1) - error("string expected for library name"); - else - { - Expression *e = (Expression *)args->data[0]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - if (e->op != TOKstring) - error("string expected for library name, not '%s'", e->toChars()); - else if (global.params.verbose) - { - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - printf("library %s\n", name); - mem.free(name); - } - } - } - else - error("unrecognized pragma(%s)", ident->toChars()); - - if (body) - { - body = body->semantic(sc); - } - return body; -} - -int PragmaStatement::usesEH() -{ - return body && body->usesEH(); -} - -int PragmaStatement::fallOffEnd() -{ - if (body) - return body->fallOffEnd(); - return TRUE; -} - -void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("pragma ("); - buf->writestring(ident->toChars()); - if (args && args->dim) - { - buf->writestring(", "); - argsToCBuffer(buf, args, hgs); - } - buf->writeByte(')'); - if (body) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - - body->toCBuffer(buf, hgs); - - buf->writeByte('}'); - buf->writenl(); - } - else - { - buf->writeByte(';'); - buf->writenl(); - } -} - - -/******************************** StaticAssertStatement ***************************/ - -StaticAssertStatement::StaticAssertStatement(StaticAssert *sa) - : Statement(sa->loc) -{ - this->sa = sa; -} - -Statement *StaticAssertStatement::syntaxCopy() -{ - StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL)); - return s; -} - -Statement *StaticAssertStatement::semantic(Scope *sc) -{ - sa->semantic2(sc); - return NULL; -} - -void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - sa->toCBuffer(buf, hgs); -} - - -/******************************** SwitchStatement ***************************/ - -SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b) - : Statement(loc) -{ - condition = c; - body = b; - sdefault = NULL; - cases = NULL; - hasNoDefault = 0; - // LLVMDC - enclosingtryfinally = 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 - - enclosingtryfinally = sc->tfOfTry; - - 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 Array(); - sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead - body = body->semantic(sc); - sc->noctor--; - - // Resolve any goto case's with exp - for (int i = 0; i < gotoCases.dim; i++) - { - GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i]; - - if (!gcs->exp) - { - gcs->error("no case statement following goto case;"); - break; - } - - for (Scope *scx = sc; scx; scx = scx->enclosing) - { - if (!scx->sw) - continue; - for (int j = 0; j < scx->sw->cases->dim; j++) - { - CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j]; - - if (cs->exp->equals(gcs->exp)) - { - gcs->cs = cs; - goto Lfoundcase; - } - } - } - gcs->error("case %s not found", gcs->exp->toChars()); - - Lfoundcase: - ; - } - - if (!sc->sw->sdefault) - { hasNoDefault = 1; - - if (global.params.warnings) - { fprintf(stdmsg, "warning - "); - error("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); - a->push(new BreakStatement(loc, NULL)); - sc->sw->sdefault = new DefaultStatement(loc, s); - a->push(sc->sw->sdefault); - cs = new CompoundStatement(loc, a); - body = cs; - } - - sc->pop(); - return this; -} - -int SwitchStatement::hasBreak() -{ - return TRUE; -} - -int SwitchStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int SwitchStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; // need to do this better -} - -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; -} - -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) - { int i; - - exp = exp->implicitCastTo(sc, sw->condition->type); - exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op != TOKstring && exp->op != TOKint64) - { - error("case must be a string or an integral constant, not %s", exp->toChars()); - exp = new IntegerExp(0); - } - - for (i = 0; i < sw->cases->dim; i++) - { - CaseStatement *cs = (CaseStatement *)sw->cases->data[i]; - - //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars()); - if (cs->exp->equals(exp)) - { error("duplicate case %s in switch statement", exp->toChars()); - break; - } - } - - sw->cases->push(this); - - // Resolve any goto case's with no exp to this case statement - for (i = 0; i < sw->gotoCases.dim; i++) - { - GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i]; - - if (!gcs->exp) - { - gcs->cs = this; - sw->gotoCases.remove(i); // remove from array - } - } - } - 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::fallOffEnd() -{ - return statement->fallOffEnd(); -} - -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); -} - -/******************************** DefaultStatement ***************************/ - -DefaultStatement::DefaultStatement(Loc loc, Statement *s) - : Statement(loc) -{ - this->statement = s; -#if IN_GCC -+ cblock = NULL; -#endif - bodyBB = NULL; -} - -Statement *DefaultStatement::syntaxCopy() -{ - DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy()); - return s; -} - -Statement *DefaultStatement::semantic(Scope *sc) -{ - if (sc->sw) - { - if (sc->sw->sdefault) - { - error("switch statement already has a default"); - } - sc->sw->sdefault = this; - } - else - error("default not in switch statement"); - statement = statement->semantic(sc); - return this; -} - -int DefaultStatement::usesEH() -{ - return statement->usesEH(); -} - -int DefaultStatement::fallOffEnd() -{ - return statement->fallOffEnd(); -} - -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; - enclosingtryfinally = NULL; -} - -Statement *GotoDefaultStatement::syntaxCopy() -{ - GotoDefaultStatement *s = new GotoDefaultStatement(loc); - return s; -} - -Statement *GotoDefaultStatement::semantic(Scope *sc) -{ - enclosingtryfinally = sc->tfOfTry; - sw = sc->sw; - if (!sw) - error("goto default not in switch statement"); - return this; -} - -int GotoDefaultStatement::fallOffEnd() -{ - return FALSE; -} - -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; - enclosingtryfinally = NULL; - sw = NULL; -} - -Statement *GotoCaseStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - GotoCaseStatement *s = new GotoCaseStatement(loc, e); - return s; -} - -Statement *GotoCaseStatement::semantic(Scope *sc) -{ - enclosingtryfinally = sc->tfOfTry; - 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::fallOffEnd() -{ - return FALSE; -} - -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::fallOffEnd() -{ - return FALSE; -} - -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->enclosingtryfinally = NULL; -} - -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()); - this->enclosingtryfinally = sc->tfOfTry; - - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - Scope *scx = sc; - int implicit0 = 0; - - if (sc->fes) - { - // Find scope of function foreach is in - for (; 1; scx = scx->enclosing) - { - assert(scx); - if (scx->func != fd) - { fd = scx->func; // fd is now function enclosing foreach - break; - } - } - } - - Type *tret = fd->type->nextOf(); - if (fd->tintro) - 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->tf || scx->tf) - 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) - fd->nrvo_var = v; - else - fd->nrvo_can = 0; - } - else if (fd->nrvo_var != v) - fd->nrvo_can = 0; - } - else - fd->nrvo_can = 0; - - if (fd->returnLabel && tbret->ty != Tvoid) - { - } - else if (fd->inferRetType) - { - if (fd->type->nextOf()) - { - if (!exp->type->equals(fd->type->nextOf())) - error("mismatched function return type inference of %s and %s", - exp->type->toChars(), fd->type->nextOf()->toChars()); - } - else - { - fd->type->next = exp->type; - fd->type = fd->type->semantic(loc, sc); - if (!fd->tintro) - { tret = fd->type->nextOf(); - tbret = tret->toBasetype(); - } - } - } - else if (tbret->ty != Tvoid) - { - exp = exp->implicitCastTo(sc, tret); - } - } - 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); - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - } - else if (fd->type->nextOf()->toBasetype() == Type::tvoid) - { - Statement *s1; - Statement *s2; - - s = new ReturnStatement(0, NULL); - sc->fes->cases.push(s); - - // Construct: { exp; return cases.dim + 1; } - s1 = new ExpStatement(loc, exp); - s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - else - { - VarExp *v; - Statement *s1; - Statement *s2; - - // Construct: return vresult; - if (!fd->vresult) - { VarDeclaration *v; - - v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noauto = 1; - v->semantic(scx); - if (!scx->insert(v)) - assert(0); - v->parent = fd; - fd->vresult = v; - } - - v = new VarExp(0, fd->vresult); - s = new ReturnStatement(0, v); - sc->fes->cases.push(s); - - // Construct: { vresult = exp; return cases.dim + 1; } - v = new VarExp(0, fd->vresult); - exp = new AssignExp(loc, v, exp); - exp = exp->semantic(sc); - s1 = new ExpStatement(loc, exp); - s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - return s; - } - - if (exp) - { - if (fd->returnLabel && tbret->ty != Tvoid) - { - assert(fd->vresult); - VarExp *v = new VarExp(0, fd->vresult); - - exp = new AssignExp(loc, v, exp); - exp = 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) - { Statement *s; - - s = new ExpStatement(0, exp); - return new CompoundStatement(loc, s, gs); - } - return gs; - } - - if (exp && tbret->ty == Tvoid && !fd->isMain()) - { Statement *s; - - s = new ExpStatement(loc, exp); - loc = 0; - exp = NULL; - return new CompoundStatement(loc, s, this); - } - - return this; -} - -int ReturnStatement::fallOffEnd() -{ - return FALSE; -} - -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; - this->enclosingtryfinally = NULL; -} - -Statement *BreakStatement::syntaxCopy() -{ - BreakStatement *s = new BreakStatement(loc, ident); - return s; -} - -Statement *BreakStatement::semantic(Scope *sc) -{ - enclosingtryfinally = sc->tfOfTry; - // 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->tf != sc->tf) - 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::fallOffEnd() -{ - return FALSE; -} - -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; - this->enclosingtryfinally = NULL; -} - -Statement *ContinueStatement::syntaxCopy() -{ - ContinueStatement *s = new ContinueStatement(loc, ident); - return s; -} - -Statement *ContinueStatement::semantic(Scope *sc) -{ - enclosingtryfinally = sc->tfOfTry; - //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->tf != sc->tf) - 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::fallOffEnd() -{ - return FALSE; -} - -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; -} - -SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body) - : Statement(loc) -{ - this->exp = NULL; - this->body = body; - this->esync = esync; -} - -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) - { ClassDeclaration *cd; - - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - cd = exp->type->isClassHandle(); - if (!cd) - error("can only synchronize on class objects, not '%s'", exp->type->toChars()); - else if (cd->isInterfaceDeclaration()) - { Type *t = new TypeIdentifier(0, Id::Object); - - t = t->semantic(0, sc); - exp = new CastExp(loc, exp, t); - exp = exp->semantic(sc); - } - } - 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::fallOffEnd() -{ - return body ? body->fallOffEnd() : TRUE; -} - -void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("synchronized"); - if (exp) - { buf->writebyte('('); - exp->toCBuffer(buf, hgs); - buf->writebyte(')'); - } - if (body) - { - buf->writebyte(' '); - body->toCBuffer(buf, hgs); - } -} - -/******************************** WithStatement ***************************/ - -WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body) - : Statement(loc) -{ - this->exp = exp; - this->body = body; - wthis = NULL; -} - -Statement *WithStatement::syntaxCopy() -{ - WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *WithStatement::semantic(Scope *sc) -{ ScopeDsymbol *sym; - Initializer *init; - - //printf("WithStatement::semantic()\n"); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (exp->op == TOKimport) - { ScopeExp *es = (ScopeExp *)exp; - - sym = es->sds; - } - else if (exp->op == TOKtype) - { TypeExp *es = (TypeExp *)exp; - - sym = es->type->toDsymbol(sc)->isScopeDsymbol(); - if (!sym) - { error("%s has no members", es->toChars()); - body = body->semantic(sc); - return this; - } - } - else - { Type *t = exp->type; - - assert(t); - t = t->toBasetype(); - if (t->isClassHandle()) - { - init = new ExpInitializer(loc, exp); - wthis = new VarDeclaration(loc, exp->type, Id::withSym, init); - wthis->semantic(sc); - - sym = new WithScopeSymbol(this); - sym->parent = sc->scopesym; - } - else if (t->ty == Tstruct) - { - Expression *e = exp->addressOf(sc); - init = new ExpInitializer(loc, e); - wthis = new VarDeclaration(loc, e->type, Id::withSym, init); - wthis->semantic(sc); - sym = new WithScopeSymbol(this); - sym->parent = sc->scopesym; - } - else - { error("with expressions must be class objects, not '%s'", exp->type->toChars()); - return NULL; - } - } - sc = sc->push(sym); - - if (body) - body = body->semantic(sc); - - sc->pop(); - - return this; -} - -void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("with ("); - exp->toCBuffer(buf, hgs); - buf->writestring(")\n"); - if (body) - body->toCBuffer(buf, hgs); -} - -int WithStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int WithStatement::fallOffEnd() -{ - return body ? body->fallOffEnd() : TRUE; -} - -/******************************** TryCatchStatement ***************************/ - -TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches) - : Statement(loc) -{ - this->body = body; - this->catches = catches; -} - -Statement *TryCatchStatement::syntaxCopy() -{ - Array *a = new Array(); - a->setDim(catches->dim); - for (int i = 0; i < a->dim; i++) - { Catch *c; - - c = (Catch *)catches->data[i]; - c = c->syntaxCopy(); - a->data[i] = c; - } - TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); - return s; -} - -Statement *TryCatchStatement::semantic(Scope *sc) -{ - body = body->semanticScope(sc, NULL /*this*/, NULL); - - for (int i = 0; i < catches->dim; i++) - { Catch *c; - - c = (Catch *)catches->data[i]; - c->semantic(sc); - - // Determine if current catch 'hides' any previous catches - for (int j = 0; j < i; j++) - { Catch *cj = (Catch *)catches->data[j]; - char *si = c->loc.toChars(); - char *sj = cj->loc.toChars(); - - if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype())) - error("catch at %s hides catch at %s", sj, si); - } - } - return this; -} - -int TryCatchStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int TryCatchStatement::usesEH() -{ - return TRUE; -} - -int TryCatchStatement::fallOffEnd() -{ - int result = FALSE; - - if (body) - result = body->fallOffEnd(); - for (int i = 0; i < catches->dim; i++) - { Catch *c; - - c = (Catch *)catches->data[i]; - if (c->handler) - result |= c->handler->fallOffEnd(); - } - return result; -} - -void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("try"); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - int i; - for (i = 0; i < catches->dim; i++) - { - Catch *c = (Catch *)catches->data[i]; - c->toCBuffer(buf, hgs); - } -} - -/******************************** Catch ***************************/ - -Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler) -{ - //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars()); - this->loc = loc; - this->type = t; - this->ident = id; - this->handler = handler; - var = NULL; -} - -Catch *Catch::syntaxCopy() -{ - Catch *c = new Catch(loc, - (type ? type->syntaxCopy() : NULL), - ident, - (handler ? handler->syntaxCopy() : NULL)); - return c; -} - -void Catch::semantic(Scope *sc) -{ ScopeDsymbol *sym; - - //printf("Catch::semantic(%s)\n", ident->toChars()); - -#ifndef IN_GCC - if (sc->tf) - { - /* This is because the _d_local_unwind() gets the stack munged - * up on this. The workaround is to place any try-catches into - * a separate function, and call that. - * To fix, have the compiler automatically convert the finally - * body into a nested function. - */ - error(loc, "cannot put catch statement inside finally block"); - } -#endif - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - if (!type) - type = new TypeIdentifier(0, Id::Object); - type = type->semantic(loc, sc); - if (!type->toBasetype()->isClassHandle()) - error("can only catch class objects, not '%s'", type->toChars()); - else if (ident) - { - var = new VarDeclaration(loc, type, ident, NULL); - var->parent = sc->parent; - sc->insert(var); - } - handler = handler->semantic(sc); - - sc->pop(); -} - -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(); - 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; - this->enclosingtryfinally = NULL; -} - -Statement *TryFinallyStatement::syntaxCopy() -{ - TryFinallyStatement *s = new TryFinallyStatement(loc, - body->syntaxCopy(), finalbody->syntaxCopy()); - return s; -} - -Statement *TryFinallyStatement::semantic(Scope *sc) -{ - //printf("TryFinallyStatement::semantic()\n"); - - enclosingtryfinally = sc->tfOfTry; - sc->tfOfTry = this; - body = body->semantic(sc); - sc->tfOfTry = enclosingtryfinally; - - sc = sc->push(); - sc->tf = this; - sc->sbreak = NULL; - sc->scontinue = NULL; // no break or continue out of finally block - finalbody = finalbody->semantic(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::fallOffEnd() -{ int result; - - result = body->fallOffEnd(); -// if (finalbody) -// result = finalbody->fallOffEnd(); - return result; -} - -/****************************** 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; -} - -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(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; - */ - static int num; - char name[5 + sizeof(num) * 3 + 1]; - sprintf(name, "__osf%d", ++num); - Identifier *id = Lexer::idPool(name); - - ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0)); - VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie); - *sentry = new DeclarationStatement(loc, v); - - Expression *e = new IntegerExp(1); - e = new AssignExp(0, new VarExp(0, v), e); - *sexception = new ExpStatement(0, e); - - e = new VarExp(0, v); - e = new NotExp(0, e); - *sfinally = new IfStatement(0, NULL, e, statement, NULL); - - break; - } - - default: - assert(0); - } -} - -/******************************** ThrowStatement ***************************/ - -ThrowStatement::ThrowStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *ThrowStatement::syntaxCopy() -{ - ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy()); - return s; -} - -Statement *ThrowStatement::semantic(Scope *sc) -{ - //printf("ThrowStatement::semantic()\n"); - - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - fd->hasReturnExp |= 2; - - if (sc->incontract) - error("Throw statements cannot be in contracts"); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (!exp->type->toBasetype()->isClassHandle()) - error("can only throw class objects, not type %s", exp->type->toChars()); - return this; -} - -int ThrowStatement::fallOffEnd() -{ - return FALSE; -} - -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) -{ - statement = statement ? statement->semantic(sc) : NULL; - return this; -} - -Statements *VolatileStatement::flatten(Scope *sc) -{ - Statements *a; - - a = statement ? statement->flatten(sc) : NULL; - if (a) - { for (int i = 0; i < a->dim; i++) - { Statement *s = (Statement *)a->data[i]; - - s = new VolatileStatement(loc, s); - a->data[i] = s; - } - } - - return a; -} - -int VolatileStatement::fallOffEnd() -{ - return statement ? statement->fallOffEnd() : TRUE; -} - -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->tf = NULL; - this->enclosingtryfinally = 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"); - tf = sc->tf; - enclosingtryfinally = sc->tfOfTry; - label = fd->searchLabel(ident); - if (!label->statement && sc->fes) - { - /* Either the goto label is forward referenced or it - * is in the function that the enclosing foreach is in. - * Can't know yet, so wrap the goto in a compound statement - * so we can patch it later, and add it to a 'look at this later' - * list. - */ - Statements *a = new Statements(); - Statement *s; - - a->push(this); - s = new CompoundStatement(loc, a); - sc->fes->gotos.push(s); // 'look at this later' list - return s; - } - if (label->statement && label->statement->tf != sc->tf) - error("cannot goto in or out of finally block"); - return this; -} - -int GotoStatement::fallOffEnd() -{ - return FALSE; -} - -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->tf = NULL; - this->enclosingtryfinally = NULL; - this->lblock = NULL; - this->isReturnLabel = 0; - this->llvmBB = 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; - tf = sc->tf; - enclosingtryfinally = sc->tfOfTry; - sc = sc->push(); - sc->scopesym = sc->enclosing->scopesym; - sc->callSuper |= CSXlabel; - sc->slabel = this; - if (statement) - statement = statement->semantic(sc); - sc->pop(); - return this; -} - -Statements *LabelStatement::flatten(Scope *sc) -{ - Statements *a = NULL; - - if (statement) - { - a = statement->flatten(sc); - if (a) - { - if (!a->dim) - { - a->push(new ExpStatement(loc, NULL)); - } - Statement *s = (Statement *)a->data[0]; - - s = new LabelStatement(loc, ident, s); - a->data[0] = s; - } - } - - return a; -} - - -int LabelStatement::usesEH() -{ - return statement ? statement->usesEH() : FALSE; -} - -int LabelStatement::fallOffEnd() -{ - return statement ? statement->fallOffEnd() : TRUE; -} - -int LabelStatement::comeFrom() -{ - //printf("LabelStatement::comeFrom()\n"); - return TRUE; -} - -void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - buf->writebyte(':'); - buf->writenl(); - if (statement) - statement->toCBuffer(buf, hgs); -} - - -/******************************** LabelDsymbol ***************************/ - -LabelDsymbol::LabelDsymbol(Identifier *ident) - : Dsymbol(ident) -{ - statement = NULL; -#if IN_GCC - asmLabelNum = 0; -#endif -} - -LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()? -{ - return this; -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include + +#include "mem.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" + +/******************************** Statement ***************************/ + +Statement::Statement(Loc loc) + : loc(loc) +{ +#ifdef _DH + // If this is an in{} contract scope statement (skip for determining + // inlineStatus of a function body for header content) + incontract = 0; +#endif +} + +Statement *Statement::syntaxCopy() +{ + assert(0); + return NULL; +} + +void Statement::print() +{ + fprintf(stdmsg, "%s\n", toChars()); + fflush(stdmsg); +} + +char *Statement::toChars() +{ OutBuffer *buf; + HdrGenState hgs; + + buf = new OutBuffer(); + toCBuffer(buf, &hgs); + return buf->toChars(); +} + +void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("Statement::toCBuffer()"); + buf->writenl(); +} + +Statement *Statement::semantic(Scope *sc) +{ + return this; +} + +// Same as semantic(), but do create a new scope + +Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue) +{ Scope *scd; + Statement *s; + + scd = sc->push(); + if (sbreak) + scd->sbreak = sbreak; + if (scontinue) + scd->scontinue = scontinue; + s = semantic(scd); + scd->pop(); + return s; +} + +void Statement::error(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + ::verror(loc, format, ap); + va_end( ap ); +} + +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; +} + +// TRUE if statement may fall off the end without a throw or return + +int Statement::fallOffEnd() +{ + return TRUE; +} + +// TRUE if statement 'comes from' somewhere else, like a goto + +int Statement::comeFrom() +{ + //printf("Statement::comeFrom()\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(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; +} + + +/******************************** ExpStatement ***************************/ + +ExpStatement::ExpStatement(Loc loc, Expression *exp) + : Statement(loc) +{ + this->exp = exp; +} + +Statement *ExpStatement::syntaxCopy() +{ + Expression *e = exp ? exp->syntaxCopy() : NULL; + ExpStatement *es = new ExpStatement(loc, e); + return es; +} + +void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (exp) + exp->toCBuffer(buf, hgs); + buf->writeByte(';'); + if (!hgs->FLinit.init) + buf->writenl(); +} + +Statement *ExpStatement::semantic(Scope *sc) +{ + if (exp) + { + //printf("ExpStatement::semantic() %s\n", exp->toChars()); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp->checkSideEffect(0); + exp = exp->optimize(0); + //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0); + } + return this; +} + +int ExpStatement::fallOffEnd() +{ + if (exp) + { + if (exp->op == TOKassert) + { AssertExp *a = (AssertExp *)exp; + + if (a->e1->isBool(FALSE)) // if it's an assert(0) + return FALSE; + } + else if (exp->op == TOKhalt) + return FALSE; + } + return TRUE; +} + +/******************************** 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(); +} + +Statement *CompileStatement::semantic(Scope *sc) +{ + //printf("CompileStatement::semantic() %s\n", exp->toChars()); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp = exp->optimize(WANTvalue | WANTinterpret); + if (exp->op != TOKstring) + { error("argument to mixin must be a string, not (%s)", exp->toChars()); + return this; + } + StringExp *se = (StringExp *)exp; + se = se->toUTF8(sc); + Parser p(sc->module, (unsigned char *)se->string, se->len, 0); + p.loc = loc; + p.nextToken(); + + Statements *statements = new Statements(); + while (p.token.value != TOKeof) + { + Statement *s = p.parseStatement(PSsemi | PScurlyscope); + statements->push(s); + } + + Statement *s = new CompoundStatement(loc, statements); + return s->semantic(sc); +} + + +/******************************** DeclarationStatement ***************************/ + +DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration) + : ExpStatement(loc, new DeclarationExp(loc, declaration)) +{ +} + +DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp) + : ExpStatement(loc, exp) +{ +} + +Statement *DeclarationStatement::syntaxCopy() +{ + DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy()); + return ds; +} + +void DeclarationStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) +{ + //printf("DeclarationStatement::scopeCode()\n"); + //print(); + + *sentry = NULL; + *sexception = NULL; + *sfinally = NULL; + + if (exp) + { + if (exp->op == TOKdeclaration) + { + DeclarationExp *de = (DeclarationExp *)(exp); + VarDeclaration *v = de->declaration->isVarDeclaration(); + if (v) + { Expression *e; + + e = v->callAutoDtor(); + if (e) + { + //printf("dtor is: "); e->print(); + *sfinally = new ExpStatement(loc, e); + } + } + } + } +} + +void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + exp->toCBuffer(buf, hgs); +} + + +/******************************** CompoundStatement ***************************/ + +CompoundStatement::CompoundStatement(Loc loc, Statements *s) + : Statement(loc) +{ + statements = s; +} + +CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2) + : Statement(loc) +{ + statements = new Statements(); + statements->reserve(2); + statements->push(s1); + statements->push(s2); +} + +Statement *CompoundStatement::syntaxCopy() +{ + Statements *a = new Statements(); + a->setDim(statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + if (s) + s = s->syntaxCopy(); + a->data[i] = s; + } + CompoundStatement *cs = new CompoundStatement(loc, a); + return cs; +} + + +Statement *CompoundStatement::semantic(Scope *sc) +{ Statement *s; + + //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc); + + for (size_t i = 0; i < statements->dim; ) + { + s = (Statement *) statements->data[i]; + if (s) + { Statements *a = s->flatten(sc); + + if (a) + { + statements->remove(i); + statements->insert(i, a); + continue; + } + s = s->semantic(sc); + statements->data[i] = s; + if (s) + { + Statement *sentry; + Statement *sexception; + Statement *sfinally; + + s->scopeCode(&sentry, &sexception, &sfinally); + if (sentry) + { + sentry = sentry->semantic(sc); + statements->data[i] = sentry; + } + if (sexception) + { + if (i + 1 == statements->dim && !sfinally) + { +#if 1 + sexception = sexception->semantic(sc); +#else + statements->push(sexception); + if (sfinally) + // Assume sexception does not throw + statements->push(sfinally); +#endif + } + else + { + /* Rewrite: + * s; s1; s2; + * As: + * s; + * try { s1; s2; } + * catch (Object __o) + * { sexception; throw __o; } + */ + Statement *body; + Statements *a = new Statements(); + + for (int j = i + 1; j < statements->dim; j++) + { + a->push(statements->data[j]); + } + body = new CompoundStatement(0, a); + body = new ScopeStatement(0, body); + + static int num; + char name[3 + sizeof(num) * 3 + 1]; + sprintf(name, "__o%d", ++num); + Identifier *id = Lexer::idPool(name); + + Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id)); + handler = new CompoundStatement(0, sexception, handler); + + Array *catches = new Array(); + Catch *ctch = new Catch(0, NULL, id, handler); + catches->push(ctch); + s = new TryCatchStatement(0, body, catches); + + if (sfinally) + s = new TryFinallyStatement(0, s, sfinally); + s = s->semantic(sc); + statements->setDim(i + 1); + statements->push(s); + break; + } + } + else if (sfinally) + { + if (0 && i + 1 == statements->dim) + { + statements->push(sfinally); + } + else + { + /* Rewrite: + * s; s1; s2; + * As: + * s; try { s1; s2; } finally { sfinally; } + */ + Statement *body; + Statements *a = new Statements(); + + for (int j = i + 1; j < statements->dim; j++) + { + a->push(statements->data[j]); + } + body = new CompoundStatement(0, a); + s = new TryFinallyStatement(0, body, sfinally); + s = s->semantic(sc); + statements->setDim(i + 1); + statements->push(s); + break; + } + } + } + } + i++; + } + if (statements->dim == 1) + return s; + return this; +} + +Statements *CompoundStatement::flatten(Scope *sc) +{ + return statements; +} + +ReturnStatement *CompoundStatement::isReturnStatement() +{ int i; + ReturnStatement *rs = NULL; + + for (i = 0; i < statements->dim; i++) + { Statement *s; + + s = (Statement *) statements->data[i]; + if (s) + { + rs = s->isReturnStatement(); + if (rs) + break; + } + } + return rs; +} + +void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + for (i = 0; i < statements->dim; i++) + { Statement *s; + + s = (Statement *) statements->data[i]; + if (s) + s->toCBuffer(buf, hgs); + } +} + +int CompoundStatement::usesEH() +{ + for (int i = 0; i < statements->dim; i++) + { Statement *s; + + s = (Statement *) statements->data[i]; + if (s && s->usesEH()) + return TRUE; + } + return FALSE; +} + +int CompoundStatement::fallOffEnd() +{ int falloff = TRUE; + + //printf("CompoundStatement::fallOffEnd() %s\n", toChars()); + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (!s) + continue; + + if (!falloff && global.params.warnings && !s->comeFrom()) + { + fprintf(stdmsg, "warning - "); + s->error("statement is not reachable"); + } + falloff = s->fallOffEnd(); + } + return falloff; +} + +int CompoundStatement::comeFrom() +{ int comefrom = FALSE; + + //printf("CompoundStatement::comeFrom()\n"); + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (!s) + continue; + + comefrom |= s->comeFrom(); + } + return comefrom; +} + + +/**************************** UnrolledLoopStatement ***************************/ + +UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s) + : Statement(loc) +{ + statements = s; + enclosingtryfinally = NULL; +} + +Statement *UnrolledLoopStatement::syntaxCopy() +{ + Statements *a = new Statements(); + a->setDim(statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + if (s) + s = s->syntaxCopy(); + a->data[i] = s; + } + UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); + return cs; +} + + +Statement *UnrolledLoopStatement::semantic(Scope *sc) +{ + //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); + + enclosingtryfinally = sc->tfOfTry; + + sc->noctor++; + Scope *scd = sc->push(); + scd->sbreak = this; + scd->scontinue = this; + + for (size_t i = 0; i < statements->dim; i++) + { + Statement *s = (Statement *) statements->data[i]; + if (s) + { + s = s->semantic(scd); + statements->data[i] = s; + } + } + + scd->pop(); + sc->noctor--; + return this; +} + +void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("unrolled {"); + buf->writenl(); + + for (size_t i = 0; i < statements->dim; i++) + { Statement *s; + + s = (Statement *) statements->data[i]; + if (s) + s->toCBuffer(buf, hgs); + } + + buf->writeByte('}'); + buf->writenl(); +} + +int UnrolledLoopStatement::hasBreak() +{ + return TRUE; +} + +int UnrolledLoopStatement::hasContinue() +{ + return TRUE; +} + +int UnrolledLoopStatement::usesEH() +{ + for (size_t i = 0; i < statements->dim; i++) + { Statement *s; + + s = (Statement *) statements->data[i]; + if (s && s->usesEH()) + return TRUE; + } + return FALSE; +} + +int UnrolledLoopStatement::fallOffEnd() +{ + //printf("UnrolledLoopStatement::fallOffEnd()\n"); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (s) + s->fallOffEnd(); + } + return TRUE; +} + + +int UnrolledLoopStatement::comeFrom() +{ int comefrom = FALSE; + + //printf("UnrolledLoopStatement::comeFrom()\n"); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (!s) + continue; + + comefrom |= s->comeFrom(); + } + return comefrom; +} + + +/******************************** ScopeStatement ***************************/ + +ScopeStatement::ScopeStatement(Loc loc, Statement *s) + : Statement(loc) +{ + this->statement = s; +} + +Statement *ScopeStatement::syntaxCopy() +{ + Statement *s; + + s = statement ? statement->syntaxCopy() : NULL; + s = new ScopeStatement(loc, s); + return s; +} + + +Statement *ScopeStatement::semantic(Scope *sc) +{ ScopeDsymbol *sym; + + //printf("ScopeStatement::semantic(sc = %p)\n", sc); + if (statement) + { Statements *a; + + sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + + a = statement->flatten(sc); + if (a) + { + statement = new CompoundStatement(loc, a); + } + + statement = statement->semantic(sc); + if (statement) + { + Statement *sentry; + Statement *sexception; + Statement *sfinally; + + statement->scopeCode(&sentry, &sexception, &sfinally); + if (sfinally) + { + //printf("adding sfinally\n"); + statement = new CompoundStatement(loc, statement, sfinally); + } + } + + sc->pop(); + } + return this; +} + +int ScopeStatement::hasBreak() +{ + //printf("ScopeStatement::hasBreak() %s\n", toChars()); + return statement ? statement->hasBreak() : FALSE; +} + +int ScopeStatement::hasContinue() +{ + return statement ? statement->hasContinue() : FALSE; +} + +int ScopeStatement::usesEH() +{ + return statement ? statement->usesEH() : FALSE; +} + +int ScopeStatement::fallOffEnd() +{ + return statement ? statement->fallOffEnd() : TRUE; +} + +int ScopeStatement::comeFrom() +{ + //printf("ScopeStatement::comeFrom()\n"); + return statement ? statement->comeFrom() : FALSE; +} + +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; + enclosingtryfinally = NULL; +} + +Statement *WhileStatement::syntaxCopy() +{ + WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL); + return s; +} + + +Statement *WhileStatement::semantic(Scope *sc) +{ +#if 0 + if (condition->op == TOKmatch) + { + /* Rewrite while (condition) body as: + * if (condition) + * do + * body + * while ((_match = _match.opNext), _match); + */ + + Expression *ew = new IdentifierExp(0, Id::_match); + ew = new DotIdExp(0, ew, Id::next); + ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew); + ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0)); + Expression *ev = new IdentifierExp(0, Id::_match); + //ev = new CastExp(0, ev, Type::tvoidptr); + ew = new CommaExp(0, ew, ev); + Statement *sw = new DoStatement(loc, body, ew); + Statement *si = new IfStatement(loc, condition, sw, NULL); + return si->semantic(sc); + } +#endif + + enclosingtryfinally = sc->tfOfTry; + + condition = condition->semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition->optimize(WANTvalue); + condition = condition->checkToBoolean(); + + sc->noctor++; + + Scope *scd = sc->push(); + scd->sbreak = this; + scd->scontinue = this; + if (body) + body = body->semantic(scd); + scd->pop(); + + sc->noctor--; + + return this; +} + +int WhileStatement::hasBreak() +{ + return TRUE; +} + +int WhileStatement::hasContinue() +{ + return TRUE; +} + +int WhileStatement::usesEH() +{ + return body ? body->usesEH() : 0; +} + +int WhileStatement::fallOffEnd() +{ + if (body) + body->fallOffEnd(); + return TRUE; +} + +int WhileStatement::comeFrom() +{ + 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; + enclosingtryfinally = NULL; +} + +Statement *DoStatement::syntaxCopy() +{ + DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy()); + return s; +} + + +Statement *DoStatement::semantic(Scope *sc) +{ + enclosingtryfinally = sc->tfOfTry; + + 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::fallOffEnd() +{ + if (body) + body->fallOffEnd(); + return TRUE; +} + +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; + this->enclosingtryfinally = NULL; +} + +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) +{ + enclosingtryfinally = sc->tfOfTry; + + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + if (init) + init = init->semantic(sc); + if (!condition) + // Use a default value + condition = new IntegerExp(loc, 1, Type::tboolean); + sc->noctor++; + condition = condition->semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition->optimize(WANTvalue); + condition = condition->checkToBoolean(); + if (increment) + increment = increment->semantic(sc); + + sc->sbreak = this; + sc->scontinue = this; + body = body->semantic(sc); + sc->noctor--; + + sc->pop(); + return this; +} + +void ForStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) +{ + //printf("ForStatement::scopeCode()\n"); + //print(); + if (init) + init->scopeCode(sentry, sexception, sfinally); + else + Statement::scopeCode(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::fallOffEnd() +{ + if (body) + body->fallOffEnd(); + return TRUE; +} + +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++; + hgs->FLinit.decl = 0; + init->toCBuffer(buf, hgs); + if (hgs->FLinit.decl > 0) + buf->writebyte(';'); + hgs->FLinit.decl = 0; + hgs->FLinit.init--; + } + else + buf->writebyte(';'); + if (condition) + { buf->writebyte(' '); + condition->toCBuffer(buf, hgs); + } + buf->writebyte(';'); + if (increment) + { buf->writebyte(' '); + increment->toCBuffer(buf, hgs); + } + buf->writebyte(')'); + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + body->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); +} + +/******************************** ForeachStatement ***************************/ + +ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, + Expression *aggr, Statement *body) + : Statement(loc) +{ + this->op = op; + this->arguments = arguments; + this->aggr = aggr; + this->body = body; + this->enclosingtryfinally = NULL; + + this->key = NULL; + this->value = NULL; + + this->func = NULL; +} + +Statement *ForeachStatement::syntaxCopy() +{ + Arguments *args = Argument::arraySyntaxCopy(arguments); + Expression *exp = aggr->syntaxCopy(); + ForeachStatement *s = new ForeachStatement(loc, op, args, exp, + body ? body->syntaxCopy() : NULL); + return s; +} + +Statement *ForeachStatement::semantic(Scope *sc) +{ + //printf("ForeachStatement::semantic() %p\n", this); + ScopeDsymbol *sym; + Statement *s = this; + int dim = arguments->dim; + int i; + TypeAArray *taa = NULL; + + Type *tn = NULL; + Type *tnv = NULL; + + enclosingtryfinally = sc->tfOfTry; + + func = sc->func; + if (func->fes) + func = func->fes->func; + + aggr = aggr->semantic(sc); + aggr = resolveProperties(sc, aggr); + if (!aggr->type) + { + error("invalid foreach aggregate %s", aggr->toChars()); + return this; + } + + inferApplyArgTypes(op, arguments, aggr); + + /* Check for inference errors + */ + if (dim != arguments->dim) + { + //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim); + error("cannot uniquely infer foreach argument types"); + return this; + } + + Type *tab = aggr->type->toBasetype(); + + if (tab->ty == Ttuple) // don't generate new scope for tuple loops + { + if (dim < 1 || dim > 2) + { + error("only one (value) or two (key,value) arguments for tuple foreach"); + return s; + } + + TypeTuple *tuple = (TypeTuple *)tab; + Statements *statements = new Statements(); + //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); + size_t n; + TupleExp *te = NULL; + if (aggr->op == TOKtuple) // expression tuple + { te = (TupleExp *)aggr; + n = te->exps->dim; + } + else if (aggr->op == TOKtype) // type tuple + { + n = Argument::dim(tuple->arguments); + } + else + assert(0); + for (size_t j = 0; j < n; j++) + { size_t k = (op == TOKforeach) ? j : n - 1 - j; + Expression *e; + Type *t; + if (te) + e = (Expression *)te->exps->data[k]; + else + t = Argument::getNth(tuple->arguments, k)->type; + Argument *arg = (Argument *)arguments->data[0]; + Statements *st = new Statements(); + + if (dim == 2) + { // Declare key + if (arg->storageClass & (STCout | STCref | STClazy)) + error("no storage class for key %s", arg->ident->toChars()); + TY keyty = arg->type->ty; + if ((keyty != Tint32 && keyty != Tuns32) && + (global.params.is64bit && keyty != Tint64 && keyty != Tuns64) + ) + { + error("foreach: key type must be %s, not %s", global.params.is64bit ? "int, uint, long or ulong" : "int or uint",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 = (Argument *)arguments->data[1]; // value + } + // Declare value + if (arg->storageClass & (STCout | STCref | STClazy)) + error("no storage class for value %s", arg->ident->toChars()); + Dsymbol *var; + if (te) + { + if (e->type->toBasetype()->ty == Tfunction && + e->op == TOKvar) + { VarExp *ve = (VarExp *)e; + var = new AliasDeclaration(loc, arg->ident, ve->var); + } + else + { + arg->type = e->type; + Initializer *ie = new ExpInitializer(0, e); + VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); + if (e->isConst()) + v->storage_class |= STCconst; +#if V2 + else + v->storage_class |= STCfinal; +#endif + 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 (i = 0; i < dim; i++) + { Argument *arg = (Argument *)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) + { Argument *arg; + + i = (dim == 1) ? 0 : 1; // index of value + arg = (Argument *)arguments->data[i]; + arg->type = arg->type->semantic(loc, sc); + tnv = arg->type->toBasetype(); + if (tnv->ty != tn->ty && + (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar)) + { + if (arg->storageClass & STCref) + error("foreach: value of UTF conversion cannot be ref"); + if (dim == 2) + { arg = (Argument *)arguments->data[0]; + if (arg->storageClass & STCref) + error("foreach: key cannot be ref"); + } + goto Lapply; + } + } + + for (i = 0; i < dim; i++) + { // Declare args + Argument *arg = (Argument *)arguments->data[i]; + VarDeclaration *var; + + var = new VarDeclaration(loc, arg->type, arg->ident, NULL); + var->storage_class |= STCforeach; + var->storage_class |= arg->storageClass & (STCin | STCout | STCref); +#if 1 + DeclarationExp *de = new DeclarationExp(loc, var); + de->semantic(sc); +#else + var->semantic(sc); + if (!sc->insert(var)) + error("%s already defined", var->ident->toChars()); +#endif + if (dim == 2 && i == 0) + key = var; + else + value = var; + } + + sc->sbreak = this; + sc->scontinue = this; + body = body->semantic(sc); + + 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 && + ((key->type->ty != Tint32 && key->type->ty != Tuns32) && + (global.params.is64bit && key->type->ty != Tint64 && key->type->ty != Tuns64) + ) + ) + { + error("foreach: key type must be %s, not %s", global.params.is64bit ? "int, uint, long or ulong" : "int or uint", key->type->toChars()); + } + + if (key && key->storage_class & (STCout | STCref)) + error("foreach: key cannot be out or ref"); + break; + + 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: + case Tdelegate: + Lapply: + { FuncDeclaration *fdapply; + Arguments *args; + Expression *ec; + Expression *e; + FuncLiteralDeclaration *fld; + Argument *a; + Type *t; + Expression *flde; + Identifier *id; + Type *tret; + + tret = func->type->nextOf(); + + // Need a variable to hold value from any return statements in body. + if (!sc->func->vresult && tret && tret != Type::tvoid) + { VarDeclaration *v; + + v = new VarDeclaration(loc, tret, Id::result, NULL); + v->noauto = 1; + v->semantic(sc); + if (!sc->insert(v)) + assert(0); + v->parent = sc->func; + sc->func->vresult = v; + } + + /* Turn body into the function literal: + * int delegate(ref T arg) { body } + */ + args = new Arguments(); + for (i = 0; i < dim; i++) + { Argument *arg = (Argument *)arguments->data[i]; + + arg->type = arg->type->semantic(loc, sc); + if (arg->storageClass & STCref) + id = arg->ident; + else + { // Make a copy of the ref argument so it isn't + // a reference. + VarDeclaration *v; + Initializer *ie; + char applyArg[10 + sizeof(i)*3 + 1]; + + sprintf(applyArg, "__applyArg%d", i); + id = Lexer::idPool(applyArg); + + ie = new ExpInitializer(0, new IdentifierExp(0, id)); + v = new VarDeclaration(0, arg->type, arg->ident, ie); + s = new DeclarationStatement(0, v); + body = new CompoundStatement(loc, s, body); + } + a = new Argument(STCref, arg->type, id, NULL); + args->push(a); + } + t = new TypeFunction(args, Type::tint32, 0, LINKd); + fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this); + fld->fbody = body; + flde = new FuncExp(loc, fld); + flde = flde->semantic(sc); + + // Resolve any forward referenced goto's + for (int i = 0; i < gotos.dim; i++) + { CompoundStatement *cs = (CompoundStatement *)gotos.data[i]; + GotoStatement *gs = (GotoStatement *)cs->statements->data[0]; + + if (!gs->label->statement) + { // 'Promote' it to this scope, and replace with a return + cases.push(gs); + s = new ReturnStatement(0, new IntegerExp(cases.dim + 1)); + cs->statements->data[0] = (void *)s; + } + } + + if (tab->ty == Taarray) + { + // Check types + Argument *arg = (Argument *)arguments->data[0]; + if (dim == 2) + { + if (arg->storageClass & STCref) + error("foreach: index cannot be ref"); + if (!arg->type->equals(taa->index)) + error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars()); + arg = (Argument *)arguments->data[1]; + } + if (!arg->type->equals(taa->nextOf())) + error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars()); + + /* Call: + * _aaApply(aggr, keysize, flde) + */ + if (dim == 2) + fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply2"); + else + fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply"); + fdapply->runTimeHack = true; + ec = new VarExp(0, fdapply); + Expressions *exps = new Expressions(); + exps->push(aggr); + size_t keysize = taa->key->size(); + keysize = (keysize + 3) & ~3; + exps->push(new IntegerExp(0, keysize, Type::tsize_t)); + exps->push(flde); + e = new CallExp(loc, ec, exps); + e->type = Type::tindex; // don't run semantic() on e + } + else if (tab->ty == Tarray || tab->ty == Tsarray) + { + /* Call: + * _aApply(aggr, flde) + */ + static char fntab[9][3] = + { "cc","cw","cd", + "wc","cc","wd", + "dc","dw","dd" + }; + char fdname[7+1+2+ sizeof(dim)*3 + 1]; + int flag; + + switch (tn->ty) + { + case Tchar: flag = 0; break; + case Twchar: flag = 3; break; + case Tdchar: flag = 6; break; + default: assert(0); + } + switch (tnv->ty) + { + case Tchar: flag += 0; break; + case Twchar: flag += 1; break; + case Tdchar: flag += 2; break; + default: assert(0); + } + const char *r = (op == TOKforeach_reverse) ? "R" : ""; + int j = sprintf(fdname, "_aApply%s%.*s%d", r, 2, fntab[flag], dim); + assert(j < sizeof(fdname)); + fdapply = FuncDeclaration::genCfunc(Type::tindex, fdname); + fdapply->runTimeHack = true; + + ec = new VarExp(0, fdapply); + Expressions *exps = new Expressions(); + if (tab->ty == Tsarray) + aggr = aggr->castTo(sc, tn->arrayOf()); + exps->push(aggr); + exps->push(flde); + e = new CallExp(loc, ec, exps); + e->type = Type::tindex; // don't run semantic() on e + } + else if (tab->ty == Tdelegate) + { + /* Call: + * aggr(flde) + */ + Expressions *exps = new Expressions(); + exps->push(flde); + e = new CallExp(loc, aggr, exps); + e = e->semantic(sc); + if (e->type != Type::tint32) + error("opApply() function for %s must return an int", tab->toChars()); + } + else + { + /* 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 (int i = 0; i < cases.dim; i++) + { + s = (Statement *)cases.data[i]; + s = new CaseStatement(0, new IntegerExp(i + 2), s); + a->push(s); + } + + s = new CompoundStatement(loc, a); + s = new SwitchStatement(loc, e, s); + s = s->semantic(sc); + } + break; + } + + default: + error("foreach: %s is not an aggregate type", aggr->type->toChars()); + 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::fallOffEnd() +{ + if (body) + body->fallOffEnd(); + return TRUE; +} + +int ForeachStatement::comeFrom() +{ + if (body) + return body->comeFrom(); + return FALSE; +} + +void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(op)); + buf->writestring(" ("); + int i; + for (int i = 0; i < arguments->dim; i++) + { + Argument *a = (Argument *)arguments->data[i]; + if (i) + buf->writestring(", "); + if (a->storageClass & STCref) + buf->writestring((global.params.Dversion == 1) + ? (char*)"inout " : (char*)"ref "); + if (a->type) + a->type->toCBuffer(buf, a->ident, hgs); + else + buf->writestring(a->ident->toChars()); + } + buf->writestring("; "); + aggr->toCBuffer(buf, hgs); + buf->writebyte(')'); + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); +} + +/******************************** IfStatement ***************************/ + +IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody) + : Statement(loc) +{ + this->arg = arg; + this->condition = condition; + this->ifbody = ifbody; + this->elsebody = elsebody; + this->match = NULL; +} + +Statement *IfStatement::syntaxCopy() +{ + Statement *i = NULL; + if (ifbody) + i = ifbody->syntaxCopy(); + + Statement *e = NULL; + if (elsebody) + e = elsebody->syntaxCopy(); + + Argument *a = arg ? arg->syntaxCopy() : NULL; + IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e); + return s; +} + +Statement *IfStatement::semantic(Scope *sc) +{ + condition = condition->semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition->checkToBoolean(); + + // If we can short-circuit evaluate the if statement, don't do the + // semantic analysis of the skipped code. + // This feature allows a limited form of conditional compilation. + condition = condition->optimize(WANTflags); + + // Evaluate at runtime + unsigned cs0 = sc->callSuper; + unsigned cs1; + + Scope *scd; + if (arg) + { /* Declare arg, which we will set to be the + * result of condition. + */ + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + scd = sc->push(sym); + + Type *t = arg->type ? arg->type : condition->type; + match = new VarDeclaration(loc, t, arg->ident, NULL); + match->noauto = 1; + match->semantic(scd); + if (!scd->insert(match)) + assert(0); + match->parent = sc->func; + + /* Generate: + * (arg = condition) + */ + VarExp *v = new VarExp(0, match); + condition = new AssignExp(loc, v, condition); + condition = condition->semantic(scd); + } + else + scd = sc->push(); + ifbody = ifbody->semantic(scd); + scd->pop(); + + cs1 = sc->callSuper; + sc->callSuper = cs0; + if (elsebody) + elsebody = elsebody->semanticScope(sc, NULL, NULL); + sc->mergeCallSuper(loc, cs1); + + return this; +} + +int IfStatement::usesEH() +{ + return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); +} + +int IfStatement::fallOffEnd() +{ + if (!ifbody || ifbody->fallOffEnd() || + !elsebody || elsebody->fallOffEnd()) + return TRUE; + return FALSE; +} + + +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(arg->ident->toChars()); + buf->writebyte(';'); + } + 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()); +} + +void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + condition->toCBuffer(buf, hgs); + buf->writenl(); + if (ifbody) + ifbody->toCBuffer(buf, hgs); + if (elsebody) + { + buf->writestring("else"); + buf->writenl(); + elsebody->toCBuffer(buf, hgs); + } + buf->writenl(); +} + + +/******************************** PragmaStatement ***************************/ + +PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body) + : Statement(loc) +{ + this->ident = ident; + this->args = args; + this->body = body; +} + +Statement *PragmaStatement::syntaxCopy() +{ + Statement *b = NULL; + if (body) + b = body->syntaxCopy(); + PragmaStatement *s = new PragmaStatement(loc, + ident, Expression::arraySyntaxCopy(args), b); + return s; +} + +Statement *PragmaStatement::semantic(Scope *sc) +{ // Should be merged with PragmaDeclaration + //printf("PragmaStatement::semantic() %s\n", toChars()); + //printf("body = %p\n", body); + if (ident == Id::msg) + { + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { + Expression *e = (Expression *)args->data[i]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKstring) + { + StringExp *se = (StringExp *)e; + fprintf(stdmsg, "%.*s", (int)se->len, se->string); + } + else + error("string expected for message, not '%s'", e->toChars()); + } + fprintf(stdmsg, "\n"); + } + } + else if (ident == Id::lib) + { + if (!args || args->dim != 1) + error("string expected for library name"); + else + { + Expression *e = (Expression *)args->data[0]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + if (e->op != TOKstring) + error("string expected for library name, not '%s'", e->toChars()); + else if (global.params.verbose) + { + StringExp *se = (StringExp *)e; + char *name = (char *)mem.malloc(se->len + 1); + memcpy(name, se->string, se->len); + name[se->len] = 0; + printf("library %s\n", name); + mem.free(name); + } + } + } + else + error("unrecognized pragma(%s)", ident->toChars()); + + if (body) + { + body = body->semantic(sc); + } + return body; +} + +int PragmaStatement::usesEH() +{ + return body && body->usesEH(); +} + +int PragmaStatement::fallOffEnd() +{ + if (body) + return body->fallOffEnd(); + return TRUE; +} + +void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("pragma ("); + buf->writestring(ident->toChars()); + if (args && args->dim) + { + buf->writestring(", "); + argsToCBuffer(buf, args, hgs); + } + buf->writeByte(')'); + if (body) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + + body->toCBuffer(buf, hgs); + + buf->writeByte('}'); + buf->writenl(); + } + else + { + buf->writeByte(';'); + buf->writenl(); + } +} + + +/******************************** StaticAssertStatement ***************************/ + +StaticAssertStatement::StaticAssertStatement(StaticAssert *sa) + : Statement(sa->loc) +{ + this->sa = sa; +} + +Statement *StaticAssertStatement::syntaxCopy() +{ + StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL)); + return s; +} + +Statement *StaticAssertStatement::semantic(Scope *sc) +{ + sa->semantic2(sc); + return NULL; +} + +void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + sa->toCBuffer(buf, hgs); +} + + +/******************************** SwitchStatement ***************************/ + +SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b) + : Statement(loc) +{ + condition = c; + body = b; + sdefault = NULL; + cases = NULL; + hasNoDefault = 0; + // LLVMDC + enclosingtryfinally = 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 + + enclosingtryfinally = sc->tfOfTry; + + 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 Array(); + sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead + body = body->semantic(sc); + sc->noctor--; + + // Resolve any goto case's with exp + for (int i = 0; i < gotoCases.dim; i++) + { + GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i]; + + if (!gcs->exp) + { + gcs->error("no case statement following goto case;"); + break; + } + + for (Scope *scx = sc; scx; scx = scx->enclosing) + { + if (!scx->sw) + continue; + for (int j = 0; j < scx->sw->cases->dim; j++) + { + CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j]; + + if (cs->exp->equals(gcs->exp)) + { + gcs->cs = cs; + goto Lfoundcase; + } + } + } + gcs->error("case %s not found", gcs->exp->toChars()); + + Lfoundcase: + ; + } + + if (!sc->sw->sdefault) + { hasNoDefault = 1; + + if (global.params.warnings) + { fprintf(stdmsg, "warning - "); + error("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); + a->push(new BreakStatement(loc, NULL)); + sc->sw->sdefault = new DefaultStatement(loc, s); + a->push(sc->sw->sdefault); + cs = new CompoundStatement(loc, a); + body = cs; + } + + sc->pop(); + return this; +} + +int SwitchStatement::hasBreak() +{ + return TRUE; +} + +int SwitchStatement::usesEH() +{ + return body ? body->usesEH() : 0; +} + +int SwitchStatement::fallOffEnd() +{ + if (body) + body->fallOffEnd(); + return TRUE; // need to do this better +} + +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; +} + +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) + { int i; + + exp = exp->implicitCastTo(sc, sw->condition->type); + exp = exp->optimize(WANTvalue | WANTinterpret); + if (exp->op != TOKstring && exp->op != TOKint64) + { + error("case must be a string or an integral constant, not %s", exp->toChars()); + exp = new IntegerExp(0); + } + + for (i = 0; i < sw->cases->dim; i++) + { + CaseStatement *cs = (CaseStatement *)sw->cases->data[i]; + + //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars()); + if (cs->exp->equals(exp)) + { error("duplicate case %s in switch statement", exp->toChars()); + break; + } + } + + sw->cases->push(this); + + // Resolve any goto case's with no exp to this case statement + for (i = 0; i < sw->gotoCases.dim; i++) + { + GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i]; + + if (!gcs->exp) + { + gcs->cs = this; + sw->gotoCases.remove(i); // remove from array + } + } + } + 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::fallOffEnd() +{ + return statement->fallOffEnd(); +} + +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); +} + +/******************************** DefaultStatement ***************************/ + +DefaultStatement::DefaultStatement(Loc loc, Statement *s) + : Statement(loc) +{ + this->statement = s; +#if IN_GCC ++ cblock = NULL; +#endif + bodyBB = NULL; +} + +Statement *DefaultStatement::syntaxCopy() +{ + DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy()); + return s; +} + +Statement *DefaultStatement::semantic(Scope *sc) +{ + if (sc->sw) + { + if (sc->sw->sdefault) + { + error("switch statement already has a default"); + } + sc->sw->sdefault = this; + } + else + error("default not in switch statement"); + statement = statement->semantic(sc); + return this; +} + +int DefaultStatement::usesEH() +{ + return statement->usesEH(); +} + +int DefaultStatement::fallOffEnd() +{ + return statement->fallOffEnd(); +} + +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; + enclosingtryfinally = NULL; +} + +Statement *GotoDefaultStatement::syntaxCopy() +{ + GotoDefaultStatement *s = new GotoDefaultStatement(loc); + return s; +} + +Statement *GotoDefaultStatement::semantic(Scope *sc) +{ + enclosingtryfinally = sc->tfOfTry; + sw = sc->sw; + if (!sw) + error("goto default not in switch statement"); + return this; +} + +int GotoDefaultStatement::fallOffEnd() +{ + return FALSE; +} + +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; + enclosingtryfinally = NULL; + sw = NULL; +} + +Statement *GotoCaseStatement::syntaxCopy() +{ + Expression *e = exp ? exp->syntaxCopy() : NULL; + GotoCaseStatement *s = new GotoCaseStatement(loc, e); + return s; +} + +Statement *GotoCaseStatement::semantic(Scope *sc) +{ + enclosingtryfinally = sc->tfOfTry; + 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::fallOffEnd() +{ + return FALSE; +} + +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::fallOffEnd() +{ + return FALSE; +} + +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->enclosingtryfinally = NULL; +} + +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()); + this->enclosingtryfinally = sc->tfOfTry; + + FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + Scope *scx = sc; + int implicit0 = 0; + + if (sc->fes) + { + // Find scope of function foreach is in + for (; 1; scx = scx->enclosing) + { + assert(scx); + if (scx->func != fd) + { fd = scx->func; // fd is now function enclosing foreach + break; + } + } + } + + Type *tret = fd->type->nextOf(); + if (fd->tintro) + 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->tf || scx->tf) + 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) + fd->nrvo_var = v; + else + fd->nrvo_can = 0; + } + else if (fd->nrvo_var != v) + fd->nrvo_can = 0; + } + else + fd->nrvo_can = 0; + + if (fd->returnLabel && tbret->ty != Tvoid) + { + } + else if (fd->inferRetType) + { + if (fd->type->nextOf()) + { + if (!exp->type->equals(fd->type->nextOf())) + error("mismatched function return type inference of %s and %s", + exp->type->toChars(), fd->type->nextOf()->toChars()); + } + else + { + fd->type->next = exp->type; + fd->type = fd->type->semantic(loc, sc); + if (!fd->tintro) + { tret = fd->type->nextOf(); + tbret = tret->toBasetype(); + } + } + } + else if (tbret->ty != Tvoid) + { + exp = exp->implicitCastTo(sc, tret); + } + } + 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); + s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); + } + else if (fd->type->nextOf()->toBasetype() == Type::tvoid) + { + Statement *s1; + Statement *s2; + + s = new ReturnStatement(0, NULL); + sc->fes->cases.push(s); + + // Construct: { exp; return cases.dim + 1; } + s1 = new ExpStatement(loc, exp); + s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); + s = new CompoundStatement(loc, s1, s2); + } + else + { + VarExp *v; + Statement *s1; + Statement *s2; + + // Construct: return vresult; + if (!fd->vresult) + { VarDeclaration *v; + + v = new VarDeclaration(loc, tret, Id::result, NULL); + v->noauto = 1; + v->semantic(scx); + if (!scx->insert(v)) + assert(0); + v->parent = fd; + fd->vresult = v; + } + + v = new VarExp(0, fd->vresult); + s = new ReturnStatement(0, v); + sc->fes->cases.push(s); + + // Construct: { vresult = exp; return cases.dim + 1; } + v = new VarExp(0, fd->vresult); + exp = new AssignExp(loc, v, exp); + exp = exp->semantic(sc); + s1 = new ExpStatement(loc, exp); + s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); + s = new CompoundStatement(loc, s1, s2); + } + return s; + } + + if (exp) + { + if (fd->returnLabel && tbret->ty != Tvoid) + { + assert(fd->vresult); + VarExp *v = new VarExp(0, fd->vresult); + + exp = new AssignExp(loc, v, exp); + exp = 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) + { Statement *s; + + s = new ExpStatement(0, exp); + return new CompoundStatement(loc, s, gs); + } + return gs; + } + + if (exp && tbret->ty == Tvoid && !fd->isMain()) + { Statement *s; + + s = new ExpStatement(loc, exp); + loc = 0; + exp = NULL; + return new CompoundStatement(loc, s, this); + } + + return this; +} + +int ReturnStatement::fallOffEnd() +{ + return FALSE; +} + +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; + this->enclosingtryfinally = NULL; +} + +Statement *BreakStatement::syntaxCopy() +{ + BreakStatement *s = new BreakStatement(loc, ident); + return s; +} + +Statement *BreakStatement::semantic(Scope *sc) +{ + enclosingtryfinally = sc->tfOfTry; + // 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->tf != sc->tf) + 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::fallOffEnd() +{ + return FALSE; +} + +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; + this->enclosingtryfinally = NULL; +} + +Statement *ContinueStatement::syntaxCopy() +{ + ContinueStatement *s = new ContinueStatement(loc, ident); + return s; +} + +Statement *ContinueStatement::semantic(Scope *sc) +{ + enclosingtryfinally = sc->tfOfTry; + //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->tf != sc->tf) + 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::fallOffEnd() +{ + return FALSE; +} + +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; +} + +SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body) + : Statement(loc) +{ + this->exp = NULL; + this->body = body; + this->esync = esync; +} + +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) + { ClassDeclaration *cd; + + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + cd = exp->type->isClassHandle(); + if (!cd) + error("can only synchronize on class objects, not '%s'", exp->type->toChars()); + else if (cd->isInterfaceDeclaration()) + { Type *t = new TypeIdentifier(0, Id::Object); + + t = t->semantic(0, sc); + exp = new CastExp(loc, exp, t); + exp = exp->semantic(sc); + } + } + 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::fallOffEnd() +{ + return body ? body->fallOffEnd() : TRUE; +} + +void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("synchronized"); + if (exp) + { buf->writebyte('('); + exp->toCBuffer(buf, hgs); + buf->writebyte(')'); + } + if (body) + { + buf->writebyte(' '); + body->toCBuffer(buf, hgs); + } +} + +/******************************** WithStatement ***************************/ + +WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body) + : Statement(loc) +{ + this->exp = exp; + this->body = body; + wthis = NULL; +} + +Statement *WithStatement::syntaxCopy() +{ + WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL); + return s; +} + +Statement *WithStatement::semantic(Scope *sc) +{ ScopeDsymbol *sym; + Initializer *init; + + //printf("WithStatement::semantic()\n"); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + if (exp->op == TOKimport) + { ScopeExp *es = (ScopeExp *)exp; + + sym = es->sds; + } + else if (exp->op == TOKtype) + { TypeExp *es = (TypeExp *)exp; + + sym = es->type->toDsymbol(sc)->isScopeDsymbol(); + if (!sym) + { error("%s has no members", es->toChars()); + body = body->semantic(sc); + return this; + } + } + else + { Type *t = exp->type; + + assert(t); + t = t->toBasetype(); + if (t->isClassHandle()) + { + init = new ExpInitializer(loc, exp); + wthis = new VarDeclaration(loc, exp->type, Id::withSym, init); + wthis->semantic(sc); + + sym = new WithScopeSymbol(this); + sym->parent = sc->scopesym; + } + else if (t->ty == Tstruct) + { + Expression *e = exp->addressOf(sc); + init = new ExpInitializer(loc, e); + wthis = new VarDeclaration(loc, e->type, Id::withSym, init); + wthis->semantic(sc); + sym = new WithScopeSymbol(this); + sym->parent = sc->scopesym; + } + else + { error("with expressions must be class objects, not '%s'", exp->type->toChars()); + return NULL; + } + } + sc = sc->push(sym); + + if (body) + body = body->semantic(sc); + + sc->pop(); + + return this; +} + +void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("with ("); + exp->toCBuffer(buf, hgs); + buf->writestring(")\n"); + if (body) + body->toCBuffer(buf, hgs); +} + +int WithStatement::usesEH() +{ + return body ? body->usesEH() : 0; +} + +int WithStatement::fallOffEnd() +{ + return body ? body->fallOffEnd() : TRUE; +} + +/******************************** TryCatchStatement ***************************/ + +TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches) + : Statement(loc) +{ + this->body = body; + this->catches = catches; +} + +Statement *TryCatchStatement::syntaxCopy() +{ + Array *a = new Array(); + a->setDim(catches->dim); + for (int i = 0; i < a->dim; i++) + { Catch *c; + + c = (Catch *)catches->data[i]; + c = c->syntaxCopy(); + a->data[i] = c; + } + TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); + return s; +} + +Statement *TryCatchStatement::semantic(Scope *sc) +{ + body = body->semanticScope(sc, NULL /*this*/, NULL); + + for (int i = 0; i < catches->dim; i++) + { Catch *c; + + c = (Catch *)catches->data[i]; + c->semantic(sc); + + // Determine if current catch 'hides' any previous catches + for (int j = 0; j < i; j++) + { Catch *cj = (Catch *)catches->data[j]; + char *si = c->loc.toChars(); + char *sj = cj->loc.toChars(); + + if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype())) + error("catch at %s hides catch at %s", sj, si); + } + } + return this; +} + +int TryCatchStatement::hasBreak() +{ + return FALSE; //TRUE; +} + +int TryCatchStatement::usesEH() +{ + return TRUE; +} + +int TryCatchStatement::fallOffEnd() +{ + int result = FALSE; + + if (body) + result = body->fallOffEnd(); + for (int i = 0; i < catches->dim; i++) + { Catch *c; + + c = (Catch *)catches->data[i]; + if (c->handler) + result |= c->handler->fallOffEnd(); + } + return result; +} + +void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("try"); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); + int i; + for (i = 0; i < catches->dim; i++) + { + Catch *c = (Catch *)catches->data[i]; + c->toCBuffer(buf, hgs); + } +} + +/******************************** Catch ***************************/ + +Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler) +{ + //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars()); + this->loc = loc; + this->type = t; + this->ident = id; + this->handler = handler; + var = NULL; +} + +Catch *Catch::syntaxCopy() +{ + Catch *c = new Catch(loc, + (type ? type->syntaxCopy() : NULL), + ident, + (handler ? handler->syntaxCopy() : NULL)); + return c; +} + +void Catch::semantic(Scope *sc) +{ ScopeDsymbol *sym; + + //printf("Catch::semantic(%s)\n", ident->toChars()); + +#ifndef IN_GCC + if (sc->tf) + { + /* This is because the _d_local_unwind() gets the stack munged + * up on this. The workaround is to place any try-catches into + * a separate function, and call that. + * To fix, have the compiler automatically convert the finally + * body into a nested function. + */ + error(loc, "cannot put catch statement inside finally block"); + } +#endif + + sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + + if (!type) + type = new TypeIdentifier(0, Id::Object); + type = type->semantic(loc, sc); + if (!type->toBasetype()->isClassHandle()) + error("can only catch class objects, not '%s'", type->toChars()); + else if (ident) + { + var = new VarDeclaration(loc, type, ident, NULL); + var->parent = sc->parent; + sc->insert(var); + } + handler = handler->semantic(sc); + + sc->pop(); +} + +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(); + 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; + this->enclosingtryfinally = NULL; +} + +Statement *TryFinallyStatement::syntaxCopy() +{ + TryFinallyStatement *s = new TryFinallyStatement(loc, + body->syntaxCopy(), finalbody->syntaxCopy()); + return s; +} + +Statement *TryFinallyStatement::semantic(Scope *sc) +{ + //printf("TryFinallyStatement::semantic()\n"); + + enclosingtryfinally = sc->tfOfTry; + sc->tfOfTry = this; + body = body->semantic(sc); + sc->tfOfTry = enclosingtryfinally; + + sc = sc->push(); + sc->tf = this; + sc->sbreak = NULL; + sc->scontinue = NULL; // no break or continue out of finally block + finalbody = finalbody->semantic(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::fallOffEnd() +{ int result; + + result = body ? body->fallOffEnd() : TRUE; +// if (finalbody) +// result = finalbody->fallOffEnd(); + return result; +} + +/****************************** 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; +} + +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(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; + */ + static int num; + char name[5 + sizeof(num) * 3 + 1]; + sprintf(name, "__osf%d", ++num); + Identifier *id = Lexer::idPool(name); + + ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0)); + VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie); + *sentry = new DeclarationStatement(loc, v); + + Expression *e = new IntegerExp(1); + e = new AssignExp(0, new VarExp(0, v), e); + *sexception = new ExpStatement(0, e); + + e = new VarExp(0, v); + e = new NotExp(0, e); + *sfinally = new IfStatement(0, NULL, e, statement, NULL); + + break; + } + + default: + assert(0); + } +} + +/******************************** ThrowStatement ***************************/ + +ThrowStatement::ThrowStatement(Loc loc, Expression *exp) + : Statement(loc) +{ + this->exp = exp; +} + +Statement *ThrowStatement::syntaxCopy() +{ + ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy()); + return s; +} + +Statement *ThrowStatement::semantic(Scope *sc) +{ + //printf("ThrowStatement::semantic()\n"); + + FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + fd->hasReturnExp |= 2; + + if (sc->incontract) + error("Throw statements cannot be in contracts"); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + if (!exp->type->toBasetype()->isClassHandle()) + error("can only throw class objects, not type %s", exp->type->toChars()); + return this; +} + +int ThrowStatement::fallOffEnd() +{ + return FALSE; +} + +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) +{ + statement = statement ? statement->semantic(sc) : NULL; + return this; +} + +Statements *VolatileStatement::flatten(Scope *sc) +{ + Statements *a; + + a = statement ? statement->flatten(sc) : NULL; + if (a) + { for (int i = 0; i < a->dim; i++) + { Statement *s = (Statement *)a->data[i]; + + s = new VolatileStatement(loc, s); + a->data[i] = s; + } + } + + return a; +} + +int VolatileStatement::fallOffEnd() +{ + return statement ? statement->fallOffEnd() : TRUE; +} + +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->tf = NULL; + this->enclosingtryfinally = 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"); + tf = sc->tf; + enclosingtryfinally = sc->tfOfTry; + label = fd->searchLabel(ident); + if (!label->statement && sc->fes) + { + /* Either the goto label is forward referenced or it + * is in the function that the enclosing foreach is in. + * Can't know yet, so wrap the goto in a compound statement + * so we can patch it later, and add it to a 'look at this later' + * list. + */ + Statements *a = new Statements(); + Statement *s; + + a->push(this); + s = new CompoundStatement(loc, a); + sc->fes->gotos.push(s); // 'look at this later' list + return s; + } + if (label->statement && label->statement->tf != sc->tf) + error("cannot goto in or out of finally block"); + return this; +} + +int GotoStatement::fallOffEnd() +{ + return FALSE; +} + +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->tf = NULL; + this->enclosingtryfinally = NULL; + this->lblock = NULL; + this->isReturnLabel = 0; + this->llvmBB = 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; + tf = sc->tf; + enclosingtryfinally = sc->tfOfTry; + sc = sc->push(); + sc->scopesym = sc->enclosing->scopesym; + sc->callSuper |= CSXlabel; + sc->slabel = this; + if (statement) + statement = statement->semantic(sc); + sc->pop(); + return this; +} + +Statements *LabelStatement::flatten(Scope *sc) +{ + Statements *a = NULL; + + if (statement) + { + a = statement->flatten(sc); + if (a) + { + if (!a->dim) + { + a->push(new ExpStatement(loc, NULL)); + } + Statement *s = (Statement *)a->data[0]; + + s = new LabelStatement(loc, ident, s); + a->data[0] = s; + } + } + + return a; +} + + +int LabelStatement::usesEH() +{ + return statement ? statement->usesEH() : FALSE; +} + +int LabelStatement::fallOffEnd() +{ + return statement ? statement->fallOffEnd() : TRUE; +} + +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/template.c b/dmd/template.c index 17d17124..52604018 100644 --- a/dmd/template.c +++ b/dmd/template.c @@ -130,6 +130,7 @@ int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) Dsymbol *s2 = isDsymbol(o2); Tuple *v1 = isTuple(o1); Tuple *v2 = isTuple(o2); + //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, v1 %p v2 %p\n", t1,t2,e1,e2,s1,s2,v1,v2); /* A proper implementation of the various equals() overrides * should make it possible to just do o1->equals(o2), but @@ -158,7 +159,7 @@ int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) } if (!t2 || !t1->equals(t2)) - goto L1; + goto Lnomatch; } else if (e1) { @@ -168,33 +169,39 @@ int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) printf("match %d\n", e1->equals(e2)); e1->print(); e2->print(); + e1->type->print(); + e2->type->print(); } #endif - if (!e2 || !e1->equals(e2)) - goto L1; + if (!e2) + goto Lnomatch; + if (!e1->equals(e2)) + goto Lnomatch; } else if (s1) { //printf("%p %s, %p %s\n", s1, s1->toChars(), s2, s2->toChars()); if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) - goto L1; + { + goto Lnomatch; + } } else if (v1) { if (!v2) - goto L1; + goto Lnomatch; if (v1->objects.dim != v2->objects.dim) - goto L1; + goto Lnomatch; for (size_t i = 0; i < v1->objects.dim; i++) { if (!match((Object *)v1->objects.data[i], (Object *)v2->objects.data[i], tempdecl, sc)) - goto L1; + goto Lnomatch; } } return 1; // match -L1: +Lnomatch: return 0; // nomatch; } @@ -268,6 +275,7 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, TemplateParame #endif this->loc = loc; this->parameters = parameters; + this->origParameters = parameters; this->members = decldefs; this->overnext = NULL; this->overroot = NULL; @@ -336,6 +344,17 @@ void TemplateDeclaration::semantic(Scope *sc) Scope *paramscope = sc->push(paramsym); paramscope->parameterSpecialization = 1; + if (global.params.doDocComments) + { + origParameters = new TemplateParameters(); + origParameters->setDim(parameters->dim); + for (int i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + origParameters->data[i] = (void *)tp->syntaxCopy(); + } + } + for (int i = 0; i < parameters->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; @@ -348,6 +367,8 @@ void TemplateDeclaration::semantic(Scope *sc) 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(); @@ -437,6 +458,7 @@ int TemplateDeclaration::overloadInsert(Dsymbol *s) * 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. @@ -447,8 +469,9 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, { MATCH m; int dedtypes_dim = dedtypes->dim; -#if LOG - printf("+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag); +#define LOGM 0 +#if LOGM + printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag); #endif #if 0 @@ -466,7 +489,7 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, // If more arguments than parameters, no match if (ti->tiargs->dim > parameters_dim && !variadic) { -#if LOG +#if LOGM printf(" no match: more arguments than parameters\n"); #endif return MATCHnomatch; @@ -489,7 +512,7 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, Declaration *sparam; //printf("\targument [%d]\n", i); -#if 0 +#if LOGM //printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null"); TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); if (ttp) @@ -528,7 +551,7 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, } } -#if 0 +#if LOGM // Print out the results printf("--------------------------\n"); printf("template %s\n", toChars()); @@ -553,20 +576,20 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, goto Lnomatch; #endif -#if LOG +#if LOGM printf(" match = %d\n", m); #endif goto Lret; Lnomatch: -#if LOG +#if LOGM printf(" no match\n"); #endif m = MATCHnomatch; Lret: paramscope->pop(); -#if LOG +#if LOGM printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); #endif return m; @@ -645,6 +668,8 @@ int TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2) * fargs arguments to function * Output: * dedargs Expression/Type deduced template arguments + * Returns: + * match level */ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs, @@ -652,12 +677,13 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressi { size_t i; size_t nfparams; - size_t nfparams2; size_t nfargs; - size_t nargsi; + size_t nargsi; // array size of targsi + int fptupindex = -1; + int tuple_dim = 0; MATCH match = MATCHexact; FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); - TypeFunction *fdtype; + TypeFunction *fdtype; // type of fd TemplateTupleParameter *tp; Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T @@ -682,13 +708,19 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressi paramsym->parent = scope->parent; Scope *paramscope = scope->push(paramsym); + tp = isVariadic(); + nargsi = 0; if (targsi) { // Set initial template arguments nargsi = targsi->dim; if (nargsi > parameters->dim) - goto Lnomatch; + { if (!tp) + goto Lnomatch; + dedargs->setDim(nargsi); + dedargs->zero(); + } memcpy(dedargs->data, targsi->data, nargsi * sizeof(*dedargs->data)); @@ -698,6 +730,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressi Declaration *sparam; m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); + //printf("\tdeduceType m = %d\n", m); if (m == MATCHnomatch) goto Lnomatch; if (m < match) @@ -713,7 +746,6 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressi fdtype = (TypeFunction *)fd->type; nfparams = Argument::dim(fdtype->parameters); // number of function parameters - nfparams2 = nfparams; nfargs = fargs->dim; // number of function arguments /* Check for match of function arguments with variadic template @@ -723,7 +755,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressi * void main() { Foo(1,2,3); } */ tp = isVariadic(); - if (tp) + if (tp) // if variadic { if (nfparams == 0) // if no function parameters { @@ -736,33 +768,38 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressi goto L1; else { - /* See if 'A' of the template parameter matches 'A' - * of the type of the last function parameter. + /* 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. */ - Argument *fparam = (Argument *)fdtype->parameters->data[nfparams - 1]; - if (fparam->type->ty != Tident) - goto L1; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (!tp->ident->equals(tid->ident) || tid->idents.dim) - goto L1; + for (fptupindex = 0; fptupindex < nfparams; fptupindex++) + { + Argument *fparam = (Argument *)fdtype->parameters->data[fptupindex]; + if (fparam->type->ty != Tident) + continue; + TypeIdentifier *tid = (TypeIdentifier *)fparam->type; + if (!tp->ident->equals(tid->ident) || tid->idents.dim) + continue; - if (fdtype->varargs) // variadic function doesn't - goto Lnomatch; // go with variadic template + if (fdtype->varargs) // variadic function doesn't + goto Lnomatch; // go with variadic template - /* The types of the function arguments [nfparams - 1 .. nfargs] - * now form the tuple argument. - */ - Tuple *t = new Tuple(); - dedargs->data[parameters->dim - 1] = (void *)t; + /* The types of the function arguments + * now form the tuple argument. + */ + Tuple *t = new Tuple(); + dedargs->data[parameters->dim - 1] = (void *)t; - int tuple_dim = nfargs - (nfparams - 1); - t->objects.setDim(tuple_dim); - for (i = 0; i < tuple_dim; i++) - { Expression *farg = (Expression *)fargs->data[nfparams - 1 + i]; - t->objects.data[i] = (void *)farg->type; + tuple_dim = nfargs - (nfparams - 1); + t->objects.setDim(tuple_dim); + for (i = 0; i < tuple_dim; i++) + { Expression *farg = (Expression *)fargs->data[fptupindex + i]; + t->objects.data[i] = (void *)farg->type; + } + goto L2; } - nfparams2--; // don't consider the last parameter for type deduction - goto L2; + fptupindex = -1; } } @@ -778,11 +815,19 @@ L1: L2: // Loop through the function parameters - for (i = 0; i < nfparams2; i++) + for (i = 0; i < nfparams; i++) { + /* Skip over function parameters which wound up + * as part of a template tuple parameter. + */ + if (i == fptupindex) + { if (fptupindex == nfparams - 1) + break; + i += tuple_dim - 1; + continue; + } + Argument *fparam = Argument::getNth(fdtype->parameters, i); - Expression *farg; - MATCH m; if (i >= nfargs) // if not enough arguments { @@ -794,12 +839,13 @@ L2: } } else - { farg = (Expression *)fargs->data[i]; + { Expression *farg = (Expression *)fargs->data[i]; #if 0 printf("\tfarg->type = %s\n", farg->type->toChars()); printf("\tfparam->type = %s\n", fparam->type->toChars()); #endif + MATCH m; m = farg->type->deduceType(scope, fparam->type, parameters, &dedtypes); //printf("\tdeduceType m = %d\n", m); @@ -852,30 +898,40 @@ Lmatch: for (i = nargsi; i < dedargs->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + //printf("tp[%d] = %s\n", i, tp->ident->toChars()); + /* For T:T*, the dedargs is the T*, dedtypes is the T + * But for function templates, we really need them to match + */ Object *oarg = (Object *)dedargs->data[i]; - Object *o = (Object *)dedtypes.data[i]; - //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, o); + Object *oded = (Object *)dedtypes.data[i]; + //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); if (!oarg) { - if (o) + if (oded) { if (tp->specialization()) - error("specialization not allowed for deduced parameter %s", tp->ident->toChars()); + { /* The specialization can work as long as afterwards + * the oded == oarg + */ + Declaration *sparam; + dedargs->data[i] = (void *)oded; + MATCH m2 = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); + //printf("m2 = %d\n", m2); + if (!m2) + goto Lnomatch; + if (m2 < match) + match = m2; // pick worst match + if (dedtypes.data[i] != oded) + error("specialization not allowed for deduced parameter %s", tp->ident->toChars()); + } } else - { o = tp->defaultArg(paramscope); - if (!o) + { oded = tp->defaultArg(paramscope); + if (!oded) goto Lnomatch; -#if 0 - Match m; - Declaration *sparam; - m = tp->matchArg(paramscope, dedargs, i, parameters, &sparam); - if (!m) - goto Lnomatch; -#endif } - declareParameter(paramscope, tp, o); - dedargs->data[i] = (void *)o; + declareParameter(paramscope, tp, oded); + dedargs->data[i] = (void *)oded; } } @@ -887,7 +943,7 @@ Lmatch: #endif paramscope->pop(); - //printf("\tmatch\n"); + //printf("\tmatch %d\n", match); return match; Lnomatch: @@ -1044,9 +1100,9 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, int c2 = td_best->leastAsSpecialized(td); //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 && !c2) + if (c1 > c2) goto Ltd; - else if (!c1 && c2) + else if (c1 < c2) goto Ltd_best; else goto Lambig; @@ -1116,6 +1172,8 @@ void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) for (int i = 0; i < parameters->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + if (hgs->ddoc) + tp = (TemplateParameter *)origParameters->data[i]; if (i) buf->writeByte(','); tp->toCBuffer(buf, hgs); @@ -1516,7 +1574,19 @@ MATCH TypeInstance::deduceType(Scope *sc, */ int i = templateIdentifierLookup(tp->tempinst->name, parameters); if (i == -1) + { /* Didn't find it as a parameter identifier. Try looking + * it up and seeing if is an alias. See Bugzilla 1454 + */ + Dsymbol *s = tempinst->tempdecl->scope->search(0, tp->tempinst->name, NULL); + if (s) + { + s = s->toAlias(); + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (td && td == tempinst->tempdecl) + goto L2; + } goto Lnomatch; + } TemplateParameter *tpx = (TemplateParameter *)parameters->data[i]; // This logic duplicates tpx->matchArg() TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); @@ -1540,12 +1610,14 @@ MATCH TypeInstance::deduceType(Scope *sc, else if (tempinst->tempdecl != tp->tempinst->tempdecl) goto Lnomatch; + L2: if (tempinst->tiargs->dim != tp->tempinst->tiargs->dim) goto Lnomatch; for (int i = 0; i < tempinst->tiargs->dim; i++) { - //printf("test: [%d]\n", i); + //printf("\ttest: tempinst->tiargs[%d]\n", i); + int j; Object *o1 = (Object *)tempinst->tiargs->data[i]; Object *o2 = (Object *)tp->tempinst->tiargs->data[i]; @@ -1570,18 +1642,29 @@ MATCH TypeInstance::deduceType(Scope *sc, else if (e1 && e2) { if (!e1->equals(e2)) + { if (e2->op == TOKvar) + { + /* + * (T:Number!(e2), int e2) + */ + j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); + goto L1; + } goto Lnomatch; + } } else if (e1 && t2 && t2->ty == Tident) - { int i = templateParameterLookup(t2, parameters); - if (i == -1) + { + j = templateParameterLookup(t2, parameters); + L1: + if (j == -1) goto Lnomatch; - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + TemplateParameter *tp = (TemplateParameter *)parameters->data[j]; // BUG: use tp->matchArg() instead of the following TemplateValueParameter *tv = tp->isTemplateValueParameter(); if (!tv) goto Lnomatch; - Expression *e = (Expression *)dedtypes->data[i]; + Expression *e = (Expression *)dedtypes->data[j]; if (e) { if (!e1->equals(e)) @@ -1592,7 +1675,7 @@ MATCH TypeInstance::deduceType(Scope *sc, MATCH m = (MATCH)e1->implicitConvTo(vt); if (!m) goto Lnomatch; - dedtypes->data[i] = e1; + dedtypes->data[j] = e1; } } // BUG: Need to handle alias and tuple parameters @@ -2351,6 +2434,7 @@ Lmatch: return m; Lnomatch: + //printf("\tno match\n"); *psparam = NULL; return MATCHnomatch; } @@ -2780,7 +2864,7 @@ void TemplateInstance::semantic(Scope *sc) if (m->semanticdone >= 3) dosemantic3 = 1; } - for (i = 0; 1; i++) + for (int i = 0; 1; i++) { if (i == a->dim) { @@ -2953,7 +3037,7 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs) Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); - //printf("1: tiargs->data[%d] = %p, %p, %p\n", j, o, isDsymbol(o), isTuple(o)); + //printf("1: tiargs->data[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); if (ta) { //printf("type %s\n", ta->toChars()); @@ -3196,9 +3280,9 @@ TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc) int c2 = td_best->leastAsSpecialized(td); //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 && !c2) + if (c1 > c2) goto Ltd; - else if (!c1 && c2) + else if (c1 < c2) goto Ltd_best; else goto Lambig; @@ -3305,10 +3389,30 @@ int TemplateInstance::isNested(Objects *args) { // if module level template if (tempdecl->toParent()->isModule()) - { - if (isnested && isnested != d->toParent()) - error("inconsistent nesting levels %s and %s", isnested->toChars(), d->toParent()->toChars()); - isnested = d->toParent(); + { Dsymbol *dparent = d->toParent(); + if (!isnested) + isnested = dparent; + else if (isnested != dparent) + { + /* Select the more deeply nested of the two. + * Error if one is not nested inside the other. + */ + for (Dsymbol *p = isnested; p; p = p->parent) + { + if (p == dparent) + goto L1; // isnested is most nested + } + for (Dsymbol *p = dparent; 1; p = p->parent) + { + if (p == isnested) + { isnested = dparent; + goto L1; // dparent is most nested + } + } + error("is nested in both %s and %s", isnested->toChars(), dparent->toChars()); + } + L1: + //printf("\tnested inside %s\n", isnested->toChars()); nested |= 1; } else diff --git a/dmd/template.h b/dmd/template.h index 9051e337..c246e347 100644 --- a/dmd/template.h +++ b/dmd/template.h @@ -1,325 +1,328 @@ - -// 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_TEMPLATE_H -#define DMD_TEMPLATE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "arraytypes.h" -#include "dsymbol.h" -#include "mtype.h" - - -struct OutBuffer; -struct Identifier; -struct TemplateInstance; -struct TemplateParameter; -struct TemplateTypeParameter; -struct TemplateValueParameter; -struct TemplateAliasParameter; -struct TemplateTupleParameter; -struct Type; -struct TypeTypeof; -struct Scope; -struct Expression; -struct AliasDeclaration; -struct FuncDeclaration; -struct HdrGenState; -enum MATCH; - -struct Tuple : Object -{ - Objects objects; - - int dyncast() { return DYNCAST_TUPLE; } // kludge for template.isType() -}; - - -struct TemplateDeclaration : ScopeDsymbol -{ - TemplateParameters *parameters; // array of TemplateParameter's - Array instances; // array of TemplateInstance's - - TemplateDeclaration *overnext; // next overloaded TemplateDeclaration - TemplateDeclaration *overroot; // first in overnext list - - Scope *scope; - Dsymbol *onemember; // if !=NULL then one member of this template - - TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int overloadInsert(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); - char *toChars(); - - void emitComment(Scope *sc); -// void toDocBuffer(OutBuffer *buf); - - MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, int flag); - int leastAsSpecialized(TemplateDeclaration *td2); - - MATCH deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs, Objects *dedargs); - FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expressions *fargs); - void declareParameter(Scope *sc, TemplateParameter *tp, Object *o); - - TemplateDeclaration *isTemplateDeclaration() { return this; } - - TemplateTupleParameter *isVariadic(); - int isOverloadable(); -}; - -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) - */ - - Loc loc; - Identifier *ident; - - Declaration *sparam; - - TemplateParameter(Loc loc, Identifier *ident); - - virtual TemplateTypeParameter *isTemplateTypeParameter(); - virtual TemplateValueParameter *isTemplateValueParameter(); - virtual TemplateAliasParameter *isTemplateAliasParameter(); - 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(Scope *sc) = 0; - - /* If TemplateParameter's match as far as overloading goes. - */ - virtual int overloadMatch(TemplateParameter *) = 0; - - /* Match actual argument against parameter. - */ - virtual MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 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(Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); - void *dummyArg(); -}; - -struct TemplateValueParameter : TemplateParameter -{ - /* Syntax: - * valType ident : specValue = defaultValue - */ - - Type *valType; - Expression *specValue; - Expression *defaultValue; - - static Expression *edummy; - - TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue); - - TemplateValueParameter *isTemplateValueParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); - void *dummyArg(); -}; - -struct TemplateAliasParameter : TemplateParameter -{ - /* Syntax: - * 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(Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); - void *dummyArg(); -}; - -struct TemplateTupleParameter : TemplateParameter -{ - /* Syntax: - * ident ... - */ - - TemplateTupleParameter(Loc loc, Identifier *ident); - - TemplateTupleParameter *isTemplateTupleParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); - void *dummyArg(); -}; - -struct TemplateInstance : ScopeDsymbol -{ - /* Given: - * foo!(args) => - * name = foo - * tiargs = args - */ - Identifier *name; - //Array idents; - Objects *tiargs; // Array of Types/Expressions of template - // instance arguments [int*, char, 10*10] - - Objects tdtypes; // Array of Types/Expressions corresponding - // to TemplateDeclaration.parameters - // [int, char, 100] - - TemplateDeclaration *tempdecl; // referenced by foo.bar.abc - TemplateInstance *inst; // refer to existing instance - ScopeDsymbol *argsym; // argument symbol table - AliasDeclaration *aliasdecl; // !=NULL if instance is an alias for its - // sole member - WithScopeSymbol *withsym; // if a member of a with statement - int semanticdone; // has semantic() been done? - int nest; // for recursion detection - int havetempdecl; // 1 if used second constructor - Dsymbol *isnested; // if referencing local symbols, this is the context - int errors; // 1 if compiled with errors -#ifdef IN_GCC - /* On some targets, it is necessary to know whether a symbol - will be emitted in the output or not before the symbol - is used. This can be different from getModule(). */ - Module * objFileModule; -#endif - - TemplateInstance(Loc loc, Identifier *temp_id); - TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs); - static Objects *arraySyntaxCopy(Objects *objs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Dsymbol *toAlias(); // resolve real symbol - char *kind(); - int oneMember(Dsymbol **ps); - char *toChars(); - char *mangle(); - - void toObjFile(); // compile to .obj file - - // Internal - static void semanticTiargs(Loc loc, Scope *sc, Objects *tiargs); - void semanticTiargs(Scope *sc); - TemplateDeclaration *findTemplateDeclaration(Scope *sc); - TemplateDeclaration *findBestMatch(Scope *sc); - void declareParameters(Scope *sc); - int isNested(Objects *tiargs); - Identifier *genIdent(); - - TemplateInstance *isTemplateInstance() { return this; } - AliasDeclaration *isAliasDeclaration(); -}; - -struct TemplateMixin : TemplateInstance -{ - Array *idents; - Type *tqual; - - Scope *scope; // for forward referencing - - TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Array *idents, Objects *tiargs); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - char *kind(); - int oneMember(Dsymbol **ps); - int hasPointers(); - char *toChars(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toObjFile(); // compile to .obj file - - TemplateMixin *isTemplateMixin() { return this; } -}; - -Expression *isExpression(Object *o); -Dsymbol *isDsymbol(Object *o); -Type *isType(Object *o); -Tuple *isTuple(Object *o); -Type *getType(Object *o); -Dsymbol *getDsymbol(Object *o); - -void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg); - -#endif /* DMD_TEMPLATE_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-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_TEMPLATE_H +#define DMD_TEMPLATE_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "arraytypes.h" +#include "dsymbol.h" +#include "mtype.h" + + +struct OutBuffer; +struct Identifier; +struct TemplateInstance; +struct TemplateParameter; +struct TemplateTypeParameter; +struct TemplateValueParameter; +struct TemplateAliasParameter; +struct TemplateTupleParameter; +struct Type; +struct TypeTypeof; +struct Scope; +struct Expression; +struct AliasDeclaration; +struct FuncDeclaration; +struct HdrGenState; +enum MATCH; + +struct Tuple : Object +{ + Objects objects; + + int dyncast() { return DYNCAST_TUPLE; } // kludge for template.isType() +}; + + +struct TemplateDeclaration : ScopeDsymbol +{ + TemplateParameters *parameters; // array of TemplateParameter's + + TemplateParameters *origParameters; // originals for Ddoc + + Array instances; // array of TemplateInstance's + + TemplateDeclaration *overnext; // next overloaded TemplateDeclaration + TemplateDeclaration *overroot; // first in overnext list + + Scope *scope; + Dsymbol *onemember; // if !=NULL then one member of this template + + TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + int overloadInsert(Dsymbol *s); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + char *kind(); + char *toChars(); + + void emitComment(Scope *sc); +// void toDocBuffer(OutBuffer *buf); + + MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, int flag); + int leastAsSpecialized(TemplateDeclaration *td2); + + MATCH deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs, Objects *dedargs); + FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expressions *fargs); + void declareParameter(Scope *sc, TemplateParameter *tp, Object *o); + + TemplateDeclaration *isTemplateDeclaration() { return this; } + + TemplateTupleParameter *isVariadic(); + int isOverloadable(); +}; + +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) + */ + + Loc loc; + Identifier *ident; + + Declaration *sparam; + + TemplateParameter(Loc loc, Identifier *ident); + + virtual TemplateTypeParameter *isTemplateTypeParameter(); + virtual TemplateValueParameter *isTemplateValueParameter(); + virtual TemplateAliasParameter *isTemplateAliasParameter(); + 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(Scope *sc) = 0; + + /* If TemplateParameter's match as far as overloading goes. + */ + virtual int overloadMatch(TemplateParameter *) = 0; + + /* Match actual argument against parameter. + */ + virtual MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 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(Scope *sc); + int overloadMatch(TemplateParameter *); + MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + void *dummyArg(); +}; + +struct TemplateValueParameter : TemplateParameter +{ + /* Syntax: + * valType ident : specValue = defaultValue + */ + + Type *valType; + Expression *specValue; + Expression *defaultValue; + + static Expression *edummy; + + TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue); + + TemplateValueParameter *isTemplateValueParameter(); + TemplateParameter *syntaxCopy(); + void declareParameter(Scope *sc); + void semantic(Scope *); + void print(Object *oarg, Object *oded); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Object *specialization(); + Object *defaultArg(Scope *sc); + int overloadMatch(TemplateParameter *); + MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + void *dummyArg(); +}; + +struct TemplateAliasParameter : TemplateParameter +{ + /* Syntax: + * 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(Scope *sc); + int overloadMatch(TemplateParameter *); + MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + void *dummyArg(); +}; + +struct TemplateTupleParameter : TemplateParameter +{ + /* Syntax: + * ident ... + */ + + TemplateTupleParameter(Loc loc, Identifier *ident); + + TemplateTupleParameter *isTemplateTupleParameter(); + TemplateParameter *syntaxCopy(); + void declareParameter(Scope *sc); + void semantic(Scope *); + void print(Object *oarg, Object *oded); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Object *specialization(); + Object *defaultArg(Scope *sc); + int overloadMatch(TemplateParameter *); + MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + void *dummyArg(); +}; + +struct TemplateInstance : ScopeDsymbol +{ + /* Given: + * foo!(args) => + * name = foo + * tiargs = args + */ + Identifier *name; + //Array idents; + Objects *tiargs; // Array of Types/Expressions of template + // instance arguments [int*, char, 10*10] + + Objects tdtypes; // Array of Types/Expressions corresponding + // to TemplateDeclaration.parameters + // [int, char, 100] + + TemplateDeclaration *tempdecl; // referenced by foo.bar.abc + TemplateInstance *inst; // refer to existing instance + ScopeDsymbol *argsym; // argument symbol table + AliasDeclaration *aliasdecl; // !=NULL if instance is an alias for its + // sole member + WithScopeSymbol *withsym; // if a member of a with statement + int semanticdone; // has semantic() been done? + int nest; // for recursion detection + int havetempdecl; // 1 if used second constructor + Dsymbol *isnested; // if referencing local symbols, this is the context + int errors; // 1 if compiled with errors +#ifdef IN_GCC + /* On some targets, it is necessary to know whether a symbol + will be emitted in the output or not before the symbol + is used. This can be different from getModule(). */ + Module * objFileModule; +#endif + + TemplateInstance(Loc loc, Identifier *temp_id); + TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs); + static Objects *arraySyntaxCopy(Objects *objs); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + void inlineScan(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Dsymbol *toAlias(); // resolve real symbol + char *kind(); + int oneMember(Dsymbol **ps); + char *toChars(); + char *mangle(); + + void toObjFile(); // compile to .obj file + + // Internal + static void semanticTiargs(Loc loc, Scope *sc, Objects *tiargs); + void semanticTiargs(Scope *sc); + TemplateDeclaration *findTemplateDeclaration(Scope *sc); + TemplateDeclaration *findBestMatch(Scope *sc); + void declareParameters(Scope *sc); + int isNested(Objects *tiargs); + Identifier *genIdent(); + + TemplateInstance *isTemplateInstance() { return this; } + AliasDeclaration *isAliasDeclaration(); +}; + +struct TemplateMixin : TemplateInstance +{ + Array *idents; + Type *tqual; + + Scope *scope; // for forward referencing + + TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Array *idents, Objects *tiargs); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + void inlineScan(); + char *kind(); + int oneMember(Dsymbol **ps); + int hasPointers(); + char *toChars(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toObjFile(); // compile to .obj file + + TemplateMixin *isTemplateMixin() { return this; } +}; + +Expression *isExpression(Object *o); +Dsymbol *isDsymbol(Object *o); +Type *isType(Object *o); +Tuple *isTuple(Object *o); +Type *getType(Object *o); +Dsymbol *getDsymbol(Object *o); + +void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg); + +#endif /* DMD_TEMPLATE_H */