From 10e72760580eafa54924a7a0a00aff4ebdf7e970 Mon Sep 17 00:00:00 2001 From: kai Date: Mon, 4 Mar 2013 18:45:14 +0100 Subject: [PATCH 1/6] Simple part of removing D1 --- .travis.yml | 1 - CMakeLists.txt | 7 +- dmd/access.c | 418 -- dmd/aggregate.h | 373 -- dmd/apply.c | 165 - dmd/argtypes.c | 441 -- dmd/arrayop.c | 660 --- dmd/arraytypes.h | 74 - dmd/artistic.txt | 117 - dmd/attrib.c | 1563 ------ dmd/attrib.h | 204 - dmd/cast.c | 1676 ------ dmd/class.c | 1595 ------ dmd/clone.c | 175 - dmd/complex_t.h | 76 - dmd/cond.c | 430 -- dmd/cond.h | 106 - dmd/constfold.c | 1787 ------- dmd/declaration.c | 1880 ------- dmd/declaration.h | 1088 ---- dmd/delegatize.c | 140 - dmd/doc.c | 2230 -------- dmd/doc.h | 20 - dmd/dsymbol.c | 1314 ----- dmd/dsymbol.h | 387 -- dmd/dump.c | 144 - dmd/entity.c | 2391 --------- dmd/enum.c | 373 -- dmd/enum.h | 96 - dmd/expression.c | 10664 --------------------------------------- dmd/expression.h | 2063 -------- dmd/func.c | 3653 -------------- dmd/gpl.txt | 248 - dmd/hdrgen.c | 100 - dmd/hdrgen.h | 35 - dmd/html.c | 757 --- dmd/html.h | 42 - dmd/identifier.c | 101 - dmd/identifier.h | 46 - dmd/idgen.c | 378 -- dmd/impcnvgen.c | 457 -- dmd/imphint.c | 84 - dmd/import.c | 411 -- dmd/import.h | 63 - dmd/init.c | 845 ---- dmd/init.h | 149 - dmd/inline.c | 1825 ------- dmd/interpret.c | 7083 -------------------------- dmd/json.c | 462 -- dmd/json.h | 24 - dmd/lexer.c | 3227 ------------ dmd/lexer.h | 321 -- dmd/macro.c | 449 -- dmd/macro.h | 45 - dmd/mangle.c | 300 -- dmd/mars.c | 396 -- dmd/mars.h | 528 -- dmd/mem.c | 269 - dmd/mem.h | 51 - dmd/module.c | 1257 ----- dmd/module.h | 225 - dmd/mtype.c | 6089 ---------------------- dmd/mtype.h | 861 ---- dmd/opover.c | 787 --- dmd/optimize.c | 896 ---- dmd/parse.c | 5689 --------------------- dmd/parse.h | 172 - dmd/readme.txt | 27 - dmd/rmem.h | 16 - dmd/root/aav.c | 188 - dmd/root/aav.h | 11 - dmd/root/array.c | 256 - dmd/root/async.c | 325 -- dmd/root/async.h | 33 - dmd/root/gnuc.c | 55 - dmd/root/gnuc.h | 8 - dmd/root/longdouble.c | 636 --- dmd/root/longdouble.h | 254 - dmd/root/man.c | 100 - dmd/root/port.c | 663 --- dmd/root/port.h | 83 - dmd/root/root.c | 1992 -------- dmd/root/root.h | 422 -- dmd/root/stringtable.c | 189 - dmd/root/stringtable.h | 71 - dmd/scope.c | 400 -- dmd/scope.h | 130 - dmd/sideeffect.c | 34 - dmd/speller.c | 262 - dmd/speller.h | 7 - dmd/statement.c | 4665 ----------------- dmd/statement.h | 943 ---- dmd/staticassert.c | 126 - dmd/staticassert.h | 41 - dmd/struct.c | 683 --- dmd/template.c | 5601 -------------------- dmd/template.h | 388 -- dmd/unialpha.c | 323 -- dmd/utf.c | 320 -- dmd/utf.h | 35 - dmd/version.c | 181 - dmd/version.h | 51 - ldc-posix-tango | 78 - 103 files changed, 2 insertions(+), 90578 deletions(-) delete mode 100644 dmd/access.c delete mode 100644 dmd/aggregate.h delete mode 100644 dmd/apply.c delete mode 100644 dmd/argtypes.c delete mode 100644 dmd/arrayop.c delete mode 100644 dmd/arraytypes.h delete mode 100644 dmd/artistic.txt delete mode 100644 dmd/attrib.c delete mode 100644 dmd/attrib.h delete mode 100644 dmd/cast.c delete mode 100644 dmd/class.c delete mode 100644 dmd/clone.c delete mode 100644 dmd/complex_t.h delete mode 100644 dmd/cond.c delete mode 100644 dmd/cond.h delete mode 100644 dmd/constfold.c delete mode 100644 dmd/declaration.c delete mode 100644 dmd/declaration.h delete mode 100644 dmd/delegatize.c delete mode 100644 dmd/doc.c delete mode 100644 dmd/doc.h delete mode 100644 dmd/dsymbol.c delete mode 100644 dmd/dsymbol.h delete mode 100644 dmd/dump.c delete mode 100644 dmd/entity.c delete mode 100644 dmd/enum.c delete mode 100644 dmd/enum.h delete mode 100644 dmd/expression.c delete mode 100644 dmd/expression.h delete mode 100644 dmd/func.c delete mode 100644 dmd/gpl.txt delete mode 100644 dmd/hdrgen.c delete mode 100644 dmd/hdrgen.h delete mode 100644 dmd/html.c delete mode 100644 dmd/html.h delete mode 100644 dmd/identifier.c delete mode 100644 dmd/identifier.h delete mode 100644 dmd/idgen.c delete mode 100644 dmd/impcnvgen.c delete mode 100644 dmd/imphint.c delete mode 100644 dmd/import.c delete mode 100644 dmd/import.h delete mode 100644 dmd/init.c delete mode 100644 dmd/init.h delete mode 100644 dmd/inline.c delete mode 100644 dmd/interpret.c delete mode 100644 dmd/json.c delete mode 100644 dmd/json.h delete mode 100644 dmd/lexer.c delete mode 100644 dmd/lexer.h delete mode 100644 dmd/macro.c delete mode 100644 dmd/macro.h delete mode 100644 dmd/mangle.c delete mode 100644 dmd/mars.c delete mode 100644 dmd/mars.h delete mode 100644 dmd/mem.c delete mode 100644 dmd/mem.h delete mode 100644 dmd/module.c delete mode 100644 dmd/module.h delete mode 100644 dmd/mtype.c delete mode 100644 dmd/mtype.h delete mode 100644 dmd/opover.c delete mode 100644 dmd/optimize.c delete mode 100644 dmd/parse.c delete mode 100644 dmd/parse.h delete mode 100644 dmd/readme.txt delete mode 100644 dmd/rmem.h delete mode 100644 dmd/root/aav.c delete mode 100644 dmd/root/aav.h delete mode 100644 dmd/root/array.c delete mode 100644 dmd/root/async.c delete mode 100644 dmd/root/async.h delete mode 100644 dmd/root/gnuc.c delete mode 100644 dmd/root/gnuc.h delete mode 100644 dmd/root/longdouble.c delete mode 100644 dmd/root/longdouble.h delete mode 100644 dmd/root/man.c delete mode 100644 dmd/root/port.c delete mode 100644 dmd/root/port.h delete mode 100644 dmd/root/root.c delete mode 100644 dmd/root/root.h delete mode 100644 dmd/root/stringtable.c delete mode 100644 dmd/root/stringtable.h delete mode 100644 dmd/scope.c delete mode 100644 dmd/scope.h delete mode 100644 dmd/sideeffect.c delete mode 100644 dmd/speller.c delete mode 100644 dmd/speller.h delete mode 100644 dmd/statement.c delete mode 100644 dmd/statement.h delete mode 100644 dmd/staticassert.c delete mode 100644 dmd/staticassert.h delete mode 100644 dmd/struct.c delete mode 100644 dmd/template.c delete mode 100644 dmd/template.h delete mode 100644 dmd/unialpha.c delete mode 100644 dmd/utf.c delete mode 100644 dmd/utf.h delete mode 100644 dmd/version.c delete mode 100644 dmd/version.h delete mode 100644 ldc-posix-tango diff --git a/.travis.yml b/.travis.yml index e32e9dbf..b1bcc67d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ install: - sudo apt-get update -qq - sudo apt-get install -qq $LLVM_PACKAGE libconfig++8-dev env: - - DVER=1 LLVM_PACKAGE=llvm-3.1 LLVM_VERSION=3.1 - DVER=2 LLVM_PACKAGE=llvm-3.0-dev LLVM_VERSION=3.0 TESTSUITE_FILTER=debug - DVER=2 LLVM_PACKAGE=llvm-3.0-dev LLVM_VERSION=3.0 TESTSUITE_FILTER=release - DVER=2 LLVM_PACKAGE=llvm-3.1 LLVM_VERSION=3.1 TESTSUITE_FILTER=debug diff --git a/CMakeLists.txt b/CMakeLists.txt index afb801e4..03b9cf64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,11 +50,8 @@ option(USE_METADATA "use metadata and related custom optimization passes" ON) mark_as_advanced(USE_BOEHM_GC GENERATE_OFFTI USE_METADATA) if(D_VERSION EQUAL 1) - set(DMDFE_PATH dmd) - set(LDC_EXE ldc) - set(LDMD_EXE ldmd) - set(RUNTIME runtime) - add_definitions(-DDMDV1) + message(FATAL_ERROR "D version 1 is no longer supported. +Please consider using D version 2 or checkout the 'd1' git branch for the last version supporting D version 1.") elseif(D_VERSION EQUAL 2) set(DMDFE_PATH dmd2) set(LDC_EXE ldc2) diff --git a/dmd/access.c b/dmd/access.c deleted file mode 100644 index fae07af9..00000000 --- a/dmd/access.c +++ /dev/null @@ -1,418 +0,0 @@ - -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#include -#include -#include - -#include "root.h" -#include "rmem.h" - -#include "enum.h" -#include "aggregate.h" -#include "init.h" -#include "attrib.h" -#include "scope.h" -#include "id.h" -#include "mtype.h" -#include "declaration.h" -#include "aggregate.h" -#include "expression.h" -#include "module.h" - -#define LOG 0 - -/* Code to do access checks - */ - -int hasPackageAccess(Scope *sc, Dsymbol *s); - -/**************************************** - * Return PROT access for Dsymbol smember in this declaration. - */ - -enum PROT AggregateDeclaration::getAccess(Dsymbol *smember) -{ - return PROTpublic; -} - -enum PROT StructDeclaration::getAccess(Dsymbol *smember) -{ - enum PROT access_ret = PROTnone; - -#if LOG - printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n", - toChars(), smember->toChars()); -#endif - if (smember->toParent() == this) - { - access_ret = smember->prot(); - } - else if (smember->isDeclaration()->isStatic()) - { - access_ret = smember->prot(); - } - return access_ret; -} - -enum PROT ClassDeclaration::getAccess(Dsymbol *smember) -{ - enum PROT access_ret = PROTnone; - -#if LOG - printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n", - toChars(), smember->toChars()); -#endif - if (smember->toParent() == this) - { - access_ret = smember->prot(); - } - else - { - if (smember->isDeclaration()->isStatic()) - { - access_ret = smember->prot(); - } - - for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *b = (*baseclasses)[i]; - - enum PROT access = b->base->getAccess(smember); - switch (access) - { - case PROTnone: - break; - - case PROTprivate: - access_ret = PROTnone; // private members of base class not accessible - break; - - case PROTpackage: - case PROTprotected: - case PROTpublic: - case PROTexport: - // If access is to be tightened - if (b->protection < access) - access = b->protection; - - // Pick path with loosest access - if (access > access_ret) - access_ret = access; - break; - - default: - assert(0); - } - } - } -#if LOG - printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n", - toChars(), smember->toChars(), access_ret); -#endif - return access_ret; -} - -/******************************************************** - * Helper function for ClassDeclaration::accessCheck() - * Returns: - * 0 no access - * 1 access - */ - -static int accessCheckX( - Dsymbol *smember, - Dsymbol *sfunc, - AggregateDeclaration *dthis, - AggregateDeclaration *cdscope) -{ - assert(dthis); - -#if 0 - printf("accessCheckX for %s.%s in function %s() in scope %s\n", - dthis->toChars(), smember->toChars(), - sfunc ? sfunc->toChars() : "NULL", - cdscope ? cdscope->toChars() : "NULL"); -#endif - if (dthis->hasPrivateAccess(sfunc) || - dthis->isFriendOf(cdscope)) - { - if (smember->toParent() == dthis) - return 1; - else - { - ClassDeclaration *cdthis = dthis->isClassDeclaration(); - if (cdthis) - { - for (size_t i = 0; i < cdthis->baseclasses->dim; i++) - { BaseClass *b = (*cdthis->baseclasses)[i]; - enum PROT access = b->base->getAccess(smember); - if (access >= PROTprotected || - accessCheckX(smember, sfunc, b->base, cdscope) - ) - return 1; - - } - } - } - } - else - { - if (smember->toParent() != dthis) - { - ClassDeclaration *cdthis = dthis->isClassDeclaration(); - if (cdthis) - { - for (size_t i = 0; i < cdthis->baseclasses->dim; i++) - { BaseClass *b = (*cdthis->baseclasses)[i]; - - if (accessCheckX(smember, sfunc, b->base, cdscope)) - return 1; - } - } - } - } - return 0; -} - -/******************************* - * Do access check for member of this class, this class being the - * type of the 'this' pointer used to access smember. - */ - -void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember) -{ - int result; - - FuncDeclaration *f = sc->func; - AggregateDeclaration *cdscope = sc->getStructClassScope(); - enum PROT access; - -#if LOG - printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n", - toChars(), smember->toChars(), - f ? f->toChars() : NULL, - cdscope ? cdscope->toChars() : NULL); -#endif - - Dsymbol *smemberparent = smember->toParent(); - if (!smemberparent || !smemberparent->isAggregateDeclaration()) - { -#if LOG - printf("not an aggregate member\n"); -#endif - return; // then it is accessible - } - - // BUG: should enable this check - //assert(smember->parent->isBaseOf(this, NULL)); - - if (smemberparent == this) - { enum PROT access2 = smember->prot(); - - result = access2 >= PROTpublic || - hasPrivateAccess(f) || - isFriendOf(cdscope) || - (access2 == PROTpackage && hasPackageAccess(sc, this)); -#if LOG - printf("result1 = %d\n", result); -#endif - } - else if ((access = this->getAccess(smember)) >= PROTpublic) - { - result = 1; -#if LOG - printf("result2 = %d\n", result); -#endif - } - else if (access == PROTpackage && hasPackageAccess(sc, this)) - { - result = 1; -#if LOG - printf("result3 = %d\n", result); -#endif - } - else - { - result = accessCheckX(smember, f, this, cdscope); -#if LOG - printf("result4 = %d\n", result); -#endif - } - if (!result) - { - error(loc, "member %s is not accessible", smember->toChars()); - } -} - -/**************************************** - * Determine if this is the same or friend of cd. - */ - -int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd) -{ -#if LOG - printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null"); -#endif - if (this == cd) - return 1; - - // Friends if both are in the same module - //if (toParent() == cd->toParent()) - if (cd && getModule() == cd->getModule()) - { -#if LOG - printf("\tin same module\n"); -#endif - return 1; - } - -#if LOG - printf("\tnot friend\n"); -#endif - return 0; -} - -/**************************************** - * Determine if scope sc has package level access to s. - */ - -int hasPackageAccess(Scope *sc, Dsymbol *s) -{ -#if LOG - printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc); -#endif - - for (; s; s = s->parent) - { - if (s->isPackage() && !s->isModule()) - break; - } -#if LOG - if (s) - printf("\tthis is in package '%s'\n", s->toChars()); -#endif - - if (s && s == sc->module->parent) - { -#if LOG - printf("\ts is in same package as sc\n"); -#endif - return 1; - } - - -#if LOG - printf("\tno package access\n"); -#endif - return 0; -} - -/********************************** - * Determine if smember has access to private members of this declaration. - */ - -int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember) -{ - if (smember) - { AggregateDeclaration *cd = NULL; - Dsymbol *smemberparent = smember->toParent(); - if (smemberparent) - cd = smemberparent->isAggregateDeclaration(); - -#if LOG - printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n", - toChars(), smember->toChars()); -#endif - - if (this == cd) // smember is a member of this class - { -#if LOG - printf("\tyes 1\n"); -#endif - return 1; // so we get private access - } - - // If both are members of the same module, grant access - while (1) - { Dsymbol *sp = smember->toParent(); - if (sp->isFuncDeclaration() && smember->isFuncDeclaration()) - smember = sp; - else - break; - } - if (!cd && toParent() == smember->toParent()) - { -#if LOG - printf("\tyes 2\n"); -#endif - return 1; - } - if (!cd && getModule() == smember->getModule()) - { -#if LOG - printf("\tyes 3\n"); -#endif - return 1; - } - } -#if LOG - printf("\tno\n"); -#endif - return 0; -} - -/**************************************** - * Check access to d for expression e.d - */ - -void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d) -{ -#if LOG - if (e) - { printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars()); - printf("\te->type = %s\n", e->type->toChars()); - } - else - { - //printf("accessCheck(%s)\n", d->toChars()); - } -#endif - if (!e) - { - if (d->prot() == PROTprivate && d->getModule() != sc->module || - d->prot() == PROTpackage && !hasPackageAccess(sc, d)) - - error(loc, "%s %s.%s is not accessible from %s", - d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars()); - } - else if (e->type->ty == Tclass) - { // Do access check - ClassDeclaration *cd; - - cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym); -#if 1 - if (e->op == TOKsuper) - { ClassDeclaration *cd2; - - cd2 = sc->func->toParent()->isClassDeclaration(); - if (cd2) - cd = cd2; - } -#endif - cd->accessCheck(loc, sc, d); - } - else if (e->type->ty == Tstruct) - { // Do access check - StructDeclaration *cd; - - cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym); - cd->accessCheck(loc, sc, d); - } -} diff --git a/dmd/aggregate.h b/dmd/aggregate.h deleted file mode 100644 index 3ba0306a..00000000 --- a/dmd/aggregate.h +++ /dev/null @@ -1,373 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_AGGREGATE_H -#define DMD_AGGREGATE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" - -#include "dsymbol.h" - -#if IN_LLVM -#include -#include -#include -#endif - -struct Identifier; -struct Type; -struct TypeFunction; -struct Expression; -struct FuncDeclaration; -struct CtorDeclaration; -struct DtorDeclaration; -struct InvariantDeclaration; -struct NewDeclaration; -struct DeleteDeclaration; -struct InterfaceDeclaration; -struct ClassInfoDeclaration; -struct VarDeclaration; -struct dt_t; - -#if IN_LLVM -namespace llvm -{ - class Type; - class Value; - class Constant; - class ConstantStruct; - class GlobalVariable; -} -#endif - -enum Sizeok -{ - SIZEOKnone, // size of aggregate is not computed yet - SIZEOKdone, // size of aggregate is set correctly - SIZEOKfwd, // error in computing size of aggregate -}; - -struct AggregateDeclaration : ScopeDsymbol -{ - Type *type; - StorageClass storage_class; - enum PROT protection; - Type *handle; // 'this' type - unsigned structsize; // size of struct - unsigned alignsize; // size of struct for alignment purposes - structalign_t structalign; // struct member alignment in effect - int hasUnions; // set if aggregate has overlapping fields - VarDeclarations fields; // VarDeclaration fields - enum Sizeok sizeok; // set when structsize contains valid data - int isdeprecated; // !=0 if deprecated - -#if DMDV2 - int isnested; // !=0 if is nested - VarDeclaration *vthis; // 'this' parameter if this aggregate is nested -#endif - // Special member functions - InvariantDeclaration *inv; // invariant - NewDeclaration *aggNew; // allocator - DeleteDeclaration *aggDelete; // deallocator - -#if DMDV2 - //CtorDeclaration *ctor; - Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration - CtorDeclaration *defaultCtor; // default constructor - Dsymbol *aliasthis; // forward unresolved lookups to aliasthis - bool noDefaultCtor; // no default construction -#endif - - FuncDeclarations dtors; // Array of destructors - FuncDeclaration *dtor; // aggregate destructor - -#ifdef IN_GCC - Expressions *attributes; // GCC decl/type attributes - FuncDeclarations methods; // flat list of all methods for debug information -#endif - - AggregateDeclaration(Loc loc, Identifier *id); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - unsigned size(Loc loc); - static void alignmember(structalign_t salign, unsigned size, unsigned *poffset); - static unsigned placeField(unsigned *nextoffset, - unsigned memsize, unsigned memalignsize, structalign_t memalign, - unsigned *paggsize, unsigned *paggalignsize, bool isunion); - Type *getType(); - int firstFieldInUnion(int indx); // first field in union that includes indx - int numFieldsInUnion(int firstIndex); // #fields in union starting at index - int isDeprecated(); // is aggregate deprecated? - FuncDeclaration *buildDtor(Scope *sc); - int isNested(); - int isExport(); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toDocBuffer(OutBuffer *buf); - - // For access checking - virtual PROT getAccess(Dsymbol *smember); // determine access to smember - int isFriendOf(AggregateDeclaration *cd); - int hasPrivateAccess(Dsymbol *smember); // does smember have private access to members of this class? - void accessCheck(Loc loc, Scope *sc, Dsymbol *smember); - - enum PROT prot(); - -#if IN_DMD - // Back end - Symbol *stag; // tag symbol for debug data - Symbol *sinit; - Symbol *toInitializer(); -#endif - - AggregateDeclaration *isAggregateDeclaration() { return this; } - -#if IN_LLVM - // Aggregates that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. - bool availableExternally; -#endif -}; - -struct AnonymousAggregateDeclaration : AggregateDeclaration -{ - AnonymousAggregateDeclaration() - : AggregateDeclaration(0, NULL) - { - } - - AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; } -}; - -struct StructDeclaration : AggregateDeclaration -{ - int zeroInit; // !=0 if initialize with 0 fill -#if DMDV2 - int hasIdentityAssign; // !=0 if has identity opAssign - int hasIdentityEquals; // !=0 if has identity opEquals - FuncDeclaration *cpctor; // generated copy-constructor, if any - FuncDeclarations postblits; // Array of postblit functions - FuncDeclaration *postblit; // aggregate postblit - - FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals - static FuncDeclaration *xerreq; // object.xopEquals -#endif - - // For 64 bit Efl function call/return ABI - Type *arg1type; - Type *arg2type; - - StructDeclaration(Loc loc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - Dsymbol *search(Loc, Identifier *ident, int flags); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *mangle(); - const char *kind(); - void finalizeSize(Scope *sc); - bool isPOD(); -#if DMDV1 - Expression *cloneMembers(); -#endif -#if DMDV2 - int needOpAssign(); - int needOpEquals(); - FuncDeclaration *buildOpAssign(Scope *sc); - FuncDeclaration *buildOpEquals(Scope *sc); - FuncDeclaration *buildPostBlit(Scope *sc); - FuncDeclaration *buildCpCtor(Scope *sc); - - FuncDeclaration *buildXopEquals(Scope *sc); -#endif - void toDocBuffer(OutBuffer *buf); - - PROT getAccess(Dsymbol *smember); // determine access to smember - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - void toDt(dt_t **pdt); - void toDebug(); // to symbolic debug info -#endif - - StructDeclaration *isStructDeclaration() { return this; } - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -struct UnionDeclaration : StructDeclaration -{ - UnionDeclaration(Loc loc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - const char *kind(); - - UnionDeclaration *isUnionDeclaration() { return this; } -}; - -// warning: two classes with the same base class share the same -// BaseClass instance. -struct BaseClass -{ - Type *type; // (before semantic processing) - enum PROT protection; // protection for the base interface - - ClassDeclaration *base; - int offset; // 'this' pointer offset - FuncDeclarations vtbl; // for interfaces: Array of FuncDeclaration's - // making up the vtbl[] - - size_t baseInterfaces_dim; - BaseClass *baseInterfaces; // if BaseClass is an interface, these - // are a copy of the InterfaceDeclaration::interfaces - - BaseClass(); - BaseClass(Type *type, enum PROT protection); - - int fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance); - void copyBaseInterfaces(BaseClasses *); -}; - -#if DMDV2 -#define CLASSINFO_SIZE_64 0x98 // value of ClassInfo.size -#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size -#else -#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size -#define CLASSINFO_SIZE_64 (0x98) // value of ClassInfo.size -#endif - -struct ClassDeclaration : AggregateDeclaration -{ - static ClassDeclaration *object; - static ClassDeclaration *classinfo; - static ClassDeclaration *errorException; - - ClassDeclaration *baseClass; // NULL only if this is Object -#if DMDV1 - CtorDeclaration *ctor; - CtorDeclaration *defaultCtor; // default constructor -#endif - FuncDeclaration *staticCtor; - FuncDeclaration *staticDtor; - Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[] - Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[] - - BaseClasses *baseclasses; // Array of BaseClass's; first is super, - // rest are Interface's - - size_t interfaces_dim; - BaseClass **interfaces; // interfaces[interfaces_dim] for this class - // (does not include baseClass) - - BaseClasses *vtblInterfaces; // array of base interfaces that have - // their own vtbl[] - - ClassInfoDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration - int com; // !=0 if this is a COM class (meaning - // it derives from IUnknown) - int isscope; // !=0 if this is an auto class - int isabstract; // !=0 if abstract class -#if DMDV1 - int isnested; // !=0 if is nested - VarDeclaration *vthis; // 'this' parameter if this class is nested -#endif - int inuse; // to prevent recursive attempts - - ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isBaseOf2(ClassDeclaration *cd); - - #define OFFSET_RUNTIME 0x76543210 - virtual int isBaseOf(ClassDeclaration *cd, int *poffset); - - virtual int isBaseInfoComplete(); - Dsymbol *search(Loc, Identifier *ident, int flags); - Dsymbol *searchBase(Loc, Identifier *ident); -#if DMDV2 - int isFuncHidden(FuncDeclaration *fd); -#endif - FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); - void interfaceSemantic(Scope *sc); -#if DMDV1 - int isNested(); -#endif - int isCOMclass(); - virtual int isCOMinterface(); -#if DMDV2 - virtual int isCPPinterface(); -#endif - int isAbstract(); - virtual int vtblOffset(); - const char *kind(); - char *mangle(); - void toDocBuffer(OutBuffer *buf); - - PROT getAccess(Dsymbol *smember); // determine access to smember - - void addLocalClass(ClassDeclarations *); - -#if IN_DMD - // Back end - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - unsigned baseVtblOffset(BaseClass *bc); - Symbol *toSymbol(); - Symbol *toVtblSymbol(); - void toDt(dt_t **pdt); - void toDt2(dt_t **pdt, ClassDeclaration *cd); - - Symbol *vtblsym; -#endif - - ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } - -#if IN_LLVM - virtual void codegen(Ir*); -#endif -}; - -struct InterfaceDeclaration : ClassDeclaration -{ -#if DMDV2 - int cpp; // !=0 if this is a C++ interface -#endif - InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - int isBaseOf(ClassDeclaration *cd, int *poffset); - int isBaseOf(BaseClass *bc, int *poffset); - const char *kind(); - int isBaseInfoComplete(); - int vtblOffset(); -#if DMDV2 - int isCPPinterface(); -#endif - virtual int isCOMinterface(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - Symbol *toSymbol(); -#endif - - InterfaceDeclaration *isInterfaceDeclaration() { return this; } - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -#endif /* DMD_AGGREGATE_H */ diff --git a/dmd/apply.c b/dmd/apply.c deleted file mode 100644 index f5a5ede8..00000000 --- a/dmd/apply.c +++ /dev/null @@ -1,165 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "expression.h" - - -/************************************** - * An Expression tree walker that will visit each Expression e in the tree, - * in depth-first evaluation order, and call fp(e,param) on it. - * fp() signals whether the walking continues with its return value: - * Returns: - * 0 continue - * 1 done - * It's a bit slower than using virtual functions, but more encapsulated and less brittle. - * Creating an iterator for this would be much more complex. - */ - -typedef int (*fp_t)(Expression *, void *); - -int Expression::apply(fp_t fp, void *param) -{ - return (*fp)(this, param); -} - -/****************************** - * Perform apply() on an array of Expressions. - */ - -int arrayExpressionApply(Expressions *a, fp_t fp, void *param) -{ - //printf("arrayExpressionApply(%p)\n", a); - if (a) - { - for (size_t i = 0; i < a->dim; i++) - { Expression *e = (*a)[i]; - - if (e) - { - if (e->apply(fp, param)) - return 1; - } - } - } - return 0; -} - -int NewExp::apply(int (*fp)(Expression *, void *), void *param) -{ - //printf("NewExp::apply(): %s\n", toChars()); - - return ((thisexp ? thisexp->apply(fp, param) : 0) || - arrayExpressionApply(newargs, fp, param) || - arrayExpressionApply(arguments, fp, param) || - (*fp)(this, param)); -} - -int NewAnonClassExp::apply(int (*fp)(Expression *, void *), void *param) -{ - //printf("NewAnonClassExp::apply(): %s\n", toChars()); - - return ((thisexp ? thisexp->apply(fp, param) : 0) || - arrayExpressionApply(newargs, fp, param) || - arrayExpressionApply(arguments, fp, param) || - (*fp)(this, param)); -} - -int UnaExp::apply(fp_t fp, void *param) -{ - return e1->apply(fp, param) || - (*fp)(this, param); -} - -int BinExp::apply(fp_t fp, void *param) -{ - return e1->apply(fp, param) || - e2->apply(fp, param) || - (*fp)(this, param); -} - -int AssertExp::apply(fp_t fp, void *param) -{ - //printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars()); - return e1->apply(fp, param) || - (msg ? msg->apply(fp, param) : 0) || - (*fp)(this, param); -} - - -int CallExp::apply(fp_t fp, void *param) -{ - //printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars()); - return e1->apply(fp, param) || - arrayExpressionApply(arguments, fp, param) || - (*fp)(this, param); -} - - -int ArrayExp::apply(fp_t fp, void *param) -{ - //printf("ArrayExp::apply(fp_t fp, void *param): %s\n", toChars()); - return e1->apply(fp, param) || - arrayExpressionApply(arguments, fp, param) || - (*fp)(this, param); -} - - -int SliceExp::apply(fp_t fp, void *param) -{ - return e1->apply(fp, param) || - (lwr ? lwr->apply(fp, param) : 0) || - (upr ? upr->apply(fp, param) : 0) || - (*fp)(this, param); -} - - -int ArrayLiteralExp::apply(fp_t fp, void *param) -{ - return arrayExpressionApply(elements, fp, param) || - (*fp)(this, param); -} - - -int AssocArrayLiteralExp::apply(fp_t fp, void *param) -{ - return arrayExpressionApply(keys, fp, param) || - arrayExpressionApply(values, fp, param) || - (*fp)(this, param); -} - - -int StructLiteralExp::apply(fp_t fp, void *param) -{ - return arrayExpressionApply(elements, fp, param) || - (*fp)(this, param); -} - - -int TupleExp::apply(fp_t fp, void *param) -{ - return arrayExpressionApply(exps, fp, param) || - (*fp)(this, param); -} - - -int CondExp::apply(fp_t fp, void *param) -{ - return econd->apply(fp, param) || - e1->apply(fp, param) || - e2->apply(fp, param) || - (*fp)(this, param); -} - - - diff --git a/dmd/argtypes.c b/dmd/argtypes.c deleted file mode 100644 index 1021b390..00000000 --- a/dmd/argtypes.c +++ /dev/null @@ -1,441 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2010-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// http://www.dsource.org/projects/dmd/browser/branches/dmd-1.x/src/argtypes.c -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "dsymbol.h" -#include "mtype.h" -#include "scope.h" -#include "init.h" -#include "expression.h" -#include "attrib.h" -#include "declaration.h" -#include "template.h" -#include "id.h" -#include "enum.h" -#include "import.h" -#include "aggregate.h" -#include "hdrgen.h" - -#define tfloat2 tfloat64 -//#define tfloat2 tcomplex32 - -/**************************************************** - * This breaks a type down into 'simpler' types that can be passed to a function - * in registers, and returned in registers. - * It's highly platform dependent. - * Returning a tuple of zero length means the type cannot be passed/returned in registers. - */ - - -TypeTuple *Type::toArgTypes() -{ - return NULL; // not valid for a parameter -} - -TypeTuple *TypeError::toArgTypes() -{ - return new TypeTuple(Type::terror); -} - -TypeTuple *TypeBasic::toArgTypes() -{ Type *t1 = NULL; - Type *t2 = NULL; - switch (ty) - { - case Tvoid: - return NULL; - - case Tbool: - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: - case Tint32: - case Tuns32: - case Tfloat32: - case Tint64: - case Tuns64: - case Tfloat64: - case Tfloat80: - t1 = this; - break; - - case Timaginary32: - t1 = Type::tfloat32; - break; - - case Timaginary64: - t1 = Type::tfloat64; - break; - - case Timaginary80: - t1 = Type::tfloat80; - break; - - case Tcomplex32: - if (global.params.is64bit) - t1 = Type::tfloat2; - else - { - t1 = Type::tfloat64; - t2 = Type::tfloat64; - } - break; - - case Tcomplex64: - t1 = Type::tfloat64; - t2 = Type::tfloat64; - break; - - case Tcomplex80: - t1 = Type::tfloat80; - t2 = Type::tfloat80; - break; - - case Tascii: - t1 = Type::tuns8; - break; - - case Twchar: - t1 = Type::tuns16; - break; - - case Tdchar: - t1 = Type::tuns32; - break; - - default: assert(0); - } - - TypeTuple *t; - if (t1) - { - if (t2) - t = new TypeTuple(t1, t2); - else - t = new TypeTuple(t1); - } - else - t = new TypeTuple(); - return t; -} - -#if DMDV2 -TypeTuple *TypeVector::toArgTypes() -{ - return new TypeTuple(this); -} -#endif - -TypeTuple *TypeSArray::toArgTypes() -{ -#if DMDV2 - if (dim) - { - /* Should really be done as if it were a struct with dim members - * of the array's elements. - * I.e. int[2] should be done like struct S { int a; int b; } - */ - dinteger_t sz = dim->toInteger(); - if (sz == 1) - // T[1] should be passed like T - return next->toArgTypes(); - } - return new TypeTuple(); // pass on the stack for efficiency -#else - return new TypeTuple(); // pass on the stack for efficiency -#endif -} - -TypeTuple *TypeDArray::toArgTypes() -{ - /* Should be done as if it were: - * struct S { size_t length; void* ptr; } - */ - return new TypeTuple(Type::tsize_t, Type::tvoidptr); -} - -TypeTuple *TypeAArray::toArgTypes() -{ - return new TypeTuple(Type::tvoidptr); -} - -TypeTuple *TypePointer::toArgTypes() -{ - return new TypeTuple(Type::tvoidptr); -} - -TypeTuple *TypeDelegate::toArgTypes() -{ - /* Should be done as if it were: - * struct S { void* ptr; void* funcptr; } - */ - return new TypeTuple(Type::tvoidptr, Type::tvoidptr); -} - -/************************************* - * Convert a floating point type into the equivalent integral type. - */ - -Type *mergeFloatToInt(Type *t) -{ - switch (t->ty) - { - case Tfloat32: - case Timaginary32: - t = Type::tint32; - break; - case Tfloat64: - case Timaginary64: - case Tcomplex32: - t = Type::tint64; - break; - default: -#ifdef DEBUG - printf("mergeFloatToInt() %s\n", t->toChars()); -#endif - assert(0); - } - return t; -} - -/************************************* - * This merges two types into an 8byte type. - */ - -Type *argtypemerge(Type *t1, Type *t2, unsigned offset2) -{ - //printf("argtypemerge(%s, %s, %d)\n", t1 ? t1->toChars() : "", t2 ? t2->toChars() : "", offset2); - if (!t1) - { assert(!t2 || offset2 == 0); - return t2; - } - if (!t2) - return t1; - - unsigned sz1 = t1->size(0); - unsigned sz2 = t2->size(0); - - if (t1->ty != t2->ty && - (t1->ty == Tfloat80 || t2->ty == Tfloat80)) - return NULL; - - // [float,float] => [cfloat] - if (t1->ty == Tfloat32 && t2->ty == Tfloat32 && offset2 == 4) - return Type::tfloat2; - - // Merging floating and non-floating types produces the non-floating type - if (t1->isfloating()) - { - if (!t2->isfloating()) - t1 = mergeFloatToInt(t1); - } - else if (t2->isfloating()) - t2 = mergeFloatToInt(t2); - - Type *t; - - // Pick type with larger size - if (sz1 < sz2) - t = t2; - else - t = t1; - - // If t2 does not lie within t1, need to increase the size of t to enclose both - if (offset2 && sz1 < offset2 + sz2) - { - switch (offset2 + sz2) - { - case 2: - t = Type::tint16; - break; - case 3: - case 4: - t = Type::tint32; - break; - case 5: - case 6: - case 7: - case 8: - t = Type::tint64; - break; - default: - assert(0); - } - } - return t; -} - -TypeTuple *TypeStruct::toArgTypes() -{ - //printf("TypeStruct::toArgTypes() %s\n", toChars()); - if (!sym->isPOD()) - { - Lmemory: - //printf("\ttoArgTypes() %s => [ ]\n", toChars()); - return new TypeTuple(); // pass on the stack - } - Type *t1 = NULL; - Type *t2 = NULL; - d_uns64 sz = size(0); - assert(sz < 0xFFFFFFFF); - switch ((unsigned)sz) - { - case 1: - t1 = Type::tint8; - break; - case 2: - t1 = Type::tint16; - break; - case 4: - t1 = Type::tint32; - break; - case 8: - t1 = Type::tint64; - break; - case 16: - t1 = NULL; // could be a TypeVector - break; - default: - goto Lmemory; - } - if (global.params.is64bit && sym->fields.dim) - { -#if 1 - unsigned sz1 = 0; - unsigned sz2 = 0; - t1 = NULL; - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *f = sym->fields[i]; - //printf("f->type = %s\n", f->type->toChars()); - - TypeTuple *tup = f->type->toArgTypes(); - if (!tup) - goto Lmemory; - size_t dim = tup->arguments->dim; - Type *ft1 = NULL; - Type *ft2 = NULL; - switch (dim) - { - case 2: - ft1 = (*tup->arguments)[0]->type; - ft2 = (*tup->arguments)[1]->type; - break; - case 1: - if (f->offset < 8) - ft1 = (*tup->arguments)[0]->type; - else - ft2 = (*tup->arguments)[0]->type; - break; - default: - goto Lmemory; - } - - if (f->offset & 7) - { - // Misaligned fields goto Lmemory - unsigned alignsz = f->type->alignsize(); - if (f->offset & (alignsz - 1)) - goto Lmemory; - - // Fields that overlap the 8byte boundary goto Lmemory - unsigned fieldsz = f->type->size(0); - if (f->offset < 8 && (f->offset + fieldsz) > 8) - goto Lmemory; - } - - // First field in 8byte must be at start of 8byte - assert(t1 || f->offset == 0); - - if (ft1) - { - t1 = argtypemerge(t1, ft1, f->offset); - if (!t1) - goto Lmemory; - } - - if (ft2) - { - unsigned off2 = f->offset; - if (ft1) - off2 = 8; - assert(t2 || off2 == 8); - t2 = argtypemerge(t2, ft2, off2 - 8); - if (!t2) - goto Lmemory; - } - } - - if (t2) - { - if (t1->isfloating() && t2->isfloating()) - { - if (t1->ty == Tfloat64 && t2->ty == Tfloat64) - ; - else - goto Lmemory; - } - else if (t1->isfloating()) - goto Lmemory; - else if (t2->isfloating()) - goto Lmemory; - else - ; - } -#else - if (sym->fields.dim == 1) - { VarDeclaration *f = sym->fields[0]; - //printf("f->type = %s\n", f->type->toChars()); - TypeTuple *tup = f->type->toArgTypes(); - if (tup) - { - size_t dim = tup->arguments->dim; - if (dim == 1) - t1 = (*tup->arguments)[0]->type; - } - } -#endif - } - - //printf("\ttoArgTypes() %s => [%s,%s]\n", toChars(), t1 ? t1->toChars() : "", t2 ? t2->toChars() : ""); - - TypeTuple *t; - if (t1) - { - //if (t1) printf("test1: %s => %s\n", toChars(), t1->toChars()); - if (t2) - t = new TypeTuple(t1, t2); - else - t = new TypeTuple(t1); - } - else - goto Lmemory; - return t; -} - -TypeTuple *TypeEnum::toArgTypes() -{ - return toBasetype()->toArgTypes(); -} - -TypeTuple *TypeTypedef::toArgTypes() -{ - return sym->basetype->toArgTypes(); -} - -TypeTuple *TypeClass::toArgTypes() -{ - return new TypeTuple(Type::tvoidptr); -} - diff --git a/dmd/arrayop.c b/dmd/arrayop.c deleted file mode 100644 index c6e17869..00000000 --- a/dmd/arrayop.c +++ /dev/null @@ -1,660 +0,0 @@ - -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "rmem.h" - -#include "aav.h" - -#include "expression.h" -#include "statement.h" -#include "mtype.h" -#include "declaration.h" -#include "scope.h" -#include "id.h" -#include "module.h" -#include "init.h" - -#if IN_DMD -extern int binary(const char *p , const char **tab, int high); - -/************************************** - * Hash table of array op functions already generated or known about. - */ - -AA *arrayfuncs; -#endif - -/********************************************** - * Check that there are no uses of arrays without []. - */ -bool isArrayOpValid(Expression *e) -{ - if (e->op == TOKslice) - return true; - Type *tb = e->type->toBasetype(); - - if ( (tb->ty == Tarray) || (tb->ty == Tsarray) ) - { - switch (e->op) - { - case TOKadd: - case TOKmin: - case TOKmul: - case TOKdiv: - case TOKmod: - case TOKxor: - case TOKand: - case TOKor: - case TOKassign: - case TOKaddass: - case TOKminass: - case TOKmulass: - case TOKdivass: - case TOKmodass: - case TOKxorass: - case TOKandass: - case TOKorass: -#if DMDV2 - case TOKpow: - case TOKpowass: -#endif - return isArrayOpValid(((BinExp *)e)->e1) && isArrayOpValid(((BinExp *)e)->e2); - - case TOKcall: - return false; // TODO: Decide if [] is required after arrayop calls. - - case TOKneg: - case TOKtilde: - return isArrayOpValid(((UnaExp *)e)->e1); - - default: - return false; - } - } - return true; -} - -/*********************************** - * Construct the array operation expression. - */ - -Expression *BinExp::arrayOp(Scope *sc) -{ - //printf("BinExp::arrayOp() %s\n", toChars()); - - Type *tb = type->toBasetype(); - assert(tb->ty == Tarray || tb->ty == Tsarray); - if (tb->nextOf()->toBasetype()->ty == Tvoid) - { - error("Cannot perform array operations on void[] arrays"); - return new ErrorExp(); - } - - if (!isArrayOpValid(e2)) - { - e2->error("invalid array operation %s (did you forget a [] ?)", toChars()); - return new ErrorExp(); - } - - Expressions *arguments = new Expressions(); - - /* The expression to generate an array operation for is mangled - * into a name to use as the array operation function name. - * Mangle in the operands and operators in RPN order, and type. - */ - OutBuffer buf; - buf.writestring("_array"); - buildArrayIdent(&buf, arguments); - buf.writeByte('_'); - - /* Append deco of array element type - */ -#if DMDV2 - buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco); -#else - buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco); -#endif - -#if IN_LLVM - const size_t namelen = buf.offset; -#endif - - buf.writeByte(0); - char *name = buf.toChars(); - Identifier *ident = Lexer::idPool(name); - - /* Look up name in hash table - */ -#if IN_DMD - FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&arrayfuncs, ident); - FuncDeclaration *fd = (FuncDeclaration *)*pfd; -#elif IN_LLVM - StringValue *sv = sc->module->arrayfuncs.update(name, namelen); - FuncDeclaration *fd = (FuncDeclaration *)sv->ptrvalue; -#endif - if (!fd) - { -#if IN_DMD - static const char *libArrayopFuncs[] = - { - "_arrayExpSliceAddass_a", - "_arrayExpSliceAddass_d", // T[]+=T - "_arrayExpSliceAddass_f", // T[]+=T - "_arrayExpSliceAddass_g", - "_arrayExpSliceAddass_h", - "_arrayExpSliceAddass_i", - "_arrayExpSliceAddass_k", - "_arrayExpSliceAddass_s", - "_arrayExpSliceAddass_t", - "_arrayExpSliceAddass_u", - "_arrayExpSliceAddass_w", - - "_arrayExpSliceDivass_d", // T[]/=T - "_arrayExpSliceDivass_f", // T[]/=T - - "_arrayExpSliceMinSliceAssign_a", - "_arrayExpSliceMinSliceAssign_d", // T[]=T-T[] - "_arrayExpSliceMinSliceAssign_f", // T[]=T-T[] - "_arrayExpSliceMinSliceAssign_g", - "_arrayExpSliceMinSliceAssign_h", - "_arrayExpSliceMinSliceAssign_i", - "_arrayExpSliceMinSliceAssign_k", - "_arrayExpSliceMinSliceAssign_s", - "_arrayExpSliceMinSliceAssign_t", - "_arrayExpSliceMinSliceAssign_u", - "_arrayExpSliceMinSliceAssign_w", - - "_arrayExpSliceMinass_a", - "_arrayExpSliceMinass_d", // T[]-=T - "_arrayExpSliceMinass_f", // T[]-=T - "_arrayExpSliceMinass_g", - "_arrayExpSliceMinass_h", - "_arrayExpSliceMinass_i", - "_arrayExpSliceMinass_k", - "_arrayExpSliceMinass_s", - "_arrayExpSliceMinass_t", - "_arrayExpSliceMinass_u", - "_arrayExpSliceMinass_w", - - "_arrayExpSliceMulass_d", // T[]*=T - "_arrayExpSliceMulass_f", // T[]*=T - "_arrayExpSliceMulass_i", - "_arrayExpSliceMulass_k", - "_arrayExpSliceMulass_s", - "_arrayExpSliceMulass_t", - "_arrayExpSliceMulass_u", - "_arrayExpSliceMulass_w", - - "_arraySliceExpAddSliceAssign_a", - "_arraySliceExpAddSliceAssign_d", // T[]=T[]+T - "_arraySliceExpAddSliceAssign_f", // T[]=T[]+T - "_arraySliceExpAddSliceAssign_g", - "_arraySliceExpAddSliceAssign_h", - "_arraySliceExpAddSliceAssign_i", - "_arraySliceExpAddSliceAssign_k", - "_arraySliceExpAddSliceAssign_s", - "_arraySliceExpAddSliceAssign_t", - "_arraySliceExpAddSliceAssign_u", - "_arraySliceExpAddSliceAssign_w", - - "_arraySliceExpDivSliceAssign_d", // T[]=T[]/T - "_arraySliceExpDivSliceAssign_f", // T[]=T[]/T - - "_arraySliceExpMinSliceAssign_a", - "_arraySliceExpMinSliceAssign_d", // T[]=T[]-T - "_arraySliceExpMinSliceAssign_f", // T[]=T[]-T - "_arraySliceExpMinSliceAssign_g", - "_arraySliceExpMinSliceAssign_h", - "_arraySliceExpMinSliceAssign_i", - "_arraySliceExpMinSliceAssign_k", - "_arraySliceExpMinSliceAssign_s", - "_arraySliceExpMinSliceAssign_t", - "_arraySliceExpMinSliceAssign_u", - "_arraySliceExpMinSliceAssign_w", - - "_arraySliceExpMulSliceAddass_d", // T[] += T[]*T - "_arraySliceExpMulSliceAddass_f", - "_arraySliceExpMulSliceAddass_r", - - "_arraySliceExpMulSliceAssign_d", // T[]=T[]*T - "_arraySliceExpMulSliceAssign_f", // T[]=T[]*T - "_arraySliceExpMulSliceAssign_i", - "_arraySliceExpMulSliceAssign_k", - "_arraySliceExpMulSliceAssign_s", - "_arraySliceExpMulSliceAssign_t", - "_arraySliceExpMulSliceAssign_u", - "_arraySliceExpMulSliceAssign_w", - - "_arraySliceExpMulSliceMinass_d", // T[] -= T[]*T - "_arraySliceExpMulSliceMinass_f", - "_arraySliceExpMulSliceMinass_r", - - "_arraySliceSliceAddSliceAssign_a", - "_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[] - "_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[] - "_arraySliceSliceAddSliceAssign_g", - "_arraySliceSliceAddSliceAssign_h", - "_arraySliceSliceAddSliceAssign_i", - "_arraySliceSliceAddSliceAssign_k", - "_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[] - "_arraySliceSliceAddSliceAssign_s", - "_arraySliceSliceAddSliceAssign_t", - "_arraySliceSliceAddSliceAssign_u", - "_arraySliceSliceAddSliceAssign_w", - - "_arraySliceSliceAddass_a", - "_arraySliceSliceAddass_d", // T[]+=T[] - "_arraySliceSliceAddass_f", // T[]+=T[] - "_arraySliceSliceAddass_g", - "_arraySliceSliceAddass_h", - "_arraySliceSliceAddass_i", - "_arraySliceSliceAddass_k", - "_arraySliceSliceAddass_s", - "_arraySliceSliceAddass_t", - "_arraySliceSliceAddass_u", - "_arraySliceSliceAddass_w", - - "_arraySliceSliceMinSliceAssign_a", - "_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[] - "_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[] - "_arraySliceSliceMinSliceAssign_g", - "_arraySliceSliceMinSliceAssign_h", - "_arraySliceSliceMinSliceAssign_i", - "_arraySliceSliceMinSliceAssign_k", - "_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[] - "_arraySliceSliceMinSliceAssign_s", - "_arraySliceSliceMinSliceAssign_t", - "_arraySliceSliceMinSliceAssign_u", - "_arraySliceSliceMinSliceAssign_w", - - "_arraySliceSliceMinass_a", - "_arraySliceSliceMinass_d", // T[]-=T[] - "_arraySliceSliceMinass_f", // T[]-=T[] - "_arraySliceSliceMinass_g", - "_arraySliceSliceMinass_h", - "_arraySliceSliceMinass_i", - "_arraySliceSliceMinass_k", - "_arraySliceSliceMinass_s", - "_arraySliceSliceMinass_t", - "_arraySliceSliceMinass_u", - "_arraySliceSliceMinass_w", - - "_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[] - "_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[] - "_arraySliceSliceMulSliceAssign_i", - "_arraySliceSliceMulSliceAssign_k", - "_arraySliceSliceMulSliceAssign_s", - "_arraySliceSliceMulSliceAssign_t", - "_arraySliceSliceMulSliceAssign_u", - "_arraySliceSliceMulSliceAssign_w", - - "_arraySliceSliceMulass_d", // T[]*=T[] - "_arraySliceSliceMulass_f", // T[]*=T[] - "_arraySliceSliceMulass_i", - "_arraySliceSliceMulass_k", - "_arraySliceSliceMulass_s", - "_arraySliceSliceMulass_t", - "_arraySliceSliceMulass_u", - "_arraySliceSliceMulass_w", - }; - - int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *)); - if (i == -1) - { -#ifdef DEBUG // Make sure our array is alphabetized - for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++) - { - if (strcmp(name, libArrayopFuncs[i]) == 0) - assert(0); - } -#endif -#endif - /* Not in library, so generate it. - * Construct the function body: - * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++) - * loopbody; - * return p; - */ - - Parameters *fparams = new Parameters(); - Expression *loopbody = buildArrayLoop(fparams); - Parameter *p = (*fparams)[0 /*fparams->dim - 1*/]; -#if DMDV1 - // for (size_t i = 0; i < p.length; i++) - Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t)); - Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init); - Statement *s1 = new ForStatement(0, - new ExpStatement(0, d), - new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))), - new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)), - new ExpStatement(0, loopbody)); -#else - // foreach (i; 0 .. p.length) - Statement *s1 = new ForeachRangeStatement(0, TOKforeach, - new Parameter(0, NULL, Id::p, NULL), - new IntegerExp(0, 0, Type::tsize_t), - new ArrayLengthExp(0, new IdentifierExp(0, p->ident)), - new ExpStatement(0, loopbody)); -#endif - Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident)); - //printf("s2: %s\n", s2->toChars()); - Statement *fbody = new CompoundStatement(0, s1, s2); - - /* Construct the function - */ - TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc); - //printf("ftype: %s\n", ftype->toChars()); - fd = new FuncDeclaration(loc, 0, ident, STCundefined, ftype); - fd->fbody = fbody; - fd->protection = PROTpublic; - fd->linkage = LINKc; - fd->isArrayOp = 1; - - sc->module->importedFrom->members->push(fd); - - sc = sc->push(); - sc->parent = sc->module->importedFrom; - sc->stc = 0; - sc->linkage = LINKc; - fd->semantic(sc); - fd->semantic2(sc); - fd->semantic3(sc); - sc->pop(); -#if IN_DMD - } - else - { /* In library, refer to it. - */ - fd = FuncDeclaration::genCfunc(type, ident); - } - *pfd = fd; // cache symbol in hash table -#elif IN_LLVM - sv->ptrvalue = fd; // cache symbol in hash table -#endif - } - - /* Call the function fd(arguments) - */ - Expression *ec = new VarExp(0, fd); - Expression *e = new CallExp(loc, ec, arguments); - e->type = type; - return e; -} - -/****************************************** - * Construct the identifier for the array operation function, - * and build the argument list to pass to it. - */ - -void Expression::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - buf->writestring("Exp"); - arguments->shift(this); -} - -void CastExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - Type *tb = type->toBasetype(); - if (tb->ty == Tarray || tb->ty == Tsarray) - { - e1->buildArrayIdent(buf, arguments); - } - else - Expression::buildArrayIdent(buf, arguments); -} - -void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - buf->writestring("Slice"); - arguments->shift(this); -} - -void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - /* Evaluate assign expressions right to left - */ - e2->buildArrayIdent(buf, arguments); - e1->buildArrayIdent(buf, arguments); - buf->writestring("Assign"); -} - -#define X(Str) \ -void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ -{ \ - /* Evaluate assign expressions right to left \ - */ \ - e2->buildArrayIdent(buf, arguments); \ - e1->buildArrayIdent(buf, arguments); \ - buf->writestring(#Str); \ - buf->writestring("ass"); \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) -#if DMDV2 -X(Pow) -#endif - -#undef X - -void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - e1->buildArrayIdent(buf, arguments); - buf->writestring("Neg"); -} - -void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - e1->buildArrayIdent(buf, arguments); - buf->writestring("Com"); -} - -#define X(Str) \ -void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ -{ \ - /* Evaluate assign expressions left to right \ - */ \ - e1->buildArrayIdent(buf, arguments); \ - e2->buildArrayIdent(buf, arguments); \ - buf->writestring(#Str); \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) -#if DMDV2 -X(Pow) -#endif - -#undef X - -/****************************************** - * Construct the inner loop for the array operation function, - * and build the parameter list. - */ - -Expression *Expression::buildArrayLoop(Parameters *fparams) -{ - Identifier *id = Identifier::generateId("c", fparams->dim); - Parameter *param = new Parameter(0, type, id, NULL); - fparams->shift(param); - Expression *e = new IdentifierExp(0, id); - return e; -} - -Expression *CastExp::buildArrayLoop(Parameters *fparams) -{ - Type *tb = type->toBasetype(); - if (tb->ty == Tarray || tb->ty == Tsarray) - { - return e1->buildArrayLoop(fparams); - } - else - return Expression::buildArrayLoop(fparams); -} - -Expression *SliceExp::buildArrayLoop(Parameters *fparams) -{ - Identifier *id = Identifier::generateId("p", fparams->dim); - Parameter *param = new Parameter(STCconst, type, id, NULL); - fparams->shift(param); - Expression *e = new IdentifierExp(0, id); - Expressions *arguments = new Expressions(); - Expression *index = new IdentifierExp(0, Id::p); - arguments->push(index); - e = new ArrayExp(0, e, arguments); - return e; -} - -Expression *AssignExp::buildArrayLoop(Parameters *fparams) -{ - /* Evaluate assign expressions right to left - */ - Expression *ex2 = e2->buildArrayLoop(fparams); -#if DMDV2 - /* Need the cast because: - * b = c + p[i]; - * where b is a byte fails because (c + p[i]) is an int - * which cannot be implicitly cast to byte. - */ - ex2 = new CastExp(0, ex2, e1->type->nextOf()); -#endif - Expression *ex1 = e1->buildArrayLoop(fparams); - Parameter *param = (*fparams)[0]; - param->storageClass = 0; - Expression *e = new AssignExp(0, ex1, ex2); - return e; -} - -#define X(Str) \ -Expression *Str##AssignExp::buildArrayLoop(Parameters *fparams) \ -{ \ - /* Evaluate assign expressions right to left \ - */ \ - Expression *ex2 = e2->buildArrayLoop(fparams); \ - Expression *ex1 = e1->buildArrayLoop(fparams); \ - Parameter *param = (*fparams)[0]; \ - param->storageClass = 0; \ - Expression *e = new Str##AssignExp(loc, ex1, ex2); \ - return e; \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) -#if DMDV2 -X(Pow) -#endif - -#undef X - -Expression *NegExp::buildArrayLoop(Parameters *fparams) -{ - Expression *ex1 = e1->buildArrayLoop(fparams); - Expression *e = new NegExp(0, ex1); - return e; -} - -Expression *ComExp::buildArrayLoop(Parameters *fparams) -{ - Expression *ex1 = e1->buildArrayLoop(fparams); - Expression *e = new ComExp(0, ex1); - return e; -} - -#define X(Str) \ -Expression *Str##Exp::buildArrayLoop(Parameters *fparams) \ -{ \ - /* Evaluate assign expressions left to right \ - */ \ - Expression *ex1 = e1->buildArrayLoop(fparams); \ - Expression *ex2 = e2->buildArrayLoop(fparams); \ - Expression *e = new Str##Exp(0, ex1, ex2); \ - return e; \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) -#if DMDV2 -X(Pow) -#endif - -#undef X - - -/*********************************************** - * Test if operand is a valid array op operand. - */ - -int Expression::isArrayOperand() -{ - //printf("Expression::isArrayOperand() %s\n", toChars()); - if (op == TOKslice) - return 1; - if (type->toBasetype()->ty == Tarray) - { - switch (op) - { - case TOKadd: - case TOKmin: - case TOKmul: - case TOKdiv: - case TOKmod: - case TOKxor: - case TOKand: - case TOKor: - case TOKassign: - case TOKaddass: - case TOKminass: - case TOKmulass: - case TOKdivass: - case TOKmodass: - case TOKxorass: - case TOKandass: - case TOKorass: -#if DMDV2 - case TOKpow: - case TOKpowass: -#endif - case TOKneg: - case TOKtilde: - return 1; - - default: - break; - } - } - return 0; -} diff --git a/dmd/arraytypes.h b/dmd/arraytypes.h deleted file mode 100644 index 61eb7b50..00000000 --- a/dmd/arraytypes.h +++ /dev/null @@ -1,74 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2006-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_ARRAYTYPES_H -#define DMD_ARRAYTYPES_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - - -#include "root.h" - -struct Expression; -struct Statement; -struct BaseClass; -struct TemplateParameter; -struct FuncDeclaration; -struct Identifier; -struct Initializer; - -typedef ArrayBase TemplateParameters; - -typedef ArrayBase Expressions; - -typedef ArrayBase Statements; - -typedef ArrayBase BaseClasses; - -typedef ArrayBase ClassDeclarations; - -typedef ArrayBase Dsymbols; - -typedef ArrayBase Objects; - -typedef ArrayBase FuncDeclarations; - -typedef ArrayBase Parameters; - -typedef ArrayBase Identifiers; - -typedef ArrayBase Initializers; - -typedef ArrayBase VarDeclarations; - -typedef ArrayBase Types; - -typedef ArrayBase ScopeDsymbols; - -typedef ArrayBase Catches; - -typedef ArrayBase StaticDtorDeclarations; - -typedef ArrayBase SharedStaticDtorDeclarations; -typedef ArrayBase Modules; -typedef ArrayBase CaseStatements; - -typedef ArrayBase CompoundStatements; - -typedef ArrayBase GotoCaseStatements; - -typedef ArrayBase TemplateInstances; -typedef ArrayBase Blocks; - -typedef ArrayBase Symbols; - -#endif diff --git a/dmd/artistic.txt b/dmd/artistic.txt deleted file mode 100644 index cd17757e..00000000 --- a/dmd/artistic.txt +++ /dev/null @@ -1,117 +0,0 @@ - - - - - The "Artistic License" - - Preamble - -The intent of this document is to state the conditions under which a -Package may be copied, such that the Copyright Holder maintains some -semblance of artistic control over the development of the package, -while giving the users of the package the right to use and distribute -the Package in a more-or-less customary fashion, plus the right to make -reasonable modifications. - -Definitions: - - "Package" refers to the collection of files distributed by the - Copyright Holder, and derivatives of that collection of files - created through textual modification. - - "Standard Version" refers to such a Package if it has not been - modified, or has been modified in accordance with the wishes - of the Copyright Holder as specified below. - - "Copyright Holder" is whoever is named in the copyright or - copyrights for the package. - - "You" is you, if you're thinking about copying or distributing - this Package. - - "Reasonable copying fee" is whatever you can justify on the - basis of media cost, duplication charges, time of people involved, - and so on. (You will not be required to justify it to the - Copyright Holder, but only to the computing community at large - as a market that must bear the fee.) - - "Freely Available" means that no fee is charged for the item - itself, though there may be fees involved in handling the item. - It also means that recipients of the item may redistribute it - under the same conditions they received it. - -1. You may make and give away verbatim copies of the source form of the -Standard Version of this Package without restriction, provided that you -duplicate all of the original copyright notices and associated disclaimers. - -2. You may apply bug fixes, portability fixes and other modifications -derived from the Public Domain or from the Copyright Holder. A Package -modified in such a way shall still be considered the Standard Version. - -3. You may otherwise modify your copy of this Package in any way, provided -that you insert a prominent notice in each changed file stating how and -when you changed that file, and provided that you do at least ONE of the -following: - - a) place your modifications in the Public Domain or otherwise make them - Freely Available, such as by posting said modifications to Usenet or - an equivalent medium, or placing the modifications on a major archive - site such as uunet.uu.net, or by allowing the Copyright Holder to include - your modifications in the Standard Version of the Package. - - b) use the modified Package only within your corporation or organization. - - c) rename any non-standard executables so the names do not conflict - with standard executables, which must also be provided, and provide - a separate manual page for each non-standard executable that clearly - documents how it differs from the Standard Version. - - d) make other distribution arrangements with the Copyright Holder. - -4. You may distribute the programs of this Package in object code or -executable form, provided that you do at least ONE of the following: - - a) distribute a Standard Version of the executables and library files, - together with instructions (in the manual page or equivalent) on where - to get the Standard Version. - - b) accompany the distribution with the machine-readable source of - the Package with your modifications. - - c) give non-standard executables non-standard names, and clearly - document the differences in manual pages (or equivalent), together - with instructions on where to get the Standard Version. - - d) make other distribution arrangements with the Copyright Holder. - -5. You may charge a reasonable copying fee for any distribution of this -Package. You may charge any fee you choose for support of this -Package. You may not charge a fee for this Package itself. However, -you may distribute this Package in aggregate with other (possibly -commercial) programs as part of a larger (possibly commercial) software -distribution provided that you do not advertise this Package as a -product of your own. You may embed this Package's interpreter within -an executable of yours (by linking); this shall be construed as a mere -form of aggregation, provided that the complete Standard Version of the -interpreter is so embedded. - -6. The source code and object code supplied as input to or produced as -output from the programs of this Package do not automatically fall -under the copyright of this Package, but belong to whoever generated -them, and may be sold commercially, and may be aggregated with this -Package. - -7. Aggregation of this Package with a commercial distribution is always -permitted provided that the use of this Package is embedded; that is, -when no overt attempt is made to make this Package's interfaces visible -to the end user of the commercial distribution. Such use shall not be -construed as a distribution of this Package. - -8. The name of the Copyright Holder may not be used to endorse or promote -products derived from this software without specific prior written permission. - -9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - - The End diff --git a/dmd/attrib.c b/dmd/attrib.c deleted file mode 100644 index 62b38568..00000000 --- a/dmd/attrib.c +++ /dev/null @@ -1,1563 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include // memcpy() - -#include "rmem.h" - -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "cond.h" -#include "scope.h" -#include "id.h" -#include "expression.h" -#include "dsymbol.h" -#include "aggregate.h" -#include "module.h" -#include "parse.h" -#include "template.h" -#if TARGET_NET - #include "frontend.net/pragma.h" -#endif -#if IN_LLVM -#include "../gen/pragma.h" -#endif - - -extern bool obj_includelib(const char *name); - -#if IN_DMD -void obj_startaddress(Symbol *s); -#endif - - -/********************************* AttribDeclaration ****************************/ - -AttribDeclaration::AttribDeclaration(Dsymbols *decl) - : Dsymbol() -{ - this->decl = decl; -} - -Dsymbols *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) -{ - return decl; -} - -int AttribDeclaration::apply(Dsymbol_apply_ft_t fp, void *param) -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - if (s) - { - if (s->apply(fp, param)) - return 1; - } - } - } - return 0; -} - -int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - int m = 0; - Dsymbols *d = include(sc, sd); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - //printf("\taddMember %s to %s\n", s->toChars(), sd->toChars()); - m |= s->addMember(sc, sd, m | memnum); - } - } - return m; -} - -void AttribDeclaration::setScopeNewSc(Scope *sc, - StorageClass stc, enum LINK linkage, enum PROT protection, int explicitProtection, - structalign_t structalign) -{ - if (decl) - { - Scope *newsc = sc; - if (stc != sc->stc || - linkage != sc->linkage || - protection != sc->protection || - explicitProtection != sc->explicitProtection || - structalign != sc->structalign) - { - // create new one for changes - newsc = new Scope(*sc); - newsc->flags &= ~SCOPEfree; - newsc->stc = stc; - newsc->linkage = linkage; - newsc->protection = protection; - newsc->explicitProtection = explicitProtection; - newsc->structalign = structalign; - } - for (size_t i = 0; i < decl->dim; i++) - { Dsymbol *s = (*decl)[i]; - - s->setScope(newsc); // yes, the only difference from semanticNewSc() - } - if (newsc != sc) - { - sc->offset = newsc->offset; - newsc->pop(); - } - } -} - -void AttribDeclaration::semanticNewSc(Scope *sc, - StorageClass stc, enum LINK linkage, enum PROT protection, int explicitProtection, - structalign_t structalign) -{ - if (decl) - { - Scope *newsc = sc; - if (stc != sc->stc || - linkage != sc->linkage || - protection != sc->protection || - explicitProtection != sc->explicitProtection || - structalign != sc->structalign) - { - // create new one for changes - newsc = new Scope(*sc); - newsc->flags &= ~SCOPEfree; - newsc->stc = stc; - newsc->linkage = linkage; - newsc->protection = protection; - newsc->explicitProtection = explicitProtection; - newsc->structalign = structalign; - } - for (size_t i = 0; i < decl->dim; i++) - { Dsymbol *s = (*decl)[i]; - - s->semantic(newsc); - } - if (newsc != sc) - { - sc->offset = newsc->offset; - newsc->pop(); - } - } -} - -void AttribDeclaration::semantic(Scope *sc) -{ - Dsymbols *d = include(sc, NULL); - - //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[i]; - - s->semantic(sc); - } - } -} - -void AttribDeclaration::semantic2(Scope *sc) -{ - Dsymbols *d = include(sc, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - s->semantic2(sc); - } - } -} - -void AttribDeclaration::semantic3(Scope *sc) -{ - Dsymbols *d = include(sc, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - s->semantic3(sc); - } - } -} - -void AttribDeclaration::inlineScan() -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); - s->inlineScan(); - } - } -} - -void AttribDeclaration::addComment(unsigned char *comment) -{ - //printf("AttribDeclaration::addComment %s\n", comment); - if (comment) - { - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - //printf("AttribDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - } -} - -void AttribDeclaration::emitComment(Scope *sc) -{ - //printf("AttribDeclaration::emitComment(sc = %p)\n", sc); - - /* A general problem with this, illustrated by BUGZILLA 2516, - * is that attributes are not transmitted through to the underlying - * member declarations for template bodies, because semantic analysis - * is not done for template declaration bodies - * (only template instantiations). - * Hence, Ddoc omits attributes from template members. - */ - - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - //printf("AttribDeclaration::emitComment %s\n", s->toChars()); - s->emitComment(sc); - } - } -} - -#if IN_DMD - -void AttribDeclaration::toObjFile(int multiobj) -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - s->toObjFile(multiobj); - } - } -} - -#endif - -void AttribDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - s->setFieldOffset(ad, poffset, isunion); - } - } -} - -int AttribDeclaration::hasPointers() -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[i]; - if (s->hasPointers()) - return 1; - } - } - return 0; -} - -bool AttribDeclaration::hasStaticCtorOrDtor() -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[i]; - if (s->hasStaticCtorOrDtor()) - return TRUE; - } - } - return FALSE; -} - -const char *AttribDeclaration::kind() -{ - return "attribute"; -} - -int AttribDeclaration::oneMember(Dsymbol **ps) -{ - Dsymbols *d = include(NULL, NULL); - - return Dsymbol::oneMembers(d, ps); -} - -void AttribDeclaration::checkCtorConstInit() -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - s->checkCtorConstInit(); - } - } -} - -/**************************************** - */ - -void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - s->addLocalClass(aclasses); - } - } -} - - -void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (decl) - { - if (decl->dim == 0) - buf->writestring("{}"); - else if (decl->dim == 1) - ((*decl)[0])->toCBuffer(buf, hgs); - else - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - } - else - buf->writeByte(';'); - buf->writenl(); -} - -/************************* StorageClassDeclaration ****************************/ - -StorageClassDeclaration::StorageClassDeclaration(StorageClass stc, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->stc = stc; -} - -Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) -{ - StorageClassDeclaration *scd; - - assert(!s); - scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); - return scd; -} - -void StorageClassDeclaration::setScope(Scope *sc) -{ - if (decl) - { - StorageClass scstc = sc->stc; - - /* These sets of storage classes are mutually exclusive, - * so choose the innermost or most recent one. - */ - if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) - scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); - if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) - scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); - if (stc & (STCconst | STCimmutable | STCmanifest)) - scstc &= ~(STCconst | STCimmutable | STCmanifest); - if (stc & (STCgshared | STCshared | STCtls)) - scstc &= ~(STCgshared | STCshared | STCtls); - if (stc & (STCsafe | STCtrusted | STCsystem)) - scstc &= ~(STCsafe | STCtrusted | STCsystem); - scstc |= stc; - //printf("scstc = x%llx\n", scstc); - - setScopeNewSc(sc, scstc, sc->linkage, sc->protection, sc->explicitProtection, sc->structalign); - } -} - -void StorageClassDeclaration::semantic(Scope *sc) -{ - if (decl) - { - StorageClass scstc = sc->stc; - - /* These sets of storage classes are mutually exclusive, - * so choose the innermost or most recent one. - */ - if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) - scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); - if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) - scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); - if (stc & (STCconst | STCimmutable | STCmanifest)) - scstc &= ~(STCconst | STCimmutable | STCmanifest); - if (stc & (STCgshared | STCshared | STCtls)) - scstc &= ~(STCgshared | STCshared | STCtls); - if (stc & (STCsafe | STCtrusted | STCsystem)) - scstc &= ~(STCsafe | STCtrusted | STCsystem); - scstc |= stc; - - semanticNewSc(sc, scstc, sc->linkage, sc->protection, sc->explicitProtection, sc->structalign); - } -} - -void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, StorageClass stc) -{ - struct SCstring - { - StorageClass stc; - enum TOK tok; - }; - - static SCstring table[] = - { - { STCauto, TOKauto }, - { STCscope, TOKscope }, - { STCstatic, TOKstatic }, - { STCextern, TOKextern }, - { STCconst, TOKconst }, - { STCfinal, TOKfinal }, - { STCabstract, TOKabstract }, - { STCsynchronized, TOKsynchronized }, - { STCdeprecated, TOKdeprecated }, - { STCoverride, TOKoverride }, - { STClazy, TOKlazy }, - { STCalias, TOKalias }, - { STCout, TOKout }, - { STCin, TOKin }, -#if DMDV2 - { STCmanifest, TOKenum }, - { STCimmutable, TOKimmutable }, - { STCshared, TOKshared }, - { STCnothrow, TOKnothrow }, - { STCpure, TOKpure }, - { STCref, TOKref }, - { STCtls, TOKtls }, - { STCgshared, TOKgshared }, - { STCproperty, TOKat, Id::property }, - { STCsafe, TOKat, Id::safe }, - { STCtrusted, TOKat, Id::trusted }, - { STCsystem, TOKat, Id::system }, - { STCdisable, TOKat, Id::disable }, -#endif - }; - - for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) - { - if (stc & table[i].stc) - { - enum TOK tok = table[i].tok; -#if DMDV2 - if (tok == TOKat) - { - buf->writeByte('@'); - buf->writestring(table[i].id->toChars()); - } - else -#endif - buf->writestring(Token::toChars(tok)); - buf->writeByte(' '); - } - } -} - -void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - stcToCBuffer(buf, stc); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* LinkDeclaration ****************************/ - -LinkDeclaration::LinkDeclaration(enum LINK p, Dsymbols *decl) - : AttribDeclaration(decl) -{ - //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); - linkage = p; -} - -Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s) -{ - LinkDeclaration *ld; - - assert(!s); - ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); - return ld; -} - -void LinkDeclaration::setScope(Scope *sc) -{ - //printf("LinkDeclaration::setScope(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { - setScopeNewSc(sc, sc->stc, linkage, sc->protection, sc->explicitProtection, sc->structalign); - } -} - -void LinkDeclaration::semantic(Scope *sc) -{ - //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { - semanticNewSc(sc, sc->stc, linkage, sc->protection, sc->explicitProtection, sc->structalign); - } -} - -void LinkDeclaration::semantic3(Scope *sc) -{ - //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { enum LINK linkage_save = sc->linkage; - - sc->linkage = linkage; - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - - s->semantic3(sc); - } - sc->linkage = linkage_save; - } - else - { - sc->linkage = linkage; - } -} - -void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ const char *p; - - switch (linkage) - { - case LINKd: p = "D"; break; - case LINKc: p = "C"; break; - case LINKcpp: p = "C++"; break; - case LINKwindows: p = "Windows"; break; - case LINKpascal: p = "Pascal"; break; - - // LDC - case LINKintrinsic: p = "Intrinsic"; break; - - default: - assert(0); - break; - } - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - AttribDeclaration::toCBuffer(buf, hgs); -} - -char *LinkDeclaration::toChars() -{ - return (char *)"extern ()"; -} - -/********************************* ProtDeclaration ****************************/ - -ProtDeclaration::ProtDeclaration(enum PROT p, Dsymbols *decl) - : AttribDeclaration(decl) -{ - protection = p; - //printf("decl = %p\n", decl); -} - -Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s) -{ - ProtDeclaration *pd; - - assert(!s); - pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void ProtDeclaration::setScope(Scope *sc) -{ - if (decl) - { - setScopeNewSc(sc, sc->stc, sc->linkage, protection, 1, sc->structalign); - } -} - -void ProtDeclaration::importAll(Scope *sc) -{ - Scope *newsc = sc; - if (sc->protection != protection || - sc->explicitProtection != 1) - { - // create new one for changes - newsc = new Scope(*sc); - newsc->flags &= ~SCOPEfree; - newsc->protection = protection; - newsc->explicitProtection = 1; - } - - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - s->importAll(newsc); - } - - if (newsc != sc) - newsc->pop(); -} - -void ProtDeclaration::semantic(Scope *sc) -{ - if (decl) - { - semanticNewSc(sc, sc->stc, sc->linkage, protection, 1, sc->structalign); - } -} - -void ProtDeclaration::protectionToCBuffer(OutBuffer *buf, enum PROT protection) -{ - const char *p; - - switch (protection) - { - case PROTprivate: p = "private"; break; - case PROTpackage: p = "package"; break; - case PROTprotected: p = "protected"; break; - case PROTpublic: p = "public"; break; - case PROTexport: p = "export"; break; - default: - assert(0); - break; - } - buf->writestring(p); - buf->writeByte(' '); -} - -void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - protectionToCBuffer(buf, protection); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AlignDeclaration ****************************/ - -AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - salign = sa; -} - -Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s) -{ - AlignDeclaration *ad; - - assert(!s); - ad = new AlignDeclaration(loc, salign, Dsymbol::arraySyntaxCopy(decl)); - return ad; -} - -void AlignDeclaration::setScope(Scope *sc) -{ - //printf("\tAlignDeclaration::setScope '%s'\n",toChars()); - if (decl) - { - setScopeNewSc(sc, sc->stc, sc->linkage, sc->protection, sc->explicitProtection, salign); - } -} - -void AlignDeclaration::semantic(Scope *sc) -{ - // LDC - // we only support packed structs, as from the spec: align(1) struct Packed { ... } - // other alignments are simply ignored. my tests show this is what llvm-gcc does too ... - if (decl) - { - semanticNewSc(sc, sc->stc, sc->linkage, sc->protection, sc->explicitProtection, salign); - } - else - assert(0 && "what kind of align use triggers this?"); -} - - -void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (salign == STRUCTALIGN_DEFAULT) - buf->printf("align"); - else - buf->printf("align (%d)", salign); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AnonDeclaration ****************************/ - -AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->alignment = 0; - this->isunion = isunion; - this->sem = 0; -} - -Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s) -{ - AnonDeclaration *ad; - - assert(!s); - ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); - return ad; -} - -void AnonDeclaration::semantic(Scope *sc) -{ - //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); - - assert(sc->parent); - - Dsymbol *parent = sc->parent->pastMixin(); - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - - if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration())) - { - error("can only be a part of an aggregate"); - return; - } - - alignment = sc->structalign; - if (decl) - { - sc = sc->push(); - sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared); - sc->inunion = isunion; - sc->offset = 0; - sc->flags = 0; - - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - s->semantic(sc); - } - sc = sc->pop(); - } -} - - -void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); - - if (decl) - { - /* This works by treating an AnonDeclaration as an aggregate 'member', - * so in order to place that member we need to compute the member's - * size and alignment. - */ - - size_t fieldstart = ad->fields.dim; - - /* Hackishly hijack ad's structsize and alignsize fields - * for use in our fake anon aggregate member. - */ - unsigned savestructsize = ad->structsize; - unsigned savealignsize = ad->alignsize; - ad->structsize = 0; - ad->alignsize = 0; - - unsigned offset = 0; - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - - s->setFieldOffset(ad, &offset, this->isunion); - if (this->isunion) - offset = 0; - } - - unsigned anonstructsize = ad->structsize; - unsigned anonalignsize = ad->alignsize; - ad->structsize = savestructsize; - ad->alignsize = savealignsize; - - // 0 sized structs are set to 1 byte - if (anonstructsize == 0) - { - anonstructsize = 1; - anonalignsize = 1; - } - - /* Given the anon 'member's size and alignment, - * go ahead and place it. - */ - unsigned anonoffset = AggregateDeclaration::placeField( - poffset, - anonstructsize, anonalignsize, alignment, - &ad->structsize, &ad->alignsize, - isunion); - - // Add to the anon fields the base offset of this anonymous aggregate - //printf("anon fields, anonoffset = %d\n", anonoffset); - for (size_t i = fieldstart; i < ad->fields.dim; i++) - { - VarDeclaration *v = ad->fields[i]; - //printf("\t[%d] %s %d\n", i, v->toChars(), v->offset); - v->offset += anonoffset; - } - } -} - - -void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf(isunion ? "union" : "struct"); - buf->writestring("\n{\n"); - if (decl) - { - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - - //buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writestring("}\n"); -} - -const char *AnonDeclaration::kind() -{ - return (isunion ? "anonymous union" : "anonymous struct"); -} - -/********************************* PragmaDeclaration ****************************/ - -static bool parseStringExp(Expression* e, std::string& res) -{ - StringExp *s = NULL; - - e = e->optimize(WANTvalue); - if (e->op == TOKstring && (s = (StringExp *)e)) - { - char* str = (char*)s->string; - res = str; - return true; - } - return false; -} - -PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->ident = ident; - this->args = args; -} - -Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); - PragmaDeclaration *pd; - - assert(!s); - pd = new PragmaDeclaration(loc, ident, - Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void PragmaDeclaration::setScope(Scope *sc) -{ -#if TARGET_NET - if (ident == Lexer::idPool("assembly")) - { - if (!args || args->dim != 1) - { - error("pragma has invalid number of arguments"); - } - else - { - Expression *e = (*args)[0]; - e = e->semantic(sc); - e = e->ctfeInterpret(); - (*args)[0] = e; - StringExp* se = e->toString(); - if (!se) - { - error("string expected, not '%s'", e->toChars()); - } - PragmaScope* pragma = new PragmaScope(this, sc->parent, se); - - assert(sc); - pragma->setScope(sc); - - //add to module members - assert(sc->module); - assert(sc->module->members); - sc->module->members->push(pragma); - } - } -#endif // TARGET_NET -} - -void PragmaDeclaration::semantic(Scope *sc) -{ // Should be merged with PragmaStatement - -#if IN_LLVM - Pragma llvm_internal = LLVMnone; - std::string arg1str; -#endif - - //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); - if (ident == Id::msg) - { - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (*args)[i]; - - e = e->semantic(sc); - if (e->op != TOKerror && e->op != TOKtype) - e = e->ctfeInterpret(); - StringExp *se = e->toString(); - if (se) - { - fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); - } - else - fprintf(stdmsg, "%s", e->toChars()); - } - fprintf(stdmsg, "\n"); - } - goto Lnodecl; - } - else if (ident == Id::lib) - { - if (!args || args->dim != 1) - error("string expected for library name"); - else - { - Expression *e = (*args)[0]; - - e = e->semantic(sc); - e = e->ctfeInterpret(); - (*args)[0] = e; - if (e->op == TOKerror) - goto Lnodecl; - StringExp *se = e->toString(); - if (!se) - error("string expected for library name, not '%s'", e->toChars()); - else if (global.params.verbose) - { - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - printf("library %s\n", name); - mem.free(name); - } - } - goto Lnodecl; - } -#if IN_GCC - else if (ident == Id::GNU_asm) - { - if (! args || args->dim != 2) - error("identifier and string expected for asm name"); - else - { - Expression *e; - Declaration *d = NULL; - StringExp *s = NULL; - - e = (*args)[0]; - e = e->semantic(sc); - if (e->op == TOKvar) - { - d = ((VarExp *)e)->var; - if (! d->isFuncDeclaration() && ! d->isVarDeclaration()) - d = NULL; - } - if (!d) - error("first argument of GNU_asm must be a function or variable declaration"); - - e = (*args)[1]; - e = e->semantic(sc); - e = e->optimize(WANTvalue); - e = e->toString(); - if (e && ((StringExp *)e)->sz == 1) - s = ((StringExp *)e); - else - error("second argument of GNU_asm must be a character string"); - - if (d && s) - d->c_ident = Lexer::idPool((char*) s->string); - } - goto Lnodecl; - } -#endif -#if DMDV2 - else if (ident == Id::startaddress) - { - if (!args || args->dim != 1) - error("function name expected for start address"); - else - { - Expression *e = (*args)[0]; - e = e->semantic(sc); - e = e->ctfeInterpret(); - (*args)[0] = e; - Dsymbol *sa = getDsymbol(e); - if (!sa || !sa->isFuncDeclaration()) - error("function name expected for start address, not '%s'", e->toChars()); - } - goto Lnodecl; - } -#endif -#if TARGET_NET - else if (ident == Lexer::idPool("assembly")) - { - } -#endif // TARGET_NET -#if IN_LLVM - else if ((llvm_internal = DtoGetPragma(sc, this, arg1str)) != LLVMnone) - { - // nothing to do anymore - } -#endif - else if (global.params.ignoreUnsupportedPragmas) - { - if (global.params.verbose) - { - /* Print unrecognized pragmas - */ - printf("pragma %s", ident->toChars()); - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { -#if IN_LLVM - // ignore errors in ignored pragmas. - global.gag++; - unsigned errors_save = global.errors; -#endif - - Expression *e = (*args)[i]; - e = e->semantic(sc); - e = e->ctfeInterpret(); - if (i == 0) - printf(" ("); - else - printf(","); - printf("%s", e->toChars()); - -#if IN_LLVM - // restore error state. - global.gag--; - global.errors = errors_save; -#endif - } - if (args->dim) - printf(")"); - } - printf("\n"); - } - goto Lnodecl; - } - else - error("unrecognized pragma(%s)", ident->toChars()); - -Ldecl: - if (decl) - { - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - - s->semantic(sc); - -#if IN_LLVM - DtoCheckPragma(this, s, llvm_internal, arg1str); -#endif - } - } - return; - -Lnodecl: - if (decl) - { - error("pragma is missing closing ';'"); - goto Ldecl; // do them anyway, to avoid segfaults. - } -} - -int PragmaDeclaration::oneMember(Dsymbol **ps) -{ - *ps = NULL; - return TRUE; -} - -const char *PragmaDeclaration::kind() -{ - return "pragma"; -} - -#if IN_DMD -void PragmaDeclaration::toObjFile(int multiobj) -{ - if (ident == Id::lib) - { - assert(args && args->dim == 1); - - Expression *e = (*args)[0]; - - assert(e->op == TOKstring); - - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - - /* Embed the library names into the object file. - * The linker will then automatically - * search that library, too. - */ - if (!obj_includelib(name)) - { - /* The format does not allow embedded library names, - * so instead append the library name to the list to be passed - * to the linker. - */ - global.params.libfiles->push(name); - } - } -#if DMDV2 - else if (ident == Id::startaddress) - { - assert(args && args->dim == 1); - Expression *e = (*args)[0]; - Dsymbol *sa = getDsymbol(e); - FuncDeclaration *f = sa->isFuncDeclaration(); - assert(f); - Symbol *s = f->toSymbol(); - obj_startaddress(s); - } -#endif - AttribDeclaration::toObjFile(multiobj); -} -#endif - -void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("pragma(%s", ident->toChars()); - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (Expression *)args->data[i]; - - buf->writestring(", "); - e->toCBuffer(buf, hgs); - } - } - buf->writeByte(')'); - AttribDeclaration::toCBuffer(buf, hgs); -} - - -/********************************* ConditionalDeclaration ****************************/ - -ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl) - : AttribDeclaration(decl) -{ - //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); - this->condition = condition; - this->elsedecl = elsedecl; -} - -Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) -{ - ConditionalDeclaration *dd; - - assert(!s); - dd = new ConditionalDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int ConditionalDeclaration::oneMember(Dsymbol **ps) -{ - //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); - if (condition->inc) - { - Dsymbols *d = condition->include(NULL, NULL) ? decl : elsedecl; - return Dsymbol::oneMembers(d, ps); - } - *ps = NULL; - return TRUE; -} - -void ConditionalDeclaration::emitComment(Scope *sc) -{ - //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc); - if (condition->inc) - { - AttribDeclaration::emitComment(sc); - } - else if (sc->docbuf) - { - /* If generating doc comment, be careful because if we're inside - * a template, then include(NULL, NULL) will fail. - */ - Dsymbols *d = decl ? decl : elsedecl; - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - s->emitComment(sc); - } - } -} - -// Decide if 'then' or 'else' code should be included - -Dsymbols *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) -{ - //printf("ConditionalDeclaration::include()\n"); - assert(condition); - return condition->include(sc, sd) ? decl : elsedecl; -} - -void ConditionalDeclaration::setScope(Scope *sc) -{ - Dsymbols *d = include(sc, NULL); - - //printf("\tConditionalDeclaration::setScope '%s', d = %p\n",toChars(), d); - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[i]; - - s->setScope(sc); - } - } -} - -void ConditionalDeclaration::importAll(Scope *sc) -{ - Dsymbols *d = include(sc, NULL); - - //printf("\tConditionalDeclaration::importAll '%s', d = %p\n",toChars(), d); - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[i]; - - s->importAll(sc); - } - } -} - -void ConditionalDeclaration::addComment(unsigned char *comment) -{ - /* Because addComment is called by the parser, if we called - * include() it would define a version before it was used. - * But it's no problem to drill down to both decl and elsedecl, - * so that's the workaround. - */ - - if (comment) - { - Dsymbols *d = decl; - - for (int j = 0; j < 2; j++) - { - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = (*d)[i]; - //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - d = elsedecl; - } - } -} - -void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - condition->toCBuffer(buf, hgs); - if (decl || elsedecl) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - if (decl) - { - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writeByte('}'); - if (elsedecl) - { - buf->writenl(); - buf->writestring("else"); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (size_t i = 0; i < elsedecl->dim; i++) - { - Dsymbol *s = (*elsedecl)[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - } - else - buf->writeByte(':'); - buf->writenl(); -} - -/***************************** StaticIfDeclaration ****************************/ - -StaticIfDeclaration::StaticIfDeclaration(Condition *condition, - Dsymbols *decl, Dsymbols *elsedecl) - : ConditionalDeclaration(condition, decl, elsedecl) -{ - //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); - sd = NULL; - addisdone = 0; -} - - -Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticIfDeclaration *dd; - - assert(!s); - dd = new StaticIfDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("StaticIfDeclaration::addMember() '%s'\n",toChars()); - /* This is deferred until semantic(), so that - * expressions in the condition can refer to declarations - * in the same scope, such as: - * - * template Foo(int i) - * { - * const int j = i + 1; - * static if (j == 3) - * const int k; - * } - */ - this->sd = sd; - int m = 0; - - if (memnum == 0) - { m = AttribDeclaration::addMember(sc, sd, memnum); - addisdone = 1; - } - return m; -} - - -void StaticIfDeclaration::importAll(Scope *sc) -{ - // do not evaluate condition before semantic pass -} - -void StaticIfDeclaration::setScope(Scope *sc) -{ - // do not evaluate condition before semantic pass - - // But do set the scope, in case we need it for forward referencing - Dsymbol::setScope(sc); - - // Set the scopes for both the decl and elsedecl, as we don't know yet - // which will be selected, and the scope will be the same regardless - Dsymbols *d = decl; - for (int j = 0; j < 2; j++) - { - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[i]; - - s->setScope(sc); - } - } - d = elsedecl; - } -} - -void StaticIfDeclaration::semantic(Scope *sc) -{ - Dsymbols *d = include(sc, sd); - - //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d); - if (d) - { - if (!addisdone) - { AttribDeclaration::addMember(sc, sd, 1); - addisdone = 1; - } - - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[i]; - - s->semantic(sc); - } - } -} - -const char *StaticIfDeclaration::kind() -{ - return "static if"; -} - - -/***************************** CompileDeclaration *****************************/ - -// These are mixin declarations, like mixin("int x"); - -CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) - : AttribDeclaration(NULL) -{ - //printf("CompileDeclaration(loc = %d)\n", loc.linnum); - this->loc = loc; - this->exp = exp; - this->sd = NULL; - this->compiled = 0; -} - -Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); - CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy()); - return sc; -} - -int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("CompileDeclaration::addMember(sc = %p, sd = %p, memnum = %d)\n", sc, sd, memnum); - this->sd = sd; - if (memnum == 0) - { /* No members yet, so parse the mixin now - */ - compileIt(sc); - memnum |= AttribDeclaration::addMember(sc, sd, memnum); - compiled = 1; - } - return memnum; -} - -void CompileDeclaration::compileIt(Scope *sc) -{ - //printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->ctfeInterpret(); - StringExp *se = exp->toString(); - if (!se) - { exp->error("argument to mixin must be a string, not (%s)", exp->toChars()); - } - else - { - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - decl = p.parseDeclDefs(0); - if (p.token.value != TOKeof) - exp->error("incomplete mixin declaration (%s)", se->toChars()); - } -} - -void CompileDeclaration::semantic(Scope *sc) -{ - //printf("CompileDeclaration::semantic()\n"); - - if (!compiled) - { - compileIt(sc); - AttribDeclaration::addMember(sc, sd, 0); - compiled = 1; - } - AttribDeclaration::semantic(sc); -} - -void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - exp->toCBuffer(buf, hgs); - buf->writestring(");"); - buf->writenl(); -} diff --git a/dmd/attrib.h b/dmd/attrib.h deleted file mode 100644 index 91b135cd..00000000 --- a/dmd/attrib.h +++ /dev/null @@ -1,204 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_ATTRIB_H -#define DMD_ATTRIB_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - -struct Expression; -struct Statement; -struct LabelDsymbol; -struct Initializer; -struct Module; -struct Condition; -struct HdrGenState; - -/**************************************************************/ - -struct AttribDeclaration : Dsymbol -{ - Dsymbols *decl; // array of Dsymbol's - - AttribDeclaration(Dsymbols *decl); - virtual Dsymbols *include(Scope *sc, ScopeDsymbol *s); - int apply(Dsymbol_apply_ft_t fp, void *param); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void setScopeNewSc(Scope *sc, - StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, - structalign_t structalign); - void semanticNewSc(Scope *sc, - StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, - structalign_t structalign); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - void addComment(unsigned char *comment); - void emitComment(Scope *sc); - const char *kind(); - int oneMember(Dsymbol **ps); - void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - int hasPointers(); - bool hasStaticCtorOrDtor(); - void checkCtorConstInit(); - void addLocalClass(ClassDeclarations *); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); - AttribDeclaration *isAttribDeclaration() { return this; } - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - -#if IN_LLVM - virtual void codegen(Ir*); -#endif -}; - -struct StorageClassDeclaration: AttribDeclaration -{ - StorageClass stc; - - StorageClassDeclaration(StorageClass stc, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - static void stcToCBuffer(OutBuffer *buf, StorageClass stc); -}; - -struct LinkDeclaration : AttribDeclaration -{ - enum LINK linkage; - - LinkDeclaration(enum LINK p, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void semantic3(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *toChars(); -}; - -struct ProtDeclaration : AttribDeclaration -{ - enum PROT protection; - - ProtDeclaration(enum PROT p, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void importAll(Scope *sc); - void setScope(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - static void protectionToCBuffer(OutBuffer *buf, enum PROT protection); -}; - -struct AlignDeclaration : AttribDeclaration -{ - unsigned salign; - - AlignDeclaration(Loc loc, unsigned sa, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct AnonDeclaration : AttribDeclaration -{ - bool isunion; - structalign_t alignment; - int sem; // 1 if successful semantic() - - AnonDeclaration(Loc loc, int isunion, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); -}; - -struct PragmaDeclaration : AttribDeclaration -{ - Expressions *args; // array of Expression's - - PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void setScope(Scope *sc); - int oneMember(Dsymbol **ps); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -struct ConditionalDeclaration : AttribDeclaration -{ - Condition *condition; - Dsymbols *elsedecl; // array of Dsymbol's for else block - - ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); - Dsymbol *syntaxCopy(Dsymbol *s); - int oneMember(Dsymbol **ps); - void emitComment(Scope *sc); - Dsymbols *include(Scope *sc, ScopeDsymbol *s); - void addComment(unsigned char *comment); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); - void importAll(Scope *sc); - void setScope(Scope *sc); -}; - -struct StaticIfDeclaration : ConditionalDeclaration -{ - ScopeDsymbol *sd; - int addisdone; - - StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void semantic(Scope *sc); - void importAll(Scope *sc); - void setScope(Scope *sc); - const char *kind(); -}; - -// Mixin declarations - -struct CompileDeclaration : AttribDeclaration -{ - Expression *exp; - - ScopeDsymbol *sd; - int compiled; - - CompileDeclaration(Loc loc, Expression *exp); - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *sd, int memnum); - void compileIt(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#endif /* DMD_ATTRIB_H */ diff --git a/dmd/cast.c b/dmd/cast.c deleted file mode 100644 index fbd03637..00000000 --- a/dmd/cast.c +++ /dev/null @@ -1,1676 +0,0 @@ - -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include // mem{set|cpy}() - -#include "rmem.h" - -#include "expression.h" -#include "mtype.h" -#include "utf.h" -#include "declaration.h" -#include "aggregate.h" - -/* ==================== implicitCast ====================== */ - -/************************************** - * Do an implicit cast. - * Issue error if it can't be done. - */ - -Expression *Expression::implicitCastTo(Scope *sc, Type *t) -{ - //printf("implicitCastTo(%s) => %s\n", type->toChars(), t->toChars()); - if (implicitConvTo(t)) - { TY tyfrom = type->toBasetype()->ty; - TY tyto = t->toBasetype()->ty; - if (global.params.warnings && - Type::impcnvWarn[tyfrom][tyto] && - op != TOKint64) - { - Expression *e = optimize(WANTflags | WANTvalue); - - if (e->op == TOKint64) - return e->implicitCastTo(sc, t); - - if (tyfrom == Tint32 && - (op == TOKadd || op == TOKmin || - op == TOKand || op == TOKor || op == TOKxor) - ) - { - /* This is really only a semi-kludge fix, - * we really should look at the operands of op - * and see if they are narrower types. - * For example, b=b|b and b=b|7 and s=b+b should be allowed, - * but b=b|i should be an error. - */ - ; - } - else - { - warning("implicit conversion of expression (%s) of type %s to %s can cause loss of data", - toChars(), type->toChars(), t->toChars()); - } - } -#if DMDV2 - if (match == MATCHconst && t == type->constOf()) - { - Expression *e = copy(); - e->type = t; - return e; - } -#endif - return castTo(sc, t); - } - - Expression *e = optimize(WANTflags | WANTvalue); - if (e != this) - return e->implicitCastTo(sc, t); - -#if 0 -printf("ty = %d\n", type->ty); -print(); -type->print(); -printf("to:\n"); -t->print(); -printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco); -//printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t); -fflush(stdout); -#endif - if (t->ty != Terror && type->ty != Terror) - { - if (!t->deco) - { /* Can happen with: - * enum E { One } - * class A - * { static void fork(EDG dg) { dg(E.One); } - * alias void delegate(E) EDG; - * } - * Should eventually make it work. - */ - error("forward reference to type %s", t->toChars()); - } - else if (t->reliesOnTident()) - error("forward reference to type %s", t->reliesOnTident()->toChars()); - - error("cannot implicitly convert expression (%s) of type %s to %s", - toChars(), type->toChars(), t->toChars()); - } - return new ErrorExp(); -} - -Expression *ErrorExp::implicitCastTo(Scope *sc, Type *t) -{ - return this; -} - -/******************************************* - * Return !=0 if we can implicitly convert this to type t. - * Don't do the actual cast. - */ - -MATCH Expression::implicitConvTo(Type *t) -{ -#if 0 - printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - //static int nest; if (++nest == 10) halt(); - if (t == Type::terror) - return MATCHnomatch; - if (!type) - { error("%s is not an expression", toChars()); - type = Type::terror; - } - if (t->ty == Tbit && isBit()) - return MATCHconvert; - Expression *e = optimize(WANTvalue | WANTflags); - if (e != this) - { //printf("optimzed to %s\n", e->toChars()); - return e->implicitConvTo(t); - } - MATCH match = type->implicitConvTo(t); - if (match) - return match; -#if 0 - Type *tb = t->toBasetype(); - if (tb->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) - { - match = type->implicitConvTo(tf->nextOf()); - if (match) - return match; - if (tf->nextOf()->toBasetype()->ty == Tvoid) - return MATCHconvert; - } - } -#endif - return MATCHnomatch; -} - - -MATCH IntegerExp::implicitConvTo(Type *t) -{ -#if 0 - printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type->equals(t)) - return MATCHexact; - - enum TY ty = type->toBasetype()->ty; - enum TY toty = t->toBasetype()->ty; - enum TY oldty = ty; - - if (type->implicitConvTo(t) == MATCHnomatch && t->ty == Tenum) - { - return MATCHnomatch; - } - - switch (ty) - { - case Tbit: - case Tbool: - value &= 1; - ty = Tint32; - break; - - case Tint8: - value = (signed char)value; - ty = Tint32; - break; - - case Tchar: - case Tuns8: - value &= 0xFF; - ty = Tint32; - break; - - case Tint16: - value = (short)value; - ty = Tint32; - break; - - case Tuns16: - case Twchar: - value &= 0xFFFF; - ty = Tint32; - break; - - case Tint32: - value = (int)value; - break; - - case Tuns32: - case Tdchar: - value &= 0xFFFFFFFF; - ty = Tuns32; - break; - - default: - break; - } - - // Only allow conversion if no change in value - switch (toty) - { - case Tbit: - case Tbool: - if ((value & 1) != value) - goto Lno; - goto Lyes; - - case Tint8: - if ((signed char)value != value) - goto Lno; - goto Lyes; - - case Tchar: - if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F) - goto Lno; - case Tuns8: - //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); - if ((unsigned char)value != value) - goto Lno; - goto Lyes; - - case Tint16: - if ((short)value != value) - goto Lno; - goto Lyes; - - case Twchar: - if (oldty == Tdchar && value > 0xD7FF && value < 0xE000) - goto Lno; - case Tuns16: - if ((unsigned short)value != value) - goto Lno; - goto Lyes; - - case Tint32: - if (ty == Tuns32) - { - } - else if ((int)value != value) - goto Lno; - goto Lyes; - - case Tuns32: - if (ty == Tint32) - { - } - else if ((unsigned)value != value) - goto Lno; - goto Lyes; - - case Tdchar: - if (value > 0x10FFFFUL) - goto Lno; - goto Lyes; - - case Tfloat32: - { - volatile float f; - if (type->isunsigned()) - { - f = (float)value; - if (f != value) - goto Lno; - } - else - { - f = (float)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tfloat64: - { - volatile double f; - if (type->isunsigned()) - { - f = (double)value; - if (f != value) - goto Lno; - } - else - { - f = (double)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tfloat80: - { - volatile long double f; - if (type->isunsigned()) - { - f = (long double)value; - if (f != value) - goto Lno; - } - else - { - f = (long double)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - } - return Expression::implicitConvTo(t); - -Lyes: - //printf("MATCHconvert\n"); - return MATCHconvert; - -Lno: - //printf("MATCHnomatch\n"); - return MATCHnomatch; -} - -MATCH NullExp::implicitConvTo(Type *t) -{ -#if 0 - printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n", - toChars(), type->toChars(), t->toChars(), committed); -#endif - if (this->type->equals(t)) - return MATCHexact; - // NULL implicitly converts to any pointer type or dynamic array - if (type->ty == Tpointer && type->next->ty == Tvoid) - { - if (t->ty == Ttypedef) - t = ((TypeTypedef *)t)->sym->basetype; - if (t->ty == Tpointer || t->ty == Tarray || - t->ty == Taarray || t->ty == Tclass || - t->ty == Tdelegate) - return committed ? MATCHconvert : MATCHexact; - } - return Expression::implicitConvTo(t); -} - -#if DMDV2 -MATCH StructLiteralExp::implicitConvTo(Type *t) -{ -#if 0 - printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH m = Expression::implicitConvTo(t); - if (m != MATCHnomatch) - return m; - if (type->ty == t->ty && type->ty == Tstruct && - ((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym) - { - m = MATCHconst; - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - Type *te = e->type; - if (t->mod == 0) - te = te->mutableOf(); - else - { assert(t->mod == MODimmutable); - te = te->invariantOf(); - } - MATCH m2 = e->implicitConvTo(te); - //printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2); - if (m2 < m) - m = m2; - } - } - return m; -} -#endif - -MATCH StringExp::implicitConvTo(Type *t) -{ -#if 0 - printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", - toChars(), committed, type->toChars(), t->toChars()); -#endif - if (!committed && t->ty == Tpointer && t->next->ty == Tvoid) - { - return MATCHnomatch; - } - if (!committed) - if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer) - { - if (type->next->ty == Tchar) - { - switch (t->ty) - { - case Tsarray: - if (type->ty == Tsarray && - ((TypeSArray *)type)->dim->toInteger() != - ((TypeSArray *)t)->dim->toInteger()) - return MATCHnomatch; - goto L1; - case Tarray: - goto L1; - case Tpointer: - L1: - if (t->next->ty == Tchar) - return MATCHexact; - else if (!committed) - { if (t->next->ty == Twchar) - return MATCHexact; - else if (t->next->ty == Tdchar) - return MATCHexact; - } - break; - } - } - } - return Expression::implicitConvTo(t); -#if 0 - m = (MATCH)type->implicitConvTo(t); - if (m) - { - return m; - } - - return MATCHnomatch; -#endif -} - -MATCH ArrayLiteralExp::implicitConvTo(Type *t) -{ MATCH result = MATCHexact; - -#if 0 - printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if ((tb->ty == Tarray || tb->ty == Tsarray) && - (typeb->ty == Tarray || typeb->ty == Tsarray)) - { - if (tb->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)tb; - if (elements->dim != tsa->dim->toInteger()) - result = MATCHnomatch; - } - - if (!elements->dim && typeb->nextOf()->toBasetype()->ty != Tvoid) - result = MATCHnomatch; - - Type *telement = tb->nextOf(); - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - if (result == MATCHnomatch) - break; // no need to check for worse - MATCH m = (MATCH)e->implicitConvTo(telement); - if (m < result) - result = m; // remember worst match - } - - if (!result) - result = type->implicitConvTo(t); - - return result; - } -#if DMDV2 - else if (tb->ty == Tvector && - (typeb->ty == Tarray || typeb->ty == Tsarray)) - { - // Convert array literal to vector type - TypeVector *tv = (TypeVector *)tb; - TypeSArray *tbase = (TypeSArray *)tv->basetype; - assert(tbase->ty == Tsarray); - if (elements->dim != tbase->dim->toInteger()) - return MATCHnomatch; - - Type *telement = tv->elementType(); - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - MATCH m = (MATCH)e->implicitConvTo(telement); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - } - return result; - } -#endif - else - return Expression::implicitConvTo(t); -} - -MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) -{ MATCH result = MATCHexact; - - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if (tb->ty == Taarray && typeb->ty == Taarray) - { - for (size_t i = 0; i < keys->dim; i++) - { Expression *e = (Expression *)keys->data[i]; - MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->key); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - e = (Expression *)values->data[i]; - m = (MATCH)e->implicitConvTo(tb->nextOf()); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - } - return result; - } - else - return Expression::implicitConvTo(t); -} - -MATCH AddrExp::implicitConvTo(Type *t) -{ -#if 0 - printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - //printf("\tresult = %d\n", result); - - if (result == MATCHnomatch) - { - // Look for pointers to functions where the functions are overloaded. - VarExp *ve; - FuncDeclaration *f; - - t = t->toBasetype(); - if (type->ty == Tpointer && type->next->ty == Tfunction && - t->ty == Tpointer && t->next->ty == Tfunction && - e1->op == TOKvar) - { - ve = (VarExp *)e1; - f = ve->var->isFuncDeclaration(); - if (f && f->overloadExactMatch(t->next, m)) - result = MATCHexact; - } - } - //printf("\tresult = %d\n", result); - return result; -} - -MATCH SymOffExp::implicitConvTo(Type *t) -{ -#if 0 - printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - //printf("\tresult = %d\n", result); - - if (result == MATCHnomatch) - { - // Look for pointers to functions where the functions are overloaded. - FuncDeclaration *f; - - t = t->toBasetype(); - if (type->ty == Tpointer && type->next->ty == Tfunction && - t->ty == Tpointer && t->next->ty == Tfunction) - { - f = var->isFuncDeclaration(); - if (f && f->overloadExactMatch(t->next, m)) - result = MATCHexact; - } - } - //printf("\tresult = %d\n", result); - return result; -} - -MATCH DelegateExp::implicitConvTo(Type *t) -{ -#if 0 - printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - - if (result == 0) - { - // Look for pointers to functions where the functions are overloaded. - - t = t->toBasetype(); - if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction && - t->ty == Tdelegate && t->nextOf()->ty == Tfunction) - { - if (func && func->overloadExactMatch(t->nextOf(), m)) - result = MATCHexact; - } - } - return result; -} - -MATCH CondExp::implicitConvTo(Type *t) -{ - MATCH m1; - MATCH m2; - - m1 = e1->implicitConvTo(t); - m2 = e2->implicitConvTo(t); - - // Pick the worst match - return (m1 < m2) ? m1 : m2; -} - - -/* ==================== castTo ====================== */ - -/************************************** - * Do an explicit cast. - */ - -Expression *Expression::castTo(Scope *sc, Type *t) -{ - //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars()); -#if 0 - printf("Expression::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t) - return this; - Expression *e = this; - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { - // Do (type *) cast of (type [dim]) - if (tb->ty == Tpointer && - typeb->ty == Tsarray - ) - { - //printf("Converting [dim] to *\n"); - - if (typeb->size(loc) == 0) - e = new NullExp(loc); - else - e = new AddrExp(loc, e); - } -#if 0 - else if (tb->ty == Tdelegate && type->ty != Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - return toDelegate(sc, tf->nextOf()); - } -#endif - else - { - e = new CastExp(loc, e, tb); - } - } - else - { - e = e->copy(); // because of COW for assignment to e->type - } - assert(e != this); - e->type = t; - //printf("Returning: %s\n", e->toChars()); - return e; -} - - -Expression *ErrorExp::castTo(Scope *sc, Type *t) -{ - return this; -} - - -Expression *RealExp::castTo(Scope *sc, Type *t) -{ Expression *e = this; - if (type != t) - { - if ((type->isreal() && t->isreal()) || - (type->isimaginary() && t->isimaginary()) - ) - { e = copy(); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - - -Expression *ComplexExp::castTo(Scope *sc, Type *t) -{ Expression *e = this; - if (type != t) - { - if (type->iscomplex() && t->iscomplex()) - { e = copy(); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - - -Expression *NullExp::castTo(Scope *sc, Type *t) -{ NullExp *e; - Type *tb; - - //printf("NullExp::castTo(t = %p)\n", t); - if (type == t) - { - committed = 1; - return this; - } - e = (NullExp *)copy(); - e->committed = 1; - tb = t->toBasetype(); - e->type = type->toBasetype(); - if (tb != e->type) - { - // NULL implicitly converts to any pointer type or dynamic array - if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid && - (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray || - tb->ty == Tdelegate)) - { -#if 0 - if (tb->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) - { - return Expression::castTo(sc, t); - } - } -#endif - } - else - { - return e->Expression::castTo(sc, t); - } - } - e->type = t; - return e; -} - -Expression *StringExp::castTo(Scope *sc, Type *t) -{ - /* This follows copy-on-write; any changes to 'this' - * will result in a copy. - * The this->string member is considered immutable. - */ - int copied = 0; - - //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed); - - if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) - { - error("cannot convert string literal to void*"); - return new ErrorExp(); - } - - StringExp *se = this; - if (!committed) - { se = (StringExp *)copy(); - se->committed = 1; - copied = 1; - } - - if (type == t) - { - return se; - } - - Type *tb = t->toBasetype(); - //printf("\ttype = %s\n", type->toChars()); - if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate) - return Expression::castTo(sc, t); - - Type *typeb = type->toBasetype(); - if (typeb == tb) - { - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - se->type = t; - return se; - } - - if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer) - { if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - goto Lcast; - } - if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer) - { if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - goto Lcast; - } - - if (typeb->nextOf()->size() == tb->nextOf()->size()) - { - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - if (tb->ty == Tsarray) - goto L2; // handle possible change in static array dimension - se->type = t; - return se; - } - - if (committed) - goto Lcast; - -#define X(tf,tt) ((tf) * 256 + (tt)) - { - OutBuffer buffer; - size_t newlen = 0; - int tfty = typeb->nextOf()->toBasetype()->ty; - int ttty = tb->nextOf()->toBasetype()->ty; - switch (X(tfty, ttty)) - { - case X(Tchar, Tchar): - case X(Twchar,Twchar): - case X(Tdchar,Tdchar): - break; - - case X(Tchar, Twchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); - if (p) - error("%s", p); - else - buffer.writeUTF16(c); - } - newlen = buffer.offset / 2; - buffer.writeUTF16(0); - goto L1; - - case X(Tchar, Tdchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); - if (p) - error("%s", p); - buffer.write4(c); - newlen++; - } - buffer.write4(0); - goto L1; - - case X(Twchar,Tchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); - if (p) - error("%s", p); - else - buffer.writeUTF8(c); - } - newlen = buffer.offset; - buffer.writeUTF8(0); - goto L1; - - case X(Twchar,Tdchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); - if (p) - error("%s", p); - buffer.write4(c); - newlen++; - } - buffer.write4(0); - goto L1; - - case X(Tdchar,Tchar): - for (size_t u = 0; u < len; u++) - { - unsigned c = ((unsigned *)se->string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - buffer.writeUTF8(c); - newlen++; - } - newlen = buffer.offset; - buffer.writeUTF8(0); - goto L1; - - case X(Tdchar,Twchar): - for (size_t u = 0; u < len; u++) - { - unsigned c = ((unsigned *)se->string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - buffer.writeUTF16(c); - newlen++; - } - newlen = buffer.offset / 2; - buffer.writeUTF16(0); - goto L1; - - L1: - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - se->string = buffer.extractData(); - se->len = newlen; - { - d_uns64 szx = tb->nextOf()->size(); - assert(szx <= 255); - se->sz = (unsigned char)szx; - } - break; - - default: - assert(typeb->nextOf()->size() != tb->nextOf()->size()); - goto Lcast; - } - } -#undef X -L2: - assert(copied); - - // See if need to truncate or extend the literal - if (tb->ty == Tsarray) - { - dinteger_t dim2 = ((TypeSArray *)tb)->dim->toInteger(); - - //printf("dim from = %d, to = %d\n", (int)se->len, (int)dim2); - - // Changing dimensions - if (dim2 != se->len) - { - // Copy when changing the string literal - unsigned newsz = se->sz; - void *s; - int d; - - d = (dim2 < se->len) ? dim2 : se->len; - s = (unsigned char *)mem.malloc((dim2 + 1) * newsz); - memcpy(s, se->string, d * newsz); - // Extend with 0, add terminating 0 - memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz); - se->string = s; - se->len = dim2; - } - } - se->type = t; - return se; - -Lcast: - Expression *e = new CastExp(loc, se, t); - e->type = t; // so semantic() won't be run on e - return e; -} - -Expression *AddrExp::castTo(Scope *sc, Type *t) -{ - Type *tb; - -#if 0 - printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - Expression *e = this; - - tb = t->toBasetype(); - type = type->toBasetype(); - if (tb != type) - { - // Look for pointers to functions where the functions are overloaded. - VarExp *ve; - FuncDeclaration *f; - - if (type->ty == Tpointer && type->next->ty == Tfunction && - tb->ty == Tpointer && tb->next->ty == Tfunction && - e1->op == TOKvar) - { - ve = (VarExp *)e1; - f = ve->var->isFuncDeclaration(); - if (f) - { - f = f->overloadExactMatch(tb->next, m); - if (f) - { - e = new VarExp(loc, f); - e->type = f->type; - e = new AddrExp(loc, e); - e->type = t; - return e; - } - } - } - e = Expression::castTo(sc, t); - } - e->type = t; - return e; -} - - -Expression *TupleExp::castTo(Scope *sc, Type *t) -{ TupleExp *e = (TupleExp *)copy(); - e->exps = (Expressions *)exps->copy(); - for (size_t i = 0; i < e->exps->dim; i++) - { Expression *ex = (Expression *)e->exps->data[i]; - ex = ex->castTo(sc, t); - e->exps->data[i] = (void *)ex; - } - return e; -} - - -Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t) - return this; - ArrayLiteralExp *e = this; - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if ((tb->ty == Tarray || tb->ty == Tsarray) && - (typeb->ty == Tarray || typeb->ty == Tsarray) && - // Not trying to convert non-void[] to void[] - !(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)) - { - if (tb->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)tb; - if (elements->dim != tsa->dim->toInteger()) - goto L1; - } - - e = (ArrayLiteralExp *)copy(); - e->elements = (Expressions *)elements->copy(); - for (size_t i = 0; i < elements->dim; i++) - { Expression *ex = (*elements)[i]; - ex = ex->castTo(sc, tb->nextOf()); - (*e->elements)[i] = ex; - } - e->type = t; - return e; - } - if (tb->ty == Tpointer && typeb->ty == Tsarray) - { - e = (ArrayLiteralExp *)copy(); - e->type = typeb->nextOf()->pointerTo(); - } -#if DMDV2 - else if (tb->ty == Tvector && - (typeb->ty == Tarray || typeb->ty == Tsarray)) - { - // Convert array literal to vector type - TypeVector *tv = (TypeVector *)tb; - TypeSArray *tbase = (TypeSArray *)tv->basetype; - assert(tbase->ty == Tsarray); - if (elements->dim != tbase->dim->toInteger()) - goto L1; - - e = (ArrayLiteralExp *)copy(); - e->elements = (Expressions *)elements->copy(); - Type *telement = tv->elementType(); - for (size_t i = 0; i < elements->dim; i++) - { Expression *ex = (*elements)[i]; - ex = ex->castTo(sc, telement); - (*e->elements)[i] = ex; - } - Expression *ev = new VectorExp(loc, e, tb); - ev = ev->semantic(sc); - return ev; - } -#endif -L1: - return e->Expression::castTo(sc, t); -} - -Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) -{ - if (type == t) - return this; - AssocArrayLiteralExp *e = this; - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if (tb->ty == Taarray && typeb->ty == Taarray && - tb->nextOf()->toBasetype()->ty != Tvoid) - { - e = (AssocArrayLiteralExp *)copy(); - e->keys = (Expressions *)keys->copy(); - e->values = (Expressions *)values->copy(); - assert(keys->dim == values->dim); - for (size_t i = 0; i < keys->dim; i++) - { Expression *ex = (Expression *)values->data[i]; - ex = ex->castTo(sc, tb->nextOf()); - e->values->data[i] = (void *)ex; - - ex = (Expression *)keys->data[i]; - ex = ex->castTo(sc, ((TypeAArray *)tb)->index); - e->keys->data[i] = (void *)ex; - } - e->type = t; - return e; - } - return e->Expression::castTo(sc, t); -} - -Expression *SymOffExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - Expression *e = this; - - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { - // Look for pointers to functions where the functions are overloaded. - FuncDeclaration *f; - - if (typeb->ty == Tpointer && typeb->next->ty == Tfunction && - tb->ty == Tpointer && tb->next->ty == Tfunction) - { - f = var->isFuncDeclaration(); - if (f) - { - f = f->overloadExactMatch(tb->next, m); - if (f) - { -#if DMDV2 - if (tb->ty == Tdelegate) - { - if (f->needThis() && hasThis(sc)) - { - e = new DelegateExp(loc, new ThisExp(loc), f); - e = e->semantic(sc); - } - else if (f->isNested()) - { - e = new DelegateExp(loc, new IntegerExp(0), f); - e = e->semantic(sc); - } - else if (f->needThis()) - { error("no 'this' to create delegate for %s", f->toChars()); - return new ErrorExp(); - } - else - { error("cannot cast from function pointer to delegate"); - return new ErrorExp(); - } - } - else -#endif - { - e = new SymOffExp(loc, f, 0); - e->type = t; - } -#if DMDV2 - f->tookAddressOf++; -#endif - return e; - } - } - } - e = Expression::castTo(sc, t); - } - else - { - e->type = t; - } - return e; -} - -Expression *DelegateExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - static char msg[] = "cannot form delegate due to covariant return type"; - - Expression *e = this; - Type *tb = t->toBasetype(); - type = type->toBasetype(); - if (tb != type || hasOverloads) - { - // Look for delegates to functions where the functions are overloaded. - FuncDeclaration *f; - - if (type->ty == Tdelegate && type->next->ty == Tfunction && - tb->ty == Tdelegate && tb->next->ty == Tfunction) - { - if (func) - { - f = func->overloadExactMatch(tb->next, m); - if (f) - { int offset; - if (f->tintro && f->tintro->next->isBaseOf(f->type->next, &offset) && offset) - error("%s", msg); - e = new DelegateExp(loc, e1, f); - e->type = t; - return e; - } - if (func->tintro) - error("%s", msg); - } - } - e = Expression::castTo(sc, t); - } - else - { int offset; - - if (func->tintro && func->tintro->next->isBaseOf(func->type->next, &offset) && offset) - error("%s", msg); - } - e->type = t; - return e; -} - -Expression *CondExp::castTo(Scope *sc, Type *t) -{ - Expression *e = this; - - if (type != t) - { - if (1 || e1->op == TOKstring || e2->op == TOKstring) - { e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t)); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - -/* ==================== ====================== */ - -/**************************************** - * Scale addition/subtraction to/from pointer. - */ - -Expression *BinExp::scaleFactor(Scope *sc) -{ d_uns64 stride; - Type *t1b = e1->type->toBasetype(); - Type *t2b = e2->type->toBasetype(); - - if (t1b->ty == Tpointer && t2b->isintegral()) - { // Need to adjust operator by the stride - // Replace (ptr + int) with (ptr + (int * stride)) - Type *t = Type::tptrdiff_t; - - stride = t1b->nextOf()->size(loc); - if (!t->equals(t2b)) - e2 = e2->castTo(sc, t); - // LDC: llvm uses typesafe pointer arithmetic - #if !IN_LLVM - if (t1b->next->isbit()) - // BUG: should add runtime check for misaligned offsets - // This perhaps should be done by rewriting as &p[i] - // and letting back end do it. - e2 = new UshrExp(loc, e2, new IntegerExp(0, 3, t)); - else - e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t)); - #endif - e2->type = t; - type = e1->type; - } - else if (t2b->ty == Tpointer && t1b->isintegral()) - { // Need to adjust operator by the stride - // Replace (int + ptr) with (ptr + (int * stride)) - Type *t = Type::tptrdiff_t; - Expression *e; - - stride = t2b->nextOf()->size(loc); - if (!t->equals(t1b)) - e = e1->castTo(sc, t); - else - e = e1; - #if !IN_LLVM - if (t2b->next->isbit()) - // BUG: should add runtime check for misaligned offsets - e = new UshrExp(loc, e, new IntegerExp(0, 3, t)); - else - e = new MulExp(loc, e, new IntegerExp(0, stride, t)); - #endif - e->type = t; - type = e2->type; - e1 = e2; - e2 = e; - } - return this; -} - -/************************************ - * Bring leaves to common type. - */ - -Expression *BinExp::typeCombine(Scope *sc) -{ - Type *t1; - Type *t2; - Type *t; - TY ty; - - //printf("BinExp::typeCombine()\n"); - //dump(0); - - e1 = e1->integralPromotions(sc); - e2 = e2->integralPromotions(sc); - - // BUG: do toBasetype() - t1 = e1->type; - t2 = e2->type; - assert(t1); - - //if (t1) printf("\tt1 = %s\n", t1->toChars()); - //if (t2) printf("\tt2 = %s\n", t2->toChars()); -#ifdef DEBUG - if (!t2) printf("\te2 = '%s'\n", e2->toChars()); -#endif - assert(t2); - - Type *t1b = t1->toBasetype(); - Type *t2b = t2->toBasetype(); - - ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty]; - if (ty != Terror) - { TY ty1; - TY ty2; - - ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty]; - ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty]; - - if (t1b->ty == ty1) // if no promotions - { - if (t1 == t2) - { - if (!type) - type = t1; - return this; - } - - if (t1b == t2b) - { - if (!type) - type = t1b; - return this; - } - } - - if (!type) - type = Type::basic[ty]; - - t1 = Type::basic[ty1]; - t2 = Type::basic[ty2]; - e1 = e1->castTo(sc, t1); - e2 = e2->castTo(sc, t2); -#if 0 - if (type != Type::basic[ty]) - { t = type; - type = Type::basic[ty]; - return castTo(sc, t); - } -#endif - //printf("after typeCombine():\n"); - //dump(0); - //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2); - return this; - } - - t = t1; - if (t1 == t2) - { - if ((t1->ty == Tstruct || t1->ty == Tclass) && - (op == TOKmin || op == TOKadd)) - goto Lincompatible; - } - else if (t1->isintegral() && t2->isintegral()) - { - printf("t1 = %s, t2 = %s\n", t1->toChars(), t2->toChars()); - int sz1 = t1->size(); - int sz2 = t2->size(); - int sign1 = t1->isunsigned() == 0; - int sign2 = t2->isunsigned() == 0; - - if (sign1 == sign2) - { - if (sz1 < sz2) - goto Lt2; - else - goto Lt1; - } - if (!sign1) - { - if (sz1 >= sz2) - goto Lt1; - else - goto Lt2; - } - else - { - if (sz2 >= sz1) - goto Lt2; - else - goto Lt1; - } - } - else if (t1->ty == Tpointer && t2->ty == Tpointer) - { - // Bring pointers to compatible type - Type *t1n = t1->next; - Type *t2n = t2->next; - -//t1->print(); -//t2->print(); -//if (t1n == t2n) *(char *)0 = 0; - assert(t1n != t2n); - if (t1n->ty == Tvoid) // pointers to void are always compatible - t = t2; - else if (t2n->ty == Tvoid) - ; - else if (t1n->ty == Tclass && t2n->ty == Tclass) - { ClassDeclaration *cd1 = t1n->isClassHandle(); - ClassDeclaration *cd2 = t2n->isClassHandle(); - int offset; - - if (cd1->isBaseOf(cd2, &offset)) - { - if (offset) - e2 = e2->castTo(sc, t); - } - else if (cd2->isBaseOf(cd1, &offset)) - { - t = t2; - if (offset) - e1 = e1->castTo(sc, t); - } - else - goto Lincompatible; - } - else - goto Lincompatible; - } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && - e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid) - { /* (T[n] op void*) - * (T[] op void*) - */ - goto Lx1; - } - else if ((t2->ty == Tsarray || t2->ty == Tarray) && - e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid) - { /* (void* op T[n]) - * (void* op T[]) - */ - goto Lx2; - } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) - { - if (t1->ty == Tsarray && e2->op == TOKarrayliteral) - goto Lt1; - goto Lt2; - } - else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1)) - { - if (t2->ty == Tsarray && e1->op == TOKarrayliteral) - goto Lt2; - goto Lt1; - } - else if (t1->ty == Tclass || t2->ty == Tclass) - { - while (1) - { - int i1 = e2->implicitConvTo(t1); - int i2 = e1->implicitConvTo(t2); - - if (i1 && i2) - { - // We have the case of class vs. void*, so pick class - if (t1->ty == Tpointer) - i1 = 0; - else if (t2->ty == Tpointer) - i2 = 0; - } - - if (i2) - { - goto Lt2; - } - else if (i1) - { - goto Lt1; - } - else if (t1->ty == Tclass && t2->ty == Tclass) - { TypeClass *tc1 = (TypeClass *)t1; - TypeClass *tc2 = (TypeClass *)t2; - - /* Pick 'tightest' type - */ - ClassDeclaration *cd1 = tc1->sym->baseClass; - ClassDeclaration *cd2 = tc2->sym->baseClass; - - if (cd1 && cd2) - { t1 = cd1->type; - t2 = cd2->type; - } - else if (cd1) - t1 = cd1->type; - else if (cd2) - t2 = cd2->type; - else - goto Lincompatible; - } - else - goto Lincompatible; - } - } - else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2)) - { - goto Lt2; - } -//else if (e2->op == TOKstring) { printf("test2\n"); } - else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1)) - { - goto Lt1; - } - else if (t1->ty == Tsarray && t2->ty == Tsarray && - e2->implicitConvTo(t1->nextOf()->arrayOf())) - { - Lx1: - t = t1->nextOf()->arrayOf(); - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - } - else if (t1->ty == Tsarray && t2->ty == Tsarray && - e1->implicitConvTo(t2->nextOf()->arrayOf())) - { - Lx2: - t = t2->nextOf()->arrayOf(); - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - } - else if (t1->isintegral() && t2->isintegral()) - { - assert(0); - } - else if (e1->isArrayOperand() && t1->ty == Tarray && - e2->implicitConvTo(t1->nextOf())) - { // T[] op T - e2 = e2->castTo(sc, t1->nextOf()); - t = t1->nextOf()->arrayOf(); - } - else if (e2->isArrayOperand() && t2->ty == Tarray && - e1->implicitConvTo(t2->nextOf())) - { // T op T[] - e1 = e1->castTo(sc, t2->nextOf()); - t = t2->nextOf()->arrayOf(); - - //printf("test %s\n", e->toChars()); - e1 = e1->optimize(WANTvalue); - if (isCommutative() && e1->isConst()) - { /* Swap operands to minimize number of functions generated - */ - //printf("swap %s\n", e->toChars()); - Expression *tmp = e1; - e1 = e2; - e2 = tmp; - } - } - else - { - Lincompatible: - incompatibleTypes(); - type = Type::terror; - e1 = new ErrorExp(); - e2 = new ErrorExp(); - return new ErrorExp(); - } -Lret: - if (!type) - type = t; - //dump(0); - return this; - - -Lt1: - e2 = e2->castTo(sc, t1); - t = t1; - goto Lret; - -Lt2: - e1 = e1->castTo(sc, t2); - t = t2; - goto Lret; -} - -/*********************************** - * Do integral promotions (convertchk). - * Don't convert to - */ - -Expression *Expression::integralPromotions(Scope *sc) -{ - Expression *e = this; - - //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars()); - switch (type->toBasetype()->ty) - { - case Tvoid: - error("void has no value"); - return new ErrorExp(); - - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: - case Tbit: - case Tbool: - case Tchar: - case Twchar: - e = e->castTo(sc, Type::tint32); - break; - - case Tdchar: - e = e->castTo(sc, Type::tuns32); - break; - } - return e; -} - diff --git a/dmd/class.c b/dmd/class.c deleted file mode 100644 index 84300229..00000000 --- a/dmd/class.c +++ /dev/null @@ -1,1595 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include // mem{cpy|set}() - -#include "root.h" -#include "rmem.h" - -#include "enum.h" -#include "init.h" -#include "attrib.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" -#include "mtype.h" -#include "scope.h" -#include "module.h" -#include "expression.h" -#include "statement.h" - -/********************************* ClassDeclaration ****************************/ - -ClassDeclaration *ClassDeclaration::classinfo; -ClassDeclaration *ClassDeclaration::object; -ClassDeclaration *ClassDeclaration::errorException; - -ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) - : AggregateDeclaration(loc, id) -{ - static char msg[] = "only object.d can define this reserved class name"; - - if (baseclasses) - // Actually, this is a transfer - this->baseclasses = baseclasses; - else - this->baseclasses = new BaseClasses(); - baseClass = NULL; - - interfaces_dim = 0; - interfaces = NULL; - - vtblInterfaces = NULL; - - //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses->dim); - - // For forward references - type = new TypeClass(this); - handle = type; - - ctor = NULL; - defaultCtor = NULL; - staticCtor = NULL; - staticDtor = NULL; - -#if IN_DMD - vtblsym = NULL; -#endif - vclassinfo = NULL; - - if (id) - { // Look for special class names - - if (id == Id::__sizeof || id == Id::__xalignof || id == Id::mangleof) - error("illegal class name"); - - // BUG: What if this is the wrong TypeInfo, i.e. it is nested? - if (id->toChars()[0] == 'T') - { - if (id == Id::TypeInfo) - { if (Type::typeinfo) - Type::typeinfo->error("%s", msg); - Type::typeinfo = this; - } - - if (id == Id::TypeInfo_Class) - { if (Type::typeinfoclass) - Type::typeinfoclass->error("%s", msg); - Type::typeinfoclass = this; - } - - if (id == Id::TypeInfo_Interface) - { if (Type::typeinfointerface) - Type::typeinfointerface->error("%s", msg); - Type::typeinfointerface = this; - } - - if (id == Id::TypeInfo_Struct) - { if (Type::typeinfostruct) - Type::typeinfostruct->error("%s", msg); - Type::typeinfostruct = this; - } - - if (id == Id::TypeInfo_Typedef) - { if (Type::typeinfotypedef) - Type::typeinfotypedef->error("%s", msg); - Type::typeinfotypedef = this; - } - - if (id == Id::TypeInfo_Pointer) - { if (Type::typeinfopointer) - Type::typeinfopointer->error("%s", msg); - Type::typeinfopointer = this; - } - - if (id == Id::TypeInfo_Array) - { if (Type::typeinfoarray) - Type::typeinfoarray->error("%s", msg); - Type::typeinfoarray = this; - } - - if (id == Id::TypeInfo_StaticArray) - { //if (Type::typeinfostaticarray) - //Type::typeinfostaticarray->error("%s", msg); - Type::typeinfostaticarray = this; - } - - if (id == Id::TypeInfo_AssociativeArray) - { if (Type::typeinfoassociativearray) - Type::typeinfoassociativearray->error("%s", msg); - Type::typeinfoassociativearray = this; - } - - if (id == Id::TypeInfo_Enum) - { if (Type::typeinfoenum) - Type::typeinfoenum->error("%s", msg); - Type::typeinfoenum = this; - } - - if (id == Id::TypeInfo_Function) - { if (Type::typeinfofunction) - Type::typeinfofunction->error("%s", msg); - Type::typeinfofunction = this; - } - - if (id == Id::TypeInfo_Delegate) - { if (Type::typeinfodelegate) - Type::typeinfodelegate->error("%s", msg); - Type::typeinfodelegate = this; - } - - if (id == Id::TypeInfo_Tuple) - { if (Type::typeinfotypelist) - Type::typeinfotypelist->error("%s", msg); - Type::typeinfotypelist = this; - } - -#if DMDV2 - if (id == Id::TypeInfo_Const) - { if (Type::typeinfoconst) - Type::typeinfoconst->error("%s", msg); - Type::typeinfoconst = this; - } - - if (id == Id::TypeInfo_Invariant) - { if (Type::typeinfoinvariant) - Type::typeinfoinvariant->error("%s", msg); - Type::typeinfoinvariant = this; - } - - if (id == Id::TypeInfo_Shared) - { if (Type::typeinfoshared) - Type::typeinfoshared->error("%s", msg); - Type::typeinfoshared = this; - } - - if (id == Id::TypeInfo_Wild) - { if (Type::typeinfowild) - Type::typeinfowild->error("%s", msg); - Type::typeinfowild = this; - } -#endif - } - - if (id == Id::Object) - { if (object) - object->error("%s", msg); - object = this; - } - - if (id == Id::Error) - { if (errorException) - errorException->error("%s", msg); - errorException = this; - } - - if (id == Id::ClassInfo) - { if (classinfo) - classinfo->error("%s", msg); - classinfo = this; - } - - if (id == Id::ModuleInfo) - { if (Module::moduleinfo) - Module::moduleinfo->error("%s", msg); - Module::moduleinfo = this; - } - } - - com = 0; - isscope = 0; - isabstract = 0; - isnested = 0; - vthis = NULL; - inuse = 0; -} - -Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) -{ - ClassDeclaration *cd; - - //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - cd = (ClassDeclaration *)s; - else - cd = new ClassDeclaration(loc, ident, NULL); - - cd->storage_class |= storage_class; - - cd->baseclasses->setDim(this->baseclasses->dim); - for (size_t i = 0; i < cd->baseclasses->dim; i++) - { - BaseClass *b = (*this->baseclasses)[i]; - BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); - (*cd->baseclasses)[i] = b2; - } - - ScopeDsymbol::syntaxCopy(cd); - return cd; -} - -void ClassDeclaration::semantic(Scope *sc) -{ - //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); - //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : ""); - //printf("sc->stc = %x\n", sc->stc); - - //{ static int n; if (++n == 20) *(char*)0=0; } - - if (!ident) // if anonymous class - { const char *id = "__anonclass"; - - ident = Identifier::generateId(id); - } - - if (!sc) - sc = scope; - if (!parent && sc->parent && !sc->parent->isModule()) - parent = sc->parent; - - type = type->semantic(loc, sc); - handle = type; - - if (!members) // if forward reference - { //printf("\tclass '%s' is forward referenced\n", toChars()); - return; - } - if (symtab) - { if (sizeok == SIZEOKdone || !scope) - { //printf("\tsemantic for '%s' is already completed\n", toChars()); - return; // semantic() already completed - } - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - unsigned dprogress_save = Module::dprogress; -#ifdef IN_GCC - methods.setDim(0); -#endif - - if (sc->stc & STCdeprecated) - { - isdeprecated = 1; - } - - // Expand any tuples in baseclasses[] - for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = (*baseclasses)[i]; - b->type = b->type->semantic(loc, sc); - Type *tb = b->type->toBasetype(); - - if (tb->ty == Ttuple) - { TypeTuple *tup = (TypeTuple *)tb; - enum PROT protection = b->protection; - baseclasses->remove(i); - size_t dim = Parameter::dim(tup->arguments); - for (size_t j = 0; j < dim; j++) - { Parameter *arg = Parameter::getNth(tup->arguments, j); - b = new BaseClass(arg->type, protection); - baseclasses->insert(i + j, b); - } - } - else - i++; - } - - // See if there's a base class as first in baseclasses[] - if (baseclasses->dim) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (*baseclasses)[0]; - //b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty != Tclass) - { if (b->type != Type::terror) - error("base type must be class or interface, not %s", b->type->toChars()); - baseclasses->remove(0); - } - else - { - tc = (TypeClass *)(tb); - - if (tc->sym->isDeprecated()) - { - if (!isDeprecated()) - { - // Deriving from deprecated class makes this one deprecated too - isdeprecated = true; - - tc->checkDeprecated(loc, sc); - } - } - - if (tc->sym->isInterfaceDeclaration()) - ; - else - { - for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass) - { - if (cdb == this) - { - error("circular inheritance"); - baseclasses->remove(0); - goto L7; - } - } - if (!tc->sym->symtab || tc->sym->sizeok == SIZEOKnone) - { // Try to resolve forward reference - if (/*sc->mustsemantic &&*/ tc->sym->scope) - tc->sym->semantic(NULL); - } - if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == SIZEOKnone) - { - //printf("%s: forward reference of base class %s\n", toChars(), tc->sym->toChars()); - //error("forward reference of base class %s", baseClass->toChars()); - // Forward reference of base class, try again later - //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - if (tc->sym->scope) - tc->sym->scope->module->addDeferredSemantic(tc->sym); - scope->module->addDeferredSemantic(this); - return; - } - else - { baseClass = tc->sym; - b->base = baseClass; - } - L7: ; - } - } - } - - // Treat the remaining entries in baseclasses as interfaces - // Check for errors, handle forward references - for (size_t i = (baseClass ? 1 : 0); i < baseclasses->dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (*baseclasses)[i]; - b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty == Tclass) - tc = (TypeClass *)tb; - else - tc = NULL; - if (!tc || !tc->sym->isInterfaceDeclaration()) - { if (b->type != Type::terror) - error("base type must be interface, not %s", b->type->toChars()); - baseclasses->remove(i); - continue; - } - else - { - if (tc->sym->isDeprecated()) - { - if (!isDeprecated()) - { - // Deriving from deprecated class makes this one deprecated too - isdeprecated = true; - - tc->checkDeprecated(loc, sc); - } - } - - // Check for duplicate interfaces - for (size_t j = (baseClass ? 1 : 0); j < i; j++) - { - BaseClass *b2 = (*baseclasses)[j]; - if (b2->base == tc->sym) - error("inherits from duplicate interface %s", b2->base->toChars()); - } - - if (!tc->sym->symtab) - { // Try to resolve forward reference - if (/*sc->mustsemantic &&*/ tc->sym->scope) - tc->sym->semantic(NULL); - } - - b->base = tc->sym; - if (!b->base->symtab || b->base->scope) - { - //error("forward reference of base class %s", baseClass->toChars()); - // Forward reference of base, try again later - //printf("\ttry later, forward reference of base %s\n", baseClass->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - if (tc->sym->scope) - tc->sym->scope->module->addDeferredSemantic(tc->sym); - scope->module->addDeferredSemantic(this); - return; - } - } - i++; - } - - - // If no base class, and this is not an Object, use Object as base class - if (!baseClass && ident != Id::Object) - { - if (!object) - { - error("missing or corrupt object.d"); - fatal(); - } - - Type *t = object->type; - t = t->semantic(loc, sc)->toBasetype(); - assert(t->ty == Tclass); - TypeClass *tc = (TypeClass *)t; - - BaseClass *b = new BaseClass(tc, PROTpublic); - baseclasses->shift(b); - - baseClass = tc->sym; - assert(!baseClass->isInterfaceDeclaration()); - b->base = baseClass; - } - - interfaces_dim = baseclasses->dim; - interfaces = baseclasses->tdata(); - - - if (baseClass) - { - if (baseClass->storage_class & STCfinal) - error("cannot inherit from final class %s", baseClass->toChars()); - - interfaces_dim--; - interfaces++; - - // Copy vtbl[] from base class - vtbl.setDim(baseClass->vtbl.dim); - memcpy(vtbl.tdata(), baseClass->vtbl.tdata(), sizeof(void *) * vtbl.dim); - - // Inherit properties from base class - com = baseClass->isCOMclass(); - isscope = baseClass->isscope; - vthis = baseClass->vthis; - } - else - { - // No base class, so this is the root of the class hierarchy - vtbl.setDim(0); - vtbl.push(this); // leave room for classinfo as first member - } - - protection = sc->protection; - storage_class |= sc->stc; - - if (sizeok == 0) - { - interfaceSemantic(sc); - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->addMember(sc, this, 1); - } - - /* If this is a nested class, add the hidden 'this' - * member which is a pointer to the enclosing scope. - */ - if (vthis) // if inheriting from nested class - { // Use the base class's 'this' member - isnested = 1; - if (storage_class & STCstatic) - error("static class cannot inherit from nested class %s", baseClass->toChars()); - if (toParent2() != baseClass->toParent2() && - (!toParent2() || - !baseClass->toParent2()->getType()->isBaseOf(toParent2()->getType(), NULL))) - { - if (toParent2()) - { - error("is nested within %s, but super class %s is nested within %s", - toParent2()->toChars(), - baseClass->toChars(), - baseClass->toParent2()->toChars()); - } - else - { - error("is not nested, but super class %s is nested within %s", - baseClass->toChars(), - baseClass->toParent2()->toChars()); - } - isnested = 0; - } - } - else if (!(storage_class & STCstatic)) - { Dsymbol *s = toParent2(); - if (s) - { - AggregateDeclaration *ad = s->isClassDeclaration(); - FuncDeclaration *fd = s->isFuncDeclaration(); - - - if (ad || fd) - { isnested = 1; - Type *t; - if (ad) - t = ad->handle; - else if (fd) - { AggregateDeclaration *ad2 = fd->isMember2(); - if (ad2) - t = ad2->handle; - else - { - t = new TypePointer(Type::tvoid); - t = t->semantic(0, sc); - } - } - else - assert(0); - assert(!vthis); - vthis = new ThisDeclaration(loc, t); - members->push(vthis); - } - } - } - } - - if (storage_class & STCauto) - error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?"); - if (storage_class & STCscope) - isscope = 1; - if (storage_class & STCabstract) - isabstract = 1; - - sc = sc->push(this); - sc->stc &= STCsafe | STCtrusted | STCsystem; - sc->parent = this; - sc->inunion = 0; - - if (isCOMclass()) - { -#if _WIN32 - sc->linkage = LINKwindows; -#else - /* This enables us to use COM objects under Linux and - * work with things like XPCOM - */ - sc->linkage = LINKc; -#endif - } - sc->protection = PROTpublic; - sc->explicitProtection = 0; - sc->structalign = STRUCTALIGN_DEFAULT; - structalign = sc->structalign; - if (baseClass) - { sc->offset = baseClass->structsize; - alignsize = baseClass->alignsize; -// if (isnested) -// sc->offset += PTRSIZE; // room for uplevel context pointer - } - else - { sc->offset = PTRSIZE * 2; // allow room for __vptr and __monitor - alignsize = PTRSIZE; - } - structsize = sc->offset; - Scope scsave = *sc; - size_t members_dim = members->dim; - sizeok = SIZEOKnone; - - /* Set scope so if there are forward references, we still might be able to - * resolve individual members like enums. - */ - for (size_t i = 0; i < members_dim; i++) - { Dsymbol *s = (*members)[i]; - /* There are problems doing this in the general case because - * Scope keeps track of things like 'offset' - */ - if (s->isEnumDeclaration() || - (s->isAggregateDeclaration() && s->ident) || - s->isTemplateMixin() || - s->isAttribDeclaration() || - s->isAliasDeclaration()) - { - //printf("[%d] setScope %s %s, sc = %p\n", i, s->kind(), s->toChars(), sc); - s->setScope(sc); - } - } - - for (size_t i = 0; i < members_dim; i++) - { Dsymbol *s = (*members)[i]; - s->semantic(sc); - } - - // Set the offsets of the fields and determine the size of the class - - unsigned offset = structsize; - bool isunion = isUnionDeclaration() != NULL; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->setFieldOffset(this, &offset, false); - } - sc->offset = structsize; - - if (global.gag && global.gaggedErrors != errors) - { // The type is no good, yet the error messages were gagged. - type = Type::terror; - } - - if (sizeok == 2) // failed due to forward references - { // semantic() failed due to forward references - // Unwind what we did, and defer it for later - - for (size_t i = 0; i < fields.dim; i++) - { Dsymbol *s = fields[i]; - VarDeclaration *vd = s->isVarDeclaration(); - if (vd) - vd->offset = 0; - } - fields.setDim(0); - structsize = 0; - alignsize = 0; - structalign = 0; - - sc = sc->pop(); - - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - - Module::dprogress = dprogress_save; - - //printf("\tsemantic('%s') failed due to forward references\n", toChars()); - return; - } - - //printf("\tsemantic('%s') successful\n", toChars()); - - //members->print(); - - /* Look for special member functions. - * They must be in this class, not in a base class. - */ - ctor = (CtorDeclaration *)search(0, Id::ctor, 0); - if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration())) - ctor = NULL; - -// dtor = (DtorDeclaration *)search(Id::dtor, 0); -// if (dtor && dtor->toParent() != this) -// dtor = NULL; - -// inv = (InvariantDeclaration *)search(Id::classInvariant, 0); -// if (inv && inv->toParent() != this) -// inv = NULL; - - // Can be in base class - aggNew = (NewDeclaration *)search(0, Id::classNew, 0); - aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); - - // If this class has no constructor, but base class does, create - // a constructor: - // this() { } - if (!ctor && baseClass && baseClass->ctor) - { - //printf("Creating default this(){} for class %s\n", toChars()); - CtorDeclaration *ctor = new CtorDeclaration(loc, 0, NULL, 0); - ctor->fbody = new CompoundStatement(0, new Statements()); - members->push(ctor); - ctor->addMember(sc, this, 1); - *sc = scsave; // why? What about sc->nofree? - ctor->semantic(sc); - this->ctor = ctor; - defaultCtor = ctor; - } - -#if 0 - if (baseClass) - { if (!aggDelete) - aggDelete = baseClass->aggDelete; - if (!aggNew) - aggNew = baseClass->aggNew; - } -#endif - - // Allocate instance of each new interface - sc->offset = structsize; - for (size_t i = 0; i < vtblInterfaces->dim; i++) - { - BaseClass *b = (*vtblInterfaces)[i]; - unsigned thissize = PTRSIZE; - - alignmember(structalign, thissize, &sc->offset); - assert(b->offset == 0); - b->offset = sc->offset; - - // Take care of single inheritance offsets - while (b->baseInterfaces_dim) - { - b = &b->baseInterfaces[0]; - b->offset = sc->offset; - } - - sc->offset += thissize; - if (alignsize < thissize) - alignsize = thissize; - } - structsize = sc->offset; - sizeok = SIZEOKdone; - Module::dprogress++; - - dtor = buildDtor(sc); - - sc->pop(); - -#if 0 // Do not call until toObjfile() because of forward references - // Fill in base class vtbl[]s - for (i = 0; i < vtblInterfaces->dim; i++) - { - BaseClass *b = (*vtblInterfaces)[i]; - - //b->fillVtbl(this, &b->vtbl, 1); - } -#endif - //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type); -} - -void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (!isAnonymous()) - { - buf->printf("%s ", kind()); - buf->writestring(toChars()); - if (baseclasses->dim) - buf->writestring(" : "); - } - for (size_t i = 0; i < baseclasses->dim; i++) - { - BaseClass *b = (*baseclasses)[i]; - - if (i) - buf->writeByte(','); - //buf->writestring(b->base->ident->toChars()); - b->type->toCBuffer(buf, NULL, hgs); - } - if (members) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writestring("}"); - } - else - buf->writeByte(';'); - buf->writenl(); -} - -#if 0 -void ClassDeclaration::defineRef(Dsymbol *s) -{ - ClassDeclaration *cd; - - AggregateDeclaration::defineRef(s); - cd = s->isClassDeclaration(); - baseType = cd->baseType; - cd->baseType = NULL; -} -#endif - -/********************************************* - * Determine if 'this' is a base class of cd. - * This is used to detect circular inheritance only. - */ - -int ClassDeclaration::isBaseOf2(ClassDeclaration *cd) -{ - if (!cd) - return 0; - //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); - for (size_t i = 0; i < cd->baseclasses->dim; i++) - { BaseClass *b = (*cd->baseclasses)[i]; - - if (b->base == this || isBaseOf2(b->base)) - return 1; - } - return 0; -} - -/******************************************* - * Determine if 'this' is a base class of cd. - */ - -int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) -{ - //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); - if (poffset) - *poffset = 0; - while (cd) - { - /* cd->baseClass might not be set if cd is forward referenced. - */ - if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) - { - cd->semantic(NULL); - if (!cd->baseClass) - cd->error("base class is forward referenced by %s", toChars()); - } - - if (this == cd->baseClass) - return 1; - - cd = cd->baseClass; - } - return 0; -} - -/********************************************* - * Determine if 'this' has complete base class information. - * This is used to detect forward references in covariant overloads. - */ - -int ClassDeclaration::isBaseInfoComplete() -{ - if (!baseClass) - return ident == Id::Object; - for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *b = (*baseclasses)[i]; - if (!b->base || !b->base->isBaseInfoComplete()) - return 0; - } - return 1; -} - -Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) -{ - Dsymbol *s; - //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); - - if (scope && !symtab) - { Scope *sc = scope; - sc->mustsemantic++; - // If speculatively gagged, ungag now. - unsigned oldgag = global.gag; - if (global.isSpeculativeGagging()) - global.gag = 0; - semantic(sc); - global.gag = oldgag; - sc->mustsemantic--; - } - - if (!members || !symtab) - { - error("is forward referenced when looking for '%s'", ident->toChars()); - //*(char*)0=0; - return NULL; - } - - s = ScopeDsymbol::search(loc, ident, flags); - if (!s) - { - // Search bases classes in depth-first, left to right order - - for (size_t i = 0; i < baseclasses->dim; i++) - { - BaseClass *b = (*baseclasses)[i]; - - if (b->base) - { - if (!b->base->symtab) - error("base %s is forward referenced", b->base->ident->toChars()); - else - { - s = b->base->search(loc, ident, flags); - if (s == this) // happens if s is nested in this and derives from this - s = NULL; - else if (s) - break; - } - } - } - } - return s; -} - -Dsymbol *ClassDeclaration::searchBase(Loc loc, Identifier *ident) -{ - // Search bases classes in depth-first, left to right order - - for (size_t i = 0; i < baseclasses->dim; i++) - { - BaseClass *b = (*baseclasses)[i]; - Dsymbol *cdb = b->type->isClassHandle(); - if (cdb->ident->equals(ident)) - return cdb; - cdb = ((ClassDeclaration *)cdb)->searchBase(loc, ident); - if (cdb) - return cdb; - } - return NULL; -} - -/********************************************************** - * fd is in the vtbl[] for this class. - * Return 1 if function is hidden (not findable through search). - */ - -#if DMDV2 -int isf(void *param, FuncDeclaration *fd) -{ - //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars()); - return param == fd; -} - -int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) -{ - //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars()); - Dsymbol *s = search(0, fd->ident, 4|2); - if (!s) - { //printf("not found\n"); - /* Because, due to a hack, if there are multiple definitions - * of fd->ident, NULL is returned. - */ - return 0; - } - FuncDeclaration *fdstart = s->toAlias()->isFuncDeclaration(); - //printf("%s fdstart = %p\n", s->kind(), fdstart); - if (overloadApply(fdstart, &isf, fd)) - return 0; - - return !fd->parent->isTemplateMixin(); -} -#endif - -/**************** - * Find virtual function matching identifier and type. - * Used to build virtual function tables for interface implementations. - */ - -FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) -{ - //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars()); - FuncDeclaration *fdmatch = NULL; - FuncDeclaration *fdambig = NULL; - - ClassDeclaration *cd = this; - Dsymbols *vtbl = &cd->vtbl; - while (1) - { - for (size_t i = 0; i < vtbl->dim; i++) - { - FuncDeclaration *fd = (*vtbl)[i]->isFuncDeclaration(); - if (!fd) - continue; // the first entry might be a ClassInfo - - //printf("\t[%d] = %s\n", i, fd->toChars()); - if (ident == fd->ident && - fd->type->covariant(tf) == 1) - { //printf("fd->parent->isClassDeclaration() = %p\n", fd->parent->isClassDeclaration()); - if (!fdmatch) - goto Lfd; - if (fd == fdmatch) - goto Lfdmatch; - - { - // Function type matcing: exact > covariant - int m1 = tf->equals(fd ->type) ? MATCHexact : MATCHnomatch; - int m2 = tf->equals(fdmatch->type) ? MATCHexact : MATCHnomatch; - if (m1 > m2) - goto Lfd; - else if (m1 < m2) - goto Lfdmatch; - } - - { - // The way of definition: non-mixin > mixin - int m1 = fd ->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch; - int m2 = fdmatch->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch; - if (m1 > m2) - goto Lfd; - else if (m1 < m2) - goto Lfdmatch; - } - - Lambig: - fdambig = fd; - //printf("Lambig fdambig = %s %s [%s]\n", fdambig->toChars(), fdambig->type->toChars(), fdambig->loc.toChars()); - continue; - - Lfd: - fdmatch = fd, fdambig = NULL; - //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch->toChars(), fdmatch->type->toChars(), fdmatch->loc.toChars()); - continue; - - Lfdmatch: - continue; - } - //else printf("\t\t%d\n", fd->type->covariant(tf)); - } - if (!cd) - break; - vtbl = &cd->vtblFinal; - cd = cd->baseClass; - } - - if (fdambig) - error("ambiguous virtual function %s", fdambig->toChars()); - return fdmatch; -} - -void ClassDeclaration::interfaceSemantic(Scope *sc) -{ - vtblInterfaces = new BaseClasses(); - vtblInterfaces->reserve(interfaces_dim); - - for (size_t i = 0; i < interfaces_dim; i++) - { - BaseClass *b = interfaces[i]; - - // If this is an interface, and it derives from a COM interface, - // then this is a COM interface too. - if (b->base->isCOMinterface()) - com = 1; - - vtblInterfaces->push(b); - b->copyBaseInterfaces(vtblInterfaces); - } -} - -/**************************************** - */ - -int ClassDeclaration::isCOMclass() -{ - return com; -} - -int ClassDeclaration::isCOMinterface() -{ - return 0; -} - -#if DMDV2 -int ClassDeclaration::isCPPinterface() -{ - return 0; -} -#endif - - -/**************************************** - */ - -int ClassDeclaration::isAbstract() -{ - if (isabstract) - return TRUE; - for (size_t i = 1; i < vtbl.dim; i++) - { - FuncDeclaration *fd = vtbl[i]->isFuncDeclaration(); - - //printf("\tvtbl[%d] = %p\n", i, fd); - if (!fd || fd->isAbstract()) - { - isabstract |= 1; - return TRUE; - } - } - return FALSE; -} - - -/**************************************** - * Returns !=0 if there's an extra member which is the 'this' - * pointer to the enclosing context (enclosing class or function) - */ - -int ClassDeclaration::isNested() -{ - return isnested; -} - -/**************************************** - * Determine if slot 0 of the vtbl[] is reserved for something else. - * For class objects, yes, this is where the classinfo ptr goes. - * For COM interfaces, no. - * For non-COM interfaces, yes, this is where the Interface ptr goes. - */ - -int ClassDeclaration::vtblOffset() -{ - return 1; -} - -/**************************************** - */ - -const char *ClassDeclaration::kind() -{ - return "class"; -} - -/**************************************** - */ - -void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ - aclasses->push(this); -} - -/********************************* InterfaceDeclaration ****************************/ - -InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) - : ClassDeclaration(loc, id, baseclasses) -{ - com = 0; - if (id == Id::IUnknown) // IUnknown is the root of all COM objects - com = 1; -} - -Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s) -{ - InterfaceDeclaration *id; - - if (s) - id = (InterfaceDeclaration *)s; - else - id = new InterfaceDeclaration(loc, ident, NULL); - - ClassDeclaration::syntaxCopy(id); - return id; -} - -void InterfaceDeclaration::semantic(Scope *sc) -{ - //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); - if (inuse) - return; - - if (!sc) - sc = scope; - if (!parent && sc->parent && !sc->parent->isModule()) - parent = sc->parent; - - type = type->semantic(loc, sc); - handle = type; - - if (!members) // if forward reference - { //printf("\tinterface '%s' is forward referenced\n", toChars()); - return; - } - if (symtab) // if already done - { if (!scope) - return; - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - if (sc->stc & STCdeprecated) - { - isdeprecated = true; - } - - // Expand any tuples in baseclasses[] - for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = (*baseclasses)[i]; - b->type = b->type->semantic(loc, sc); - Type *tb = b->type->toBasetype(); - - if (tb->ty == Ttuple) - { TypeTuple *tup = (TypeTuple *)tb; - enum PROT protection = b->protection; - baseclasses->remove(i); - size_t dim = Parameter::dim(tup->arguments); - for (size_t j = 0; j < dim; j++) - { Parameter *arg = Parameter::getNth(tup->arguments, j); - b = new BaseClass(arg->type, protection); - baseclasses->insert(i + j, b); - } - } - else - i++; - } - - // Check for errors, handle forward references - for (size_t i = 0; i < baseclasses->dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (*baseclasses)[i]; - b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty == Tclass) - tc = (TypeClass *)tb; - else - tc = NULL; - if (!tc || !tc->sym->isInterfaceDeclaration()) - { if (b->type != Type::terror) - error("base type must be interface, not %s", b->type->toChars()); - baseclasses->remove(i); - continue; - } - else - { - // Check for duplicate interfaces - for (size_t j = 0; j < i; j++) - { - BaseClass *b2 = (*baseclasses)[j]; - if (b2->base == tc->sym) - error("inherits from duplicate interface %s", b2->base->toChars()); - } - - b->base = tc->sym; - if (b->base == this || isBaseOf2(b->base)) - { - error("circular inheritance of interface"); - baseclasses->remove(i); - continue; - } - if (!b->base->symtab) - { // Try to resolve forward reference - if (sc->mustsemantic && b->base->scope) - b->base->semantic(NULL); - } - if (!b->base->symtab || b->base->scope || b->base->inuse) - { - //error("forward reference of base class %s", baseClass->toChars()); - // Forward reference of base, try again later - //printf("\ttry later, forward reference of base %s\n", b->base->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - return; - } - } - i++; - } - - interfaces_dim = baseclasses->dim; - interfaces = baseclasses->tdata(); - - interfaceSemantic(sc); - - if (vtblOffset()) - vtbl.push(this); // leave room at vtbl[0] for classinfo - - // Cat together the vtbl[]'s from base interfaces - for (size_t i = 0; i < interfaces_dim; i++) - { BaseClass *b = interfaces[i]; - - // Skip if b has already appeared - for (size_t k = 0; k < i; k++) - { - if (b == interfaces[k]) - goto Lcontinue; - } - - // Copy vtbl[] from base class - if (b->base->vtblOffset()) - { size_t d = b->base->vtbl.dim; - if (d > 1) - { - vtbl.reserve(d - 1); - for (size_t j = 1; j < d; j++) - vtbl.push(b->base->vtbl[j]); - } - } - else - { - vtbl.append(&b->base->vtbl); - } - - Lcontinue: - ; - } - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->addMember(sc, this, 1); - } - - sc = sc->push(this); - sc->stc &= STCsafe | STCtrusted | STCsystem; - sc->parent = this; - if (isCOMinterface()) - sc->linkage = LINKwindows; - sc->structalign = STRUCTALIGN_DEFAULT; - sc->protection = PROTpublic; - sc->explicitProtection = 0; - structalign = sc->structalign; - sc->offset = PTRSIZE * 2; - structsize = sc->offset; - inuse++; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->semantic(sc); - } - inuse--; - //members->print(); - sc->pop(); - //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); -} - - -/******************************************* - * Determine if 'this' is a base class of cd. - * (Actually, if it is an interface supported by cd) - * Output: - * *poffset offset to start of class - * OFFSET_RUNTIME must determine offset at runtime - * Returns: - * 0 not a base - * 1 is a base - */ - -int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) -{ - unsigned j; - - //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars()); - assert(!baseClass); - for (j = 0; j < cd->interfaces_dim; j++) - { - BaseClass *b = cd->interfaces[j]; - - //printf("\tbase %s\n", b->base->toChars()); - if (this == b->base) - { - //printf("\tfound at offset %d\n", b->offset); - if (poffset) - { *poffset = b->offset; - if (j && cd->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - } - return 1; - } - if (isBaseOf(b, poffset)) - { if (j && poffset && cd->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - return 1; - } - } - - if (cd->baseClass && isBaseOf(cd->baseClass, poffset)) - return 1; - - if (poffset) - *poffset = 0; - return 0; -} - - -int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset) -{ - //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars()); - for (unsigned j = 0; j < bc->baseInterfaces_dim; j++) - { - BaseClass *b = &bc->baseInterfaces[j]; - - if (this == b->base) - { - if (poffset) - { *poffset = b->offset; - if (j && bc->base->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - } - return 1; - } - if (isBaseOf(b, poffset)) - { if (j && poffset && bc->base->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - return 1; - } - } - if (poffset) - *poffset = 0; - return 0; -} - -/********************************************* - * Determine if 'this' has clomplete base class information. - * This is used to detect forward references in covariant overloads. - */ - -int InterfaceDeclaration::isBaseInfoComplete() -{ - assert(!baseClass); - for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *b = (*baseclasses)[i]; - if (!b->base || !b->base->isBaseInfoComplete ()) - return 0; - } - return 1; -} - -/**************************************** - * Determine if slot 0 of the vtbl[] is reserved for something else. - * For class objects, yes, this is where the ClassInfo ptr goes. - * For COM interfaces, no. - * For non-COM interfaces, yes, this is where the Interface ptr goes. - */ - -int InterfaceDeclaration::vtblOffset() -{ - if (isCOMinterface()) - return 0; - return 1; -} - -int InterfaceDeclaration::isCOMinterface() -{ - return com; -} - -#if DMDV2 -int InterfaceDeclaration::isCPPinterface() -{ - return cpp; -} -#endif - -/******************************************* - */ - -const char *InterfaceDeclaration::kind() -{ - return "interface"; -} - - -/******************************** BaseClass *****************************/ - -BaseClass::BaseClass() -{ - memset(this, 0, sizeof(BaseClass)); -} - -BaseClass::BaseClass(Type *type, enum PROT protection) -{ - //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); - this->type = type; - this->protection = protection; - base = NULL; - offset = 0; - - baseInterfaces_dim = 0; - baseInterfaces = NULL; -} - -/**************************************** - * Fill in vtbl[] for base class based on member functions of class cd. - * Input: - * vtbl if !=NULL, fill it in - * newinstance !=0 means all entries must be filled in by members - * of cd, not members of any base classes of cd. - * Returns: - * !=0 if any entries were filled in by members of cd (not exclusively - * by base classes) - */ - -int BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance) -{ - ClassDeclaration *id = base; - int result = 0; - - //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars()); - if (vtbl) - vtbl->setDim(base->vtbl.dim); - - // first entry is ClassInfo reference - for (size_t j = base->vtblOffset(); j < base->vtbl.dim; j++) - { - FuncDeclaration *ifd = base->vtbl[j]->isFuncDeclaration(); - FuncDeclaration *fd; - TypeFunction *tf; - - //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null"); - - assert(ifd); - // Find corresponding function in this class - tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL; - fd = cd->findFunc(ifd->ident, tf); - if (fd && !fd->isAbstract()) - { - //printf(" found\n"); - // Check that calling conventions match - if (fd->linkage != ifd->linkage) - fd->error("linkage doesn't match interface function"); - - // Check that it is current - if (newinstance && - fd->toParent() != cd && - ifd->toParent() == base) - cd->error("interface function %s.%s is not implemented", - id->toChars(), ifd->ident->toChars()); - - if (fd->toParent() == cd) - result = 1; - } - else - { - //printf(" not found\n"); - // BUG: should mark this class as abstract? - if (!cd->isAbstract()) - cd->error("interface function %s.%s isn't implemented", - id->toChars(), ifd->ident->toChars()); - fd = NULL; - } - if (vtbl) - (*vtbl)[j] = fd; - } - - return result; -} - -void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces) -{ - //printf("+copyBaseInterfaces(), %s\n", base->toChars()); -// if (baseInterfaces_dim) -// return; - - baseInterfaces_dim = base->interfaces_dim; - baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass)); - - //printf("%s.copyBaseInterfaces()\n", base->toChars()); - for (int i = 0; i < baseInterfaces_dim; i++) - { - BaseClass *b = &baseInterfaces[i]; - BaseClass *b2 = base->interfaces[i]; - - assert(b2->vtbl.dim == 0); // should not be filled yet - memcpy(b, b2, sizeof(BaseClass)); - - if (i) // single inheritance is i==0 - vtblInterfaces->push(b); // only need for M.I. - b->copyBaseInterfaces(vtblInterfaces); - } - //printf("-copyBaseInterfaces\n"); -} diff --git a/dmd/clone.c b/dmd/clone.c deleted file mode 100644 index b2bf8f6b..00000000 --- a/dmd/clone.c +++ /dev/null @@ -1,175 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" -#include "aggregate.h" -#include "scope.h" -#include "mtype.h" -#include "declaration.h" -#include "module.h" -#include "id.h" -#include "expression.h" -#include "statement.h" - - -/********************************* - * Generate expression that calls opClone() - * for each member of the struct - * (can be NULL for members that don't need one) - */ - -#if DMDV2 -Expression *StructDeclaration::cloneMembers() -{ - Expression *e = NULL; - - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - Type *tv = v->type->toBasetype(); - dinteger_t dim = (tv->ty == Tsarray ? 1 : 0); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - dim *= ((TypeSArray *)tv)->dim->toInteger(); - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->opclone) - { - - // this.v - Expression *ex = new ThisExp(0); - ex = new DotVarExp(0, ex, v, 0); - - if (dim == 1) - { // this.v.opClone() - ex = new DotVarExp(0, ex, sd->opclone, 0); - ex = new CallExp(0, ex); - } - else - { - // _callOpClones(&this.v, opclone, dim) - Expressions *args = new Expressions(); - args->push(new AddrExp(0, ex)); - args->push(new SymOffExp(0, sd->opclone, 0)); - args->push(new IntegerExp(dim)); - FuncDeclaration *ec = FuncDeclaration::genCfunc(Type::tvoid, "_callOpClones"); - ex = new CallExp(0, new VarExp(0, ec), args); - } - e = Expression::combine(e, ex); - } - } - } - return e; -} -#endif - -/***************************************** - * Create inclusive destructor for struct by aggregating - * all the destructors in dtors[] with the destructors for - * all the members. - */ - -FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) -{ - //printf("StructDeclaration::buildDtor() %s\n", toChars()); - Expression *e = NULL; - -#if DMDV2 - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - Type *tv = v->type->toBasetype(); - dinteger_t dim = (tv->ty == Tsarray ? 1 : 0); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - dim *= ((TypeSArray *)tv)->dim->toInteger(); - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->dtor) - { Expression *ex; - - // this.v - ex = new ThisExp(0); - ex = new DotVarExp(0, ex, v, 0); - - if (dim == 1) - { // this.v.dtor() - ex = new DotVarExp(0, ex, sd->dtor, 0); - ex = new CallExp(0, ex); - } - else - { - // Typeinfo.destroy(cast(void*)&this.v); - Expression *ea = new AddrExp(0, ex); - ea = new CastExp(0, ea, Type::tvoid->pointerTo()); - Expressions *args = new Expressions(); - args->push(ea); - - Expression *et = v->type->getTypeInfo(sc); - et = new DotIdExp(0, et, Id::destroy); - - ex = new CallExp(0, et, args); - } - e = Expression::combine(ex, e); // combine in reverse order - } - } - } - - /* Build our own "destructor" which executes e - */ - if (e) - { //printf("Building __fieldDtor()\n"); - DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__fieldDtor")); - dd->fbody = new ExpStatement(0, e); - dtors.shift(dd); - members->push(dd); - dd->semantic(sc); - } -#endif - - switch (dtors.dim) - { - case 0: - return NULL; - - case 1: - return (FuncDeclaration *)dtors.data[0]; - - default: - e = NULL; - for (size_t i = 0; i < dtors.dim; i++) - { FuncDeclaration *fd = (FuncDeclaration *)dtors.data[i]; - Expression *ex = new ThisExp(0); - ex = new DotVarExp(0, ex, fd); - ex = new CallExp(0, ex); - e = Expression::combine(ex, e); - } - DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__aggrDtor")); - dd->fbody = new ExpStatement(0, e); - members->push(dd); - dd->semantic(sc); - return dd; - } -} - - diff --git a/dmd/complex_t.h b/dmd/complex_t.h deleted file mode 100644 index fa39271e..00000000 --- a/dmd/complex_t.h +++ /dev/null @@ -1,76 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright and Burton Radons -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_COMPLEX_T_H -#define DMD_COMPLEX_T_H - -/* Roll our own complex type for compilers that don't support complex - */ - -struct complex_t -{ - longdouble re; - longdouble im; - - complex_t() { this->re = 0; this->im = 0; } - complex_t(longdouble re) { this->re = re; this->im = 0; } - complex_t(double re) { this->re = re; this->im = 0; } - complex_t(longdouble re, longdouble im) { this->re = re; this->im = im; } - complex_t(double re, double im) { this->re = re; this->im = im; } - - complex_t operator + (complex_t y) { complex_t r; r.re = re + y.re; r.im = im + y.im; return r; } - complex_t operator - (complex_t y) { complex_t r; r.re = re - y.re; r.im = im - y.im; return r; } - complex_t operator - () { complex_t r; r.re = -re; r.im = -im; return r; } - complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); } - - complex_t operator / (complex_t y) - { - longdouble abs_y_re = y.re < 0 ? -y.re : y.re; - longdouble abs_y_im = y.im < 0 ? -y.im : y.im; - longdouble r, den; - - if (abs_y_re < abs_y_im) - { - r = y.re / y.im; - den = y.im + r * y.re; - return complex_t((re * r + im) / den, - (im * r - re) / den); - } - else - { - r = y.im / y.re; - den = y.re + r * y.im; - return complex_t((re + r * im) / den, - (im - r * re) / den); - } - } - - operator bool () { return re || im; } - - int operator == (complex_t y) { return re == y.re && im == y.im; } - int operator != (complex_t y) { return re != y.re || im != y.im; } -}; - -inline complex_t operator * (longdouble x, complex_t y) { return complex_t(x) * y; } -inline complex_t operator * (complex_t x, longdouble y) { return x * complex_t(y); } -inline complex_t operator / (complex_t x, longdouble y) { return x / complex_t(y); } - - -inline longdouble creall(complex_t x) -{ - return x.re; -} - -inline longdouble cimagl(complex_t x) -{ - return x.im; -} - -#endif diff --git a/dmd/cond.c b/dmd/cond.c deleted file mode 100644 index f54fd467..00000000 --- a/dmd/cond.c +++ /dev/null @@ -1,430 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include // strcmp() - -#include "id.h" -#include "init.h" -#include "declaration.h" -#include "identifier.h" -#include "expression.h" -#include "cond.h" -#include "module.h" -#include "template.h" -#include "lexer.h" -#include "mtype.h" -#include "scope.h" -#include "arraytypes.h" - -int findCondition(Strings *ids, Identifier *ident) -{ - if (ids) - { - for (size_t i = 0; i < ids->dim; i++) - { - const char *id = (*ids)[i]; - - if (strcmp(id, ident->toChars()) == 0) - return TRUE; - } - } - - return FALSE; -} - -/* ============================================================ */ - -Condition::Condition(Loc loc) -{ - this->loc = loc; - inc = 0; -} - -/* ============================================================ */ - -DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident) - : Condition(0) -{ - this->mod = mod; - this->level = level; - this->ident = ident; -} - -Condition *DVCondition::syntaxCopy() -{ - return this; // don't need to copy -} - -/* ============================================================ */ - -void DebugCondition::setGlobalLevel(unsigned level) -{ - global.params.debuglevel = level; -} - -void DebugCondition::addGlobalIdent(const char *ident) -{ - if (!global.params.debugids) - global.params.debugids = new Strings(); - global.params.debugids->push((char *)ident); -} - - -DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident) - : DVCondition(mod, level, ident) -{ -} - -int DebugCondition::include(Scope *sc, ScopeDsymbol *s) -{ - //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); - if (inc == 0) - { - inc = 2; - if (ident) - { - if (findCondition(mod->debugids, ident)) - inc = 1; - else if (findCondition(global.params.debugids, ident)) - inc = 1; - else - { if (!mod->debugidsNot) - mod->debugidsNot = new Strings(); - mod->debugidsNot->push(ident->toChars()); - } - } - else if (level <= global.params.debuglevel || level <= mod->debuglevel) - inc = 1; - } - return (inc == 1); -} - -void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (ident) - buf->printf("debug (%s)", ident->toChars()); - else - buf->printf("debug (%u)", level); -} - -/* ============================================================ */ - -void VersionCondition::setGlobalLevel(unsigned level) -{ - global.params.versionlevel = level; -} - -void VersionCondition::checkPredefined(Loc loc, const char *ident) -{ - static const char* reserved[] = - { - "DigitalMars", "X86", "X86_64", - "Windows", "Win32", "Win64", - "linux", -#if DMDV2 - /* Although Posix is predefined by D1, disallowing its - * redefinition breaks makefiles and older builds. - */ - "Posix", - "D_NET", -#endif - "OSX", "FreeBSD", - "OpenBSD", - "Solaris", - "LittleEndian", "BigEndian", - "all", - "none", - -#if IN_LLVM - "LLVM", "LDC", "LLVM64", - "PPC", "PPC64", - "darwin","solaris","freebsd" -#endif - }; - - for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) - { - if (strcmp(ident, reserved[i]) == 0) - goto Lerror; - } - - if (ident[0] == 'D' && ident[1] == '_') - goto Lerror; - - return; - - Lerror: - error(loc, "version identifier '%s' is reserved and cannot be set", ident); -} - -void VersionCondition::addGlobalIdent(const char *ident) -{ - checkPredefined(0, ident); - addPredefinedGlobalIdent(ident); -} - -void VersionCondition::addPredefinedGlobalIdent(const char *ident) -{ - if (!global.params.versionids) - global.params.versionids = new Strings(); - global.params.versionids->push((char *)ident); -} - - -VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident) - : DVCondition(mod, level, ident) -{ -} - -int VersionCondition::include(Scope *sc, ScopeDsymbol *s) -{ - //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); - //if (ident) printf("\tident = '%s'\n", ident->toChars()); - if (inc == 0) - { - inc = 2; - if (ident) - { - if (findCondition(mod->versionids, ident)) - inc = 1; - else if (findCondition(global.params.versionids, ident)) - inc = 1; - else - { - if (!mod->versionidsNot) - mod->versionidsNot = new Strings(); - mod->versionidsNot->push(ident->toChars()); - } - } - else if (level <= global.params.versionlevel || level <= mod->versionlevel) - inc = 1; - } - return (inc == 1); -} - -void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (ident) - buf->printf("version (%s)", ident->toChars()); - else - buf->printf("version (%u)", level); -} - - -/**************************** StaticIfCondition *******************************/ - -StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) - : Condition(loc) -{ - this->exp = exp; - this->nest = 0; -} - -Condition *StaticIfCondition::syntaxCopy() -{ - return new StaticIfCondition(loc, exp->syntaxCopy()); -} - -int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) -{ -#if 0 - printf("StaticIfCondition::include(sc = %p, s = %p) this=%p inc = %d\n", sc, s, this, inc); - if (s) - { - printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind()); - } -#endif - if (inc == 0) - { - if (exp->op == TOKerror || nest > 100) - { - error(loc, (nest > 1000) ? "unresolvable circular static if expression" - : "error evaluating static if expression"); - if (!global.gag) - inc = 2; // so we don't see the error message again - return 0; - } - - if (!sc) - { - error(loc, "static if conditional cannot be at global scope"); - inc = 2; - return 0; - } - - ++nest; - sc = sc->push(sc->scopesym); - sc->sd = s; // s gets any addMember() - sc->flags |= SCOPEstaticif; - Expression *e = exp->semantic(sc); - sc->pop(); - if (!e->type->checkBoolean()) - { - if (e->type->toBasetype() != Type::terror) - exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars()); - inc = 0; - return 0; - } - e = e->ctfeInterpret(); - --nest; - if (e->op == TOKerror) - { exp = e; - inc = 0; - } - else if (e->isBool(TRUE)) - inc = 1; - else if (e->isBool(FALSE)) - inc = 2; - else - { - e->error("expression %s is not constant or does not evaluate to a bool", e->toChars()); - inc = 2; - } - } - return (inc == 1); -} - -void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("static if("); - exp->toCBuffer(buf, hgs); - buf->writeByte(')'); -} - - -/**************************** IftypeCondition *******************************/ - -IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec) - : Condition(loc) -{ - this->targ = targ; - this->id = id; - this->tok = tok; - this->tspec = tspec; -} - -Condition *IftypeCondition::syntaxCopy() -{ - return new IftypeCondition(loc, - targ->syntaxCopy(), - id, - tok, - tspec ? tspec->syntaxCopy() : NULL); -} - -int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd) -{ - //printf("IftypeCondition::include()\n"); - if (inc == 0) - { - if (!sc) - { - error(loc, "iftype conditional cannot be at global scope"); - inc = 2; - return 0; - } - Type *t = targ->trySemantic(loc, sc); - if (t) - targ = t; - else - inc = 2; // condition is false - - if (!t) - { - } - else if (id && tspec) - { - /* Evaluate to TRUE if targ matches tspec. - * If TRUE, declare id as an alias for the specialized type. - */ - - MATCH m; - TemplateTypeParameter tp(loc, id, NULL, NULL); - - TemplateParameters parameters; - parameters.setDim(1); - parameters[0] = &tp; - - Objects dedtypes; - dedtypes.setDim(1); - - m = targ->deduceType(sc, tspec, ¶meters, &dedtypes); - if (m == MATCHnomatch || - (m != MATCHexact && tok == TOKequal)) - inc = 2; - else - { - inc = 1; - Type *tded = (Type *)dedtypes[0]; - if (!tded) - tded = targ; - Dsymbol *s = new AliasDeclaration(loc, id, tded); - s->semantic(sc); - sc->insert(s); - if (sd) - s->addMember(sc, sd, 1); - } - } - else if (id) - { - /* Declare id as an alias for type targ. Evaluate to TRUE - */ - Dsymbol *s = new AliasDeclaration(loc, id, targ); - s->semantic(sc); - sc->insert(s); - if (sd) - s->addMember(sc, sd, 1); - inc = 1; - } - else if (tspec) - { - /* Evaluate to TRUE if targ matches tspec - */ - tspec = tspec->semantic(loc, sc); - //printf("targ = %s\n", targ->toChars()); - //printf("tspec = %s\n", tspec->toChars()); - if (tok == TOKcolon) - { if (targ->implicitConvTo(tspec)) - inc = 1; - else - inc = 2; - } - else /* == */ - { if (targ->equals(tspec)) - inc = 1; - else - inc = 2; - } - } - else - inc = 1; - //printf("inc = %d\n", inc); - } - return (inc == 1); -} - -void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("iftype("); - targ->toCBuffer(buf, id, hgs); - if (tspec) - { - if (tok == TOKcolon) - buf->writestring(" : "); - else - buf->writestring(" == "); - tspec->toCBuffer(buf, NULL, hgs); - } - buf->writeByte(')'); -} - - diff --git a/dmd/cond.h b/dmd/cond.h deleted file mode 100644 index 71400314..00000000 --- a/dmd/cond.h +++ /dev/null @@ -1,106 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_DEBCOND_H -#define DMD_DEBCOND_H - -struct Expression; -struct Identifier; -struct OutBuffer; -struct Module; -struct Scope; -struct ScopeDsymbol; -struct DebugCondition; -#include "lexer.h" // dmdhg -enum TOK; -struct HdrGenState; - -int findCondition(Strings *ids, Identifier *ident); - -struct Condition -{ - Loc loc; - int inc; // 0: not computed yet - // 1: include - // 2: do not include - - Condition(Loc loc); - - virtual Condition *syntaxCopy() = 0; - virtual int include(Scope *sc, ScopeDsymbol *s) = 0; - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; - virtual DebugCondition *isDebugCondition() { return NULL; } -}; - -struct DVCondition : Condition -{ - unsigned level; - Identifier *ident; - Module *mod; - - DVCondition(Module *mod, unsigned level, Identifier *ident); - - Condition *syntaxCopy(); -}; - -struct DebugCondition : DVCondition -{ - static void setGlobalLevel(unsigned level); - static void addGlobalIdent(const char *ident); - static void addPredefinedGlobalIdent(const char *ident); - - DebugCondition(Module *mod, unsigned level, Identifier *ident); - - int include(Scope *sc, ScopeDsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - DebugCondition *isDebugCondition() { return this; } -}; - -struct VersionCondition : DVCondition -{ - static void setGlobalLevel(unsigned level); - static void checkPredefined(Loc loc, const char *ident); - static void addGlobalIdent(const char *ident); - static void addPredefinedGlobalIdent(const char *ident); - - VersionCondition(Module *mod, unsigned level, Identifier *ident); - - int include(Scope *sc, ScopeDsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct StaticIfCondition : Condition -{ - Expression *exp; - int nest; // limit circular dependencies - - StaticIfCondition(Loc loc, Expression *exp); - Condition *syntaxCopy(); - int include(Scope *sc, ScopeDsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct IftypeCondition : Condition -{ - /* iftype (targ id tok tspec) - */ - Type *targ; - Identifier *id; // can be NULL - enum TOK tok; // ':' or '==' - Type *tspec; // can be NULL - - IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec); - Condition *syntaxCopy(); - int include(Scope *sc, ScopeDsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - - -#endif diff --git a/dmd/constfold.c b/dmd/constfold.c deleted file mode 100644 index e630ba1c..00000000 --- a/dmd/constfold.c +++ /dev/null @@ -1,1787 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include // mem{cpy|set|cmp}() -#include - -#if __DMC__ -#include -#endif - -#include "rmem.h" -#include "root.h" -#include "port.h" - -#include "mtype.h" -#include "expression.h" -#include "aggregate.h" -#include "declaration.h" -#include "utf.h" - -#ifdef IN_GCC -#include "d-gcc-real.h" - -/* %% fix? */ -extern "C" bool real_isnan (const real_t *); -#endif - -static real_t zero; // work around DMC bug for now - -#define LOG 0 - -int RealEquals(real_t x1, real_t x2); - -Expression *expType(Type *type, Expression *e) -{ - if (type != e->type) - { - e = e->copy(); - e->type = type; - } - return e; -} - -/* ================================== isConst() ============================== */ - -int Expression::isConst() -{ - //printf("Expression::isConst(): %s\n", toChars()); - return 0; -} - -int IntegerExp::isConst() -{ - return 1; -} - -int RealExp::isConst() -{ - return 1; -} - -int ComplexExp::isConst() -{ - return 1; -} - -int NullExp::isConst() -{ - return 0; -} - -int SymOffExp::isConst() -{ - return 2; -} - -/* =============================== constFold() ============================== */ - -/* The constFold() functions were redundant with the optimize() ones, - * and so have been folded in with them. - */ - -/* ========================================================================== */ - -Expression *Neg(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - if (e1->type->isreal()) - { - e = new RealExp(loc, -e1->toReal(), type); - } - else if (e1->type->isimaginary()) - { - e = new RealExp(loc, -e1->toImaginary(), type); - } - else if (e1->type->iscomplex()) - { - e = new ComplexExp(loc, -e1->toComplex(), type); - } - else - e = new IntegerExp(loc, -e1->toInteger(), type); - return e; -} - -Expression *Com(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, ~e1->toInteger(), type); - return e; -} - -Expression *Not(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->isBool(0), type); - return e; -} - -Expression *Bool(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->isBool(1), type); - return e; -} - -Expression *Add(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - -#if LOG - printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); -#endif - if (type->isreal()) - { - e = new RealExp(loc, e1->toReal() + e2->toReal(), type); - } - else if (type->isimaginary()) - { - e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type); - } - else if (type->iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - complex_t c1; - real_t r1; - real_t i1; - - complex_t c2; - real_t r2; - real_t i2; - - complex_t v; - int x; - - if (e1->type->isreal()) - { r1 = e1->toReal(); - x = 0; - } - else if (e1->type->isimaginary()) - { i1 = e1->toImaginary(); - x = 3; - } - else - { c1 = e1->toComplex(); - x = 6; - } - - if (e2->type->isreal()) - { r2 = e2->toReal(); - } - else if (e2->type->isimaginary()) - { i2 = e2->toImaginary(); - x += 1; - } - else - { c2 = e2->toComplex(); - x += 2; - } - - switch (x) - { -#if __DMC__ - case 0+0: v = (complex_t) (r1 + r2); break; - case 0+1: v = r1 + i2 * I; break; - case 0+2: v = r1 + c2; break; - case 3+0: v = i1 * I + r2; break; - case 3+1: v = (complex_t) ((i1 + i2) * I); break; - case 3+2: v = i1 * I + c2; break; - case 6+0: v = c1 + r2; break; - case 6+1: v = c1 + i2 * I; break; - case 6+2: v = c1 + c2; break; -#else - case 0+0: v = complex_t(r1 + r2, 0); break; - case 0+1: v = complex_t(r1, i2); break; - case 0+2: v = complex_t(r1 + creall(c2), cimagl(c2)); break; - case 3+0: v = complex_t(r2, i1); break; - case 3+1: v = complex_t(0, i1 + i2); break; - case 3+2: v = complex_t(creall(c2), i1 + cimagl(c2)); break; - case 6+0: v = complex_t(creall(c1) + r2, cimagl(c2)); break; - case 6+1: v = complex_t(creall(c1), cimagl(c1) + i2); break; - case 6+2: v = c1 + c2; break; -#endif - default: assert(0); - } - e = new ComplexExp(loc, v, type); - } - else if (e1->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e1; - e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger()); - e->type = type; - } - else if (e2->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e2; - e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger()); - e->type = type; - } - else - e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type); - return e; -} - - -Expression *Min(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isreal()) - { - e = new RealExp(loc, e1->toReal() - e2->toReal(), type); - } - else if (type->isimaginary()) - { - e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type); - } - else if (type->iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - complex_t c1; - real_t r1; - real_t i1; - - complex_t c2; - real_t r2; - real_t i2; - - complex_t v; - int x; - - if (e1->type->isreal()) - { r1 = e1->toReal(); - x = 0; - } - else if (e1->type->isimaginary()) - { i1 = e1->toImaginary(); - x = 3; - } - else - { c1 = e1->toComplex(); - x = 6; - } - - if (e2->type->isreal()) - { r2 = e2->toReal(); - } - else if (e2->type->isimaginary()) - { i2 = e2->toImaginary(); - x += 1; - } - else - { c2 = e2->toComplex(); - x += 2; - } - - switch (x) - { -#if __DMC__ - case 0+0: v = (complex_t) (r1 - r2); break; - case 0+1: v = r1 - i2 * I; break; - case 0+2: v = r1 - c2; break; - case 3+0: v = i1 * I - r2; break; - case 3+1: v = (complex_t) ((i1 - i2) * I); break; - case 3+2: v = i1 * I - c2; break; - case 6+0: v = c1 - r2; break; - case 6+1: v = c1 - i2 * I; break; - case 6+2: v = c1 - c2; break; -#else - case 0+0: v = complex_t(r1 - r2, 0); break; - case 0+1: v = complex_t(r1, -i2); break; - case 0+2: v = complex_t(r1 - creall(c2), -cimagl(c2)); break; - case 3+0: v = complex_t(-r2, i1); break; - case 3+1: v = complex_t(0, i1 - i2); break; - case 3+2: v = complex_t(-creall(c2), i1 - cimagl(c2)); break; - case 6+0: v = complex_t(creall(c1) - r2, cimagl(c1)); break; - case 6+1: v = complex_t(creall(c1), cimagl(c1) - i2); break; - case 6+2: v = c1 - c2; break; -#endif - default: assert(0); - } - e = new ComplexExp(loc, v, type); - } - else if (e1->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e1; - e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger()); - e->type = type; - } - else - { - e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type); - } - return e; -} - -Expression *Mul(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { complex_t c; -#ifdef IN_GCC - real_t r; -#else - d_float80 r; -#endif - - if (e1->type->isreal()) - { -#if __DMC__ - c = e1->toReal() * e2->toComplex(); -#else - r = e1->toReal(); - c = e2->toComplex(); - c = complex_t(r * creall(c), r * cimagl(c)); -#endif - } - else if (e1->type->isimaginary()) - { -#if __DMC__ - c = e1->toImaginary() * I * e2->toComplex(); -#else - r = e1->toImaginary(); - c = e2->toComplex(); - c = complex_t(-r * cimagl(c), r * creall(c)); -#endif - } - else if (e2->type->isreal()) - { -#if __DMC__ - c = e2->toReal() * e1->toComplex(); -#else - r = e2->toReal(); - c = e1->toComplex(); - c = complex_t(r * creall(c), r * cimagl(c)); -#endif - } - else if (e2->type->isimaginary()) - { -#if __DMC__ - c = e1->toComplex() * e2->toImaginary() * I; -#else - r = e2->toImaginary(); - c = e1->toComplex(); - c = complex_t(-r * cimagl(c), r * creall(c)); -#endif - } - else - c = e1->toComplex() * e2->toComplex(); - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { - e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type); - } - return e; -} - -Expression *Div(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { complex_t c; -#ifdef IN_GCC - real_t r; -#else - d_float80 r; -#endif - - //e1->type->print(); - //e2->type->print(); - if (e2->type->isreal()) - { - if (e1->type->isreal()) - { - e = new RealExp(loc, e1->toReal() / e2->toReal(), type); - return e; - } -#if __DMC__ - //r = e2->toReal(); - //c = e1->toComplex(); - //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r); - - c = e1->toComplex() / e2->toReal(); -#else - r = e2->toReal(); - c = e1->toComplex(); - c = complex_t(creall(c) / r, cimagl(c) / r); -#endif - } - else if (e2->type->isimaginary()) - { -#if __DMC__ - //r = e2->toImaginary(); - //c = e1->toComplex(); - //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r); - - c = e1->toComplex() / (e2->toImaginary() * I); -#else - r = e2->toImaginary(); - c = e1->toComplex(); - c = complex_t(cimagl(c) / r, -creall(c) / r); -#endif - } - else - { - c = e1->toComplex() / e2->toComplex(); - } - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - sinteger_t n; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (n2 == 0) - { e2->error("divide by 0"); - e2 = new IntegerExp(loc, 1, e2->type); - n2 = 1; - } - if (e1->type->isunsigned() || e2->type->isunsigned()) - n = ((d_uns64) n1) / ((d_uns64) n2); - else - n = n1 / n2; - e = new IntegerExp(loc, n, type); - } - return e; -} - -Expression *Mod(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { - complex_t c; - - if (e2->type->isreal()) - { real_t r2 = e2->toReal(); - -#ifdef __DMC__ - c = Port::fmodl(e1->toReal(), r2) + Port::fmodl(e1->toImaginary(), r2) * I; -#elif defined(IN_GCC) - c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2); -#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__) - // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?! - // arm also doesn't like fmodl - c = complex_t(fmod(e1->toReal(), r2), fmod(e1->toImaginary(), r2)); -#else - c = complex_t(Port::fmodl(e1->toReal(), r2), Port::fmodl(e1->toImaginary(), r2)); -#endif - } - else if (e2->type->isimaginary()) - { real_t i2 = e2->toImaginary(); - -#ifdef __DMC__ - c = Port::fmodl(e1->toReal(), i2) + Port::fmodl(e1->toImaginary(), i2) * I; -#elif defined(IN_GCC) - c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2); -#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__) - // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?! - // arm also doesn't like fmodl - c = complex_t(fmod(e1->toReal(), i2), fmod(e1->toImaginary(), i2)); -#else - c = complex_t(Port::fmodl(e1->toReal(), i2), Port::fmodl(e1->toImaginary(), i2)); -#endif - } - else - assert(0); - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - sinteger_t n; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (n2 == 0) - { e2->error("divide by 0"); - e2 = new IntegerExp(loc, 1, e2->type); - n2 = 1; - } - if (n2 == -1 && !type->isunsigned()) - { // Check for int.min % -1 - if (n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64) - { - e2->error("integer overflow: int.min % -1"); - e2 = new IntegerExp(loc, 1, e2->type); - n2 = 1; - } - else if (n1 == 0x8000000000000000LL) // long.min % -1 - { - e2->error("integer overflow: long.min % -1"); - e2 = new IntegerExp(loc, 1, e2->type); - n2 = 1; - } - } - if (e1->type->isunsigned() || e2->type->isunsigned()) - n = ((d_uns64) n1) % ((d_uns64) n2); - else - n = n1 % n2; - e = new IntegerExp(loc, n, type); - } - return e; -} - -Expression *Shl(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type); - return e; -} - -Expression *Shr(Type *type, Expression *e1, Expression *e2) -{ - Loc loc = e1->loc; - - dinteger_t value = e1->toInteger(); - dinteger_t dcount = e2->toInteger(); - assert(dcount <= 0xFFFFFFFF); - unsigned count = (unsigned)dcount; - switch (e1->type->toBasetype()->ty) - { - case Tint8: - value = (d_int8)(value) >> count; - break; - - case Tuns8: - case Tchar: - value = (d_uns8)(value) >> count; - break; - - case Tint16: - value = (d_int16)(value) >> count; - break; - - case Tuns16: - case Twchar: - value = (d_uns16)(value) >> count; - break; - - case Tint32: - value = (d_int32)(value) >> count; - break; - - case Tuns32: - case Tdchar: - value = (d_uns32)(value) >> count; - break; - - case Tint64: - value = (d_int64)(value) >> count; - break; - - case Tuns64: - value = (d_uns64)(value) >> count; - break; - - case Terror: - return e1; - - default: - assert(0); - } - Expression *e = new IntegerExp(loc, value, type); - return e; -} - -Expression *Ushr(Type *type, Expression *e1, Expression *e2) -{ - Loc loc = e1->loc; - - dinteger_t value = e1->toInteger(); - dinteger_t dcount = e2->toInteger(); - assert(dcount <= 0xFFFFFFFF); - unsigned count = (unsigned)dcount; - switch (e1->type->toBasetype()->ty) - { - case Tint8: - case Tuns8: - case Tchar: - // Possible only with >>>=. >>> always gets promoted to int. - value = (value & 0xFF) >> count; - break; - - case Tint16: - case Tuns16: - case Twchar: - // Possible only with >>>=. >>> always gets promoted to int. - value = (value & 0xFFFF) >> count; - break; - - case Tint32: - case Tuns32: - case Tdchar: - value = (value & 0xFFFFFFFF) >> count; - break; - - case Tint64: - case Tuns64: - value = (d_uns64)(value) >> count; - break; - - case Terror: - return e1; - - default: - assert(0); - } - Expression *e = new IntegerExp(loc, value, type); - return e; -} - -Expression *And(Type *type, Expression *e1, Expression *e2) -{ - Expression *e; - e = new IntegerExp(e1->loc, e1->toInteger() & e2->toInteger(), type); - return e; -} - -Expression *Or(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - e = new IntegerExp(e1->loc, e1->toInteger() | e2->toInteger(), type); - return e; -} - -Expression *Xor(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - e = new IntegerExp(e1->loc, e1->toInteger() ^ e2->toInteger(), type); - return e; -} - -/* Also returns EXP_CANT_INTERPRET if cannot be computed. - */ -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - int cmp; - real_t r1; - real_t r2; - - //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - - assert(op == TOKequal || op == TOKnotequal); - - if (e1->op == TOKnull) - { - if (e2->op == TOKnull) - cmp = 1; - else if (e2->op == TOKstring) - { StringExp *es2 = (StringExp *)e2; - cmp = (0 == es2->len); - } - else if (e2->op == TOKarrayliteral) - { ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - cmp = !es2->elements || (0 == es2->elements->dim); - } - else - return EXP_CANT_INTERPRET; - } - else if (e2->op == TOKnull) - { - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - cmp = (0 == es1->len); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - cmp = !es1->elements || (0 == es1->elements->dim); - } - else - return EXP_CANT_INTERPRET; - } - else if (e1->op == TOKstring && e2->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - - if (es1->sz != es2->sz) - { - assert(global.errors); - return EXP_CANT_INTERPRET; - } - if (es1->len == es2->len && - memcmp(es1->string, es2->string, es1->sz * es1->len) == 0) - cmp = 1; - else - cmp = 0; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - if ((!es1->elements || !es1->elements->dim) && - (!es2->elements || !es2->elements->dim)) - cmp = 1; // both arrays are empty - else if (!es1->elements || !es2->elements) - cmp = 0; - else if (es1->elements->dim != es2->elements->dim) - cmp = 0; - else - { - for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (*es1->elements)[i]; - Expression *ee2 = (*es2->elements)[i]; - - Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); - if (v == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - cmp = v->toInteger(); - if (cmp == 0) - break; - } - } - } - else if (e1->op == TOKarrayliteral && e2->op == TOKstring) - { // Swap operands and use common code - Expression *etmp = e1; - e1 = e2; - e2 = etmp; - goto Lsa; - } - else if (e1->op == TOKstring && e2->op == TOKarrayliteral) - { - Lsa: - StringExp *es1 = (StringExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - size_t dim1 = es1->len; - size_t dim2 = es2->elements ? es2->elements->dim : 0; - if (dim1 != dim2) - cmp = 0; - else - { - cmp = 1; // if dim1 winds up being 0 - for (size_t i = 0; i < dim1; i++) - { - uinteger_t c = es1->charAt(i); - Expression *ee2 = (*es2->elements)[i]; - if (ee2->isConst() != 1) - return EXP_CANT_INTERPRET; - cmp = (c == ee2->toInteger()); - if (cmp == 0) - break; - } - } - } - else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) - { StructLiteralExp *es1 = (StructLiteralExp *)e1; - StructLiteralExp *es2 = (StructLiteralExp *)e2; - - if (es1->sd != es2->sd) - cmp = 0; - else if ((!es1->elements || !es1->elements->dim) && - (!es2->elements || !es2->elements->dim)) - cmp = 1; // both arrays are empty - else if (!es1->elements || !es2->elements) - cmp = 0; - else if (es1->elements->dim != es2->elements->dim) - cmp = 0; - else - { - cmp = 1; - for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (*es1->elements)[i]; - Expression *ee2 = (*es2->elements)[i]; - - if (ee1 == ee2) - continue; - if (!ee1 || !ee2) - { cmp = 0; - break; - } - Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); - if (v == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - cmp = v->toInteger(); - if (cmp == 0) - break; - } - } - } -#if 0 // Should handle this - else if (e1->op == TOKarrayliteral && e2->op == TOKstring) - { - } -#endif - else if (e1->isConst() != 1 || e2->isConst() != 1) - return EXP_CANT_INTERPRET; - else if (e1->type->isreal()) - { - r1 = e1->toReal(); - r2 = e2->toReal(); - goto L1; - } - else if (e1->type->isimaginary()) - { - r1 = e1->toImaginary(); - r2 = e2->toImaginary(); - L1: -#if __DMC__ - cmp = (r1 == r2); -#else - if (Port::isNan(r1) || Port::isNan(r2)) // if unordered - { - cmp = 0; - } - else - { - cmp = (r1 == r2); - } -#endif - } - else if (e1->type->iscomplex()) - { - cmp = e1->toComplex() == e2->toComplex(); - } - else if (e1->type->isintegral() || e1->type->toBasetype()->ty == Tpointer) - { - cmp = (e1->toInteger() == e2->toInteger()); - } - else - return EXP_CANT_INTERPRET; - if (op == TOKnotequal) - cmp ^= 1; - e = new IntegerExp(loc, cmp, type); - return e; -} - -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ - Loc loc = e1->loc; - int cmp; - - if (e1->op == TOKnull) - { - cmp = (e2->op == TOKnull); - } - else if (e2->op == TOKnull) - { - cmp = 0; - } - else if (e1->op == TOKsymoff && e2->op == TOKsymoff) - { - SymOffExp *es1 = (SymOffExp *)e1; - SymOffExp *es2 = (SymOffExp *)e2; - - cmp = (es1->var == es2->var && es1->offset == es2->offset); - } - else - { - return Equal((op == TOKidentity) ? TOKequal : TOKnotequal, - type, e1, e2); - } - if (op == TOKnotidentity) - cmp ^= 1; - return new IntegerExp(loc, cmp, type); -} - - -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - dinteger_t n; - real_t r1; - real_t r2; - - if (e1->type->isreal()) - { - r1 = e1->toReal(); - r2 = e2->toReal(); - goto L1; - } - else if (e1->type->isimaginary()) - { - r1 = e1->toImaginary(); - r2 = e2->toImaginary(); - L1: -#if __DMC__ - // DMC is the only compiler I know of that handles NAN arguments - // correctly in comparisons. - switch (op) - { - case TOKlt: n = r1 < r2; break; - case TOKle: n = r1 <= r2; break; - case TOKgt: n = r1 > r2; break; - case TOKge: n = r1 >= r2; break; - - case TOKleg: n = r1 <>= r2; break; - case TOKlg: n = r1 <> r2; break; - case TOKunord: n = r1 !<>= r2; break; - case TOKue: n = r1 !<> r2; break; - case TOKug: n = r1 !<= r2; break; - case TOKuge: n = r1 !< r2; break; - case TOKul: n = r1 !>= r2; break; - case TOKule: n = r1 !> r2; break; - - default: - assert(0); - } -#else - // Don't rely on compiler, handle NAN arguments separately - if (Port::isNan(r1) || Port::isNan(r2)) // if unordered - { - switch (op) - { - case TOKlt: n = 0; break; - case TOKle: n = 0; break; - case TOKgt: n = 0; break; - case TOKge: n = 0; break; - - case TOKleg: n = 0; break; - case TOKlg: n = 0; break; - case TOKunord: n = 1; break; - case TOKue: n = 1; break; - case TOKug: n = 1; break; - case TOKuge: n = 1; break; - case TOKul: n = 1; break; - case TOKule: n = 1; break; - - default: - assert(0); - } - } - else - { - switch (op) - { - case TOKlt: n = r1 < r2; break; - case TOKle: n = r1 <= r2; break; - case TOKgt: n = r1 > r2; break; - case TOKge: n = r1 >= r2; break; - - case TOKleg: n = 1; break; - case TOKlg: n = r1 != r2; break; - case TOKunord: n = 0; break; - case TOKue: n = r1 == r2; break; - case TOKug: n = r1 > r2; break; - case TOKuge: n = r1 >= r2; break; - case TOKul: n = r1 < r2; break; - case TOKule: n = r1 <= r2; break; - - default: - assert(0); - } - } -#endif - } - else if (e1->type->iscomplex()) - { - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (e1->type->isunsigned() || e2->type->isunsigned()) - { - switch (op) - { - case TOKlt: n = ((d_uns64) n1) < ((d_uns64) n2); break; - case TOKle: n = ((d_uns64) n1) <= ((d_uns64) n2); break; - case TOKgt: n = ((d_uns64) n1) > ((d_uns64) n2); break; - case TOKge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; - - case TOKleg: n = 1; break; - case TOKlg: n = ((d_uns64) n1) != ((d_uns64) n2); break; - case TOKunord: n = 0; break; - case TOKue: n = ((d_uns64) n1) == ((d_uns64) n2); break; - case TOKug: n = ((d_uns64) n1) > ((d_uns64) n2); break; - case TOKuge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; - case TOKul: n = ((d_uns64) n1) < ((d_uns64) n2); break; - case TOKule: n = ((d_uns64) n1) <= ((d_uns64) n2); break; - - default: - assert(0); - } - } - else - { - switch (op) - { - case TOKlt: n = n1 < n2; break; - case TOKle: n = n1 <= n2; break; - case TOKgt: n = n1 > n2; break; - case TOKge: n = n1 >= n2; break; - - case TOKleg: n = 1; break; - case TOKlg: n = n1 != n2; break; - case TOKunord: n = 0; break; - case TOKue: n = n1 == n2; break; - case TOKug: n = n1 > n2; break; - case TOKuge: n = n1 >= n2; break; - case TOKul: n = n1 < n2; break; - case TOKule: n = n1 <= n2; break; - - default: - assert(0); - } - } - } - e = new IntegerExp(loc, n, type); - return e; -} - -/* Also returns EXP_CANT_INTERPRET if cannot be computed. - * to: type to cast to - * type: type to paint the result - */ - -Expression *Cast(Type *type, Type *to, Expression *e1) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - - //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars()); - //printf("\te1->type = %s\n", e1->type->toChars()); - if (type->equals(e1->type) && to->equals(type)) - return e1; - - Type *tb = to->toBasetype(); - Type *typeb = type->toBasetype(); - - /* Allow casting from one string type to another - */ - if (e1->op == TOKstring) - { - if (tb->ty == Tarray && typeb->ty == Tarray && - tb->nextOf()->size() == typeb->nextOf()->size()) - { - return expType(to, e1); - } - } - - if (e1->op == TOKarrayliteral && typeb == tb) - return e1; - - if (e1->isConst() != 1) - return EXP_CANT_INTERPRET; - - if (tb->ty == Tbool) - e = new IntegerExp(loc, e1->toInteger() != 0, type); - else if (type->isintegral()) - { - if (e1->type->isfloating()) - { dinteger_t result; - real_t r = e1->toReal(); - - switch (typeb->ty) - { - case Tint8: result = (d_int8)r; break; - case Tchar: - case Tuns8: result = (d_uns8)r; break; - case Tint16: result = (d_int16)r; break; - case Twchar: - case Tuns16: result = (d_uns16)r; break; - case Tint32: result = (d_int32)r; break; - case Tdchar: - case Tuns32: result = (d_uns32)r; break; - case Tint64: result = (d_int64)r; break; - case Tuns64: result = (d_uns64)r; break; - default: - assert(0); - } - - e = new IntegerExp(loc, result, type); - } - else if (type->isunsigned()) - e = new IntegerExp(loc, e1->toUInteger(), type); - else - e = new IntegerExp(loc, e1->toInteger(), type); - } - else if (tb->isreal()) - { real_t value = e1->toReal(); - - e = new RealExp(loc, value, type); - } - else if (tb->isimaginary()) - { real_t value = e1->toImaginary(); - - e = new RealExp(loc, value, type); - } - else if (tb->iscomplex()) - { complex_t value = e1->toComplex(); - - e = new ComplexExp(loc, value, type); - } - else if (tb->isscalar()) - e = new IntegerExp(loc, e1->toInteger(), type); - else if (tb->ty == Tvoid) - e = EXP_CANT_INTERPRET; - else if (tb->ty == Tstruct && e1->op == TOKint64) - { // Struct = 0; - StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration(); - assert(sd); - Expressions *elements = new Expressions; - for (size_t i = 0; i < sd->fields.dim; i++) - { Dsymbol *s = sd->fields[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - Expression *exp = new IntegerExp(0); - exp = Cast(v->type, v->type, exp); - if (exp == EXP_CANT_INTERPRET) - return exp; - elements->push(exp); - } - e = new StructLiteralExp(loc, sd, elements); - e->type = type; - } - else - { - if (type != Type::terror) - error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars()); - e = new ErrorExp(); - } - return e; -} - - -Expression *ArrayLength(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - - e = new IntegerExp(loc, es1->len, type); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - size_t dim; - - dim = ale->elements ? ale->elements->dim : 0; - e = new IntegerExp(loc, dim, type); - } - else if (e1->op == TOKassocarrayliteral) - { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1; - size_t dim = ale->keys->dim; - - e = new IntegerExp(loc, dim, type); - } - else - e = EXP_CANT_INTERPRET; - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Index(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - - //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - assert(e1->type); - if (e1->op == TOKstring && e2->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; - uinteger_t i = e2->toInteger(); - - if (i >= es1->len) - { - e1->error("string index %ju is out of bounds [0 .. %zu]", i, es1->len); - e = new ErrorExp(); - } - else - { - e = new IntegerExp(loc, es1->charAt(i), type); - } - } - else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64) - { TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype(); - uinteger_t length = tsa->dim->toInteger(); - uinteger_t i = e2->toInteger(); - - if (i >= length) - { - e1->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length); - e = new ErrorExp(); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - e = (*ale->elements)[i]; - e->type = type; - if (e->hasSideEffect()) - e = EXP_CANT_INTERPRET; - } - } - else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64) - { - uinteger_t i = e2->toInteger(); - - if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - if (i >= ale->elements->dim) - { - e1->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim); - e = new ErrorExp(); - } - else - { e = (*ale->elements)[i]; - e->type = type; - if (e->hasSideEffect()) - e = EXP_CANT_INTERPRET; - } - } - } - else if (e1->op == TOKassocarrayliteral) - { - AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1; - /* Search the keys backwards, in case there are duplicate keys - */ - for (size_t i = ae->keys->dim; i;) - { - i--; - Expression *ekey = (*ae->keys)[i]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2); - if (ex == EXP_CANT_INTERPRET) - return ex; - if (ex->isBool(TRUE)) - { e = (*ae->values)[i]; - e->type = type; - if (e->hasSideEffect()) - e = EXP_CANT_INTERPRET; - break; - } - } - } - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - -#if LOG - printf("Slice()\n"); - if (lwr) - { printf("\te1 = %s\n", e1->toChars()); - printf("\tlwr = %s\n", lwr->toChars()); - printf("\tupr = %s\n", upr->toChars()); - } -#endif - if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; - uinteger_t ilwr = lwr->toInteger(); - uinteger_t iupr = upr->toInteger(); - - if (iupr > es1->len || ilwr > iupr) - { - e1->error("string slice [%ju .. %ju] is out of bounds", ilwr, iupr); - e = new ErrorExp(); - } - else - { - void *s; - size_t len = iupr - ilwr; - int sz = es1->sz; - StringExp *es; - - s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz); - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len, es1->postfix); - es->sz = sz; - es->committed = 1; - es->type = type; - e = es; - } - } - else if (e1->op == TOKarrayliteral && - lwr->op == TOKint64 && upr->op == TOKint64 && - !e1->hasSideEffect()) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - uinteger_t ilwr = lwr->toInteger(); - uinteger_t iupr = upr->toInteger(); - - if (iupr > es1->elements->dim || ilwr > iupr) - { - e1->error("array slice [%ju .. %ju] is out of bounds", ilwr, iupr); - e = new ErrorExp(); - } - else - { - Expressions *elements = new Expressions(); - elements->setDim(iupr - ilwr); - memcpy(elements->tdata(), - es1->elements->tdata() + ilwr, - (iupr - ilwr) * sizeof((*es1->elements)[0])); - e = new ArrayLiteralExp(e1->loc, elements); - e->type = type; - } - } - return e; -} - -/* Set a slice of char array literal 'existingAE' from a string 'newval'. - * existingAE[firstIndex..firstIndex+newval.length] = newval. - */ -void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex) -{ - size_t newlen = newval->len; - size_t sz = newval->sz; - unsigned char *s = (unsigned char *)newval->string; - Type *elemType = existingAE->type->nextOf(); - for (size_t j = 0; j < newlen; j++) - { - dinteger_t val; - switch (sz) - { - case 1: val = s[j]; break; - case 2: val = ((unsigned short *)s)[j]; break; - case 4: val = ((unsigned *)s)[j]; break; - default: - assert(0); - break; - } - (*existingAE->elements)[j+firstIndex] - = new IntegerExp(newval->loc, val, elemType); - } -} - -/* Set a slice of string 'existingSE' from a char array literal 'newae'. - * existingSE[firstIndex..firstIndex+newae.length] = newae. - */ -void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex) -{ - unsigned char *s = (unsigned char *)existingSE->string; - for (size_t j = 0; j < newae->elements->dim; j++) - { - unsigned value = (unsigned)((*newae->elements)[j]->toInteger()); - switch (existingSE->sz) - { - case 1: s[j+firstIndex] = value; break; - case 2: ((unsigned short *)s)[j+firstIndex] = value; break; - case 4: ((unsigned *)s)[j+firstIndex] = value; break; - default: - assert(0); - break; - } - } -} - -/* Set a slice of string 'existingSE' from a string 'newstr'. - * existingSE[firstIndex..firstIndex+newstr.length] = newstr. - */ -void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex) -{ - unsigned char *s = (unsigned char *)existingSE->string; - size_t sz = existingSE->sz; - assert(sz == newstr->sz); - memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len); -} - -/* Compare a string slice with another string slice. - * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len]) - */ -int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len) -{ - unsigned char *s1 = (unsigned char *)se1->string; - unsigned char *s2 = (unsigned char *)se2->string; - size_t sz = se1->sz; - assert(sz == se2->sz); - - return memcmp(s1 + sz * lo1, s2 + sz * lo2, sz * len); -} - -/* Compare a string slice with an array literal slice - * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len]) - */ -int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len) -{ - unsigned char *s = (unsigned char *)se1->string; - size_t sz = se1->sz; - - int c = 0; - - for (size_t j = 0; j < len; j++) - { - unsigned value = (unsigned)((*ae2->elements)[j + lo2]->toInteger()); - unsigned svalue; - switch (sz) - { - case 1: svalue = s[j + lo1]; break; - case 2: svalue = ((unsigned short *)s)[j+lo1]; break; - case 4: svalue = ((unsigned *)s)[j + lo1]; break; - default: - assert(0); - } - int c = svalue - value; - if (c) - return c; - } - return 0; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Cat(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - Type *t; - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - - //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - //printf("\tt1 = %s, t2 = %s, type = %s\n", t1->toChars(), t2->toChars(), type->toChars()); - - if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral)) - { e = e2; - t = t1; - goto L2; - } - else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull) - { e = e1; - t = t2; - L2: - Type *tn = e->type->toBasetype(); - if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) - { - // Create a StringExp - void *s; - StringExp *es; - if (t->nextOf()) - t = t->nextOf()->toBasetype(); - int sz = t->size(); - - dinteger_t v = e->toInteger(); - - size_t len = (t->ty == tn->ty) ? 1 : utf_codeLength(sz, v); - s = mem.malloc((len + 1) * sz); - if (t->ty == tn->ty) - memcpy((unsigned char *)s, &v, sz); - else - utf_encode(sz, s, v); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = 1; - e = es; - } - else - { // Create an ArrayLiteralExp - Expressions *elements = new Expressions(); - elements->push(e); - e = new ArrayLiteralExp(e->loc, elements); - } - e->type = type; - return e; - } - else if (e1->op == TOKnull && e2->op == TOKnull) - { - if (type == e1->type) - { - // Handle null ~= null - if (t1->ty == Tarray && t2 == t1->nextOf()) - { - e = new ArrayLiteralExp(e1->loc, e2); - e->type = type; - return e; - } - else - return e1; - } - if (type == e2->type) - return e2; - return new NullExp(e1->loc, type); - } - else if (e1->op == TOKstring && e2->op == TOKstring) - { - // Concatenate the strings - void *s; - StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - StringExp *es; - size_t len = es1->len + es2->len; - int sz = es1->sz; - - if (sz != es2->sz) - { - /* Can happen with: - * auto s = "foo"d ~ "bar"c; - */ - assert(global.errors); - return e; - } - s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es1->committed | es2->committed; - es->type = type; - e = es; - } - else if (e2->op == TOKstring && e1->op == TOKarrayliteral && - t1->nextOf()->isintegral()) - { - // [chars] ~ string --> [chars] - StringExp *es = (StringExp *)e2; - ArrayLiteralExp *ea = (ArrayLiteralExp *)e1; - size_t len = es->len + ea->elements->dim; - Expressions * elems = new Expressions; - elems->setDim(len); - for (size_t i= 0; i < ea->elements->dim; ++i) - { - (*elems)[i] = (*ea->elements)[i]; - } - ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems); - dest->type = type; - sliceAssignArrayLiteralFromString(dest, es, ea->elements->dim); - return dest; - } - else if (e1->op == TOKstring && e2->op == TOKarrayliteral && - t2->nextOf()->isintegral()) - { - // string ~ [chars] --> [chars] - StringExp *es = (StringExp *)e1; - ArrayLiteralExp *ea = (ArrayLiteralExp *)e2; - size_t len = es->len + ea->elements->dim; - Expressions * elems = new Expressions; - elems->setDim(len); - for (size_t i= 0; i < ea->elements->dim; ++i) - { - (*elems)[es->len + i] = (*ea->elements)[i]; - } - ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems); - dest->type = type; - sliceAssignArrayLiteralFromString(dest, es, 0); - return dest; - } - else if (e1->op == TOKstring && e2->op == TOKint64) - { - // string ~ char --> string - void *s; - StringExp *es1 = (StringExp *)e1; - StringExp *es; - int sz = es1->sz; - dinteger_t v = e2->toInteger(); - - // Is it a concatentation of homogenous types? - // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar) - bool homoConcat = (sz == t2->size()); - size_t len = es1->len; - len += homoConcat ? 1 : utf_codeLength(sz, v); - - s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - if (homoConcat) - memcpy((unsigned char *)s + (sz * es1->len), &v, sz); - else - utf_encode(sz, (unsigned char *)s + (sz * es1->len), v); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es1->committed; - es->type = type; - e = es; - } - else if (e1->op == TOKint64 && e2->op == TOKstring) - { - // Concatenate the strings - void *s; - StringExp *es2 = (StringExp *)e2; - StringExp *es; - size_t len = 1 + es2->len; - int sz = es2->sz; - dinteger_t v = e1->toInteger(); - - s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, &v, sz); - memcpy((unsigned char *)s + sz, es2->string, es2->len * sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es2->committed; - es->type = type; - e = es; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral && - e1->type->equals(e2->type)) - { - // Concatenate the arrays - ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); - es1->elements->insert(es1->elements->dim, es2->elements); - e = es1; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKnull && - t1->nextOf()->equals(t2->nextOf())) - { - e = e1; - goto L3; - } - else if (e1->op == TOKnull && e2->op == TOKarrayliteral && - t1->nextOf()->equals(t2->nextOf())) - { - e = e2; - L3: - // Concatenate the array with null - ArrayLiteralExp *es = (ArrayLiteralExp *)e; - - es = new ArrayLiteralExp(es->loc, (Expressions *)es->elements->copy()); - e = es; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) && - e1->type->toBasetype()->nextOf()->equals(e2->type)) - { - ArrayLiteralExp *es1; - if (e1->op == TOKarrayliteral) - { es1 = (ArrayLiteralExp *)e1; - es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); - es1->elements->push(e2); - } - else - { - es1 = new ArrayLiteralExp(e1->loc, e2); - } - e = es1; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(e2->type, new IntegerExp(loc, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e2->op == TOKarrayliteral && - e2->type->toBasetype()->nextOf()->equals(e1->type)) - { - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy()); - es2->elements->shift(e1); - e = es2; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(e1->type, new IntegerExp(loc, es2->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e1->op == TOKnull && e2->op == TOKstring) - { - t = e1->type; - e = e2; - goto L1; - } - else if (e1->op == TOKstring && e2->op == TOKnull) - { e = e1; - t = e2->type; - L1: - Type *tb = t->toBasetype(); - if (tb->ty == Tarray && tb->nextOf()->equals(e->type)) - { Expressions *expressions = new Expressions(); - expressions->push(e); - e = new ArrayLiteralExp(loc, expressions); - e->type = t; - } - if (!e->type->equals(type)) - { StringExp *se = (StringExp *)e->copy(); - e = se->castTo(NULL, type); - } - } - return e; -} - -Expression *Ptr(Type *type, Expression *e1) -{ - //printf("Ptr(e1 = %s)\n", e1->toChars()); - if (e1->op == TOKadd) - { AddExp *ae = (AddExp *)e1; - if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) - { AddrExp *ade = (AddrExp *)ae->e1; - if (ade->e1->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ade->e1; - unsigned offset = ae->e2->toInteger(); - Expression *e = se->getField(type, offset); - if (!e) - e = EXP_CANT_INTERPRET; - return e; - } - } - } - return EXP_CANT_INTERPRET; -} - diff --git a/dmd/declaration.c b/dmd/declaration.c deleted file mode 100644 index 2075e4c7..00000000 --- a/dmd/declaration.c +++ /dev/null @@ -1,1880 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "mtype.h" -#include "template.h" -#include "scope.h" -#include "aggregate.h" -#include "module.h" -#include "id.h" -#include "expression.h" -#include "hdrgen.h" - -/********************************* Declaration ****************************/ - -Declaration::Declaration(Identifier *id) - : Dsymbol(id) -{ - type = NULL; - originalType = NULL; - storage_class = STCundefined; - protection = PROTundefined; - linkage = LINKdefault; - inuse = 0; -} - -void Declaration::semantic(Scope *sc) -{ -} - -const char *Declaration::kind() -{ - return "declaration"; -} - -unsigned Declaration::size(Loc loc) -{ - assert(type); - return type->size(); -} - -int Declaration::isStaticConstructor() -{ - return FALSE; -} - -int Declaration::isStaticDestructor() -{ - return FALSE; -} - -int Declaration::isDelete() -{ - return FALSE; -} - -int Declaration::isDataseg() -{ - return FALSE; -} - -int Declaration::isThreadlocal() -{ - return FALSE; -} - -int Declaration::isCodeseg() -{ - return FALSE; -} - -enum PROT Declaration::prot() -{ - return protection; -} - -/************************************* - * Check to see if declaration can be modified in this context (sc). - * Issue error if not. - */ - -#if DMDV2 - -void Declaration::checkModify(Loc loc, Scope *sc, Type *t) -{ - if (sc->incontract && isParameter()) - error(loc, "cannot modify parameter '%s' in contract", toChars()); - - if (sc->incontract && isResult()) - error(loc, "cannot modify result '%s' in contract", toChars()); - - if (isCtorinit() && !t->isMutable() || - (storage_class & STCnodefaultctor)) - { // It's only modifiable if inside the right constructor - modifyFieldVar(loc, sc, isVarDeclaration(), NULL); - } - else - { - VarDeclaration *v = isVarDeclaration(); - if (v && v->canassign == 0) - { - const char *p = NULL; - if (isConst()) - p = "const"; - else if (isImmutable()) - p = "immutable"; - else if (isWild()) - p = "inout"; - else if (storage_class & STCmanifest) - p = "enum"; - else if (!t->isAssignable()) - p = "struct with immutable members"; - if (p) - { error(loc, "cannot modify %s", p); - } - } - } -} -#endif - - -/********************************* TupleDeclaration ****************************/ - -TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) - : Declaration(id) -{ - this->loc = loc; - this->type = NULL; - this->objects = objects; - this->isexp = 0; - this->tupletype = NULL; -} - -Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); - return NULL; -} - -const char *TupleDeclaration::kind() -{ - return "tuple"; -} - -Type *TupleDeclaration::getType() -{ - /* If this tuple represents a type, return that type - */ - - //printf("TupleDeclaration::getType() %s\n", toChars()); - if (isexp) - return NULL; - if (!tupletype) - { - /* It's only a type tuple if all the Object's are types - */ - for (size_t i = 0; i < objects->dim; i++) - { Object *o = (*objects)[i]; - - if (o->dyncast() != DYNCAST_TYPE) - { - //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); - return NULL; - } - } - - /* We know it's a type tuple, so build the TypeTuple - */ - Types *types = (Types *)objects; - Parameters *args = new Parameters(); - args->setDim(objects->dim); - OutBuffer buf; - int hasdeco = 1; - for (size_t i = 0; i < types->dim; i++) - { Type *t = (*types)[i]; - - //printf("type = %s\n", t->toChars()); -#if 0 - buf.printf("_%s_%d", ident->toChars(), i); - char *name = (char *)buf.extractData(); - Identifier *id = new Identifier(name, TOKidentifier); - Parameter *arg = new Parameter(STCin, t, id, NULL); -#else - Parameter *arg = new Parameter(STCin, t, NULL, NULL); -#endif - (*args)[i] = arg; - if (!t->deco) - hasdeco = 0; - } - - tupletype = new TypeTuple(args); - if (hasdeco) - return tupletype->semantic(0, NULL); - } - - return tupletype; -} - -int TupleDeclaration::needThis() -{ - //printf("TupleDeclaration::needThis(%s)\n", toChars()); - for (size_t i = 0; i < objects->dim; i++) - { Object *o = (*objects)[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - if (e->op == TOKdsymbol) - { DsymbolExp *ve = (DsymbolExp *)e; - Declaration *d = ve->s->isDeclaration(); - if (d && d->needThis()) - { - return 1; - } - } - } - } - return 0; -} - -/********************************* TypedefDeclaration ****************************/ - -TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) - : Declaration(id) -{ - this->type = new TypeTypedef(this); - this->basetype = basetype->toBasetype(); - this->init = init; - this->htype = NULL; - this->hbasetype = NULL; - this->sem = 0; - this->loc = loc; -#if IN_DMD - this->sinit = NULL; -#endif -} - -Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) -{ - Type *basetype = this->basetype->syntaxCopy(); - - Initializer *init = NULL; - if (this->init) - init = this->init->syntaxCopy(); - - assert(!s); - TypedefDeclaration *st; - st = new TypedefDeclaration(loc, ident, basetype, init); - - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - st->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - st->htype = htype->syntaxCopy(); - if (!hbasetype) - { if (basetype) - { hbasetype = basetype->syntaxCopy(); - st->hbasetype = basetype->syntaxCopy(); - } - } - else - st->hbasetype = hbasetype->syntaxCopy(); - - return st; -} - -void TypedefDeclaration::semantic(Scope *sc) -{ - //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); - if (sem == SemanticStart) - { sem = SemanticIn; - parent = sc->parent; - int errors = global.errors; - Type *savedbasetype = basetype; - basetype = basetype->semantic(loc, sc); - if (errors != global.errors) - { - basetype = savedbasetype; - sem = SemanticStart; - return; - } - sem = SemanticDone; -#if DMDV2 - type = type->addStorageClass(storage_class); -#endif - Type *savedtype = type; - type = type->semantic(loc, sc); - if (sc->parent->isFuncDeclaration() && init) - semantic2(sc); - if (errors != global.errors) - { - basetype = savedbasetype; - type = savedtype; - sem = SemanticStart; - return; - } - storage_class |= sc->stc & STCdeprecated; - } - else if (sem == SemanticIn) - { - error("circular definition"); - } -} - -void TypedefDeclaration::semantic2(Scope *sc) -{ - //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); - if (sem == SemanticDone) - { sem = Semantic2Done; - if (init) - { - Initializer *savedinit = init; - int errors = global.errors; - init = init->semantic(sc, basetype, INITinterpret); - if (errors != global.errors) - { - init = savedinit; - return; - } - - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - { - if (ie->exp->type == basetype) - ie->exp->type = type; - } - } - } -} - -const char *TypedefDeclaration::kind() -{ - return "typedef"; -} - -Type *TypedefDeclaration::getType() -{ - return type; -} - -void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typedef "); - basetype->toCBuffer(buf, ident, hgs); - if (init) - { - buf->writestring(" = "); - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -/********************************* AliasDeclaration ****************************/ - -AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) - : Declaration(id) -{ - //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type); - //printf("type = '%s'\n", type->toChars()); - this->loc = loc; - this->type = type; - this->aliassym = NULL; - this->htype = NULL; - this->haliassym = NULL; - this->overnext = NULL; - this->inSemantic = 0; - this->importprot = PROTundefined; - assert(type); -} - -AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) - : Declaration(id) -{ - //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s); - assert(s != this); - this->loc = loc; - this->type = NULL; - this->aliassym = s; - this->htype = NULL; - this->haliassym = NULL; - this->overnext = NULL; - this->inSemantic = 0; - assert(s); -} - -Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("AliasDeclaration::syntaxCopy()\n"); - assert(!s); - AliasDeclaration *sa; - if (type) - sa = new AliasDeclaration(loc, ident, type->syntaxCopy()); - else - sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sa->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sa->htype = htype->syntaxCopy(); - if (!haliassym) - { if (aliassym) - { haliassym = aliassym->syntaxCopy(s); - sa->haliassym = aliassym->syntaxCopy(s); - } - } - else - sa->haliassym = haliassym->syntaxCopy(s); - return sa; -} - -void AliasDeclaration::semantic(Scope *sc) -{ - //printf("AliasDeclaration::semantic() %s\n", toChars()); - if (aliassym) - { - if (aliassym->isTemplateInstance()) - aliassym->semantic(sc); - return; - } - this->inSemantic = 1; - -#if DMDV1 // don't really know why this is here - if (storage_class & STCconst) - error("cannot be const"); -#endif - - storage_class |= sc->stc & STCdeprecated; - protection = sc->protection; - - // Given: - // alias foo.bar.abc def; - // it is not knowable from the syntax whether this is an alias - // for a type or an alias for a symbol. It is up to the semantic() - // pass to distinguish. - // If it is a type, then type is set and getType() will return that - // type. If it is a symbol, then aliassym is set and type is NULL - - // toAlias() will return aliasssym. - - int errors = global.errors; - Type *savedtype = type; - - Dsymbol *s; - Type *t; - Expression *e; - - /* This section is needed because resolve() will: - * const x = 3; - * alias x y; - * try to alias y to 3. - */ - s = type->toDsymbol(sc); - if (s -#if DMDV2 - && ((s->getType() && type->equals(s->getType())) || s->isEnumMember()) -#endif - ) - goto L2; // it's a symbolic alias - -#if DMDV2 - type = type->addStorageClass(storage_class); - if (storage_class & (STCref | STCnothrow | STCpure | STCdisable)) - { // For 'ref' to be attached to function types, and picked - // up by Type::resolve(), it has to go into sc. - sc = sc->push(); - sc->stc |= storage_class & (STCref | STCnothrow | STCpure | STCshared | STCdisable); - type->resolve(loc, sc, &e, &t, &s); - sc = sc->pop(); - } - else -#endif - type->resolve(loc, sc, &e, &t, &s); - if (s) - { - goto L2; - } - else if (e) - { - // Try to convert Expression to Dsymbol - if (e->op == TOKvar) - { s = ((VarExp *)e)->var; - goto L2; - } - else if (e->op == TOKfunction) - { s = ((FuncExp *)e)->fd; - goto L2; - } - else - { if (e->op != TOKerror) - error("cannot alias an expression %s", e->toChars()); - t = e->type; - } - } - else if (t) - { - type = t->semantic(loc, sc); - - /* If type is class or struct, convert to symbol. - * See bugzilla 6475. - */ - s = type->toDsymbol(sc); - if (s -#if DMDV2 - && ((s->getType() && type->equals(s->getType())) || s->isEnumMember()) -#endif - ) - goto L2; - - //printf("\talias resolved to type %s\n", type->toChars()); - } - if (overnext) - ScopeDsymbol::multiplyDefined(0, this, overnext); - this->inSemantic = 0; - - if (global.gag && errors != global.errors) - type = savedtype; - return; - - L2: - //printf("alias is a symbol %s %s\n", s->kind(), s->toChars()); - type = NULL; - VarDeclaration *v = s->isVarDeclaration(); - if (0 && v && v->linkage == LINKdefault) - { - error("forward reference of %s", v->toChars()); - s = NULL; - } - else - { - Dsymbol *savedovernext = overnext; - FuncDeclaration *f = s->toAlias()->isFuncDeclaration(); - if (f) - { - if (overnext) - { - FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); - fa->importprot = importprot; - if (!fa->overloadInsert(overnext)) - ScopeDsymbol::multiplyDefined(0, f, overnext); - overnext = NULL; - s = fa; - s->parent = sc->parent; - } - } - if (overnext) - ScopeDsymbol::multiplyDefined(0, this, overnext); - if (s == this) - { - assert(global.errors); - s = NULL; - } - if (global.gag && errors != global.errors) - { - type = savedtype; - overnext = savedovernext; - aliassym = NULL; - inSemantic = 0; - return; - } - } - if (!type || type->ty != Terror) - { //printf("setting aliassym %s to %s %s\n", toChars(), s->kind(), s->toChars()); - aliassym = s; - } - this->inSemantic = 0; -} - -int AliasDeclaration::overloadInsert(Dsymbol *s) -{ - /* Don't know yet what the aliased symbol is, so assume it can - * be overloaded and check later for correctness. - */ - - //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars()); - if (aliassym) // see test/test56.d - { - Dsymbol *a = aliassym->toAlias(); - FuncDeclaration *f = a->isFuncDeclaration(); - if (f) // BUG: what if it's a template? - { - FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); - aliassym = fa; - return fa->overloadInsert(s); - } - } - - if (overnext == NULL) - { - if (s == this) - { - return TRUE; - } - overnext = s; - return TRUE; - } - else - { - return overnext->overloadInsert(s); - } -} - -const char *AliasDeclaration::kind() -{ - return "alias"; -} - -Type *AliasDeclaration::getType() -{ - //printf("AliasDeclaration::getType() %s\n", type->toChars()); -#if 0 - if (!type->deco && scope) - semantic(scope); - if (type && !type->deco) - error("forward reference to alias %s\n", toChars()); -#endif - return type; -} - -Dsymbol *AliasDeclaration::toAlias() -{ - //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : ""); - assert(this != aliassym); - //static int count; if (++count == 75) exit(0); //*(char*)0=0; - if (inSemantic) - { error("recursive alias declaration"); - aliassym = new AliasDeclaration(loc, ident, Type::terror); - type = Type::terror; - } - else if (aliassym || type->deco) - ; // semantic is already done. - else if (scope) - semantic(scope); - Dsymbol *s = aliassym ? aliassym->toAlias() : this; - return s; -} - -void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); -#if 0 - if (hgs->hdrgen) - { - if (haliassym) - { -#if !IN_LLVM - haliassym->toCBuffer(buf, hgs); -#else - buf->writestring(haliassym->toChars()); -#endif - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - htype->toCBuffer(buf, ident, hgs); - } - else -#endif - { - if (aliassym) - { -#if !IN_LLVM - aliassym->toCBuffer(buf, hgs); -#else - buf->writestring(aliassym->toChars()); -#endif - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - type->toCBuffer(buf, ident, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -/********************************* VarDeclaration ****************************/ - -VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init) - : Declaration(id) -{ - //printf("VarDeclaration('%s')\n", id->toChars()); -#ifdef DEBUG - if (!type && !init) - { printf("VarDeclaration('%s')\n", id->toChars()); - //*(char*)0=0; - } -#endif - assert(type || init); - this->type = type; - this->init = init; - this->htype = NULL; - this->hinit = NULL; - this->loc = loc; - offset = 0; - noscope = 0; -#if DMDV2 - isargptr = FALSE; -#endif -#if DMDV1 - nestedref = 0; -#endif - alignment = 0; - ctorinit = 0; - aliassym = NULL; - onstack = 0; - canassign = 0; - ctfeAdrOnStack = (size_t)(-1); -#if DMDV2 - rundtor = NULL; - edtor = NULL; -#endif - -#if IN_LLVM - aggrIndex = 0; - - nakedUse = false; - - availableExternally = true; // assume this unless proven otherwise -#endif -} - -Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); - - VarDeclaration *sv; - if (s) - { sv = (VarDeclaration *)s; - } - else - { - Initializer *init = NULL; - if (this->init) - { init = this->init->syntaxCopy(); - //init->isExpInitializer()->exp->print(); - //init->isExpInitializer()->exp->dump(0); - } - - sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); - sv->storage_class = storage_class; - } - - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sv->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sv->htype = htype->syntaxCopy(); - if (!hinit) - { if (init) - { hinit = init->syntaxCopy(); - sv->hinit = init->syntaxCopy(); - } - } - else - sv->hinit = hinit->syntaxCopy(); - return sv; -} - -void VarDeclaration::semantic(Scope *sc) -{ -#if 0 - printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); - printf(" type = %s\n", type ? type->toChars() : "null"); - printf(" stc = x%x\n", sc->stc); - printf(" storage_class = x%x\n", storage_class); - printf("linkage = %d\n", sc->linkage); - //if (strcmp(toChars(), "mul") == 0) halt(); -#endif - - if (scope) - { sc = scope; - scope = NULL; - } - - storage_class |= sc->stc; - if (storage_class & STCextern && init) - error("extern symbols cannot have initializers"); - - AggregateDeclaration *ad = isThis(); - if (ad) - storage_class |= ad->storage_class & STC_TYPECTOR; - - /* If auto type inference, do the inference - */ - int inferred = 0; - if (!type) - { inuse++; - type = init->inferType(sc); - type = type->semantic(loc, sc); - inuse--; - inferred = 1; - - /* This is a kludge to support the existing syntax for RAII - * declarations. - */ - storage_class &= ~STCauto; - originalType = type; - } - else - { if (!originalType) - originalType = type; - type = type->semantic(loc, sc); - } - //printf(" semantic type = %s\n", type ? type->toChars() : "null"); - - type->checkDeprecated(loc, sc); - linkage = sc->linkage; - this->parent = sc->parent; - //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); - protection = sc->protection; - //printf("sc->stc = %x\n", sc->stc); - //printf("storage_class = x%x\n", storage_class); - -#if DMDV2 - // Safety checks - if (sc->func && !sc->intypeof) - { - if (storage_class & STCgshared) - { - if (sc->func->setUnsafe()) - error("__gshared not allowed in safe functions; use shared"); - } - if (init && init->isVoidInitializer() && type->hasPointers()) - { - if (sc->func->setUnsafe()) - error("void initializers for pointers not allowed in safe functions"); - } - if (type->hasPointers() && type->toDsymbol(sc)) - { - Dsymbol *s = type->toDsymbol(sc); - if (s) - { - AggregateDeclaration *ad2 = s->isAggregateDeclaration(); - if (ad2 && ad2->hasUnions) - { - if (sc->func->setUnsafe()) - error("unions containing pointers are not allowed in @safe functions"); - } - } - } - } -#endif - - Dsymbol *parent = toParent(); - FuncDeclaration *fd = parent->isFuncDeclaration(); - - Type *tb = type->toBasetype(); - if (tb->ty == Tvoid && !(storage_class & STClazy)) - { error("voids have no value"); - type = Type::terror; - tb = type; - } - if (tb->ty == Tfunction) - { error("cannot be declared to be a function"); - type = Type::terror; - tb = type; - } - if (tb->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tb; - - if (!ts->sym->members) - { - error("no definition of struct %s", ts->toChars()); - } - } - if ((storage_class & STCauto) && !inferred) - error("storage class 'auto' has no effect if type is not inferred, did you mean 'scope'?"); - - if (tb->ty == Ttuple) - { /* Instead, declare variables for each of the tuple elements - * and add those. - */ - TypeTuple *tt = (TypeTuple *)tb; - size_t nelems = Parameter::dim(tt->arguments); - Objects *exps = new Objects(); - exps->setDim(nelems); - Expression *ie = init ? init->toExpression() : NULL; - - for (size_t i = 0; i < nelems; i++) - { Parameter *arg = Parameter::getNth(tt->arguments, i); - - OutBuffer buf; - buf.printf("_%s_field_%zu", ident->toChars(), i); - buf.writeByte(0); - const char *name = (const char *)buf.extractData(); - Identifier *id = Lexer::idPool(name); - - Expression *einit = ie; - if (ie && ie->op == TOKtuple) - { einit = (Expression *)((TupleExp *)ie)->exps->data[i]; - } - Initializer *ti = init; - if (einit) - { ti = new ExpInitializer(einit->loc, einit); - } - - VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); - //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); - v->semantic(sc); - -#if !IN_LLVM -// removed for LDC since TupleDeclaration::toObj already creates the fields; -// adding them to the scope again leads to duplicates - if (sc->scopesym) - { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); - if (sc->scopesym->members) - sc->scopesym->members->push(v); - } -#endif - - Expression *e = new DsymbolExp(loc, v); - exps->data[i] = e; - } - TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); - v2->isexp = 1; - aliassym = v2; - return; - } - - if (storage_class & STCconst && !init && !fd) - // Initialize by constructor only - storage_class = (storage_class & ~STCconst) | STCctorinit; - - if (isConst()) - { - } - else if (isStatic()) - { - } - else if (isSynchronized()) - { - error("variable %s cannot be synchronized", toChars()); - } - else if (isOverride()) - { - error("override cannot be applied to variable"); - } - else if (isAbstract()) - { - error("abstract cannot be applied to variable"); - } - else if (storage_class & STCtemplateparameter) - { - } - else if (storage_class & STCctfe) - { - } - else - { - AggregateDeclaration *aad = parent->isAggregateDeclaration(); - if (aad) - { -#if DMDV2 - assert(!(storage_class & (STCextern | STCstatic | STCtls | STCgshared))); - - if (storage_class & (STCconst | STCimmutable) && init) - { - if (!type->toBasetype()->isTypeBasic()) - storage_class |= STCstatic; - } - else -#endif - { - storage_class |= STCfield; - alignment = sc->structalign; -#if DMDV2 - if (tb->ty == Tstruct && ((TypeStruct *)tb)->sym->noDefaultCtor || - tb->ty == Tclass && ((TypeClass *)tb)->sym->noDefaultCtor) - aad->noDefaultCtor = TRUE; -#endif - } - } - - InterfaceDeclaration *id = parent->isInterfaceDeclaration(); - if (id) - { - error("field not allowed in interface"); - } - - /* Templates cannot add fields to aggregates - */ - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - AggregateDeclaration *ad2 = ti->tempdecl->isMember(); - if (ad2 && storage_class != STCundefined) - { - error("cannot use template to add field to aggregate '%s'", ad2->toChars()); - } - } - } - -#if DMDV2 - if ((storage_class & (STCref | STCparameter | STCforeach)) == STCref && - ident != Id::This) - { - error("only parameters or foreach declarations can be ref"); - } -#endif - - if (type->isscope() && !noscope) - { - if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd) - { - error("globals, statics, fields, ref and out parameters cannot be auto"); - } - - if (!(storage_class & STCscope)) - { - if (!(storage_class & STCparameter) && ident != Id::withSym) - error("reference to scope class must be scope"); - } - } - - enum TOK op = TOKconstruct; - if (!init && !sc->inunion && !isStatic() && !isConst() && fd && - !(storage_class & (STCfield | STCin | STCforeach)) && - type->size() != 0) - { - // Provide a default initializer - //printf("Providing default initializer for '%s'\n", toChars()); - if (type->ty == Tstruct && - ((TypeStruct *)type)->sym->zeroInit == 1) - { /* If a struct is all zeros, as a special case - * set it's initializer to the integer 0. - * In AssignExp::toElem(), we check for this and issue - * a memset() to initialize the struct. - * Must do same check in interpreter. - */ - Expression *e = new IntegerExp(loc, 0, Type::tint32); - Expression *e1; - e1 = new VarExp(loc, this); - e = new AssignExp(loc, e1, e); - e->op = TOKconstruct; - e->type = e1->type; // don't type check this, it would fail - init = new ExpInitializer(loc, e); - return; - } - else if (type->ty == Ttypedef) - { TypeTypedef *td = (TypeTypedef *)type; - if (td->sym->init) - { init = td->sym->init; - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - // Make copy so we can modify it - init = new ExpInitializer(ie->loc, ie->exp); - } - else - init = getExpInitializer(); - } - else - { - init = getExpInitializer(); - } - // Default initializer is always a blit - op = TOKblit; - } - - if (init) - { - sc = sc->push(); - sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCref); - - ArrayInitializer *ai = init->isArrayInitializer(); - if (ai && tb->ty == Taarray) - { - init = ai->toAssocArrayInitializer(); - } - - StructInitializer *si = init->isStructInitializer(); - ExpInitializer *ei = init->isExpInitializer(); - - // See if initializer is a NewExp that can be allocated on the stack - if (ei && isScope() && ei->exp->op == TOKnew) - { NewExp *ne = (NewExp *)ei->exp; - if (!(ne->newargs && ne->newargs->dim)) - { ne->onstack = 1; - onstack = 1; - if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) - onstack = 2; - } - } - - // If inside function, there is no semantic3() call - if (sc->func) - { - // If local variable, use AssignExp to handle all the various - // possibilities. - if (fd && !isStatic() && !isConst() && !init->isVoidInitializer()) - { - //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); - if (!ei) - { - Expression *e = init->toExpression(); - if (!e) - { - init = init->semantic(sc, type, INITnointerpret); - e = init->toExpression(); - if (!e) - { error("is not a static and cannot have static initializer"); - return; - } - } - ei = new ExpInitializer(init->loc, e); - init = ei; - } - - Expression *e1 = new VarExp(loc, this); - - Type *t = type->toBasetype(); - if (t->ty == Tsarray && !(storage_class & (STCref | STCout))) - { - ei->exp = ei->exp->semantic(sc); - if (!ei->exp->implicitConvTo(type)) - { - dinteger_t dim = ((TypeSArray *)t)->dim->toInteger(); - // If multidimensional static array, treat as one large array - while (1) - { - t = t->nextOf()->toBasetype(); - if (t->ty != Tsarray) - break; - dim *= ((TypeSArray *)t)->dim->toInteger(); - e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); - } - } - e1 = new SliceExp(loc, e1, NULL, NULL); - } - else if (t->ty == Tstruct) - { - ei->exp = ei->exp->semantic(sc); - ei->exp = resolveProperties(sc, ei->exp); - StructDeclaration *sd = ((TypeStruct *)t)->sym; -#if DMDV2 - /* Look to see if initializer is a call to the constructor - */ - if (sd->ctor && // there are constructors - ei->exp->type->ty == Tstruct && // rvalue is the same struct - ((TypeStruct *)ei->exp->type)->sym == sd && - ei->exp->op == TOKstar) - { - /* Look for form of constructor call which is: - * *__ctmp.ctor(arguments...) - */ - PtrExp *pe = (PtrExp *)ei->exp; - if (pe->e1->op == TOKcall) - { CallExp *ce = (CallExp *)pe->e1; - if (ce->e1->op == TOKdotvar) - { DotVarExp *dve = (DotVarExp *)ce->e1; - if (dve->var->isCtorDeclaration()) - { /* It's a constructor call, currently constructing - * a temporary __ctmp. - */ - /* Before calling the constructor, initialize - * variable with a bit copy of the default - * initializer - */ - Expression *e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); - e->op = TOKblit; - e->type = t; - ei->exp = new CommaExp(loc, e, ei->exp); - - /* Replace __ctmp being constructed with e1 - */ - dve->e1 = e1; - return; - } - } - } - } -#endif - if (!ei->exp->implicitConvTo(type)) - { - /* Look for opCall - * See bugzilla 2702 for more discussion - */ - Type *ti = ei->exp->type->toBasetype(); - // Don't cast away invariant or mutability in initializer - if (search_function(sd, Id::call) && - /* Initializing with the same type is done differently - */ - !(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) - { // Rewrite as e1.call(arguments) - Expression * eCall = new DotIdExp(loc, e1, Id::call); - ei->exp = new CallExp(loc, eCall, ei->exp); - } - } - } - ei->exp = new AssignExp(loc, e1, ei->exp); - ei->exp->op = TOKconstruct; - canassign++; - ei->exp = ei->exp->semantic(sc); - canassign--; - ei->exp->optimize(WANTvalue); - } - else - { - init = init->semantic(sc, type, INITinterpret); - if (fd && isConst() && !isStatic()) - { // Make it static - storage_class |= STCstatic; - } - } - } - else if (isConst() || isFinal() || - parent->isAggregateDeclaration()) - { - /* Because we may need the results of a const declaration in a - * subsequent type, such as an array dimension, before semantic2() - * gets ordinarily run, try to run semantic2() now. - * Ignore failure. - */ - - if (!global.errors && !inferred) - { - unsigned errors = global.startGagging(); - Expression *e; - Initializer *i2 = init; - inuse++; - if (ei) - { - e = ei->exp->syntaxCopy(); - e = e->semantic(sc); - e = e->implicitCastTo(sc, type); - } - else if (si || ai) - { i2 = init->syntaxCopy(); - i2 = i2->semantic(sc, type, INITinterpret); - } - inuse--; - if (global.endGagging(errors)) // if errors happened - { -#if DMDV2 - /* Save scope for later use, to try again - */ - scope = new Scope(*sc); - scope->setNoFree(); -#endif - } - else if (ei) - { - if (isDataseg() || (storage_class & STCmanifest)) - e = e->ctfeInterpret(); - else - e = e->optimize(WANTvalue); - switch (e->op) - { - case TOKint64: - case TOKfloat64: - case TOKstring: - case TOKarrayliteral: - case TOKassocarrayliteral: - case TOKstructliteral: - case TOKnull: - ei->exp = e; // no errors, keep result - break; - - default: -#if DMDV2 - /* Save scope for later use, to try again - */ - scope = new Scope(*sc); - scope->setNoFree(); -#endif - break; - } - } - else - init = i2; // no errors, keep result - } - } - sc = sc->pop(); - } -} - -ExpInitializer *VarDeclaration::getExpInitializer() -{ - ExpInitializer *ei; - - if (init) - ei = init->isExpInitializer(); - else - { - Expression *e = type->defaultInit(loc); - if (e) - ei = new ExpInitializer(loc, e); - else - ei = NULL; - } - return ei; -} - -void VarDeclaration::semantic2(Scope *sc) -{ - //printf("VarDeclaration::semantic2('%s')\n", toChars()); - // Inside unions, default to void initializers - if (!init && sc->inunion && !toParent()->isFuncDeclaration()) - { - AggregateDeclaration *aad = parent->isAggregateDeclaration(); - if (aad) - { - if (aad->fields[0] == this) - { - int hasinit = 0; - for (size_t i = 1; i < aad->fields.dim; i++) - { - if (aad->fields[i]->init && - !aad->fields[i]->init->isVoidInitializer()) - { - hasinit = 1; - break; - } - } - if (!hasinit) - init = new ExpInitializer(loc, type->defaultInitLiteral(loc)); - } - else - init = new VoidInitializer(loc); - } - } - if (init && !toParent()->isFuncDeclaration()) - { inuse++; -#if 0 - ExpInitializer *ei = init->isExpInitializer(); - if (ei) - { - ei->exp->dump(0); - printf("type = %p\n", ei->exp->type); - } -#endif - init = init->semantic(sc, type, INITinterpret); - inuse--; - } -} - -void VarDeclaration::semantic3(Scope *sc) -{ - // LDC - if (!global.params.useAvailableExternally) - availableExternally = false; - - // Preserve call chain - Declaration::semantic3(sc); -} - -void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad->toChars(), toChars()); - - if (aliassym) - { // If this variable was really a tuple, set the offsets for the tuple fields - TupleDeclaration *v2 = aliassym->isTupleDeclaration(); - assert(v2); - for (size_t i = 0; i < v2->objects->dim; i++) - { Object *o = (*v2->objects)[i]; - assert(o->dyncast() == DYNCAST_EXPRESSION); - Expression *e = (Expression *)o; - assert(e->op == TOKdsymbol); - DsymbolExp *se = (DsymbolExp *)e; - se->s->setFieldOffset(ad, poffset, isunion); - } - return; - } - - if (!(storage_class & STCfield)) - return; - assert(!(storage_class & (STCstatic | STCextern | STCparameter | STCtls))); - - /* Fields that are tuples appear both as part of TupleDeclarations and - * as members. That means ignore them if they are already a field. - */ - if (offset) - return; // already a field - for (size_t i = 0; i < ad->fields.dim; i++) - { - if (ad->fields[i] == this) - return; // already a field - } - - // Check for forward referenced types which will fail the size() call - Type *t = type->toBasetype(); - if (storage_class & STCref) - { // References are the size of a pointer - t = Type::tvoidptr; - } - if (t->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)t; -#if DMDV2 - if (ts->sym == ad) - { - ad->error("cannot have field %s with same struct type", toChars()); - } -#endif - - if (ts->sym->sizeok != SIZEOKdone && ts->sym->scope) - ts->sym->semantic(NULL); - if (ts->sym->sizeok != SIZEOKdone) - { - ad->sizeok = SIZEOKfwd; // cannot finish; flag as forward referenced - return; - } - } - if (t->ty == Tident) - { - ad->sizeok = SIZEOKfwd; // cannot finish; flag as forward referenced - return; - } - - unsigned memsize = t->size(loc); // size of member - unsigned memalignsize = t->alignsize(); // size of member for alignment purposes - structalign_t memalign = t->memalign(alignment); // alignment boundaries - - offset = AggregateDeclaration::placeField(poffset, memsize, memalignsize, memalign, - &ad->structsize, &ad->alignsize, isunion); - - //printf("\t%s: alignsize = %d\n", toChars(), alignsize); - - //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad->toChars(), offset, memsize); - ad->fields.push(this); -} - -const char *VarDeclaration::kind() -{ - return "variable"; -} - -Dsymbol *VarDeclaration::toAlias() -{ - //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym); - assert(this != aliassym); - Dsymbol *s = aliassym ? aliassym->toAlias() : this; - return s; -} - -void VarDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - StorageClassDeclaration::stcToCBuffer(buf, storage_class); - - /* If changing, be sure and fix CompoundDeclarationStatement::toCBuffer() - * too. - */ - if (type) - type->toCBuffer(buf, ident, hgs); - else - buf->writestring(ident->toChars()); - if (init) - { buf->writestring(" = "); -#if DMDV2 - ExpInitializer *ie = init->isExpInitializer(); - if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) - ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); - else -#endif - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -AggregateDeclaration *VarDeclaration::isThis() -{ - AggregateDeclaration *ad = NULL; - - if (!(storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | - STCtls | STCgshared | STCctfe))) - { - if ((storage_class & (STCconst | STCimmutable)) && init) - return NULL; - - for (Dsymbol *s = this; s; s = s->parent) - { - ad = s->isMember(); - if (ad) - break; - if (!s->parent || !s->parent->isTemplateMixin()) break; - } - } - return ad; -} - -int VarDeclaration::needThis() -{ - //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); - return storage_class & STCfield; -} - -int VarDeclaration::isImportedSymbol() -{ - if (protection == PROTexport && !init && (isStatic() || isConst() || parent->isModule())) - return TRUE; - return FALSE; -} - -void VarDeclaration::checkCtorConstInit() -{ - if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield)) - error("missing initializer in static constructor for const variable"); -} - -/************************************ - * Check to see if this variable is actually in an enclosing function - * rather than the current one. - */ - -void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) -{ - //printf("VarDeclaration::checkNestedReference() %s\n", toChars()); - if (parent && !isDataseg() && parent != sc->parent) - { - // The function that this variable is in - FuncDeclaration *fdv = toParent()->isFuncDeclaration(); - // The current function - FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); - - if (fdv && fdthis && fdv != fdthis) - { - nestedref = 1; -#if !IN_LLVM - // In LDC (D1), __ensure is actually just treated like a normal - // nested function, we don't use the magic stack layout hack like - // DMD (see DMD Bugzilla 7932 for why this was added). - if (fdthis->ident != Id::ensure) -#endif - { - /* __ensure is always called directly, - * so it never becomes closure. - */ - - if (loc.filename) - fdthis->getLevel(loc, fdv); - fdv->nestedFrameRef = 1; -#if IN_LLVM -#if DMDV1 - fdv->nestedVars.insert(this); -#endif -#endif - //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); - // __dollar creates problems because it isn't a real variable Bugzilla 3326 - if (ident == Id::dollar) - ::error(loc, "cannnot use $ inside a function literal"); - } - } - } -} - -/******************************* - * Does symbol go into data segment? - * Includes extern variables. - */ - -int VarDeclaration::isDataseg() -{ -#if 0 - printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); - printf("%llx, %p, %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance()); - printf("parent = '%s'\n", parent->toChars()); -#endif - Dsymbol *parent = this->toParent(); - if (!parent && !(storage_class & (STCstatic | STCconst))) - { error("forward referenced"); - type = Type::terror; - return 0; - } - return (storage_class & (STCstatic | STCconst) || - parent->isModule() || - parent->isTemplateInstance()); -} - -/************************************ - * Does symbol go into thread local storage? - */ - -int VarDeclaration::isThreadlocal() -{ - return 0; -} - -/******************************************** - * Can variable be read and written by CTFE? - */ - -int VarDeclaration::isCTFE() -{ - //printf("VarDeclaration::isCTFE(%p, '%s')\n", this, toChars()); - //printf("%llx\n", storage_class); - return (storage_class & STCctfe) != 0; // || !isDataseg(); -} - -int VarDeclaration::hasPointers() -{ - //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty); - return (!isDataseg() && type->hasPointers()); -} - -int VarDeclaration::isSameAsInitializer() -{ - if (init && init->isExpInitializer() && - init->isExpInitializer()->exp->op == TOKstructliteral) - return 0; - return isConst(); -} - -/****************************************** - * If a variable has a scope destructor call, return call for it. - * Otherwise, return NULL. - */ - -Expression *VarDeclaration::callScopeDtor(Scope *sc) -{ Expression *e = NULL; - - //printf("VarDeclaration::callScopeDtor() %s\n", toChars()); - if (storage_class & (STCauto | STCscope) && !noscope) - { - for (ClassDeclaration *cd = type->isClassHandle(); - cd; - cd = cd->baseClass) - { - /* We can do better if there's a way with onstack - * classes to determine if there's no way the monitor - * could be set. - */ - //if (cd->isInterfaceDeclaration()) - //error("interface %s cannot be scope", cd->toChars()); - if (1 || onstack || cd->dtors.dim) // if any destructors - { - // delete this; - Expression *ec; - - ec = new VarExp(loc, this); - e = new DeleteExp(loc, ec); - e->type = Type::tvoid; - break; - } - } - } - return e; -} - -/****************************************** - */ - -void ObjectNotFound(Identifier *id) -{ - Type::error(0, "%s not found. object.d may be incorrectly installed or corrupt.", id->toChars()); - fatal(); -} - - -/********************************* ClassInfoDeclaration ****************************/ - -ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd) - : VarDeclaration(0, ClassDeclaration::classinfo->type, cd->ident, NULL) -{ - this->cd = cd; - storage_class = STCstatic; -} - -Dsymbol *ClassInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void ClassInfoDeclaration::semantic(Scope *sc) -{ -} - -/********************************* ModuleInfoDeclaration ****************************/ - -ModuleInfoDeclaration::ModuleInfoDeclaration(Module *mod) - : VarDeclaration(0, Module::moduleinfo->type, mod->ident, NULL) -{ - this->mod = mod; - storage_class = STCstatic; -} - -Dsymbol *ModuleInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void ModuleInfoDeclaration::semantic(Scope *sc) -{ -} - -/********************************* TypeInfoDeclaration ****************************/ - -TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo, int internal) - : VarDeclaration(0, Type::typeinfo->type, tinfo->getTypeInfoIdent(internal), NULL) -{ - this->tinfo = tinfo; - storage_class = STCstatic; - protection = PROTpublic; - linkage = LINKc; -} - -Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void TypeInfoDeclaration::semantic(Scope *sc) -{ - assert(linkage == LINKc); -#if IN_LLVM - if (!global.params.useAvailableExternally) - availableExternally = false; -#endif -} - -/***************************** TypeInfoConstDeclaration **********************/ - -#if DMDV2 -TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoInvariantDeclaration **********************/ - -#if DMDV2 -TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoSharedDeclaration **********************/ - -#if DMDV2 -TypeInfoSharedDeclaration::TypeInfoSharedDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoStructDeclaration **********************/ - -TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoClassDeclaration ***********************/ - -TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoInterfaceDeclaration *******************/ - -TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoTypedefDeclaration *********************/ - -TypeInfoTypedefDeclaration::TypeInfoTypedefDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoPointerDeclaration *********************/ - -TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoArrayDeclaration ***********************/ - -TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoStaticArrayDeclaration *****************/ - -TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoAssociativeArrayDeclaration ************/ - -TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoEnumDeclaration ***********************/ - -TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoFunctionDeclaration ********************/ - -TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoDelegateDeclaration ********************/ - -TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoTupleDeclaration **********************/ - -TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/********************************* ThisDeclaration ****************************/ - -// For the "this" parameter to member functions - -ThisDeclaration::ThisDeclaration(Loc loc, Type *t) - : VarDeclaration(loc, t, Id::This, NULL) -{ - noscope = 1; -} - -Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -/********************** StaticStructInitDeclaration ***************************/ - -StaticStructInitDeclaration::StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym) - : Declaration(new Identifier("", TOKidentifier)) -{ - this->loc = loc; - this->dsym = dsym; - storage_class |= STCconst; -} diff --git a/dmd/declaration.h b/dmd/declaration.h deleted file mode 100644 index ba3a79a7..00000000 --- a/dmd/declaration.h +++ /dev/null @@ -1,1088 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_DECLARATION_H -#define DMD_DECLARATION_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#if IN_LLVM -#include -#include -#include -#if LDC_LLVM_VER >= 302 -#include "llvm/DebugInfo.h" -#else -#include "llvm/Analysis/DebugInfo.h" -#endif -#endif - -#include "dsymbol.h" -#include "lexer.h" -#include "mtype.h" - -struct Expression; -struct Statement; -struct LabelDsymbol; -struct LabelStatement; -struct Initializer; -struct Module; -struct InlineScanState; -struct ForeachStatement; -struct FuncDeclaration; -struct ExpInitializer; -struct StructDeclaration; -struct TupleType; -struct InterState; -struct IRState; -struct AnonDeclaration; - -enum PROT; -enum LINK; -enum TOK; -enum MATCH; - -enum STC -{ - STCundefined = 0, - STCstatic = 1, - STCextern = 2, - STCconst = 4, - STCfinal = 8, - STCabstract = 0x10, - STCparameter = 0x20, - STCfield = 0x40, - STCoverride = 0x80, - STCauto = 0x100, - STCsynchronized = 0x200, - STCdeprecated = 0x400, - STCin = 0x800, // in parameter - STCout = 0x1000, // out parameter - STClazy = 0x2000, // lazy parameter - STCforeach = 0x4000, // variable for foreach loop - STCcomdat = 0x8000, // should go into COMDAT record - STCvariadic = 0x10000, // variadic function argument - STCctorinit = 0x20000, // can only be set inside constructor - STCtemplateparameter = 0x40000, // template parameter - STCscope = 0x80000, // template parameter - STCimmutable = 0x100000, - STCref = 0x200000, - STCinit = 0x400000, // has explicit initializer - STCmanifest = 0x800000, // manifest constant - STCnodtor = 0x1000000, // don't run destructor - STCnothrow = 0x2000000, // never throws exceptions - STCpure = 0x4000000, // pure function - STCtls = 0x8000000, // thread local - STCalias = 0x10000000, // alias parameter - STCshared = 0x20000000, // accessible from multiple threads - STCgshared = 0x40000000, // accessible from multiple threads - // but not typed as "shared" - STCwild = 0x80000000, // for "wild" type constructor - STC_TYPECTOR = (STCconst | STCimmutable | STCshared | STCwild), -}; - -#define STCproperty 0x100000000LL -#define STCsafe 0x200000000LL -#define STCtrusted 0x400000000LL -#define STCsystem 0x800000000LL -#define STCctfe 0x1000000000LL // can be used in CTFE, even if it is static -#define STCdisable 0x2000000000LL // for functions that are not callable -#define STCresult 0x4000000000LL // for result variables passed to out contracts - -struct Match -{ - int count; // number of matches found - MATCH last; // match level of lastf - FuncDeclaration *lastf; // last matching function we found - FuncDeclaration *nextf; // current matching function - FuncDeclaration *anyf; // pick a func, any func, to use for error recovery -}; - -void overloadResolveX(Match *m, FuncDeclaration *f, - Expression *ethis, Expressions *arguments, Module *from); -int overloadApply(Module* from, FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param); - -enum Semantic -{ - SemanticStart, // semantic has not been run - SemanticIn, // semantic() is in progress - SemanticDone, // semantic() has been run - Semantic2Done, // semantic2() has been run -}; - -/**************************************************************/ - -struct Declaration : Dsymbol -{ - Type *type; - Type *originalType; // before semantic analysis - StorageClass storage_class; - enum PROT protection; - enum LINK linkage; - int inuse; // used to detect cycles - - Declaration(Identifier *id); - void semantic(Scope *sc); - const char *kind(); - unsigned size(Loc loc); - void checkModify(Loc loc, Scope *sc, Type *t); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toDocBuffer(OutBuffer *buf); - - char *mangle(); - int isStatic() { return storage_class & STCstatic; } - virtual int isStaticConstructor(); - virtual int isStaticDestructor(); - virtual int isDelete(); - virtual int isDataseg(); - virtual int isThreadlocal(); - virtual int isCodeseg(); - int isCtorinit() { return storage_class & STCctorinit; } - int isFinal() { return storage_class & STCfinal; } - int isAbstract() { return storage_class & STCabstract; } - int isConst() { return storage_class & STCconst; } - int isImmutable() { return storage_class & STCimmutable; } - int isAuto() { return storage_class & STCauto; } - int isScope() { return storage_class & STCscope; } - int isSynchronized() { return storage_class & STCsynchronized; } - int isParameter() { return storage_class & STCparameter; } - int isDeprecated() { return storage_class & STCdeprecated; } - int isOverride() { return storage_class & STCoverride; } - - virtual int isSameAsInitializer() { return isConst(); }; - - int isIn() { return storage_class & STCin; } - int isOut() { return storage_class & STCout; } - int isRef() { return storage_class & STCref; } - - enum PROT prot(); - - Declaration *isDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct TupleDeclaration : Declaration -{ - Objects *objects; - int isexp; // 1: expression tuple - - TypeTuple *tupletype; // !=NULL if this is a type tuple - - TupleDeclaration(Loc loc, Identifier *ident, Objects *objects); - Dsymbol *syntaxCopy(Dsymbol *); - const char *kind(); - Type *getType(); - int needThis(); - - TupleDeclaration *isTupleDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct TypedefDeclaration : Declaration -{ - Type *basetype; - Initializer *init; - int sem; // 0: semantic() has not been run - // 1: semantic() is in progress - // 2: semantic() has been run - // 3: semantic2() has been run - - TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - char *mangle(); - const char *kind(); - Type *getType(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *htype; - Type *hbasetype; - - void toDocBuffer(OutBuffer *buf); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - int cvMember(unsigned char *p); -#endif - - TypedefDeclaration *isTypedefDeclaration() { return this; } - -#if IN_DMD - Symbol *sinit; - Symbol *toInitializer(); -#endif - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct AliasDeclaration : Declaration -{ - Dsymbol *aliassym; - Dsymbol *overnext; // next in overload list - int inSemantic; - PROT importprot; // if generated by import, store its protection - - AliasDeclaration(Loc loc, Identifier *ident, Type *type); - AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int overloadInsert(Dsymbol *s); - const char *kind(); - Type *getType(); - Dsymbol *toAlias(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *htype; - Dsymbol *haliassym; - - void toDocBuffer(OutBuffer *buf); - - AliasDeclaration *isAliasDeclaration() { return this; } -}; - -/**************************************************************/ - -struct VarDeclaration : Declaration -{ - Initializer *init; - unsigned offset; - int noscope; // no auto semantics -#if DMDV2 - FuncDeclarations nestedrefs; // referenced by these lexically nested functions - bool isargptr; // if parameter that _argptr points to -#else - int nestedref; // referenced by a lexically nested function -#endif - structalign_t alignment; - int ctorinit; // it has been initialized in a ctor - int onstack; // 1: it has been allocated on the stack - // 2: on stack, run destructor anyway - int canassign; // it can be assigned to - Dsymbol *aliassym; // if redone as alias to another symbol - - // When interpreting, these point to the value (NULL if value not determinable) - // The index of this variable on the CTFE stack, -1 if not allocated - size_t ctfeAdrOnStack; - // The various functions are used only to detect compiler CTFE bugs - Expression *getValue(); - bool hasValue(); - void setValueNull(); - void setValueWithoutChecking(Expression *newval); - void setValue(Expression *newval); - -#if DMDV2 - VarDeclaration *rundtor; // if !NULL, rundtor is tested at runtime to see - // if the destructor should be run. Used to prevent - // dtor calls on postblitted vars - Expression *edtor; // if !=NULL, does the destruction of the variable -#endif - - VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - void semantic2(Scope *sc); - const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *htype; - Initializer *hinit; - AggregateDeclaration *isThis(); - int needThis(); - int isImportedSymbol(); - int isDataseg(); - int isThreadlocal(); - int isCTFE(); - int hasPointers(); -#if DMDV2 - int canTakeAddressOf(); - int needsAutoDtor(); -#endif - Expression *callScopeDtor(Scope *sc); - ExpInitializer *getExpInitializer(); - Expression *getConstInitializer(); - void checkCtorConstInit(); - void checkNestedReference(Scope *sc, Loc loc); - Dsymbol *toAlias(); - - virtual int isSameAsInitializer(); - -#if IN_DMD - Symbol *toSymbol(); - void toObjFile(int multiobj); // compile to .obj file - int cvMember(unsigned char *p); -#endif - - // Eliminate need for dynamic_cast - VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } - -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); - - /// Index into parent aggregate. - /// Set during type generation. - unsigned aggrIndex; - - /// Variables that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. - bool availableExternally; - /// Override added to set above flag. - void semantic3(Scope *sc); - - /// This var is used by a naked function. - bool nakedUse; - - // debug description - llvm::DIVariable debugVariable; - llvm::DISubprogram debugFunc; -#endif -}; - -/**************************************************************/ - -// LDC uses this to denote static struct initializers - -struct StaticStructInitDeclaration : Declaration -{ - StructDeclaration *dsym; - - StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym); - -#if IN_DMD - Symbol *toSymbol(); -#endif - - // Eliminate need for dynamic_cast - StaticStructInitDeclaration *isStaticStructInitDeclaration() { return (StaticStructInitDeclaration *)this; } -}; - -struct ClassInfoDeclaration : VarDeclaration -{ - ClassDeclaration *cd; - - ClassInfoDeclaration(ClassDeclaration *cd); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - -#if IN_DMD - Symbol *toSymbol(); -#endif - - ClassInfoDeclaration* isClassInfoDeclaration() { return this; } -}; - -struct ModuleInfoDeclaration : VarDeclaration -{ - Module *mod; - - ModuleInfoDeclaration(Module *mod); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - -#if IN_DMD - Symbol *toSymbol(); -#endif -}; - -struct TypeInfoDeclaration : VarDeclaration -{ - Type *tinfo; - - TypeInfoDeclaration(Type *tinfo, int internal); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - -#if IN_DMD - Symbol *toSymbol(); - void toObjFile(int multiobj); // compile to .obj file - virtual void toDt(dt_t **pdt); -#endif - - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); - virtual void llvmDefine(); -#endif -}; - -struct TypeInfoStructDeclaration : TypeInfoDeclaration -{ - TypeInfoStructDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoClassDeclaration : TypeInfoDeclaration -{ - TypeInfoClassDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration -{ - TypeInfoInterfaceDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoTypedefDeclaration : TypeInfoDeclaration -{ - TypeInfoTypedefDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoPointerDeclaration : TypeInfoDeclaration -{ - TypeInfoPointerDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoStaticArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoAssociativeArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoEnumDeclaration : TypeInfoDeclaration -{ - TypeInfoEnumDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoFunctionDeclaration : TypeInfoDeclaration -{ - TypeInfoFunctionDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoDelegateDeclaration : TypeInfoDeclaration -{ - TypeInfoDelegateDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoTupleDeclaration : TypeInfoDeclaration -{ - TypeInfoTupleDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -#if DMDV2 -struct TypeInfoConstDeclaration : TypeInfoDeclaration -{ - TypeInfoConstDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoInvariantDeclaration : TypeInfoDeclaration -{ - TypeInfoInvariantDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoSharedDeclaration : TypeInfoDeclaration -{ - TypeInfoSharedDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); -}; - -struct TypeInfoWildDeclaration : TypeInfoDeclaration -{ - TypeInfoWildDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); -}; -#endif - -/**************************************************************/ - -struct ThisDeclaration : VarDeclaration -{ - ThisDeclaration(Loc loc, Type *t); - Dsymbol *syntaxCopy(Dsymbol *); - ThisDeclaration *isThisDeclaration() { return this; } -}; - -enum ILS -{ - ILSuninitialized, // not computed yet - ILSno, // cannot inline - ILSyes, // can inline -}; - -/**************************************************************/ -#if DMDV2 - -enum BUILTIN -{ - BUILTINunknown = -1, // not known if this is a builtin - BUILTINnot, // this is not a builtin - BUILTINsin, // std.math.sin - BUILTINcos, // std.math.cos - BUILTINtan, // std.math.tan - BUILTINsqrt, // std.math.sqrt - BUILTINfabs, // std.math.fabs - BUILTINatan2, // std.math.atan2 - BUILTINrndtol, // std.math.rndtol - BUILTINexpm1, // std.math.expm1 - BUILTINexp2, // std.math.exp2 - BUILTINyl2x, // std.math.yl2x - BUILTINyl2xp1, // std.math.yl2xp1 - BUILTINbsr, // core.bitop.bsr - BUILTINbsf, // core.bitop.bsf - BUILTINbswap, // core.bitop.bswap -}; - -Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments); - -#else -enum BUILTIN { }; -#endif - -struct FuncDeclaration : Declaration -{ - Types *fthrows; // Array of Type's of exceptions (not used) - Statement *frequire; - Statement *fensure; - Statement *fbody; - - FuncDeclarations foverrides; // functions this function overrides - FuncDeclaration *fdrequire; // function that does the in contract - FuncDeclaration *fdensure; // function that does the out contract - - Identifier *outId; // identifier for out statement - VarDeclaration *vresult; // variable corresponding to outId - LabelDsymbol *returnLabel; // where the return goes - Scope *scout; // out contract scope for vresult->semantic - - DsymbolTable *localsymtab; // used to prevent symbols in different - // scopes from having the same name - VarDeclaration *vthis; // 'this' parameter (member and nested) - VarDeclaration *v_arguments; // '_arguments' parameter -#if IN_GCC - VarDeclaration *v_argptr; // '_argptr' variable -#endif - VarDeclaration *v_argsave; // save area for args passed in registers for variadic functions - VarDeclarations *parameters; // Array of VarDeclaration's for parameters - DsymbolTable *labtab; // statement label symbol table - Declaration *overnext; // next in overload list - Loc endloc; // location of closing curly bracket - int vtblIndex; // for member functions, index into vtbl[] - int naked; // !=0 if naked - int inlineAsm; // !=0 if has inline assembler - ILS inlineStatusStmt; - ILS inlineStatusExp; - int inlineNest; // !=0 if nested inline - int isArrayOp; // !=0 if array operation - int semanticRun; // 1 semantic() run - // 2 semantic2() run - // 3 semantic3() started - // 4 semantic3() done - // 5 toObjFile() run - // this function's frame ptr - int semantic3Errors; // !=0 if errors in semantic3 - ForeachStatement *fes; // if foreach body, this is the foreach - int introducing; // !=0 if 'introducing' function - Type *tintro; // if !=NULL, then this is the type - // of the 'introducing' function - // this one is overriding - int inferRetType; // !=0 if return type is to be inferred - - // Things that should really go into Scope - int hasReturnExp; // 1 if there's a return exp; statement - // 2 if there's a throw statement - // 4 if there's an assert(0) - // 8 if there's inline asm - - // Support for NRVO (named return value optimization) - int nrvo_can; // !=0 means we can do it - VarDeclaration *nrvo_var; // variable to replace with shidden -#if IN_DMD - Symbol *shidden; // hidden pointer passed to function -#endif - -#if DMDV2 - enum BUILTIN builtin; // set if this is a known, builtin - // function we can evaluate at compile - // time - - int tookAddressOf; // set if someone took the address of - // this function - VarDeclarations closureVars; // local variables in this function - // which are referenced by nested - // functions - - unsigned flags; - #define FUNCFLAGpurityInprocess 1 // working on determining purity - #define FUNCFLAGsafetyInprocess 2 // working on determining safety - #define FUNCFLAGnothrowInprocess 4 // working on determining nothrow -#else - int nestedFrameRef; // !=0 if nested variables referenced -#endif - - FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - // called from semantic3 - void varArgs(Scope *sc, TypeFunction*, VarDeclaration *&, VarDeclaration *&); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); - int overrides(FuncDeclaration *fd); - int findVtblIndex(Dsymbols *vtbl, int dim); - int overloadInsert(Dsymbol *s); - FuncDeclaration *overloadExactMatch(Type *t, Module* from); - FuncDeclaration *overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, Module *from, int flags = 0); - MATCH leastAsSpecialized(FuncDeclaration *g); - LabelDsymbol *searchLabel(Identifier *ident); - AggregateDeclaration *isThis(); - AggregateDeclaration *isMember2(); - int getLevel(Loc loc, FuncDeclaration *fd); // lexical nesting level difference - void appendExp(Expression *e); - void appendState(Statement *s); - char *mangle(); - const char *toPrettyChars(); - int isMain(); - int isWinMain(); - int isDllMain(); - enum BUILTIN isBuiltin(); - int isExport(); - int isImportedSymbol(); - int isAbstract(); - int isCodeseg(); - int isOverloadable(); - int hasOverloads(); - int isPure(); - int isSafe(); - int isTrusted(); - virtual int isNested(); - int needThis(); - int isVirtualMethod(); - virtual int isVirtual(); - virtual int isFinal(); - virtual int addPreInvariant(); - virtual int addPostInvariant(); - Expression *interpret(InterState *istate, Expressions *arguments, Expression *thisexp = NULL); - void inlineScan(); - int canInline(int hasthis, int hdrscan = false, int statementsToo = true); - Expression *expandInline(InlineScanState *iss, Expression *ethis, Expressions *arguments, Statement **ps); - const char *kind(); - void toDocBuffer(OutBuffer *buf); - FuncDeclaration *isUnique(); - int needsClosure(); - int hasNestedFrameRefs(); - void buildResultVar(); - Statement *mergeFrequire(Statement *); - Statement *mergeFensure(Statement *); - Parameters *getParameters(int *pvarargs); - -// LDC: give argument types to runtime functions - static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name); - static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id); - -#if IN_DMD - Symbol *toSymbol(); - Symbol *toThunkSymbol(int offset); // thunk version - void toObjFile(int multiobj); // compile to .obj file - int cvMember(unsigned char *p); - void buildClosure(IRState *irs); -#endif - - FuncDeclaration *isFuncDeclaration() { return this; } - -#if IN_LLVM - // LDC stuff - - /// Codegen traversal - void codegen(Ir* ir); - - // vars declared in this function that nested funcs reference - // is this is not empty, nestedFrameRef is set and these VarDecls - // probably have nestedref set too, see VarDeclaration::checkNestedReference - std::set nestedVars; - - std::string intrinsicName; - uint32_t priority; - - bool isIntrinsic(); - bool isVaIntrinsic(); - - // we keep our own table of label statements as LabelDsymbolS - // don't always carry their corresponding statement along ... - typedef std::map LabelMap; - LabelMap labmap; - - // Functions that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. - bool availableExternally; - - // true if overridden with the pragma(allow_inline); stmt - bool allowInlining; -#endif -}; - -#if DMDV2 -FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, - Objects *tiargs, - Expression *ethis, - Expressions *arguments, - int flags); -#endif - -struct FuncAliasDeclaration : FuncDeclaration -{ - FuncDeclaration *funcalias; - PROT importprot; // if generated by import, store its protection - - FuncAliasDeclaration(FuncDeclaration *funcalias); - - FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } - const char *kind(); -#if IN_DMD - Symbol *toSymbol(); -#endif -}; - -struct FuncLiteralDeclaration : FuncDeclaration -{ - enum TOK tok; // TOKfunction or TOKdelegate - - FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok, - ForeachStatement *fes); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Dsymbol *syntaxCopy(Dsymbol *); - int isNested(); - int isVirtual(); - - FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } - const char *kind(); -}; - -struct CtorDeclaration : FuncDeclaration -{ Parameters *arguments; - int varargs; - - CtorDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void toDocBuffer(OutBuffer *buf); - - CtorDeclaration *isCtorDeclaration() { return this; } -}; - -#if DMDV2 -struct PostBlitDeclaration : FuncDeclaration -{ - PostBlitDeclaration(Loc loc, Loc endloc); - PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - - PostBlitDeclaration *isPostBlitDeclaration() { return this; } -}; -#endif - -struct DtorDeclaration : FuncDeclaration -{ - DtorDeclaration(Loc loc, Loc endloc); - DtorDeclaration(Loc loc, Loc endloc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - - DtorDeclaration *isDtorDeclaration() { return this; } -}; - -struct StaticCtorDeclaration : FuncDeclaration -{ - StaticCtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isStaticConstructor(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - bool hasStaticCtorOrDtor(); - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } -}; - -#if DMDV2 -struct SharedStaticCtorDeclaration : StaticCtorDeclaration -{ - SharedStaticCtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return this; } -}; -#endif - -struct StaticDtorDeclaration : FuncDeclaration -{ VarDeclaration *vgate; // 'gate' variable - - StaticDtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isStaticDestructor(); - int isVirtual(); - bool hasStaticCtorOrDtor(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } -}; - -#if DMDV2 -struct SharedStaticDtorDeclaration : StaticDtorDeclaration -{ - SharedStaticDtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return this; } -}; -#endif - -struct InvariantDeclaration : FuncDeclaration -{ - InvariantDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - InvariantDeclaration *isInvariantDeclaration() { return this; } -}; - -struct UnitTestDeclaration : FuncDeclaration -{ - UnitTestDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); - - UnitTestDeclaration *isUnitTestDeclaration() { return this; } -}; - -struct NewDeclaration : FuncDeclaration -{ Parameters *arguments; - int varargs; - - NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - - NewDeclaration *isNewDeclaration() { return this; } -}; - - -struct DeleteDeclaration : FuncDeclaration -{ Parameters *arguments; - - DeleteDeclaration(Loc loc, Loc endloc, Parameters *arguments); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - int isDelete(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - DeleteDeclaration *isDeleteDeclaration() { return this; } -}; - -#endif /* DMD_DECLARATION_H */ diff --git a/dmd/delegatize.c b/dmd/delegatize.c deleted file mode 100644 index a4d37152..00000000 --- a/dmd/delegatize.c +++ /dev/null @@ -1,140 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "expression.h" -#include "statement.h" -#include "mtype.h" -#include "utf.h" -#include "declaration.h" -#include "aggregate.h" -#include "scope.h" - -/******************************************** - * Convert from expression to delegate that returns the expression, - * i.e. convert: - * expr - * to: - * t delegate() { return expr; } - */ - -int lambdaSetParent(Expression *e, void *param); -int lambdaCheckForNestedRef(Expression *e, void *param); - -Expression *Expression::toDelegate(Scope *sc, Type *t) -{ - //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), toChars()); - TypeFunction *tf = new TypeFunction(NULL, t, 0, LINKd); - FuncLiteralDeclaration *fld = - new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL); - Expression *e; - sc = sc->push(); - sc->parent = fld; // set current function to be the delegate - e = this; - e->apply(&lambdaSetParent, sc); - e->apply(&lambdaCheckForNestedRef, sc); - sc = sc->pop(); - Statement *s; - if (t->ty == Tvoid) - s = new ExpStatement(loc, e); - else - s = new ReturnStatement(loc, e); - fld->fbody = s; - e = new FuncExp(loc, fld); - e = e->semantic(sc); - return e; -} - -/****************************************** - * Patch the parent of declarations to be the new function literal. - */ -int lambdaSetParent(Expression *e, void *param) -{ - Scope *sc = (Scope *)param; - /* We could use virtual functions instead of a switch, - * but it doesn't seem worth the bother. - */ - switch (e->op) - { - case TOKdeclaration: - { DeclarationExp *de = (DeclarationExp *)e; - de->declaration->parent = sc->parent; - break; - } - - case TOKindex: - { IndexExp *de = (IndexExp *)e; - if (de->lengthVar) - { //printf("lengthVar\n"); - de->lengthVar->parent = sc->parent; - } - break; - } - - case TOKslice: - { SliceExp *se = (SliceExp *)e; - if (se->lengthVar) - { //printf("lengthVar\n"); - se->lengthVar->parent = sc->parent; - } - break; - } - - default: - break; - } - return 0; -} - -/******************************************* - * Look for references to variables in a scope enclosing the new function literal. - */ -int lambdaCheckForNestedRef(Expression *e, void *param) -{ - Scope *sc = (Scope *)param; - /* We could use virtual functions instead of a switch, - * but it doesn't seem worth the bother. - */ - switch (e->op) - { - case TOKsymoff: - { SymOffExp *se = (SymOffExp *)e; - VarDeclaration *v = se->var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, 0); - break; - } - - case TOKvar: - { VarExp *ve = (VarExp *)e; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, 0); - break; - } - - case TOKthis: - case TOKsuper: - { ThisExp *te = (ThisExp *)e; - VarDeclaration *v = te->var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, 0); - break; - } - - default: - break; - } - return 0; -} - diff --git a/dmd/doc.c b/dmd/doc.c deleted file mode 100644 index a616b84f..00000000 --- a/dmd/doc.c +++ /dev/null @@ -1,2230 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// This implements the Ddoc capability. - -#include -#include -#include -#include -#include - -#include "rmem.h" -#include "root.h" - -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ -#include "gnuc.h" -#endif - -#include "mars.h" -#include "dsymbol.h" -#include "macro.h" -#include "template.h" -#include "lexer.h" -#include "aggregate.h" -#include "declaration.h" -#include "enum.h" -#include "id.h" -#include "module.h" -#include "scope.h" -#include "hdrgen.h" -#include "doc.h" -#include "mtype.h" -#include "utf.h" - -struct Escape -{ - const char *strings[256]; - - static const char *escapeChar(unsigned c); -}; - -struct Section -{ - unsigned char *name; - unsigned namelen; - - unsigned char *body; - unsigned bodylen; - - int nooutput; - - virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -struct ParamSection : Section -{ - void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -struct MacroSection : Section -{ - void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -typedef ArrayBase
Sections; - -struct DocComment -{ - Sections sections; // Section*[] - - Section *summary; - Section *copyright; - Section *macros; - Macro **pmacrotable; - Escape **pescapetable; - - DocComment() : - summary(NULL), copyright(NULL), macros(NULL), pmacrotable(NULL), pescapetable(NULL) - { } - - static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); - static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen); - static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen); - - void parseSections(unsigned char *comment); - void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - - -int cmp(const char *stringz, void *s, size_t slen); -int icmp(const char *stringz, void *s, size_t slen); -int isDitto(unsigned char *comment); -unsigned char *skipwhitespace(unsigned char *p); -unsigned skiptoident(OutBuffer *buf, size_t i); -unsigned skippastident(OutBuffer *buf, size_t i); -unsigned skippastURL(OutBuffer *buf, size_t i); -void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); - -int isIdStart(unsigned char *p); -int isIdTail(unsigned char *p); -int utfStride(unsigned char *p); - -static unsigned char ddoc_default[] = "\ -DDOC = \n\ - \n\ - $(TITLE)\n\ - \n\ -

$(TITLE)

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

$0

\n\ -DL =
$0
\n\ -DT =
$0
\n\ -DD =
$0
\n\ -TABLE = $0
\n\ -TR = $0\n\ -TH = $0\n\ -TD = $0\n\ -OL =
    $0
\n\ -UL =
    $0
\n\ -LI =
  • $0
  • \n\ -BIG = $0\n\ -SMALL = $0\n\ -BR =
    \n\ -LINK = $0\n\ -LINK2 = $+\n\ -LPAREN= (\n\ -RPAREN= )\n\ -DOLLAR= $\n\ -\n\ -RED = $0\n\ -BLUE = $0\n\ -GREEN = $0\n\ -YELLOW =$0\n\ -BLACK = $0\n\ -WHITE = $0\n\ -\n\ -D_CODE =
    $0
    \n\ -D_COMMENT = $(GREEN $0)\n\ -D_STRING = $(RED $0)\n\ -D_KEYWORD = $(BLUE $0)\n\ -D_PSYMBOL = $(U $0)\n\ -D_PARAM = $(I $0)\n\ -\n\ -DDOC_COMMENT = \n\ -DDOC_DECL = $(DT $(BIG $0))\n\ -DDOC_DECL_DD = $(DD $0)\n\ -DDOC_DITTO = $(BR)$0\n\ -DDOC_SECTIONS = $0\n\ -DDOC_SUMMARY = $0$(BR)$(BR)\n\ -DDOC_DESCRIPTION = $0$(BR)$(BR)\n\ -DDOC_AUTHORS = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_BUGS = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_DATE = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_EXAMPLES = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_HISTORY = $(B History:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_LICENSE = $(B License:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_RETURNS = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_SEE_ALSO = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_THROWS = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_VERSION = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_SECTION_H = $(B $0)$(BR)\n\ -DDOC_SECTION = $0$(BR)$(BR)\n\ -DDOC_MEMBERS = $(DL $0)\n\ -DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\ -DDOC_PARAM_ROW = $(TR $0)\n\ -DDOC_PARAM_ID = $(TD $0)\n\ -DDOC_PARAM_DESC = $(TD $0)\n\ -DDOC_BLANKLINE = $(BR)$(BR)\n\ -\n\ -DDOC_PSYMBOL = $(U $0)\n\ -DDOC_KEYWORD = $(B $0)\n\ -DDOC_PARAM = $(I $0)\n\ -\n\ -ESCAPES = //>/\n\ - /&/&/\n\ -"; - -static char ddoc_decl_s[] = "$(DDOC_DECL "; -static char ddoc_decl_e[] = ")\n"; - -static char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD "; -static char ddoc_decl_dd_e[] = ")\n"; - - -/**************************************************** - */ - -void Module::gendocfile() -{ - static OutBuffer mbuf; - static int mbuf_done; - - OutBuffer buf; - - //printf("Module::gendocfile()\n"); - - if (!mbuf_done) // if not already read the ddoc files - { mbuf_done = 1; - - // Use our internal default - mbuf.write(ddoc_default, sizeof(ddoc_default) - 1); - - // Override with DDOCFILE specified in the sc.ini file - char *p = getenv("DDOCFILE"); - if (p) - global.params.ddocfiles->shift(p); - - // Override with the ddoc macro files from the command line - for (size_t i = 0; i < global.params.ddocfiles->dim; i++) - { - FileName f((*global.params.ddocfiles)[i], 0); - File file(&f); - file.readv(); - // BUG: convert file contents to UTF-8 before use - - //printf("file: '%.*s'\n", file.len, file.buffer); - mbuf.write(file.buffer, file.len); - } - } - DocComment::parseMacros(&escapetable, ¯otable, mbuf.data, mbuf.offset); - - Scope *sc = Scope::createGlobal(this); // create root scope - sc->docbuf = &buf; - - DocComment *dc = DocComment::parse(sc, this, comment); - dc->pmacrotable = ¯otable; - dc->pescapetable = &escapetable; - - // Generate predefined macros - - // Set the title to be the name of the module - { const char *p = toPrettyChars(); - Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); - } - - // Set time macros - { time_t t; - time(&t); - char *p = ctime(&t); - p = mem.strdup(p); - Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); - Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); - } - - char *srcfilename = srcfile->toChars(); - Macro::define(¯otable, (unsigned char *)"SRCFILENAME", 11, (unsigned char *)srcfilename, strlen(srcfilename)); - - char *docfilename = docfile->toChars(); - Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); - - if (dc->copyright) - { - dc->copyright->nooutput = 1; - Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); - } - - buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); - if (isDocFile) - { - size_t commentlen = strlen((char *)comment); - if (dc->macros) - { - commentlen = dc->macros->name - comment; - dc->macros->write(dc, sc, this, sc->docbuf); - } - sc->docbuf->write(comment, commentlen); - highlightText(NULL, this, sc->docbuf, 0); - } - else - { - dc->writeSections(sc, this, sc->docbuf); - emitMemberComments(sc); - } - - //printf("BODY= '%.*s'\n", buf.offset, buf.data); - Macro::define(¯otable, (unsigned char *)"BODY", 4, buf.data, buf.offset); - - OutBuffer buf2; - buf2.writestring("$(DDOC)\n"); - unsigned end = buf2.offset; - macrotable->expand(&buf2, 0, &end, NULL, 0); - -#if 1 - /* Remove all the escape sequences from buf2, - * and make CR-LF the newline. - */ - { - buf.setsize(0); - buf.reserve(buf2.offset); - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - unsigned char c = p[j]; - if (c == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - if (c == '\n') - buf.writeByte('\r'); - else if (c == '\r') - { - buf.writestring("\r\n"); - if (j + 1 < buf2.offset && p[j + 1] == '\n') - { - j++; - } - continue; - } - buf.writeByte(c); - } - } - - // Transfer image to file - assert(docfile); - docfile->setbuffer(buf.data, buf.offset); - docfile->ref = 1; - char *pt = FileName::path(docfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - docfile->writev(); -#else - /* Remove all the escape sequences from buf2 - */ - { unsigned i = 0; - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - if (p[j] == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - p[i] = p[j]; - i++; - } - buf2.setsize(i); - } - - // Transfer image to file - docfile->setbuffer(buf2.data, buf2.offset); - docfile->ref = 1; - char *pt = FileName::path(docfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - docfile->writev(); -#endif -} - -/**************************************************** - * Having unmatched parentheses can hose the output of Ddoc, - * as the macros depend on properly nested parentheses. - * This function replaces all ( with $(LPAREN) and ) with $(RPAREN) - * to preserve text literally. This also means macros in the - * text won't be expanded. - */ -void escapeDdocString(OutBuffer *buf, unsigned start) -{ - for (unsigned u = start; u < buf->offset; u++) - { - unsigned char c = buf->data[u]; - switch(c) - { - case '$': - buf->remove(u, 1); - buf->insert(u, "$(DOLLAR)", 9); - u += 8; - break; - - case '(': - buf->remove(u, 1); //remove the ( - buf->insert(u, "$(LPAREN)", 9); //insert this instead - u += 8; //skip over newly inserted macro - break; - - case ')': - buf->remove(u, 1); //remove the ) - buf->insert(u, "$(RPAREN)", 9); //insert this instead - u += 8; //skip over newly inserted macro - break; - } - } -} - -/**************************************************** - * Having unmatched parentheses can hose the output of Ddoc, - * as the macros depend on properly nested parentheses. - - * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN). - */ -void escapeStrayParenthesis(OutBuffer *buf, unsigned start, Loc loc) -{ - unsigned par_open = 0; - - for (unsigned u = start; u < buf->offset; u++) - { - unsigned char c = buf->data[u]; - switch(c) - { - case '(': - par_open++; - break; - - case ')': - if (par_open == 0) - { - //stray ')' - if (global.params.warnings) - warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output." - " Use $(RPAREN) instead for unpaired right parentheses."); - buf->remove(u, 1); //remove the ) - buf->insert(u, "$(RPAREN)", 9); //insert this instead - u += 8; //skip over newly inserted macro - } - else - par_open--; - break; -#if 0 - // For this to work, loc must be set to the beginning of the passed - // text which is currently not possible - // (loc is set to the Loc of the Dsymbol) - case '\n': - loc.linnum++; - break; -#endif - } - } - - if (par_open) // if any unmatched lparens - { par_open = 0; - for (unsigned u = buf->offset; u > start;) - { u--; - unsigned char c = buf->data[u]; - switch(c) - { - case ')': - par_open++; - break; - - case '(': - if (par_open == 0) - { - //stray '(' - if (global.params.warnings) - warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output." - " Use $(LPAREN) instead for unpaired left parentheses."); - buf->remove(u, 1); //remove the ( - buf->insert(u, "$(LPAREN)", 9); //insert this instead - } - else - par_open--; - break; - } - } - } -} - -/******************************* emitComment **********************************/ - -/* - * Emit doc comment to documentation file - */ - -void Dsymbol::emitDitto(Scope *sc) -{ - //printf("Dsymbol::emitDitto() %s %s\n", kind(), toChars()); - OutBuffer *buf = sc->docbuf; - unsigned o; - OutBuffer b; - - b.writestring("$(DDOC_DITTO "); - o = b.offset; - toDocBuffer(&b); - //printf("b: '%.*s'\n", b.offset, b.data); - /* If 'this' is a function template, then highlightCode() was - * already run by FuncDeclaration::toDocbuffer(). - */ - TemplateDeclaration *td; - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { - } - else - highlightCode(sc, this, &b, o); - b.writeByte(')'); - buf->spread(sc->lastoffset, b.offset); - memcpy(buf->data + sc->lastoffset, b.data, b.offset); - sc->lastoffset += b.offset; -} - -void ScopeDsymbol::emitMemberComments(Scope *sc) -{ - //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); - OutBuffer *buf = sc->docbuf; - - if (members) - { const char *m = "$(DDOC_MEMBERS \n"; - - if (isModule()) - m = "$(DDOC_MODULE_MEMBERS \n"; - else if (isClassDeclaration()) - m = "$(DDOC_CLASS_MEMBERS \n"; - else if (isStructDeclaration()) - m = "$(DDOC_STRUCT_MEMBERS \n"; - else if (isEnumDeclaration()) - m = "$(DDOC_ENUM_MEMBERS \n"; - else if (isTemplateDeclaration()) - m = "$(DDOC_TEMPLATE_MEMBERS \n"; - - unsigned offset1 = buf->offset; // save starting offset - buf->writestring(m); - unsigned offset2 = buf->offset; // to see if we write anything - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - //printf("\ts = '%s'\n", s->toChars()); - s->emitComment(sc); - } - sc->pop(); - if (buf->offset == offset2) - { - /* Didn't write out any members, so back out last write - */ - buf->offset = offset1; - } - else - buf->writestring(")\n"); - } -} - -void emitProtection(OutBuffer *buf, PROT prot) -{ - const char *p; - - switch (prot) - { - case PROTpackage: p = "package"; break; - case PROTprotected: p = "protected"; break; - case PROTexport: p = "export"; break; - default: p = NULL; break; - } - if (p) - buf->printf("%s ", p); -} - -void Dsymbol::emitComment(Scope *sc) { } -void InvariantDeclaration::emitComment(Scope *sc) { } -#if DMDV2 -void PostBlitDeclaration::emitComment(Scope *sc) { } -#endif -void DtorDeclaration::emitComment(Scope *sc) { } -void StaticCtorDeclaration::emitComment(Scope *sc) { } -void StaticDtorDeclaration::emitComment(Scope *sc) { } -void ClassInfoDeclaration::emitComment(Scope *sc) { } -void ModuleInfoDeclaration::emitComment(Scope *sc) { } -void TypeInfoDeclaration::emitComment(Scope *sc) { } - - -void Declaration::emitComment(Scope *sc) -{ - //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); - //printf("type = %p\n", type); - - if (protection == PROTprivate || !ident || - (!type && !isCtorDeclaration() && !isAliasDeclaration())) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - unsigned o; - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - toDocBuffer(buf); - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - buf->writestring(ddoc_decl_dd_e); -} - -void AggregateDeclaration::emitComment(Scope *sc) -{ - //printf("AggregateDeclaration::emitComment() '%s'\n", toChars()); - if (prot() == PROTprivate) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - toDocBuffer(buf); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void TemplateDeclaration::emitComment(Scope *sc) -{ - //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind()); - if (prot() == PROTprivate) - return; - - unsigned char *com = comment; - int hasmembers = 1; - - Dsymbol *ss = this; - - if (onemember) - { - ss = onemember->isAggregateDeclaration(); - if (!ss) - { - ss = onemember->isFuncDeclaration(); - if (ss) - { hasmembers = 0; - if (com != ss->comment) - com = Lexer::combineComments(com, ss->comment); - } - else - ss = this; - } - } - - if (!com) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, com); - unsigned o; - - if (!dc) - { - ss->emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - ss->toDocBuffer(buf); - if (ss == this) - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - if (hasmembers) - ((ScopeDsymbol *)ss)->emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void EnumDeclaration::emitComment(Scope *sc) -{ - if (prot() == PROTprivate) - return; -// if (!comment) - { if (isAnonymous() && members) - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->emitComment(sc); - } - return; - } - } - if (!comment) - return; - if (isAnonymous()) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - toDocBuffer(buf); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void EnumMember::emitComment(Scope *sc) -{ - //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); - if (prot() == PROTprivate) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - unsigned o; - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - toDocBuffer(buf); - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - buf->writestring(ddoc_decl_dd_e); -} - -/******************************* toDocBuffer **********************************/ - -void Dsymbol::toDocBuffer(OutBuffer *buf) -{ - //printf("Dsymbol::toDocbuffer() %s\n", toChars()); - HdrGenState hgs; - - hgs.ddoc = 1; - toCBuffer(buf, &hgs); -} - -void prefix(OutBuffer *buf, Dsymbol *s) -{ - if (s->isDeprecated()) - buf->writestring("deprecated "); - Declaration *d = s->isDeclaration(); - if (d) - { - emitProtection(buf, d->protection); - if (d->isAbstract()) - buf->writestring("abstract "); - if (d->isStatic()) - buf->writestring("static "); - if (d->isConst()) - buf->writestring("const "); -#if DMDV2 - if (d->isImmutable()) - buf->writestring("immutable "); -#endif - if (d->isFinal()) - buf->writestring("final "); - if (d->isSynchronized()) - buf->writestring("synchronized "); - } -} - -void declarationToDocBuffer(Declaration *decl, OutBuffer *buf, TemplateDeclaration *td) -{ - //printf("declarationToDocBuffer() %s, originalType = %s, td = %s\n", decl->toChars(), decl->originalType ? decl->originalType->toChars() : "--", td ? td->toChars() : "--"); - if (decl->ident) - { - prefix(buf, decl); - - if (decl->type) - { HdrGenState hgs; - hgs.ddoc = 1; - Type *origType = decl->originalType ? decl->originalType : decl->type; - if (origType->ty == Tfunction) - { - TypeFunction *attrType = (TypeFunction*)(decl->ident == Id::ctor ? origType : decl->type); - ((TypeFunction*)origType)->toCBufferWithAttributes(buf, decl->ident, &hgs, attrType, td); - } - else - origType->toCBuffer(buf, decl->ident, &hgs); - } - else - buf->writestring(decl->ident->toChars()); - buf->writestring(";\n"); - } -} - -void Declaration::toDocBuffer(OutBuffer *buf) -{ - declarationToDocBuffer(this, buf, NULL); -} - -void AliasDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("AliasDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { - if (isDeprecated()) - buf->writestring("deprecated "); - - emitProtection(buf, protection); - buf->writestring("alias "); - buf->writestring(toChars()); - buf->writestring(";\n"); - } -} - - -void TypedefDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - if (isDeprecated()) - buf->writestring("deprecated "); - - emitProtection(buf, protection); - buf->writestring("typedef "); - buf->writestring(toChars()); - buf->writestring(";\n"); - } -} - - -void FuncDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("FuncDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { /* It's a function template - */ - unsigned o = buf->offset; - - declarationToDocBuffer(this, buf, td); - - highlightCode(NULL, this, buf, o); - } - else - { - Declaration::toDocBuffer(buf); - } - } -} - -#if DMDV1 -void CtorDeclaration::toDocBuffer(OutBuffer *buf) -{ - HdrGenState hgs; - - buf->writestring("this"); - Parameter::argsToCBuffer(buf, &hgs, arguments, varargs); - buf->writestring(";\n"); -} -#endif - -void AggregateDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); - } -} - -void StructDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("StructDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { unsigned o = buf->offset; - td->toDocBuffer(buf); - highlightCode(NULL, this, buf, o); - } - else - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - buf->writestring(";\n"); - } -} - -void ClassDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("ClassDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { unsigned o = buf->offset; - td->toDocBuffer(buf); - highlightCode(NULL, this, buf, o); - } - else - { - if (isAbstract()) - buf->writestring("abstract "); - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - int any = 0; - for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *bc = (*baseclasses)[i]; - - if (bc->protection == PROTprivate) - continue; - if (bc->base && bc->base->ident == Id::Object) - continue; - - if (any) - buf->writestring(", "); - else - { buf->writestring(": "); - any = 1; - } - emitProtection(buf, bc->protection); - if (bc->base) - { - buf->writestring(bc->base->toPrettyChars()); - } - else - { - HdrGenState hgs; - bc->type->toCBuffer(buf, NULL, &hgs); - } - } - buf->writestring(";\n"); - } -} - - -void EnumDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); - } -} - -void EnumMember::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - buf->writestring(toChars()); - } -} - - -/********************************* DocComment *********************************/ - -DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) -{ - //printf("parse(%s): '%s'\n", s->toChars(), comment); - if (sc->lastdc && isDitto(comment)) - return NULL; - - DocComment *dc = new DocComment(); - if (!comment) - return dc; - - dc->parseSections(comment); - - for (size_t i = 0; i < dc->sections.dim; i++) - { Section *sec = dc->sections[i]; - - if (icmp("copyright", sec->name, sec->namelen) == 0) - { - dc->copyright = sec; - } - if (icmp("macros", sec->name, sec->namelen) == 0) - { - dc->macros = sec; - } - } - - sc->lastdc = dc; - return dc; -} - -/***************************************** - * Parse next paragraph out of *pcomment. - * Update *pcomment to point past paragraph. - * Returns NULL if no more paragraphs. - * If paragraph ends in 'identifier:', - * then (*pcomment)[0 .. idlen] is the identifier. - */ - -void DocComment::parseSections(unsigned char *comment) -{ unsigned char *p; - unsigned char *pstart; - unsigned char *pend; - unsigned char *idstart; - unsigned idlen; - - unsigned char *name = NULL; - unsigned namelen = 0; - - //printf("parseSections('%s')\n", comment); - p = comment; - while (*p) - { - p = skipwhitespace(p); - pstart = p; - pend = p; - - /* Find end of section, which is ended by one of: - * 'identifier:' (but not inside a code section) - * '\0' - */ - idlen = 0; - int inCode = 0; - while (1) - { - // Check for start/end of a code section - if (*p == '-') - { - int numdash = 0; - while (*p == '-') - { - ++numdash; - p++; - } - // BUG: handle UTF PS and LS too - if (!*p || *p == '\r' || *p == '\n' && numdash >= 3) - inCode ^= 1; - pend = p; - } - - if (!inCode && isIdStart(p)) - { - unsigned char *q = p + utfStride(p); - while (isIdTail(q)) - q += utfStride(q); - if (*q == ':') // identifier: ends it - { idlen = q - p; - idstart = p; - for (pend = p; pend > pstart; pend--) - { if (pend[-1] == '\n') - break; - } - p = q + 1; - break; - } - } - while (1) - { - if (!*p) - goto L1; - if (*p == '\n') - { p++; - if (*p == '\n' && !summary && !namelen && !inCode) - { - pend = p; - p++; - goto L1; - } - break; - } - p++; - pend = p; - } - p = skipwhitespace(p); - } - L1: - - if (namelen || pstart < pend) - { - Section *s; - if (icmp("Params", name, namelen) == 0) - s = new ParamSection(); - else if (icmp("Macros", name, namelen) == 0) - s = new MacroSection(); - else - s = new Section(); - s->name = name; - s->namelen = namelen; - s->body = pstart; - s->bodylen = pend - pstart; - s->nooutput = 0; - - //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); - - sections.push(s); - - if (!summary && !namelen) - summary = s; - } - - if (idlen) - { name = idstart; - namelen = idlen; - } - else - { name = NULL; - namelen = 0; - if (!*p) - break; - } - } -} - -void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - //printf("DocComment::writeSections()\n"); - if (sections.dim) - { - buf->writestring("$(DDOC_SECTIONS \n"); - for (size_t i = 0; i < sections.dim; i++) - { Section *sec = sections[i]; - - if (sec->nooutput) - continue; - //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); - if (sec->namelen || i) - sec->write(this, sc, s, buf); - else - { - buf->writestring("$(DDOC_SUMMARY "); - unsigned o = buf->offset; - buf->write(sec->body, sec->bodylen); - escapeStrayParenthesis(buf, o, s->loc); - highlightText(sc, s, buf, o); - buf->writestring(")\n"); - } - } - buf->writestring(")\n"); - } - else - { - buf->writestring("$(DDOC_BLANKLINE)\n"); - } -} - -/*************************************************** - */ - -void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - if (namelen) - { - static const char *table[] = - { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", - "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", - "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", - "VERSION" }; - - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (icmp(table[i], name, namelen) == 0) - { - buf->printf("$(DDOC_%s ", table[i]); - goto L1; - } - } - - buf->writestring("$(DDOC_SECTION "); - // Replace _ characters with spaces - buf->writestring("$(DDOC_SECTION_H "); - unsigned o = buf->offset; - for (unsigned u = 0; u < namelen; u++) - { unsigned char c = name[u]; - buf->writeByte((c == '_') ? ' ' : c); - } - escapeStrayParenthesis(buf, o, s->loc); - buf->writestring(":)\n"); - } - else - { - buf->writestring("$(DDOC_DESCRIPTION "); - } - L1: - unsigned o = buf->offset; - buf->write(body, bodylen); - escapeStrayParenthesis(buf, o, s->loc); - highlightText(sc, s, buf, o); - buf->writestring(")\n"); -} - -/*************************************************** - */ - -void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - unsigned char *p = body; - unsigned len = bodylen; - unsigned char *pend = p + len; - - unsigned char *tempstart; - unsigned templen; - - unsigned char *namestart; - unsigned namelen = 0; // !=0 if line continuation - - unsigned char *textstart; - unsigned textlen; - - unsigned o; - Parameter *arg; - - buf->writestring("$(DDOC_PARAMS \n"); - while (p < pend) - { - // Skip to start of macro - while (1) - { - switch (*p) - { - case ' ': - case '\t': - p++; - continue; - - case '\n': - p++; - goto Lcont; - - default: - if (isIdStart(p)) - break; - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - tempstart = p; - - while (isIdTail(p)) - p += utfStride(p); - templen = p - tempstart; - - while (*p == ' ' || *p == '\t') - p++; - - if (*p != '=') - { if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - p++; - - if (namelen) - { // Output existing param - - L1: - //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); - HdrGenState hgs; - buf->writestring("$(DDOC_PARAM_ROW "); - buf->writestring("$(DDOC_PARAM_ID "); - o = buf->offset; - arg = isFunctionParameter(s, namestart, namelen); - if (arg && arg->type && arg->ident) - arg->type->toCBuffer(buf, arg->ident, &hgs); - else - buf->write(namestart, namelen); - escapeStrayParenthesis(buf, o, s->loc); - highlightCode(sc, s, buf, o); - buf->writestring(")\n"); - - buf->writestring("$(DDOC_PARAM_DESC "); - o = buf->offset; - buf->write(textstart, textlen); - escapeStrayParenthesis(buf, o, s->loc); - highlightText(sc, s, buf, o); - buf->writestring(")"); - buf->writestring(")\n"); - namelen = 0; - if (p >= pend) - break; - } - - namestart = tempstart; - namelen = templen; - - while (*p == ' ' || *p == '\t') - p++; - textstart = p; - - Ltext: - while (*p != '\n') - p++; - textlen = p - textstart; - p++; - - Lcont: - continue; - - Lskipline: - // Ignore this line - while (*p++ != '\n') - ; - } - if (namelen) - goto L1; // write out last one - buf->writestring(")\n"); -} - -/*************************************************** - */ - -void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - //printf("MacroSection::write()\n"); - DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen); -} - -/************************************************ - * Parse macros out of Macros: section. - * Macros are of the form: - * name1 = value1 - * - * name2 = value2 - */ - -void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen) -{ - unsigned char *p = m; - unsigned len = mlen; - unsigned char *pend = p + len; - - unsigned char *tempstart; - unsigned templen; - - unsigned char *namestart; - unsigned namelen = 0; // !=0 if line continuation - - unsigned char *textstart; - unsigned textlen; - - while (p < pend) - { - // Skip to start of macro - while (1) - { - if (p >= pend) - goto Ldone; - switch (*p) - { - case ' ': - case '\t': - p++; - continue; - - case '\n': - p++; - goto Lcont; - - default: - if (isIdStart(p)) - break; - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - tempstart = p; - - while (1) - { - if (p >= pend) - goto Ldone; - if (!isIdTail(p)) - break; - p += utfStride(p); - } - templen = p - tempstart; - - while (1) - { - if (p >= pend) - goto Ldone; - if (!(*p == ' ' || *p == '\t')) - break; - p++; - } - - if (*p != '=') - { if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - p++; - if (p >= pend) - goto Ldone; - - if (namelen) - { // Output existing macro - L1: - //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); - if (icmp("ESCAPES", namestart, namelen) == 0) - parseEscapes(pescapetable, textstart, textlen); - else - Macro::define(pmacrotable, namestart, namelen, textstart, textlen); - namelen = 0; - if (p >= pend) - break; - } - - namestart = tempstart; - namelen = templen; - - while (p < pend && (*p == ' ' || *p == '\t')) - p++; - textstart = p; - - Ltext: - while (p < pend && *p != '\n') - p++; - textlen = p - textstart; - - // Remove trailing \r if there is one - if (p > m && p[-1] == '\r') - textlen--; - - p++; - //printf("p = %p, pend = %p\n", p, pend); - - Lcont: - continue; - - Lskipline: - // Ignore this line - while (p < pend && *p++ != '\n') - ; - } -Ldone: - if (namelen) - goto L1; // write out last one -} - -/************************************** - * Parse escapes of the form: - * /c/string/ - * where c is a single character. - * Multiple escapes can be separated - * by whitespace and/or commas. - */ - -void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen) -{ Escape *escapetable = *pescapetable; - - if (!escapetable) - { escapetable = new Escape; - *pescapetable = escapetable; - } - unsigned char *p = textstart; - unsigned char *pend = p + textlen; - - while (1) - { - while (1) - { - if (p + 4 >= pend) - return; - if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) - break; - p++; - } - if (p[0] != '/' || p[2] != '/') - return; - unsigned char c = p[1]; - p += 3; - unsigned char *start = p; - while (1) - { - if (p >= pend) - return; - if (*p == '/') - break; - p++; - } - size_t len = p - start; - char *s = (char *)memcpy(mem.malloc(len + 1), start, len); - s[len] = 0; - escapetable->strings[c] = s; - //printf("%c = '%s'\n", c, s); - p++; - } -} - - -/****************************************** - * Compare 0-terminated string with length terminated string. - * Return < 0, ==0, > 0 - */ - -int cmp(const char *stringz, void *s, size_t slen) -{ - size_t len1 = strlen(stringz); - - if (len1 != slen) - return len1 - slen; - return memcmp(stringz, s, slen); -} - -int icmp(const char *stringz, void *s, size_t slen) -{ - size_t len1 = strlen(stringz); - - if (len1 != slen) - return len1 - slen; - return memicmp(stringz, (char *)s, slen); -} - -/***************************************** - * Return !=0 if comment consists entirely of "ditto". - */ - -int isDitto(unsigned char *comment) -{ - if (comment) - { - unsigned char *p = skipwhitespace(comment); - - if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) - return 1; - } - return 0; -} - -/********************************************** - * Skip white space. - */ - -unsigned char *skipwhitespace(unsigned char *p) -{ - for (; 1; p++) - { switch (*p) - { - case ' ': - case '\t': - case '\n': - continue; - } - break; - } - return p; -} - - -/************************************************ - * Scan forward to one of: - * start of identifier - * beginning of next line - * end of buf - */ - -unsigned skiptoident(OutBuffer *buf, size_t i) -{ - while (i < buf->offset) - { dchar_t c; - - size_t oi = i; - if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) - /* Ignore UTF errors, but still consume input - */ - break; - if (c >= 0x80) - { - if (!isUniAlpha(c)) - continue; - } - else if (!(isalpha(c) || c == '_' || c == '\n')) - continue; - i = oi; - break; - } - return i; -} - -/************************************************ - * Scan forward past end of identifier. - */ - -unsigned skippastident(OutBuffer *buf, size_t i) -{ - while (i < buf->offset) - { dchar_t c; - - size_t oi = i; - if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) - /* Ignore UTF errors, but still consume input - */ - break; - if (c >= 0x80) - { - if (isUniAlpha(c)) - continue; - } - else if (isalnum(c) || c == '_') - continue; - i = oi; - break; - } - return i; -} - - -/************************************************ - * Scan forward past URL starting at i. - * We don't want to highlight parts of a URL. - * Returns: - * i if not a URL - * index just past it if it is a URL - */ - -unsigned skippastURL(OutBuffer *buf, size_t i) -{ unsigned length = buf->offset - i; - unsigned char *p = &buf->data[i]; - unsigned j; - unsigned sawdot = 0; - - if (length > 7 && memicmp((char *)p, "http://", 7) == 0) - { - j = 7; - } - else if (length > 8 && memicmp((char *)p, "https://", 8) == 0) - { - j = 8; - } - else - goto Lno; - - for (; j < length; j++) - { unsigned char c = p[j]; - if (isalnum(c)) - continue; - if (c == '-' || c == '_' || c == '?' || - c == '=' || c == '%' || c == '&' || - c == '/' || c == '+' || c == '#' || - c == '~') - continue; - if (c == '.') - { - sawdot = 1; - continue; - } - break; - } - if (sawdot) - return i + j; - -Lno: - return i; -} - - -/**************************************************** - */ - -int isKeyword(unsigned char *p, unsigned len) -{ - static const char *table[] = { "true", "false", "null" }; - - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (cmp(table[i], p, len) == 0) - return 1; - } - return 0; -} - -/**************************************************** - */ - -Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) -{ - FuncDeclaration *f = s->isFuncDeclaration(); - - /* f->type may be NULL for template members. - */ - if (f && f->type) - { - TypeFunction *tf; - if (f->originalType) - { - tf = (TypeFunction *)f->originalType; - } - else - tf = (TypeFunction *)f->type; - - if (tf->parameters) - { - for (size_t k = 0; k < tf->parameters->dim; k++) - { Parameter *arg = (*tf->parameters)[k]; - - if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) - { - return arg; - } - } - } - } - return NULL; -} - -/************************************************** - * Highlight text section. - */ - -void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - //printf("highlightText()\n"); - const char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - unsigned char *p; - const char *se; - - int leadingBlank = 1; - int inCode = 0; - //int inComment = 0; // in comment - unsigned iCodeStart; // start of code section - - unsigned iLineStart = offset; - - for (unsigned i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; - - Lcont: - switch (c) - { - case ' ': - case '\t': - break; - - case '\n': - if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" - { - static char blankline[] = "$(DDOC_BLANKLINE)\n"; - - i = buf->insert(i, blankline, sizeof(blankline) - 1); - } - leadingBlank = 1; - iLineStart = i + 1; - break; - - case '<': - leadingBlank = 0; - if (inCode) - break; - p = &buf->data[i]; - - // Skip over comments - if (p[1] == '!' && p[2] == '-' && p[3] == '-') - { unsigned j = i + 4; - p += 4; - while (1) - { - if (j == buf->offset) - goto L1; - if (p[0] == '-' && p[1] == '-' && p[2] == '>') - { - i = j + 2; // place on closing '>' - break; - } - j++; - p++; - } - break; - } - - // Skip over HTML tag - if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) - { unsigned j = i + 2; - p += 2; - while (1) - { - if (j == buf->offset) - goto L1; - if (p[0] == '>') - { - i = j; // place on closing '>' - break; - } - j++; - p++; - } - break; - } - - L1: - // Replace '<' with '<' character entity - se = Escape::escapeChar('<'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '>': - leadingBlank = 0; - if (inCode) - break; - // Replace '>' with '>' character entity - se = Escape::escapeChar('>'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '&': - leadingBlank = 0; - if (inCode) - break; - p = &buf->data[i]; - if (p[1] == '#' || isalpha(p[1])) - break; // already a character entity - // Replace '&' with '&' character entity - se = Escape::escapeChar('&'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '-': - /* A line beginning with --- delimits a code section. - * inCode tells us if it is start or end of a code section. - */ - if (leadingBlank) - { int istart = i; - int eollen = 0; - - leadingBlank = 0; - while (1) - { - ++i; - if (i >= buf->offset) - break; - c = buf->data[i]; - if (c == '\n') - { eollen = 1; - break; - } - if (c == '\r') - { - eollen = 1; - if (i + 1 >= buf->offset) - break; - if (buf->data[i + 1] == '\n') - { eollen = 2; - break; - } - } - // BUG: handle UTF PS and LS too - if (c != '-') - goto Lcont; - } - if (i - istart < 3) - goto Lcont; - - // We have the start/end of a code section - - // Remove the entire --- line, including blanks and \n - buf->remove(iLineStart, i - iLineStart + eollen); - i = iLineStart; - - if (inCode && (i <= iCodeStart)) - { // Empty code section, just remove it completely. - inCode = 0; - break; - } - - if (inCode) - { - inCode = 0; - // The code section is from iCodeStart to i - OutBuffer codebuf; - - codebuf.write(buf->data + iCodeStart, i - iCodeStart); - codebuf.writeByte(0); - highlightCode2(sc, s, &codebuf, 0); - buf->remove(iCodeStart, i - iCodeStart); - i = buf->insert(iCodeStart, codebuf.data, codebuf.offset); - i = buf->insert(i, ")\n", 2); - i--; - } - else - { static char pre[] = "$(D_CODE \n"; - - inCode = 1; - i = buf->insert(i, pre, sizeof(pre) - 1); - iCodeStart = i; - i--; // place i on > - leadingBlank = true; - } - } - break; - - default: - leadingBlank = 0; - if (sc && !inCode && isIdStart(&buf->data[i])) - { unsigned j; - - j = skippastident(buf, i); - if (j > i) - { - unsigned k = skippastURL(buf, i); - if (k > i) - { i = k - 1; - break; - } - - if (buf->data[i] == '_') // leading '_' means no highlight - { - buf->remove(i, 1); - i = j - 1; - } - else - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - break; - } - else if (isKeyword(buf->data + i, j - i)) - { - i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; - break; - } - else - { - if (f && isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - break; - } - } - i = j - 1; - } - } - } - break; - } - } - if (inCode) - s->error("unmatched --- in DDoc comment"); - ; -} - -/************************************************** - * Highlight code for DDOC section. - */ - -void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - - //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); - for (unsigned i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; - const char *se; - - se = Escape::escapeChar(c); - if (se) - { - size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - else if (isIdStart(&buf->data[i])) - { unsigned j; - - j = skippastident(buf, i); - if (j > i) - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - continue; - } - else if (f) - { - if (isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - continue; - } - } - i = j - 1; - } - } - } -} - -/**************************************** - */ - -void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) -{ - for (; p < pend; p++) - { const char *s = Escape::escapeChar(*p); - if (s) - buf->writestring(s); - else - buf->writeByte(*p); - } -} - -/************************************************** - * Highlight code for CODE section. - */ - - -void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - unsigned errorsave = global.errors; - Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1); - Token tok; - OutBuffer res; - unsigned char *lastp = buf->data; - const char *highlight; - - //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data); - res.reserve(buf->offset); - while (1) - { - lex.scan(&tok); - highlightCode3(&res, lastp, tok.ptr); - highlight = NULL; - switch (tok.value) - { - case TOKidentifier: - if (!sc) - break; - if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0) - { - highlight = "$(D_PSYMBOL "; - break; - } - else if (f) - { - if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - highlight = "$(D_PARAM "; - break; - } - } - break; - - case TOKcomment: - highlight = "$(D_COMMENT "; - break; - - case TOKstring: - highlight = "$(D_STRING "; - break; - - default: - if (tok.isKeyword()) - highlight = "$(D_KEYWORD "; - break; - } - if (highlight) - res.writestring(highlight); - highlightCode3(&res, tok.ptr, lex.p); - if (highlight) - res.writeByte(')'); - if (tok.value == TOKeof) - break; - lastp = lex.p; - } - buf->setsize(offset); - buf->write(&res); - global.errors = errorsave; -} - -/*************************************** - * Find character string to replace c with. - */ - -const char *Escape::escapeChar(unsigned c) -{ const char *s; - - switch (c) - { - case '<': - s = "<"; - break; - case '>': - s = ">"; - break; - case '&': - s = "&"; - break; - default: - s = NULL; - break; - } - return s; -} - -/**************************************** - * Determine if p points to the start of an identifier. - */ - -int isIdStart(unsigned char *p) -{ - unsigned c = *p; - if (isalpha(c) || c == '_') - return 1; - if (c >= 0x80) - { size_t i = 0; - if (utf_decodeChar(p, 4, &i, &c)) - return 0; // ignore errors - if (isUniAlpha(c)) - return 1; - } - return 0; -} - -/**************************************** - * Determine if p points to the rest of an identifier. - */ - -int isIdTail(unsigned char *p) -{ - unsigned c = *p; - if (isalnum(c) || c == '_') - return 1; - if (c >= 0x80) - { size_t i = 0; - if (utf_decodeChar(p, 4, &i, &c)) - return 0; // ignore errors - if (isUniAlpha(c)) - return 1; - } - return 0; -} - -/***************************************** - * Return number of bytes in UTF character. - */ - -int utfStride(unsigned char *p) -{ - unsigned c = *p; - if (c < 0x80) - return 1; - size_t i = 0; - utf_decodeChar(p, 4, &i, &c); // ignore errors, but still consume input - return i; -} diff --git a/dmd/doc.h b/dmd/doc.h deleted file mode 100644 index ffa97fb9..00000000 --- a/dmd/doc.h +++ /dev/null @@ -1,20 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_DOC_H -#define DMD_DOC_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -void escapeDdocString(OutBuffer *buf, unsigned start); - -#endif diff --git a/dmd/dsymbol.c b/dmd/dsymbol.c deleted file mode 100644 index 6b60124f..00000000 --- a/dmd/dsymbol.c +++ /dev/null @@ -1,1314 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "rmem.h" -#include "speller.h" -#include "aav.h" - -#include "mars.h" -#include "dsymbol.h" -#include "aggregate.h" -#include "identifier.h" -#include "module.h" -#include "mtype.h" -#include "expression.h" -#include "statement.h" -#include "declaration.h" -#include "id.h" -#include "scope.h" -#include "init.h" -#include "import.h" -#include "template.h" -#include "attrib.h" -#if IN_LLVM -#include "../gen/pragma.h" -#endif - -/****************************** Dsymbol ******************************/ - -Dsymbol::Dsymbol() -{ - //printf("Dsymbol::Dsymbol(%p)\n", this); - this->ident = NULL; - this->c_ident = NULL; - this->parent = NULL; -#if IN_DMD - this->csym = NULL; - this->isym = NULL; -#endif - this->loc = 0; - this->comment = NULL; - this->scope = NULL; - this->errors = false; -#if IN_LLVM - this->llvmInternal = LLVMnone; -#endif -} - -Dsymbol::Dsymbol(Identifier *ident) -{ - //printf("Dsymbol::Dsymbol(%p, ident)\n", this); - this->ident = ident; - this->c_ident = NULL; - this->parent = NULL; -#if IN_DMD - this->csym = NULL; - this->isym = NULL; -#endif - this->loc = 0; - this->comment = NULL; - this->scope = NULL; - this->errors = false; -#if IN_LLVM - this->llvmInternal = LLVMnone; -#endif -} - -int Dsymbol::equals(Object *o) -{ Dsymbol *s; - - if (this == o) - return TRUE; - s = (Dsymbol *)(o); - if (s && ident->equals(s->ident)) - return TRUE; - return FALSE; -} - -/************************************** - * Copy the syntax. - * Used for template instantiations. - * If s is NULL, allocate the new object, otherwise fill it in. - */ - -Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s) -{ - print(); - printf("%s %s\n", kind(), toChars()); - assert(0); - return NULL; -} - -/************************************** - * Determine if this symbol is only one. - * Returns: - * FALSE, *ps = NULL: There are 2 or more symbols - * TRUE, *ps = NULL: There are zero symbols - * TRUE, *ps = symbol: The one and only one symbol - */ - -int Dsymbol::oneMember(Dsymbol **ps) -{ - //printf("Dsymbol::oneMember()\n"); - *ps = this; - return TRUE; -} - -/***************************************** - * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. - */ - -int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps) -{ - //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); - Dsymbol *s = NULL; - - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *sx = (*members)[i]; - - int x = sx->oneMember(ps); - //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); - if (!x) - { - //printf("\tfalse 1\n"); - assert(*ps == NULL); - return FALSE; - } - if (*ps) - { - if (s) // more than one symbol - { *ps = NULL; - //printf("\tfalse 2\n"); - return FALSE; - } - s = *ps; - } - } - } - *ps = s; // s is the one symbol, NULL if none - //printf("\ttrue\n"); - return TRUE; -} - -/***************************************** - * Is Dsymbol a variable that contains pointers? - */ - -int Dsymbol::hasPointers() -{ - //printf("Dsymbol::hasPointers() %s\n", toChars()); - return 0; -} - -bool Dsymbol::hasStaticCtorOrDtor() -{ - //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars()); - return FALSE; -} - -void Dsymbol::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ -} - -char *Dsymbol::toChars() -{ - return ident ? ident->toChars() : (char *)"__anonymous"; -} - -const char *Dsymbol::toPrettyChars() -{ Dsymbol *p; - char *s; - char *q; - size_t len; - - //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); - if (!parent) - return toChars(); - - len = 0; - for (p = this; p; p = p->parent) - len += strlen(p->toChars()) + 1; - - s = (char *)mem.malloc(len); - q = s + len - 1; - *q = 0; - for (p = this; p; p = p->parent) - { - char *t = p->toChars(); - len = strlen(t); - q -= len; - memcpy(q, t, len); - if (q == s) - break; - q--; -#if TARGET_NET - if (AggregateDeclaration* ad = p->isAggregateDeclaration()) - { - if (ad->isNested() && p->parent && p->parent->isAggregateDeclaration()) - { - *q = '/'; - continue; - } - } -#endif - *q = '.'; - } - return s; -} - -char *Dsymbol::locToChars() -{ - OutBuffer buf; - - if (!loc.filename) // avoid bug 5861. - { - Module *m = getModule(); - - if (m && m->srcfile) - loc.filename = m->srcfile->toChars(); - } - return loc.toChars(); -} - -const char *Dsymbol::kind() -{ - return "symbol"; -} - -/********************************* - * If this symbol is really an alias for another, - * return that other. - */ - -Dsymbol *Dsymbol::toAlias() -{ - return this; -} - -Dsymbol *Dsymbol::toParent() -{ - return parent ? parent->pastMixin() : NULL; -} - -Dsymbol *Dsymbol::pastMixin() -{ - Dsymbol *s = this; - - //printf("Dsymbol::pastMixin() %s\n", toChars()); - while (s && s->isTemplateMixin()) - s = s->parent; - return s; -} - -/********************************** - * Use this instead of toParent() when looking for the - * 'this' pointer of the enclosing function/class. - */ - -Dsymbol *Dsymbol::toParent2() -{ - Dsymbol *s = parent; - while (s && s->isTemplateInstance()) - s = s->parent; - return s; -} - -TemplateInstance *Dsymbol::inTemplateInstance() -{ - for (Dsymbol *parent = this->parent; parent; parent = parent->parent) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - return ti; - } - return NULL; -} - -// Check if this function is a member of a template which has only been -// instantiated speculatively, eg from inside is(typeof()). -// Return the speculative template instance it is part of, -// or NULL if not speculative. -TemplateInstance *Dsymbol::isSpeculative() -{ - Dsymbol * par = parent; - while (par) - { - TemplateInstance *ti = par->isTemplateInstance(); - if (ti && ti->speculative) - return ti; - par = par->toParent(); - } - return NULL; -} - -int Dsymbol::isAnonymous() -{ - return ident ? 0 : 1; -} - -/************************************* - * Set scope for future semantic analysis so we can - * deal better with forward references. - */ - -void Dsymbol::setScope(Scope *sc) -{ - //printf("Dsymbol::setScope() %p %s\n", this, toChars()); - if (!sc->nofree) - sc->setNoFree(); // may need it even after semantic() finishes - scope = sc; -} - -void Dsymbol::importAll(Scope *sc) -{ -} - -/************************************* - * Does semantic analysis on the public face of declarations. - */ - -void Dsymbol::semantic0(Scope *sc) -{ -} - -void Dsymbol::semantic(Scope *sc) -{ - error("%p has no semantic routine", this); -} - -/************************************* - * Does semantic analysis on initializers and members of aggregates. - */ - -void Dsymbol::semantic2(Scope *sc) -{ - // Most Dsymbols have no further semantic analysis needed -} - -/************************************* - * Does semantic analysis on function bodies. - */ - -void Dsymbol::semantic3(Scope *sc) -{ - // Most Dsymbols have no further semantic analysis needed -} - -/************************************* - * Look for function inlining possibilities. - */ - -void Dsymbol::inlineScan() -{ - // Most Dsymbols aren't functions -} - -/********************************************* - * Search for ident as member of s. - * Input: - * flags: 1 don't find private members - * 2 don't give error messages - * 4 return NULL if ambiguous - * Returns: - * NULL if not found - */ - -Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); - return NULL; -} - -/*************************************************** - * Search for symbol with correct spelling. - */ - -void *symbol_search_fp(void *arg, const char *seed) -{ - /* If not in the lexer's string table, it certainly isn't in the symbol table. - * Doing this first is a lot faster. - */ - size_t len = strlen(seed); - if (!len) - return NULL; - StringValue *sv = Lexer::stringtable.lookup(seed, len); - if (!sv) - return NULL; - Identifier *id = (Identifier *)sv->ptrvalue; - assert(id); - - Dsymbol *s = (Dsymbol *)arg; - Module::clearCache(); - return s->search(0, id, 4|2); -} - -Dsymbol *Dsymbol::search_correct(Identifier *ident) -{ - if (global.gag) - return NULL; // don't do it for speculative compiles; too time consuming - - return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, this, idchars); -} - -/*************************************** - * Search for identifier id as a member of 'this'. - * id may be a template instance. - * Returns: - * symbol found, NULL if not - */ - -Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) -{ - //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); - Dsymbol *s = toAlias(); - Dsymbol *sm; - - switch (id->dyncast()) - { - case DYNCAST_IDENTIFIER: - sm = s->search(loc, id, 0); - break; - - case DYNCAST_DSYMBOL: - { // It's a template instance - //printf("\ttemplate instance id\n"); - Dsymbol *st = (Dsymbol *)id; - TemplateInstance *ti = st->isTemplateInstance(); - id = ti->name; - sm = s->search(loc, id, 0); - if (!sm) - { - sm = s->search_correct(id); - if (sm) - error("template identifier '%s' is not a member of '%s %s', did you mean '%s %s'?", - id->toChars(), s->kind(), s->toChars(), sm->kind(), sm->toChars()); - else - error("template identifier '%s' is not a member of '%s %s'", - id->toChars(), s->kind(), s->toChars()); - return NULL; - } - sm = sm->toAlias(); - TemplateDeclaration *td = sm->isTemplateDeclaration(); - if (!td) - { - error("%s is not a template, it is a %s", id->toChars(), sm->kind()); - return NULL; - } - ti->tempdecl = td; - if (!ti->semanticRun) - ti->semantic(sc); - sm = ti->toAlias(); - break; - } - - default: - assert(0); - } - return sm; -} - -int Dsymbol::overloadInsert(Dsymbol *s) -{ - //printf("Dsymbol::overloadInsert('%s')\n", s->toChars()); - return FALSE; -} - -void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(toChars()); -} - -unsigned Dsymbol::size(Loc loc) -{ - error("Dsymbol '%s' has no size\n", toChars()); - return 0; -} - -int Dsymbol::isforwardRef() -{ - return FALSE; -} - -AggregateDeclaration *Dsymbol::isThis() -{ - return NULL; -} - -ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class? -{ - Dsymbol *parent = toParent(); - if (parent && parent->isClassDeclaration()) - return (ClassDeclaration *)parent; - return NULL; -} - -void Dsymbol::defineRef(Dsymbol *s) -{ - assert(0); -} - -int Dsymbol::isExport() -{ - return FALSE; -} - -int Dsymbol::isImportedSymbol() -{ - return FALSE; -} - -int Dsymbol::isDeprecated() -{ - return FALSE; -} - -#if DMDV2 -int Dsymbol::isOverloadable() -{ - return 0; -} -#endif - -int Dsymbol::hasOverloads() -{ - return 0; -} - -LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? -{ - return NULL; -} - -AggregateDeclaration *Dsymbol::isMember() // is this a member of an AggregateDeclaration? -{ - //printf("Dsymbol::isMember() %s\n", toChars()); - Dsymbol *parent = toParent(); - //printf("parent is %s %s\n", parent->kind(), parent->toChars()); - return parent ? parent->isAggregateDeclaration() : NULL; -} - -Type *Dsymbol::getType() -{ - return NULL; -} - -int Dsymbol::needThis() -{ - return FALSE; -} - -int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param) -{ - return (*fp)(this, param); -} - -int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("Dsymbol::addMember('%s')\n", toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab); - parent = sd; - if (!isAnonymous()) // no name, so can't add it to symbol table - { - if (!sd->symtabInsert(this)) // if name is already defined - { - Dsymbol *s2; - - s2 = sd->symtab->lookup(ident); - if (!s2->overloadInsert(this)) - { - sd->multiplyDefined(0, this, s2); - } - } - if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) - { - if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::mangleof) - error(".%s property cannot be redefined", ident->toChars()); - } - return 1; - } - return 0; -} - -void Dsymbol::error(const char *format, ...) -{ - //printf("Dsymbol::error()\n"); - if (!loc.filename) // avoid bug 5861. - { - Module *m = getModule(); - - if (m && m->srcfile) - loc.filename = m->srcfile->toChars(); - } - va_list ap; - va_start(ap, format); - verror(loc, format, ap, kind(), toPrettyChars()); - va_end(ap); -} - -void Dsymbol::error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap, kind(), toPrettyChars()); - va_end(ap); -} - -void Dsymbol::checkDeprecated(Loc loc, Scope *sc) -{ - if (!global.params.useDeprecated && isDeprecated()) - { - // Don't complain if we're inside a deprecated symbol's scope - for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) - { if (sp->isDeprecated()) - goto L1; - } - - for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing) - { - if (sc2->scopesym && sc2->scopesym->isDeprecated()) - goto L1; - - // If inside a StorageClassDeclaration that is deprecated - if (sc2->stc & STCdeprecated) - goto L1; - } - - error(loc, "is deprecated"); - } - - L1: - ; -} - -/********************************** - * Determine which Module a Dsymbol is in. - */ - -Module *Dsymbol::getModule() -{ - //printf("Dsymbol::getModule()\n"); - TemplateDeclaration *td = getFuncTemplateDecl(this); - if (td) - return td->getModule(); - - Dsymbol *s = this; - while (s) - { - //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); - Module *m = s->isModule(); - if (m) - return m; - s = s->parent; - } - return NULL; -} - - -/********************************** - * Determine which Module a Dsymbol will be compiled in. - * This may be different from getModule for templates. - */ - -Module *Dsymbol::getCompilationModule() -{ - Module *m; - TemplateInstance *ti; - Dsymbol *s; - - //printf("Dsymbol::getModule()\n"); - s = this; - while (s) - { - //printf("\ts = '%s'\n", s->toChars()); - m = s->isModule(); - if (m) - return m; - ti = s->isTemplateInstance(); - if (ti && ti->tmodule) - return ti->tmodule; - s = s->parent; - } - return NULL; -} - -/************************************* - */ - -enum PROT Dsymbol::prot() -{ - return PROTpublic; -} - -/************************************* - * Do syntax copy of an array of Dsymbol's. - */ - - -Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a) -{ - - Dsymbols *b = NULL; - if (a) - { - b = a->copy(); - for (size_t i = 0; i < b->dim; i++) - { - Dsymbol *s = (*b)[i]; - - s = s->syntaxCopy(NULL); - (*b)[i] = s; - } - } - return b; -} - - -/**************************************** - * Add documentation comment to Dsymbol. - * Ignore NULL comments. - */ - -void Dsymbol::addComment(unsigned char *comment) -{ - //if (comment) - //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); - - if (!this->comment) - this->comment = comment; -#if 1 - else if (comment && strcmp((char *)comment, (char *)this->comment)) - { // Concatenate the two - this->comment = Lexer::combineComments(this->comment, comment); - } -#endif -} - -/********************************* OverloadSet ****************************/ - -#if DMDV2 -OverloadSet::OverloadSet() - : Dsymbol() -{ -} - -void OverloadSet::push(Dsymbol *s) -{ - a.push(s); -} - -const char *OverloadSet::kind() -{ - return "overloadset"; -} -#endif - - -/********************************* ScopeDsymbol ****************************/ - -ScopeDsymbol::ScopeDsymbol() - : Dsymbol() -{ - members = NULL; - symtab = NULL; - imports = NULL; - prots = NULL; -} - -ScopeDsymbol::ScopeDsymbol(Identifier *id) - : Dsymbol(id) -{ - members = NULL; - symtab = NULL; - imports = NULL; - prots = NULL; -} - -Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s) -{ - //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars()); - - ScopeDsymbol *sd; - if (s) - sd = (ScopeDsymbol *)s; - else - sd = new ScopeDsymbol(ident); - sd->members = arraySyntaxCopy(members); - return sd; -} - -Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); - //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; - - // Look in symbols declared in this module - Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; - //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0); - - // hide the aliases generated by selective or renamed private imports - if (s && flags & 1) - if (AliasDeclaration* ad = s->isAliasDeclaration()) - // may be a private alias to a function that is overloaded. these - // are sorted out during overload resolution, accept them here - if (ad->importprot == PROTprivate && !ad->aliassym->isFuncAliasDeclaration()) - s = NULL; - - if (s) - { - //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); - } - else if (imports) - { - // Look in imported modules - for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *ss = (*imports)[i]; - Dsymbol *s2; - - // If private import, don't search it - if (flags & 1 && prots[i] == PROTprivate) - continue; - - //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); - /* Don't find private members if ss is a module - */ - s2 = ss->search(loc, ident, ss->isImport() ? 1 : 0); - if (!s) - s = s2; - else if (s2 && s != s2) - { - if (s->toAlias() == s2->toAlias()) - { - /* After following aliases, we found the same symbol, - * so it's not an ambiguity. - * But if one alias is deprecated, prefer the other. - */ - if (s->isDeprecated()) - s = s2; - } - else - { - /* Two imports of the same module should be regarded as - * the same. - */ - Import *i1 = s->isImport(); - Import *i2 = s2->isImport(); - if (!(i1 && i2 && - (i1->mod == i2->mod || - (!i1->parent->isImport() && !i2->parent->isImport() && - i1->ident->equals(i2->ident)) - ) - ) - ) - { - ScopeDsymbol::multiplyDefined(loc, s, s2); - break; - } - } - } - } - if (s) - { - Declaration *d = s->isDeclaration(); - if (d && d->protection == PROTprivate && - !d->parent->isTemplateMixin()) - error(loc, "%s is private", d->toPrettyChars()); - } - } - return s; -} - -void ScopeDsymbol::importScope(Dsymbol *s, enum PROT protection) -{ - //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); - - // No circular or redundant import's - if (s != this) - { - if (!imports) - imports = new Dsymbols(); - else - { - for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *ss = (*imports)[i]; - if (ss == s) // if already imported - { - if (protection > prots[i]) - prots[i] = protection; // upgrade access - return; - } - } - } - imports->push(s); - prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0])); - prots[imports->dim - 1] = protection; - } -} - -int ScopeDsymbol::isforwardRef() -{ - return (members == NULL); -} - -void ScopeDsymbol::defineRef(Dsymbol *s) -{ - ScopeDsymbol *ss; - - ss = s->isScopeDsymbol(); - members = ss->members; - ss->members = NULL; -} - -void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2) -{ -#if 0 - printf("ScopeDsymbol::multiplyDefined()\n"); - printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1->toChars(), s1->kind(), s1->parent ? s1->parent->toChars() : ""); - printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : ""); -#endif - if (loc.filename) - { ::error(loc, "%s at %s conflicts with %s at %s", - s1->toPrettyChars(), - s1->locToChars(), - s2->toPrettyChars(), - s2->locToChars()); - } - else - { - s1->error(loc, "conflicts with %s %s at %s", - s2->kind(), - s2->toPrettyChars(), - s2->locToChars()); - } -} - -Dsymbol *ScopeDsymbol::nameCollision(Dsymbol *s) -{ - Dsymbol *sprev; - - // Look to see if we are defining a forward referenced symbol - - sprev = symtab->lookup(s->ident); - assert(sprev); - if (s->equals(sprev)) // if the same symbol - { - if (s->isforwardRef()) // if second declaration is a forward reference - return sprev; - if (sprev->isforwardRef()) - { - sprev->defineRef(s); // copy data from s into sprev - return sprev; - } - } - multiplyDefined(0, s, sprev); - return sprev; -} - -const char *ScopeDsymbol::kind() -{ - return "ScopeDsymbol"; -} - -Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s) -{ - return symtab->insert(s); -} - -/**************************************** - * Return true if any of the members are static ctors or static dtors, or if - * any members have members that are. - */ - -bool ScopeDsymbol::hasStaticCtorOrDtor() -{ - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *member = (*members)[i]; - - if (member->hasStaticCtorOrDtor()) - return TRUE; - } - } - return FALSE; -} - -/*************************************** - * Determine number of Dsymbols, folding in AttribDeclaration members. - */ - -#if DMDV2 -static int dimDg(void *ctx, size_t n, Dsymbol *) -{ - ++*(size_t *)ctx; - return 0; -} - -size_t ScopeDsymbol::dim(Dsymbols *members) -{ - size_t n = 0; - foreach(members, &dimDg, &n); - return n; -} -#endif - -/*************************************** - * Get nth Dsymbol, folding in AttribDeclaration members. - * Returns: - * Dsymbol* nth Dsymbol - * NULL not found, *pn gets incremented by the number - * of Dsymbols - */ - -#if DMDV2 -struct GetNthSymbolCtx -{ - size_t nth; - Dsymbol *sym; -}; - -static int getNthSymbolDg(void *ctx, size_t n, Dsymbol *sym) -{ - GetNthSymbolCtx *p = (GetNthSymbolCtx *)ctx; - if (n == p->nth) - { p->sym = sym; - return 1; - } - return 0; -} - -Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *pn) -{ - GetNthSymbolCtx ctx = { nth, NULL }; - int res = foreach(members, &getNthSymbolDg, &ctx); - return res ? ctx.sym : NULL; -} -#endif - -/*************************************** - * Expands attribute declarations in members in depth first - * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each - * member. - * If dg returns !=0, stops and returns that value else returns 0. - * Use this function to avoid the O(N + N^2/2) complexity of - * calculating dim and calling N times getNth. - */ - -#if DMDV2 -int ScopeDsymbol::foreach(Dsymbols *members, ScopeDsymbol::ForeachDg dg, void *ctx, size_t *pn) -{ - assert(dg); - if (!members) - return 0; - - size_t n = pn ? *pn : 0; // take over index - int result = 0; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - - if (AttribDeclaration *a = s->isAttribDeclaration()) - result = foreach(a->decl, dg, ctx, &n); - else if (TemplateMixin *tm = s->isTemplateMixin()) - result = foreach(tm->members, dg, ctx, &n); - else if (s->isTemplateInstance()) - ; - else - result = dg(ctx, n++, s); - - if (result) - break; - } - - if (pn) - *pn = n; // update index - return result; -} -#endif - -/******************************************* - * Look for member of the form: - * const(MemberInfo)[] getMembers(string); - * Returns NULL if not found - */ - -#if DMDV2 -FuncDeclaration *ScopeDsymbol::findGetMembers() -{ - Dsymbol *s = search_function(this, Id::getmembers); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - -#if 0 // Finish - static TypeFunction *tfgetmembers; - - if (!tfgetmembers) - { - Scope sc; - Parameters *arguments = new Parameters; - Parameters *arg = new Parameter(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL); - arguments->push(arg); - - Type *tret = NULL; - tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd); - tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc); - } - if (fdx) - fdx = fdx->overloadExactMatch(tfgetmembers); -#endif - if (fdx && fdx->isVirtual()) - fdx = NULL; - - return fdx; -} -#endif - - -/****************************** WithScopeSymbol ******************************/ - -WithScopeSymbol::WithScopeSymbol(WithStatement *withstate) - : ScopeDsymbol() -{ - this->withstate = withstate; -} - -Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags) -{ - // Acts as proxy to the with class declaration - return withstate->exp->type->toDsymbol(NULL)->search(loc, ident, 0); -} - -/****************************** ArrayScopeSymbol ******************************/ - -ArrayScopeSymbol::ArrayScopeSymbol(Expression *e) - : ScopeDsymbol() -{ - assert(e->op == TOKindex || e->op == TOKslice); - exp = e; - type = NULL; - td = NULL; -} - -ArrayScopeSymbol::ArrayScopeSymbol(TypeTuple *t) - : ScopeDsymbol() -{ - exp = NULL; - type = t; - td = NULL; -} - -ArrayScopeSymbol::ArrayScopeSymbol(TupleDeclaration *s) - : ScopeDsymbol() -{ - exp = NULL; - type = NULL; - td = s; -} - -Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); - if (ident == Id::length || ident == Id::dollar) - { VarDeclaration **pvar; - Expression *ce; - - L1: - - if (td) - { /* $ gives the number of elements in the tuple - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCconst; - return v; - } - - if (type) - { /* $ gives the number of type entries in the type tuple - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCconst; - return v; - } - - if (exp->op == TOKindex) - { /* array[index] where index is some function of $ - */ - IndexExp *ie = (IndexExp *)exp; - - pvar = &ie->lengthVar; - ce = ie->e1; - } - else if (exp->op == TOKslice) - { /* array[lwr .. upr] where lwr or upr is some function of $ - */ - SliceExp *se = (SliceExp *)exp; - - pvar = &se->lengthVar; - ce = se->e1; - } - else - /* Didn't find $, look in enclosing scope(s). - */ - return NULL; - - /* If we are indexing into an array that is really a type - * tuple, rewrite this as an index into a type tuple and - * try again. - */ - if (ce->op == TOKtype) - { - Type *t = ((TypeExp *)ce)->type; - if (t->ty == Ttuple) - { type = (TypeTuple *)t; - goto L1; - } - } - - /* *pvar is lazily initialized, so if we refer to $ - * multiple times, it gets set only once. - */ - if (!*pvar) // if not already initialized - { /* Create variable v and set it to the value of $ - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - if (ce->op == TOKtuple) - { /* It is for an expression tuple, so the - * length will be a compile-time constant. - */ - Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCconst; - } - else - { /* For arrays, $ will either be a compile-time constant - * (in which case its value in set during constant-folding), - * or a variable (in which case an expression is created in - * toir.c). - */ - VoidInitializer *e = new VoidInitializer(0); - e->type = Type::tsize_t; - v->init = e; - v->storage_class |= STCctfe; // it's never a true static variable - } - *pvar = v; - } - return (*pvar); - } - return NULL; -} - - -/****************************** DsymbolTable ******************************/ - -DsymbolTable::DsymbolTable() -{ - tab = NULL; -} - -DsymbolTable::~DsymbolTable() -{ -} - -Dsymbol *DsymbolTable::lookup(Identifier *ident) -{ - //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); - return (Dsymbol *)_aaGetRvalue(tab, ident); -} - -Dsymbol *DsymbolTable::insert(Dsymbol *s) -{ - //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); - Identifier *ident = s->ident; - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - if (*ps) - return NULL; // already in table - *ps = s; - return s; -} - -Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) -{ - //printf("DsymbolTable::insert()\n"); - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - if (*ps) - return NULL; // already in table - *ps = s; - return s; -} - -Dsymbol *DsymbolTable::update(Dsymbol *s) -{ - Identifier *ident = s->ident; - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - *ps = s; - return s; -} - - - - diff --git a/dmd/dsymbol.h b/dmd/dsymbol.h deleted file mode 100644 index 4c5a4538..00000000 --- a/dmd/dsymbol.h +++ /dev/null @@ -1,387 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_DSYMBOL_H -#define DMD_DSYMBOL_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "stringtable.h" - -#include "mars.h" -#include "arraytypes.h" - -#if IN_LLVM -#if defined(_MSC_VER) -#undef min -#undef max -#endif -#include "../ir/irdsymbol.h" -#endif - -struct Identifier; -struct Scope; -struct DsymbolTable; -struct Declaration; -struct ThisDeclaration; -struct TupleDeclaration; -struct TypedefDeclaration; -struct AliasDeclaration; -struct AggregateDeclaration; -struct EnumDeclaration; -struct ClassDeclaration; -struct InterfaceDeclaration; -struct StructDeclaration; -struct UnionDeclaration; -struct FuncDeclaration; -struct FuncAliasDeclaration; -struct FuncLiteralDeclaration; -struct CtorDeclaration; -struct PostBlitDeclaration; -struct DtorDeclaration; -struct StaticCtorDeclaration; -struct StaticDtorDeclaration; -struct InvariantDeclaration; -struct UnitTestDeclaration; -struct NewDeclaration; -struct VarDeclaration; -struct AttribDeclaration; -#if IN_DMD -struct Symbol; -#endif -struct Package; -struct Module; -struct Import; -struct Type; -struct TypeTuple; -struct WithStatement; -struct LabelDsymbol; -struct ScopeDsymbol; -struct TemplateDeclaration; -struct TemplateInstance; -struct TemplateMixin; -struct EnumMember; -struct ScopeDsymbol; -struct WithScopeSymbol; -struct ArrayScopeSymbol; -struct StaticStructInitDeclaration; -struct Expression; -struct DeleteDeclaration; -struct HdrGenState; -struct TypeInfoDeclaration; -struct ClassInfoDeclaration; -struct OverloadSet; -struct AA; -#if TARGET_NET -struct PragmaScope; -#endif -#if IN_GCC -union tree_node; -typedef union tree_node TYPE; -#else -struct TYPE; -#endif - -// Back end -struct Classsym; - -#if IN_LLVM -class Ir; -namespace llvm -{ - class Value; -} -#endif - -enum PROT -{ - PROTundefined, - PROTnone, // no access - PROTprivate, - PROTpackage, - PROTprotected, - PROTpublic, - PROTexport, -}; - -/* State of symbol in winding its way through the passes of the compiler - */ -enum PASS -{ - PASSinit, // initial state - PASSsemantic, // semantic() started - PASSsemanticdone, // semantic() done - PASSsemantic2, // semantic2() run - PASSsemantic3, // semantic3() started - PASSsemantic3done, // semantic3() done - PASSobj, // toObjFile() run -}; - -typedef int (*Dsymbol_apply_ft_t)(Dsymbol *, void *); - -struct Dsymbol : Object -{ - Identifier *ident; - Identifier *c_ident; - Dsymbol *parent; -#if IN_DMD - Symbol *csym; // symbol for code generator - Symbol *isym; // import version of csym -#endif - unsigned char *comment; // documentation comment for this Dsymbol - Loc loc; // where defined - Scope *scope; // !=NULL means context to use for semantic() - bool errors; // this symbol failed to pass semantic() - - Dsymbol(); - Dsymbol(Identifier *); - char *toChars(); - char *locToChars(); - int equals(Object *o); - int isAnonymous(); - void error(Loc loc, const char *format, ...) IS_PRINTF(3); - void error(const char *format, ...) IS_PRINTF(2); - void checkDeprecated(Loc loc, Scope *sc); - Module *getModule(); // module where declared - Module *getCompilationModule(); // possibly different for templates - Dsymbol *pastMixin(); - Dsymbol *toParent(); - Dsymbol *toParent2(); - TemplateInstance *inTemplateInstance(); - TemplateInstance *isSpeculative(); - - int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() - - static Dsymbols *arraySyntaxCopy(Dsymbols *a); - - virtual const char *toPrettyChars(); - virtual const char *kind(); - virtual Dsymbol *toAlias(); // resolve real symbol - virtual int apply(Dsymbol_apply_ft_t fp, void *param); - virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - virtual void setScope(Scope *sc); - virtual void importAll(Scope *sc); - virtual void semantic0(Scope *sc); - virtual void semantic(Scope *sc); - virtual void semantic2(Scope *sc); - virtual void semantic3(Scope *sc); - virtual void inlineScan(); - virtual Dsymbol *search(Loc loc, Identifier *ident, int flags); - Dsymbol *search_correct(Identifier *id); - Dsymbol *searchX(Loc loc, Scope *sc, Identifier *id); - virtual int overloadInsert(Dsymbol *s); - char *toHChars(); - virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toDocBuffer(OutBuffer *buf); - virtual void toJsonBuffer(OutBuffer *buf); - virtual unsigned size(Loc loc); - virtual int isforwardRef(); - virtual void defineRef(Dsymbol *s); - virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member - virtual ClassDeclaration *isClassMember(); // are we a member of a class? - virtual int isExport(); // is Dsymbol exported? - virtual int isImportedSymbol(); // is Dsymbol imported? - virtual int isDeprecated(); // is Dsymbol deprecated? -#if DMDV2 - virtual int isOverloadable(); -#endif - virtual int hasOverloads(); - virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? - virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? - virtual Type *getType(); // is this a type? - virtual char *mangle(); - virtual int needThis(); // need a 'this' pointer? - virtual enum PROT prot(); - virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - virtual int oneMember(Dsymbol **ps); - static int oneMembers(Dsymbols *members, Dsymbol **ps); - virtual void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - virtual int hasPointers(); - virtual bool hasStaticCtorOrDtor(); - virtual void addLocalClass(ClassDeclarations *) { } - virtual void checkCtorConstInit() { } - - virtual void addComment(unsigned char *comment); - virtual void emitComment(Scope *sc); - void emitDitto(Scope *sc); - -#if IN_DMD - // Backend - - virtual Symbol *toSymbol(); // to backend symbol - virtual void toObjFile(int multiobj); // compile to .obj file - virtual int cvMember(unsigned char *p); // emit cv debug info for member - - Symbol *toImport(); // to backend import symbol - static Symbol *toImport(Symbol *s); // to backend import symbol - - Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix); // helper -#endif - - // Eliminate need for dynamic_cast - virtual Package *isPackage() { return NULL; } - virtual Module *isModule() { return NULL; } - virtual EnumMember *isEnumMember() { return NULL; } - virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; } - virtual TemplateInstance *isTemplateInstance() { return NULL; } - virtual TemplateMixin *isTemplateMixin() { return NULL; } - virtual Declaration *isDeclaration() { return NULL; } - virtual ThisDeclaration *isThisDeclaration() { return NULL; } - virtual TupleDeclaration *isTupleDeclaration() { return NULL; } - virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; } - virtual AliasDeclaration *isAliasDeclaration() { return NULL; } - virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; } - virtual FuncDeclaration *isFuncDeclaration() { return NULL; } - virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; } - virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; } - virtual CtorDeclaration *isCtorDeclaration() { return NULL; } - virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; } - virtual DtorDeclaration *isDtorDeclaration() { return NULL; } - virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; } - virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; } - virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; } - virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; } - virtual NewDeclaration *isNewDeclaration() { return NULL; } - virtual VarDeclaration *isVarDeclaration() { return NULL; } - virtual ClassDeclaration *isClassDeclaration() { return NULL; } - virtual StructDeclaration *isStructDeclaration() { return NULL; } - virtual UnionDeclaration *isUnionDeclaration() { return NULL; } - virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; } - virtual ScopeDsymbol *isScopeDsymbol() { return NULL; } - virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; } - virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; } - virtual Import *isImport() { return NULL; } - virtual EnumDeclaration *isEnumDeclaration() { return NULL; } - virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } - //virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; } - virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; } - virtual AttribDeclaration *isAttribDeclaration() { return NULL; } - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } - virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } - - virtual OverloadSet *isOverloadSet() { return NULL; } -#if TARGET_NET - virtual PragmaScope* isPragmaScope() { return NULL; } -#endif - -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); - - // llvm stuff - int llvmInternal; - - IrDsymbol ir; -#endif -}; - -// Dsymbol that generates a scope - -struct ScopeDsymbol : Dsymbol -{ - Dsymbols *members; // all Dsymbol's in this scope - DsymbolTable *symtab; // members[] sorted into table - - Dsymbols *imports; // imported Dsymbol's - unsigned char *prots; // array of PROT, one for each import - - ScopeDsymbol(); - ScopeDsymbol(Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - void importScope(Dsymbol *s, enum PROT protection); - int isforwardRef(); - void defineRef(Dsymbol *s); - static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); - Dsymbol *nameCollision(Dsymbol *s); - const char *kind(); - FuncDeclaration *findGetMembers(); - virtual Dsymbol *symtabInsert(Dsymbol *s); - bool hasStaticCtorOrDtor(); - - void emitMemberComments(Scope *sc); - - static size_t dim(Dsymbols *members); - static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL); - - typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s); - static int foreach(Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn=NULL); - - ScopeDsymbol *isScopeDsymbol() { return this; } -}; - -// With statement scope - -struct WithScopeSymbol : ScopeDsymbol -{ - WithStatement *withstate; - - WithScopeSymbol(WithStatement *withstate); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - - WithScopeSymbol *isWithScopeSymbol() { return this; } -}; - -// Array Index/Slice scope - -struct ArrayScopeSymbol : ScopeDsymbol -{ - Expression *exp; // IndexExp or SliceExp - TypeTuple *type; // for tuple[length] - TupleDeclaration *td; // for tuples of objects - Scope *sc; - - ArrayScopeSymbol(Expression *e); - ArrayScopeSymbol(TypeTuple *t); - ArrayScopeSymbol(TupleDeclaration *td); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - - ArrayScopeSymbol *isArrayScopeSymbol() { return this; } -}; - -// Overload Sets - -#if DMDV2 -struct OverloadSet : Dsymbol -{ - Dsymbols a; // array of Dsymbols - - OverloadSet(); - void push(Dsymbol *s); - OverloadSet *isOverloadSet() { return this; } - const char *kind(); -}; -#endif - -// Table of Dsymbol's - -struct DsymbolTable : Object -{ - AA *tab; - - DsymbolTable(); - ~DsymbolTable(); - - // Look up Identifier. Return Dsymbol if found, NULL if not. - Dsymbol *lookup(Identifier *ident); - - // Insert Dsymbol in table. Return NULL if already there. - Dsymbol *insert(Dsymbol *s); - - // Look for Dsymbol in table. If there, return it. If not, insert s and return that. - Dsymbol *update(Dsymbol *s); - Dsymbol *insert(Identifier *ident, Dsymbol *s); // when ident and s are not the same -}; - -#endif /* DMD_DSYMBOL_H */ diff --git a/dmd/dump.c b/dmd/dump.c deleted file mode 100644 index d1468264..00000000 --- a/dmd/dump.c +++ /dev/null @@ -1,144 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "mars.h" -#include "mtype.h" -#include "declaration.h" -#include "expression.h" -#include "template.h" - -static void indent(int indent) -{ - int i; - - for (i = 0; i < indent; i++) - printf(" "); -} - -static char *type_print(Type *type) -{ - return type ? type->toChars() : (char *) "null"; -} - -void dumpExpressions(int i, Expressions *exps) -{ - for (size_t j = 0; j < exps->dim; j++) - { Expression *e = (Expression *)exps->data[j]; - indent(i); - printf("(\n"); - e->dump(i + 2); - indent(i); - printf(")\n"); - } -} - -void Expression::dump(int i) -{ - indent(i); - printf("%p %s type=%s\n", this, Token::toChars(op), type_print(type)); -} - -void IntegerExp::dump(int i) -{ - indent(i); - printf("%p %jd type=%s\n", this, (intmax_t)value, type_print(type)); -} - -void IdentifierExp::dump(int i) -{ - indent(i); - printf("%p ident '%s' type=%s\n", this, ident->toChars(), type_print(type)); -} - -void DsymbolExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s\n", this, s->toChars(), type_print(type)); -} - -void VarExp::dump(int i) -{ - indent(i); - printf("%p %s var=%s type=%s\n", this, Token::toChars(op), var->toChars(), type_print(type)); -} - -void UnaExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1); - if (e1) - e1->dump(i + 2); -} - -void CallExp::dump(int i) -{ - UnaExp::dump(i); - dumpExpressions(i, arguments); -} - -void SliceExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1); - if (e1) - e1->dump(i + 2); - if (lwr) - lwr->dump(i + 2); - if (upr) - upr->dump(i + 2); -} - -void DotIdExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s ident=%s e1=%p\n", this, Token::toChars(op), type_print(type), ident->toChars(), e1); - if (e1) - e1->dump(i + 2); -} - -void DotVarExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s var='%s' e1=%p\n", this, Token::toChars(op), type_print(type), var->toChars(), e1); - if (e1) - e1->dump(i + 2); -} - -void DotTemplateInstanceExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s ti='%s' e1=%p\n", this, Token::toChars(op), type_print(type), ti->toChars(), e1); - if (e1) - e1->dump(i + 2); -} - -void DelegateExp::dump(int i) -{ - indent(i); - printf("%p %s func=%s type=%s e1=%p\n", this, Token::toChars(op), func->toChars(), type_print(type), e1); - if (e1) - e1->dump(i + 2); -} - -void BinExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s e1=%p e2=%p\n", this, Token::toChars(op), type_print(type), e1, e2); - if (e1) - e1->dump(i + 2); - if (e2) - e2->dump(i + 2); -} - - diff --git a/dmd/entity.c b/dmd/entity.c deleted file mode 100644 index 98b81141..00000000 --- a/dmd/entity.c +++ /dev/null @@ -1,2391 +0,0 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#include -#include - -/********************************************* - * Convert from named entity to its encoding. - * For reference: - * http://www.htmlhelp.com/reference/html40/entities/ - * http://www.w3.org/2003/entities/2007/w3centities-f.ent - */ - -struct NameId -{ - const char *name; - unsigned value; -}; - -static NameId namesA[]={ - "Aacgr", 0x00386, // GREEK CAPITAL LETTER ALPHA WITH TONOS - "aacgr", 0x003AC, // GREEK SMALL LETTER ALPHA WITH TONOS - "Aacute", 0x000C1, // LATIN CAPITAL LETTER A WITH ACUTE - "aacute", 0x000E1, // LATIN SMALL LETTER A WITH ACUTE - "Abreve", 0x00102, // LATIN CAPITAL LETTER A WITH BREVE - "abreve", 0x00103, // LATIN SMALL LETTER A WITH BREVE - "ac", 0x0223E, // INVERTED LAZY S - "acd", 0x0223F, // SINE WAVE -// "acE", 0x0223E;0x00333, // INVERTED LAZY S with double underline - "Acirc", 0x000C2, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX - "acirc", 0x000E2, // LATIN SMALL LETTER A WITH CIRCUMFLEX - "acute", 0x000B4, // ACUTE ACCENT - "Acy", 0x00410, // CYRILLIC CAPITAL LETTER A - "acy", 0x00430, // CYRILLIC SMALL LETTER A - "AElig", 0x000C6, // LATIN CAPITAL LETTER AE - "aelig", 0x000E6, // LATIN SMALL LETTER AE - "af", 0x02061, // FUNCTION APPLICATION - "Afr", 0x1D504, // MATHEMATICAL FRAKTUR CAPITAL A - "afr", 0x1D51E, // MATHEMATICAL FRAKTUR SMALL A - "Agr", 0x00391, // GREEK CAPITAL LETTER ALPHA - "agr", 0x003B1, // GREEK SMALL LETTER ALPHA - "Agrave", 0x000C0, // LATIN CAPITAL LETTER A WITH GRAVE - "agrave", 0x000E0, // LATIN SMALL LETTER A WITH GRAVE - "alefsym", 0x02135, // ALEF SYMBOL - "aleph", 0x02135, // ALEF SYMBOL - "Alpha", 0x00391, // GREEK CAPITAL LETTER ALPHA - "alpha", 0x003B1, // GREEK SMALL LETTER ALPHA - "Amacr", 0x00100, // LATIN CAPITAL LETTER A WITH MACRON - "amacr", 0x00101, // LATIN SMALL LETTER A WITH MACRON - "amalg", 0x02A3F, // AMALGAMATION OR COPRODUCT - "amp", 0x00026, // AMPERSAND - "AMP", 0x00026, // AMPERSAND - "and", 0x02227, // LOGICAL AND - "And", 0x02A53, // DOUBLE LOGICAL AND - "andand", 0x02A55, // TWO INTERSECTING LOGICAL AND - "andd", 0x02A5C, // LOGICAL AND WITH HORIZONTAL DASH - "andslope", 0x02A58, // SLOPING LARGE AND - "andv", 0x02A5A, // LOGICAL AND WITH MIDDLE STEM - "ang", 0x02220, // ANGLE - "ange", 0x029A4, // ANGLE WITH UNDERBAR - "angle", 0x02220, // ANGLE - "angmsd", 0x02221, // MEASURED ANGLE - "angmsdaa", 0x029A8, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT - "angmsdab", 0x029A9, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT - "angmsdac", 0x029AA, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT - "angmsdad", 0x029AB, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT - "angmsdae", 0x029AC, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP - "angmsdaf", 0x029AD, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP - "angmsdag", 0x029AE, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN - "angmsdah", 0x029AF, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN - "angrt", 0x0221F, // RIGHT ANGLE - "angrtvb", 0x022BE, // RIGHT ANGLE WITH ARC - "angrtvbd", 0x0299D, // MEASURED RIGHT ANGLE WITH DOT - "angsph", 0x02222, // SPHERICAL ANGLE - "angst", 0x000C5, // LATIN CAPITAL LETTER A WITH RING ABOVE - "angzarr", 0x0237C, // RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW - "Aogon", 0x00104, // LATIN CAPITAL LETTER A WITH OGONEK - "aogon", 0x00105, // LATIN SMALL LETTER A WITH OGONEK - "Aopf", 0x1D538, // MATHEMATICAL DOUBLE-STRUCK CAPITAL A - "aopf", 0x1D552, // MATHEMATICAL DOUBLE-STRUCK SMALL A - "ap", 0x02248, // ALMOST EQUAL TO - "apacir", 0x02A6F, // ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT - "ape", 0x0224A, // ALMOST EQUAL OR EQUAL TO - "apE", 0x02A70, // APPROXIMATELY EQUAL OR EQUAL TO - "apid", 0x0224B, // TRIPLE TILDE - "apos", 0x00027, // APOSTROPHE - "ApplyFunction", 0x02061, // FUNCTION APPLICATION - "approx", 0x02248, // ALMOST EQUAL TO - "approxeq", 0x0224A, // ALMOST EQUAL OR EQUAL TO - "Aring", 0x000C5, // LATIN CAPITAL LETTER A WITH RING ABOVE - "aring", 0x000E5, // LATIN SMALL LETTER A WITH RING ABOVE - "Ascr", 0x1D49C, // MATHEMATICAL SCRIPT CAPITAL A - "ascr", 0x1D4B6, // MATHEMATICAL SCRIPT SMALL A - "Assign", 0x02254, // COLON EQUALS - "ast", 0x0002A, // ASTERISK - "asymp", 0x02248, // ALMOST EQUAL TO - "asympeq", 0x0224D, // EQUIVALENT TO - "Atilde", 0x000C3, // LATIN CAPITAL LETTER A WITH TILDE - "atilde", 0x000E3, // LATIN SMALL LETTER A WITH TILDE - "Auml", 0x000C4, // LATIN CAPITAL LETTER A WITH DIAERESIS - "auml", 0x000E4, // LATIN SMALL LETTER A WITH DIAERESIS - "awconint", 0x02233, // ANTICLOCKWISE CONTOUR INTEGRAL - "awint", 0x02A11, // ANTICLOCKWISE INTEGRATION - NULL, 0 -}; - -static NameId namesB[]={ - "backcong", 0x0224C, // ALL EQUAL TO - "backepsilon", 0x003F6, // GREEK REVERSED LUNATE EPSILON SYMBOL - "backprime", 0x02035, // REVERSED PRIME - "backsim", 0x0223D, // REVERSED TILDE - "backsimeq", 0x022CD, // REVERSED TILDE EQUALS - "Backslash", 0x02216, // SET MINUS -// "b.alpha", 0x1D6C2, // MATHEMATICAL BOLD SMALL ALPHA - "Barv", 0x02AE7, // SHORT DOWN TACK WITH OVERBAR - "barvee", 0x022BD, // NOR - "barwed", 0x02305, // PROJECTIVE - "Barwed", 0x02306, // PERSPECTIVE - "barwedge", 0x02305, // PROJECTIVE -// "b.beta", 0x1D6C3, // MATHEMATICAL BOLD SMALL BETA - "bbrk", 0x023B5, // BOTTOM SQUARE BRACKET - "bbrktbrk", 0x023B6, // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET -// "b.chi", 0x1D6D8, // MATHEMATICAL BOLD SMALL CHI - "bcong", 0x0224C, // ALL EQUAL TO - "Bcy", 0x00411, // CYRILLIC CAPITAL LETTER BE - "bcy", 0x00431, // CYRILLIC SMALL LETTER BE -// "b.Delta", 0x1D6AB, // MATHEMATICAL BOLD CAPITAL DELTA -// "b.delta", 0x1D6C5, // MATHEMATICAL BOLD SMALL DELTA - "bdquo", 0x0201E, // DOUBLE LOW-9 QUOTATION MARK - "becaus", 0x02235, // BECAUSE - "because", 0x02235, // BECAUSE - "Because", 0x02235, // BECAUSE - "bemptyv", 0x029B0, // REVERSED EMPTY SET - "bepsi", 0x003F6, // GREEK REVERSED LUNATE EPSILON SYMBOL -// "b.epsi", 0x1D6C6, // MATHEMATICAL BOLD SMALL EPSILON -// "b.epsiv", 0x1D6DC, // MATHEMATICAL BOLD EPSILON SYMBOL - "bernou", 0x0212C, // SCRIPT CAPITAL B - "Bernoullis", 0x0212C, // SCRIPT CAPITAL B - "Beta", 0x00392, // GREEK CAPITAL LETTER BETA - "beta", 0x003B2, // GREEK SMALL LETTER BETA -// "b.eta", 0x1D6C8, // MATHEMATICAL BOLD SMALL ETA - "beth", 0x02136, // BET SYMBOL - "between", 0x0226C, // BETWEEN - "Bfr", 0x1D505, // MATHEMATICAL FRAKTUR CAPITAL B - "bfr", 0x1D51F, // MATHEMATICAL FRAKTUR SMALL B -// "b.Gamma", 0x1D6AA, // MATHEMATICAL BOLD CAPITAL GAMMA -// "b.gamma", 0x1D6C4, // MATHEMATICAL BOLD SMALL GAMMA -// "b.Gammad", 0x1D7CA, // MATHEMATICAL BOLD CAPITAL DIGAMMA -// "b.gammad", 0x1D7CB, // MATHEMATICAL BOLD SMALL DIGAMMA - "Bgr", 0x00392, // GREEK CAPITAL LETTER BETA - "bgr", 0x003B2, // GREEK SMALL LETTER BETA - "bigcap", 0x022C2, // N-ARY INTERSECTION - "bigcirc", 0x025EF, // LARGE CIRCLE - "bigcup", 0x022C3, // N-ARY UNION - "bigodot", 0x02A00, // N-ARY CIRCLED DOT OPERATOR - "bigoplus", 0x02A01, // N-ARY CIRCLED PLUS OPERATOR - "bigotimes", 0x02A02, // N-ARY CIRCLED TIMES OPERATOR - "bigsqcup", 0x02A06, // N-ARY SQUARE UNION OPERATOR - "bigstar", 0x02605, // BLACK STAR - "bigtriangledown", 0x025BD, // WHITE DOWN-POINTING TRIANGLE - "bigtriangleup", 0x025B3, // WHITE UP-POINTING TRIANGLE - "biguplus", 0x02A04, // N-ARY UNION OPERATOR WITH PLUS - "bigvee", 0x022C1, // N-ARY LOGICAL OR - "bigwedge", 0x022C0, // N-ARY LOGICAL AND -// "b.iota", 0x1D6CA, // MATHEMATICAL BOLD SMALL IOTA -// "b.kappa", 0x1D6CB, // MATHEMATICAL BOLD SMALL KAPPA -// "b.kappav", 0x1D6DE, // MATHEMATICAL BOLD KAPPA SYMBOL - "bkarow", 0x0290D, // RIGHTWARDS DOUBLE DASH ARROW - "blacklozenge", 0x029EB, // BLACK LOZENGE - "blacksquare", 0x025AA, // BLACK SMALL SQUARE - "blacktriangle", 0x025B4, // BLACK UP-POINTING SMALL TRIANGLE - "blacktriangledown", 0x025BE, // BLACK DOWN-POINTING SMALL TRIANGLE - "blacktriangleleft", 0x025C2, // BLACK LEFT-POINTING SMALL TRIANGLE - "blacktriangleright", 0x025B8, // BLACK RIGHT-POINTING SMALL TRIANGLE -// "b.Lambda", 0x1D6B2, // MATHEMATICAL BOLD CAPITAL LAMDA -// "b.lambda", 0x1D6CC, // MATHEMATICAL BOLD SMALL LAMDA - "blank", 0x02423, // OPEN BOX - "blk12", 0x02592, // MEDIUM SHADE - "blk14", 0x02591, // LIGHT SHADE - "blk34", 0x02593, // DARK SHADE - "block", 0x02588, // FULL BLOCK -// "b.mu", 0x1D6CD, // MATHEMATICAL BOLD SMALL MU -// "bne", 0x0003D;0x020E5, // EQUALS SIGN with reverse slash -// "bnequiv", 0x02261;0x020E5, // IDENTICAL TO with reverse slash - "bnot", 0x02310, // REVERSED NOT SIGN - "bNot", 0x02AED, // REVERSED DOUBLE STROKE NOT SIGN -// "b.nu", 0x1D6CE, // MATHEMATICAL BOLD SMALL NU -// "b.Omega", 0x1D6C0, // MATHEMATICAL BOLD CAPITAL OMEGA -// "b.omega", 0x1D6DA, // MATHEMATICAL BOLD SMALL OMEGA - "Bopf", 0x1D539, // MATHEMATICAL DOUBLE-STRUCK CAPITAL B - "bopf", 0x1D553, // MATHEMATICAL DOUBLE-STRUCK SMALL B - "bot", 0x022A5, // UP TACK - "bottom", 0x022A5, // UP TACK - "bowtie", 0x022C8, // BOWTIE - "boxbox", 0x029C9, // TWO JOINED SQUARES - "boxdl", 0x02510, // BOX DRAWINGS LIGHT DOWN AND LEFT - "boxdL", 0x02555, // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE - "boxDl", 0x02556, // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE - "boxDL", 0x02557, // BOX DRAWINGS DOUBLE DOWN AND LEFT - "boxdr", 0x0250C, // BOX DRAWINGS LIGHT DOWN AND RIGHT - "boxdR", 0x02552, // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE - "boxDr", 0x02553, // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE - "boxDR", 0x02554, // BOX DRAWINGS DOUBLE DOWN AND RIGHT - "boxh", 0x02500, // BOX DRAWINGS LIGHT HORIZONTAL - "boxH", 0x02550, // BOX DRAWINGS DOUBLE HORIZONTAL - "boxhd", 0x0252C, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - "boxHd", 0x02564, // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE - "boxhD", 0x02565, // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE - "boxHD", 0x02566, // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL - "boxhu", 0x02534, // BOX DRAWINGS LIGHT UP AND HORIZONTAL - "boxHu", 0x02567, // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE - "boxhU", 0x02568, // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE - "boxHU", 0x02569, // BOX DRAWINGS DOUBLE UP AND HORIZONTAL - "boxminus", 0x0229F, // SQUARED MINUS - "boxplus", 0x0229E, // SQUARED PLUS - "boxtimes", 0x022A0, // SQUARED TIMES - "boxul", 0x02518, // BOX DRAWINGS LIGHT UP AND LEFT - "boxuL", 0x0255B, // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE - "boxUl", 0x0255C, // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE - "boxUL", 0x0255D, // BOX DRAWINGS DOUBLE UP AND LEFT - "boxur", 0x02514, // BOX DRAWINGS LIGHT UP AND RIGHT - "boxuR", 0x02558, // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE - "boxUr", 0x02559, // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE - "boxUR", 0x0255A, // BOX DRAWINGS DOUBLE UP AND RIGHT - "boxv", 0x02502, // BOX DRAWINGS LIGHT VERTICAL - "boxV", 0x02551, // BOX DRAWINGS DOUBLE VERTICAL - "boxvh", 0x0253C, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - "boxvH", 0x0256A, // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE - "boxVh", 0x0256B, // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE - "boxVH", 0x0256C, // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL - "boxvl", 0x02524, // BOX DRAWINGS LIGHT VERTICAL AND LEFT - "boxvL", 0x02561, // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE - "boxVl", 0x02562, // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE - "boxVL", 0x02563, // BOX DRAWINGS DOUBLE VERTICAL AND LEFT - "boxvr", 0x0251C, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT - "boxvR", 0x0255E, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE - "boxVr", 0x0255F, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE - "boxVR", 0x02560, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -// "b.Phi", 0x1D6BD, // MATHEMATICAL BOLD CAPITAL PHI -// "b.phi", 0x1D6D7, // MATHEMATICAL BOLD SMALL PHI -// "b.phiv", 0x1D6DF, // MATHEMATICAL BOLD PHI SYMBOL -// "b.Pi", 0x1D6B7, // MATHEMATICAL BOLD CAPITAL PI -// "b.pi", 0x1D6D1, // MATHEMATICAL BOLD SMALL PI -// "b.piv", 0x1D6E1, // MATHEMATICAL BOLD PI SYMBOL - "bprime", 0x02035, // REVERSED PRIME -// "b.Psi", 0x1D6BF, // MATHEMATICAL BOLD CAPITAL PSI -// "b.psi", 0x1D6D9, // MATHEMATICAL BOLD SMALL PSI - "breve", 0x002D8, // BREVE - "Breve", 0x002D8, // BREVE -// "b.rho", 0x1D6D2, // MATHEMATICAL BOLD SMALL RHO -// "b.rhov", 0x1D6E0, // MATHEMATICAL BOLD RHO SYMBOL - "brvbar", 0x000A6, // BROKEN BAR - "Bscr", 0x0212C, // SCRIPT CAPITAL B - "bscr", 0x1D4B7, // MATHEMATICAL SCRIPT SMALL B - "bsemi", 0x0204F, // REVERSED SEMICOLON -// "b.Sigma", 0x1D6BA, // MATHEMATICAL BOLD CAPITAL SIGMA -// "b.sigma", 0x1D6D4, // MATHEMATICAL BOLD SMALL SIGMA -// "b.sigmav", 0x1D6D3, // MATHEMATICAL BOLD SMALL FINAL SIGMA - "bsim", 0x0223D, // REVERSED TILDE - "bsime", 0x022CD, // REVERSED TILDE EQUALS - "bsol", 0x0005C, // REVERSE SOLIDUS - "bsolb", 0x029C5, // SQUARED FALLING DIAGONAL SLASH - "bsolhsub", 0x027C8, // REVERSE SOLIDUS PRECEDING SUBSET -// "b.tau", 0x1D6D5, // MATHEMATICAL BOLD SMALL TAU -// "b.Theta", 0x1D6AF, // MATHEMATICAL BOLD CAPITAL THETA -// "b.thetas", 0x1D6C9, // MATHEMATICAL BOLD SMALL THETA -// "b.thetav", 0x1D6DD, // MATHEMATICAL BOLD THETA SYMBOL - "bull", 0x02022, // BULLET - "bullet", 0x02022, // BULLET - "bump", 0x0224E, // GEOMETRICALLY EQUIVALENT TO - "bumpe", 0x0224F, // DIFFERENCE BETWEEN - "bumpE", 0x02AAE, // EQUALS SIGN WITH BUMPY ABOVE - "Bumpeq", 0x0224E, // GEOMETRICALLY EQUIVALENT TO - "bumpeq", 0x0224F, // DIFFERENCE BETWEEN -// "b.Upsi", 0x1D6BC, // MATHEMATICAL BOLD CAPITAL UPSILON -// "b.upsi", 0x1D6D6, // MATHEMATICAL BOLD SMALL UPSILON -// "b.Xi", 0x1D6B5, // MATHEMATICAL BOLD CAPITAL XI -// "b.xi", 0x1D6CF, // MATHEMATICAL BOLD SMALL XI -// "b.zeta", 0x1D6C7, // MATHEMATICAL BOLD SMALL ZETA - NULL, 0 -}; - -static NameId namesC[]={ - "Cacute", 0x00106, // LATIN CAPITAL LETTER C WITH ACUTE - "cacute", 0x00107, // LATIN SMALL LETTER C WITH ACUTE - "cap", 0x02229, // INTERSECTION - "Cap", 0x022D2, // DOUBLE INTERSECTION - "capand", 0x02A44, // INTERSECTION WITH LOGICAL AND - "capbrcup", 0x02A49, // INTERSECTION ABOVE BAR ABOVE UNION - "capcap", 0x02A4B, // INTERSECTION BESIDE AND JOINED WITH INTERSECTION - "capcup", 0x02A47, // INTERSECTION ABOVE UNION - "capdot", 0x02A40, // INTERSECTION WITH DOT - "CapitalDifferentialD", 0x02145, // DOUBLE-STRUCK ITALIC CAPITAL D -// "caps", 0x02229;0x0FE00, // INTERSECTION with serifs - "caret", 0x02041, // CARET INSERTION POINT - "caron", 0x002C7, // CARON - "Cayleys", 0x0212D, // BLACK-LETTER CAPITAL C - "ccaps", 0x02A4D, // CLOSED INTERSECTION WITH SERIFS - "Ccaron", 0x0010C, // LATIN CAPITAL LETTER C WITH CARON - "ccaron", 0x0010D, // LATIN SMALL LETTER C WITH CARON - "Ccedil", 0x000C7, // LATIN CAPITAL LETTER C WITH CEDILLA - "ccedil", 0x000E7, // LATIN SMALL LETTER C WITH CEDILLA - "Ccirc", 0x00108, // LATIN CAPITAL LETTER C WITH CIRCUMFLEX - "ccirc", 0x00109, // LATIN SMALL LETTER C WITH CIRCUMFLEX - "Cconint", 0x02230, // VOLUME INTEGRAL - "ccups", 0x02A4C, // CLOSED UNION WITH SERIFS - "ccupssm", 0x02A50, // CLOSED UNION WITH SERIFS AND SMASH PRODUCT - "Cdot", 0x0010A, // LATIN CAPITAL LETTER C WITH DOT ABOVE - "cdot", 0x0010B, // LATIN SMALL LETTER C WITH DOT ABOVE - "cedil", 0x000B8, // CEDILLA - "Cedilla", 0x000B8, // CEDILLA - "cemptyv", 0x029B2, // EMPTY SET WITH SMALL CIRCLE ABOVE - "cent", 0x000A2, // CENT SIGN - "centerdot", 0x000B7, // MIDDLE DOT - "CenterDot", 0x000B7, // MIDDLE DOT - "Cfr", 0x0212D, // BLACK-LETTER CAPITAL C - "cfr", 0x1D520, // MATHEMATICAL FRAKTUR SMALL C - "CHcy", 0x00427, // CYRILLIC CAPITAL LETTER CHE - "chcy", 0x00447, // CYRILLIC SMALL LETTER CHE - "check", 0x02713, // CHECK MARK - "checkmark", 0x02713, // CHECK MARK - "Chi", 0x003A7, // GREEK CAPITAL LETTER CHI - "chi", 0x003C7, // GREEK SMALL LETTER CHI - "cir", 0x025CB, // WHITE CIRCLE - "circ", 0x002C6, // MODIFIER LETTER CIRCUMFLEX ACCENT - "circeq", 0x02257, // RING EQUAL TO - "circlearrowleft", 0x021BA, // ANTICLOCKWISE OPEN CIRCLE ARROW - "circlearrowright", 0x021BB, // CLOCKWISE OPEN CIRCLE ARROW - "circledast", 0x0229B, // CIRCLED ASTERISK OPERATOR - "circledcirc", 0x0229A, // CIRCLED RING OPERATOR - "circleddash", 0x0229D, // CIRCLED DASH - "CircleDot", 0x02299, // CIRCLED DOT OPERATOR - "circledR", 0x000AE, // REGISTERED SIGN - "circledS", 0x024C8, // CIRCLED LATIN CAPITAL LETTER S - "CircleMinus", 0x02296, // CIRCLED MINUS - "CirclePlus", 0x02295, // CIRCLED PLUS - "CircleTimes", 0x02297, // CIRCLED TIMES - "cire", 0x02257, // RING EQUAL TO - "cirE", 0x029C3, // CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT - "cirfnint", 0x02A10, // CIRCULATION FUNCTION - "cirmid", 0x02AEF, // VERTICAL LINE WITH CIRCLE ABOVE - "cirscir", 0x029C2, // CIRCLE WITH SMALL CIRCLE TO THE RIGHT - "ClockwiseContourIntegral", 0x02232, // CLOCKWISE CONTOUR INTEGRAL - "CloseCurlyDoubleQuote", 0x0201D, // RIGHT DOUBLE QUOTATION MARK - "CloseCurlyQuote", 0x02019, // RIGHT SINGLE QUOTATION MARK - "clubs", 0x02663, // BLACK CLUB SUIT - "clubsuit", 0x02663, // BLACK CLUB SUIT - "colon", 0x0003A, // COLON - "Colon", 0x02237, // PROPORTION - "colone", 0x02254, // COLON EQUALS - "Colone", 0x02A74, // DOUBLE COLON EQUAL - "coloneq", 0x02254, // COLON EQUALS - "comma", 0x0002C, // COMMA - "commat", 0x00040, // COMMERCIAL AT - "comp", 0x02201, // COMPLEMENT - "compfn", 0x02218, // RING OPERATOR - "complement", 0x02201, // COMPLEMENT - "complexes", 0x02102, // DOUBLE-STRUCK CAPITAL C - "cong", 0x02245, // APPROXIMATELY EQUAL TO - "congdot", 0x02A6D, // CONGRUENT WITH DOT ABOVE - "Congruent", 0x02261, // IDENTICAL TO - "conint", 0x0222E, // CONTOUR INTEGRAL - "Conint", 0x0222F, // SURFACE INTEGRAL - "ContourIntegral", 0x0222E, // CONTOUR INTEGRAL - "Copf", 0x02102, // DOUBLE-STRUCK CAPITAL C - "copf", 0x1D554, // MATHEMATICAL DOUBLE-STRUCK SMALL C - "coprod", 0x02210, // N-ARY COPRODUCT - "Coproduct", 0x02210, // N-ARY COPRODUCT - "copy", 0x000A9, // COPYRIGHT SIGN - "COPY", 0x000A9, // COPYRIGHT SIGN - "copysr", 0x02117, // SOUND RECORDING COPYRIGHT - "CounterClockwiseContourIntegral", 0x02233, // ANTICLOCKWISE CONTOUR INTEGRAL - "crarr", 0x021B5, // DOWNWARDS ARROW WITH CORNER LEFTWARDS - "cross", 0x02717, // BALLOT X - "Cross", 0x02A2F, // VECTOR OR CROSS PRODUCT - "Cscr", 0x1D49E, // MATHEMATICAL SCRIPT CAPITAL C - "cscr", 0x1D4B8, // MATHEMATICAL SCRIPT SMALL C - "csub", 0x02ACF, // CLOSED SUBSET - "csube", 0x02AD1, // CLOSED SUBSET OR EQUAL TO - "csup", 0x02AD0, // CLOSED SUPERSET - "csupe", 0x02AD2, // CLOSED SUPERSET OR EQUAL TO - "ctdot", 0x022EF, // MIDLINE HORIZONTAL ELLIPSIS - "cudarrl", 0x02938, // RIGHT-SIDE ARC CLOCKWISE ARROW - "cudarrr", 0x02935, // ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS - "cuepr", 0x022DE, // EQUAL TO OR PRECEDES - "cuesc", 0x022DF, // EQUAL TO OR SUCCEEDS - "cularr", 0x021B6, // ANTICLOCKWISE TOP SEMICIRCLE ARROW - "cularrp", 0x0293D, // TOP ARC ANTICLOCKWISE ARROW WITH PLUS - "cup", 0x0222A, // UNION - "Cup", 0x022D3, // DOUBLE UNION - "cupbrcap", 0x02A48, // UNION ABOVE BAR ABOVE INTERSECTION - "CupCap", 0x0224D, // EQUIVALENT TO - "cupcap", 0x02A46, // UNION ABOVE INTERSECTION - "cupcup", 0x02A4A, // UNION BESIDE AND JOINED WITH UNION - "cupdot", 0x0228D, // MULTISET MULTIPLICATION - "cupor", 0x02A45, // UNION WITH LOGICAL OR -// "cups", 0x0222A;0x0FE00, // UNION with serifs - "curarr", 0x021B7, // CLOCKWISE TOP SEMICIRCLE ARROW - "curarrm", 0x0293C, // TOP ARC CLOCKWISE ARROW WITH MINUS - "curlyeqprec", 0x022DE, // EQUAL TO OR PRECEDES - "curlyeqsucc", 0x022DF, // EQUAL TO OR SUCCEEDS - "curlyvee", 0x022CE, // CURLY LOGICAL OR - "curlywedge", 0x022CF, // CURLY LOGICAL AND - "curren", 0x000A4, // CURRENCY SIGN - "curvearrowleft", 0x021B6, // ANTICLOCKWISE TOP SEMICIRCLE ARROW - "curvearrowright", 0x021B7, // CLOCKWISE TOP SEMICIRCLE ARROW - "cuvee", 0x022CE, // CURLY LOGICAL OR - "cuwed", 0x022CF, // CURLY LOGICAL AND - "cwconint", 0x02232, // CLOCKWISE CONTOUR INTEGRAL - "cwint", 0x02231, // CLOCKWISE INTEGRAL - "cylcty", 0x0232D, // CYLINDRICITY - NULL, 0 -}; - -static NameId namesD[]={ - "dagger", 0x02020, // DAGGER - "Dagger", 0x02021, // DOUBLE DAGGER - "daleth", 0x02138, // DALET SYMBOL - "darr", 0x02193, // DOWNWARDS ARROW - "Darr", 0x021A1, // DOWNWARDS TWO HEADED ARROW - "dArr", 0x021D3, // DOWNWARDS DOUBLE ARROW - "dash", 0x02010, // HYPHEN - "dashv", 0x022A3, // LEFT TACK - "Dashv", 0x02AE4, // VERTICAL BAR DOUBLE LEFT TURNSTILE - "dbkarow", 0x0290F, // RIGHTWARDS TRIPLE DASH ARROW - "dblac", 0x002DD, // DOUBLE ACUTE ACCENT - "Dcaron", 0x0010E, // LATIN CAPITAL LETTER D WITH CARON - "dcaron", 0x0010F, // LATIN SMALL LETTER D WITH CARON - "Dcy", 0x00414, // CYRILLIC CAPITAL LETTER DE - "dcy", 0x00434, // CYRILLIC SMALL LETTER DE - "DD", 0x02145, // DOUBLE-STRUCK ITALIC CAPITAL D - "dd", 0x02146, // DOUBLE-STRUCK ITALIC SMALL D - "ddagger", 0x02021, // DOUBLE DAGGER - "ddarr", 0x021CA, // DOWNWARDS PAIRED ARROWS - "DDotrahd", 0x02911, // RIGHTWARDS ARROW WITH DOTTED STEM - "ddotseq", 0x02A77, // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW - "deg", 0x000B0, // DEGREE SIGN - "Del", 0x02207, // NABLA - "Delta", 0x00394, // GREEK CAPITAL LETTER DELTA - "delta", 0x003B4, // GREEK SMALL LETTER DELTA - "demptyv", 0x029B1, // EMPTY SET WITH OVERBAR - "dfisht", 0x0297F, // DOWN FISH TAIL - "Dfr", 0x1D507, // MATHEMATICAL FRAKTUR CAPITAL D - "dfr", 0x1D521, // MATHEMATICAL FRAKTUR SMALL D - "Dgr", 0x00394, // GREEK CAPITAL LETTER DELTA - "dgr", 0x003B4, // GREEK SMALL LETTER DELTA - "dHar", 0x02965, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT - "dharl", 0x021C3, // DOWNWARDS HARPOON WITH BARB LEFTWARDS - "dharr", 0x021C2, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS - "DiacriticalAcute", 0x000B4, // ACUTE ACCENT - "DiacriticalDot", 0x002D9, // DOT ABOVE - "DiacriticalDoubleAcute", 0x002DD, // DOUBLE ACUTE ACCENT - "DiacriticalGrave", 0x00060, // GRAVE ACCENT - "DiacriticalTilde", 0x002DC, // SMALL TILDE - "diam", 0x022C4, // DIAMOND OPERATOR - "diamond", 0x022C4, // DIAMOND OPERATOR - "Diamond", 0x022C4, // DIAMOND OPERATOR - "diamondsuit", 0x02666, // BLACK DIAMOND SUIT - "diams", 0x02666, // BLACK DIAMOND SUIT - "die", 0x000A8, // DIAERESIS - "DifferentialD", 0x02146, // DOUBLE-STRUCK ITALIC SMALL D - "digamma", 0x003DD, // GREEK SMALL LETTER DIGAMMA - "disin", 0x022F2, // ELEMENT OF WITH LONG HORIZONTAL STROKE - "div", 0x000F7, // DIVISION SIGN - "divide", 0x000F7, // DIVISION SIGN - "divideontimes", 0x022C7, // DIVISION TIMES - "divonx", 0x022C7, // DIVISION TIMES - "DJcy", 0x00402, // CYRILLIC CAPITAL LETTER DJE - "djcy", 0x00452, // CYRILLIC SMALL LETTER DJE - "dlcorn", 0x0231E, // BOTTOM LEFT CORNER - "dlcrop", 0x0230D, // BOTTOM LEFT CROP - "dollar", 0x00024, // DOLLAR SIGN - "Dopf", 0x1D53B, // MATHEMATICAL DOUBLE-STRUCK CAPITAL D - "dopf", 0x1D555, // MATHEMATICAL DOUBLE-STRUCK SMALL D - "Dot", 0x000A8, // DIAERESIS - "dot", 0x002D9, // DOT ABOVE - "DotDot", 0x020DC, // COMBINING FOUR DOTS ABOVE - "doteq", 0x02250, // APPROACHES THE LIMIT - "doteqdot", 0x02251, // GEOMETRICALLY EQUAL TO - "DotEqual", 0x02250, // APPROACHES THE LIMIT - "dotminus", 0x02238, // DOT MINUS - "dotplus", 0x02214, // DOT PLUS - "dotsquare", 0x022A1, // SQUARED DOT OPERATOR - "doublebarwedge", 0x02306, // PERSPECTIVE - "DoubleContourIntegral", 0x0222F, // SURFACE INTEGRAL - "DoubleDot", 0x000A8, // DIAERESIS - "DoubleDownArrow", 0x021D3, // DOWNWARDS DOUBLE ARROW - "DoubleLeftArrow", 0x021D0, // LEFTWARDS DOUBLE ARROW - "DoubleLeftRightArrow", 0x021D4, // LEFT RIGHT DOUBLE ARROW - "DoubleLeftTee", 0x02AE4, // VERTICAL BAR DOUBLE LEFT TURNSTILE - "DoubleLongLeftArrow", 0x027F8, // LONG LEFTWARDS DOUBLE ARROW - "DoubleLongLeftRightArrow", 0x027FA, // LONG LEFT RIGHT DOUBLE ARROW - "DoubleLongRightArrow", 0x027F9, // LONG RIGHTWARDS DOUBLE ARROW - "DoubleRightArrow", 0x021D2, // RIGHTWARDS DOUBLE ARROW - "DoubleRightTee", 0x022A8, // TRUE - "DoubleUpArrow", 0x021D1, // UPWARDS DOUBLE ARROW - "DoubleUpDownArrow", 0x021D5, // UP DOWN DOUBLE ARROW - "DoubleVerticalBar", 0x02225, // PARALLEL TO - "downarrow", 0x02193, // DOWNWARDS ARROW - "DownArrow", 0x02193, // DOWNWARDS ARROW - "Downarrow", 0x021D3, // DOWNWARDS DOUBLE ARROW - "DownArrowBar", 0x02913, // DOWNWARDS ARROW TO BAR - "DownArrowUpArrow", 0x021F5, // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW - "DownBreve", 0x00311, // COMBINING INVERTED BREVE - "downdownarrows", 0x021CA, // DOWNWARDS PAIRED ARROWS - "downharpoonleft", 0x021C3, // DOWNWARDS HARPOON WITH BARB LEFTWARDS - "downharpoonright", 0x021C2, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS - "DownLeftRightVector", 0x02950, // LEFT BARB DOWN RIGHT BARB DOWN HARPOON - "DownLeftTeeVector", 0x0295E, // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR - "DownLeftVector", 0x021BD, // LEFTWARDS HARPOON WITH BARB DOWNWARDS - "DownLeftVectorBar", 0x02956, // LEFTWARDS HARPOON WITH BARB DOWN TO BAR - "DownRightTeeVector", 0x0295F, // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR - "DownRightVector", 0x021C1, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS - "DownRightVectorBar", 0x02957, // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR - "DownTee", 0x022A4, // DOWN TACK - "DownTeeArrow", 0x021A7, // DOWNWARDS ARROW FROM BAR - "drbkarow", 0x02910, // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW - "drcorn", 0x0231F, // BOTTOM RIGHT CORNER - "drcrop", 0x0230C, // BOTTOM RIGHT CROP - "Dscr", 0x1D49F, // MATHEMATICAL SCRIPT CAPITAL D - "dscr", 0x1D4B9, // MATHEMATICAL SCRIPT SMALL D - "DScy", 0x00405, // CYRILLIC CAPITAL LETTER DZE - "dscy", 0x00455, // CYRILLIC SMALL LETTER DZE - "dsol", 0x029F6, // SOLIDUS WITH OVERBAR - "Dstrok", 0x00110, // LATIN CAPITAL LETTER D WITH STROKE - "dstrok", 0x00111, // LATIN SMALL LETTER D WITH STROKE - "dtdot", 0x022F1, // DOWN RIGHT DIAGONAL ELLIPSIS - "dtri", 0x025BF, // WHITE DOWN-POINTING SMALL TRIANGLE - "dtrif", 0x025BE, // BLACK DOWN-POINTING SMALL TRIANGLE - "duarr", 0x021F5, // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW - "duhar", 0x0296F, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT - "dwangle", 0x029A6, // OBLIQUE ANGLE OPENING UP - "DZcy", 0x0040F, // CYRILLIC CAPITAL LETTER DZHE - "dzcy", 0x0045F, // CYRILLIC SMALL LETTER DZHE - "dzigrarr", 0x027FF, // LONG RIGHTWARDS SQUIGGLE ARROW - NULL, 0 -}; - -static NameId namesE[]={ - "Eacgr", 0x00388, // GREEK CAPITAL LETTER EPSILON WITH TONOS - "eacgr", 0x003AD, // GREEK SMALL LETTER EPSILON WITH TONOS - "Eacute", 0x000C9, // LATIN CAPITAL LETTER E WITH ACUTE - "eacute", 0x000E9, // LATIN SMALL LETTER E WITH ACUTE - "easter", 0x02A6E, // EQUALS WITH ASTERISK - "Ecaron", 0x0011A, // LATIN CAPITAL LETTER E WITH CARON - "ecaron", 0x0011B, // LATIN SMALL LETTER E WITH CARON - "ecir", 0x02256, // RING IN EQUAL TO - "Ecirc", 0x000CA, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX - "ecirc", 0x000EA, // LATIN SMALL LETTER E WITH CIRCUMFLEX - "ecolon", 0x02255, // EQUALS COLON - "Ecy", 0x0042D, // CYRILLIC CAPITAL LETTER E - "ecy", 0x0044D, // CYRILLIC SMALL LETTER E - "eDDot", 0x02A77, // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW - "Edot", 0x00116, // LATIN CAPITAL LETTER E WITH DOT ABOVE - "edot", 0x00117, // LATIN SMALL LETTER E WITH DOT ABOVE - "eDot", 0x02251, // GEOMETRICALLY EQUAL TO - "ee", 0x02147, // DOUBLE-STRUCK ITALIC SMALL E - "EEacgr", 0x00389, // GREEK CAPITAL LETTER ETA WITH TONOS - "eeacgr", 0x003AE, // GREEK SMALL LETTER ETA WITH TONOS - "EEgr", 0x00397, // GREEK CAPITAL LETTER ETA - "eegr", 0x003B7, // GREEK SMALL LETTER ETA - "efDot", 0x02252, // APPROXIMATELY EQUAL TO OR THE IMAGE OF - "Efr", 0x1D508, // MATHEMATICAL FRAKTUR CAPITAL E - "efr", 0x1D522, // MATHEMATICAL FRAKTUR SMALL E - "eg", 0x02A9A, // DOUBLE-LINE EQUAL TO OR GREATER-THAN - "Egr", 0x00395, // GREEK CAPITAL LETTER EPSILON - "egr", 0x003B5, // GREEK SMALL LETTER EPSILON - "Egrave", 0x000C8, // LATIN CAPITAL LETTER E WITH GRAVE - "egrave", 0x000E8, // LATIN SMALL LETTER E WITH GRAVE - "egs", 0x02A96, // SLANTED EQUAL TO OR GREATER-THAN - "egsdot", 0x02A98, // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE - "el", 0x02A99, // DOUBLE-LINE EQUAL TO OR LESS-THAN - "Element", 0x02208, // ELEMENT OF - "elinters", 0x023E7, // ELECTRICAL INTERSECTION - "ell", 0x02113, // SCRIPT SMALL L - "els", 0x02A95, // SLANTED EQUAL TO OR LESS-THAN - "elsdot", 0x02A97, // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE - "Emacr", 0x00112, // LATIN CAPITAL LETTER E WITH MACRON - "emacr", 0x00113, // LATIN SMALL LETTER E WITH MACRON - "empty", 0x02205, // EMPTY SET - "emptyset", 0x02205, // EMPTY SET - "EmptySmallSquare", 0x025FB, // WHITE MEDIUM SQUARE - "emptyv", 0x02205, // EMPTY SET - "EmptyVerySmallSquare", 0x025AB, // WHITE SMALL SQUARE - "emsp", 0x02003, // EM SPACE - "emsp13", 0x02004, // THREE-PER-EM SPACE - "emsp14", 0x02005, // FOUR-PER-EM SPACE - "ENG", 0x0014A, // LATIN CAPITAL LETTER ENG - "eng", 0x0014B, // LATIN SMALL LETTER ENG - "ensp", 0x02002, // EN SPACE - "Eogon", 0x00118, // LATIN CAPITAL LETTER E WITH OGONEK - "eogon", 0x00119, // LATIN SMALL LETTER E WITH OGONEK - "Eopf", 0x1D53C, // MATHEMATICAL DOUBLE-STRUCK CAPITAL E - "eopf", 0x1D556, // MATHEMATICAL DOUBLE-STRUCK SMALL E - "epar", 0x022D5, // EQUAL AND PARALLEL TO - "eparsl", 0x029E3, // EQUALS SIGN AND SLANTED PARALLEL - "eplus", 0x02A71, // EQUALS SIGN ABOVE PLUS SIGN - "epsi", 0x003B5, // GREEK SMALL LETTER EPSILON - "Epsilon", 0x00395, // GREEK CAPITAL LETTER EPSILON - "epsilon", 0x003B5, // GREEK SMALL LETTER EPSILON - "epsiv", 0x003F5, // GREEK LUNATE EPSILON SYMBOL - "eqcirc", 0x02256, // RING IN EQUAL TO - "eqcolon", 0x02255, // EQUALS COLON - "eqsim", 0x02242, // MINUS TILDE - "eqslantgtr", 0x02A96, // SLANTED EQUAL TO OR GREATER-THAN - "eqslantless", 0x02A95, // SLANTED EQUAL TO OR LESS-THAN - "Equal", 0x02A75, // TWO CONSECUTIVE EQUALS SIGNS - "equals", 0x0003D, // EQUALS SIGN - "EqualTilde", 0x02242, // MINUS TILDE - "equest", 0x0225F, // QUESTIONED EQUAL TO - "Equilibrium", 0x021CC, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - "equiv", 0x02261, // IDENTICAL TO - "equivDD", 0x02A78, // EQUIVALENT WITH FOUR DOTS ABOVE - "eqvparsl", 0x029E5, // IDENTICAL TO AND SLANTED PARALLEL - "erarr", 0x02971, // EQUALS SIGN ABOVE RIGHTWARDS ARROW - "erDot", 0x02253, // IMAGE OF OR APPROXIMATELY EQUAL TO - "escr", 0x0212F, // SCRIPT SMALL E - "Escr", 0x02130, // SCRIPT CAPITAL E - "esdot", 0x02250, // APPROACHES THE LIMIT - "esim", 0x02242, // MINUS TILDE - "Esim", 0x02A73, // EQUALS SIGN ABOVE TILDE OPERATOR - "Eta", 0x00397, // GREEK CAPITAL LETTER ETA - "eta", 0x003B7, // GREEK SMALL LETTER ETA - "ETH", 0x000D0, // LATIN CAPITAL LETTER ETH - "eth", 0x000F0, // LATIN SMALL LETTER ETH - "Euml", 0x000CB, // LATIN CAPITAL LETTER E WITH DIAERESIS - "euml", 0x000EB, // LATIN SMALL LETTER E WITH DIAERESIS - "euro", 0x020AC, // EURO SIGN - "excl", 0x00021, // EXCLAMATION MARK - "exist", 0x02203, // THERE EXISTS - "Exists", 0x02203, // THERE EXISTS - "expectation", 0x02130, // SCRIPT CAPITAL E - "exponentiale", 0x02147, // DOUBLE-STRUCK ITALIC SMALL E - "ExponentialE", 0x02147, // DOUBLE-STRUCK ITALIC SMALL E - NULL, 0 -}; - -static NameId namesF[]={ - "fallingdotseq", 0x02252, // APPROXIMATELY EQUAL TO OR THE IMAGE OF - "Fcy", 0x00424, // CYRILLIC CAPITAL LETTER EF - "fcy", 0x00444, // CYRILLIC SMALL LETTER EF - "female", 0x02640, // FEMALE SIGN - "ffilig", 0x0FB03, // LATIN SMALL LIGATURE FFI - "fflig", 0x0FB00, // LATIN SMALL LIGATURE FF - "ffllig", 0x0FB04, // LATIN SMALL LIGATURE FFL - "Ffr", 0x1D509, // MATHEMATICAL FRAKTUR CAPITAL F - "ffr", 0x1D523, // MATHEMATICAL FRAKTUR SMALL F - "filig", 0x0FB01, // LATIN SMALL LIGATURE FI - "FilledSmallSquare", 0x025FC, // BLACK MEDIUM SQUARE - "FilledVerySmallSquare", 0x025AA, // BLACK SMALL SQUARE -// "fjlig", 0x00066;0x0006A, // fj ligature - "flat", 0x0266D, // MUSIC FLAT SIGN - "fllig", 0x0FB02, // LATIN SMALL LIGATURE FL - "fltns", 0x025B1, // WHITE PARALLELOGRAM - "fnof", 0x00192, // LATIN SMALL LETTER F WITH HOOK - "Fopf", 0x1D53D, // MATHEMATICAL DOUBLE-STRUCK CAPITAL F - "fopf", 0x1D557, // MATHEMATICAL DOUBLE-STRUCK SMALL F - "forall", 0x02200, // FOR ALL - "ForAll", 0x02200, // FOR ALL - "fork", 0x022D4, // PITCHFORK - "forkv", 0x02AD9, // ELEMENT OF OPENING DOWNWARDS - "Fouriertrf", 0x02131, // SCRIPT CAPITAL F - "fpartint", 0x02A0D, // FINITE PART INTEGRAL - "frac12", 0x000BD, // VULGAR FRACTION ONE HALF - "frac13", 0x02153, // VULGAR FRACTION ONE THIRD - "frac14", 0x000BC, // VULGAR FRACTION ONE QUARTER - "frac15", 0x02155, // VULGAR FRACTION ONE FIFTH - "frac16", 0x02159, // VULGAR FRACTION ONE SIXTH - "frac18", 0x0215B, // VULGAR FRACTION ONE EIGHTH - "frac23", 0x02154, // VULGAR FRACTION TWO THIRDS - "frac25", 0x02156, // VULGAR FRACTION TWO FIFTHS - "frac34", 0x000BE, // VULGAR FRACTION THREE QUARTERS - "frac35", 0x02157, // VULGAR FRACTION THREE FIFTHS - "frac38", 0x0215C, // VULGAR FRACTION THREE EIGHTHS - "frac45", 0x02158, // VULGAR FRACTION FOUR FIFTHS - "frac56", 0x0215A, // VULGAR FRACTION FIVE SIXTHS - "frac58", 0x0215D, // VULGAR FRACTION FIVE EIGHTHS - "frac78", 0x0215E, // VULGAR FRACTION SEVEN EIGHTHS - "frasl", 0x02044, // FRACTION SLASH - "frown", 0x02322, // FROWN - "Fscr", 0x02131, // SCRIPT CAPITAL F - "fscr", 0x1D4BB, // MATHEMATICAL SCRIPT SMALL F - NULL, 0 -}; - -static NameId namesG[]={ - "gacute", 0x001F5, // LATIN SMALL LETTER G WITH ACUTE - "Gamma", 0x00393, // GREEK CAPITAL LETTER GAMMA - "gamma", 0x003B3, // GREEK SMALL LETTER GAMMA - "Gammad", 0x003DC, // GREEK LETTER DIGAMMA - "gammad", 0x003DD, // GREEK SMALL LETTER DIGAMMA - "gap", 0x02A86, // GREATER-THAN OR APPROXIMATE - "Gbreve", 0x0011E, // LATIN CAPITAL LETTER G WITH BREVE - "gbreve", 0x0011F, // LATIN SMALL LETTER G WITH BREVE - "Gcedil", 0x00122, // LATIN CAPITAL LETTER G WITH CEDILLA - "Gcirc", 0x0011C, // LATIN CAPITAL LETTER G WITH CIRCUMFLEX - "gcirc", 0x0011D, // LATIN SMALL LETTER G WITH CIRCUMFLEX - "Gcy", 0x00413, // CYRILLIC CAPITAL LETTER GHE - "gcy", 0x00433, // CYRILLIC SMALL LETTER GHE - "Gdot", 0x00120, // LATIN CAPITAL LETTER G WITH DOT ABOVE - "gdot", 0x00121, // LATIN SMALL LETTER G WITH DOT ABOVE - "ge", 0x02265, // GREATER-THAN OR EQUAL TO - "gE", 0x02267, // GREATER-THAN OVER EQUAL TO - "gel", 0x022DB, // GREATER-THAN EQUAL TO OR LESS-THAN - "gEl", 0x02A8C, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN - "geq", 0x02265, // GREATER-THAN OR EQUAL TO - "geqq", 0x02267, // GREATER-THAN OVER EQUAL TO - "geqslant", 0x02A7E, // GREATER-THAN OR SLANTED EQUAL TO - "ges", 0x02A7E, // GREATER-THAN OR SLANTED EQUAL TO - "gescc", 0x02AA9, // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL - "gesdot", 0x02A80, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE - "gesdoto", 0x02A82, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE - "gesdotol", 0x02A84, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT -// "gesl", 0x022DB;0x0FE00, // GREATER-THAN slanted EQUAL TO OR LESS-THAN - "gesles", 0x02A94, // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL - "Gfr", 0x1D50A, // MATHEMATICAL FRAKTUR CAPITAL G - "gfr", 0x1D524, // MATHEMATICAL FRAKTUR SMALL G - "gg", 0x0226B, // MUCH GREATER-THAN - "Gg", 0x022D9, // VERY MUCH GREATER-THAN - "ggg", 0x022D9, // VERY MUCH GREATER-THAN - "Ggr", 0x00393, // GREEK CAPITAL LETTER GAMMA - "ggr", 0x003B3, // GREEK SMALL LETTER GAMMA - "gimel", 0x02137, // GIMEL SYMBOL - "GJcy", 0x00403, // CYRILLIC CAPITAL LETTER GJE - "gjcy", 0x00453, // CYRILLIC SMALL LETTER GJE - "gl", 0x02277, // GREATER-THAN OR LESS-THAN - "gla", 0x02AA5, // GREATER-THAN BESIDE LESS-THAN - "glE", 0x02A92, // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL - "glj", 0x02AA4, // GREATER-THAN OVERLAPPING LESS-THAN - "gnap", 0x02A8A, // GREATER-THAN AND NOT APPROXIMATE - "gnapprox", 0x02A8A, // GREATER-THAN AND NOT APPROXIMATE - "gnE", 0x02269, // GREATER-THAN BUT NOT EQUAL TO - "gne", 0x02A88, // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO - "gneq", 0x02A88, // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO - "gneqq", 0x02269, // GREATER-THAN BUT NOT EQUAL TO - "gnsim", 0x022E7, // GREATER-THAN BUT NOT EQUIVALENT TO - "Gopf", 0x1D53E, // MATHEMATICAL DOUBLE-STRUCK CAPITAL G - "gopf", 0x1D558, // MATHEMATICAL DOUBLE-STRUCK SMALL G - "grave", 0x00060, // GRAVE ACCENT - "GreaterEqual", 0x02265, // GREATER-THAN OR EQUAL TO - "GreaterEqualLess", 0x022DB, // GREATER-THAN EQUAL TO OR LESS-THAN - "GreaterFullEqual", 0x02267, // GREATER-THAN OVER EQUAL TO - "GreaterGreater", 0x02AA2, // DOUBLE NESTED GREATER-THAN - "GreaterLess", 0x02277, // GREATER-THAN OR LESS-THAN - "GreaterSlantEqual", 0x02A7E, // GREATER-THAN OR SLANTED EQUAL TO - "GreaterTilde", 0x02273, // GREATER-THAN OR EQUIVALENT TO - "gscr", 0x0210A, // SCRIPT SMALL G - "Gscr", 0x1D4A2, // MATHEMATICAL SCRIPT CAPITAL G - "gsim", 0x02273, // GREATER-THAN OR EQUIVALENT TO - "gsime", 0x02A8E, // GREATER-THAN ABOVE SIMILAR OR EQUAL - "gsiml", 0x02A90, // GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN - "gt", 0x0003E, // GREATER-THAN SIGN - "GT", 0x0003E, // GREATER-THAN SIGN - "Gt", 0x0226B, // MUCH GREATER-THAN - "gtcc", 0x02AA7, // GREATER-THAN CLOSED BY CURVE - "gtcir", 0x02A7A, // GREATER-THAN WITH CIRCLE INSIDE - "gtdot", 0x022D7, // GREATER-THAN WITH DOT - "gtlPar", 0x02995, // DOUBLE LEFT ARC GREATER-THAN BRACKET - "gtquest", 0x02A7C, // GREATER-THAN WITH QUESTION MARK ABOVE - "gtrapprox", 0x02A86, // GREATER-THAN OR APPROXIMATE - "gtrarr", 0x02978, // GREATER-THAN ABOVE RIGHTWARDS ARROW - "gtrdot", 0x022D7, // GREATER-THAN WITH DOT - "gtreqless", 0x022DB, // GREATER-THAN EQUAL TO OR LESS-THAN - "gtreqqless", 0x02A8C, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN - "gtrless", 0x02277, // GREATER-THAN OR LESS-THAN - "gtrsim", 0x02273, // GREATER-THAN OR EQUIVALENT TO -// "gvertneqq", 0x02269;0x0FE00, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke -// "gvnE", 0x02269;0x0FE00, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke - NULL, 0 -}; - -static NameId namesH[]={ - "Hacek", 0x002C7, // CARON - "hairsp", 0x0200A, // HAIR SPACE - "half", 0x000BD, // VULGAR FRACTION ONE HALF - "hamilt", 0x0210B, // SCRIPT CAPITAL H - "HARDcy", 0x0042A, // CYRILLIC CAPITAL LETTER HARD SIGN - "hardcy", 0x0044A, // CYRILLIC SMALL LETTER HARD SIGN - "harr", 0x02194, // LEFT RIGHT ARROW - "hArr", 0x021D4, // LEFT RIGHT DOUBLE ARROW - "harrcir", 0x02948, // LEFT RIGHT ARROW THROUGH SMALL CIRCLE - "harrw", 0x021AD, // LEFT RIGHT WAVE ARROW - "Hat", 0x0005E, // CIRCUMFLEX ACCENT - "hbar", 0x0210F, // PLANCK CONSTANT OVER TWO PI - "Hcirc", 0x00124, // LATIN CAPITAL LETTER H WITH CIRCUMFLEX - "hcirc", 0x00125, // LATIN SMALL LETTER H WITH CIRCUMFLEX - "hearts", 0x02665, // BLACK HEART SUIT - "heartsuit", 0x02665, // BLACK HEART SUIT - "hellip", 0x02026, // HORIZONTAL ELLIPSIS - "hercon", 0x022B9, // HERMITIAN CONJUGATE MATRIX - "Hfr", 0x0210C, // BLACK-LETTER CAPITAL H - "hfr", 0x1D525, // MATHEMATICAL FRAKTUR SMALL H - "HilbertSpace", 0x0210B, // SCRIPT CAPITAL H - "hksearow", 0x02925, // SOUTH EAST ARROW WITH HOOK - "hkswarow", 0x02926, // SOUTH WEST ARROW WITH HOOK - "hoarr", 0x021FF, // LEFT RIGHT OPEN-HEADED ARROW - "homtht", 0x0223B, // HOMOTHETIC - "hookleftarrow", 0x021A9, // LEFTWARDS ARROW WITH HOOK - "hookrightarrow", 0x021AA, // RIGHTWARDS ARROW WITH HOOK - "Hopf", 0x0210D, // DOUBLE-STRUCK CAPITAL H - "hopf", 0x1D559, // MATHEMATICAL DOUBLE-STRUCK SMALL H - "horbar", 0x02015, // HORIZONTAL BAR - "HorizontalLine", 0x02500, // BOX DRAWINGS LIGHT HORIZONTAL - "Hscr", 0x0210B, // SCRIPT CAPITAL H - "hscr", 0x1D4BD, // MATHEMATICAL SCRIPT SMALL H - "hslash", 0x0210F, // PLANCK CONSTANT OVER TWO PI - "Hstrok", 0x00126, // LATIN CAPITAL LETTER H WITH STROKE - "hstrok", 0x00127, // LATIN SMALL LETTER H WITH STROKE - "HumpDownHump", 0x0224E, // GEOMETRICALLY EQUIVALENT TO - "HumpEqual", 0x0224F, // DIFFERENCE BETWEEN - "hybull", 0x02043, // HYPHEN BULLET - "hyphen", 0x02010, // HYPHEN - NULL, 0 -}; - -static NameId namesI[]={ - "Iacgr", 0x0038A, // GREEK CAPITAL LETTER IOTA WITH TONOS - "iacgr", 0x003AF, // GREEK SMALL LETTER IOTA WITH TONOS - "Iacute", 0x000CD, // LATIN CAPITAL LETTER I WITH ACUTE - "iacute", 0x000ED, // LATIN SMALL LETTER I WITH ACUTE - "ic", 0x02063, // INVISIBLE SEPARATOR - "Icirc", 0x000CE, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX - "icirc", 0x000EE, // LATIN SMALL LETTER I WITH CIRCUMFLEX - "Icy", 0x00418, // CYRILLIC CAPITAL LETTER I - "icy", 0x00438, // CYRILLIC SMALL LETTER I - "idiagr", 0x00390, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS - "Idigr", 0x003AA, // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA - "idigr", 0x003CA, // GREEK SMALL LETTER IOTA WITH DIALYTIKA - "Idot", 0x00130, // LATIN CAPITAL LETTER I WITH DOT ABOVE - "IEcy", 0x00415, // CYRILLIC CAPITAL LETTER IE - "iecy", 0x00435, // CYRILLIC SMALL LETTER IE - "iexcl", 0x000A1, // INVERTED EXCLAMATION MARK - "iff", 0x021D4, // LEFT RIGHT DOUBLE ARROW - "Ifr", 0x02111, // BLACK-LETTER CAPITAL I - "ifr", 0x1D526, // MATHEMATICAL FRAKTUR SMALL I - "Igr", 0x00399, // GREEK CAPITAL LETTER IOTA - "igr", 0x003B9, // GREEK SMALL LETTER IOTA - "Igrave", 0x000CC, // LATIN CAPITAL LETTER I WITH GRAVE - "igrave", 0x000EC, // LATIN SMALL LETTER I WITH GRAVE - "ii", 0x02148, // DOUBLE-STRUCK ITALIC SMALL I - "iiiint", 0x02A0C, // QUADRUPLE INTEGRAL OPERATOR - "iiint", 0x0222D, // TRIPLE INTEGRAL - "iinfin", 0x029DC, // INCOMPLETE INFINITY - "iiota", 0x02129, // TURNED GREEK SMALL LETTER IOTA - "IJlig", 0x00132, // LATIN CAPITAL LIGATURE IJ - "ijlig", 0x00133, // LATIN SMALL LIGATURE IJ - "Im", 0x02111, // BLACK-LETTER CAPITAL I - "Imacr", 0x0012A, // LATIN CAPITAL LETTER I WITH MACRON - "imacr", 0x0012B, // LATIN SMALL LETTER I WITH MACRON - "image", 0x02111, // BLACK-LETTER CAPITAL I - "ImaginaryI", 0x02148, // DOUBLE-STRUCK ITALIC SMALL I - "imagline", 0x02110, // SCRIPT CAPITAL I - "imagpart", 0x02111, // BLACK-LETTER CAPITAL I - "imath", 0x00131, // LATIN SMALL LETTER DOTLESS I - "imof", 0x022B7, // IMAGE OF - "imped", 0x001B5, // LATIN CAPITAL LETTER Z WITH STROKE - "Implies", 0x021D2, // RIGHTWARDS DOUBLE ARROW - "in", 0x02208, // ELEMENT OF - "incare", 0x02105, // CARE OF - "infin", 0x0221E, // INFINITY - "infintie", 0x029DD, // TIE OVER INFINITY - "inodot", 0x00131, // LATIN SMALL LETTER DOTLESS I - "int", 0x0222B, // INTEGRAL - "Int", 0x0222C, // DOUBLE INTEGRAL - "intcal", 0x022BA, // INTERCALATE - "integers", 0x02124, // DOUBLE-STRUCK CAPITAL Z - "Integral", 0x0222B, // INTEGRAL - "intercal", 0x022BA, // INTERCALATE - "Intersection", 0x022C2, // N-ARY INTERSECTION - "intlarhk", 0x02A17, // INTEGRAL WITH LEFTWARDS ARROW WITH HOOK - "intprod", 0x02A3C, // INTERIOR PRODUCT - "InvisibleComma", 0x02063, // INVISIBLE SEPARATOR - "InvisibleTimes", 0x02062, // INVISIBLE TIMES - "IOcy", 0x00401, // CYRILLIC CAPITAL LETTER IO - "iocy", 0x00451, // CYRILLIC SMALL LETTER IO - "Iogon", 0x0012E, // LATIN CAPITAL LETTER I WITH OGONEK - "iogon", 0x0012F, // LATIN SMALL LETTER I WITH OGONEK - "Iopf", 0x1D540, // MATHEMATICAL DOUBLE-STRUCK CAPITAL I - "iopf", 0x1D55A, // MATHEMATICAL DOUBLE-STRUCK SMALL I - "Iota", 0x00399, // GREEK CAPITAL LETTER IOTA - "iota", 0x003B9, // GREEK SMALL LETTER IOTA - "iprod", 0x02A3C, // INTERIOR PRODUCT - "iquest", 0x000BF, // INVERTED QUESTION MARK - "Iscr", 0x02110, // SCRIPT CAPITAL I - "iscr", 0x1D4BE, // MATHEMATICAL SCRIPT SMALL I - "isin", 0x02208, // ELEMENT OF - "isindot", 0x022F5, // ELEMENT OF WITH DOT ABOVE - "isinE", 0x022F9, // ELEMENT OF WITH TWO HORIZONTAL STROKES - "isins", 0x022F4, // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - "isinsv", 0x022F3, // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - "isinv", 0x02208, // ELEMENT OF - "it", 0x02062, // INVISIBLE TIMES - "Itilde", 0x00128, // LATIN CAPITAL LETTER I WITH TILDE - "itilde", 0x00129, // LATIN SMALL LETTER I WITH TILDE - "Iukcy", 0x00406, // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I - "iukcy", 0x00456, // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I - "Iuml", 0x000CF, // LATIN CAPITAL LETTER I WITH DIAERESIS - "iuml", 0x000EF, // LATIN SMALL LETTER I WITH DIAERESIS - NULL, 0 -}; - -static NameId namesJ[]={ - "Jcirc", 0x00134, // LATIN CAPITAL LETTER J WITH CIRCUMFLEX - "jcirc", 0x00135, // LATIN SMALL LETTER J WITH CIRCUMFLEX - "Jcy", 0x00419, // CYRILLIC CAPITAL LETTER SHORT I - "jcy", 0x00439, // CYRILLIC SMALL LETTER SHORT I - "Jfr", 0x1D50D, // MATHEMATICAL FRAKTUR CAPITAL J - "jfr", 0x1D527, // MATHEMATICAL FRAKTUR SMALL J - "jmath", 0x00237, // LATIN SMALL LETTER DOTLESS J - "Jopf", 0x1D541, // MATHEMATICAL DOUBLE-STRUCK CAPITAL J - "jopf", 0x1D55B, // MATHEMATICAL DOUBLE-STRUCK SMALL J - "Jscr", 0x1D4A5, // MATHEMATICAL SCRIPT CAPITAL J - "jscr", 0x1D4BF, // MATHEMATICAL SCRIPT SMALL J - "Jsercy", 0x00408, // CYRILLIC CAPITAL LETTER JE - "jsercy", 0x00458, // CYRILLIC SMALL LETTER JE - "Jukcy", 0x00404, // CYRILLIC CAPITAL LETTER UKRAINIAN IE - "jukcy", 0x00454, // CYRILLIC SMALL LETTER UKRAINIAN IE - NULL, 0 -}; - -static NameId namesK[]={ - "Kappa", 0x0039A, // GREEK CAPITAL LETTER KAPPA - "kappa", 0x003BA, // GREEK SMALL LETTER KAPPA - "kappav", 0x003F0, // GREEK KAPPA SYMBOL - "Kcedil", 0x00136, // LATIN CAPITAL LETTER K WITH CEDILLA - "kcedil", 0x00137, // LATIN SMALL LETTER K WITH CEDILLA - "Kcy", 0x0041A, // CYRILLIC CAPITAL LETTER KA - "kcy", 0x0043A, // CYRILLIC SMALL LETTER KA - "Kfr", 0x1D50E, // MATHEMATICAL FRAKTUR CAPITAL K - "kfr", 0x1D528, // MATHEMATICAL FRAKTUR SMALL K - "Kgr", 0x0039A, // GREEK CAPITAL LETTER KAPPA - "kgr", 0x003BA, // GREEK SMALL LETTER KAPPA - "kgreen", 0x00138, // LATIN SMALL LETTER KRA - "KHcy", 0x00425, // CYRILLIC CAPITAL LETTER HA - "khcy", 0x00445, // CYRILLIC SMALL LETTER HA - "KHgr", 0x003A7, // GREEK CAPITAL LETTER CHI - "khgr", 0x003C7, // GREEK SMALL LETTER CHI - "KJcy", 0x0040C, // CYRILLIC CAPITAL LETTER KJE - "kjcy", 0x0045C, // CYRILLIC SMALL LETTER KJE - "Kopf", 0x1D542, // MATHEMATICAL DOUBLE-STRUCK CAPITAL K - "kopf", 0x1D55C, // MATHEMATICAL DOUBLE-STRUCK SMALL K - "Kscr", 0x1D4A6, // MATHEMATICAL SCRIPT CAPITAL K - "kscr", 0x1D4C0, // MATHEMATICAL SCRIPT SMALL K - NULL, 0 -}; - -static NameId namesL[]={ - "lAarr", 0x021DA, // LEFTWARDS TRIPLE ARROW - "Lacute", 0x00139, // LATIN CAPITAL LETTER L WITH ACUTE - "lacute", 0x0013A, // LATIN SMALL LETTER L WITH ACUTE - "laemptyv", 0x029B4, // EMPTY SET WITH LEFT ARROW ABOVE - "lagran", 0x02112, // SCRIPT CAPITAL L - "Lambda", 0x0039B, // GREEK CAPITAL LETTER LAMDA - "lambda", 0x003BB, // GREEK SMALL LETTER LAMDA - "lang", 0x027E8, // MATHEMATICAL LEFT ANGLE BRACKET - "Lang", 0x027EA, // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET - "langd", 0x02991, // LEFT ANGLE BRACKET WITH DOT - "langle", 0x027E8, // MATHEMATICAL LEFT ANGLE BRACKET - "lap", 0x02A85, // LESS-THAN OR APPROXIMATE - "Laplacetrf", 0x02112, // SCRIPT CAPITAL L - "laquo", 0x000AB, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - "larr", 0x02190, // LEFTWARDS ARROW - "Larr", 0x0219E, // LEFTWARDS TWO HEADED ARROW - "lArr", 0x021D0, // LEFTWARDS DOUBLE ARROW - "larrb", 0x021E4, // LEFTWARDS ARROW TO BAR - "larrbfs", 0x0291F, // LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND - "larrfs", 0x0291D, // LEFTWARDS ARROW TO BLACK DIAMOND - "larrhk", 0x021A9, // LEFTWARDS ARROW WITH HOOK - "larrlp", 0x021AB, // LEFTWARDS ARROW WITH LOOP - "larrpl", 0x02939, // LEFT-SIDE ARC ANTICLOCKWISE ARROW - "larrsim", 0x02973, // LEFTWARDS ARROW ABOVE TILDE OPERATOR - "larrtl", 0x021A2, // LEFTWARDS ARROW WITH TAIL - "lat", 0x02AAB, // LARGER THAN - "latail", 0x02919, // LEFTWARDS ARROW-TAIL - "lAtail", 0x0291B, // LEFTWARDS DOUBLE ARROW-TAIL - "late", 0x02AAD, // LARGER THAN OR EQUAL TO -// "lates", 0x02AAD;0x0FE00, // LARGER THAN OR slanted EQUAL - "lbarr", 0x0290C, // LEFTWARDS DOUBLE DASH ARROW - "lBarr", 0x0290E, // LEFTWARDS TRIPLE DASH ARROW - "lbbrk", 0x02772, // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT - "lbrace", 0x0007B, // LEFT CURLY BRACKET - "lbrack", 0x0005B, // LEFT SQUARE BRACKET - "lbrke", 0x0298B, // LEFT SQUARE BRACKET WITH UNDERBAR - "lbrksld", 0x0298F, // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER - "lbrkslu", 0x0298D, // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER - "Lcaron", 0x0013D, // LATIN CAPITAL LETTER L WITH CARON - "lcaron", 0x0013E, // LATIN SMALL LETTER L WITH CARON - "Lcedil", 0x0013B, // LATIN CAPITAL LETTER L WITH CEDILLA - "lcedil", 0x0013C, // LATIN SMALL LETTER L WITH CEDILLA - "lceil", 0x02308, // LEFT CEILING - "lcub", 0x0007B, // LEFT CURLY BRACKET - "Lcy", 0x0041B, // CYRILLIC CAPITAL LETTER EL - "lcy", 0x0043B, // CYRILLIC SMALL LETTER EL - "ldca", 0x02936, // ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS - "ldquo", 0x0201C, // LEFT DOUBLE QUOTATION MARK - "ldquor", 0x0201E, // DOUBLE LOW-9 QUOTATION MARK - "ldrdhar", 0x02967, // LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN - "ldrushar", 0x0294B, // LEFT BARB DOWN RIGHT BARB UP HARPOON - "ldsh", 0x021B2, // DOWNWARDS ARROW WITH TIP LEFTWARDS - "le", 0x02264, // LESS-THAN OR EQUAL TO - "lE", 0x02266, // LESS-THAN OVER EQUAL TO - "LeftAngleBracket", 0x027E8, // MATHEMATICAL LEFT ANGLE BRACKET - "leftarrow", 0x02190, // LEFTWARDS ARROW - "LeftArrow", 0x02190, // LEFTWARDS ARROW - "Leftarrow", 0x021D0, // LEFTWARDS DOUBLE ARROW - "LeftArrowBar", 0x021E4, // LEFTWARDS ARROW TO BAR - "LeftArrowRightArrow", 0x021C6, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - "leftarrowtail", 0x021A2, // LEFTWARDS ARROW WITH TAIL - "LeftCeiling", 0x02308, // LEFT CEILING - "LeftDoubleBracket", 0x027E6, // MATHEMATICAL LEFT WHITE SQUARE BRACKET - "LeftDownTeeVector", 0x02961, // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR - "LeftDownVector", 0x021C3, // DOWNWARDS HARPOON WITH BARB LEFTWARDS - "LeftDownVectorBar", 0x02959, // DOWNWARDS HARPOON WITH BARB LEFT TO BAR - "LeftFloor", 0x0230A, // LEFT FLOOR - "leftharpoondown", 0x021BD, // LEFTWARDS HARPOON WITH BARB DOWNWARDS - "leftharpoonup", 0x021BC, // LEFTWARDS HARPOON WITH BARB UPWARDS - "leftleftarrows", 0x021C7, // LEFTWARDS PAIRED ARROWS - "leftrightarrow", 0x02194, // LEFT RIGHT ARROW - "LeftRightArrow", 0x02194, // LEFT RIGHT ARROW - "Leftrightarrow", 0x021D4, // LEFT RIGHT DOUBLE ARROW - "leftrightarrows", 0x021C6, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - "leftrightharpoons", 0x021CB, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - "leftrightsquigarrow", 0x021AD, // LEFT RIGHT WAVE ARROW - "LeftRightVector", 0x0294E, // LEFT BARB UP RIGHT BARB UP HARPOON - "LeftTee", 0x022A3, // LEFT TACK - "LeftTeeArrow", 0x021A4, // LEFTWARDS ARROW FROM BAR - "LeftTeeVector", 0x0295A, // LEFTWARDS HARPOON WITH BARB UP FROM BAR - "leftthreetimes", 0x022CB, // LEFT SEMIDIRECT PRODUCT - "LeftTriangle", 0x022B2, // NORMAL SUBGROUP OF - "LeftTriangleBar", 0x029CF, // LEFT TRIANGLE BESIDE VERTICAL BAR - "LeftTriangleEqual", 0x022B4, // NORMAL SUBGROUP OF OR EQUAL TO - "LeftUpDownVector", 0x02951, // UP BARB LEFT DOWN BARB LEFT HARPOON - "LeftUpTeeVector", 0x02960, // UPWARDS HARPOON WITH BARB LEFT FROM BAR - "LeftUpVector", 0x021BF, // UPWARDS HARPOON WITH BARB LEFTWARDS - "LeftUpVectorBar", 0x02958, // UPWARDS HARPOON WITH BARB LEFT TO BAR - "LeftVector", 0x021BC, // LEFTWARDS HARPOON WITH BARB UPWARDS - "LeftVectorBar", 0x02952, // LEFTWARDS HARPOON WITH BARB UP TO BAR - "leg", 0x022DA, // LESS-THAN EQUAL TO OR GREATER-THAN - "lEg", 0x02A8B, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN - "leq", 0x02264, // LESS-THAN OR EQUAL TO - "leqq", 0x02266, // LESS-THAN OVER EQUAL TO - "leqslant", 0x02A7D, // LESS-THAN OR SLANTED EQUAL TO - "les", 0x02A7D, // LESS-THAN OR SLANTED EQUAL TO - "lescc", 0x02AA8, // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL - "lesdot", 0x02A7F, // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE - "lesdoto", 0x02A81, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE - "lesdotor", 0x02A83, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT -// "lesg", 0x022DA;0x0FE00, // LESS-THAN slanted EQUAL TO OR GREATER-THAN - "lesges", 0x02A93, // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL - "lessapprox", 0x02A85, // LESS-THAN OR APPROXIMATE - "lessdot", 0x022D6, // LESS-THAN WITH DOT - "lesseqgtr", 0x022DA, // LESS-THAN EQUAL TO OR GREATER-THAN - "lesseqqgtr", 0x02A8B, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN - "LessEqualGreater", 0x022DA, // LESS-THAN EQUAL TO OR GREATER-THAN - "LessFullEqual", 0x02266, // LESS-THAN OVER EQUAL TO - "LessGreater", 0x02276, // LESS-THAN OR GREATER-THAN - "lessgtr", 0x02276, // LESS-THAN OR GREATER-THAN - "LessLess", 0x02AA1, // DOUBLE NESTED LESS-THAN - "lesssim", 0x02272, // LESS-THAN OR EQUIVALENT TO - "LessSlantEqual", 0x02A7D, // LESS-THAN OR SLANTED EQUAL TO - "LessTilde", 0x02272, // LESS-THAN OR EQUIVALENT TO - "lfisht", 0x0297C, // LEFT FISH TAIL - "lfloor", 0x0230A, // LEFT FLOOR - "Lfr", 0x1D50F, // MATHEMATICAL FRAKTUR CAPITAL L - "lfr", 0x1D529, // MATHEMATICAL FRAKTUR SMALL L - "lg", 0x02276, // LESS-THAN OR GREATER-THAN - "lgE", 0x02A91, // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL - "Lgr", 0x0039B, // GREEK CAPITAL LETTER LAMDA - "lgr", 0x003BB, // GREEK SMALL LETTER LAMDA - "lHar", 0x02962, // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN - "lhard", 0x021BD, // LEFTWARDS HARPOON WITH BARB DOWNWARDS - "lharu", 0x021BC, // LEFTWARDS HARPOON WITH BARB UPWARDS - "lharul", 0x0296A, // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH - "lhblk", 0x02584, // LOWER HALF BLOCK - "LJcy", 0x00409, // CYRILLIC CAPITAL LETTER LJE - "ljcy", 0x00459, // CYRILLIC SMALL LETTER LJE - "ll", 0x0226A, // MUCH LESS-THAN - "Ll", 0x022D8, // VERY MUCH LESS-THAN - "llarr", 0x021C7, // LEFTWARDS PAIRED ARROWS - "llcorner", 0x0231E, // BOTTOM LEFT CORNER - "Lleftarrow", 0x021DA, // LEFTWARDS TRIPLE ARROW - "llhard", 0x0296B, // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH - "lltri", 0x025FA, // LOWER LEFT TRIANGLE - "Lmidot", 0x0013F, // LATIN CAPITAL LETTER L WITH MIDDLE DOT - "lmidot", 0x00140, // LATIN SMALL LETTER L WITH MIDDLE DOT - "lmoust", 0x023B0, // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION - "lmoustache", 0x023B0, // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION - "lnap", 0x02A89, // LESS-THAN AND NOT APPROXIMATE - "lnapprox", 0x02A89, // LESS-THAN AND NOT APPROXIMATE - "lnE", 0x02268, // LESS-THAN BUT NOT EQUAL TO - "lne", 0x02A87, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO - "lneq", 0x02A87, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO - "lneqq", 0x02268, // LESS-THAN BUT NOT EQUAL TO - "lnsim", 0x022E6, // LESS-THAN BUT NOT EQUIVALENT TO - "loang", 0x027EC, // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET - "loarr", 0x021FD, // LEFTWARDS OPEN-HEADED ARROW - "lobrk", 0x027E6, // MATHEMATICAL LEFT WHITE SQUARE BRACKET - "longleftarrow", 0x027F5, // LONG LEFTWARDS ARROW - "LongLeftArrow", 0x027F5, // LONG LEFTWARDS ARROW - "Longleftarrow", 0x027F8, // LONG LEFTWARDS DOUBLE ARROW - "longleftrightarrow", 0x027F7, // LONG LEFT RIGHT ARROW - "LongLeftRightArrow", 0x027F7, // LONG LEFT RIGHT ARROW - "Longleftrightarrow", 0x027FA, // LONG LEFT RIGHT DOUBLE ARROW - "longmapsto", 0x027FC, // LONG RIGHTWARDS ARROW FROM BAR - "longrightarrow", 0x027F6, // LONG RIGHTWARDS ARROW - "LongRightArrow", 0x027F6, // LONG RIGHTWARDS ARROW - "Longrightarrow", 0x027F9, // LONG RIGHTWARDS DOUBLE ARROW - "looparrowleft", 0x021AB, // LEFTWARDS ARROW WITH LOOP - "looparrowright", 0x021AC, // RIGHTWARDS ARROW WITH LOOP - "lopar", 0x02985, // LEFT WHITE PARENTHESIS - "Lopf", 0x1D543, // MATHEMATICAL DOUBLE-STRUCK CAPITAL L - "lopf", 0x1D55D, // MATHEMATICAL DOUBLE-STRUCK SMALL L - "loplus", 0x02A2D, // PLUS SIGN IN LEFT HALF CIRCLE - "lotimes", 0x02A34, // MULTIPLICATION SIGN IN LEFT HALF CIRCLE - "lowast", 0x02217, // ASTERISK OPERATOR - "lowbar", 0x0005F, // LOW LINE - "LowerLeftArrow", 0x02199, // SOUTH WEST ARROW - "LowerRightArrow", 0x02198, // SOUTH EAST ARROW - "loz", 0x025CA, // LOZENGE - "lozenge", 0x025CA, // LOZENGE - "lozf", 0x029EB, // BLACK LOZENGE - "lpar", 0x00028, // LEFT PARENTHESIS - "lparlt", 0x02993, // LEFT ARC LESS-THAN BRACKET - "lrarr", 0x021C6, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - "lrcorner", 0x0231F, // BOTTOM RIGHT CORNER - "lrhar", 0x021CB, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - "lrhard", 0x0296D, // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH - "lrm", 0x0200E, // LEFT-TO-RIGHT MARK - "lrtri", 0x022BF, // RIGHT TRIANGLE - "lsaquo", 0x02039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK - "Lscr", 0x02112, // SCRIPT CAPITAL L - "lscr", 0x1D4C1, // MATHEMATICAL SCRIPT SMALL L - "lsh", 0x021B0, // UPWARDS ARROW WITH TIP LEFTWARDS - "Lsh", 0x021B0, // UPWARDS ARROW WITH TIP LEFTWARDS - "lsim", 0x02272, // LESS-THAN OR EQUIVALENT TO - "lsime", 0x02A8D, // LESS-THAN ABOVE SIMILAR OR EQUAL - "lsimg", 0x02A8F, // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN - "lsqb", 0x0005B, // LEFT SQUARE BRACKET - "lsquo", 0x02018, // LEFT SINGLE QUOTATION MARK - "lsquor", 0x0201A, // SINGLE LOW-9 QUOTATION MARK - "Lstrok", 0x00141, // LATIN CAPITAL LETTER L WITH STROKE - "lstrok", 0x00142, // LATIN SMALL LETTER L WITH STROKE - "lt", 0x0003C, // LESS-THAN SIGN - "LT", 0x0003C, // LESS-THAN SIGN - "Lt", 0x0226A, // MUCH LESS-THAN - "ltcc", 0x02AA6, // LESS-THAN CLOSED BY CURVE - "ltcir", 0x02A79, // LESS-THAN WITH CIRCLE INSIDE - "ltdot", 0x022D6, // LESS-THAN WITH DOT - "lthree", 0x022CB, // LEFT SEMIDIRECT PRODUCT - "ltimes", 0x022C9, // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT - "ltlarr", 0x02976, // LESS-THAN ABOVE LEFTWARDS ARROW - "ltquest", 0x02A7B, // LESS-THAN WITH QUESTION MARK ABOVE - "ltri", 0x025C3, // WHITE LEFT-POINTING SMALL TRIANGLE - "ltrie", 0x022B4, // NORMAL SUBGROUP OF OR EQUAL TO - "ltrif", 0x025C2, // BLACK LEFT-POINTING SMALL TRIANGLE - "ltrPar", 0x02996, // DOUBLE RIGHT ARC LESS-THAN BRACKET - "lurdshar", 0x0294A, // LEFT BARB UP RIGHT BARB DOWN HARPOON - "luruhar", 0x02966, // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP -// "lvertneqq", 0x02268;0x0FE00, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke -// "lvnE", 0x02268;0x0FE00, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke - NULL, 0 -}; - -static NameId namesM[]={ - "macr", 0x000AF, // MACRON - "male", 0x02642, // MALE SIGN - "malt", 0x02720, // MALTESE CROSS - "maltese", 0x02720, // MALTESE CROSS - "map", 0x021A6, // RIGHTWARDS ARROW FROM BAR - "Map", 0x02905, // RIGHTWARDS TWO-HEADED ARROW FROM BAR - "mapsto", 0x021A6, // RIGHTWARDS ARROW FROM BAR - "mapstodown", 0x021A7, // DOWNWARDS ARROW FROM BAR - "mapstoleft", 0x021A4, // LEFTWARDS ARROW FROM BAR - "mapstoup", 0x021A5, // UPWARDS ARROW FROM BAR - "marker", 0x025AE, // BLACK VERTICAL RECTANGLE - "mcomma", 0x02A29, // MINUS SIGN WITH COMMA ABOVE - "Mcy", 0x0041C, // CYRILLIC CAPITAL LETTER EM - "mcy", 0x0043C, // CYRILLIC SMALL LETTER EM - "mdash", 0x02014, // EM DASH - "mDDot", 0x0223A, // GEOMETRIC PROPORTION - "measuredangle", 0x02221, // MEASURED ANGLE - "MediumSpace", 0x0205F, // MEDIUM MATHEMATICAL SPACE - "Mellintrf", 0x02133, // SCRIPT CAPITAL M - "Mfr", 0x1D510, // MATHEMATICAL FRAKTUR CAPITAL M - "mfr", 0x1D52A, // MATHEMATICAL FRAKTUR SMALL M - "Mgr", 0x0039C, // GREEK CAPITAL LETTER MU - "mgr", 0x003BC, // GREEK SMALL LETTER MU - "mho", 0x02127, // INVERTED OHM SIGN - "micro", 0x000B5, // MICRO SIGN - "mid", 0x02223, // DIVIDES - "midast", 0x0002A, // ASTERISK - "midcir", 0x02AF0, // VERTICAL LINE WITH CIRCLE BELOW - "middot", 0x000B7, // MIDDLE DOT - "minus", 0x02212, // MINUS SIGN - "minusb", 0x0229F, // SQUARED MINUS - "minusd", 0x02238, // DOT MINUS - "minusdu", 0x02A2A, // MINUS SIGN WITH DOT BELOW - "MinusPlus", 0x02213, // MINUS-OR-PLUS SIGN - "mlcp", 0x02ADB, // TRANSVERSAL INTERSECTION - "mldr", 0x02026, // HORIZONTAL ELLIPSIS - "mnplus", 0x02213, // MINUS-OR-PLUS SIGN - "models", 0x022A7, // MODELS - "Mopf", 0x1D544, // MATHEMATICAL DOUBLE-STRUCK CAPITAL M - "mopf", 0x1D55E, // MATHEMATICAL DOUBLE-STRUCK SMALL M - "mp", 0x02213, // MINUS-OR-PLUS SIGN - "Mscr", 0x02133, // SCRIPT CAPITAL M - "mscr", 0x1D4C2, // MATHEMATICAL SCRIPT SMALL M - "mstpos", 0x0223E, // INVERTED LAZY S - "Mu", 0x0039C, // GREEK CAPITAL LETTER MU - "mu", 0x003BC, // GREEK SMALL LETTER MU - "multimap", 0x022B8, // MULTIMAP - "mumap", 0x022B8, // MULTIMAP - NULL, 0 -}; - -static NameId namesN[]={ - "nabla", 0x02207, // NABLA - "Nacute", 0x00143, // LATIN CAPITAL LETTER N WITH ACUTE - "nacute", 0x00144, // LATIN SMALL LETTER N WITH ACUTE -// "nang", 0x02220;0x020D2, // ANGLE with vertical line - "nap", 0x02249, // NOT ALMOST EQUAL TO -// "napE", 0x02A70;0x00338, // APPROXIMATELY EQUAL OR EQUAL TO with slash -// "napid", 0x0224B;0x00338, // TRIPLE TILDE with slash - "napos", 0x00149, // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE - "napprox", 0x02249, // NOT ALMOST EQUAL TO - "natur", 0x0266E, // MUSIC NATURAL SIGN - "natural", 0x0266E, // MUSIC NATURAL SIGN - "naturals", 0x02115, // DOUBLE-STRUCK CAPITAL N - "nbsp", 0x000A0, // NO-BREAK SPACE -// "nbump", 0x0224E;0x00338, // GEOMETRICALLY EQUIVALENT TO with slash -// "nbumpe", 0x0224F;0x00338, // DIFFERENCE BETWEEN with slash - "ncap", 0x02A43, // INTERSECTION WITH OVERBAR - "Ncaron", 0x00147, // LATIN CAPITAL LETTER N WITH CARON - "ncaron", 0x00148, // LATIN SMALL LETTER N WITH CARON - "Ncedil", 0x00145, // LATIN CAPITAL LETTER N WITH CEDILLA - "ncedil", 0x00146, // LATIN SMALL LETTER N WITH CEDILLA - "ncong", 0x02247, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO -// "ncongdot", 0x02A6D;0x00338, // CONGRUENT WITH DOT ABOVE with slash - "ncup", 0x02A42, // UNION WITH OVERBAR - "Ncy", 0x0041D, // CYRILLIC CAPITAL LETTER EN - "ncy", 0x0043D, // CYRILLIC SMALL LETTER EN - "ndash", 0x02013, // EN DASH - "ne", 0x02260, // NOT EQUAL TO - "nearhk", 0x02924, // NORTH EAST ARROW WITH HOOK - "nearr", 0x02197, // NORTH EAST ARROW - "neArr", 0x021D7, // NORTH EAST DOUBLE ARROW - "nearrow", 0x02197, // NORTH EAST ARROW -// "nedot", 0x02250;0x00338, // APPROACHES THE LIMIT with slash - "NegativeMediumSpace", 0x0200B, // ZERO WIDTH SPACE - "NegativeThickSpace", 0x0200B, // ZERO WIDTH SPACE - "NegativeThinSpace", 0x0200B, // ZERO WIDTH SPACE - "NegativeVeryThinSpace", 0x0200B, // ZERO WIDTH SPACE - "nequiv", 0x02262, // NOT IDENTICAL TO - "nesear", 0x02928, // NORTH EAST ARROW AND SOUTH EAST ARROW -// "nesim", 0x02242;0x00338, // MINUS TILDE with slash - "NestedGreaterGreater", 0x0226B, // MUCH GREATER-THAN - "NestedLessLess", 0x0226A, // MUCH LESS-THAN - "NewLine", 0x0000A, // LINE FEED (LF) - "nexist", 0x02204, // THERE DOES NOT EXIST - "nexists", 0x02204, // THERE DOES NOT EXIST - "Nfr", 0x1D511, // MATHEMATICAL FRAKTUR CAPITAL N - "nfr", 0x1D52B, // MATHEMATICAL FRAKTUR SMALL N -// "ngE", 0x02267;0x00338, // GREATER-THAN OVER EQUAL TO with slash - "nge", 0x02271, // NEITHER GREATER-THAN NOR EQUAL TO - "ngeq", 0x02271, // NEITHER GREATER-THAN NOR EQUAL TO -// "ngeqq", 0x02267;0x00338, // GREATER-THAN OVER EQUAL TO with slash -// "ngeqslant", 0x02A7E;0x00338, // GREATER-THAN OR SLANTED EQUAL TO with slash -// "nges", 0x02A7E;0x00338, // GREATER-THAN OR SLANTED EQUAL TO with slash -// "nGg", 0x022D9;0x00338, // VERY MUCH GREATER-THAN with slash - "Ngr", 0x0039D, // GREEK CAPITAL LETTER NU - "ngr", 0x003BD, // GREEK SMALL LETTER NU - "ngsim", 0x02275, // NEITHER GREATER-THAN NOR EQUIVALENT TO -// "nGt", 0x0226B;0x020D2, // MUCH GREATER THAN with vertical line - "ngt", 0x0226F, // NOT GREATER-THAN - "ngtr", 0x0226F, // NOT GREATER-THAN -// "nGtv", 0x0226B;0x00338, // MUCH GREATER THAN with slash - "nharr", 0x021AE, // LEFT RIGHT ARROW WITH STROKE - "nhArr", 0x021CE, // LEFT RIGHT DOUBLE ARROW WITH STROKE - "nhpar", 0x02AF2, // PARALLEL WITH HORIZONTAL STROKE - "ni", 0x0220B, // CONTAINS AS MEMBER - "nis", 0x022FC, // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - "nisd", 0x022FA, // CONTAINS WITH LONG HORIZONTAL STROKE - "niv", 0x0220B, // CONTAINS AS MEMBER - "NJcy", 0x0040A, // CYRILLIC CAPITAL LETTER NJE - "njcy", 0x0045A, // CYRILLIC SMALL LETTER NJE - "nlarr", 0x0219A, // LEFTWARDS ARROW WITH STROKE - "nlArr", 0x021CD, // LEFTWARDS DOUBLE ARROW WITH STROKE - "nldr", 0x02025, // TWO DOT LEADER -// "nlE", 0x02266;0x00338, // LESS-THAN OVER EQUAL TO with slash - "nle", 0x02270, // NEITHER LESS-THAN NOR EQUAL TO - "nleftarrow", 0x0219A, // LEFTWARDS ARROW WITH STROKE - "nLeftarrow", 0x021CD, // LEFTWARDS DOUBLE ARROW WITH STROKE - "nleftrightarrow", 0x021AE, // LEFT RIGHT ARROW WITH STROKE - "nLeftrightarrow", 0x021CE, // LEFT RIGHT DOUBLE ARROW WITH STROKE - "nleq", 0x02270, // NEITHER LESS-THAN NOR EQUAL TO -// "nleqq", 0x02266;0x00338, // LESS-THAN OVER EQUAL TO with slash -// "nleqslant", 0x02A7D;0x00338, // LESS-THAN OR SLANTED EQUAL TO with slash -// "nles", 0x02A7D;0x00338, // LESS-THAN OR SLANTED EQUAL TO with slash - "nless", 0x0226E, // NOT LESS-THAN -// "nLl", 0x022D8;0x00338, // VERY MUCH LESS-THAN with slash - "nlsim", 0x02274, // NEITHER LESS-THAN NOR EQUIVALENT TO -// "nLt", 0x0226A;0x020D2, // MUCH LESS THAN with vertical line - "nlt", 0x0226E, // NOT LESS-THAN - "nltri", 0x022EA, // NOT NORMAL SUBGROUP OF - "nltrie", 0x022EC, // NOT NORMAL SUBGROUP OF OR EQUAL TO -// "nLtv", 0x0226A;0x00338, // MUCH LESS THAN with slash - "nmid", 0x02224, // DOES NOT DIVIDE - "NoBreak", 0x02060, // WORD JOINER - "NonBreakingSpace", 0x000A0, // NO-BREAK SPACE - "Nopf", 0x02115, // DOUBLE-STRUCK CAPITAL N - "nopf", 0x1D55F, // MATHEMATICAL DOUBLE-STRUCK SMALL N - "not", 0x000AC, // NOT SIGN - "Not", 0x02AEC, // DOUBLE STROKE NOT SIGN - "NotCongruent", 0x02262, // NOT IDENTICAL TO - "NotCupCap", 0x0226D, // NOT EQUIVALENT TO - "NotDoubleVerticalBar", 0x02226, // NOT PARALLEL TO - "NotElement", 0x02209, // NOT AN ELEMENT OF - "NotEqual", 0x02260, // NOT EQUAL TO -// "NotEqualTilde", 0x02242;0x00338, // MINUS TILDE with slash - "NotExists", 0x02204, // THERE DOES NOT EXIST - "NotGreater", 0x0226F, // NOT GREATER-THAN - "NotGreaterEqual", 0x02271, // NEITHER GREATER-THAN NOR EQUAL TO -// "NotGreaterFullEqual", 0x02267;0x00338, // GREATER-THAN OVER EQUAL TO with slash -// "NotGreaterGreater", 0x0226B;0x00338, // MUCH GREATER THAN with slash - "NotGreaterLess", 0x02279, // NEITHER GREATER-THAN NOR LESS-THAN -// "NotGreaterSlantEqual", 0x02A7E;0x00338, // GREATER-THAN OR SLANTED EQUAL TO with slash - "NotGreaterTilde", 0x02275, // NEITHER GREATER-THAN NOR EQUIVALENT TO -// "NotHumpDownHump", 0x0224E;0x00338, // GEOMETRICALLY EQUIVALENT TO with slash -// "NotHumpEqual", 0x0224F;0x00338, // DIFFERENCE BETWEEN with slash - "notin", 0x02209, // NOT AN ELEMENT OF -// "notindot", 0x022F5;0x00338, // ELEMENT OF WITH DOT ABOVE with slash -// "notinE", 0x022F9;0x00338, // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash - "notinva", 0x02209, // NOT AN ELEMENT OF - "notinvb", 0x022F7, // SMALL ELEMENT OF WITH OVERBAR - "notinvc", 0x022F6, // ELEMENT OF WITH OVERBAR - "NotLeftTriangle", 0x022EA, // NOT NORMAL SUBGROUP OF -// "NotLeftTriangleBar", 0x029CF;0x00338, // LEFT TRIANGLE BESIDE VERTICAL BAR with slash - "NotLeftTriangleEqual", 0x022EC, // NOT NORMAL SUBGROUP OF OR EQUAL TO - "NotLess", 0x0226E, // NOT LESS-THAN - "NotLessEqual", 0x02270, // NEITHER LESS-THAN NOR EQUAL TO - "NotLessGreater", 0x02278, // NEITHER LESS-THAN NOR GREATER-THAN -// "NotLessLess", 0x0226A;0x00338, // MUCH LESS THAN with slash -// "NotLessSlantEqual", 0x02A7D;0x00338, // LESS-THAN OR SLANTED EQUAL TO with slash - "NotLessTilde", 0x02274, // NEITHER LESS-THAN NOR EQUIVALENT TO -// "NotNestedGreaterGreater", 0x02AA2;0x00338, // DOUBLE NESTED GREATER-THAN with slash -// "NotNestedLessLess", 0x02AA1;0x00338, // DOUBLE NESTED LESS-THAN with slash - "notni", 0x0220C, // DOES NOT CONTAIN AS MEMBER - "notniva", 0x0220C, // DOES NOT CONTAIN AS MEMBER - "notnivb", 0x022FE, // SMALL CONTAINS WITH OVERBAR - "notnivc", 0x022FD, // CONTAINS WITH OVERBAR - "NotPrecedes", 0x02280, // DOES NOT PRECEDE -// "NotPrecedesEqual", 0x02AAF;0x00338, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash - "NotPrecedesSlantEqual", 0x022E0, // DOES NOT PRECEDE OR EQUAL - "NotReverseElement", 0x0220C, // DOES NOT CONTAIN AS MEMBER - "NotRightTriangle", 0x022EB, // DOES NOT CONTAIN AS NORMAL SUBGROUP -// "NotRightTriangleBar", 0x029D0;0x00338, // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash - "NotRightTriangleEqual", 0x022ED, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL -// "NotSquareSubset", 0x0228F;0x00338, // SQUARE IMAGE OF with slash - "NotSquareSubsetEqual", 0x022E2, // NOT SQUARE IMAGE OF OR EQUAL TO -// "NotSquareSuperset", 0x02290;0x00338, // SQUARE ORIGINAL OF with slash - "NotSquareSupersetEqual", 0x022E3, // NOT SQUARE ORIGINAL OF OR EQUAL TO -// "NotSubset", 0x02282;0x020D2, // SUBSET OF with vertical line - "NotSubsetEqual", 0x02288, // NEITHER A SUBSET OF NOR EQUAL TO - "NotSucceeds", 0x02281, // DOES NOT SUCCEED -// "NotSucceedsEqual", 0x02AB0;0x00338, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash - "NotSucceedsSlantEqual", 0x022E1, // DOES NOT SUCCEED OR EQUAL -// "NotSucceedsTilde", 0x0227F;0x00338, // SUCCEEDS OR EQUIVALENT TO with slash -// "NotSuperset", 0x02283;0x020D2, // SUPERSET OF with vertical line - "NotSupersetEqual", 0x02289, // NEITHER A SUPERSET OF NOR EQUAL TO - "NotTilde", 0x02241, // NOT TILDE - "NotTildeEqual", 0x02244, // NOT ASYMPTOTICALLY EQUAL TO - "NotTildeFullEqual", 0x02247, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO - "NotTildeTilde", 0x02249, // NOT ALMOST EQUAL TO - "NotVerticalBar", 0x02224, // DOES NOT DIVIDE - "npar", 0x02226, // NOT PARALLEL TO - "nparallel", 0x02226, // NOT PARALLEL TO -// "nparsl", 0x02AFD;0x020E5, // DOUBLE SOLIDUS OPERATOR with reverse slash -// "npart", 0x02202;0x00338, // PARTIAL DIFFERENTIAL with slash - "npolint", 0x02A14, // LINE INTEGRATION NOT INCLUDING THE POLE - "npr", 0x02280, // DOES NOT PRECEDE - "nprcue", 0x022E0, // DOES NOT PRECEDE OR EQUAL -// "npre", 0x02AAF;0x00338, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash - "nprec", 0x02280, // DOES NOT PRECEDE -// "npreceq", 0x02AAF;0x00338, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash - "nrarr", 0x0219B, // RIGHTWARDS ARROW WITH STROKE - "nrArr", 0x021CF, // RIGHTWARDS DOUBLE ARROW WITH STROKE -// "nrarrc", 0x02933;0x00338, // WAVE ARROW POINTING DIRECTLY RIGHT with slash -// "nrarrw", 0x0219D;0x00338, // RIGHTWARDS WAVE ARROW with slash - "nrightarrow", 0x0219B, // RIGHTWARDS ARROW WITH STROKE - "nRightarrow", 0x021CF, // RIGHTWARDS DOUBLE ARROW WITH STROKE - "nrtri", 0x022EB, // DOES NOT CONTAIN AS NORMAL SUBGROUP - "nrtrie", 0x022ED, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL - "nsc", 0x02281, // DOES NOT SUCCEED - "nsccue", 0x022E1, // DOES NOT SUCCEED OR EQUAL -// "nsce", 0x02AB0;0x00338, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash - "Nscr", 0x1D4A9, // MATHEMATICAL SCRIPT CAPITAL N - "nscr", 0x1D4C3, // MATHEMATICAL SCRIPT SMALL N - "nshortmid", 0x02224, // DOES NOT DIVIDE - "nshortparallel", 0x02226, // NOT PARALLEL TO - "nsim", 0x02241, // NOT TILDE - "nsime", 0x02244, // NOT ASYMPTOTICALLY EQUAL TO - "nsimeq", 0x02244, // NOT ASYMPTOTICALLY EQUAL TO - "nsmid", 0x02224, // DOES NOT DIVIDE - "nspar", 0x02226, // NOT PARALLEL TO - "nsqsube", 0x022E2, // NOT SQUARE IMAGE OF OR EQUAL TO - "nsqsupe", 0x022E3, // NOT SQUARE ORIGINAL OF OR EQUAL TO - "nsub", 0x02284, // NOT A SUBSET OF - "nsube", 0x02288, // NEITHER A SUBSET OF NOR EQUAL TO -// "nsubE", 0x02AC5;0x00338, // SUBSET OF ABOVE EQUALS SIGN with slash -// "nsubset", 0x02282;0x020D2, // SUBSET OF with vertical line - "nsubseteq", 0x02288, // NEITHER A SUBSET OF NOR EQUAL TO -// "nsubseteqq", 0x02AC5;0x00338, // SUBSET OF ABOVE EQUALS SIGN with slash - "nsucc", 0x02281, // DOES NOT SUCCEED -// "nsucceq", 0x02AB0;0x00338, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash - "nsup", 0x02285, // NOT A SUPERSET OF - "nsupe", 0x02289, // NEITHER A SUPERSET OF NOR EQUAL TO -// "nsupE", 0x02AC6;0x00338, // SUPERSET OF ABOVE EQUALS SIGN with slash -// "nsupset", 0x02283;0x020D2, // SUPERSET OF with vertical line - "nsupseteq", 0x02289, // NEITHER A SUPERSET OF NOR EQUAL TO -// "nsupseteqq", 0x02AC6;0x00338, // SUPERSET OF ABOVE EQUALS SIGN with slash - "ntgl", 0x02279, // NEITHER GREATER-THAN NOR LESS-THAN - "Ntilde", 0x000D1, // LATIN CAPITAL LETTER N WITH TILDE - "ntilde", 0x000F1, // LATIN SMALL LETTER N WITH TILDE - "ntlg", 0x02278, // NEITHER LESS-THAN NOR GREATER-THAN - "ntriangleleft", 0x022EA, // NOT NORMAL SUBGROUP OF - "ntrianglelefteq", 0x022EC, // NOT NORMAL SUBGROUP OF OR EQUAL TO - "ntriangleright", 0x022EB, // DOES NOT CONTAIN AS NORMAL SUBGROUP - "ntrianglerighteq", 0x022ED, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL - "Nu", 0x0039D, // GREEK CAPITAL LETTER NU - "nu", 0x003BD, // GREEK SMALL LETTER NU - "num", 0x00023, // NUMBER SIGN - "numero", 0x02116, // NUMERO SIGN - "numsp", 0x02007, // FIGURE SPACE -// "nvap", 0x0224D;0x020D2, // EQUIVALENT TO with vertical line - "nvdash", 0x022AC, // DOES NOT PROVE - "nvDash", 0x022AD, // NOT TRUE - "nVdash", 0x022AE, // DOES NOT FORCE - "nVDash", 0x022AF, // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE -// "nvge", 0x02265;0x020D2, // GREATER-THAN OR EQUAL TO with vertical line -// "nvgt", 0x0003E;0x020D2, // GREATER-THAN SIGN with vertical line - "nvHarr", 0x02904, // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE - "nvinfin", 0x029DE, // INFINITY NEGATED WITH VERTICAL BAR - "nvlArr", 0x02902, // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE -// "nvle", 0x02264;0x020D2, // LESS-THAN OR EQUAL TO with vertical line -// "nvlt", 0x0003C;0x020D2, // LESS-THAN SIGN with vertical line -// "nvltrie", 0x022B4;0x020D2, // NORMAL SUBGROUP OF OR EQUAL TO with vertical line - "nvrArr", 0x02903, // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE -// "nvrtrie", 0x022B5;0x020D2, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line -// "nvsim", 0x0223C;0x020D2, // TILDE OPERATOR with vertical line - "nwarhk", 0x02923, // NORTH WEST ARROW WITH HOOK - "nwarr", 0x02196, // NORTH WEST ARROW - "nwArr", 0x021D6, // NORTH WEST DOUBLE ARROW - "nwarrow", 0x02196, // NORTH WEST ARROW - "nwnear", 0x02927, // NORTH WEST ARROW AND NORTH EAST ARROW - NULL, 0 -}; - -static NameId namesO[]={ - "Oacgr", 0x0038C, // GREEK CAPITAL LETTER OMICRON WITH TONOS - "oacgr", 0x003CC, // GREEK SMALL LETTER OMICRON WITH TONOS - "Oacute", 0x000D3, // LATIN CAPITAL LETTER O WITH ACUTE - "oacute", 0x000F3, // LATIN SMALL LETTER O WITH ACUTE - "oast", 0x0229B, // CIRCLED ASTERISK OPERATOR - "ocir", 0x0229A, // CIRCLED RING OPERATOR - "Ocirc", 0x000D4, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX - "ocirc", 0x000F4, // LATIN SMALL LETTER O WITH CIRCUMFLEX - "Ocy", 0x0041E, // CYRILLIC CAPITAL LETTER O - "ocy", 0x0043E, // CYRILLIC SMALL LETTER O - "odash", 0x0229D, // CIRCLED DASH - "Odblac", 0x00150, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE - "odblac", 0x00151, // LATIN SMALL LETTER O WITH DOUBLE ACUTE - "odiv", 0x02A38, // CIRCLED DIVISION SIGN - "odot", 0x02299, // CIRCLED DOT OPERATOR - "odsold", 0x029BC, // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN - "OElig", 0x00152, // LATIN CAPITAL LIGATURE OE - "oelig", 0x00153, // LATIN SMALL LIGATURE OE - "ofcir", 0x029BF, // CIRCLED BULLET - "Ofr", 0x1D512, // MATHEMATICAL FRAKTUR CAPITAL O - "ofr", 0x1D52C, // MATHEMATICAL FRAKTUR SMALL O - "ogon", 0x002DB, // OGONEK - "Ogr", 0x0039F, // GREEK CAPITAL LETTER OMICRON - "ogr", 0x003BF, // GREEK SMALL LETTER OMICRON - "Ograve", 0x000D2, // LATIN CAPITAL LETTER O WITH GRAVE - "ograve", 0x000F2, // LATIN SMALL LETTER O WITH GRAVE - "ogt", 0x029C1, // CIRCLED GREATER-THAN - "OHacgr", 0x0038F, // GREEK CAPITAL LETTER OMEGA WITH TONOS - "ohacgr", 0x003CE, // GREEK SMALL LETTER OMEGA WITH TONOS - "ohbar", 0x029B5, // CIRCLE WITH HORIZONTAL BAR - "OHgr", 0x003A9, // GREEK CAPITAL LETTER OMEGA - "ohgr", 0x003C9, // GREEK SMALL LETTER OMEGA - "ohm", 0x003A9, // GREEK CAPITAL LETTER OMEGA - "oint", 0x0222E, // CONTOUR INTEGRAL - "olarr", 0x021BA, // ANTICLOCKWISE OPEN CIRCLE ARROW - "olcir", 0x029BE, // CIRCLED WHITE BULLET - "olcross", 0x029BB, // CIRCLE WITH SUPERIMPOSED X - "oline", 0x0203E, // OVERLINE - "olt", 0x029C0, // CIRCLED LESS-THAN - "Omacr", 0x0014C, // LATIN CAPITAL LETTER O WITH MACRON - "omacr", 0x0014D, // LATIN SMALL LETTER O WITH MACRON - "Omega", 0x003A9, // GREEK CAPITAL LETTER OMEGA - "omega", 0x003C9, // GREEK SMALL LETTER OMEGA - "Omicron", 0x0039F, // GREEK CAPITAL LETTER OMICRON - "omicron", 0x003BF, // GREEK SMALL LETTER OMICRON - "omid", 0x029B6, // CIRCLED VERTICAL BAR - "ominus", 0x02296, // CIRCLED MINUS - "Oopf", 0x1D546, // MATHEMATICAL DOUBLE-STRUCK CAPITAL O - "oopf", 0x1D560, // MATHEMATICAL DOUBLE-STRUCK SMALL O - "opar", 0x029B7, // CIRCLED PARALLEL - "OpenCurlyDoubleQuote", 0x0201C, // LEFT DOUBLE QUOTATION MARK - "OpenCurlyQuote", 0x02018, // LEFT SINGLE QUOTATION MARK - "operp", 0x029B9, // CIRCLED PERPENDICULAR - "oplus", 0x02295, // CIRCLED PLUS - "or", 0x02228, // LOGICAL OR - "Or", 0x02A54, // DOUBLE LOGICAL OR - "orarr", 0x021BB, // CLOCKWISE OPEN CIRCLE ARROW - "ord", 0x02A5D, // LOGICAL OR WITH HORIZONTAL DASH - "order", 0x02134, // SCRIPT SMALL O - "orderof", 0x02134, // SCRIPT SMALL O - "ordf", 0x000AA, // FEMININE ORDINAL INDICATOR - "ordm", 0x000BA, // MASCULINE ORDINAL INDICATOR - "origof", 0x022B6, // ORIGINAL OF - "oror", 0x02A56, // TWO INTERSECTING LOGICAL OR - "orslope", 0x02A57, // SLOPING LARGE OR - "orv", 0x02A5B, // LOGICAL OR WITH MIDDLE STEM - "oS", 0x024C8, // CIRCLED LATIN CAPITAL LETTER S - "oscr", 0x02134, // SCRIPT SMALL O - "Oscr", 0x1D4AA, // MATHEMATICAL SCRIPT CAPITAL O - "Oslash", 0x000D8, // LATIN CAPITAL LETTER O WITH STROKE - "oslash", 0x000F8, // LATIN SMALL LETTER O WITH STROKE - "osol", 0x02298, // CIRCLED DIVISION SLASH - "Otilde", 0x000D5, // LATIN CAPITAL LETTER O WITH TILDE - "otilde", 0x000F5, // LATIN SMALL LETTER O WITH TILDE - "otimes", 0x02297, // CIRCLED TIMES - "Otimes", 0x02A37, // MULTIPLICATION SIGN IN DOUBLE CIRCLE - "otimesas", 0x02A36, // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT - "Ouml", 0x000D6, // LATIN CAPITAL LETTER O WITH DIAERESIS - "ouml", 0x000F6, // LATIN SMALL LETTER O WITH DIAERESIS - "ovbar", 0x0233D, // APL FUNCTIONAL SYMBOL CIRCLE STILE - "OverBar", 0x0203E, // OVERLINE - "OverBrace", 0x023DE, // TOP CURLY BRACKET - "OverBracket", 0x023B4, // TOP SQUARE BRACKET - "OverParenthesis", 0x023DC, // TOP PARENTHESIS - NULL, 0 -}; - -static NameId namesP[]={ - "par", 0x02225, // PARALLEL TO - "para", 0x000B6, // PILCROW SIGN - "parallel", 0x02225, // PARALLEL TO - "parsim", 0x02AF3, // PARALLEL WITH TILDE OPERATOR - "parsl", 0x02AFD, // DOUBLE SOLIDUS OPERATOR - "part", 0x02202, // PARTIAL DIFFERENTIAL - "PartialD", 0x02202, // PARTIAL DIFFERENTIAL - "Pcy", 0x0041F, // CYRILLIC CAPITAL LETTER PE - "pcy", 0x0043F, // CYRILLIC SMALL LETTER PE - "percnt", 0x00025, // PERCENT SIGN - "period", 0x0002E, // FULL STOP - "permil", 0x02030, // PER MILLE SIGN - "perp", 0x022A5, // UP TACK - "pertenk", 0x02031, // PER TEN THOUSAND SIGN - "Pfr", 0x1D513, // MATHEMATICAL FRAKTUR CAPITAL P - "pfr", 0x1D52D, // MATHEMATICAL FRAKTUR SMALL P - "Pgr", 0x003A0, // GREEK CAPITAL LETTER PI - "pgr", 0x003C0, // GREEK SMALL LETTER PI - "PHgr", 0x003A6, // GREEK CAPITAL LETTER PHI - "phgr", 0x003C6, // GREEK SMALL LETTER PHI - "Phi", 0x003A6, // GREEK CAPITAL LETTER PHI - "phi", 0x003C6, // GREEK SMALL LETTER PHI - "phiv", 0x003D5, // GREEK PHI SYMBOL - "phmmat", 0x02133, // SCRIPT CAPITAL M - "phone", 0x0260E, // BLACK TELEPHONE - "Pi", 0x003A0, // GREEK CAPITAL LETTER PI - "pi", 0x003C0, // GREEK SMALL LETTER PI - "pitchfork", 0x022D4, // PITCHFORK - "piv", 0x003D6, // GREEK PI SYMBOL - "planck", 0x0210F, // PLANCK CONSTANT OVER TWO PI - "planckh", 0x0210E, // PLANCK CONSTANT - "plankv", 0x0210F, // PLANCK CONSTANT OVER TWO PI - "plus", 0x0002B, // PLUS SIGN - "plusacir", 0x02A23, // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE - "plusb", 0x0229E, // SQUARED PLUS - "pluscir", 0x02A22, // PLUS SIGN WITH SMALL CIRCLE ABOVE - "plusdo", 0x02214, // DOT PLUS - "plusdu", 0x02A25, // PLUS SIGN WITH DOT BELOW - "pluse", 0x02A72, // PLUS SIGN ABOVE EQUALS SIGN - "PlusMinus", 0x000B1, // PLUS-MINUS SIGN - "plusmn", 0x000B1, // PLUS-MINUS SIGN - "plussim", 0x02A26, // PLUS SIGN WITH TILDE BELOW - "plustwo", 0x02A27, // PLUS SIGN WITH SUBSCRIPT TWO - "pm", 0x000B1, // PLUS-MINUS SIGN - "Poincareplane", 0x0210C, // BLACK-LETTER CAPITAL H - "pointint", 0x02A15, // INTEGRAL AROUND A POINT OPERATOR - "Popf", 0x02119, // DOUBLE-STRUCK CAPITAL P - "popf", 0x1D561, // MATHEMATICAL DOUBLE-STRUCK SMALL P - "pound", 0x000A3, // POUND SIGN - "pr", 0x0227A, // PRECEDES - "Pr", 0x02ABB, // DOUBLE PRECEDES - "prap", 0x02AB7, // PRECEDES ABOVE ALMOST EQUAL TO - "prcue", 0x0227C, // PRECEDES OR EQUAL TO - "pre", 0x02AAF, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN - "prE", 0x02AB3, // PRECEDES ABOVE EQUALS SIGN - "prec", 0x0227A, // PRECEDES - "precapprox", 0x02AB7, // PRECEDES ABOVE ALMOST EQUAL TO - "preccurlyeq", 0x0227C, // PRECEDES OR EQUAL TO - "Precedes", 0x0227A, // PRECEDES - "PrecedesEqual", 0x02AAF, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN - "PrecedesSlantEqual", 0x0227C, // PRECEDES OR EQUAL TO - "PrecedesTilde", 0x0227E, // PRECEDES OR EQUIVALENT TO - "preceq", 0x02AAF, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN - "precnapprox", 0x02AB9, // PRECEDES ABOVE NOT ALMOST EQUAL TO - "precneqq", 0x02AB5, // PRECEDES ABOVE NOT EQUAL TO - "precnsim", 0x022E8, // PRECEDES BUT NOT EQUIVALENT TO - "precsim", 0x0227E, // PRECEDES OR EQUIVALENT TO - "prime", 0x02032, // PRIME - "Prime", 0x02033, // DOUBLE PRIME - "primes", 0x02119, // DOUBLE-STRUCK CAPITAL P - "prnap", 0x02AB9, // PRECEDES ABOVE NOT ALMOST EQUAL TO - "prnE", 0x02AB5, // PRECEDES ABOVE NOT EQUAL TO - "prnsim", 0x022E8, // PRECEDES BUT NOT EQUIVALENT TO - "prod", 0x0220F, // N-ARY PRODUCT - "Product", 0x0220F, // N-ARY PRODUCT - "profalar", 0x0232E, // ALL AROUND-PROFILE - "profline", 0x02312, // ARC - "profsurf", 0x02313, // SEGMENT - "prop", 0x0221D, // PROPORTIONAL TO - "Proportion", 0x02237, // PROPORTION - "Proportional", 0x0221D, // PROPORTIONAL TO - "propto", 0x0221D, // PROPORTIONAL TO - "prsim", 0x0227E, // PRECEDES OR EQUIVALENT TO - "prurel", 0x022B0, // PRECEDES UNDER RELATION - "Pscr", 0x1D4AB, // MATHEMATICAL SCRIPT CAPITAL P - "pscr", 0x1D4C5, // MATHEMATICAL SCRIPT SMALL P - "PSgr", 0x003A8, // GREEK CAPITAL LETTER PSI - "psgr", 0x003C8, // GREEK SMALL LETTER PSI - "Psi", 0x003A8, // GREEK CAPITAL LETTER PSI - "psi", 0x003C8, // GREEK SMALL LETTER PSI - "puncsp", 0x02008, // PUNCTUATION SPACE - NULL, 0 -}; - -static NameId namesQ[]={ - "Qfr", 0x1D514, // MATHEMATICAL FRAKTUR CAPITAL Q - "qfr", 0x1D52E, // MATHEMATICAL FRAKTUR SMALL Q - "qint", 0x02A0C, // QUADRUPLE INTEGRAL OPERATOR - "Qopf", 0x0211A, // DOUBLE-STRUCK CAPITAL Q - "qopf", 0x1D562, // MATHEMATICAL DOUBLE-STRUCK SMALL Q - "qprime", 0x02057, // QUADRUPLE PRIME - "Qscr", 0x1D4AC, // MATHEMATICAL SCRIPT CAPITAL Q - "qscr", 0x1D4C6, // MATHEMATICAL SCRIPT SMALL Q - "quaternions", 0x0210D, // DOUBLE-STRUCK CAPITAL H - "quatint", 0x02A16, // QUATERNION INTEGRAL OPERATOR - "quest", 0x0003F, // QUESTION MARK - "questeq", 0x0225F, // QUESTIONED EQUAL TO - "quot", 0x00022, // QUOTATION MARK - "QUOT", 0x00022, // QUOTATION MARK - NULL, 0 -}; - -static NameId namesR[]={ - "rAarr", 0x021DB, // RIGHTWARDS TRIPLE ARROW -// "race", 0x0223D;0x00331, // REVERSED TILDE with underline - "Racute", 0x00154, // LATIN CAPITAL LETTER R WITH ACUTE - "racute", 0x00155, // LATIN SMALL LETTER R WITH ACUTE - "radic", 0x0221A, // SQUARE ROOT - "raemptyv", 0x029B3, // EMPTY SET WITH RIGHT ARROW ABOVE - "rang", 0x027E9, // MATHEMATICAL RIGHT ANGLE BRACKET - "Rang", 0x027EB, // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET - "rangd", 0x02992, // RIGHT ANGLE BRACKET WITH DOT - "range", 0x029A5, // REVERSED ANGLE WITH UNDERBAR - "rangle", 0x027E9, // MATHEMATICAL RIGHT ANGLE BRACKET - "raquo", 0x000BB, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - "rarr", 0x02192, // RIGHTWARDS ARROW - "Rarr", 0x021A0, // RIGHTWARDS TWO HEADED ARROW - "rArr", 0x021D2, // RIGHTWARDS DOUBLE ARROW - "rarrap", 0x02975, // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO - "rarrb", 0x021E5, // RIGHTWARDS ARROW TO BAR - "rarrbfs", 0x02920, // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND - "rarrc", 0x02933, // WAVE ARROW POINTING DIRECTLY RIGHT - "rarrfs", 0x0291E, // RIGHTWARDS ARROW TO BLACK DIAMOND - "rarrhk", 0x021AA, // RIGHTWARDS ARROW WITH HOOK - "rarrlp", 0x021AC, // RIGHTWARDS ARROW WITH LOOP - "rarrpl", 0x02945, // RIGHTWARDS ARROW WITH PLUS BELOW - "rarrsim", 0x02974, // RIGHTWARDS ARROW ABOVE TILDE OPERATOR - "rarrtl", 0x021A3, // RIGHTWARDS ARROW WITH TAIL - "Rarrtl", 0x02916, // RIGHTWARDS TWO-HEADED ARROW WITH TAIL - "rarrw", 0x0219D, // RIGHTWARDS WAVE ARROW - "ratail", 0x0291A, // RIGHTWARDS ARROW-TAIL - "rAtail", 0x0291C, // RIGHTWARDS DOUBLE ARROW-TAIL - "ratio", 0x02236, // RATIO - "rationals", 0x0211A, // DOUBLE-STRUCK CAPITAL Q - "rbarr", 0x0290D, // RIGHTWARDS DOUBLE DASH ARROW - "rBarr", 0x0290F, // RIGHTWARDS TRIPLE DASH ARROW - "RBarr", 0x02910, // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW - "rbbrk", 0x02773, // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT - "rbrace", 0x0007D, // RIGHT CURLY BRACKET - "rbrack", 0x0005D, // RIGHT SQUARE BRACKET - "rbrke", 0x0298C, // RIGHT SQUARE BRACKET WITH UNDERBAR - "rbrksld", 0x0298E, // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER - "rbrkslu", 0x02990, // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER - "Rcaron", 0x00158, // LATIN CAPITAL LETTER R WITH CARON - "rcaron", 0x00159, // LATIN SMALL LETTER R WITH CARON - "Rcedil", 0x00156, // LATIN CAPITAL LETTER R WITH CEDILLA - "rcedil", 0x00157, // LATIN SMALL LETTER R WITH CEDILLA - "rceil", 0x02309, // RIGHT CEILING - "rcub", 0x0007D, // RIGHT CURLY BRACKET - "Rcy", 0x00420, // CYRILLIC CAPITAL LETTER ER - "rcy", 0x00440, // CYRILLIC SMALL LETTER ER - "rdca", 0x02937, // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS - "rdldhar", 0x02969, // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN - "rdquo", 0x0201D, // RIGHT DOUBLE QUOTATION MARK - "rdquor", 0x0201D, // RIGHT DOUBLE QUOTATION MARK - "rdsh", 0x021B3, // DOWNWARDS ARROW WITH TIP RIGHTWARDS - "Re", 0x0211C, // BLACK-LETTER CAPITAL R - "real", 0x0211C, // BLACK-LETTER CAPITAL R - "realine", 0x0211B, // SCRIPT CAPITAL R - "realpart", 0x0211C, // BLACK-LETTER CAPITAL R - "reals", 0x0211D, // DOUBLE-STRUCK CAPITAL R - "rect", 0x025AD, // WHITE RECTANGLE - "reg", 0x000AE, // REGISTERED SIGN - "REG", 0x000AE, // REGISTERED SIGN - "ReverseElement", 0x0220B, // CONTAINS AS MEMBER - "ReverseEquilibrium", 0x021CB, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - "ReverseUpEquilibrium", 0x0296F, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT - "rfisht", 0x0297D, // RIGHT FISH TAIL - "rfloor", 0x0230B, // RIGHT FLOOR - "Rfr", 0x0211C, // BLACK-LETTER CAPITAL R - "rfr", 0x1D52F, // MATHEMATICAL FRAKTUR SMALL R - "Rgr", 0x003A1, // GREEK CAPITAL LETTER RHO - "rgr", 0x003C1, // GREEK SMALL LETTER RHO - "rHar", 0x02964, // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN - "rhard", 0x021C1, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS - "rharu", 0x021C0, // RIGHTWARDS HARPOON WITH BARB UPWARDS - "rharul", 0x0296C, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH - "Rho", 0x003A1, // GREEK CAPITAL LETTER RHO - "rho", 0x003C1, // GREEK SMALL LETTER RHO - "rhov", 0x003F1, // GREEK RHO SYMBOL - "RightAngleBracket", 0x027E9, // MATHEMATICAL RIGHT ANGLE BRACKET - "rightarrow", 0x02192, // RIGHTWARDS ARROW - "RightArrow", 0x02192, // RIGHTWARDS ARROW - "Rightarrow", 0x021D2, // RIGHTWARDS DOUBLE ARROW - "RightArrowBar", 0x021E5, // RIGHTWARDS ARROW TO BAR - "RightArrowLeftArrow", 0x021C4, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - "rightarrowtail", 0x021A3, // RIGHTWARDS ARROW WITH TAIL - "RightCeiling", 0x02309, // RIGHT CEILING - "RightDoubleBracket", 0x027E7, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET - "RightDownTeeVector", 0x0295D, // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR - "RightDownVector", 0x021C2, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS - "RightDownVectorBar", 0x02955, // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR - "RightFloor", 0x0230B, // RIGHT FLOOR - "rightharpoondown", 0x021C1, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS - "rightharpoonup", 0x021C0, // RIGHTWARDS HARPOON WITH BARB UPWARDS - "rightleftarrows", 0x021C4, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - "rightleftharpoons", 0x021CC, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - "rightrightarrows", 0x021C9, // RIGHTWARDS PAIRED ARROWS - "rightsquigarrow", 0x0219D, // RIGHTWARDS WAVE ARROW - "RightTee", 0x022A2, // RIGHT TACK - "RightTeeArrow", 0x021A6, // RIGHTWARDS ARROW FROM BAR - "RightTeeVector", 0x0295B, // RIGHTWARDS HARPOON WITH BARB UP FROM BAR - "rightthreetimes", 0x022CC, // RIGHT SEMIDIRECT PRODUCT - "RightTriangle", 0x022B3, // CONTAINS AS NORMAL SUBGROUP - "RightTriangleBar", 0x029D0, // VERTICAL BAR BESIDE RIGHT TRIANGLE - "RightTriangleEqual", 0x022B5, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO - "RightUpDownVector", 0x0294F, // UP BARB RIGHT DOWN BARB RIGHT HARPOON - "RightUpTeeVector", 0x0295C, // UPWARDS HARPOON WITH BARB RIGHT FROM BAR - "RightUpVector", 0x021BE, // UPWARDS HARPOON WITH BARB RIGHTWARDS - "RightUpVectorBar", 0x02954, // UPWARDS HARPOON WITH BARB RIGHT TO BAR - "RightVector", 0x021C0, // RIGHTWARDS HARPOON WITH BARB UPWARDS - "RightVectorBar", 0x02953, // RIGHTWARDS HARPOON WITH BARB UP TO BAR - "ring", 0x002DA, // RING ABOVE - "risingdotseq", 0x02253, // IMAGE OF OR APPROXIMATELY EQUAL TO - "rlarr", 0x021C4, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - "rlhar", 0x021CC, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - "rlm", 0x0200F, // RIGHT-TO-LEFT MARK - "rmoust", 0x023B1, // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION - "rmoustache", 0x023B1, // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION - "rnmid", 0x02AEE, // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH - "roang", 0x027ED, // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET - "roarr", 0x021FE, // RIGHTWARDS OPEN-HEADED ARROW - "robrk", 0x027E7, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET - "ropar", 0x02986, // RIGHT WHITE PARENTHESIS - "Ropf", 0x0211D, // DOUBLE-STRUCK CAPITAL R - "ropf", 0x1D563, // MATHEMATICAL DOUBLE-STRUCK SMALL R - "roplus", 0x02A2E, // PLUS SIGN IN RIGHT HALF CIRCLE - "rotimes", 0x02A35, // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE - "RoundImplies", 0x02970, // RIGHT DOUBLE ARROW WITH ROUNDED HEAD - "rpar", 0x00029, // RIGHT PARENTHESIS - "rpargt", 0x02994, // RIGHT ARC GREATER-THAN BRACKET - "rppolint", 0x02A12, // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE - "rrarr", 0x021C9, // RIGHTWARDS PAIRED ARROWS - "Rrightarrow", 0x021DB, // RIGHTWARDS TRIPLE ARROW - "rsaquo", 0x0203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - "Rscr", 0x0211B, // SCRIPT CAPITAL R - "rscr", 0x1D4C7, // MATHEMATICAL SCRIPT SMALL R - "rsh", 0x021B1, // UPWARDS ARROW WITH TIP RIGHTWARDS - "Rsh", 0x021B1, // UPWARDS ARROW WITH TIP RIGHTWARDS - "rsqb", 0x0005D, // RIGHT SQUARE BRACKET - "rsquo", 0x02019, // RIGHT SINGLE QUOTATION MARK - "rsquor", 0x02019, // RIGHT SINGLE QUOTATION MARK - "rthree", 0x022CC, // RIGHT SEMIDIRECT PRODUCT - "rtimes", 0x022CA, // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT - "rtri", 0x025B9, // WHITE RIGHT-POINTING SMALL TRIANGLE - "rtrie", 0x022B5, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO - "rtrif", 0x025B8, // BLACK RIGHT-POINTING SMALL TRIANGLE - "rtriltri", 0x029CE, // RIGHT TRIANGLE ABOVE LEFT TRIANGLE - "RuleDelayed", 0x029F4, // RULE-DELAYED - "ruluhar", 0x02968, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP - "rx", 0x0211E, // PRESCRIPTION TAKE - NULL, 0 -}; - -static NameId namesS[]={ - "Sacute", 0x0015A, // LATIN CAPITAL LETTER S WITH ACUTE - "sacute", 0x0015B, // LATIN SMALL LETTER S WITH ACUTE - "sbquo", 0x0201A, // SINGLE LOW-9 QUOTATION MARK - "sc", 0x0227B, // SUCCEEDS - "Sc", 0x02ABC, // DOUBLE SUCCEEDS - "scap", 0x02AB8, // SUCCEEDS ABOVE ALMOST EQUAL TO - "Scaron", 0x00160, // LATIN CAPITAL LETTER S WITH CARON - "scaron", 0x00161, // LATIN SMALL LETTER S WITH CARON - "sccue", 0x0227D, // SUCCEEDS OR EQUAL TO - "sce", 0x02AB0, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN - "scE", 0x02AB4, // SUCCEEDS ABOVE EQUALS SIGN - "Scedil", 0x0015E, // LATIN CAPITAL LETTER S WITH CEDILLA - "scedil", 0x0015F, // LATIN SMALL LETTER S WITH CEDILLA - "Scirc", 0x0015C, // LATIN CAPITAL LETTER S WITH CIRCUMFLEX - "scirc", 0x0015D, // LATIN SMALL LETTER S WITH CIRCUMFLEX - "scnap", 0x02ABA, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO - "scnE", 0x02AB6, // SUCCEEDS ABOVE NOT EQUAL TO - "scnsim", 0x022E9, // SUCCEEDS BUT NOT EQUIVALENT TO - "scpolint", 0x02A13, // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE - "scsim", 0x0227F, // SUCCEEDS OR EQUIVALENT TO - "Scy", 0x00421, // CYRILLIC CAPITAL LETTER ES - "scy", 0x00441, // CYRILLIC SMALL LETTER ES - "sdot", 0x022C5, // DOT OPERATOR - "sdotb", 0x022A1, // SQUARED DOT OPERATOR - "sdote", 0x02A66, // EQUALS SIGN WITH DOT BELOW - "searhk", 0x02925, // SOUTH EAST ARROW WITH HOOK - "searr", 0x02198, // SOUTH EAST ARROW - "seArr", 0x021D8, // SOUTH EAST DOUBLE ARROW - "searrow", 0x02198, // SOUTH EAST ARROW - "sect", 0x000A7, // SECTION SIGN - "semi", 0x0003B, // SEMICOLON - "seswar", 0x02929, // SOUTH EAST ARROW AND SOUTH WEST ARROW - "setminus", 0x02216, // SET MINUS - "setmn", 0x02216, // SET MINUS - "sext", 0x02736, // SIX POINTED BLACK STAR - "sfgr", 0x003C2, // GREEK SMALL LETTER FINAL SIGMA - "Sfr", 0x1D516, // MATHEMATICAL FRAKTUR CAPITAL S - "sfr", 0x1D530, // MATHEMATICAL FRAKTUR SMALL S - "sfrown", 0x02322, // FROWN - "Sgr", 0x003A3, // GREEK CAPITAL LETTER SIGMA - "sgr", 0x003C3, // GREEK SMALL LETTER SIGMA - "sharp", 0x0266F, // MUSIC SHARP SIGN - "SHCHcy", 0x00429, // CYRILLIC CAPITAL LETTER SHCHA - "shchcy", 0x00449, // CYRILLIC SMALL LETTER SHCHA - "SHcy", 0x00428, // CYRILLIC CAPITAL LETTER SHA - "shcy", 0x00448, // CYRILLIC SMALL LETTER SHA - "ShortDownArrow", 0x02193, // DOWNWARDS ARROW - "ShortLeftArrow", 0x02190, // LEFTWARDS ARROW - "shortmid", 0x02223, // DIVIDES - "shortparallel", 0x02225, // PARALLEL TO - "ShortRightArrow", 0x02192, // RIGHTWARDS ARROW - "ShortUpArrow", 0x02191, // UPWARDS ARROW - "shy", 0x000AD, // SOFT HYPHEN - "Sigma", 0x003A3, // GREEK CAPITAL LETTER SIGMA - "sigma", 0x003C3, // GREEK SMALL LETTER SIGMA - "sigmaf", 0x003C2, // GREEK SMALL LETTER FINAL SIGMA - "sigmav", 0x003C2, // GREEK SMALL LETTER FINAL SIGMA - "sim", 0x0223C, // TILDE OPERATOR - "simdot", 0x02A6A, // TILDE OPERATOR WITH DOT ABOVE - "sime", 0x02243, // ASYMPTOTICALLY EQUAL TO - "simeq", 0x02243, // ASYMPTOTICALLY EQUAL TO - "simg", 0x02A9E, // SIMILAR OR GREATER-THAN - "simgE", 0x02AA0, // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN - "siml", 0x02A9D, // SIMILAR OR LESS-THAN - "simlE", 0x02A9F, // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN - "simne", 0x02246, // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO - "simplus", 0x02A24, // PLUS SIGN WITH TILDE ABOVE - "simrarr", 0x02972, // TILDE OPERATOR ABOVE RIGHTWARDS ARROW - "slarr", 0x02190, // LEFTWARDS ARROW - "SmallCircle", 0x02218, // RING OPERATOR - "smallsetminus", 0x02216, // SET MINUS - "smashp", 0x02A33, // SMASH PRODUCT - "smeparsl", 0x029E4, // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE - "smid", 0x02223, // DIVIDES - "smile", 0x02323, // SMILE - "smt", 0x02AAA, // SMALLER THAN - "smte", 0x02AAC, // SMALLER THAN OR EQUAL TO -// "smtes", 0x02AAC;0x0FE00, // SMALLER THAN OR slanted EQUAL - "SOFTcy", 0x0042C, // CYRILLIC CAPITAL LETTER SOFT SIGN - "softcy", 0x0044C, // CYRILLIC SMALL LETTER SOFT SIGN - "sol", 0x0002F, // SOLIDUS - "solb", 0x029C4, // SQUARED RISING DIAGONAL SLASH - "solbar", 0x0233F, // APL FUNCTIONAL SYMBOL SLASH BAR - "Sopf", 0x1D54A, // MATHEMATICAL DOUBLE-STRUCK CAPITAL S - "sopf", 0x1D564, // MATHEMATICAL DOUBLE-STRUCK SMALL S - "spades", 0x02660, // BLACK SPADE SUIT - "spadesuit", 0x02660, // BLACK SPADE SUIT - "spar", 0x02225, // PARALLEL TO - "sqcap", 0x02293, // SQUARE CAP -// "sqcaps", 0x02293;0x0FE00, // SQUARE CAP with serifs - "sqcup", 0x02294, // SQUARE CUP -// "sqcups", 0x02294;0x0FE00, // SQUARE CUP with serifs - "Sqrt", 0x0221A, // SQUARE ROOT - "sqsub", 0x0228F, // SQUARE IMAGE OF - "sqsube", 0x02291, // SQUARE IMAGE OF OR EQUAL TO - "sqsubset", 0x0228F, // SQUARE IMAGE OF - "sqsubseteq", 0x02291, // SQUARE IMAGE OF OR EQUAL TO - "sqsup", 0x02290, // SQUARE ORIGINAL OF - "sqsupe", 0x02292, // SQUARE ORIGINAL OF OR EQUAL TO - "sqsupset", 0x02290, // SQUARE ORIGINAL OF - "sqsupseteq", 0x02292, // SQUARE ORIGINAL OF OR EQUAL TO - "squ", 0x025A1, // WHITE SQUARE - "square", 0x025A1, // WHITE SQUARE - "Square", 0x025A1, // WHITE SQUARE - "SquareIntersection", 0x02293, // SQUARE CAP - "SquareSubset", 0x0228F, // SQUARE IMAGE OF - "SquareSubsetEqual", 0x02291, // SQUARE IMAGE OF OR EQUAL TO - "SquareSuperset", 0x02290, // SQUARE ORIGINAL OF - "SquareSupersetEqual", 0x02292, // SQUARE ORIGINAL OF OR EQUAL TO - "SquareUnion", 0x02294, // SQUARE CUP - "squarf", 0x025AA, // BLACK SMALL SQUARE - "squf", 0x025AA, // BLACK SMALL SQUARE - "srarr", 0x02192, // RIGHTWARDS ARROW - "Sscr", 0x1D4AE, // MATHEMATICAL SCRIPT CAPITAL S - "sscr", 0x1D4C8, // MATHEMATICAL SCRIPT SMALL S - "ssetmn", 0x02216, // SET MINUS - "ssmile", 0x02323, // SMILE - "sstarf", 0x022C6, // STAR OPERATOR - "Star", 0x022C6, // STAR OPERATOR - "star", 0x02606, // WHITE STAR - "starf", 0x02605, // BLACK STAR - "straightepsilon", 0x003F5, // GREEK LUNATE EPSILON SYMBOL - "straightphi", 0x003D5, // GREEK PHI SYMBOL - "strns", 0x000AF, // MACRON - "sub", 0x02282, // SUBSET OF - "Sub", 0x022D0, // DOUBLE SUBSET - "subdot", 0x02ABD, // SUBSET WITH DOT - "sube", 0x02286, // SUBSET OF OR EQUAL TO - "subE", 0x02AC5, // SUBSET OF ABOVE EQUALS SIGN - "subedot", 0x02AC3, // SUBSET OF OR EQUAL TO WITH DOT ABOVE - "submult", 0x02AC1, // SUBSET WITH MULTIPLICATION SIGN BELOW - "subne", 0x0228A, // SUBSET OF WITH NOT EQUAL TO - "subnE", 0x02ACB, // SUBSET OF ABOVE NOT EQUAL TO - "subplus", 0x02ABF, // SUBSET WITH PLUS SIGN BELOW - "subrarr", 0x02979, // SUBSET ABOVE RIGHTWARDS ARROW - "subset", 0x02282, // SUBSET OF - "Subset", 0x022D0, // DOUBLE SUBSET - "subseteq", 0x02286, // SUBSET OF OR EQUAL TO - "subseteqq", 0x02AC5, // SUBSET OF ABOVE EQUALS SIGN - "SubsetEqual", 0x02286, // SUBSET OF OR EQUAL TO - "subsetneq", 0x0228A, // SUBSET OF WITH NOT EQUAL TO - "subsetneqq", 0x02ACB, // SUBSET OF ABOVE NOT EQUAL TO - "subsim", 0x02AC7, // SUBSET OF ABOVE TILDE OPERATOR - "subsub", 0x02AD5, // SUBSET ABOVE SUBSET - "subsup", 0x02AD3, // SUBSET ABOVE SUPERSET - "succ", 0x0227B, // SUCCEEDS - "succapprox", 0x02AB8, // SUCCEEDS ABOVE ALMOST EQUAL TO - "succcurlyeq", 0x0227D, // SUCCEEDS OR EQUAL TO - "Succeeds", 0x0227B, // SUCCEEDS - "SucceedsEqual", 0x02AB0, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN - "SucceedsSlantEqual", 0x0227D, // SUCCEEDS OR EQUAL TO - "SucceedsTilde", 0x0227F, // SUCCEEDS OR EQUIVALENT TO - "succeq", 0x02AB0, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN - "succnapprox", 0x02ABA, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO - "succneqq", 0x02AB6, // SUCCEEDS ABOVE NOT EQUAL TO - "succnsim", 0x022E9, // SUCCEEDS BUT NOT EQUIVALENT TO - "succsim", 0x0227F, // SUCCEEDS OR EQUIVALENT TO - "SuchThat", 0x0220B, // CONTAINS AS MEMBER - "sum", 0x02211, // N-ARY SUMMATION - "Sum", 0x02211, // N-ARY SUMMATION - "sung", 0x0266A, // EIGHTH NOTE - "sup", 0x02283, // SUPERSET OF - "Sup", 0x022D1, // DOUBLE SUPERSET - "sup1", 0x000B9, // SUPERSCRIPT ONE - "sup2", 0x000B2, // SUPERSCRIPT TWO - "sup3", 0x000B3, // SUPERSCRIPT THREE - "supdot", 0x02ABE, // SUPERSET WITH DOT - "supdsub", 0x02AD8, // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET - "supe", 0x02287, // SUPERSET OF OR EQUAL TO - "supE", 0x02AC6, // SUPERSET OF ABOVE EQUALS SIGN - "supedot", 0x02AC4, // SUPERSET OF OR EQUAL TO WITH DOT ABOVE - "Superset", 0x02283, // SUPERSET OF - "SupersetEqual", 0x02287, // SUPERSET OF OR EQUAL TO - "suphsol", 0x027C9, // SUPERSET PRECEDING SOLIDUS - "suphsub", 0x02AD7, // SUPERSET BESIDE SUBSET - "suplarr", 0x0297B, // SUPERSET ABOVE LEFTWARDS ARROW - "supmult", 0x02AC2, // SUPERSET WITH MULTIPLICATION SIGN BELOW - "supne", 0x0228B, // SUPERSET OF WITH NOT EQUAL TO - "supnE", 0x02ACC, // SUPERSET OF ABOVE NOT EQUAL TO - "supplus", 0x02AC0, // SUPERSET WITH PLUS SIGN BELOW - "supset", 0x02283, // SUPERSET OF - "Supset", 0x022D1, // DOUBLE SUPERSET - "supseteq", 0x02287, // SUPERSET OF OR EQUAL TO - "supseteqq", 0x02AC6, // SUPERSET OF ABOVE EQUALS SIGN - "supsetneq", 0x0228B, // SUPERSET OF WITH NOT EQUAL TO - "supsetneqq", 0x02ACC, // SUPERSET OF ABOVE NOT EQUAL TO - "supsim", 0x02AC8, // SUPERSET OF ABOVE TILDE OPERATOR - "supsub", 0x02AD4, // SUPERSET ABOVE SUBSET - "supsup", 0x02AD6, // SUPERSET ABOVE SUPERSET - "swarhk", 0x02926, // SOUTH WEST ARROW WITH HOOK - "swarr", 0x02199, // SOUTH WEST ARROW - "swArr", 0x021D9, // SOUTH WEST DOUBLE ARROW - "swarrow", 0x02199, // SOUTH WEST ARROW - "swnwar", 0x0292A, // SOUTH WEST ARROW AND NORTH WEST ARROW - "szlig", 0x000DF, // LATIN SMALL LETTER SHARP S - NULL, 0 -}; - -static NameId namesT[]={ - "Tab", 0x00009, // CHARACTER TABULATION - "target", 0x02316, // POSITION INDICATOR - "Tau", 0x003A4, // GREEK CAPITAL LETTER TAU - "tau", 0x003C4, // GREEK SMALL LETTER TAU - "tbrk", 0x023B4, // TOP SQUARE BRACKET - "Tcaron", 0x00164, // LATIN CAPITAL LETTER T WITH CARON - "tcaron", 0x00165, // LATIN SMALL LETTER T WITH CARON - "Tcedil", 0x00162, // LATIN CAPITAL LETTER T WITH CEDILLA - "tcedil", 0x00163, // LATIN SMALL LETTER T WITH CEDILLA - "Tcy", 0x00422, // CYRILLIC CAPITAL LETTER TE - "tcy", 0x00442, // CYRILLIC SMALL LETTER TE - "tdot", 0x020DB, // COMBINING THREE DOTS ABOVE - "telrec", 0x02315, // TELEPHONE RECORDER - "Tfr", 0x1D517, // MATHEMATICAL FRAKTUR CAPITAL T - "tfr", 0x1D531, // MATHEMATICAL FRAKTUR SMALL T - "Tgr", 0x003A4, // GREEK CAPITAL LETTER TAU - "tgr", 0x003C4, // GREEK SMALL LETTER TAU - "there4", 0x02234, // THEREFORE - "therefore", 0x02234, // THEREFORE - "Therefore", 0x02234, // THEREFORE - "Theta", 0x00398, // GREEK CAPITAL LETTER THETA - "theta", 0x003B8, // GREEK SMALL LETTER THETA - "thetasym", 0x003D1, // GREEK THETA SYMBOL - "thetav", 0x003D1, // GREEK THETA SYMBOL - "THgr", 0x00398, // GREEK CAPITAL LETTER THETA - "thgr", 0x003B8, // GREEK SMALL LETTER THETA - "thickapprox", 0x02248, // ALMOST EQUAL TO - "thicksim", 0x0223C, // TILDE OPERATOR -// "ThickSpace", 0x0205F;0x0200A, // space of width 5/18 em - "thinsp", 0x02009, // THIN SPACE - "ThinSpace", 0x02009, // THIN SPACE - "thkap", 0x02248, // ALMOST EQUAL TO - "thksim", 0x0223C, // TILDE OPERATOR - "THORN", 0x000DE, // LATIN CAPITAL LETTER THORN - "thorn", 0x000FE, // LATIN SMALL LETTER THORN - "tilde", 0x002DC, // SMALL TILDE - "Tilde", 0x0223C, // TILDE OPERATOR - "TildeEqual", 0x02243, // ASYMPTOTICALLY EQUAL TO - "TildeFullEqual", 0x02245, // APPROXIMATELY EQUAL TO - "TildeTilde", 0x02248, // ALMOST EQUAL TO - "times", 0x000D7, // MULTIPLICATION SIGN - "timesb", 0x022A0, // SQUARED TIMES - "timesbar", 0x02A31, // MULTIPLICATION SIGN WITH UNDERBAR - "timesd", 0x02A30, // MULTIPLICATION SIGN WITH DOT ABOVE - "tint", 0x0222D, // TRIPLE INTEGRAL - "toea", 0x02928, // NORTH EAST ARROW AND SOUTH EAST ARROW - "top", 0x022A4, // DOWN TACK - "topbot", 0x02336, // APL FUNCTIONAL SYMBOL I-BEAM - "topcir", 0x02AF1, // DOWN TACK WITH CIRCLE BELOW - "Topf", 0x1D54B, // MATHEMATICAL DOUBLE-STRUCK CAPITAL T - "topf", 0x1D565, // MATHEMATICAL DOUBLE-STRUCK SMALL T - "topfork", 0x02ADA, // PITCHFORK WITH TEE TOP - "tosa", 0x02929, // SOUTH EAST ARROW AND SOUTH WEST ARROW - "tprime", 0x02034, // TRIPLE PRIME - "trade", 0x02122, // TRADE MARK SIGN - "TRADE", 0x02122, // TRADE MARK SIGN - "triangle", 0x025B5, // WHITE UP-POINTING SMALL TRIANGLE - "triangledown", 0x025BF, // WHITE DOWN-POINTING SMALL TRIANGLE - "triangleleft", 0x025C3, // WHITE LEFT-POINTING SMALL TRIANGLE - "trianglelefteq", 0x022B4, // NORMAL SUBGROUP OF OR EQUAL TO - "triangleq", 0x0225C, // DELTA EQUAL TO - "triangleright", 0x025B9, // WHITE RIGHT-POINTING SMALL TRIANGLE - "trianglerighteq", 0x022B5, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO - "tridot", 0x025EC, // WHITE UP-POINTING TRIANGLE WITH DOT - "trie", 0x0225C, // DELTA EQUAL TO - "triminus", 0x02A3A, // MINUS SIGN IN TRIANGLE - "TripleDot", 0x020DB, // COMBINING THREE DOTS ABOVE - "triplus", 0x02A39, // PLUS SIGN IN TRIANGLE - "trisb", 0x029CD, // TRIANGLE WITH SERIFS AT BOTTOM - "tritime", 0x02A3B, // MULTIPLICATION SIGN IN TRIANGLE - "trpezium", 0x023E2, // WHITE TRAPEZIUM - "Tscr", 0x1D4AF, // MATHEMATICAL SCRIPT CAPITAL T - "tscr", 0x1D4C9, // MATHEMATICAL SCRIPT SMALL T - "TScy", 0x00426, // CYRILLIC CAPITAL LETTER TSE - "tscy", 0x00446, // CYRILLIC SMALL LETTER TSE - "TSHcy", 0x0040B, // CYRILLIC CAPITAL LETTER TSHE - "tshcy", 0x0045B, // CYRILLIC SMALL LETTER TSHE - "Tstrok", 0x00166, // LATIN CAPITAL LETTER T WITH STROKE - "tstrok", 0x00167, // LATIN SMALL LETTER T WITH STROKE - "twixt", 0x0226C, // BETWEEN - "twoheadleftarrow", 0x0219E, // LEFTWARDS TWO HEADED ARROW - "twoheadrightarrow", 0x021A0, // RIGHTWARDS TWO HEADED ARROW - NULL, 0 -}; - -static NameId namesU[]={ - "Uacgr", 0x0038E, // GREEK CAPITAL LETTER UPSILON WITH TONOS - "uacgr", 0x003CD, // GREEK SMALL LETTER UPSILON WITH TONOS - "Uacute", 0x000DA, // LATIN CAPITAL LETTER U WITH ACUTE - "uacute", 0x000FA, // LATIN SMALL LETTER U WITH ACUTE - "uarr", 0x02191, // UPWARDS ARROW - "Uarr", 0x0219F, // UPWARDS TWO HEADED ARROW - "uArr", 0x021D1, // UPWARDS DOUBLE ARROW - "Uarrocir", 0x02949, // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE - "Ubrcy", 0x0040E, // CYRILLIC CAPITAL LETTER SHORT U - "ubrcy", 0x0045E, // CYRILLIC SMALL LETTER SHORT U - "Ubreve", 0x0016C, // LATIN CAPITAL LETTER U WITH BREVE - "ubreve", 0x0016D, // LATIN SMALL LETTER U WITH BREVE - "Ucirc", 0x000DB, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX - "ucirc", 0x000FB, // LATIN SMALL LETTER U WITH CIRCUMFLEX - "Ucy", 0x00423, // CYRILLIC CAPITAL LETTER U - "ucy", 0x00443, // CYRILLIC SMALL LETTER U - "udarr", 0x021C5, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW - "Udblac", 0x00170, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE - "udblac", 0x00171, // LATIN SMALL LETTER U WITH DOUBLE ACUTE - "udhar", 0x0296E, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT - "udiagr", 0x003B0, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS - "Udigr", 0x003AB, // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA - "udigr", 0x003CB, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA - "ufisht", 0x0297E, // UP FISH TAIL - "Ufr", 0x1D518, // MATHEMATICAL FRAKTUR CAPITAL U - "ufr", 0x1D532, // MATHEMATICAL FRAKTUR SMALL U - "Ugr", 0x003A5, // GREEK CAPITAL LETTER UPSILON - "ugr", 0x003C5, // GREEK SMALL LETTER UPSILON - "Ugrave", 0x000D9, // LATIN CAPITAL LETTER U WITH GRAVE - "ugrave", 0x000F9, // LATIN SMALL LETTER U WITH GRAVE - "uHar", 0x02963, // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT - "uharl", 0x021BF, // UPWARDS HARPOON WITH BARB LEFTWARDS - "uharr", 0x021BE, // UPWARDS HARPOON WITH BARB RIGHTWARDS - "uhblk", 0x02580, // UPPER HALF BLOCK - "ulcorn", 0x0231C, // TOP LEFT CORNER - "ulcorner", 0x0231C, // TOP LEFT CORNER - "ulcrop", 0x0230F, // TOP LEFT CROP - "ultri", 0x025F8, // UPPER LEFT TRIANGLE - "Umacr", 0x0016A, // LATIN CAPITAL LETTER U WITH MACRON - "umacr", 0x0016B, // LATIN SMALL LETTER U WITH MACRON - "uml", 0x000A8, // DIAERESIS - "UnderBar", 0x0005F, // LOW LINE - "UnderBrace", 0x023DF, // BOTTOM CURLY BRACKET - "UnderBracket", 0x023B5, // BOTTOM SQUARE BRACKET - "UnderParenthesis", 0x023DD, // BOTTOM PARENTHESIS - "Union", 0x022C3, // N-ARY UNION - "UnionPlus", 0x0228E, // MULTISET UNION - "Uogon", 0x00172, // LATIN CAPITAL LETTER U WITH OGONEK - "uogon", 0x00173, // LATIN SMALL LETTER U WITH OGONEK - "Uopf", 0x1D54C, // MATHEMATICAL DOUBLE-STRUCK CAPITAL U - "uopf", 0x1D566, // MATHEMATICAL DOUBLE-STRUCK SMALL U - "uparrow", 0x02191, // UPWARDS ARROW - "UpArrow", 0x02191, // UPWARDS ARROW - "Uparrow", 0x021D1, // UPWARDS DOUBLE ARROW - "UpArrowBar", 0x02912, // UPWARDS ARROW TO BAR - "UpArrowDownArrow", 0x021C5, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW - "updownarrow", 0x02195, // UP DOWN ARROW - "UpDownArrow", 0x02195, // UP DOWN ARROW - "Updownarrow", 0x021D5, // UP DOWN DOUBLE ARROW - "UpEquilibrium", 0x0296E, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT - "upharpoonleft", 0x021BF, // UPWARDS HARPOON WITH BARB LEFTWARDS - "upharpoonright", 0x021BE, // UPWARDS HARPOON WITH BARB RIGHTWARDS - "uplus", 0x0228E, // MULTISET UNION - "UpperLeftArrow", 0x02196, // NORTH WEST ARROW - "UpperRightArrow", 0x02197, // NORTH EAST ARROW - "upsi", 0x003C5, // GREEK SMALL LETTER UPSILON - "Upsi", 0x003D2, // GREEK UPSILON WITH HOOK SYMBOL - "upsih", 0x003D2, // GREEK UPSILON WITH HOOK SYMBOL - "Upsilon", 0x003A5, // GREEK CAPITAL LETTER UPSILON - "upsilon", 0x003C5, // GREEK SMALL LETTER UPSILON - "UpTee", 0x022A5, // UP TACK - "UpTeeArrow", 0x021A5, // UPWARDS ARROW FROM BAR - "upuparrows", 0x021C8, // UPWARDS PAIRED ARROWS - "urcorn", 0x0231D, // TOP RIGHT CORNER - "urcorner", 0x0231D, // TOP RIGHT CORNER - "urcrop", 0x0230E, // TOP RIGHT CROP - "Uring", 0x0016E, // LATIN CAPITAL LETTER U WITH RING ABOVE - "uring", 0x0016F, // LATIN SMALL LETTER U WITH RING ABOVE - "urtri", 0x025F9, // UPPER RIGHT TRIANGLE - "Uscr", 0x1D4B0, // MATHEMATICAL SCRIPT CAPITAL U - "uscr", 0x1D4CA, // MATHEMATICAL SCRIPT SMALL U - "utdot", 0x022F0, // UP RIGHT DIAGONAL ELLIPSIS - "Utilde", 0x00168, // LATIN CAPITAL LETTER U WITH TILDE - "utilde", 0x00169, // LATIN SMALL LETTER U WITH TILDE - "utri", 0x025B5, // WHITE UP-POINTING SMALL TRIANGLE - "utrif", 0x025B4, // BLACK UP-POINTING SMALL TRIANGLE - "uuarr", 0x021C8, // UPWARDS PAIRED ARROWS - "Uuml", 0x000DC, // LATIN CAPITAL LETTER U WITH DIAERESIS - "uuml", 0x000FC, // LATIN SMALL LETTER U WITH DIAERESIS - "uwangle", 0x029A7, // OBLIQUE ANGLE OPENING DOWN - NULL, 0 -}; - -static NameId namesV[]={ - "vangrt", 0x0299C, // RIGHT ANGLE VARIANT WITH SQUARE - "varepsilon", 0x003F5, // GREEK LUNATE EPSILON SYMBOL - "varkappa", 0x003F0, // GREEK KAPPA SYMBOL - "varnothing", 0x02205, // EMPTY SET - "varphi", 0x003D5, // GREEK PHI SYMBOL - "varpi", 0x003D6, // GREEK PI SYMBOL - "varpropto", 0x0221D, // PROPORTIONAL TO - "varr", 0x02195, // UP DOWN ARROW - "vArr", 0x021D5, // UP DOWN DOUBLE ARROW - "varrho", 0x003F1, // GREEK RHO SYMBOL - "varsigma", 0x003C2, // GREEK SMALL LETTER FINAL SIGMA -// "varsubsetneq", 0x0228A;0x0FE00, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -// "varsubsetneqq", 0x02ACB;0x0FE00, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members -// "varsupsetneq", 0x0228B;0x0FE00, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -// "varsupsetneqq", 0x02ACC;0x0FE00, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members - "vartheta", 0x003D1, // GREEK THETA SYMBOL - "vartriangleleft", 0x022B2, // NORMAL SUBGROUP OF - "vartriangleright", 0x022B3, // CONTAINS AS NORMAL SUBGROUP - "vBar", 0x02AE8, // SHORT UP TACK WITH UNDERBAR - "Vbar", 0x02AEB, // DOUBLE UP TACK - "vBarv", 0x02AE9, // SHORT UP TACK ABOVE SHORT DOWN TACK - "Vcy", 0x00412, // CYRILLIC CAPITAL LETTER VE - "vcy", 0x00432, // CYRILLIC SMALL LETTER VE - "vdash", 0x022A2, // RIGHT TACK - "vDash", 0x022A8, // TRUE - "Vdash", 0x022A9, // FORCES - "VDash", 0x022AB, // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE - "Vdashl", 0x02AE6, // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL - "vee", 0x02228, // LOGICAL OR - "Vee", 0x022C1, // N-ARY LOGICAL OR - "veebar", 0x022BB, // XOR - "veeeq", 0x0225A, // EQUIANGULAR TO - "vellip", 0x022EE, // VERTICAL ELLIPSIS - "verbar", 0x0007C, // VERTICAL LINE - "Verbar", 0x02016, // DOUBLE VERTICAL LINE - "vert", 0x0007C, // VERTICAL LINE - "Vert", 0x02016, // DOUBLE VERTICAL LINE - "VerticalBar", 0x02223, // DIVIDES - "VerticalLine", 0x0007C, // VERTICAL LINE - "VerticalSeparator", 0x02758, // LIGHT VERTICAL BAR - "VerticalTilde", 0x02240, // WREATH PRODUCT - "VeryThinSpace", 0x0200A, // HAIR SPACE - "Vfr", 0x1D519, // MATHEMATICAL FRAKTUR CAPITAL V - "vfr", 0x1D533, // MATHEMATICAL FRAKTUR SMALL V - "vltri", 0x022B2, // NORMAL SUBGROUP OF -// "vnsub", 0x02282;0x020D2, // SUBSET OF with vertical line -// "vnsup", 0x02283;0x020D2, // SUPERSET OF with vertical line - "Vopf", 0x1D54D, // MATHEMATICAL DOUBLE-STRUCK CAPITAL V - "vopf", 0x1D567, // MATHEMATICAL DOUBLE-STRUCK SMALL V - "vprop", 0x0221D, // PROPORTIONAL TO - "vrtri", 0x022B3, // CONTAINS AS NORMAL SUBGROUP - "Vscr", 0x1D4B1, // MATHEMATICAL SCRIPT CAPITAL V - "vscr", 0x1D4CB, // MATHEMATICAL SCRIPT SMALL V -// "vsubne", 0x0228A;0x0FE00, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -// "vsubnE", 0x02ACB;0x0FE00, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members -// "vsupne", 0x0228B;0x0FE00, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -// "vsupnE", 0x02ACC;0x0FE00, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members - "Vvdash", 0x022AA, // TRIPLE VERTICAL BAR RIGHT TURNSTILE - "vzigzag", 0x0299A, // VERTICAL ZIGZAG LINE - NULL, 0 -}; - -static NameId namesW[]={ - "Wcirc", 0x00174, // LATIN CAPITAL LETTER W WITH CIRCUMFLEX - "wcirc", 0x00175, // LATIN SMALL LETTER W WITH CIRCUMFLEX - "wedbar", 0x02A5F, // LOGICAL AND WITH UNDERBAR - "wedge", 0x02227, // LOGICAL AND - "Wedge", 0x022C0, // N-ARY LOGICAL AND - "wedgeq", 0x02259, // ESTIMATES - "weierp", 0x02118, // SCRIPT CAPITAL P - "Wfr", 0x1D51A, // MATHEMATICAL FRAKTUR CAPITAL W - "wfr", 0x1D534, // MATHEMATICAL FRAKTUR SMALL W - "Wopf", 0x1D54E, // MATHEMATICAL DOUBLE-STRUCK CAPITAL W - "wopf", 0x1D568, // MATHEMATICAL DOUBLE-STRUCK SMALL W - "wp", 0x02118, // SCRIPT CAPITAL P - "wr", 0x02240, // WREATH PRODUCT - "wreath", 0x02240, // WREATH PRODUCT - "Wscr", 0x1D4B2, // MATHEMATICAL SCRIPT CAPITAL W - "wscr", 0x1D4CC, // MATHEMATICAL SCRIPT SMALL W - NULL, 0 -}; - -static NameId namesX[]={ - "xcap", 0x022C2, // N-ARY INTERSECTION - "xcirc", 0x025EF, // LARGE CIRCLE - "xcup", 0x022C3, // N-ARY UNION - "xdtri", 0x025BD, // WHITE DOWN-POINTING TRIANGLE - "Xfr", 0x1D51B, // MATHEMATICAL FRAKTUR CAPITAL X - "xfr", 0x1D535, // MATHEMATICAL FRAKTUR SMALL X - "Xgr", 0x0039E, // GREEK CAPITAL LETTER XI - "xgr", 0x003BE, // GREEK SMALL LETTER XI - "xharr", 0x027F7, // LONG LEFT RIGHT ARROW - "xhArr", 0x027FA, // LONG LEFT RIGHT DOUBLE ARROW - "Xi", 0x0039E, // GREEK CAPITAL LETTER XI - "xi", 0x003BE, // GREEK SMALL LETTER XI - "xlarr", 0x027F5, // LONG LEFTWARDS ARROW - "xlArr", 0x027F8, // LONG LEFTWARDS DOUBLE ARROW - "xmap", 0x027FC, // LONG RIGHTWARDS ARROW FROM BAR - "xnis", 0x022FB, // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - "xodot", 0x02A00, // N-ARY CIRCLED DOT OPERATOR - "Xopf", 0x1D54F, // MATHEMATICAL DOUBLE-STRUCK CAPITAL X - "xopf", 0x1D569, // MATHEMATICAL DOUBLE-STRUCK SMALL X - "xoplus", 0x02A01, // N-ARY CIRCLED PLUS OPERATOR - "xotime", 0x02A02, // N-ARY CIRCLED TIMES OPERATOR - "xrarr", 0x027F6, // LONG RIGHTWARDS ARROW - "xrArr", 0x027F9, // LONG RIGHTWARDS DOUBLE ARROW - "Xscr", 0x1D4B3, // MATHEMATICAL SCRIPT CAPITAL X - "xscr", 0x1D4CD, // MATHEMATICAL SCRIPT SMALL X - "xsqcup", 0x02A06, // N-ARY SQUARE UNION OPERATOR - "xuplus", 0x02A04, // N-ARY UNION OPERATOR WITH PLUS - "xutri", 0x025B3, // WHITE UP-POINTING TRIANGLE - "xvee", 0x022C1, // N-ARY LOGICAL OR - "xwedge", 0x022C0, // N-ARY LOGICAL AND - NULL, 0 -}; - -static NameId namesY[]={ - "Yacute", 0x000DD, // LATIN CAPITAL LETTER Y WITH ACUTE - "yacute", 0x000FD, // LATIN SMALL LETTER Y WITH ACUTE - "YAcy", 0x0042F, // CYRILLIC CAPITAL LETTER YA - "yacy", 0x0044F, // CYRILLIC SMALL LETTER YA - "Ycirc", 0x00176, // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX - "ycirc", 0x00177, // LATIN SMALL LETTER Y WITH CIRCUMFLEX - "Ycy", 0x0042B, // CYRILLIC CAPITAL LETTER YERU - "ycy", 0x0044B, // CYRILLIC SMALL LETTER YERU - "yen", 0x000A5, // YEN SIGN - "Yfr", 0x1D51C, // MATHEMATICAL FRAKTUR CAPITAL Y - "yfr", 0x1D536, // MATHEMATICAL FRAKTUR SMALL Y - "YIcy", 0x00407, // CYRILLIC CAPITAL LETTER YI - "yicy", 0x00457, // CYRILLIC SMALL LETTER YI - "Yopf", 0x1D550, // MATHEMATICAL DOUBLE-STRUCK CAPITAL Y - "yopf", 0x1D56A, // MATHEMATICAL DOUBLE-STRUCK SMALL Y - "Yscr", 0x1D4B4, // MATHEMATICAL SCRIPT CAPITAL Y - "yscr", 0x1D4CE, // MATHEMATICAL SCRIPT SMALL Y - "YUcy", 0x0042E, // CYRILLIC CAPITAL LETTER YU - "yucy", 0x0044E, // CYRILLIC SMALL LETTER YU - "yuml", 0x000FF, // LATIN SMALL LETTER Y WITH DIAERESIS - "Yuml", 0x00178, // LATIN CAPITAL LETTER Y WITH DIAERESIS - NULL, 0 -}; - -static NameId namesZ[]={ - "Zacute", 0x00179, // LATIN CAPITAL LETTER Z WITH ACUTE - "zacute", 0x0017A, // LATIN SMALL LETTER Z WITH ACUTE - "Zcaron", 0x0017D, // LATIN CAPITAL LETTER Z WITH CARON - "zcaron", 0x0017E, // LATIN SMALL LETTER Z WITH CARON - "Zcy", 0x00417, // CYRILLIC CAPITAL LETTER ZE - "zcy", 0x00437, // CYRILLIC SMALL LETTER ZE - "Zdot", 0x0017B, // LATIN CAPITAL LETTER Z WITH DOT ABOVE - "zdot", 0x0017C, // LATIN SMALL LETTER Z WITH DOT ABOVE - "zeetrf", 0x02128, // BLACK-LETTER CAPITAL Z - "ZeroWidthSpace", 0x0200B, // ZERO WIDTH SPACE - "Zeta", 0x00396, // GREEK CAPITAL LETTER ZETA - "zeta", 0x003B6, // GREEK SMALL LETTER ZETA - "Zfr", 0x02128, // BLACK-LETTER CAPITAL Z - "zfr", 0x1D537, // MATHEMATICAL FRAKTUR SMALL Z - "Zgr", 0x00396, // GREEK CAPITAL LETTER ZETA - "zgr", 0x003B6, // GREEK SMALL LETTER ZETA - "ZHcy", 0x00416, // CYRILLIC CAPITAL LETTER ZHE - "zhcy", 0x00436, // CYRILLIC SMALL LETTER ZHE - "zigrarr", 0x021DD, // RIGHTWARDS SQUIGGLE ARROW - "Zopf", 0x02124, // DOUBLE-STRUCK CAPITAL Z - "zopf", 0x1D56B, // MATHEMATICAL DOUBLE-STRUCK SMALL Z - "Zscr", 0x1D4B5, // MATHEMATICAL SCRIPT CAPITAL Z - "zscr", 0x1D4CF, // MATHEMATICAL SCRIPT SMALL Z - "zwj", 0x0200D, // ZERO WIDTH JOINER - "zwnj", 0x0200C, // ZERO WIDTH NON-JOINER - NULL, 0 -}; - -// @todo@ order namesTable and names? by frequency -static NameId* namesTable[] = { - namesA, namesB, namesC, namesD, namesE, namesF, namesG, namesH, namesI, - namesJ, namesK, namesL, namesM, namesN, namesO, namesP, namesQ, namesR, - namesS, namesT, namesU, namesV, namesW, namesX, namesY, namesZ, NULL -}; - -int HtmlNamedEntity(unsigned char *p, int length) -{ - int tableIndex = tolower(*p) - 'a'; - if (tableIndex >= 0 && tableIndex < 26) - { - NameId* names = namesTable[tableIndex]; - int i; - - for (i = 0; names[i].name; i++) - { - if (strncmp(names[i].name, (char *)p, length) == 0) - return names[i].value; - } - } - return -1; -} - diff --git a/dmd/enum.c b/dmd/enum.c deleted file mode 100644 index 7c0c40bd..00000000 --- a/dmd/enum.c +++ /dev/null @@ -1,373 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" -#include "enum.h" -#include "mtype.h" -#include "scope.h" -#include "module.h" -#include "declaration.h" - -/********************************* EnumDeclaration ****************************/ - -EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype) - : ScopeDsymbol(id) -{ - this->loc = loc; - type = new TypeEnum(this); - this->memtype = memtype; - maxval = 0; - minval = 0; - defaultval = 0; -#if IN_DMD - sinit = NULL; -#endif - isdeprecated = 0; - isdone = 0; -} - -Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s) -{ - Type *t = NULL; - if (memtype) - t = memtype->syntaxCopy(); - - EnumDeclaration *ed; - if (s) - { ed = (EnumDeclaration *)s; - ed->memtype = t; - } - else - ed = new EnumDeclaration(loc, ident, t); - ScopeDsymbol::syntaxCopy(ed); - return ed; -} - -void EnumDeclaration::semantic0(Scope *sc) -{ - /* This function is a hack to get around a significant problem. - * The members of anonymous enums, like: - * enum { A, B, C } - * don't get installed into the symbol table until after they are - * semantically analyzed, yet they're supposed to go into the enclosing - * scope's table. Hence, when forward referenced, they come out as - * 'undefined'. The real fix is to add them in at addSymbol() time. - * But to get code to compile, we'll just do this quick hack at the moment - * to compile it if it doesn't depend on anything else. - */ - - if (isdone || !scope) - return; - if (!isAnonymous() || memtype) - return; - for (size_t i = 0; i < members->dim; i++) - { - EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); - if (em && em->value) - return; - } - - // Can do it - semantic(sc); -} - -void EnumDeclaration::semantic(Scope *sc) -{ - uinteger_t number; - Type *t; - Scope *sce; - - //printf("EnumDeclaration::semantic(sd = %p, '%s')\n", sc->scopesym, sc->scopesym->toChars()); - if (!memtype) - memtype = Type::tint32; - - if (symtab) // if already done - { if (isdone || !scope) - return; // semantic() already completed - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - unsigned dprogress_save = Module::dprogress; - - if (sc->stc & STCdeprecated) - isdeprecated = 1; - - parent = sc->scopesym; - memtype = memtype->semantic(loc, sc); - - /* Check to see if memtype is forward referenced - */ - if (memtype->ty == Tenum) - { EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc); - if (!sym->memtype) - { - error("base enum %s is forward referenced", sym->toChars()); - memtype = Type::tint32; - } - } - - if (!memtype->isintegral()) - { error("base type must be of integral type, not %s", memtype->toChars()); - memtype = Type::tint32; - } - - isdone = 1; - Module::dprogress++; - - t = isAnonymous() ? memtype : type; - symtab = new DsymbolTable(); - sce = sc->push(this); - sce->parent = this; - number = 0; - if (!members) // enum ident; - return; - if (members->dim == 0) - error("enum %s must have at least one member", toChars()); - int first = 1; - for (size_t i = 0; i < members->dim; i++) - { - EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); - Expression *e; - - if (!em) - /* The e->semantic(sce) can insert other symbols, such as - * template instances and function literals. - */ - continue; - - //printf("Enum member '%s'\n",em->toChars()); - e = em->value; - if (e) - { - assert(e->dyncast() == DYNCAST_EXPRESSION); - e = e->semantic(sce); - e = e->optimize(WANTvalue); - // Need to copy it because we're going to change the type - e = e->copy(); - e = e->implicitCastTo(sc, memtype); - e = e->optimize(WANTvalue); - number = e->toInteger(); - e->type = t; - } - else - { // Default is the previous number plus 1 - - // Check for overflow - if (!first) - { - switch (t->toBasetype()->ty) - { - case Tbool: - if (number == 2) goto Loverflow; - break; - - case Tint8: - if (number == 128) goto Loverflow; - break; - - case Tchar: - case Tuns8: - if (number == 256) goto Loverflow; - break; - - case Tint16: - if (number == 0x8000) goto Loverflow; - break; - - case Twchar: - case Tuns16: - if (number == 0x10000) goto Loverflow; - break; - - case Tint32: - if (number == 0x80000000) goto Loverflow; - break; - - case Tdchar: - case Tuns32: - if (number == 0x100000000LL) goto Loverflow; - break; - - case Tint64: - if (number == 0x8000000000000000LL) goto Loverflow; - break; - - case Tuns64: - if (number == 0) goto Loverflow; - break; - - Loverflow: - error("overflow of enum value"); - break; - - default: - assert(0); - } - } - e = new IntegerExp(em->loc, number, t); - } - em->value = e; - - // Add to symbol table only after evaluating 'value' - if (isAnonymous()) - { - //sce->enclosing->insert(em); - for (Scope *sct = sce->enclosing; sct; sct = sct->enclosing) - { - if (sct->scopesym) - { - if (!sct->scopesym->symtab) - sct->scopesym->symtab = new DsymbolTable(); - em->addMember(sce, sct->scopesym, 1); - break; - } - } - } - else - em->addMember(sc, this, 1); - - if (first) - { first = 0; - defaultval = number; - minval = number; - maxval = number; - } - else if (memtype->isunsigned()) - { - if (number < minval) - minval = number; - if (number > maxval) - maxval = number; - } - else - { - if ((sinteger_t)number < (sinteger_t)minval) - minval = number; - if ((sinteger_t)number > (sinteger_t)maxval) - maxval = number; - } - - number++; - } - //printf("defaultval = %lld\n", defaultval); - - sce->pop(); - //members->print(); -} - -int EnumDeclaration::oneMember(Dsymbol **ps) -{ - if (isAnonymous()) - return Dsymbol::oneMembers(members, ps); - return Dsymbol::oneMember(ps); -} - -void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("enum "); - if (ident) - { buf->writestring(ident->toChars()); - buf->writeByte(' '); - } - if (memtype) - { - buf->writestring(": "); - memtype->toCBuffer(buf, NULL, hgs); - } - if (!members) - { - buf->writeByte(';'); - buf->writenl(); - return; - } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (size_t i = 0; i < members->dim; i++) - { - EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); - if (!em) - continue; - //buf->writestring(" "); - em->toCBuffer(buf, hgs); - buf->writeByte(','); - buf->writenl(); - } - buf->writeByte('}'); - buf->writenl(); -} - -Type *EnumDeclaration::getType() -{ - return type; -} - -const char *EnumDeclaration::kind() -{ - return "enum"; -} - -int EnumDeclaration::isDeprecated() -{ - return isdeprecated; -} - -/********************************* EnumMember ****************************/ - -EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value) - : Dsymbol(id) -{ - this->value = value; - this->loc = loc; -} - -Dsymbol *EnumMember::syntaxCopy(Dsymbol *s) -{ - Expression *e = NULL; - if (value) - e = value->syntaxCopy(); - - EnumMember *em; - if (s) - { em = (EnumMember *)s; - em->loc = loc; - em->value = e; - } - else - em = new EnumMember(loc, ident, e); - return em; -} - -void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - if (value) - { - buf->writestring(" = "); - value->toCBuffer(buf, hgs); - } -} - -const char *EnumMember::kind() -{ - return "enum member"; -} - - diff --git a/dmd/enum.h b/dmd/enum.h deleted file mode 100644 index 439211d1..00000000 --- a/dmd/enum.h +++ /dev/null @@ -1,96 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_ENUM_H -#define DMD_ENUM_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "dsymbol.h" - -struct Identifier; -struct Type; -struct Expression; -struct HdrGenState; - - -struct EnumDeclaration : ScopeDsymbol -{ /* enum ident : memtype { ... } - */ - Type *type; // the TypeEnum - Type *memtype; // type of the members - -#if DMDV1 - dinteger_t maxval; - dinteger_t minval; - dinteger_t defaultval; // default initializer -#else - Expression *maxval; - Expression *minval; - Expression *defaultval; // default initializer -#endif - int isdeprecated; - int isdone; // 0: not done - // 1: semantic() successfully completed - - EnumDeclaration(Loc loc, Identifier *id, Type *memtype); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic0(Scope *sc); - void semantic(Scope *sc); - int oneMember(Dsymbol **ps); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *getType(); - const char *kind(); -#if DMDV2 - Dsymbol *search(Loc, Identifier *ident, int flags); -#endif - int isDeprecated(); // is Dsymbol deprecated? - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toDocBuffer(OutBuffer *buf); - - EnumDeclaration *isEnumDeclaration() { return this; } - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - int cvMember(unsigned char *p); - - Symbol *sinit; - Symbol *toInitializer(); -#endif - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - - -struct EnumMember : Dsymbol -{ - Expression *value; - - EnumMember(Loc loc, Identifier *id, Expression *value); - Dsymbol *syntaxCopy(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toDocBuffer(OutBuffer *buf); - - EnumMember *isEnumMember() { return this; } -}; - -#endif /* DMD_ENUM_H */ diff --git a/dmd/expression.c b/dmd/expression.c deleted file mode 100644 index f8ab2052..00000000 --- a/dmd/expression.c +++ /dev/null @@ -1,10664 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include -#if _MSC_VER -#include -#else -#include -#endif - -#if _WIN32 && __DMC__ -extern "C" char * __cdecl __locale_decpoint; -#endif - -#if __MINGW32__ -#ifndef isnan -#define isnan _isnan -#endif -#endif - -#ifdef __APPLE__ -#ifndef isnan -int isnan(double); -#endif -#endif - -#include "rmem.h" -#include "port.h" - -#include "mtype.h" -#include "init.h" -#include "expression.h" -#include "template.h" -#include "utf.h" -#include "enum.h" -#include "scope.h" -#include "statement.h" -#include "declaration.h" -#include "aggregate.h" -#include "import.h" -#include "id.h" -#include "dsymbol.h" -#include "module.h" -#include "attrib.h" -#include "hdrgen.h" -#include "parse.h" -#include "doc.h" - - -Expression *createTypeInfoArray(Scope *sc, Expression *args[], unsigned dim); -Expression *expandVar(int result, VarDeclaration *v); - -#define LOGSEMANTIC 0 - -/************************************************************* - * Given var, we need to get the - * right 'this' pointer if var is in an outer class, but our - * existing 'this' pointer is in an inner class. - * Input: - * e1 existing 'this' - * ad struct or class we need the correct 'this' for - * var the specific member of ad we're accessing - */ - -Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, - Expression *e1, Declaration *var) -{ - //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars()); - L1: - Type *t = e1->type->toBasetype(); - //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars()); - - /* If e1 is not the 'this' pointer for ad - */ - if (ad && - !(t->ty == Tpointer && t->nextOf()->ty == Tstruct && - ((TypeStruct *)t->nextOf())->sym == ad) - && - !(t->ty == Tstruct && - ((TypeStruct *)t)->sym == ad) - ) - { - ClassDeclaration *cd = ad->isClassDeclaration(); - ClassDeclaration *tcd = t->isClassHandle(); - - /* e1 is the right this if ad is a base class of e1 - */ - if (!cd || !tcd || - !(tcd == cd || cd->isBaseOf(tcd, NULL)) - ) - { - /* Only classes can be inner classes with an 'outer' - * member pointing to the enclosing class instance - */ - if (tcd && tcd->isNested()) - { /* e1 is the 'this' pointer for an inner class: tcd. - * Rewrite it as the 'this' pointer for the outer class. - */ - - e1 = new DotVarExp(loc, e1, tcd->vthis); - e1->type = tcd->vthis->type; - // Do not call checkNestedRef() - //e1 = e1->semantic(sc); - - // Skip up over nested functions, and get the enclosing - // class type. - int n = 0; - Dsymbol *s; - for (s = tcd->toParent(); - s && s->isFuncDeclaration(); - s = s->toParent()) - { FuncDeclaration *f = s->isFuncDeclaration(); - if (f->vthis) - { - //printf("rewriting e1 to %s's this\n", f->toChars()); - n++; - - // LDC seems dmd misses it sometimes here :/ - f->vthis->nestedref = 1; - - e1 = new VarExp(loc, f->vthis); - } - else - { - e1->error("need 'this' of type %s to access member %s" - " from static function %s", - ad->toChars(), var->toChars(), f->toChars()); - e1 = new ErrorExp(); - return e1; - } - } - if (s && s->isClassDeclaration()) - { e1->type = s->isClassDeclaration()->type; - if (n > 1) - e1 = e1->semantic(sc); - } - else - e1 = e1->semantic(sc); - goto L1; - } - /* Can't find a path from e1 to ad - */ - e1->error("this for %s needs to be type %s not type %s", - var->toChars(), ad->toChars(), t->toChars()); - e1 = new ErrorExp(); - } - } - return e1; -} - -/***************************************** - * Determine if 'this' is available. - * If it is, return the FuncDeclaration that has it. - */ - -FuncDeclaration *hasThis(Scope *sc) -{ FuncDeclaration *fd; - FuncDeclaration *fdthis; - - //printf("hasThis()\n"); - fdthis = sc->parent->isFuncDeclaration(); - //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : ""); - - // Go upwards until we find the enclosing member function - fd = fdthis; - while (1) - { - if (!fd) - { - goto Lno; - } - if (!fd->isNested()) - break; - - Dsymbol *parent = fd->parent; - while (1) - { - if (!parent) - goto Lno; - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - parent = ti->parent; - else - break; - } - fd = parent->isFuncDeclaration(); - } - - if (!fd->isThis()) - { //printf("test '%s'\n", fd->toChars()); - goto Lno; - } - - assert(fd->vthis); - return fd; - -Lno: - return NULL; // don't have 'this' available -} - - -/*************************************** - * Pull out any properties. - */ - -Expression *resolveProperties(Scope *sc, Expression *e) -{ - //printf("resolveProperties(%s)\n", e->toChars()); - if (e->type) - { - Type *t = e->type->toBasetype(); - - if (t->ty == Tfunction /*|| e->op == TOKoverloadset*/) - { - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - - /* Look for e being a lazy parameter; rewrite as delegate call - */ - else if (e->op == TOKvar) - { VarExp *ve = (VarExp *)e; - - if (ve->var->storage_class & STClazy) - { - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - } - - else if (e->op == TOKdotexp) - { - e->error("expression has no value"); - return new ErrorExp(); - } - - } - else if (e->op == TOKdottd) - { - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - return e; -} - -/****************************** - * Perform semantic() on an array of Expressions. - */ - -Expressions *arrayExpressionSemantic(Expressions *exps, Scope *sc) -{ - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - if (e) - { e = e->semantic(sc); - exps->data[i] = (void *)e; - } - } - } - return exps; -} - - -/****************************** - * Perform canThrow() on an array of Expressions. - */ - -#if DMDV2 -int arrayExpressionCanThrow(Expressions *exps) -{ - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - if (e && e->canThrow()) - return 1; - } - } - return 0; -} -#endif - -/**************************************** - * Expand tuples. - */ - -void expandTuples(Expressions *exps) -{ - //printf("expandTuples()\n"); - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *arg = (Expression *)exps->data[i]; - if (!arg) - continue; - - // Look for tuple with 0 members - if (arg->op == TOKtype) - { TypeExp *e = (TypeExp *)arg; - if (e->type->toBasetype()->ty == Ttuple) - { TypeTuple *tt = (TypeTuple *)e->type->toBasetype(); - - if (!tt->arguments || tt->arguments->dim == 0) - { - exps->remove(i); - if (i == exps->dim) - return; - i--; - continue; - } - } - } - - // Inline expand all the tuples - while (arg->op == TOKtuple) - { TupleExp *te = (TupleExp *)arg; - - exps->remove(i); // remove arg - exps->insert(i, te->exps); // replace with tuple contents - if (i == exps->dim) - return; // empty tuple, no more arguments - arg = (Expression *)exps->data[i]; - } - } - } -} - -Expressions *arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt) -{ -#if DMDV1 - /* The first element sets the type - */ - Type *t0 = NULL; - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - - if (!e->type) - { error(e->loc, "%s has no value", e->toChars()); - e = new ErrorExp(); - } - e = resolveProperties(sc, e); - - if (!t0) - t0 = e->type; - else - e = e->implicitCastTo(sc, t0); - (*exps)[i] = e; - } - - if (!t0) - t0 = Type::tvoid; - if (pt) - *pt = t0; - - // Eventually, we want to make this copy-on-write - return exps; -#endif -#if DMDV2 - /* The type is determined by applying ?: to each pair. - */ - /* Still have a problem with: - * ubyte[][] = [ cast(ubyte[])"hello", [1]]; - * which works if the array literal is initialized top down with the ubyte[][] - * type, but fails with this function doing bottom up typing. - */ - //printf("arrayExpressionToCommonType()\n"); - IntegerExp integerexp(0); - CondExp condexp(0, &integerexp, NULL, NULL); - - Type *t0 = NULL; - Expression *e0; - int j0; - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - - e = resolveProperties(sc, e); - if (!e->type) - { e->error("%s has no value", e->toChars()); - e = new ErrorExp(); - } - - if (t0) - { if (t0 != e->type) - { - /* This applies ?: to merge the types. It's backwards; - * ?: should call this function to merge types. - */ - condexp.type = NULL; - condexp.e1 = e0; - condexp.e2 = e; - condexp.loc = e->loc; - condexp.semantic(sc); - (*exps)[j0] = condexp.e1; - e = condexp.e2; - j0 = i; - e0 = e; - t0 = e0->type; - } - } - else - { j0 = i; - e0 = e; - t0 = e->type; - } - (*exps)[i] = e; - } - - if (t0) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - e = e->implicitCastTo(sc, t0); - (*exps)[i] = e; - } - } - else - t0 = Type::tvoid; // [] is typed as void[] - if (pt) - *pt = t0; - - // Eventually, we want to make this copy-on-write - return exps; -#endif -} - -/**************************************** - * Get TemplateDeclaration enclosing FuncDeclaration. - */ - -TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s) -{ - FuncDeclaration *f = s->isFuncDeclaration(); - if (f && f->parent) - { TemplateInstance *ti = f->parent->isTemplateInstance(); - - if (ti && - !ti->isTemplateMixin() && - (ti->name == f->ident || - ti->toAlias()->ident == f->ident) - && - ti->tempdecl && ti->tempdecl->onemember) - { - return ti->tempdecl; - } - } - return NULL; -} - -/**************************************** - * Preprocess arguments to function. - */ - -void preFunctionParameters(Loc loc, Scope *sc, Expressions *exps) -{ - if (exps) - { - expandTuples(exps); - - for (size_t i = 0; i < exps->dim; i++) - { Expression *arg = (*exps)[i]; - - if (!arg->type) - { -#ifdef DEBUG - if (!global.gag) - printf("1: \n"); -#endif - arg->error("%s is not an expression", arg->toChars()); - arg = new ErrorExp(); - } - - arg = resolveProperties(sc, arg); - (*exps)[i] = arg; - - //arg->rvalue(); -#if 0 - if (arg->type->ty == Tfunction) - { - arg = new AddrExp(arg->loc, arg); - arg = arg->semantic(sc); - (*exps)[i] = arg; - } -#endif - } - } -} - -/********************************************* - * Call copy constructor for struct value argument. - */ -#if DMDV2 -Expression *callCpCtor(Loc loc, Scope *sc, Expression *e) -{ - Type *tb = e->type->toBasetype(); - assert(tb->ty == Tstruct); - StructDeclaration *sd = ((TypeStruct *)tb)->sym; - if (sd->cpctor) - { - /* Create a variable tmp, and replace the argument e with: - * (tmp = e),tmp - * and let AssignExp() handle the construction. - * This is not the most efficent, ideally tmp would be constructed - * directly onto the stack. - */ - Identifier *idtmp = Lexer::uniqueId("__tmp"); - VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e)); - tmp->storage_class |= STCctfe; - Expression *ae = new DeclarationExp(loc, tmp); - e = new CommaExp(loc, ae, new VarExp(loc, tmp)); - e = e->semantic(sc); - } - return e; -} -#endif - -/**************************************** - * Now that we know the exact type of the function we're calling, - * the arguments[] need to be adjusted: - * 1. implicitly convert argument to the corresponding parameter type - * 2. add default arguments for any missing arguments - * 3. do default promotions on arguments corresponding to ... - * 4. add hidden _arguments[] argument - */ - -void functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments) -{ - //printf("functionParameters()\n"); - assert(arguments); - size_t nargs = arguments ? arguments->dim : 0; - size_t nparams = Parameter::dim(tf->parameters); - - if (nargs > nparams && tf->varargs == 0) - error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf->toChars()); - -#if DMDV2 - // If inferring return type, and semantic3() needs to be run if not already run - if (!tf->next && fd->inferRetType) - { - TemplateInstance *spec = fd->isSpeculative(); - int olderrs = global.errors; - fd->semantic3(fd->scope); - // Update the template instantiation with the number - // of errors which occured. - if (spec && global.errors != olderrs) - spec->errors = global.errors - olderrs; - } -#endif - - unsigned n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) - - int done = 0; - for (size_t i = 0; i < n; i++) - { - Expression *arg; - - if (i < nargs) - arg = (*arguments)[i]; - else - arg = NULL; - - if (i < nparams) - { - Parameter *p = Parameter::getNth(tf->parameters, i); - - if (!arg) - { - if (!p->defaultArg) - { - if (tf->varargs == 2 && i + 1 == nparams) - goto L2; - error(loc, "expected %zu function arguments, not %zu", nparams, nargs); - return; - } - arg = p->defaultArg; - arg = arg->inlineCopy(sc); -#if DMDV2 - arg = arg->resolveLoc(loc, sc); // __FILE__ and __LINE__ -#endif - arguments->push(arg); - nargs++; - } - - if (tf->varargs == 2 && i + 1 == nparams) - { - //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars()); - MATCH m; - if ((m = arg->implicitConvTo(p->type)) != MATCHnomatch) - { - if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()) >= m) - goto L2; - else if (nargs != nparams) - { error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs); - return; - } - goto L1; - } - L2: - Type *tb = p->type->toBasetype(); - Type *tret = p->isLazyArray(); - switch (tb->ty) - { - case Tsarray: - case Tarray: - { // Create a static array variable v of type arg->type -#ifdef IN_GCC - /* GCC 4.0 does not like zero length arrays used like - this; pass a null array value instead. Could also - just make a one-element array. */ - if (nargs - i == 0) - { - arg = new NullExp(loc); - break; - } -#endif - Identifier *id = Lexer::uniqueId("__arrayArg"); - Type *t = new TypeSArray(((TypeArray *)tb)->next, new IntegerExp(nargs - i)); - t = t->semantic(loc, sc); - VarDeclaration *v = new VarDeclaration(loc, t, id, new VoidInitializer(loc)); - v->storage_class |= STCctfe; - v->semantic(sc); - v->parent = sc->parent; - //sc->insert(v); - - Expression *c = new DeclarationExp(0, v); - c->type = v->type; - - for (size_t u = i; u < nargs; u++) - { Expression *a = (*arguments)[u]; - if (tret && !((TypeArray *)tb)->next->equals(a->type)) - a = a->toDelegate(sc, tret); - - Expression *e = new VarExp(loc, v); - e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams)); - AssignExp *ae = new AssignExp(loc, e, a); - if (c) - c = new CommaExp(loc, c, ae); - else - c = ae; - } - arg = new VarExp(loc, v); - if (c) - arg = new CommaExp(loc, c, arg); - break; - } - case Tclass: - { /* Set arg to be: - * new Tclass(arg0, arg1, ..., argn) - */ - Expressions *args = new Expressions(); - args->setDim(nargs - i); - for (size_t u = i; u < nargs; u++) - args->data[u - i] = arguments->data[u]; - arg = new NewExp(loc, NULL, NULL, p->type, args); - break; - } - default: - if (!arg) - { error(loc, "not enough arguments"); - return; - } - break; - } - arg = arg->semantic(sc); - //printf("\targ = '%s'\n", arg->toChars()); - arguments->setDim(i + 1); - done = 1; - } - - L1: - if (!(p->storageClass & STClazy && p->type->ty == Tvoid)) - { - if (p->type != arg->type) - { - //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars()); - if (arg->op == TOKtype) - arg->error("cannot pass type %s as function argument", arg->toChars()); - arg = arg->implicitCastTo(sc, p->type); - arg = arg->optimize(WANTvalue); - } - } - if (p->storageClass & (STCout | STCref)) - { - // BUG: should check that argument to ref is type 'invariant' - // BUG: assignments to ref should also be type 'invariant' - arg = arg->modifiableLvalue(sc, arg); - - //if (arg->op == TOKslice) - //arg->error("cannot modify slice %s", arg->toChars()); - } - -// LDC we don't want this! -#if !IN_LLVM - // Convert static arrays to pointers - Type *tb = arg->type->toBasetype(); - if (tb->ty == Tsarray) - { - arg = arg->checkToPointer(); - } -#endif -#if DMDV2 - if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout))) - { - if (arg->op == TOKcall) - { - /* The struct value returned from the function is transferred - * to the function, so the callee should not call the destructor - * on it. - */ - valueNoDtor(arg); - } - else - { /* Not transferring it, so call the copy constructor - */ - arg = callCpCtor(loc, sc, arg, 1); - } - } -#endif - - // Convert lazy argument to a delegate - if (p->storageClass & STClazy) - { - arg = arg->toDelegate(sc, p->type); - } -#if DMDV2 - /* Look for arguments that cannot 'escape' from the called - * function. - */ - if (!tf->parameterEscapes(p)) - { - Expression *a = arg; - if (a->op == TOKcast) - a = ((CastExp *)a)->e1; - - /* Function literals can only appear once, so if this - * appearance was scoped, there cannot be any others. - */ - if (a->op == TOKfunction) - { FuncExp *fe = (FuncExp *)a; - fe->fd->tookAddressOf = 0; - } - - /* For passing a delegate to a scoped parameter, - * this doesn't count as taking the address of it. - * We only worry about 'escaping' references to the function. - */ - else if (a->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)a; - if (de->e1->op == TOKvar) - { VarExp *ve = (VarExp *)de->e1; - FuncDeclaration *f = ve->var->isFuncDeclaration(); - if (f) - { f->tookAddressOf--; - //printf("tookAddressOf = %d\n", f->tookAddressOf); - } - } - } - } -#endif - } - else - { - - // If not D linkage, do promotions - // LDC: don't do promotions on intrinsics - if (tf->linkage != LINKd && tf->linkage != LINKintrinsic) - { - // Promote bytes, words, etc., to ints - arg = arg->integralPromotions(sc); - - // Promote floats to doubles - switch (arg->type->ty) - { - case Tfloat32: - arg = arg->castTo(sc, Type::tfloat64); - break; - - case Timaginary32: - arg = arg->castTo(sc, Type::timaginary64); - break; - } - } - - // Convert static arrays to dynamic arrays - // BUG: I don't think this is right for D2 - Type *tb = arg->type->toBasetype(); - if (tb->ty == Tsarray) - { TypeSArray *ts = (TypeSArray *)tb; - Type *ta = ts->next->arrayOf(); - if (ts->size(arg->loc) == 0) - arg = new NullExp(arg->loc, ta); - else - arg = arg->castTo(sc, ta); - } -#if DMDV2 - if (tb->ty == Tstruct) - { - arg = callCpCtor(loc, sc, arg); - } -#endif - - // Give error for overloaded function addresses -#if DMDV2 - if (arg->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)arg; - if ( - se->hasOverloads && - !se->var->isFuncDeclaration()->isUnique()) - arg->error("function %s is overloaded", arg->toChars()); - } -#endif - arg->rvalue(); - } - arg = arg->optimize(WANTvalue); - arguments->data[i] = (void *) arg; - if (done) - break; - } - -#if !IN_LLVM - // If D linkage and variadic, add _arguments[] as first argument - if (tf->linkage == LINKd && tf->varargs == 1) - { - assert(arguments->dim >= nparams); - Expression *e = createTypeInfoArray(sc, (Expression **)&arguments->data[nparams], - arguments->dim - nparams); - arguments->insert(0, e); - } -#endif -} - -/************************************************** - * Write expression out to buf, but wrap it - * in ( ) if its precedence is less than pr. - */ - -void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) -{ -#ifdef DEBUG - if (precedence[e->op] == PREC_zero) - printf("precedence not defined for token '%s'\n",Token::tochars[e->op]); -#endif - assert(precedence[e->op] != PREC_zero); - assert(pr != PREC_zero); - - //if (precedence[e->op] == 0) e->dump(0); - if (precedence[e->op] < pr || - /* Despite precedence, we don't allow aop] == pr)) - { - buf->writeByte('('); - e->toCBuffer(buf, hgs); - buf->writeByte(')'); - } - else - e->toCBuffer(buf, hgs); -} - -/************************************************** - * Write out argument list to buf. - */ - -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) -{ - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *arg = (Expression *)arguments->data[i]; - - if (arg) - { if (i) - buf->writeByte(','); - expToCBuffer(buf, hgs, arg, PREC_assign); - } - } - } -} - -/************************************************** - * Write out argument types to buf. - */ - -void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) -{ - if (arguments) - { OutBuffer argbuf; - - for (size_t i = 0; i < arguments->dim; i++) - { Expression *arg = (Expression *)arguments->data[i]; - - if (i) - buf->writeByte(','); - argbuf.reset(); - arg->type->toCBuffer2(&argbuf, hgs, 0); - buf->write(&argbuf); - } - } -} - -/******************************** Expression **************************/ - -Expression::Expression(Loc loc, enum TOK op, int size) - : loc(loc) -{ - //printf("Expression::Expression(op = %d) this = %p\n", op, this); - this->loc = loc; - this->op = op; - this->size = size; - type = NULL; - -#if IN_LLVM - cachedLvalue = NULL; -#endif -} - -Expression *Expression::syntaxCopy() -{ - //printf("Expression::syntaxCopy()\n"); - //dump(0); - return copy(); -} - -/********************************* - * Does *not* do a deep copy. - */ - -Expression *Expression::copy() -{ - Expression *e; - if (!size) - { -#ifdef DEBUG - fprintf(stdmsg, "No expression copy for: %s\n", toChars()); - printf("op = %d\n", op); - dump(0); -#endif - assert(0); - } - e = (Expression *)mem.malloc(size); - //printf("Expression::copy(op = %d) e = %p\n", op, e); - return (Expression *)memcpy(e, this, size); -} - -/************************** - * Semantically analyze Expression. - * Determine types, fold constants, etc. - */ - -Expression *Expression::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("Expression::semantic() %s\n", toChars()); -#endif - if (type) - type = type->semantic(loc, sc); - else - type = Type::tvoid; - return this; -} - -/********************************** - * Try to run semantic routines. - * If they fail, return NULL. - */ - -Expression *Expression::trySemantic(Scope *sc) -{ - //printf("+trySemantic(%s)\n", toChars()); - unsigned errors = global.startGagging(); - Expression *e = semantic(sc); - if (global.endGagging(errors)) - { - e = NULL; - } - //printf("-trySemantic(%s)\n", toChars()); - return e; -} - -void Expression::print() -{ - fprintf(stdmsg, "%s\n", toChars()); - fflush(stdmsg); -} - -char *Expression::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - memset(&hgs, 0, sizeof(hgs)); - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); -} - -void Expression::error(const char *format, ...) -{ - if (type != Type::terror) - { - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); - } -} - -void Expression::warning(const char *format, ...) -{ - if (type != Type::terror) - { - va_list ap; - va_start(ap, format); - ::vwarning(loc, format, ap); - va_end( ap ); - } -} - -int Expression::rvalue() -{ - if (type && type->toBasetype()->ty == Tvoid) - { error("expression %s is void and has no value", toChars()); -#if 0 - dump(0); - halt(); -#endif - if (!global.gag) - type = Type::terror; - return 0; - } - return 1; -} - -Expression *Expression::combine(Expression *e1, Expression *e2) -{ - if (e1) - { - if (e2) - { - e1 = new CommaExp(e1->loc, e1, e2); - e1->type = e2->type; - } - } - else - e1 = e2; - return e1; -} - -dinteger_t Expression::toInteger() -{ - //printf("Expression %s\n", Token::toChars(op)); - error("Integer constant expression expected instead of %s", toChars()); - return 0; -} - -uinteger_t Expression::toUInteger() -{ - //printf("Expression %s\n", Token::toChars(op)); - return (uinteger_t)toInteger(); -} - -real_t Expression::toReal() -{ - error("Floating point constant expression expected instead of %s", toChars()); - return ldouble(0); -} - -real_t Expression::toImaginary() -{ - error("Floating point constant expression expected instead of %s", toChars()); - return ldouble(0); -} - -complex_t Expression::toComplex() -{ - error("Floating point constant expression expected instead of %s", toChars()); -#ifdef IN_GCC - return complex_t(real_t(0)); // %% nicer -#else - return 0.0; -#endif -} - -StringExp *Expression::toString() -{ - return NULL; -} - -void Expression::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); -} - -void Expression::toMangleBuffer(OutBuffer *buf) -{ - error("expression %s is not a valid template value argument", toChars()); -#ifdef DEBUG -dump(0); -#endif -} - -/*************************************** - * Return !=0 if expression is an lvalue. - */ - -int Expression::isLvalue() -{ - return 0; -} - - -/******************************* - * Give error if we're not an lvalue. - * If we can, convert expression to be an lvalue. - */ - -Expression *Expression::toLvalue(Scope *sc, Expression *e) -{ - if (!e) - e = this; - else if (!loc.filename) - loc = e->loc; - error("%s is not an lvalue", e->toChars()); - return new ErrorExp(); -} - -Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars()); - - // See if this expression is a modifiable lvalue (i.e. not const) -#if DMDV2 - if (type && (!type->isMutable() || !type->isAssignable())) - { error("%s is not mutable", e->toChars()); - return new ErrorExp(); - } -#endif - return toLvalue(sc, e); -} - - -/************************************ - * Detect cases where pointers to the stack can 'escape' the - * lifetime of the stack frame. - */ - -void Expression::checkEscape() -{ -} - -void Expression::checkEscapeRef() -{ -} - -void Expression::checkScalar() -{ - if (!type->isscalar()) - error("'%s' is not a scalar, it is a %s", toChars(), type->toChars()); -} - -void Expression::checkNoBool() -{ - if (type->toBasetype()->ty == Tbool) - error("operation not allowed on bool '%s'", toChars()); -} - -Expression *Expression::checkIntegral() -{ - if (!type->isintegral()) - { error("'%s' is not of integral type, it is a %s", toChars(), type->toChars()); - return new ErrorExp(); - } - return this; -} - -Expression *Expression::checkArithmetic() -{ - if (!type->isintegral() && !type->isfloating()) - { if (type->toBasetype() != Type::terror) - error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars()); - return new ErrorExp(); - } - return this; -} - -void Expression::checkDeprecated(Scope *sc, Dsymbol *s) -{ - s->checkDeprecated(loc, sc); -} - -#if DMDV2 -void Expression::checkPurity(Scope *sc, FuncDeclaration *f) -{ - if (sc->func && sc->func->isPure() && !sc->intypeof && !f->isPure()) - error("pure function '%s' cannot call impure function '%s'\n", - sc->func->toChars(), f->toChars()); -} -#endif - -/******************************** - * Check for expressions that have no use. - * Input: - * flag 0 not going to use the result, so issue error message if no - * side effects - * 1 the result of the expression is used, but still check - * for useless subexpressions - * 2 do not issue error messages, just return !=0 if expression - * has side effects - */ - -int Expression::checkSideEffect(int flag) -{ - if (flag == 0) - { if (op == TOKimport) - { - error("%s has no effect", toChars()); - } - else - error("%s has no effect in expression (%s)", - Token::toChars(op), toChars()); - } - return 0; -} - -/***************************** - * Check that expression can be tested for true or false. - */ - -Expression *Expression::checkToBoolean() -{ - // Default is 'yes' - do nothing - -#ifdef DEBUG - if (!type) - dump(0); -#endif - - if (!type->checkBoolean()) - { - error("expression %s of type %s does not have a boolean value", toChars(), type->toChars()); - } - return this; -} - -/**************************** - */ - -Expression *Expression::checkToPointer() -{ - Expression *e; - Type *tb; - - //printf("Expression::checkToPointer()\n"); - e = this; - - // If C static array, convert to pointer - tb = type->toBasetype(); - if (tb->ty == Tsarray) - { TypeSArray *ts = (TypeSArray *)tb; - if (ts->size(loc) == 0) - e = new NullExp(loc); - else - e = new AddrExp(loc, this); - e->type = ts->next->pointerTo(); - } - return e; -} - -/****************************** - * Take address of expression. - */ - -Expression *Expression::addressOf(Scope *sc) -{ - Expression *e; - Type *t = type; - - //printf("Expression::addressOf()\n"); - e = toLvalue(sc, NULL); - e = new AddrExp(loc, e); - e->type = t->pointerTo(); - return e; -} - -/****************************** - * If this is a reference, dereference it. - */ - -Expression *Expression::deref() -{ - //printf("Expression::deref()\n"); - // type could be null if forward referencing an 'auto' variable - if (type && type->ty == Treference) - { - Expression *e = new PtrExp(loc, this); - e->type = ((TypeReference *)type)->next; - return e; - } - return this; -} - -/******************************** - * Does this expression statically evaluate to a boolean TRUE or FALSE? - */ - -int Expression::isBool(int result) -{ - return FALSE; -} - -/******************************** - * Does this expression result in either a 1 or a 0? - */ - -int Expression::isBit() -{ - return FALSE; -} - -/******************************** - * Can this expression throw an exception? - * Valid only after semantic() pass. - */ - -int Expression::canThrow() -{ -#if DMDV2 - return FALSE; -#else - return TRUE; -#endif -} - - - -Expressions *Expression::arraySyntaxCopy(Expressions *exps) -{ Expressions *a = NULL; - - if (exps) - { - a = new Expressions(); - a->setDim(exps->dim); - for (size_t i = 0; i < a->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - if (e) - e = e->syntaxCopy(); - a->data[i] = e; - } - } - return a; -} - -/******************************** IntegerExp **************************/ - -IntegerExp::IntegerExp(Loc loc, dinteger_t value, Type *type) - : Expression(loc, TOKint64, sizeof(IntegerExp)) -{ - //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : ""); - if (type && !type->isscalar()) - { - //printf("%s, loc = %d\n", toChars(), loc.linnum); - if (type->ty != Terror) - error("integral constant must be scalar type, not %s", type->toChars()); - type = Type::terror; - } - this->type = type; - this->value = value; -} - -IntegerExp::IntegerExp(dinteger_t value) - : Expression(0, TOKint64, sizeof(IntegerExp)) -{ - this->type = Type::tint32; - this->value = value; -} - -int IntegerExp::equals(Object *o) -{ IntegerExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKint64 && - ((ne = (IntegerExp *)o), type->equals(ne->type)) && - value == ne->value)) - return 1; - return 0; -} - -char *IntegerExp::toChars() -{ -#if 1 - return Expression::toChars(); -#else - static char buffer[sizeof(value) * 3 + 1]; - - sprintf(buffer, "%jd", value); - return buffer; -#endif -} - -dinteger_t IntegerExp::toInteger() -{ Type *t; - - t = type; - while (t) - { - switch (t->ty) - { - case Tbit: - case Tbool: value = (value != 0); break; - case Tint8: value = (d_int8) value; break; - case Tchar: - case Tuns8: value = (d_uns8) value; break; - case Tint16: value = (d_int16) value; break; - case Twchar: - case Tuns16: value = (d_uns16) value; break; - case Tint32: value = (d_int32) value; break; - case Tdchar: - case Tuns32: value = (d_uns32) value; break; - case Tint64: value = (d_int64) value; break; - case Tuns64: value = (d_uns64) value; break; - case Tpointer: - if (PTRSIZE == 4) - value = (d_uns32) value; - else if (PTRSIZE == 8) - value = (d_uns64) value; - else - assert(0); - break; - - case Tenum: - { - TypeEnum *te = (TypeEnum *)t; - t = te->sym->memtype; - continue; - } - - case Ttypedef: - { - TypeTypedef *tt = (TypeTypedef *)t; - t = tt->sym->basetype; - continue; - } - - default: - /* This can happen if errors, such as - * the type is painted on like in fromConstInitializer(). - */ - if (!global.errors) - { type->print(); - assert(0); - } - break; - } - break; - } - return value; -} - -real_t IntegerExp::toReal() -{ - Type *t; - - toInteger(); - t = type->toBasetype(); - if (t->ty == Tuns64) - return ldouble((d_uns64)value); - else - return ldouble((d_int64)value); -} - -real_t IntegerExp::toImaginary() -{ - return ldouble(0); -} - -complex_t IntegerExp::toComplex() -{ - return toReal(); -} - -int IntegerExp::isBool(int result) -{ - int r = toInteger() != 0; - return result ? r : !r; -} - -Expression *IntegerExp::semantic(Scope *sc) -{ - if (!type) - { - // Determine what the type of this number is - dinteger_t number = value; - - if (number & 0x8000000000000000LL) - type = Type::tuns64; - else if (number & 0xFFFFFFFF80000000LL) - type = Type::tint64; - else - type = Type::tint32; - } - else - { if (!type->deco) - type = type->semantic(loc, sc); - } - return this; -} - -Expression *IntegerExp::toLvalue(Scope *sc, Expression *e) -{ - if (!e) - e = this; - else if (!loc.filename) - loc = e->loc; - e->error("constant %s is not an lvalue", e->toChars()); - return this; -} - -void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - dinteger_t v = toInteger(); - - if (type) - { Type *t = type; - - L1: - switch (t->ty) - { - case Tenum: - { TypeEnum *te = (TypeEnum *)t; - buf->printf("cast(%s)", te->sym->toChars()); - t = te->sym->memtype; - goto L1; - } - - case Ttypedef: - { TypeTypedef *tt = (TypeTypedef *)t; - buf->printf("cast(%s)", tt->sym->toChars()); - t = tt->sym->basetype; - goto L1; - } - - case Twchar: // BUG: need to cast(wchar) - case Tdchar: // BUG: need to cast(dchar) - if ((uinteger_t)v > 0xFF) - { - buf->printf("'\\U%08x'", (unsigned)v); - break; - } - case Tchar: - { - unsigned o = buf->offset; - if (v == '\'') - buf->writestring("'\\''"); - else if (isprint(v) && v != '\\') - buf->printf("'%c'", (int)v); - else - buf->printf("'\\x%02x'", (int)v); - if (hgs->ddoc) - escapeDdocString(buf, o); - break; - } - - case Tint8: - buf->writestring("cast(byte)"); - goto L2; - - case Tint16: - buf->writestring("cast(short)"); - goto L2; - - case Tint32: - L2: - buf->printf("%d", (int)v); - break; - - case Tuns8: - buf->writestring("cast(ubyte)"); - goto L3; - - case Tuns16: - buf->writestring("cast(ushort)"); - goto L3; - - case Tuns32: - L3: - buf->printf("%du", (unsigned)v); - break; - - case Tint64: - buf->printf("%jdL", v); - break; - - case Tuns64: - L4: - buf->printf("%juLU", v); - break; - - case Tbit: - case Tbool: - buf->writestring((char *)(v ? "true" : "false")); - break; - - case Tpointer: - buf->writestring("cast("); - buf->writestring(t->toChars()); - buf->writeByte(')'); - if (PTRSIZE == 4) - goto L3; - else if (PTRSIZE == 8) - goto L4; - else - assert(0); - - default: - /* This can happen if errors, such as - * the type is painted on like in fromConstInitializer(). - */ - if (!global.errors) - { -#ifdef DEBUG - t->print(); -#endif - assert(0); - } - break; - } - } - else if (v & 0x8000000000000000LL) - buf->printf("0x%jx", v); - else - buf->printf("%jd", v); -} - -void IntegerExp::toMangleBuffer(OutBuffer *buf) -{ - if ((sinteger_t)value < 0) - buf->printf("N%jd", -value); - else - { - /* This is an awful hack to maintain backwards compatibility. - * There really always should be an 'i' before a number, but - * there wasn't in earlier implementations, so to maintain - * backwards compatibility it is only done if necessary to disambiguate. - * See bugzilla 3029 - */ - if (buf->offset > 0 && isdigit(buf->data[buf->offset - 1])) - buf->writeByte('i'); - - buf->printf("%jd", value); - } -} - -/******************************** ErrorExp **************************/ - -/* Use this expression for error recovery. - * It should behave as a 'sink' to prevent further cascaded error messages. - */ - -ErrorExp::ErrorExp() - : IntegerExp(0, 0, Type::terror) -{ - op = TOKerror; -} - -void ErrorExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("__error"); -} - -/******************************** RealExp **************************/ - -RealExp::RealExp(Loc loc, real_t value, Type *type) - : Expression(loc, TOKfloat64, sizeof(RealExp)) -{ - //printf("RealExp::RealExp(%Lg)\n", value); - this->value = value; - this->type = type; -} - -char *RealExp::toChars() -{ - char buffer[sizeof(value) * 3 + 8 + 1 + 1]; - -#ifdef IN_GCC - value.format(buffer, sizeof(buffer)); - if (type->isimaginary()) - strcat(buffer, "i"); -#else - sprintf(buffer, type->isimaginary() ? "%Lgi" : "%Lg", value); -#endif - assert(strlen(buffer) < sizeof(buffer)); - return mem.strdup(buffer); -} - -dinteger_t RealExp::toInteger() -{ -#ifdef IN_GCC - return toReal().toInt(); -#else - return (sinteger_t) toReal(); -#endif -} - -uinteger_t RealExp::toUInteger() -{ -#ifdef IN_GCC - return (uinteger_t) toReal().toInt(); -#else - return (uinteger_t) toReal(); -#endif -} - -real_t RealExp::toReal() -{ - return type->isreal() ? value : ldouble(0); -} - -real_t RealExp::toImaginary() -{ - return type->isreal() ? ldouble(0) : value; -} - -complex_t RealExp::toComplex() -{ -#ifdef __DMC__ - return toReal() + toImaginary() * I; -#else - return complex_t(toReal(), toImaginary()); -#endif -} - -/******************************** - * Test to see if two reals are the same. - * Regard NaN's as equivalent. - * Regard +0 and -0 as different. - */ - -int RealEquals(real_t x1, real_t x2) -{ - return (Port::isNan(x1) && Port::isNan(x2)) || - /* In some cases, the REALPAD bytes get garbage in them, - * so be sure and ignore them. - */ - memcmp(&x1, &x2, REALSIZE - REALPAD) == 0; -} - -int RealExp::equals(Object *o) -{ RealExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKfloat64 && - ((ne = (RealExp *)o), type->equals(ne->type)) && - RealEquals(value, ne->value) - ) - ) - return 1; - return 0; -} - -Expression *RealExp::semantic(Scope *sc) -{ - if (!type) - type = Type::tfloat64; - else - type = type->semantic(loc, sc); - return this; -} - -int RealExp::isBool(int result) -{ -#ifdef IN_GCC - return result ? (! value.isZero()) : (value.isZero()); -#else - return result ? (value != 0) - : (value == 0); -#endif -} - -void floatToBuffer(OutBuffer *buf, Type *type, real_t value) -{ - /* In order to get an exact representation, try converting it - * to decimal then back again. If it matches, use it. - * If it doesn't, fall back to hex, which is - * always exact. - */ - char buffer[25]; - sprintf(buffer, "%Lg", value); - assert(strlen(buffer) < sizeof(buffer)); -#if _WIN32 && __DMC__ - char *save = __locale_decpoint; - __locale_decpoint = "."; - real_t r = strtold(buffer, NULL); - __locale_decpoint = save; -#else - real_t r = strtold(buffer, NULL); -#endif - if (r == value) // if exact duplication - buf->writestring(buffer); - else - { - #ifdef __HAIKU__ // broken printf workaround - char buffer2[25]; - char *ptr = (char *)&value; - for(int i = 0; i < sizeof(value); i++) - snprintf(buffer2, sizeof(char), "%x", ptr[i]); - - buf->writestring(buffer2); - #else - buf->printf("%La", value); // ensure exact duplication - #endif - } - - if (type) - { - Type *t = type->toBasetype(); - switch (t->ty) - { - case Tfloat32: - case Timaginary32: - case Tcomplex32: - buf->writeByte('F'); - break; - - case Tfloat80: - case Timaginary80: - case Tcomplex80: - buf->writeByte('L'); - break; - - default: - break; - } - if (t->isimaginary()) - buf->writeByte('i'); - } -} - -void RealExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - floatToBuffer(buf, type, value); -} - -void realToMangleBuffer(OutBuffer *buf, real_t value) -{ - /* Rely on %A to get portable mangling. - * Must munge result to get only identifier characters. - * - * Possible values from %A => mangled result - * NAN => NAN - * -INF => NINF - * INF => INF - * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79 - * 0X1.9P+2 => 19P2 - */ - - if (Port::isNan(value)) - buf->writestring("NAN"); // no -NAN bugs - else - { - char buffer[32]; - int n = sprintf(buffer, "%LA", value); - assert(n > 0 && n < sizeof(buffer)); - for (int i = 0; i < n; i++) - { char c = buffer[i]; - - switch (c) - { - case '-': - buf->writeByte('N'); - break; - - case '+': - case 'X': - case '.': - break; - - case '0': - if (i < 2) - break; // skip leading 0X - default: - buf->writeByte(c); - break; - } - } - } -} - -void RealExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('e'); - realToMangleBuffer(buf, value); -} - - -/******************************** ComplexExp **************************/ - -ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type) - : Expression(loc, TOKcomplex80, sizeof(ComplexExp)) -{ - this->value = value; - this->type = type; - //printf("ComplexExp::ComplexExp(%s)\n", toChars()); -} - -char *ComplexExp::toChars() -{ - char buffer[sizeof(value) * 3 + 8 + 1]; - - char buf1[sizeof(value) * 3 + 8 + 1]; - char buf2[sizeof(value) * 3 + 8 + 1]; -#ifdef IN_GCC - creall(value).format(buf1, sizeof(buf1)); - cimagl(value).format(buf2, sizeof(buf2)); -#else - ld_sprint(buf1, 'g', creall(value)); - ld_sprint(buf2, 'g', cimagl(value)); -#endif - sprintf(buffer, "(%s+%si)", buf1, buf2); - assert(strlen(buffer) < sizeof(buffer)); - return mem.strdup(buffer); -} - -dinteger_t ComplexExp::toInteger() -{ -#ifdef IN_GCC - return (sinteger_t) toReal().toInt(); -#else - return (sinteger_t) toReal(); -#endif -} - -uinteger_t ComplexExp::toUInteger() -{ -#ifdef IN_GCC - return (uinteger_t) toReal().toInt(); -#else - return (uinteger_t) toReal(); -#endif -} - -real_t ComplexExp::toReal() -{ - return creall(value); -} - -real_t ComplexExp::toImaginary() -{ - return cimagl(value); -} - -complex_t ComplexExp::toComplex() -{ - return value; -} - -int ComplexExp::equals(Object *o) -{ ComplexExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKcomplex80 && - ((ne = (ComplexExp *)o), type->equals(ne->type)) && - RealEquals(creall(value), creall(ne->value)) && - RealEquals(cimagl(value), cimagl(ne->value)) - ) - ) - return 1; - return 0; -} - -Expression *ComplexExp::semantic(Scope *sc) -{ - if (!type) - type = Type::tcomplex80; - else - type = type->semantic(loc, sc); - return this; -} - -int ComplexExp::isBool(int result) -{ - if (result) - return (bool)(value); - else - return !value; -} - -void ComplexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - /* Print as: - * (re+imi) - */ -#ifdef IN_GCC - char buf1[sizeof(value) * 3 + 8 + 1]; - char buf2[sizeof(value) * 3 + 8 + 1]; - creall(value).format(buf1, sizeof(buf1)); - cimagl(value).format(buf2, sizeof(buf2)); - buf->printf("(%s+%si)", buf1, buf2); -#else - buf->writeByte('('); - floatToBuffer(buf, type, creall(value)); - buf->writeByte('+'); - floatToBuffer(buf, type, cimagl(value)); - buf->writestring("i)"); -#endif -} - -void ComplexExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('c'); - real_t r = toReal(); - realToMangleBuffer(buf, r); - buf->writeByte('c'); // separate the two - r = toImaginary(); - realToMangleBuffer(buf, r); -} - -/******************************** IdentifierExp **************************/ - -IdentifierExp::IdentifierExp(Loc loc, Identifier *ident) - : Expression(loc, TOKidentifier, sizeof(IdentifierExp)) -{ - this->ident = ident; -} - -Expression *IdentifierExp::semantic(Scope *sc) -{ - Dsymbol *s; - Dsymbol *scopesym; - -#if LOGSEMANTIC - printf("IdentifierExp::semantic('%s')\n", ident->toChars()); -#endif - s = sc->search(loc, ident, &scopesym); - if (s) - { Expression *e; - WithScopeSymbol *withsym; - - /* See if the symbol was a member of an enclosing 'with' - */ - withsym = scopesym->isWithScopeSymbol(); - if (withsym) - { - s = s->toAlias(); - - // Same as wthis.ident - if (s->needThis() || s->isTemplateDeclaration()) - { - e = new VarExp(loc, withsym->withstate->wthis); - e = new DotIdExp(loc, e, ident); - } - else - { Type *t = withsym->withstate->wthis->type; - if (t->ty == Tpointer) - t = ((TypePointer *)t)->next; - e = typeDotIdExp(loc, t, ident); - } - } - else - { - if (!s->parent && scopesym->isArrayScopeSymbol()) - { // Kludge to run semantic() here because - // ArrayScopeSymbol::search() doesn't have access to sc. - s->semantic(sc); - } - /* If f is really a function template, - * then replace f with the function template declaration. - */ - FuncDeclaration *f = s->isFuncDeclaration(); - if (f) - { TemplateDeclaration *tempdecl = getFuncTemplateDecl(f); - if (tempdecl) - { - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - e = new TemplateExp(loc, tempdecl); - e = e->semantic(sc); - return e; - } - } - e = new DsymbolExp(loc, s); - } - return e->semantic(sc); - } -#if DMDV2 - if (ident == Id::ctfe) - { // Create the magic __ctfe bool variable - VarDeclaration *vd = new VarDeclaration(loc, Type::tbool, Id::ctfe, NULL); - Expression *e = new VarExp(loc, vd); - e = e->semantic(sc); - return e; - } -#endif - const char *n = importHint(ident->toChars()); - if (n) - error("'%s' is not defined, perhaps you need to import %s; ?", ident->toChars(), n); - else - { - s = sc->search_correct(ident); - if (s) - error("undefined identifier %s, did you mean %s %s?", ident->toChars(), s->kind(), s->toChars()); - else - error("undefined identifier %s", ident->toChars()); - } - return new ErrorExp(); -} - -char *IdentifierExp::toChars() -{ - return ident->toChars(); -} - -void IdentifierExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - buf->writestring(ident->toHChars2()); - else - buf->writestring(ident->toChars()); -} - - -int IdentifierExp::isLvalue() -{ - return 1; -} - - -Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - return this; -} - -/******************************** DollarExp **************************/ - -DollarExp::DollarExp(Loc loc) - : IdentifierExp(loc, Id::dollar) -{ -} - -/******************************** DsymbolExp **************************/ - -DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s) - : Expression(loc, TOKdsymbol, sizeof(DsymbolExp)) -{ - this->s = s; -} - -Expression *DsymbolExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DsymbolExp::semantic('%s')\n", s->toChars()); -#endif - -Lagain: - EnumMember *em; - Expression *e; - VarDeclaration *v; - FuncDeclaration *f; - FuncLiteralDeclaration *fld; - ClassDeclaration *cd; - ClassDeclaration *thiscd = NULL; - Import *imp; - Package *pkg; - Type *t; - - //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); - //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind()); - if (type && !s->needThis()) - return this; - if (!s->isFuncDeclaration()) // functions are checked after overloading - checkDeprecated(sc, s); - Dsymbol *olds = s; - s = s->toAlias(); - //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis()); - if (s != olds && !s->isFuncDeclaration()) - checkDeprecated(sc, s); - - if (sc->func) - thiscd = sc->func->parent->isClassDeclaration(); - - // BUG: This should happen after overload resolution for functions, not before - if (s->needThis()) - { - if (hasThis(sc) -#if DMDV2 - && !s->isFuncDeclaration() -#endif - ) - { - // Supply an implicit 'this', as in - // this.ident - - DotVarExp *de; - - de = new DotVarExp(loc, new ThisExp(loc), s->isDeclaration()); - return de->semantic(sc); - } - } - - em = s->isEnumMember(); - if (em) - { - e = em->value->copy(); - e->loc = loc; - e = e->semantic(sc); - return e; - } - v = s->isVarDeclaration(); - if (v) - { - //printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); - if (!type) - { if ((!v->type || !v->type->deco) && v->scope) - v->semantic(v->scope); - type = v->type; - if (!v->type) - { error("forward reference of %s %s", v->kind(), v->toChars()); - return new ErrorExp(); - } - } - if (v->isSameAsInitializer() && type->toBasetype()->ty != Tsarray) - { - if (v->init) - { - if (v->inuse) - { - error("circular reference to '%s'", v->toChars()); - return new ErrorExp(); - } - ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { - e = ei->exp->copy(); // make copy so we can change loc - if (e->op == TOKstring || !e->type) - e = e->semantic(sc); - e = e->implicitCastTo(sc, type); - e->loc = loc; - return e; - } - } - else - { - e = type->defaultInit(); - e->loc = loc; - return e; - } - } - e = new VarExp(loc, v); - e->type = type; - e = e->semantic(sc); - return e->deref(); - } - fld = s->isFuncLiteralDeclaration(); - if (fld) - { //printf("'%s' is a function literal\n", fld->toChars()); - e = new FuncExp(loc, fld); - return e->semantic(sc); - } - f = s->isFuncDeclaration(); - if (f) - { //printf("'%s' is a function\n", f->toChars()); - - if (!f->originalType && f->scope) // semantic not yet run - { - unsigned oldgag = global.gag; - if (global.isSpeculativeGagging() && !f->isSpeculative()) - global.gag = 0; - f->semantic(f->scope); - global.gag = oldgag; - } - -#if DMDV2 - // if inferring return type, sematic3 needs to be run - if (f->inferRetType && f->scope && f->type && !f->type->nextOf()) - { - TemplateInstance *spec = f->isSpeculative(); - int olderrs = global.errors; - f->semantic3(f->scope); - // Update the template instantiation with the number - // of errors which occured. - if (spec && global.errors != olderrs) - spec->errors = global.errors - olderrs; - } -#endif - - if (f->isUnitTestDeclaration()) - { - error("cannot call unittest function %s", toChars()); - return new ErrorExp(); - } - if (!f->type->deco) - { - error("forward reference to %s", toChars()); - return new ErrorExp(); - } - return new VarExp(loc, f); - } - cd = s->isClassDeclaration(); - if (cd && thiscd && cd->isBaseOf(thiscd, NULL) && sc->func->needThis()) - { - // We need to add an implicit 'this' if cd is this class or a base class. - DotTypeExp *dte; - - dte = new DotTypeExp(loc, new ThisExp(loc), s); - return dte->semantic(sc); - } - imp = s->isImport(); - if (imp) - { - if (!imp->pkg) - { error("forward reference of import %s", imp->toChars()); - return new ErrorExp(); - } - ScopeExp *ie = new ScopeExp(loc, imp->pkg); - return ie->semantic(sc); - } - pkg = s->isPackage(); - if (pkg) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, pkg); - return ie->semantic(sc); - } - Module *mod = s->isModule(); - if (mod) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, mod); - return ie->semantic(sc); - } - - t = s->getType(); - if (t) - { - TypeExp *te = new TypeExp(loc, t); - return te->semantic(sc); - } - - TupleDeclaration *tup = s->isTupleDeclaration(); - if (tup) - { - for (size_t i = 0; i < tup->objects->dim; i++) - { - Dsymbol *sa = getDsymbol((*tup->objects)[i]); - if (sa && sa->needThis()) - { - if (hasThis(sc) -#if DMDV2 - && !sa->isFuncDeclaration() -#endif - ) - { - // Supply an implicit 'this', as in - // this.ident - (*tup->objects)[i] = new DotVarExp(loc, new ThisExp(loc), sa->isDeclaration()); - } - } - } - - e = new TupleExp(loc, tup); - e = e->semantic(sc); - return e; - } - - TemplateInstance *ti = s->isTemplateInstance(); - if (ti) - { if (!ti->semanticRun) - ti->semantic(sc); - s = ti->toAlias(); - if (!s->isTemplateInstance()) - goto Lagain; - if (ti->errors) - return new ErrorExp(); - e = new ScopeExp(loc, ti); - e = e->semantic(sc); - return e; - } - - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td) - { - e = new TemplateExp(loc, td); - e = e->semantic(sc); - return e; - } - - error("%s '%s' is not a variable", s->kind(), s->toChars()); - return new ErrorExp(); -} - -char *DsymbolExp::toChars() -{ - return s->toChars(); -} - -void DsymbolExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(s->toChars()); -} - - -int DsymbolExp::isLvalue() -{ - return 1; -} - - -Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - return this; -} - -/******************************** ThisExp **************************/ - -ThisExp::ThisExp(Loc loc) - : Expression(loc, TOKthis, sizeof(ThisExp)) -{ - //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum); - var = NULL; -} - -Expression *ThisExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("ThisExp::semantic()\n"); -#endif - if (type) - { //assert(global.errors || var); - return this; - } - - FuncDeclaration *fd = hasThis(sc); // fd is the uplevel function with the 'this' variable - - /* Special case for typeof(this) and typeof(super) since both - * should work even if they are not inside a non-static member function - */ - if (!fd && sc->intypeof) - { - // Find enclosing struct or class - for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent) - { - if (!s) - { - error("%s is not in a class or struct scope", toChars()); - goto Lerr; - } - ClassDeclaration *cd = s->isClassDeclaration(); - if (cd) - { - type = cd->type; - return this; - } - StructDeclaration *sd = s->isStructDeclaration(); - if (sd) - { -#if STRUCTTHISREF - type = sd->type; -#else - type = sd->type->pointerTo(); -#endif - return this; - } - } - } - if (!fd) - goto Lerr; - - assert(fd->vthis); - var = fd->vthis; - assert(var->parent); - type = var->type; - var->isVarDeclaration()->checkNestedReference(sc, loc); - if (!sc->intypeof) - sc->callSuper |= CSXthis; - return this; - -Lerr: - error("'this' is only defined in non-static member functions, not %s", sc->parent->toChars()); - return new ErrorExp(); -} - -int ThisExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - -void ThisExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this"); -} - - -int ThisExp::isLvalue() -{ - return 1; -} - - -Expression *ThisExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - -/******************************** SuperExp **************************/ - -SuperExp::SuperExp(Loc loc) - : ThisExp(loc) -{ - op = TOKsuper; -} - -Expression *SuperExp::semantic(Scope *sc) -{ - ClassDeclaration *cd; - Dsymbol *s; - -#if LOGSEMANTIC - printf("SuperExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - FuncDeclaration *fd = hasThis(sc); - - /* Special case for typeof(this) and typeof(super) since both - * should work even if they are not inside a non-static member function - */ - if (!fd && sc->intypeof) - { - // Find enclosing class - for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent) - { - if (!s) - { - error("%s is not in a class scope", toChars()); - goto Lerr; - } - ClassDeclaration *cd = s->isClassDeclaration(); - if (cd) - { - cd = cd->baseClass; - if (!cd) - { error("class %s has no 'super'", s->toChars()); - goto Lerr; - } - type = cd->type; - return this; - } - } - } - if (!fd) - goto Lerr; - - assert(fd->vthis); - var = fd->vthis; - assert(var->parent); - - s = fd->toParent(); - while (s && s->isTemplateInstance()) - s = s->toParent(); - assert(s); - cd = s->isClassDeclaration(); -//printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars()); - if (!cd) - goto Lerr; - if (!cd->baseClass) - { - error("no base class for %s", cd->toChars()); - type = fd->vthis->type; - } - else - { - type = cd->baseClass->type; -#if DMDV2 - type = type->castMod(var->type->mod); -#endif - } - - var->isVarDeclaration()->checkNestedReference(sc, loc); - - if (!sc->intypeof) - sc->callSuper |= CSXsuper; - return this; - - -Lerr: - error("'super' is only allowed in non-static class member functions"); - return new ErrorExp(); -} - -void SuperExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("super"); -} - - -/******************************** NullExp **************************/ - -NullExp::NullExp(Loc loc, Type *type) - : Expression(loc, TOKnull, sizeof(NullExp)) -{ - committed = 0; - this->type = type; -} - -Expression *NullExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("NullExp::semantic('%s')\n", toChars()); -#endif - // NULL is the same as (void *)0 - if (!type) - type = Type::tvoid->pointerTo(); - return this; -} - -int NullExp::isBool(int result) -{ - return result ? FALSE : TRUE; -} - -StringExp *NullExp::toString() -{ - if (implicitConvTo(Type::tstring)) - { - StringExp *se = new StringExp(loc, (char*)mem.calloc(1, 1), 0); - se->type = Type::tstring; - return se; - } - return NULL; -} - -void NullExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("null"); -} - -void NullExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('n'); -} - -/******************************** StringExp **************************/ - -StringExp::StringExp(Loc loc, char *string) - : Expression(loc, TOKstring, sizeof(StringExp)) -{ - this->string = string; - this->len = strlen(string); - this->sz = 1; - this->committed = 0; - this->postfix = 0; - this->ownedByCtfe = false; -} - -StringExp::StringExp(Loc loc, void *string, size_t len) - : Expression(loc, TOKstring, sizeof(StringExp)) -{ - this->string = string; - this->len = len; - this->sz = 1; - this->committed = 0; - this->postfix = 0; - this->ownedByCtfe = false; -} - -StringExp::StringExp(Loc loc, void *string, size_t len, unsigned char postfix) - : Expression(loc, TOKstring, sizeof(StringExp)) -{ - this->string = string; - this->len = len; - this->sz = 1; - this->committed = 0; - this->postfix = postfix; - this->ownedByCtfe = false; -} - -#if 0 -Expression *StringExp::syntaxCopy() -{ - printf("StringExp::syntaxCopy() %s\n", toChars()); - return copy(); -} -#endif - -int StringExp::equals(Object *o) -{ - //printf("StringExp::equals('%s') %s\n", o->toChars(), toChars()); - if (o && o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - - if (e->op == TOKstring) - { - return compare(o) == 0; - } - } - return FALSE; -} - -char *StringExp::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *p; - - memset(&hgs, 0, sizeof(hgs)); - toCBuffer(&buf, &hgs); - buf.writeByte(0); - p = (char *)buf.data; - buf.data = NULL; - return p; -} - -Expression *StringExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("StringExp::semantic() %s\n", toChars()); -#endif - if (!type) - { OutBuffer buffer; - size_t newlen = 0; - const char *p; - size_t u; - unsigned c; - - switch (postfix) - { - case 'd': - for (u = 0; u < len;) - { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); - if (p) - { error("%s", p); - return new ErrorExp(); - } - else - { buffer.write4(c); - newlen++; - } - } - buffer.write4(0); - string = buffer.extractData(); - len = newlen; - sz = 4; - type = new TypeSArray(Type::tdchar, new IntegerExp(loc, len, Type::tindex)); - committed = 1; - break; - - case 'w': - for (u = 0; u < len;) - { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); - if (p) - { error("%s", p); - return new ErrorExp(); - } - else - { buffer.writeUTF16(c); - newlen++; - if (c >= 0x10000) - newlen++; - } - } - buffer.writeUTF16(0); - string = buffer.extractData(); - len = newlen; - sz = 2; - type = new TypeSArray(Type::twchar, new IntegerExp(loc, len, Type::tindex)); - committed = 1; - break; - - case 'c': - committed = 1; - default: - type = new TypeSArray(Type::tchar, new IntegerExp(loc, len, Type::tindex)); - break; - } - type = type->semantic(loc, sc); - } - return this; -} - -/********************************** - * Return length of string. - */ - -size_t StringExp::length() -{ - size_t result = 0; - dchar_t c; - const char *p; - - switch (sz) - { - case 1: - for (size_t u = 0; u < len;) - { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); - if (p) - { error("%s", p); - return 0; - } - else - result++; - } - break; - - case 2: - for (size_t u = 0; u < len;) - { - p = utf_decodeWchar((unsigned short *)string, len, &u, &c); - if (p) - { error("%s", p); - return 0; - } - else - result++; - } - break; - - case 4: - result = len; - break; - - default: - assert(0); - } - return result; -} - -StringExp *StringExp::toString() -{ - return this; -} - -/**************************************** - * Convert string to char[]. - */ - -StringExp *StringExp::toUTF8(Scope *sc) -{ - if (sz != 1) - { // Convert to UTF-8 string - committed = 0; - Expression *e = castTo(sc, Type::tchar->arrayOf()); - e = e->optimize(WANTvalue); - assert(e->op == TOKstring); - StringExp *se = (StringExp *)e; - assert(se->sz == 1); - return se; - } - return this; -} - -int StringExp::compare(Object *obj) -{ - //printf("StringExp::compare()\n"); - // Used to sort case statement expressions so we can do an efficient lookup - StringExp *se2 = (StringExp *)(obj); - - // This is a kludge so isExpression() in template.c will return 5 - // for StringExp's. - if (!se2) - return 5; - - assert(se2->op == TOKstring); - - int len1 = len; - int len2 = se2->len; - - //printf("sz = %d, len1 = %d, len2 = %d\n", sz, len1, len2); - if (len1 == len2) - { - switch (sz) - { - case 1: - return memcmp((char *)string, (char *)se2->string, len1); - - case 2: - { unsigned u; - d_wchar *s1 = (d_wchar *)string; - d_wchar *s2 = (d_wchar *)se2->string; - - for (u = 0; u < len; u++) - { - if (s1[u] != s2[u]) - return s1[u] - s2[u]; - } - } - - case 4: - { unsigned u; - d_dchar *s1 = (d_dchar *)string; - d_dchar *s2 = (d_dchar *)se2->string; - - for (u = 0; u < len; u++) - { - if (s1[u] != s2[u]) - return s1[u] - s2[u]; - } - } - break; - - default: - assert(0); - } - } - return len1 - len2; -} - -int StringExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - - -int StringExp::isLvalue() -{ - /* string literal is rvalue in default, but - * conversion to reference of static array is only allowed. - */ - return 0; -} - -unsigned StringExp::charAt(size_t i) -{ unsigned value; - - switch (sz) - { - case 1: - value = ((unsigned char *)string)[i]; - break; - - case 2: - value = ((unsigned short *)string)[i]; - break; - - case 4: - value = ((unsigned int *)string)[i]; - break; - - default: - assert(0); - break; - } - return value; -} - -void StringExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('"'); - unsigned o = buf->offset; - for (size_t i = 0; i < len; i++) - { unsigned c = charAt(i); - - switch (c) - { - case '"': - case '\\': - if (!hgs->console) - buf->writeByte('\\'); - default: - if (c <= 0xFF) - { if (c <= 0x7F && (isprint(c) || hgs->console)) - buf->writeByte(c); - else - buf->printf("\\x%02x", c); - } - else if (c <= 0xFFFF) - buf->printf("\\x%02x\\x%02x", c & 0xFF, c >> 8); - else - buf->printf("\\x%02x\\x%02x\\x%02x\\x%02x", - c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24); - break; - } - } - if (hgs->ddoc) - escapeDdocString(buf, o); - buf->writeByte('"'); - if (postfix) - buf->writeByte(postfix); -} - -void StringExp::toMangleBuffer(OutBuffer *buf) -{ char m; - OutBuffer tmp; - const char *p; - unsigned c; - size_t u; - unsigned char *q; - unsigned qlen; - - /* Write string in UTF-8 format - */ - switch (sz) - { case 1: - m = 'a'; - q = (unsigned char *)string; - qlen = len; - break; - case 2: - m = 'w'; - for (u = 0; u < len; ) - { - p = utf_decodeWchar((unsigned short *)string, len, &u, &c); - if (p) - error("%s", p); - else - tmp.writeUTF8(c); - } - q = tmp.data; - qlen = tmp.offset; - break; - case 4: - m = 'd'; - for (u = 0; u < len; u++) - { - c = ((unsigned *)string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - tmp.writeUTF8(c); - } - q = tmp.data; - qlen = tmp.offset; - break; - default: - assert(0); - } - buf->reserve(1 + 11 + 2 * qlen); - buf->writeByte(m); - buf->printf("%d_", qlen); // nbytes <= 11 - - for (unsigned char *p = buf->data + buf->offset, *pend = p + 2 * qlen; - p < pend; p += 2, ++q) - { - unsigned char hi = *q >> 4 & 0xF; - p[0] = (hi < 10 ? hi + '0' : hi - 10 + 'a'); - unsigned char lo = *q & 0xF; - p[1] = (lo < 10 ? lo + '0' : lo - 10 + 'a'); - } - buf->offset += 2 * qlen; -} - -/************************ ArrayLiteralExp ************************************/ - -// [ e1, e2, e3, ... ] - -ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements) - : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) -{ - this->elements = elements; - this->ownedByCtfe = false; -} - -ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e) - : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) -{ - elements = new Expressions; - elements->push(e); - this->ownedByCtfe = false; -} - -Expression *ArrayLiteralExp::syntaxCopy() -{ - return new ArrayLiteralExp(loc, arraySyntaxCopy(elements)); -} - -Expression *ArrayLiteralExp::semantic(Scope *sc) -{ Expression *e; - Type *t0 = NULL; - -#if LOGSEMANTIC - printf("ArrayLiteralExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - // Run semantic() on each element - for (size_t i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - e = e->semantic(sc); - elements->data[i] = (void *)e; - } - expandTuples(elements); - for (size_t i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - - if (!e->type) - error("%s has no value", e->toChars()); - e = resolveProperties(sc, e); - - unsigned char committed = 1; - if (e->op == TOKstring) - committed = ((StringExp *)e)->committed; - - if (!t0) - { t0 = e->type; - // Convert any static arrays to dynamic arrays - if (t0->ty == Tsarray) - { - t0 = ((TypeSArray *)t0)->next->arrayOf(); - e = e->implicitCastTo(sc, t0); - } - } - else - e = e->implicitCastTo(sc, t0); - if (!committed && e->op == TOKstring) - { StringExp *se = (StringExp *)e; - se->committed = 0; - } - elements->data[i] = (void *)e; - } - - if (!t0) - t0 = Type::tvoid; - - type = new TypeSArray(t0, new IntegerExp(elements->dim)); - type = type->semantic(loc, sc); - - /* Disallow array literals of type void being used. - */ - if (elements->dim > 0 && t0->ty == Tvoid) - { error("%s of type %s has no value", toChars(), type->toChars()); - return new ErrorExp(); - } - - return this; -} - -int ArrayLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; - - f |= e->hasSideEffect(); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -int ArrayLiteralExp::isBool(int result) -{ - size_t dim = elements ? elements->dim : 0; - return result ? (dim != 0) : (dim == 0); -} - -StringExp *ArrayLiteralExp::toString() -{ - TY telem = type->nextOf()->toBasetype()->ty; - - if (telem == Tchar || telem == Twchar || telem == Tdchar || - (telem == Tvoid && (!elements || elements->dim == 0))) - { - OutBuffer buf; - if (elements) - for (int i = 0; i < elements->dim; ++i) - { - Expression *ch = (*elements)[i]; - if (ch->op != TOKint64) - return NULL; - buf.writeUTF8(ch->toInteger()); - } - buf.writebyte(0); - - char prefix = 'c'; - if (telem == Twchar) prefix = 'w'; - else if (telem == Tdchar) prefix = 'd'; - - const size_t len = buf.offset - 1; - StringExp *se = new StringExp(loc, buf.extractData(), len, prefix); - se->type = type; - return se; - } - return NULL; -} - -void ArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('['); - argsToCBuffer(buf, elements, hgs); - buf->writeByte(']'); -} - -void ArrayLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = elements ? elements->dim : 0; - buf->printf("A%u", dim); - for (size_t i = 0; i < dim; i++) - { Expression *e = (*elements)[i]; - e->toMangleBuffer(buf); - } -} - -/************************ AssocArrayLiteralExp ************************************/ - -// [ key0 : value0, key1 : value1, ... ] - -AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc, - Expressions *keys, Expressions *values) - : Expression(loc, TOKassocarrayliteral, sizeof(AssocArrayLiteralExp)) -{ - assert(keys->dim == values->dim); - this->keys = keys; - this->values = values; - this->ownedByCtfe = false; -} - -Expression *AssocArrayLiteralExp::syntaxCopy() -{ - return new AssocArrayLiteralExp(loc, - arraySyntaxCopy(keys), arraySyntaxCopy(values)); -} - -Expression *AssocArrayLiteralExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AssocArrayLiteralExp::semantic('%s')\n", toChars()); -#endif - - if (type) - return this; - - // Run semantic() on each element - arrayExpressionSemantic(keys, sc); - arrayExpressionSemantic(values, sc); - expandTuples(keys); - expandTuples(values); - if (keys->dim != values->dim) - { - error("number of keys is %u, must match number of values %u", keys->dim, values->dim); - return new ErrorExp(); - } - - Type *tkey = NULL; - Type *tvalue = NULL; - keys = arrayExpressionToCommonType(sc, keys, &tkey); - values = arrayExpressionToCommonType(sc, values, &tvalue); - - if (tkey == Type::terror || tvalue == Type::terror) - return new ErrorExp; - - type = new TypeAArray(tvalue, tkey); - type = type->semantic(loc, sc); - return this; -} - -int AssocArrayLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - f |= key->hasSideEffect(); - f |= value->hasSideEffect(); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -int AssocArrayLiteralExp::isBool(int result) -{ - size_t dim = keys->dim; - return result ? (dim != 0) : (dim == 0); -} - -#if DMDV2 -int AssocArrayLiteralExp::canThrow() -{ - return 1; -} -#endif - -void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('['); - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (*keys)[i]; - Expression *value = (*values)[i]; - - if (i) - buf->writeByte(','); - expToCBuffer(buf, hgs, key, PREC_assign); - buf->writeByte(':'); - expToCBuffer(buf, hgs, value, PREC_assign); - } - buf->writeByte(']'); -} - -void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = keys->dim; - buf->printf("A%u", dim); - for (size_t i = 0; i < dim; i++) - { Expression *key = (*keys)[i]; - Expression *value = (*values)[i]; - - key->toMangleBuffer(buf); - value->toMangleBuffer(buf); - } -} - -/************************ StructLiteralExp ************************************/ - -// sd( e1, e2, e3, ... ) - -StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype) - : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp)) -{ - this->sd = sd; - this->elements = elements; - this->stype = stype; -#if IN_DMD - this->sym = NULL; -#endif - this->soffset = 0; - this->fillHoles = 1; - this->ownedByCtfe = false; -#if IN_LLVM - constType = NULL; -#endif -} - -Expression *StructLiteralExp::syntaxCopy() -{ - return new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), stype); -} - -Expression *StructLiteralExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("StructLiteralExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - // Run semantic() on each element - for (size_t i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - if (!e) - continue; - e = e->semantic(sc); - elements->data[i] = (void *)e; - } - expandTuples(elements); - size_t offset = 0; - for (size_t i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - if (!e) - continue; - - if (!e->type) - { error("%s has no value", e->toChars()); - return new ErrorExp(); - } - e = resolveProperties(sc, e); - if (i >= sd->fields.dim) - { error("more initializers than fields of %s", sd->toChars()); - break; - } - Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - if (v->offset < offset) - error("overlapping initialization for %s", v->toChars()); - offset = v->offset + v->type->size(); - - Type *telem = v->type; - while (!e->implicitConvTo(telem) && telem->toBasetype()->ty == Tsarray) - { /* Static array initialization, as in: - * T[3][5] = e; - */ - telem = telem->toBasetype()->nextOf(); - } - - e = e->implicitCastTo(sc, telem); - - elements->data[i] = (void *)e; - } - - /* Fill out remainder of elements[] with default initializers for fields[] - */ - for (size_t i = elements->dim; i < sd->fields.dim; i++) - { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - if (v->offset < offset) - { e = NULL; - sd->hasUnions = 1; - } - else - { - if (v->init) - { if (v->init->isVoidInitializer()) - e = NULL; - else - { e = v->init->toExpression(); - if (!e) - { error("cannot make expression out of initializer for %s", v->toChars()); - return new ErrorExp(); - } - else if (v->scope) - { // Do deferred semantic analysis - Initializer *i2 = v->init->syntaxCopy(); - i2 = i2->semantic(v->scope, v->type, INITinterpret); - e = i2->toExpression(); - // remove v->scope (see bug 3426) - // but not if gagged, for we might be called again. - if (!global.gag) - v->scope = NULL; - } - } - } - else - e = v->type->defaultInitLiteral(loc); - offset = v->offset + v->type->size(); - } - elements->push(e); - } - - type = stype ? stype : sd->type; - return this; -} - -/************************************** - * Gets expression at offset of type. - * Returns NULL if not found. - */ - -Expression *StructLiteralExp::getField(Type *type, unsigned offset) -{ - //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n", -// /*toChars()*/"", type->toChars(), offset); - Expression *e = NULL; - int i = getFieldIndex(type, offset); - - if (i != -1) - { - //printf("\ti = %d\n", i); - assert(i < elements->dim); - e = (Expression *)elements->data[i]; - if (e) - { - //printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars()); - - /* If type is a static array, and e is an initializer for that array, - * then the field initializer should be an array literal of e. - */ - if (e->type != type && type->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)type; - uinteger_t length = tsa->dim->toInteger(); - Expressions *z = new Expressions; - z->setDim(length); - for (int q = 0; q < length; ++q) - z->data[q] = e->copy(); - e = new ArrayLiteralExp(loc, z); - e->type = type; - } - else - { - e = e->copy(); - e->type = type; - } - } - } - return e; -} - -/************************************ - * Get index of field. - * Returns -1 if not found. - */ - -int StructLiteralExp::getFieldIndex(Type *type, unsigned offset) -{ - /* Find which field offset is by looking at the field offsets - */ - if (elements->dim) - { - for (size_t i = 0; i < sd->fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - if (offset == v->offset && - type->size() == v->type->size()) - { Expression *e = (Expression *)elements->data[i]; - if (e) - { - return i; - } - break; - } - } - } - return -1; -} - -#if DMDV2 -int StructLiteralExp::isLvalue() -{ - return 1; -} -#endif - -Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - - -int StructLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - if (!e) - continue; - - f |= e->hasSideEffect(); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -#if DMDV2 -int StructLiteralExp::canThrow() -{ - return arrayExpressionCanThrow(elements); -} -#endif - -void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(sd->toChars()); - buf->writeByte('('); - argsToCBuffer(buf, elements, hgs); - buf->writeByte(')'); -} - -void StructLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = elements ? elements->dim : 0; - buf->printf("S%u", dim); - for (size_t i = 0; i < dim; i++) - { Expression *e = (*elements)[i]; - if (e) - e->toMangleBuffer(buf); - else - buf->writeByte('v'); // 'v' for void - } -} - -/************************ TypeDotIdExp ************************************/ - -/* Things like: - * int.size - * foo.size - * (foo).size - * cast(foo).size - */ - -Expression *typeDotIdExp(Loc loc, Type *type, Identifier *ident) -{ - return new DotIdExp(loc, new TypeExp(loc, type), ident); -} - - -/************************************************************/ - -// Mainly just a placeholder - -TypeExp::TypeExp(Loc loc, Type *type) - : Expression(loc, TOKtype, sizeof(TypeExp)) -{ - //printf("TypeExp::TypeExp(%s)\n", type->toChars()); - this->type = type; -} - -Expression *TypeExp::syntaxCopy() -{ - //printf("TypeExp::syntaxCopy()\n"); - return new TypeExp(loc, type->syntaxCopy()); -} - -Expression *TypeExp::semantic(Scope *sc) -{ - //printf("TypeExp::semantic(%s)\n", type->toChars()); - type = type->semantic(loc, sc); - return this; -} - -void TypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - type->toCBuffer(buf, NULL, hgs); -} - -/************************************************************/ - -// Mainly just a placeholder - -ScopeExp::ScopeExp(Loc loc, ScopeDsymbol *pkg) - : Expression(loc, TOKimport, sizeof(ScopeExp)) -{ - //printf("ScopeExp::ScopeExp(pkg = '%s')\n", pkg->toChars()); - //static int count; if (++count == 38) *(char*)0=0; - this->sds = pkg; -} - -Expression *ScopeExp::syntaxCopy() -{ - ScopeExp *se = new ScopeExp(loc, (ScopeDsymbol *)sds->syntaxCopy(NULL)); - return se; -} - -Expression *ScopeExp::semantic(Scope *sc) -{ - TemplateInstance *ti; - ScopeDsymbol *sds2; - -#if LOGSEMANTIC - printf("+ScopeExp::semantic('%s')\n", toChars()); -#endif -Lagain: - ti = sds->isTemplateInstance(); - if (ti && !ti->errors) - { - unsigned olderrs = global.errors; - if (!ti->semanticRun) - ti->semantic(sc); - if (ti->inst) - { - if (ti->inst->errors) - return new ErrorExp(); - Dsymbol *s = ti->inst->toAlias(); - sds2 = s->isScopeDsymbol(); - if (!sds2) - { Expression *e; - - //printf("s = %s, '%s'\n", s->kind(), s->toChars()); - if (ti->withsym) - { - // Same as wthis.s - e = new VarExp(loc, ti->withsym->withstate->wthis); - e = new DotVarExp(loc, e, s->isDeclaration()); - } - else - e = new DsymbolExp(loc, s); - e = e->semantic(sc); - //printf("-1ScopeExp::semantic()\n"); - return e; - } - if (sds2 != sds) - { - sds = sds2; - goto Lagain; - } - //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); - } - if (olderrs != global.errors) - return new ErrorExp(); - } - else - { - //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); - //printf("\tparent = '%s'\n", sds->parent->toChars()); - sds->semantic(sc); - - AggregateDeclaration *ad = sds->isAggregateDeclaration(); - if (ad) - return (new TypeExp(loc, ad->type))->semantic(sc); - } - type = Type::tvoid; - //printf("-2ScopeExp::semantic() %s\n", toChars()); - return this; -} - -void ScopeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (sds->isTemplateInstance()) - { - sds->toCBuffer(buf, hgs); - } - else if (hgs != NULL && hgs->ddoc) - { // fixes bug 6491 - Module *module = sds->isModule(); - if (module) - buf->writestring(module->md->toChars()); - else - buf->writestring(sds->toChars()); - } - else - { - buf->writestring(sds->kind()); - buf->writestring(" "); - buf->writestring(sds->toChars()); - } -} - -/********************** TemplateExp **************************************/ - -// Mainly just a placeholder - -TemplateExp::TemplateExp(Loc loc, TemplateDeclaration *td) - : Expression(loc, TOKtemplate, sizeof(TemplateExp)) -{ - //printf("TemplateExp(): %s\n", td->toChars()); - this->td = td; -} - -void TemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(td->toChars()); -} - -int TemplateExp::rvalue() -{ - error("template %s has no value", toChars()); - return 0; -} - -/********************** NewExp **************************************/ - -/* thisexp.new(newargs) newtype(arguments) */ - -NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs, - Type *newtype, Expressions *arguments) - : Expression(loc, TOKnew, sizeof(NewExp)) -{ - this->thisexp = thisexp; - this->newargs = newargs; - this->newtype = newtype; - this->arguments = arguments; - member = NULL; - allocator = NULL; - onstack = 0; -} - -Expression *NewExp::syntaxCopy() -{ - return new NewExp(loc, - thisexp ? thisexp->syntaxCopy() : NULL, - arraySyntaxCopy(newargs), - newtype->syntaxCopy(), arraySyntaxCopy(arguments)); -} - - -Expression *NewExp::semantic(Scope *sc) -{ - Type *tb; - ClassDeclaration *cdthis = NULL; - -#if LOGSEMANTIC - printf("NewExp::semantic() %s\n", toChars()); - if (thisexp) - printf("\tthisexp = %s\n", thisexp->toChars()); - printf("\tnewtype: %s\n", newtype->toChars()); -#endif - if (type) // if semantic() already run - return this; - -Lagain: - if (thisexp) - { thisexp = thisexp->semantic(sc); - cdthis = thisexp->type->isClassHandle(); - if (cdthis) - { - sc = sc->push(cdthis); - type = newtype->semantic(loc, sc); - sc = sc->pop(); - } - else - { - error("'this' for nested class must be a class type, not %s", thisexp->type->toChars()); - goto Lerr; - } - } - else - type = newtype->semantic(loc, sc); - newtype = type; // in case type gets cast to something else - tb = type->toBasetype(); - //printf("tb: %s, deco = %s\n", tb->toChars(), tb->deco); - - arrayExpressionSemantic(newargs, sc); - preFunctionParameters(loc, sc, newargs); - arrayExpressionSemantic(arguments, sc); - preFunctionParameters(loc, sc, arguments); - - if (thisexp && tb->ty != Tclass) - { error("e.new is only for allocating nested classes, not %s", tb->toChars()); - goto Lerr; - } - - if (tb->ty == Tclass) - { TypeFunction *tf; - - TypeClass *tc = (TypeClass *)(tb); - ClassDeclaration *cd = tc->sym->isClassDeclaration(); - if (cd->isInterfaceDeclaration()) - { error("cannot create instance of interface %s", cd->toChars()); - goto Lerr; - } - else if (cd->isAbstract()) - { error("cannot create instance of abstract class %s", cd->toChars()); - for (size_t i = 0; i < cd->vtbl.dim; i++) - { FuncDeclaration *fd = cd->vtbl.tdata()[i]->isFuncDeclaration(); - if (fd && fd->isAbstract()) - error("function %s is abstract", fd->toChars()); - } - goto Lerr; - } - checkDeprecated(sc, cd); - if (cd->isNested()) - { /* We need a 'this' pointer for the nested class. - * Ensure we have the right one. - */ - Dsymbol *s = cd->toParent2(); - ClassDeclaration *cdn = s->isClassDeclaration(); - FuncDeclaration *fdn = s->isFuncDeclaration(); - - //printf("cd isNested, cdn = %s\n", cdn ? cdn->toChars() : "null"); - if (cdn) - { - if (!cdthis) - { - // Supply an implicit 'this' and try again - thisexp = new ThisExp(loc); - for (Dsymbol *sp = sc->parent; 1; sp = sp->parent) - { if (!sp) - { - error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); - goto Lerr; - } - ClassDeclaration *cdp = sp->isClassDeclaration(); - if (!cdp) - continue; - if (cdp == cdn || cdn->isBaseOf(cdp, NULL)) - break; - // Add a '.outer' and try again - thisexp = new DotIdExp(loc, thisexp, Id::outer); - } - if (!global.errors) - goto Lagain; - } - if (cdthis) - { - //printf("cdthis = %s\n", cdthis->toChars()); - if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL)) - { error("'this' for nested class must be of type %s, not %s", cdn->toChars(), thisexp->type->toChars()); - goto Lerr; - } - } -#if 0 - else - { - for (Dsymbol *sf = sc->func; 1; sf= sf->toParent2()->isFuncDeclaration()) - { - if (!sf) - { - error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); - goto Lerr; - } - printf("sf = %s\n", sf->toChars()); - AggregateDeclaration *ad = sf->isThis(); - if (ad && (ad == cdn || cdn->isBaseOf(ad->isClassDeclaration(), NULL))) - break; - } - } -#endif - } - else if (thisexp) - { error("e.new is only for allocating nested classes"); - goto Lerr; - } - else if (fdn) - { - // make sure the parent context fdn of cd is reachable from sc - for (Dsymbol *sp = sc->parent; 1; sp = sp->parent) - { - if (fdn == sp) - break; - FuncDeclaration *fsp = sp ? sp->isFuncDeclaration() : NULL; - if (!sp || (fsp && fsp->isStatic())) - { - error("outer function context of %s is needed to 'new' nested class %s", fdn->toPrettyChars(), cd->toPrettyChars()); - goto Lerr; - } - } - } - } - else if (thisexp) - { error("e.new is only for allocating nested classes"); - goto Lerr; - } - - FuncDeclaration *f = cd->ctor; - if (f) - { - assert(f); - f = f->overloadResolve(loc, NULL, arguments, sc->module); - checkDeprecated(sc, f); - member = f->isCtorDeclaration(); - assert(member); - - cd->accessCheck(loc, sc, member); - - tf = (TypeFunction *)f->type; - type = tf->next; - - if (!arguments) - arguments = new Expressions(); - unsigned olderrors = global.errors; - functionParameters(loc, sc, tf, arguments); - if (olderrors != global.errors) - return new ErrorExp(); - - } - else - { - if (arguments && arguments->dim) - { error("no constructor for %s", cd->toChars()); - goto Lerr; - } - } - - if (cd->aggNew) - { - // Prepend the size argument to newargs[] - Expression *e = new IntegerExp(loc, cd->size(loc), Type::tsize_t); - if (!newargs) - newargs = new Expressions(); - newargs->shift(e); - - f = cd->aggNew->overloadResolve(loc, NULL, newargs, sc->module); - allocator = f->isNewDeclaration(); - assert(allocator); - - tf = (TypeFunction *)f->type; - unsigned olderrors = global.errors; - functionParameters(loc, sc, tf, newargs); - if (olderrors != global.errors) - return new ErrorExp(); - - } - else - { - if (newargs && newargs->dim) - { error("no allocator for %s", cd->toChars()); - goto Lerr; - } - } - } - else if (tb->ty == Tstruct) - { - TypeStruct *ts = (TypeStruct *)tb; - StructDeclaration *sd = ts->sym; - FuncDeclaration *f = sd->aggNew; - TypeFunction *tf; - - if (arguments && arguments->dim) - error("no constructor for %s", type->toChars()); - - if (f) - { - Expression *e; - - // Prepend the uint size argument to newargs[] - e = new IntegerExp(loc, sd->size(loc), Type::tuns32); - if (!newargs) - newargs = new Expressions(); - newargs->shift(e); - - f = f->overloadResolve(loc, NULL, newargs, sc->module); - allocator = f->isNewDeclaration(); - assert(allocator); - - tf = (TypeFunction *)f->type; - unsigned olderrors = global.errors; - functionParameters(loc, sc, tf, newargs); - if (olderrors != global.errors) - return new ErrorExp(); - - e = new VarExp(loc, f); - e = new CallExp(loc, e, newargs); - e = e->semantic(sc); - e->type = type->pointerTo(); - return e; - } - - type = type->pointerTo(); - } - else if (tb->ty == Tarray && (arguments && arguments->dim)) - { - for (size_t i = 0; i < arguments->dim; i++) - { - if (tb->ty != Tarray) - { error("too many arguments for array"); - goto Lerr; - } - - Expression *arg = arguments->tdata()[i]; - arg = resolveProperties(sc, arg); - arg = arg->implicitCastTo(sc, Type::tsize_t); - if (arg->op == TOKint64 && (long long)arg->toInteger() < 0) - { error("negative array index %s", arg->toChars()); - goto Lerr; - } - arguments->tdata()[i] = arg; - tb = ((TypeDArray *)tb)->next->toBasetype(); - } - } - else if (tb->isscalar()) - { - if (arguments && arguments->dim) - { error("no constructor for %s", type->toChars()); - goto Lerr; - } - - type = type->pointerTo(); - } - else - { - error("new can only create structs, dynamic arrays or class objects, not %s's", type->toChars()); - goto Lerr; - } - -//printf("NewExp: '%s'\n", toChars()); -//printf("NewExp:type '%s'\n", type->toChars()); - - return this; - -Lerr: - return new ErrorExp(); -} - -int NewExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int NewExp::canThrow(bool mustNotThrow) -{ - if (arrayExpressionCanThrow(newargs, mustNotThrow) || - arrayExpressionCanThrow(arguments, mustNotThrow)) - return 1; - if (member) - { - // See if constructor call can throw - Type *t = member->type->toBasetype(); - if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow) - { - if (mustNotThrow) - error("constructor %s is not nothrow", member->toChars()); - return 1; - } - } - // regard storage allocation failures as not recoverable - return 0; -} -#endif - -void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (thisexp) - { expToCBuffer(buf, hgs, thisexp, PREC_primary); - buf->writeByte('.'); - } - buf->writestring("new "); - if (newargs && newargs->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, newargs, hgs); - buf->writeByte(')'); - } - newtype->toCBuffer(buf, NULL, hgs); - if (arguments && arguments->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); - } -} - -/********************** NewAnonClassExp **************************************/ - -NewAnonClassExp::NewAnonClassExp(Loc loc, Expression *thisexp, - Expressions *newargs, ClassDeclaration *cd, Expressions *arguments) - : Expression(loc, TOKnewanonclass, sizeof(NewAnonClassExp)) -{ - this->thisexp = thisexp; - this->newargs = newargs; - this->cd = cd; - this->arguments = arguments; -} - -Expression *NewAnonClassExp::syntaxCopy() -{ - return new NewAnonClassExp(loc, - thisexp ? thisexp->syntaxCopy() : NULL, - arraySyntaxCopy(newargs), - (ClassDeclaration *)cd->syntaxCopy(NULL), - arraySyntaxCopy(arguments)); -} - - -Expression *NewAnonClassExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("NewAnonClassExp::semantic() %s\n", toChars()); - //printf("thisexp = %p\n", thisexp); - //printf("type: %s\n", type->toChars()); -#endif - - Expression *d = new DeclarationExp(loc, cd); - d = d->semantic(sc); - - Expression *n = new NewExp(loc, thisexp, newargs, cd->type, arguments); - - Expression *c = new CommaExp(loc, d, n); - return c->semantic(sc); -} - -int NewAnonClassExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int NewAnonClassExp::canThrow() -{ - return 1; -} -#endif - -void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (thisexp) - { expToCBuffer(buf, hgs, thisexp, PREC_primary); - buf->writeByte('.'); - } - buf->writestring("new"); - if (newargs && newargs->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, newargs, hgs); - buf->writeByte(')'); - } - buf->writestring(" class "); - if (arguments && arguments->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); - } - //buf->writestring(" { }"); - if (cd) - { - cd->toCBuffer(buf, hgs); - } -} - -/********************** SymbolExp **************************************/ - -#if DMDV2 -SymbolExp::SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads) - : Expression(loc, op, size) -{ - assert(var); - this->var = var; - this->hasOverloads = hasOverloads; -} -#endif - -/********************** SymOffExp **************************************/ - -SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset) - : Expression(loc, TOKsymoff, sizeof(SymOffExp)) -{ - assert(var); - this->var = var; - this->offset = offset; - m = NULL; - VarDeclaration *v = var->isVarDeclaration(); - if (v && v->needThis()) - error("need 'this' for address of %s", v->toChars()); -} - -Expression *SymOffExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("SymOffExp::semantic('%s')\n", toChars()); -#endif - //var->semantic(sc); - m = sc->module; - if (!type) - type = var->type->pointerTo(); - VarDeclaration *v = var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, loc); - return this; -} - -int SymOffExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - -void SymOffExp::checkEscape() -{ - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg() && !(v->storage_class & (STCref | STCout))) - { /* BUG: This should be allowed: - * void foo() - * { int a; - * int* bar() { return &a; } - * } - */ - error("escaping reference to local %s", v->toChars()); - } - } -} - -void SymOffExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (offset) - buf->printf("(& %s+%u)", var->toChars(), offset); - else - buf->printf("& %s", var->toChars()); -} - -/******************************** VarExp **************************/ - -VarExp::VarExp(Loc loc, Declaration *var) - : Expression(loc, TOKvar, sizeof(VarExp)) -{ - //printf("VarExp(this = %p, '%s')\n", this, var->toChars()); - this->var = var; - this->type = var->type; -} - -int VarExp::equals(Object *o) -{ VarExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKvar && - ((ne = (VarExp *)o), type->equals(ne->type)) && - var == ne->var)) - return 1; - return 0; -} - -Expression *VarExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("VarExp::semantic(%s)\n", toChars()); -#endif - if (!type) - { type = var->type; -#if 0 - if (var->storage_class & STClazy) - { - TypeFunction *tf = new TypeFunction(NULL, type, 0, LINKd); - type = new TypeDelegate(tf); - type = type->semantic(loc, sc); - } -#endif - } - - if (type && !type->deco) - type = type->semantic(loc, sc); - - /* Fix for 1161 doesn't work because it causes protection - * problems when instantiating imported templates passing private - * variables as alias template parameters. - */ - //accessCheck(loc, sc, NULL, var); - - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { - if (v->isSameAsInitializer() && type->toBasetype()->ty != Tsarray && v->init) - { - ExpInitializer *ei = v->init->isExpInitializer(); - if (ei && ei->exp->type) - { - //ei->exp->implicitCastTo(sc, type)->print(); - return ei->exp->implicitCastTo(sc, type); - } - } - v->checkNestedReference(sc, loc); -#if DMDV2 - if (sc->func && sc->func->isPure() && !sc->intypeof) - { - if (v->isDataseg() && !v->isImmutable()) - error("pure function '%s' cannot access mutable static data '%s'", sc->func->toChars(), v->toChars()); - } -#endif - } -#if 0 - else if ((fd = var->isFuncLiteralDeclaration()) != NULL) - { Expression *e; - e = new FuncExp(loc, fd); - e->type = type; - return e; - } -#endif - - return this; -} - -char *VarExp::toChars() -{ - return var->toChars(); -} - -void VarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(var->toChars()); -} - -void VarExp::checkEscape() -{ - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { Type *tb = v->type->toBasetype(); - // if reference type - if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass) - { - if (v->isScope() && !v->noscope) - error("escaping reference to auto local %s", v->toChars()); - else if (v->storage_class & STCvariadic) - error("escaping reference to variadic parameter %s", v->toChars()); - } - } -} - -void VarExp::checkEscapeRef() -{ - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg() && !(v->storage_class & (STCref | STCout))) - error("escaping reference to local variable %s", v->toChars()); - } -} - - -int VarExp::isLvalue() -{ - if (var->storage_class & STClazy) - return 0; - return 1; -} - - -Expression *VarExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - if (var->storage_class & STClazy) - error("lazy variables cannot be lvalues"); - return this; -} - -Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("VarExp::modifiableLvalue('%s')\n", var->toChars()); - if (sc->incontract && var->isParameter()) - error("cannot modify parameter '%s' in contract", var->toChars()); - - if (type && type->toBasetype()->ty == Tsarray) - error("cannot change reference to static array '%s'", var->toChars()); - - VarDeclaration *v = var->isVarDeclaration(); - if (v && v->canassign == 0 && - (var->isConst() || (global.params.Dversion > 1 && var->isFinal()))) - error("cannot modify final variable '%s'", var->toChars()); - - if (var->isCtorinit()) - { // It's only modifiable if inside the right constructor - Dsymbol *s = sc->func; - while (1) - { - FuncDeclaration *fd = NULL; - if (s) - fd = s->isFuncDeclaration(); - if (fd && - ((fd->isCtorDeclaration() && var->storage_class & STCfield) || - (fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) && - fd->toParent() == var->toParent() - ) - { - VarDeclaration *v = var->isVarDeclaration(); - assert(v); - v->ctorinit = 1; - //printf("setting ctorinit\n"); - } - else - { - if (s) - { s = s->toParent2(); - continue; - } - else - { - const char *p = var->isStatic() ? "static " : ""; - error("can only initialize %sconst %s inside %sconstructor", - p, var->toChars(), p); - } - } - break; - } - } - - // See if this expression is a modifiable lvalue (i.e. not const) - return toLvalue(sc, e); -} - - -/******************************** OverExp **************************/ - -#if DMDV2 -OverExp::OverExp(OverloadSet *s) - : Expression(loc, TOKoverloadset, sizeof(OverExp)) -{ - //printf("OverExp(this = %p, '%s')\n", this, var->toChars()); - vars = s; - type = Type::tvoid; -} - -int OverExp::isLvalue() -{ - return 1; -} - -Expression *OverExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} -#endif - - -/******************************** TupleExp **************************/ - -TupleExp::TupleExp(Loc loc, Expressions *exps) - : Expression(loc, TOKtuple, sizeof(TupleExp)) -{ - //printf("TupleExp(this = %p)\n", this); - this->exps = exps; - this->type = NULL; -} - - -TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) - : Expression(loc, TOKtuple, sizeof(TupleExp)) -{ - exps = new Expressions(); - type = NULL; - - exps->reserve(tup->objects->dim); - for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = tup->objects->tdata()[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { - Expression *e = (Expression *)o; - e = e->syntaxCopy(); - exps->push(e); - } - else if (o->dyncast() == DYNCAST_DSYMBOL) - { - Dsymbol *s = (Dsymbol *)o; - Expression *e = new DsymbolExp(loc, s); - exps->push(e); - } - else if (o->dyncast() == DYNCAST_TYPE) - { - Type *t = (Type *)o; - Expression *e = new TypeExp(loc, t); - exps->push(e); - } - else - { - error("%s is not an expression", o->toChars()); - } - } -} - -int TupleExp::equals(Object *o) -{ - if (this == o) - return 1; - if (((Expression *)o)->op == TOKtuple) - { - TupleExp *te = (TupleExp *)o; - if (exps->dim != te->exps->dim) - return 0; - for (size_t i = 0; i < exps->dim; i++) - { Expression *e1 = (*exps)[i]; - Expression *e2 = (*te->exps)[i]; - - if (!e1->equals(e2)) - return 0; - } - return 1; - } - return 0; -} - -Expression *TupleExp::syntaxCopy() -{ - return new TupleExp(loc, arraySyntaxCopy(exps)); -} - -Expression *TupleExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("+TupleExp::semantic(%s)\n", toChars()); -#endif - if (type) - return this; - - // Run semantic() on each argument - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - - e = e->semantic(sc); - if (!e->type) - { error("%s has no value", e->toChars()); - e = new ErrorExp(); - } - (*exps)[i] = e; - } - - expandTuples(exps); - type = new TypeTuple(exps); - type = type->semantic(loc, sc); - //printf("-TupleExp::semantic(%s)\n", toChars()); - return this; -} - -void TupleExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("tuple("); - argsToCBuffer(buf, exps, hgs); - buf->writeByte(')'); -} - -int TupleExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - - f |= e->hasSideEffect(); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -#if DMDV2 -int TupleExp::canThrow(bool mustNotThrow) -{ - return arrayExpressionCanThrow(exps, mustNotThrow); -} -#endif - -void TupleExp::checkEscape() -{ - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - e->checkEscape(); - } -} - -/******************************** FuncExp *********************************/ - -FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd) - : Expression(loc, TOKfunction, sizeof(FuncExp)) -{ - this->fd = fd; -} - -Expression *FuncExp::syntaxCopy() -{ - return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL)); -} - -Expression *FuncExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("FuncExp::semantic(%s)\n", toChars()); -#endif - if (!type) - { - unsigned olderrors = global.errors; - fd->semantic(sc); - fd->parent = sc->parent; - if (olderrors != global.errors) - { - } - else - { - fd->semantic2(sc); - if ( (olderrors == global.errors) || - // need to infer return type - (fd->type && fd->type->ty == Tfunction && !fd->type->nextOf())) - { - fd->semantic3(sc); - - if ( (olderrors == global.errors) && global.params.useInline) - fd->inlineScan(); - } - } - - // need to infer return type - if ((olderrors != global.errors) && fd->type && fd->type->ty == Tfunction && !fd->type->nextOf()) - ((TypeFunction *)fd->type)->next = Type::terror; - - // Type is a "delegate to" or "pointer to" the function literal - if (fd->isNested()) - { - type = new TypeDelegate(fd->type); - type = type->semantic(loc, sc); - } - else - { - type = fd->type->pointerTo(); - } - } - return this; -} - -char *FuncExp::toChars() -{ - return fd->toChars(); -} - -void FuncExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - fd->toCBuffer(buf, hgs); - //buf->writestring(fd->toChars()); -} - - -/******************************** DeclarationExp **************************/ - -DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration) - : Expression(loc, TOKdeclaration, sizeof(DeclarationExp)) -{ - this->declaration = declaration; -} - -Expression *DeclarationExp::syntaxCopy() -{ - return new DeclarationExp(loc, declaration->syntaxCopy(NULL)); -} - -Expression *DeclarationExp::semantic(Scope *sc) -{ - if (type) - return this; - -#if LOGSEMANTIC - printf("DeclarationExp::semantic() %s\n", toChars()); -#endif - - unsigned olderrors = global.errors; - - /* This is here to support extern(linkage) declaration, - * where the extern(linkage) winds up being an AttribDeclaration - * wrapper. - */ - Dsymbol *s = declaration; - - AttribDeclaration *ad = declaration->isAttribDeclaration(); - if (ad) - { - if (ad->decl && ad->decl->dim == 1) - s = ad->decl->tdata()[0]; - } - - if (s->isVarDeclaration()) - { // Do semantic() on initializer first, so: - // int a = a; - // will be illegal. - declaration->semantic(sc); - s->parent = sc->parent; - } - - //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc); - // Insert into both local scope and function scope. - // Must be unique in both. - if (s->ident) - { - if (!sc->insert(s)) - error("declaration %s is already defined", s->toPrettyChars()); - else if (sc->func) - { VarDeclaration *v = s->isVarDeclaration(); - if ( (s->isFuncDeclaration() || s->isTypedefDeclaration() || - s->isAggregateDeclaration() || s->isEnumDeclaration() || - s->isInterfaceDeclaration()) && - !sc->func->localsymtab->insert(s)) - { - error("declaration %s is already defined in another scope in %s", - s->toPrettyChars(), sc->func->toChars()); - } - else if (!global.params.useDeprecated) - { // Disallow shadowing - - for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing) - { Dsymbol *s2; - - if (scx->scopesym && scx->scopesym->symtab && - (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL && - s != s2) - { - error("shadowing declaration %s is deprecated", s->toPrettyChars()); - } - } - } - } - } - if (!s->isVarDeclaration()) - { - Scope *sc2 = sc; - if (sc2->stc & (STCpure | STCnothrow)) - sc2 = sc->push(); - sc2->stc &= ~(STCpure | STCnothrow); - declaration->semantic(sc2); - if (sc2 != sc) - sc2->pop(); - s->parent = sc->parent; - } - if (global.errors == olderrors) - { - declaration->semantic2(sc); - if (global.errors == olderrors) - { - declaration->semantic3(sc); - - if ((global.errors == olderrors) && global.params.useInline) - declaration->inlineScan(); - } - } - - type = Type::tvoid; - return this; -} - -int DeclarationExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int DeclarationExp::canThrow() -{ - VarDeclaration *v = declaration->isVarDeclaration(); - if (v && v->init) - { ExpInitializer *ie = v->init->isExpInitializer(); - return ie && ie->exp->canThrow(); - } - return 0; -} -#endif - -void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - declaration->toCBuffer(buf, hgs); -} - - -/************************ TypeidExp ************************************/ - -/* - * typeid(int) - */ - -TypeidExp::TypeidExp(Loc loc, Type *typeidType) - : Expression(loc, TOKtypeid, sizeof(TypeidExp)) -{ - this->typeidType = typeidType; -} - - -Expression *TypeidExp::syntaxCopy() -{ - return new TypeidExp(loc, typeidType->syntaxCopy()); -} - - -Expression *TypeidExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("TypeidExp::semantic()\n"); -#endif - typeidType = typeidType->semantic(loc, sc); - e = typeidType->getTypeInfo(sc); - if (e->loc.linnum == 0) - e->loc = loc; // so there's at least some line number info - return e; -} - -void TypeidExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typeid("); - typeidType->toCBuffer(buf, NULL, hgs); - buf->writeByte(')'); -} - -/************************ TraitsExp ************************************/ -#if DMDV2 -/* - * __traits(identifier, args...) - */ - -TraitsExp::TraitsExp(Loc loc, Identifier *ident, Objects *args) - : Expression(loc, TOKtraits, sizeof(TraitsExp)) -{ - this->ident = ident; - this->args = args; -} - - -Expression *TraitsExp::syntaxCopy() -{ - return new TraitsExp(loc, ident, TemplateInstance::arraySyntaxCopy(args)); -} - - -void TraitsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("__traits("); - buf->writestring(ident->toChars()); - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - buf->writeByte(','); - Object *oarg = (Object *)args->data[i]; - ObjectToCBuffer(buf, hgs, oarg); - } - } - buf->writeByte(')'); -} -#endif - -/************************************************************/ - -HaltExp::HaltExp(Loc loc) - : Expression(loc, TOKhalt, sizeof(HaltExp)) -{ -} - -Expression *HaltExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("HaltExp::semantic()\n"); -#endif - type = Type::tvoid; - return this; -} - -int HaltExp::checkSideEffect(int flag) -{ - return 1; -} - -void HaltExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("halt"); -} - -/************************************************************/ - -IsExp::IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, - Type *tspec, enum TOK tok2) - : Expression(loc, TOKis, sizeof(IsExp)) -{ - this->targ = targ; - this->id = id; - this->tok = tok; - this->tspec = tspec; - this->tok2 = tok2; -} - -Expression *IsExp::syntaxCopy() -{ - return new IsExp(loc, - targ->syntaxCopy(), - id, - tok, - tspec ? tspec->syntaxCopy() : NULL, - tok2); -} - -Expression *IsExp::semantic(Scope *sc) -{ Type *tded; - - /* is(targ id tok tspec) - * is(targ id == tok2) - */ - - //printf("IsExp::semantic(%s)\n", toChars()); - if (id && !(sc->flags & SCOPEstaticif)) - error("can only declare type aliases within static if conditionals"); - - unsigned errors_save = global.startGagging(); - targ = targ->semantic(loc, sc); - if (global.endGagging(errors_save)) // if any errors happened - { // then condition is false - goto Lno; - } - else if (tok2 != TOKreserved) - { - switch (tok2) - { - case TOKtypedef: - if (targ->ty != Ttypedef) - goto Lno; - tded = ((TypeTypedef *)targ)->sym->basetype; - break; - - case TOKstruct: - if (targ->ty != Tstruct) - goto Lno; - if (((TypeStruct *)targ)->sym->isUnionDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKunion: - if (targ->ty != Tstruct) - goto Lno; - if (!((TypeStruct *)targ)->sym->isUnionDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKclass: - if (targ->ty != Tclass) - goto Lno; - if (((TypeClass *)targ)->sym->isInterfaceDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKinterface: - if (targ->ty != Tclass) - goto Lno; - if (!((TypeClass *)targ)->sym->isInterfaceDeclaration()) - goto Lno; - tded = targ; - break; -#if DMDV2 - case TOKconst: - if (!targ->isConst()) - goto Lno; - tded = targ; - break; - - case TOKinvariant: - case TOKimmutable: - if (!targ->isImmutable()) - goto Lno; - tded = targ; - break; - - case TOKshared: - if (!targ->isShared()) - goto Lno; - tded = targ; - break; -#endif - - case TOKsuper: - // If class or interface, get the base class and interfaces - if (targ->ty != Tclass) - goto Lno; - else - { ClassDeclaration *cd = ((TypeClass *)targ)->sym; - Parameters *args = new Parameters; - args->reserve(cd->baseclasses->dim); - for (size_t i = 0; i < cd->baseclasses->dim; i++) - { BaseClass *b = (BaseClass *)cd->baseclasses->data[i]; - args->push(new Parameter(STCin, b->type, NULL, NULL)); - } - tded = new TypeTuple(args); - } - break; - - case TOKenum: - if (targ->ty != Tenum) - goto Lno; - tded = ((TypeEnum *)targ)->sym->memtype; - break; - - case TOKdelegate: - if (targ->ty != Tdelegate) - goto Lno; - tded = ((TypeDelegate *)targ)->next; // the underlying function type - break; - - case TOKfunction: - { - if (targ->ty != Tfunction) - goto Lno; - tded = targ; - - /* Generate tuple from function parameter types. - */ - assert(tded->ty == Tfunction); - Parameters *params = ((TypeFunction *)tded)->parameters; - size_t dim = Parameter::dim(params); - Parameters *args = new Parameters; - args->reserve(dim); - for (size_t i = 0; i < dim; i++) - { Parameter *arg = Parameter::getNth(params, i); - assert(arg && arg->type); - args->push(new Parameter(arg->storageClass, arg->type, NULL, NULL)); - } - tded = new TypeTuple(args); - break; - } - case TOKreturn: - /* Get the 'return type' for the function, - * delegate, or pointer to function. - */ - if (targ->ty == Tfunction) - tded = ((TypeFunction *)targ)->next; - else if (targ->ty == Tdelegate) - tded = targ->next->next; - else if (targ->ty == Tpointer && targ->next->ty == Tfunction) - tded = targ->next->next; - else - goto Lno; - break; - - case TOKargTypes: - /* Generate a type tuple of the equivalent types used to determine if a - * function argument of this type can be passed in registers. - * The results of this are highly platform dependent, and intended - * primarly for use in implementing va_arg(). - */ - tded = targ->toArgTypes(); - if (!tded) - goto Lno; // not valid for a parameter - break; - - default: - assert(0); - } - goto Lyes; - } - else if (id && tspec) - { - /* Evaluate to TRUE if targ matches tspec. - * If TRUE, declare id as an alias for the specialized type. - */ - - TemplateTypeParameter tp(loc, id, NULL, NULL); - - TemplateParameters parameters; - parameters.setDim(1); - parameters.data[0] = (void *)&tp; - - Objects dedtypes; - dedtypes.setDim(parameters.dim); - dedtypes.zero(); - - MATCH m = targ->deduceType(sc, tspec, ¶meters, &dedtypes); - if (m == MATCHnomatch || - (m != MATCHexact && tok == TOKequal)) - { - goto Lno; - } - else - { - assert(dedtypes.dim == 1); - tded = (Type *)dedtypes.data[0]; - if (!tded) - tded = targ; -#if DMDV2 - Objects tiargs; - tiargs.setDim(1); - tiargs.data[0] = (void *)targ; - - /* Declare trailing parameters - */ - for (size_t i = 1; i < parameters->dim; i++) - { TemplateParameter *tp = (*parameters)[i]; - Declaration *s = NULL; - - m = tp->matchArg(sc, &tiargs, i, parameters, &dedtypes, &s); - if (m == MATCHnomatch) - goto Lno; - s->semantic(sc); - if (sc->sd) - s->addMember(sc, sc->sd, 1); - else if (!sc->insert(s)) - error("declaration %s is already defined", s->toChars()); - } -#endif - goto Lyes; - } - } - else if (id) - { - /* Declare id as an alias for type targ. Evaluate to TRUE - */ - tded = targ; - goto Lyes; - } - else if (tspec) - { - /* Evaluate to TRUE if targ matches tspec - * is(targ == tspec) - * is(targ : tspec) - */ - tspec = tspec->semantic(loc, sc); - //printf("targ = %s, %s\n", targ->toChars(), targ->deco); - //printf("tspec = %s, %s\n", tspec->toChars(), tspec->deco); - if (tok == TOKcolon) - { if (targ->implicitConvTo(tspec)) - goto Lyes; - else - goto Lno; - } - else /* == */ - { if (targ->equals(tspec)) - goto Lyes; - else - goto Lno; - } - } - -Lyes: - if (id) - { - Dsymbol *s; - Tuple *tup = isTuple(tded); - if (tup) - s = new TupleDeclaration(loc, id, &(tup->objects)); - else - s = new AliasDeclaration(loc, id, tded); - s->semantic(sc); - /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there. - * More investigation is needed. - */ - if (!tup && !sc->insert(s)) - error("declaration %s is already defined", s->toChars()); - if (sc->sd) - s->addMember(sc, sc->sd, 1); - } - return new IntegerExp(1); - -Lno: - return new IntegerExp(0); -} - -void IsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("is("); - targ->toCBuffer(buf, id, hgs); - if (tok2 != TOKreserved) - { - buf->printf(" %s %s", Token::toChars(tok), Token::toChars(tok2)); - } - else if (tspec) - { - if (tok == TOKcolon) - buf->writestring(" : "); - else - buf->writestring(" == "); - tspec->toCBuffer(buf, NULL, hgs); - } -#if DMDV2 - if (parameters) - { // First parameter is already output, so start with second - for (size_t i = 1; i < parameters->dim; i++) - { - buf->writeByte(','); - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - tp->toCBuffer(buf, hgs); - } - } -#endif - buf->writeByte(')'); -} - - -/************************************************************/ - -UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1) - : Expression(loc, op, size) -{ - this->e1 = e1; -} - -Expression *UnaExp::syntaxCopy() -{ UnaExp *e; - - e = (UnaExp *)copy(); - e->type = NULL; - e->e1 = e->e1->syntaxCopy(); - return e; -} - -Expression *UnaExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("UnaExp::semantic('%s')\n", toChars()); -#endif - e1 = e1->semantic(sc); -// if (!e1->type) -// error("%s has no value", e1->toChars()); - return this; -} - -#if DMDV2 -int UnaExp::canThrow() -{ - return e1->canThrow(); -} -#endif - -void UnaExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -BinExp::BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) - : Expression(loc, op, size) -{ - this->e1 = e1; - this->e2 = e2; -} - -Expression *BinExp::syntaxCopy() -{ BinExp *e; - - e = (BinExp *)copy(); - e->type = NULL; - e->e1 = e->e1->syntaxCopy(); - e->e2 = e->e2->syntaxCopy(); - return e; -} - -Expression *BinExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("BinExp::semantic('%s')\n", toChars()); -#endif - e1 = e1->semantic(sc); - if (!e1->type && - !(op == TOKassign && e1->op == TOKdottd)) // a.template = e2 - { - error("%s has no value", e1->toChars()); - e1 = new ErrorExp(); - } - e2 = e2->semantic(sc); - if (!e2->type) - { - error("%s has no value", e2->toChars()); - e2 = new ErrorExp(); - } - if (e1->op == TOKerror || e2->op == TOKerror) - return new ErrorExp(); - return this; -} - -Expression *BinExp::semanticp(Scope *sc) -{ - BinExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e2 = resolveProperties(sc, e2); - return this; -} - -/*************************** - * Common semantic routine for some xxxAssignExp's. - */ - -Expression *BinExp::commonSemanticAssign(Scope *sc) -{ Expression *e; - - if (!type) - { - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] op= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - type = e1->type; - if (type->toBasetype()->ty == Tbool) - { - error("operator not allowed on bool expression %s", toChars()); - } - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - - if (op == TOKmodass && e2->type->iscomplex()) - { error("cannot perform modulo complex arithmetic"); - return new ErrorExp(); - } - } - return this; -} - -Expression *BinExp::commonSemanticAssignIntegral(Scope *sc) -{ Expression *e; - - if (!type) - { - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] op= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - type = e1->type; - if (type->toBasetype()->ty == Tbool) - { - e2 = e2->implicitCastTo(sc, type); - } - - typeCombine(sc); - e1->checkIntegral(); - e2->checkIntegral(); - } - return this; -} - -int BinExp::checkSideEffect(int flag) -{ - if (op == TOKplusplus || - op == TOKminusminus || - op == TOKassign || - op == TOKconstruct || - op == TOKblit || - op == TOKaddass || - op == TOKminass || - op == TOKcatass || - op == TOKmulass || - op == TOKdivass || - op == TOKmodass || - op == TOKshlass || - op == TOKshrass || - op == TOKushrass || - op == TOKandass || - op == TOKorass || - op == TOKxorass || - op == TOKin || - op == TOKremove) - return 1; - return Expression::checkSideEffect(flag); -} - -// generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary -void BinExp::checkComplexMulAssign() -{ - // Any multiplication by an imaginary or complex number yields a complex result. - // r *= c, i*=c, r*=i, i*=i are all forbidden operations. - const char *opstr = Token::toChars(op); - if ( e1->type->isreal() && e2->type->iscomplex()) - { - error("%s %s %s is undefined. Did you mean %s %s %s.re ?", - e1->type->toChars(), opstr, e2->type->toChars(), - e1->type->toChars(), opstr, e2->type->toChars()); - } - else if (e1->type->isimaginary() && e2->type->iscomplex()) - { - error("%s %s %s is undefined. Did you mean %s %s %s.im ?", - e1->type->toChars(), opstr, e2->type->toChars(), - e1->type->toChars(), opstr, e2->type->toChars()); - } - else if ((e1->type->isreal() || e1->type->isimaginary()) && - e2->type->isimaginary()) - { - error("%s %s %s is an undefined operation", e1->type->toChars(), - opstr, e2->type->toChars()); - } -} - -// generate an error if this is a nonsensical += or -=, eg real += imaginary -void BinExp::checkComplexAddAssign() -{ - // Addition or subtraction of a real and an imaginary is a complex result. - // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. - if ( (e1->type->isreal() && (e2->type->isimaginary() || e2->type->iscomplex())) || - (e1->type->isimaginary() && (e2->type->isreal() || e2->type->iscomplex())) - ) - { - error("%s %s %s is undefined (result is complex)", - e1->type->toChars(), Token::toChars(op), e2->type->toChars()); - } -} - -void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte(' '); - buf->writestring(Token::toChars(op)); - buf->writeByte(' '); - expToCBuffer(buf, hgs, e2, (enum PREC)(precedence[op] + 1)); -} - -int BinExp::isunsigned() -{ - return e1->type->isunsigned() || e2->type->isunsigned(); -} - -#if DMDV2 -int BinExp::canThrow() -{ - return e1->canThrow() || e2->canThrow(); -} -#endif - -void BinExp::incompatibleTypes() -{ - if (e1->type->toBasetype() != Type::terror && - e2->type->toBasetype() != Type::terror - ) - error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", - e1->toChars(), Token::toChars(op), e2->toChars(), - e1->type->toChars(), e2->type->toChars()); -} - -/************************************************************/ - -Expression *BinAssignExp::semantic(Scope *sc) -{ Expression *e; - - //printf("BinAssignExp::semantic()\n"); - if (type) - return this; - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); -#if !IN_LLVM - e2 = e2->castTo(sc, Type::tshiftcnt); -#else - e2 = e2->castTo(sc, e1->type); -#endif - return this; -} - -int BinAssignExp::isLvalue() -{ - return 1; -} - -/************************************************************/ - -CompileExp::CompileExp(Loc loc, Expression *e) - : UnaExp(loc, TOKmixin, sizeof(CompileExp), e) -{ -} - -Expression *CompileExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("CompileExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - if (e1->op == TOKerror) - return e1; - if (!e1->type->isString()) - { - error("argument to mixin must be a string type, not %s\n", e1->type->toChars()); - return new ErrorExp(); - } - e1 = e1->ctfeInterpret(); - StringExp *se = e1->toString(); - if (!se) - { error("argument to mixin must be a string, not (%s)", e1->toChars()); - return new ErrorExp(); - } - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - //printf("p.loc.linnum = %d\n", p.loc.linnum); - Expression *e = p.parseExpression(); - if (p.token.value != TOKeof) - error("incomplete mixin expression (%s)", se->toChars()); - return e->semantic(sc); -} - -void CompileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - expToCBuffer(buf, hgs, e1, PREC_assign); - buf->writeByte(')'); -} - -/************************************************************/ - -FileExp::FileExp(Loc loc, Expression *e) - : UnaExp(loc, TOKmixin, sizeof(FileExp), e) -{ -} - -Expression *FileExp::semantic(Scope *sc) -{ char *name; - StringExp *se; - -#if LOGSEMANTIC - printf("FileExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->ctfeInterpret(); - if (e1->op != TOKstring) - { error("file name argument must be a string, not (%s)", e1->toChars()); - goto Lerror; - } - se = (StringExp *)e1; - se = se->toUTF8(sc); - name = (char *)se->string; - - if (!global.params.fileImppath) - { error("need -Jpath switch to import text file %s", name); - goto Lerror; - } - - /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory - * ('Path Traversal') attacks. - * http://cwe.mitre.org/data/definitions/22.html - */ - - name = FileName::safeSearchPath((Strings *)global.filePath, name); - if (!name) - { error("file %s cannot be found or not in a path specified with -J", se->toChars()); - goto Lerror; - } - - if (global.params.verbose) - printf("file %s\t(%s)\n", (char *)se->string, name); - - { File f(name); - if (f.read()) - { error("cannot read file %s", f.toChars()); - goto Lerror; - } - else - { - f.ref = 1; - se = new StringExp(loc, f.buffer, f.len); - } - } - return se->semantic(sc); - - Lerror: - return new ErrorExp(); -} - -void FileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("import("); - expToCBuffer(buf, hgs, e1, PREC_assign); - buf->writeByte(')'); -} - -/************************************************************/ - -AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg) - : UnaExp(loc, TOKassert, sizeof(AssertExp), e) -{ - this->msg = msg; -} - -Expression *AssertExp::syntaxCopy() -{ - AssertExp *ae = new AssertExp(loc, e1->syntaxCopy(), - msg ? msg->syntaxCopy() : NULL); - return ae; -} - -Expression *AssertExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AssertExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - // BUG: see if we can do compile time elimination of the Assert - e1 = e1->optimize(WANTvalue); - e1 = e1->checkToBoolean(); - if (msg) - { - msg = msg->semantic(sc); - msg = resolveProperties(sc, msg); - msg = msg->implicitCastTo(sc, Type::tchar->arrayOf()); - msg = msg->optimize(WANTvalue); - } - if (e1->isBool(FALSE)) - { - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - if (fd) - fd->hasReturnExp |= 4; - - if (!global.params.useAssert) - { Expression *e = new HaltExp(loc); - e = e->semantic(sc); - return e; - } - } - type = Type::tvoid; - return this; -} - -int AssertExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int AssertExp::canThrow() -{ - /* assert()s are non-recoverable errors, so functions that - * use them can be considered "nothrow" - */ - return 0; //(global.params.useAssert != 0); -} -#endif - -void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("assert("); - expToCBuffer(buf, hgs, e1, PREC_assign); - if (msg) - { - buf->writeByte(','); - expToCBuffer(buf, hgs, msg, PREC_assign); - } - buf->writeByte(')'); -} - -/************************************************************/ - -DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident) - : UnaExp(loc, TOKdot, sizeof(DotIdExp), e) -{ - this->ident = ident; -} - -Expression *DotIdExp::semantic(Scope *sc) -{ Expression *e; - Expression *eleft; - Expression *eright; - -#if LOGSEMANTIC - printf("DotIdExp::semantic(this = %p, '%s')\n", this, toChars()); - //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); -#endif - -//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } - -#if 0 - /* Don't do semantic analysis if we'll be converting - * it to a string. - */ - if (ident == Id::stringof) - { char *s = e1->toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } -#endif - - /* Special case: rewrite this.id and super.id - * to be classtype.id and baseclasstype.id - * if we have no this pointer. - */ - if ((e1->op == TOKthis || e1->op == TOKsuper) && !hasThis(sc)) - { ClassDeclaration *cd; - StructDeclaration *sd; - AggregateDeclaration *ad; - - ad = sc->getStructClassScope(); - if (ad) - { - cd = ad->isClassDeclaration(); - if (cd) - { - if (e1->op == TOKthis) - { - e = typeDotIdExp(loc, cd->type, ident); - return e->semantic(sc); - } - else if (cd->baseClass && e1->op == TOKsuper) - { - e = typeDotIdExp(loc, cd->baseClass->type, ident); - return e->semantic(sc); - } - } - else - { - sd = ad->isStructDeclaration(); - if (sd) - { - if (e1->op == TOKthis) - { - e = typeDotIdExp(loc, sd->type, ident); - return e->semantic(sc); - } - } - } - } - } - - UnaExp::semantic(sc); - - if (ident == Id::mangleof) - { // symbol.mangleof - Dsymbol *ds; - switch (e1->op) - { - case TOKimport: ds = ((ScopeExp *)e1)->sds; goto L1; - case TOKvar: ds = ((VarExp *)e1)->var; goto L1; - case TOKdotvar: ds = ((DotVarExp *)e1)->var; goto L1; - L1: - char* s = ds->mangle(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } - } - - if (e1->op == TOKdotexp) - { - DotExp *de = (DotExp *)e1; - eleft = de->e1; - eright = de->e2; - } - else - { - if (e1->op != TOKtype) - e1 = resolveProperties(sc, e1); - eleft = NULL; - eright = e1; - } -#if DMDV2 - if (e1->op == TOKtuple && ident == Id::offsetof) - { /* 'distribute' the .offsetof to each of the tuple elements. - */ - TupleExp *te = (TupleExp *)e1; - Expressions *exps = new Expressions(); - exps->setDim(te->exps->dim); - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)te->exps->data[i]; - e = e->semantic(sc); - e = new DotIdExp(e->loc, e, Id::offsetof); - exps->data[i] = (void *)e; - } - e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } -#endif - - if (e1->op == TOKtuple && ident == Id::length) - { - TupleExp *te = (TupleExp *)e1; - e = new IntegerExp(loc, te->exps->dim, Type::tsize_t); - return e; - } - - if (e1->op == TOKdottd) - { - error("template %s does not have property %s", e1->toChars(), ident->toChars()); - return new ErrorExp(); - } - - if (!e1->type) - { - error("expression %s does not have property %s", e1->toChars(), ident->toChars()); - return new ErrorExp(); - } - - if (eright->op == TOKimport) // also used for template alias's - { - ScopeExp *ie = (ScopeExp *)eright; - - /* Disable access to another module's private imports. - * The check for 'is sds our current module' is because - * the current module should have access to its own imports. - */ - Dsymbol *s = ie->sds->search(loc, ident, - (ie->sds->isModule() && ie->sds != sc->module) ? 1 : 0); - if (s) - { - /* Check for access before resolving aliases because public - * aliases to private symbols are public. - */ - if (Declaration *d = s->isDeclaration()) - accessCheck(loc, sc, 0, d); - - s = s->toAlias(); - checkDeprecated(sc, s); - - EnumMember *em = s->isEnumMember(); - if (em) - { - e = em->value; - e = e->semantic(sc); - return e; - } - - VarDeclaration *v = s->isVarDeclaration(); - if (v) - { - //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); - if (v->inuse) - { - error("circular reference to '%s'", v->toChars()); - type = Type::tint32; - return this; - } - type = v->type; - if (v->isSameAsInitializer()) - { - if (v->init) - { - ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { - //printf("\tei: %p (%s)\n", ei->exp, ei->exp->toChars()); - //ei->exp = ei->exp->semantic(sc); - if (ei->exp->type == type) - { - e = ei->exp->copy(); // make copy so we can change loc - e->loc = loc; - return e; - } - } - } - else if (type->isscalar()) - { - e = type->defaultInit(); - e->loc = loc; - return e; - } - } - if (v->needThis()) - { - if (!eleft) - eleft = new ThisExp(loc); - e = new DotVarExp(loc, eleft, v); - e = e->semantic(sc); - } - else - { - e = new VarExp(loc, v); - if (eleft) - { e = new CommaExp(loc, eleft, e); - e->type = v->type; - } - } - e = e->deref(); - return e->semantic(sc); - } - - FuncDeclaration *f = s->isFuncDeclaration(); - if (f) - { - //printf("it's a function\n"); - if (f->needThis()) - { - if (!eleft) - eleft = new ThisExp(loc); - e = new DotVarExp(loc, eleft, f); - e = e->semantic(sc); - } - else - { - e = new VarExp(loc, f); - if (eleft) - { e = new CommaExp(loc, eleft, e); - e->type = f->type; - } - } - return e; - } -#if DMDV2 - OverloadSet *o = s->isOverloadSet(); - if (o) - { //printf("'%s' is an overload set\n", o->toChars()); - return new OverExp(o); - } -#endif - - Type *t = s->getType(); - if (t) - { - return new TypeExp(loc, t); - } - - TupleDeclaration *tup = s->isTupleDeclaration(); - if (tup) - { - if (eleft) - { error("cannot have e.tuple"); - return new ErrorExp(); - } - e = new TupleExp(loc, tup); - e = e->semantic(sc); - return e; - } - - ScopeDsymbol *sds = s->isScopeDsymbol(); - if (sds) - { - //printf("it's a ScopeDsymbol\n"); - e = new ScopeExp(loc, sds); - e = e->semantic(sc); - if (eleft) - e = new DotExp(loc, eleft, e); - return e; - } - - Import *imp = s->isImport(); - if (imp) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, imp->pkg); - return ie->semantic(sc); - } - - // BUG: handle other cases like in IdentifierExp::semantic() -#ifdef DEBUG - printf("s = '%s', kind = '%s'\n", s->toChars(), s->kind()); -#endif - assert(0); - } - else if (ident == Id::stringof) - { char *s = ie->toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } - s = ie->sds->search_correct(ident); - if (s) - error("undefined identifier '%s', did you mean '%s %s'?", - ident->toChars(), s->kind(), s->toChars()); - else - error("undefined identifier '%s'", ident->toChars()); - return new ErrorExp(); - } - else if (e1->type->ty == Tpointer && - ident != Id::init && ident != Id::__sizeof && - ident != Id::__xalignof && ident != Id::offsetof && - ident != Id::mangleof && ident != Id::stringof) - { /* Rewrite: - * p.ident - * as: - * (*p).ident - */ - e = new PtrExp(loc, e1); - e->type = ((TypePointer *)e1->type)->next; - return e->type->dotExp(sc, e, ident); - } -#if DMDV2 - else if (t1b->ty == Tarray || - t1b->ty == Tsarray || - t1b->ty == Taarray) - { /* If ident is not a valid property, rewrite: - * e1.ident - * as: - * .ident(e1) - */ - unsigned errors = global.startGagging(); - Type *t1 = e1->type; - e = e1->type->dotExp(sc, e1, ident); - if (global.endGagging(errors)) // if failed to find the property - { - e1->type = t1; // kludge to restore type - e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident); - e = new CallExp(loc, e, e1); - } - e = e->semantic(sc); - return e; - } -#endif - else - { - e = e1->type->dotExp(sc, e1, ident); - e = e->semantic(sc); - return e; - } -} - -void DotIdExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("DotIdExp::toCBuffer()\n"); - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(ident->toChars()); -} - -/********************** DotTemplateExp ***********************************/ - -// Mainly just a placeholder - -DotTemplateExp::DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td) - : UnaExp(loc, TOKdottd, sizeof(DotTemplateExp), e) - -{ - this->td = td; -} - -void DotTemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(td->toChars()); -} - - -/************************************************************/ - -DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *v) - : UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e) -{ - //printf("DotVarExp()\n"); - this->var = v; -} - -Expression *DotVarExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotVarExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - var = var->toAlias()->isDeclaration(); - - TupleDeclaration *tup = var->isTupleDeclaration(); - if (tup) - { /* Replace: - * e1.tuple(a, b, c) - * with: - * tuple(e1.a, e1.b, e1.c) - */ - Expressions *exps = new Expressions; - - exps->reserve(tup->objects->dim); - for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = (Object *)tup->objects->data[i]; - if (o->dyncast() != DYNCAST_EXPRESSION) - { - error("%s is not an expression", o->toChars()); - } - else - { - Expression *e = (Expression *)o; - if (e->op != TOKdsymbol) - error("%s is not a member", e->toChars()); - else - { DsymbolExp *ve = (DsymbolExp *)e; - - e = new DotVarExp(loc, e1, ve->s->isDeclaration()); - exps->push(e); - } - } - } - Expression *e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } - - e1 = e1->semantic(sc); - type = var->type; - if (!type && global.errors) - { // var is goofed up, just return 0 - return new ErrorExp(); - } - assert(type); - - if (!var->isFuncDeclaration()) // for functions, do checks after overload resolution - { - Dsymbol *vparent = var->toParent(); - AggregateDeclaration *ad = vparent ? vparent->isAggregateDeclaration() : NULL; - e1 = getRightThis(loc, sc, ad, e1, var); - if (!sc->noaccesscheck) - accessCheck(loc, sc, e1, var); - - VarDeclaration *v = var->isVarDeclaration(); - if (v && v->isSameAsInitializer()) - { ExpInitializer *ei = v->getExpInitializer(); - if (ei) - { Expression *e = ei->exp->copy(); - e = e->semantic(sc); - return e; - } - if (v->init) - { Expression *e = v->init->toExpression(); - if (e) - { e = e->copy(); - e = e->semantic(sc); - return e; - } - } - } - } - } - //printf("-DotVarExp::semantic('%s')\n", toChars()); - return this; -} - - -int DotVarExp::isLvalue() -{ - return 1; -} - - -Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) -{ - //printf("DotVarExp::toLvalue(%s)\n", toChars()); - return this; -} - -Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) -{ -#if 0 - printf("DotVarExp::modifiableLvalue(%s)\n", toChars()); - printf("e1->type = %s\n", e1->type->toChars()); - printf("var->type = %s\n", var->type->toChars()); -#endif - - if (var->isCtorinit()) - { // It's only modifiable if inside the right constructor - Dsymbol *s = sc->func; - while (1) - { - FuncDeclaration *fd = NULL; - if (s) - fd = s->isFuncDeclaration(); - if (fd && - ((fd->isCtorDeclaration() && var->storage_class & STCfield) || - (fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) && - fd->toParent2() == var->toParent() && - e1->op == TOKthis - ) - { - VarDeclaration *v = var->isVarDeclaration(); - assert(v); - v->ctorinit = 1; - //printf("setting ctorinit\n"); - } - else - { - if (s) - { s = s->toParent2(); - continue; - } - else - { - const char *p = var->isStatic() ? "static " : ""; - error("can only initialize %sconst member %s inside %sconstructor", - p, var->toChars(), p); - } - } - break; - } - } -#if DMDV2 - else - { - Type *t1 = e1->type->toBasetype(); - - if (!t1->isMutable() || - (t1->ty == Tpointer && !t1->nextOf()->isMutable()) || - !var->type->isMutable() || - !var->type->isAssignable() || - var->storage_class & STCmanifest - ) - error("cannot modify const/immutable expression %s", toChars()); - } -#endif - return this; -} - -void DotVarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(var->toChars()); -} - -/************************************************************/ - -/* Things like: - * foo.bar!(args) - */ - -DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti) - : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e) -{ - //printf("DotTemplateInstanceExp()\n"); - this->ti = ti; -} - -Expression *DotTemplateInstanceExp::syntaxCopy() -{ - DotTemplateInstanceExp *de = new DotTemplateInstanceExp(loc, - e1->syntaxCopy(), - (TemplateInstance *)ti->syntaxCopy(NULL)); - return de; -} - -Expression *DotTemplateInstanceExp::semantic(Scope *sc) -{ -#if 1 -#if LOGSEMANTIC - printf("DotTemplateInstanceExp::semantic('%s')\n", toChars()); -#endif - Expression *eleft; - Expression *e = new DotIdExp(loc, e1, ti->name); -L1: - e = e->semantic(sc); - if (e->op == TOKerror) - return e; - if (e->op == TOKdottd) - { - if (ti->errors) - return new ErrorExp(); - DotTemplateExp *dte = (DotTemplateExp *)e; - TemplateDeclaration *td = dte->td; - eleft = dte->e1; - ti->tempdecl = td; -#if DMDV2 - if (ti->needsTypeInference(sc)) - { - e1 = eleft; // save result of semantic() - return this; - } - else -#endif - ti->semantic(sc); - if (!ti->inst) // if template failed to expand - return new ErrorExp(); - Dsymbol *s = ti->inst->toAlias(); - Declaration *v = s->isDeclaration(); - if (v) - { - /* Fix for Bugzilla 4003 - * The problem is a class template member function v returning a reference to the same - * type as the enclosing template instantiation. This results in a nested instantiation, - * which of course gets short circuited. The return type then gets set to - * the template instance type before instantiation, rather than after. - * We can detect this by the deco not being set. If so, go ahead and retry - * the return type semantic. - * The offending code is the return type from std.typecons.Tuple.slice: - * ref Tuple!(Types[from .. to]) slice(uint from, uint to)() - * { - * return *cast(typeof(return) *) &(field[from]); - * } - * and this line from the following unittest: - * auto s = a.slice!(1, 3); - * where s's type wound up not having semantic() run on it. - */ - if (v->type && !v->type->deco) - v->type = v->type->semantic(v->loc, sc); - - e = new DotVarExp(loc, eleft, v); - e = e->semantic(sc); - return e; - } - e = new ScopeExp(loc, ti); - e = new DotExp(loc, eleft, e); - e = e->semantic(sc); - return e; - } - else if (e->op == TOKimport) - { ScopeExp *se = (ScopeExp *)e; - TemplateDeclaration *td = se->sds->isTemplateDeclaration(); - if (!td) - { error("%s is not a template", e->toChars()); - return new ErrorExp(); - } - ti->tempdecl = td; - e = new ScopeExp(loc, ti); - e = e->semantic(sc); - return e; - } - else if (e->op == TOKdotexp) - { DotExp *de = (DotExp *)e; - - if (de->e2->op == TOKimport) - { // This should *really* be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)de->e2; - de->e2 = new DsymbolExp(loc, se->sds); - de->e2 = de->e2->semantic(sc); - } - - if (de->e2->op == TOKtemplate) - { TemplateExp *te = (TemplateExp *) de->e2; - e = new DotTemplateExp(loc,de->e1,te->td); - } - goto L1; - } - error("%s isn't a template", e->toChars()); - return new ErrorExp(); -#else - Dsymbol *s; - Dsymbol *s2; - TemplateDeclaration *td; - Expression *e; - Identifier *id; - Type *t1; - Expression *eleft = NULL; - Expression *eright; - -#if LOGSEMANTIC - printf("DotTemplateInstanceExp::semantic('%s')\n", toChars()); -#endif - //e1->print(); - //print(); - e1 = e1->semantic(sc); - t1 = e1->type; - if (t1) - t1 = t1->toBasetype(); - //t1->print(); - - /* Extract the following from e1: - * s: the symbol which ti should be a member of - * eleft: if not NULL, it is the 'this' pointer for ti - */ - - if (e1->op == TOKdotexp) - { DotExp *de = (DotExp *)e1; - eleft = de->e1; - eright = de->e2; - } - else - { eleft = NULL; - eright = e1; - } - if (eright->op == TOKimport) - { - s = ((ScopeExp *)eright)->sds; - } - else if (e1->op == TOKtype) - { - s = t1->isClassHandle(); - if (!s) - { if (t1->ty == Tstruct) - s = ((TypeStruct *)t1)->sym; - else - goto L1; - } - } - else if (t1 && (t1->ty == Tstruct || t1->ty == Tclass)) - { - s = t1->toDsymbol(sc); - eleft = e1; - } - else if (t1 && t1->ty == Tpointer) - { - t1 = ((TypePointer *)t1)->next->toBasetype(); - if (t1->ty != Tstruct) - goto L1; - s = t1->toDsymbol(sc); - eleft = e1; - } - else - { - L1: - error("template %s is not a member of %s", ti->toChars(), e1->toChars()); - goto Lerr; - } - - assert(s); - id = ti->name; - s2 = s->search(loc, id, 0); - if (!s2) - { - if (!s->ident) - error("template identifier %s is not a member of undefined %s", id->toChars(), s->kind()); - else - error("template identifier %s is not a member of %s %s", id->toChars(), s->kind(), s->ident->toChars()); - goto Lerr; - } - s = s2; - s->semantic(sc); - s = s->toAlias(); - td = s->isTemplateDeclaration(); - if (!td) - { - error("%s is not a template", id->toChars()); - goto Lerr; - } - if (global.errors) - goto Lerr; - - ti->tempdecl = td; - - if (eleft) - { Declaration *v; - - ti->semantic(sc); - s = ti->inst->toAlias(); - v = s->isDeclaration(); - if (v) - { e = new DotVarExp(loc, eleft, v); - e = e->semantic(sc); - return e; - } - } - - e = new ScopeExp(loc, ti); - if (eleft) - { - e = new DotExp(loc, eleft, e); - } - e = e->semantic(sc); - return e; - -Lerr: - return new IntegerExp(loc, 0, Type::tint32); -#endif -} - -void DotTemplateInstanceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - ti->toCBuffer(buf, hgs); -} - -/************************************************************/ - -DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f) - : UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e) -{ - this->func = f; - this->hasOverloads = 0; - m = NULL; -} - -Expression *DelegateExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DelegateExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - m = sc->module; - e1 = e1->semantic(sc); - // LDC we need a copy as we store the LLVM tpye in TypeFunction, and delegate/members have different types for 'this' - type = new TypeDelegate(func->type->syntaxCopy()); - type = type->semantic(loc, sc); - AggregateDeclaration *ad = func->toParent()->isAggregateDeclaration(); - if (func->needThis()) - e1 = getRightThis(loc, sc, ad, e1, func); - if (ad && ad->isClassDeclaration() && ad->type != e1->type) - { // A downcast is required for interfaces, see Bugzilla 3706 - e1 = new CastExp(loc, e1, ad->type); - e1 = e1->semantic(sc); - } - } - return this; -} - -void DelegateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('&'); - if (!func->isNested()) - { - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - } - buf->writestring(func->toChars()); -} - -/************************************************************/ - -DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s) - : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e) -{ - this->sym = s; - this->type = s->getType(); -} - -Expression *DotTypeExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotTypeExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - return this; -} - -void DotTypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(sym->toChars()); -} - -/************************************************************/ - -CallExp::CallExp(Loc loc, Expression *e, Expressions *exps) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - this->arguments = exps; -} - -CallExp::CallExp(Loc loc, Expression *e) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - this->arguments = NULL; -} - -CallExp::CallExp(Loc loc, Expression *e, Expression *earg1) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - Expressions *arguments = new Expressions(); - if (earg1) - { arguments->setDim(1); - arguments->data[0] = (void *)earg1; - } - this->arguments = arguments; -} - -CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - Expressions *arguments = new Expressions(); - arguments->setDim(2); - arguments->data[0] = (void *)earg1; - arguments->data[1] = (void *)earg2; - - this->arguments = arguments; -} - -Expression *CallExp::syntaxCopy() -{ - return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); -} - - -Expression *CallExp::semantic(Scope *sc) -{ - TypeFunction *tf; - FuncDeclaration *f; - Type *t1; - int istemp; - Objects *targsi = NULL; // initial list of template arguments - -#if LOGSEMANTIC - printf("CallExp::semantic() %s\n", toChars()); -#endif - if (type) - return this; // semantic() already run -#if 0 - if (arguments && arguments->dim) - { - Expression *earg = (Expression *)arguments->data[0]; - earg->print(); - if (earg->type) earg->type->print(); - } -#endif - - if (e1->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)e1; - - e1 = new DotVarExp(de->loc, de->e1, de->func); - return semantic(sc); - } - - /* Transform: - * array.id(args) into id(array,args) - * aa.remove(arg) into delete aa[arg] - */ - if (e1->op == TOKdot) - { - // BUG: we should handle array.a.b.c.e(args) too - - DotIdExp *dotid = (DotIdExp *)(e1); - dotid->e1 = dotid->e1->semantic(sc); - assert(dotid->e1); - if (dotid->e1->type) - { - TY e1ty = dotid->e1->type->toBasetype()->ty; - if (e1ty == Taarray && dotid->ident == Id::remove) - { - if (!arguments || arguments->dim != 1) - { error("expected key as argument to aa.remove()"); - goto Lagain; - } - Expression *key = (Expression *)arguments->data[0]; - key = key->semantic(sc); - key = resolveProperties(sc, key); - key->rvalue(); - - TypeAArray *taa = (TypeAArray *)dotid->e1->type->toBasetype(); - key = key->implicitCastTo(sc, taa->index); - key = key->implicitCastTo(sc, taa->key); - - return new RemoveExp(loc, dotid->e1, key); - } - else if (e1ty == Tarray || e1ty == Tsarray || e1ty == Taarray) - { - if (!arguments) - arguments = new Expressions(); - arguments->shift(dotid->e1); -#if DMDV2 - e1 = new DotIdExp(dotid->loc, new IdentifierExp(dotid->loc, Id::empty), dotid->ident); -#else - e1 = new IdentifierExp(dotid->loc, dotid->ident); -#endif - } - } - } - -#if 1 - /* This recognizes: - * foo!(tiargs)(funcargs) - */ - if (e1->op == TOKimport && !e1->type) - { ScopeExp *se = (ScopeExp *)e1; - TemplateInstance *ti = se->sds->isTemplateInstance(); - if (ti && !ti->semanticRun) - { - /* Attempt to instantiate ti. If that works, go with it. - * If not, go with partial explicit specialization. - */ - ti->semanticTiargs(sc); - unsigned errors = global.startGagging(); - ti->semantic(sc); - if (global.endGagging(errors)) - { - /* Didn't work, go with partial explicit specialization - */ - targsi = ti->tiargs; - e1 = new IdentifierExp(loc, ti->name); - } - } - } - - /* This recognizes: - * expr.foo!(tiargs)(funcargs) - */ - if (e1->op == TOKdotti && !e1->type) - { DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)e1; - TemplateInstance *ti = se->ti; - if (!ti->semanticRun) - { - /* Attempt to instantiate ti. If that works, go with it. - * If not, go with partial explicit specialization. - */ - ti->semanticTiargs(sc); - Expression *etmp; - unsigned errors = global.startGagging(); - etmp = e1->semantic(sc); - if (global.endGagging(errors)) - { - targsi = ti->tiargs; - e1 = new DotIdExp(loc, se->e1, ti->name); - } - else - e1 = etmp; - } - } -#endif - - istemp = 0; -Lagain: - //printf("Lagain: %s\n", toChars()); - f = NULL; - if (e1->op == TOKthis || e1->op == TOKsuper) - { - // semantic() run later for these - } - else - { - static int nest; - if (++nest > 500) - { - error("recursive evaluation of %s", toChars()); - --nest; - return new ErrorExp(); - } - UnaExp::semantic(sc); - --nest; - - /* Look for e1 being a lazy parameter - */ - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - - if (ve->var->storage_class & STClazy) - { - TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd); - TypeDelegate *t = new TypeDelegate(tf); - ve->type = t->semantic(loc, sc); - } - } - - if (e1->op == TOKimport) - { // Perhaps this should be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)e1; - e1 = new DsymbolExp(loc, se->sds); - e1 = e1->semantic(sc); - } -#if DMDV2 - else if (e1->op == TOKsymoff && ((SymOffExp *)e1)->hasOverloads) - { - SymOffExp *se = (SymOffExp *)e1; - e1 = new VarExp(se->loc, se->var, 1); - e1 = e1->semantic(sc); - } -#endif -#if 1 // patch for #540 by Oskar Linde - else if (e1->op == TOKdotexp) - { - DotExp *de = (DotExp *) e1; - - if (de->e2->op == TOKimport) - { // This should *really* be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)de->e2; - de->e2 = new DsymbolExp(loc, se->sds); - de->e2 = de->e2->semantic(sc); - } - - if (de->e2->op == TOKtemplate) - { TemplateExp *te = (TemplateExp *) de->e2; - e1 = new DotTemplateExp(loc,de->e1,te->td); - } - } -#endif - } - - if (e1->op == TOKcomma) - { - CommaExp *ce = (CommaExp *)e1; - - e1 = ce->e2; - e1->type = ce->type; - ce->e2 = this; - ce->type = NULL; - return ce->semantic(sc); - } - - t1 = NULL; - if (e1->type) - t1 = e1->type->toBasetype(); - - // Check for call operator overload - if (t1) - { AggregateDeclaration *ad; - - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; -#if DMDV2 - // First look for constructor - if (ad->ctor && arguments && arguments->dim) - { - // Create variable that will get constructed - Identifier *idtmp = Lexer::uniqueId("__ctmp"); - VarDeclaration *tmp = new VarDeclaration(loc, t1, idtmp, NULL); - Expression *av = new DeclarationExp(loc, tmp); - av = new CommaExp(loc, av, new VarExp(loc, tmp)); - - Expression *e; - CtorDeclaration *cf = ad->ctor->isCtorDeclaration(); - if (cf) - e = new DotVarExp(loc, av, cf, 1); - else - { TemplateDeclaration *td = ad->ctor->isTemplateDeclaration(); - assert(td); - e = new DotTemplateExp(loc, av, td); - } - e = new CallExp(loc, e, arguments); -#if !STRUCTTHISREF - /* Constructors return a pointer to the instance - */ - e = new PtrExp(loc, e); -#endif - e = e->semantic(sc); - return e; - } -#endif - // No constructor, look for overload of opCall - if (search_function(ad, Id::call)) - goto L1; // overload of opCall, therefore it's a call - - if (e1->op != TOKtype) - error("%s %s does not overload ()", ad->kind(), ad->toChars()); - /* It's a struct literal - */ - Expression *e = new StructLiteralExp(loc, (StructDeclaration *)ad, arguments); - e = e->semantic(sc); - e->type = e1->type; // in case e1->type was a typedef - return e; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - goto L1; - L1: - // Rewrite as e1.call(arguments) - Expression *e = new DotIdExp(loc, e1, Id::call); - e = new CallExp(loc, e, arguments); - e = e->semantic(sc); - return e; - } - } - - arrayExpressionSemantic(arguments, sc); - preFunctionParameters(loc, sc, arguments); - - // If there was an error processing any template argument, - // return an error without trying to resolve the template. - if (targsi && targsi->dim) - { - for (size_t k = 0; k < targsi->dim; k++) - { Object *o = targsi->tdata()[k]; - if (isError(o)) - return new ErrorExp(); - } - } - - if (e1->op == TOKdotvar && t1->ty == Tfunction || - e1->op == TOKdottd) - { - DotVarExp *dve; - DotTemplateExp *dte; - AggregateDeclaration *ad; - UnaExp *ue = (UnaExp *)(e1); - - if (e1->op == TOKdotvar) - { // Do overload resolution - dve = (DotVarExp *)(e1); - - f = dve->var->isFuncDeclaration(); - assert(f); - f = f->overloadResolve(loc, NULL, arguments, sc->module); - - ad = f->toParent()->isAggregateDeclaration(); - } - else - { dte = (DotTemplateExp *)(e1); - TemplateDeclaration *td = dte->td; - assert(td); - if (!arguments) - // Should fix deduceFunctionTemplate() so it works on NULL argument - arguments = new Expressions(); - f = td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); - if (!f) - return new ErrorExp(); - ad = td->toParent()->isAggregateDeclaration(); - } - if (f->needThis()) - { - ue->e1 = getRightThis(loc, sc, ad, ue->e1, f); - } - - /* Cannot call public functions from inside invariant - * (because then the invariant would have infinite recursion) - */ - if (sc->func && sc->func->isInvariantDeclaration() && - ue->e1->op == TOKthis && - f->addPostInvariant() - ) - { - error("cannot call public/export function %s from invariant", f->toChars()); - return new ErrorExp(); - } - - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); - checkSafety(sc, f); -#endif - accessCheck(loc, sc, ue->e1, f); - if (!f->needThis()) - { - VarExp *ve = new VarExp(loc, f); - if ((ue->e1)->op == TOKtype) // just a FQN - e1 = ve; - else // things like (new Foo).bar() - e1 = new CommaExp(loc, ue->e1, ve); - e1->type = f->type; - } - else - { - if (e1->op == TOKdotvar) - { - dve->var = f; - e1->type = f->type; - } - else - { - e1 = new DotVarExp(loc, dte->e1, f); - e1 = e1->semantic(sc); - } - - // See if we need to adjust the 'this' pointer - AggregateDeclaration *ad = f->isThis(); - ClassDeclaration *cd = ue->e1->type->isClassHandle(); - if (ad && cd && ad->isClassDeclaration() && ad != cd && - ue->e1->op != TOKsuper) - { - ue->e1 = ue->e1->castTo(sc, ad->type); //new CastExp(loc, ue->e1, ad->type); - ue->e1 = ue->e1->semantic(sc); - } - } - t1 = e1->type; - } - else if (e1->op == TOKsuper) - { - // Base class constructor call - ClassDeclaration *cd = NULL; - - if (sc->func) - cd = sc->func->toParent()->isClassDeclaration(); - if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration()) - { - error("super class constructor call must be in a constructor"); - return new ErrorExp(); - } - else - { - f = cd->baseClass->ctor; - if (!f) - { error("no super class constructor for %s", cd->baseClass->toChars()); - return new ErrorExp(); - } - else - { - if (!sc->intypeof) - { -#if 0 - if (sc->callSuper & (CSXthis | CSXsuper)) - error("reference to this before super()"); -#endif - if (sc->noctor || sc->callSuper & CSXlabel) - error("constructor calls not allowed in loops or after labels"); - if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) - error("multiple constructor calls"); - sc->callSuper |= CSXany_ctor | CSXsuper_ctor; - } - - f = f->overloadResolve(loc, NULL, arguments, sc->module); - accessCheck(loc, sc, NULL, f); - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); - checkSafety(sc, f); -#endif - e1 = new DotVarExp(e1->loc, e1, f); - e1 = e1->semantic(sc); - t1 = e1->type; - } - } - } - else if (e1->op == TOKthis) - { - // same class constructor call - ClassDeclaration *cd = NULL; - - if (sc->func) - cd = sc->func->toParent()->isClassDeclaration(); - if (!cd || !sc->func->isCtorDeclaration()) - { - error("class constructor call must be in a constructor"); - return new ErrorExp(); - } - else - { - if (!sc->intypeof) - { -#if 0 - if (sc->callSuper & (CSXthis | CSXsuper)) - error("reference to this before super()"); -#endif - if (sc->noctor || sc->callSuper & CSXlabel) - error("constructor calls not allowed in loops or after labels"); - if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) - error("multiple constructor calls"); - sc->callSuper |= CSXany_ctor | CSXthis_ctor; - } - - f = cd->ctor; - f = f->overloadResolve(loc, NULL, arguments, sc->module); - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); - checkSafety(sc, f); -#endif - e1 = new DotVarExp(e1->loc, e1, f); - e1 = e1->semantic(sc); - t1 = e1->type; - - // BUG: this should really be done by checking the static - // call graph - if (f == sc->func) - { error("cyclic constructor call"); - return new ErrorExp(); - } - } - } - else if (!t1) - { - error("function expected before (), not '%s'", e1->toChars()); - return new ErrorExp(); - } - else if (t1->ty != Tfunction) - { - if (t1->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)t1; - assert(td->next->ty == Tfunction); - tf = (TypeFunction *)(td->next); - goto Lcheckargs; - } - else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction) - { - Expression *e = new PtrExp(loc, e1); - t1 = ((TypePointer *)t1)->next; - e->type = t1; - e1 = e; - } - else if (e1->op == TOKtemplate) - { - TemplateExp *te = (TemplateExp *)e1; - f = te->td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); - if (!f) - { - return new ErrorExp(); - } - if (f->needThis() && hasThis(sc)) - { - // Supply an implicit 'this', as in - // this.ident - - e1 = new DotTemplateExp(loc, (new ThisExp(loc))->semantic(sc), te->td); - goto Lagain; - } - - e1 = new VarExp(loc, f); - goto Lagain; - } - else - { error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars()); - return new ErrorExp(); - } - } - else if (e1->op == TOKvar) - { - // Do overload resolution - VarExp *ve = (VarExp *)e1; - - f = ve->var->isFuncDeclaration(); - assert(f); - - // Look to see if f is really a function template - if (0 && !istemp && f->parent) - { TemplateInstance *ti = f->parent->isTemplateInstance(); - - if (ti && - (ti->name == f->ident || - ti->toAlias()->ident == f->ident) - && - ti->tempdecl) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - TemplateDeclaration *tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - e1 = new TemplateExp(loc, tempdecl); - istemp = 1; - goto Lagain; - } - } - - f = f->overloadResolve(loc, NULL, arguments, sc->module); - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); - checkSafety(sc, f); -#endif - - if (f->needThis() && hasThis(sc)) - { - // Supply an implicit 'this', as in - // this.ident - - e1 = new DotVarExp(loc, new ThisExp(loc), f); - goto Lagain; - } - - accessCheck(loc, sc, NULL, f); - - ve->var = f; - ve->type = f->type; - t1 = f->type; - } - assert(t1->ty == Tfunction); - tf = (TypeFunction *)(t1); - -Lcheckargs: - assert(tf->ty == Tfunction); - type = tf->next; - - if (!arguments) - arguments = new Expressions(); - int olderrors = global.errors; - functionParameters(loc, sc, tf, arguments); - if (olderrors != global.errors) - return new ErrorExp(); - - if (!type) - { - error("forward reference to inferred return type of function call %s", toChars()); - return new ErrorExp(); - } - - if (f && f->tintro) - { - Type *t = type; - int offset = 0; - TypeFunction *tf = (TypeFunction *)f->tintro; - - if (tf->next->isBaseOf(t, &offset) && offset) - { - type = tf->next; - return castTo(sc, t); - } - } - - return this; -} - -int CallExp::checkSideEffect(int flag) -{ -#if DMDV2 - int result = 1; - - /* Calling a function or delegate that is pure nothrow - * has no side effects. - */ - if (e1->type) - { - Type *t = e1->type->toBasetype(); - if ((t->ty == Tfunction && ((TypeFunction *)t)->purity > PUREweak && - ((TypeFunction *)t)->isnothrow) - || - (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->purity > PUREweak && - ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) - ) - { - result = 0; - //if (flag == 0) - //warning("pure nothrow function %s has no effect", e1->toChars()); - } - else - result = 1; - } - - result |= e1->checkSideEffect(1); - - /* If any of the arguments have side effects, this expression does - */ - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; - - result |= e->checkSideEffect(1); - } - - return result; -#else - return 1; -#endif -} - -#if DMDV2 -int CallExp::canThrow() -{ - //printf("CallExp::canThrow() %s\n", toChars()); - if (e1->canThrow()) - return 1; - - /* If any of the arguments can throw, then this expression can throw - */ - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; - - if (e && e->canThrow()) - return 1; - } - - if (global.errors && !e1->type) - return 0; // error recovery - - /* If calling a function or delegate that is typed as nothrow, - * then this expression cannot throw. - * Note that pure functions can throw. - */ - Type *t = e1->type->toBasetype(); - if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow) - return 0; - if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) - return 0; - - return 1; -} -#endif - -int CallExp::isLvalue() -{ - Type *tb = e1->type->toBasetype(); - if (tb->ty == Tdelegate || tb->ty == Tpointer) - tb = tb->nextOf(); -#if DMDV2 - if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) - { - if (e1->op == TOKdotvar) - if (((DotVarExp *)e1)->var->isCtorDeclaration()) - return 0; - return 1; // function returns a reference - } -#endif - return 0; -} - - -Expression *CallExp::toLvalue(Scope *sc, Expression *e) -{ -#if 1 - if (type->toBasetype()->ty == Tstruct) - return this; - else -#endif - return Expression::toLvalue(sc, e); -} - -Expression *CallExp::modifiableLvalue(Scope *sc, Expression *e) -{ -#if 1 - return Expression::modifiableLvalue(sc, e); -#else - /* Although function return values being usable as "ref" parameters is - * unsound, disabling it breaks existing code. - * Bugzilla 3167 - */ - error("cannot assign to function call"); - return toLvalue(sc, e); -#endif -} - -void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (e1->op == TOKtype) - /* Avoid parens around type to prevent forbidden cast syntax: - * (sometype)(arg1) - * This is ok since types in constructor calls - * can never depend on parens anyway - */ - e1->toCBuffer(buf, hgs); - else - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); -} - - -/************************************************************/ - -AddrExp::AddrExp(Loc loc, Expression *e) - : UnaExp(loc, TOKaddress, sizeof(AddrExp), e) -{ - m = NULL; -} - -Expression *AddrExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AddrExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - m = sc->module; - UnaExp::semantic(sc); - if (e1->type == Type::terror) - return new ErrorExp(); - e1 = e1->toLvalue(sc, NULL); - if (e1->op == TOKerror) - return e1; - if (!e1->type) - { - error("cannot take address of %s", e1->toChars()); - return new ErrorExp(); - } - if (!e1->type->deco) - { - /* No deco means semantic() was not run on the type. - * We have to run semantic() on the symbol to get the right type: - * auto x = &bar; - * pure: int bar() { return 1;} - * otherwise the 'pure' is missing from the type assigned to x. - */ - - error("forward reference to %s", e1->toChars()); - return new ErrorExp(); - } - type = e1->type->pointerTo(); - - // See if this should really be a delegate - if (e1->op == TOKdotvar) - { - DotVarExp *dve = (DotVarExp *)e1; - FuncDeclaration *f = dve->var->isFuncDeclaration(); - - if (f) - { Expression *e = new DelegateExp(loc, dve->e1, f); - e = e->semantic(sc); - return e; - } - } - else if (e1->op == TOKvar) - { - VarExp *dve = (VarExp *)e1; - FuncDeclaration *f = dve->var->isFuncDeclaration(); - VarDeclaration *v = dve->var->isVarDeclaration(); - - // LDC - if (f && f->isIntrinsic()) - { - error("cannot take the address of intrinsic function %s", e1->toChars()); - return this; - } - - if (f) - { - if (f->isNested()) - { - if (f->isFuncLiteralDeclaration()) - { - if (!f->FuncDeclaration::isNested()) - { /* Supply a 'null' for a this pointer if no this is available - */ - Expression *e = new DelegateExp(loc, new NullExp(loc, Type::tvoidptr), f); - e = e->semantic(sc); - return e; - } - } - Expression *e = new DelegateExp(loc, e1, f); - e = e->semantic(sc); - return e; - } - } - } - else if (e1->op == TOKarray) - { - if (e1->type->toBasetype()->ty == Tbit) - error("cannot take address of bit in array"); - } - return optimize(WANTvalue); - } - return this; -} - -void AddrExp::checkEscape() -{ - e1->checkEscapeRef(); -} - -/************************************************************/ - -PtrExp::PtrExp(Loc loc, Expression *e) - : UnaExp(loc, TOKstar, sizeof(PtrExp), e) -{ -// if (e->type) -// type = ((TypePointer *)e->type)->next; -} - -PtrExp::PtrExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKstar, sizeof(PtrExp), e) -{ - type = t; -} - -Expression *PtrExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("PtrExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - if (!e1->type) - printf("PtrExp::semantic('%s')\n", toChars()); - Type *tb = e1->type->toBasetype(); - switch (tb->ty) - { - case Tpointer: - type = ((TypePointer *)tb)->next; - break; - - case Tsarray: - case Tarray: - if (!global.params.useDeprecated) - error("using * on an array is deprecated; use *(%s).ptr instead", e1->toChars()); - type = ((TypeArray *)tb)->next; - e1 = e1->castTo(sc, type->pointerTo()); - break; - - default: - error("can only * a pointer, not a '%s'", e1->type->toChars()); - case Terror: - return new ErrorExp(); - } - if (!rvalue()) - return new ErrorExp(); - } - return this; -} - - -int PtrExp::isLvalue() -{ - return 1; -} - - -void PtrExp::checkEscapeRef() -{ - e1->checkEscape(); -} - -Expression *PtrExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - return this; -} - -#if DMDV2 -Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars()); - - if (e1->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)e1; - se->var->checkModify(loc, sc, type); - //return toLvalue(sc, e); - } - - return Expression::modifiableLvalue(sc, e); -} -#endif - -void PtrExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('*'); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -NegExp::NegExp(Loc loc, Expression *e) - : UnaExp(loc, TOKneg, sizeof(NegExp), e) -{ -} - -Expression *NegExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("NegExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e = op_overload(sc); - if (e) - return e; - - e1->checkNoBool(); - if (!e1->isArrayOperand()) - e1->checkArithmetic(); - type = e1->type; - } - return this; -} - -/************************************************************/ - -UAddExp::UAddExp(Loc loc, Expression *e) - : UnaExp(loc, TOKuadd, sizeof(UAddExp), e) -{ -} - -Expression *UAddExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("UAddExp::semantic('%s')\n", toChars()); -#endif - assert(!type); - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e = op_overload(sc); - if (e) - return e; - e1->checkNoBool(); - e1->checkArithmetic(); - return e1; -} - -/************************************************************/ - -ComExp::ComExp(Loc loc, Expression *e) - : UnaExp(loc, TOKtilde, sizeof(ComExp), e) -{ -} - -Expression *ComExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e = op_overload(sc); - if (e) - return e; - - e1->checkNoBool(); - if (!e1->isArrayOperand()) - e1 = e1->checkIntegral(); - type = e1->type; - } - return this; -} - -/************************************************************/ - -NotExp::NotExp(Loc loc, Expression *e) - : UnaExp(loc, TOKnot, sizeof(NotExp), e) -{ -} - -Expression *NotExp::semantic(Scope *sc) -{ - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToBoolean(); - type = Type::tboolean; - return this; -} - -int NotExp::isBit() -{ - return TRUE; -} - - - -/************************************************************/ - -BoolExp::BoolExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKtobool, sizeof(BoolExp), e) -{ - type = t; -} - -Expression *BoolExp::semantic(Scope *sc) -{ - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToBoolean(); - type = Type::tboolean; - return this; -} - -int BoolExp::isBit() -{ - return TRUE; -} - -/************************************************************/ - -DeleteExp::DeleteExp(Loc loc, Expression *e) - : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e) -{ -} - -Expression *DeleteExp::semantic(Scope *sc) -{ - Type *tb; - - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->toLvalue(sc, NULL); - if (e1->op == TOKerror) - return e1; - type = Type::tvoid; - - tb = e1->type->toBasetype(); - switch (tb->ty) - { case Tclass: - { TypeClass *tc = (TypeClass *)tb; - ClassDeclaration *cd = tc->sym; - - if (cd->isCOMinterface()) - { /* Because COM classes are deleted by IUnknown.Release() - */ - error("cannot delete instance of COM interface %s", cd->toChars()); - } - break; - } - case Tpointer: - tb = ((TypePointer *)tb)->next->toBasetype(); - if (tb->ty == Tstruct) - { - TypeStruct *ts = (TypeStruct *)tb; - StructDeclaration *sd = ts->sym; - FuncDeclaration *f = sd->aggDelete; - - if (f) - { - Type *tpv = Type::tvoid->pointerTo(); - - Expression *e = e1->castTo(sc, tpv); - Expression *ec = new VarExp(loc, f); - e = new CallExp(loc, ec, e); - return e->semantic(sc); - } - } - break; - - case Tarray: - break; - - default: - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - break; - } - error("cannot delete type %s", e1->type->toChars()); - return new ErrorExp(); - } - - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - { if (!global.params.useDeprecated) - error("delete aa[key] deprecated, use aa.remove(key)"); - } - } - - return this; -} - -int DeleteExp::checkSideEffect(int flag) -{ - return 1; -} - -Expression *DeleteExp::checkToBoolean() -{ - error("delete does not give a boolean result"); - return new ErrorExp(); -} - -void DeleteExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("delete "); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -CastExp::CastExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKcast, sizeof(CastExp), e) -{ - to = t; -} - -#if DMDV2 -/* For cast(const) and cast(immutable) - */ -CastExp::CastExp(Loc loc, Expression *e, unsigned mod) - : UnaExp(loc, TOKcast, sizeof(CastExp), e) -{ - to = NULL; - this->mod = mod; -} -#endif - -Expression *CastExp::syntaxCopy() -{ - return new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy()); -} - - -Expression *CastExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("CastExp::semantic('%s')\n", toChars()); -#endif - -//static int x; assert(++x < 10); - - if (type) - return this; - UnaExp::semantic(sc); - if (e1->type) // if not a tuple - { - e1 = resolveProperties(sc, e1); - to = to->semantic(loc, sc); - - e = op_overload(sc); - if (e) - { - return e->implicitCastTo(sc, to); - } - - if (e1->op == TOKtemplate) - { - error("cannot cast template %s to type %s", e1->toChars(), to->toChars()); - return new ErrorExp(); - } - - Type *t1b = e1->type->toBasetype(); - Type *tob = to->toBasetype(); - if (tob->ty == Tstruct && - !tob->equals(t1b) && - ((TypeStruct *)to)->sym->search(0, Id::call, 0) - ) - { - /* Look to replace: - * cast(S)t - * with: - * S(t) - */ - - // Rewrite as to.call(e1) - e = new TypeExp(loc, to); - e = new DotIdExp(loc, e, Id::call); - e = new CallExp(loc, e, e1); - e = e->semantic(sc); - return e; - } - - // Struct casts are possible only when the sizes match - // Same with static array -> static array - if (tob->ty == Tstruct || t1b->ty == Tstruct || - (tob->ty == Tsarray && t1b->ty == Tsarray)) - { - size_t fromsize = t1b->size(loc); - size_t tosize = tob->size(loc); - if (fromsize != tosize) - { - error("cannot cast from %s to %s", e1->type->toChars(), to->toChars()); - return new ErrorExp(); - } - } - } - - if (!e1->type) - { error("cannot cast %s", e1->toChars()); - return new ErrorExp(); - } - - e = e1->castTo(sc, to); - return e; -} - -int CastExp::checkSideEffect(int flag) -{ - /* if not: - * cast(void) - * cast(classtype)func() - */ - if (!to->equals(Type::tvoid) && - !(to->ty == Tclass && e1->op == TOKcall && e1->type->ty == Tclass)) - return Expression::checkSideEffect(flag); - return 1; -} - -void CastExp::checkEscape() -{ Type *tb = type->toBasetype(); - if (tb->ty == Tarray && e1->op == TOKvar && - e1->type->toBasetype()->ty == Tsarray) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg() && !v->isParameter()) - error("escaping reference to local %s", v->toChars()); - } - } -} - -void CastExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("cast("); -#if DMDV1 - to->toCBuffer(buf, NULL, hgs); -#else - if (to) - to->toCBuffer(buf, NULL, hgs); - else - { - MODtoBuffer(buf, mod); - } -#endif - buf->writeByte(')'); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - - -/************************************************************/ - -SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr) - : UnaExp(loc, TOKslice, sizeof(SliceExp), e1) -{ - this->upr = upr; - this->lwr = lwr; - lengthVar = NULL; -} - -Expression *SliceExp::syntaxCopy() -{ - Expression *lwr = NULL; - if (this->lwr) - lwr = this->lwr->syntaxCopy(); - - Expression *upr = NULL; - if (this->upr) - upr = this->upr->syntaxCopy(); - - return new SliceExp(loc, e1->syntaxCopy(), lwr, upr); -} - -Expression *SliceExp::semantic(Scope *sc) -{ Expression *e; - AggregateDeclaration *ad; - //FuncDeclaration *fd; - ScopeDsymbol *sym; - -#if LOGSEMANTIC - printf("SliceExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - e = this; - - Type *t = e1->type->toBasetype(); - if (t->ty == Tpointer) - { - if (!lwr || !upr) - { error("need upper and lower bound to slice pointer"); - return new ErrorExp(); - } - } - else if (t->ty == Tarray) - { - } - else if (t->ty == Tsarray) - { - } - else if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - goto L1; - } - else if (t->ty == Tstruct) - { - ad = ((TypeStruct *)t)->sym; - - L1: - if (search_function(ad, Id::slice)) - { - // Rewrite as e1.slice(lwr, upr) - e = new DotIdExp(loc, e1, Id::slice); - - if (lwr) - { - assert(upr); - e = new CallExp(loc, e, lwr, upr); - } - else - { assert(!upr); - e = new CallExp(loc, e); - } - e = e->semantic(sc); - return e; - } - goto Lerror; - } - else if (t->ty == Ttuple) - { - if (!lwr && !upr) - return e1; - if (!lwr || !upr) - { error("need upper and lower bound to slice tuple"); - goto Lerror; - } - } - else if (t == Type::terror) - goto Lerr; - else - goto Lerror; - - { - Scope *sc2 = sc; - if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) - { - sym = new ArrayScopeSymbol(this); - sym->loc = loc; - sym->parent = sc->scopesym; - sc2 = sc->push(sym); - } - - if (lwr) - { lwr = lwr->semantic(sc2); - lwr = resolveProperties(sc2, lwr); - lwr = lwr->implicitCastTo(sc2, Type::tsize_t); - if (lwr->type == Type::terror) - goto Lerr; - } - if (upr) - { upr = upr->semantic(sc2); - upr = resolveProperties(sc2, upr); - upr = upr->implicitCastTo(sc2, Type::tsize_t); - if (upr->type == Type::terror) - goto Lerr; - } - - if (sc2 != sc) - sc2->pop(); - } - - if (t->ty == Ttuple) - { - lwr = lwr->ctfeInterpret(); - upr = upr->ctfeInterpret(); - uinteger_t i1 = lwr->toUInteger(); - uinteger_t i2 = upr->toUInteger(); - - size_t length; - TupleExp *te; - TypeTuple *tup; - - if (e1->op == TOKtuple) // slicing an expression tuple - { te = (TupleExp *)e1; - length = te->exps->dim; - } - else if (e1->op == TOKtype) // slicing a type tuple - { tup = (TypeTuple *)t; - length = Parameter::dim(tup->arguments); - } - else - assert(0); - - if (i1 <= i2 && i2 <= length) - { size_t j1 = (size_t) i1; - size_t j2 = (size_t) i2; - - if (e1->op == TOKtuple) - { Expressions *exps = new Expressions; - exps->setDim(j2 - j1); - for (size_t i = 0; i < j2 - j1; i++) - { Expression *e = (Expression *)te->exps->data[j1 + i]; - exps->data[i] = (void *)e; - } - e = new TupleExp(loc, exps); - } - else - { Parameters *args = new Parameters; - args->reserve(j2 - j1); - for (size_t i = j1; i < j2; i++) - { Parameter *arg = Parameter::getNth(tup->arguments, i); - args->push(arg); - } - e = new TypeExp(e1->loc, new TypeTuple(args)); - } - e = e->semantic(sc); - } - else - { - error("string slice [%ju .. %ju] is out of bounds", i1, i2); - goto Lerr; - } - return e; - } - - if (t->ty == Tarray) - { - type = e1->type; - } - else - type = t->nextOf()->arrayOf(); - return e; - -Lerror: - if (e1->op == TOKerror) - return e1; - char *s; - if (t->ty == Tvoid) - s = e1->toChars(); - else - s = t->toChars(); - error("%s cannot be sliced with []", s); -Lerr: - e = new ErrorExp(); - return e; -} - -void SliceExp::checkEscape() -{ - e1->checkEscape(); -} - -void SliceExp::checkEscapeRef() -{ - e1->checkEscapeRef(); -} - - -int SliceExp::isLvalue() -{ - return 1; -} - - -Expression *SliceExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - -Expression *SliceExp::modifiableLvalue(Scope *sc, Expression *e) -{ - error("slice expression %s is not a modifiable lvalue", toChars()); - return this; -} - -int SliceExp::isBool(int result) -{ - return e1->isBool(result); -} - -void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte('['); - if (upr || lwr) - { - if (lwr) - expToCBuffer(buf, hgs, lwr, PREC_assign); - else - buf->writeByte('0'); - buf->writestring(".."); - if (upr) - expToCBuffer(buf, hgs, upr, PREC_assign); - else - buf->writestring("length"); // BUG: should be array.length - } - buf->writeByte(']'); -} - -int SliceExp::canThrow() -{ - return UnaExp::canThrow() - || (lwr != NULL && lwr->canThrow()) - || (upr != NULL && upr->canThrow()); -} - -/********************** ArrayLength **************************************/ - -ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1) - : UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1) -{ -} - -Expression *ArrayLengthExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("ArrayLengthExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - type = Type::tsize_t; - } - return this; -} - -void ArrayLengthExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writestring(".length"); -} - -/*********************** ArrayExp *************************************/ - -// e1 [ i1, i2, i3, ... ] - -ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args) - : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1) -{ - arguments = args; -} - -Expression *ArrayExp::syntaxCopy() -{ - return new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); -} - -Expression *ArrayExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - -#if LOGSEMANTIC - printf("ArrayExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - if (e1->op == TOKerror) - return e1; - - t1 = e1->type->toBasetype(); - if (t1->ty != Tclass && t1->ty != Tstruct) - { // Convert to IndexExp - if (arguments->dim != 1) - { error("only one index allowed to index %s", t1->toChars()); - goto Lerr; - } - e = new IndexExp(loc, e1, (*arguments)[0]); - return e->semantic(sc); - } - - // Run semantic() on each argument - for (size_t i = 0; i < arguments->dim; i++) - { e = (*arguments)[i]; - - e = e->semantic(sc); - if (!e->type) - { error("%s has no value", e->toChars()); - goto Lerr; - } - else if (e->type == Type::terror) - goto Lerr; - (*arguments)[i] = e; - } - - expandTuples(arguments); - assert(arguments && arguments->dim); - - e = op_overload(sc); - if (!e) - { error("no [] operator overload for type %s", e1->type->toChars()); - goto Lerr; - } - return e; - -Lerr: - return new ErrorExp(); -} - - -int ArrayExp::isLvalue() -{ - if (type && type->toBasetype()->ty == Tvoid) - return 0; - return 1; -} - - -Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) -{ - if (type && type->toBasetype()->ty == Tvoid) - error("voids have no value"); - return this; -} - - -void ArrayExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('['); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(']'); -} - -/************************* DotExp ***********************************/ - -DotExp::DotExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdotexp, sizeof(DotExp), e1, e2) -{ -} - -Expression *DotExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotExp::semantic('%s')\n", toChars()); - if (type) printf("\ttype = %s\n", type->toChars()); -#endif - e1 = e1->semantic(sc); - e2 = e2->semantic(sc); - if (e2->op == TOKimport) - { - ScopeExp *se = (ScopeExp *)e2; - TemplateDeclaration *td = se->sds->isTemplateDeclaration(); - if (td) - { Expression *e = new DotTemplateExp(loc, e1, td); - e = e->semantic(sc); - return e; - } - } - if (!type) - type = e2->type; - return this; -} - -void DotExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - expToCBuffer(buf, hgs, e2, PREC_primary); -} - -/************************* CommaExp ***********************************/ - -CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2) -{ -} - -Expression *CommaExp::semantic(Scope *sc) -{ - if (!type) - { BinExp::semanticp(sc); - type = e2->type; - } - return this; -} - -void CommaExp::checkEscape() -{ - e2->checkEscape(); -} - -void CommaExp::checkEscapeRef() -{ - e2->checkEscapeRef(); -} - - -int CommaExp::isLvalue() -{ - return e2->isLvalue(); -} - - -Expression *CommaExp::toLvalue(Scope *sc, Expression *e) -{ - e2 = e2->toLvalue(sc, NULL); - return this; -} - -Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e) -{ - e2 = e2->modifiableLvalue(sc, e); - return this; -} - -int CommaExp::isBool(int result) -{ - return e2->isBool(result); -} - -int CommaExp::checkSideEffect(int flag) -{ - if (flag == 2) - return e1->hasSideEffect() || e2->hasSideEffect(); - else - { - // Don't check e1 until we cast(void) the a,b code generation - return e2->checkSideEffect(flag); - } -} - -/************************** IndexExp **********************************/ - -// e1 [ e2 ] - -IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2) -{ - //printf("IndexExp::IndexExp('%s')\n", toChars()); - lengthVar = NULL; - modifiable = 0; // assume it is an rvalue -} - -Expression *IndexExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - ScopeDsymbol *sym; - -#if LOGSEMANTIC - printf("IndexExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - if (!e1->type) - e1 = e1->semantic(sc); - assert(e1->type); // semantic() should already be run on it - if (e1->op == TOKerror) - goto Lerr; - e = this; - - // Note that unlike C we do not implement the int[ptr] - - t1 = e1->type->toBasetype(); - - if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) - { // Create scope for 'length' variable - sym = new ArrayScopeSymbol(this); - sym->loc = loc; - sym->parent = sc->scopesym; - sc = sc->push(sym); - } - - e2 = e2->semantic(sc); - if (!e2->type) - { - error("%s has no value", e2->toChars()); - goto Lerr; - } - if (e2->type->ty == Ttuple && ((TupleExp *)e2)->exps->dim == 1) // bug 4444 fix - e2 = (*((TupleExp *)e2)->exps)[0]; - e2 = resolveProperties(sc, e2); - if (e2->type == Type::terror) - goto Lerr; - - if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) - sc = sc->pop(); - - switch (t1->ty) - { - case Tpointer: - case Tarray: - e2 = e2->implicitCastTo(sc, Type::tsize_t); - e->type = t1->next; - break; - - case Tsarray: - { - e2 = e2->implicitCastTo(sc, Type::tsize_t); - - TypeSArray *tsa = (TypeSArray *)t1; - -#if 0 // Don't do now, because it might be short-circuit evaluated - // Do compile time array bounds checking if possible - e2 = e2->optimize(WANTvalue); - if (e2->op == TOKint64) - { - dinteger_t index = e2->toInteger(); - dinteger_t length = tsa->dim->toInteger(); - if (index < 0 || index >= length) - error("array index [%lld] is outside array bounds [0 .. %lld]", - index, length); - } -#endif - e->type = t1->nextOf(); - break; - } - - case Taarray: - { TypeAArray *taa = (TypeAArray *)t1; - - e2 = e2->implicitCastTo(sc, taa->index); // type checking - e2 = e2->implicitCastTo(sc, taa->key); // actual argument type - type = taa->next; - break; - } - - case Ttuple: - { - e2 = e2->implicitCastTo(sc, Type::tsize_t); - e2 = e2->optimize(WANTvalue); - uinteger_t index = e2->toUInteger(); - size_t length; - TupleExp *te; - TypeTuple *tup; - - if (e1->op == TOKtuple) - { te = (TupleExp *)e1; - length = te->exps->dim; - } - else if (e1->op == TOKtype) - { - tup = (TypeTuple *)t1; - length = Parameter::dim(tup->arguments); - } - else - assert(0); - - if (index < length) - { - - if (e1->op == TOKtuple) - e = (Expression *)te->exps->data[(size_t)index]; - else - e = new TypeExp(e1->loc, Parameter::getNth(tup->arguments, (size_t)index)->type); - } - else - { - error("array index [%ju] is outside array bounds [0 .. %zu]", - index, length); - e = e1; - } - break; - } - - default: - if (e1->op == TOKerror) - goto Lerr; - error("%s must be an array or pointer type, not %s", - e1->toChars(), e1->type->toChars()); - case Terror: - goto Lerr; - } - return e; - -Lerr: - return new ErrorExp(); -} - - -int IndexExp::isLvalue() -{ - return 1; -} - - -Expression *IndexExp::toLvalue(Scope *sc, Expression *e) -{ -// if (type && type->toBasetype()->ty == Tvoid) -// error("voids have no value"); - return this; -} - -Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); - modifiable = 1; - if (e1->op == TOKstring) - error("string literals are immutable"); - if (e1->type->toBasetype()->ty == Taarray) - e1 = e1->modifiableLvalue(sc, e1); - return toLvalue(sc, e); -} - -void IndexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('['); - expToCBuffer(buf, hgs, e2, PREC_assign); - buf->writeByte(']'); -} - - -/************************* PostExp ***********************************/ - -PostExp::PostExp(enum TOK op, Loc loc, Expression *e) - : BinExp(loc, op, sizeof(PostExp), e, - new IntegerExp(loc, 1, Type::tint32)) -{ -} - -Expression *PostExp::semantic(Scope *sc) -{ Expression *e = this; - - if (!type) - { - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e = this; - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - if (e1->type->ty == Tpointer) - e = scaleFactor(sc); - else - e2 = e2->castTo(sc, e1->type); - e->type = e1->type; - } - return e; -} - -void PostExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writestring((op == TOKplusplus) ? (char *)"++" : (char *)"--"); -} - -/************************************************************/ - -/* op can be TOKassign, TOKconstruct, or TOKblit */ - -AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2) -{ - ismemset = 0; -} - -Expression *AssignExp::semantic(Scope *sc) -{ - Expression *e1old = e1; - -#if LOGSEMANTIC - printf("AssignExp::semantic('%s')\n", toChars()); -#endif - //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); - //printf("e2->op = %d, '%s'\n", e2->op, Token::toChars(e2->op)); - - if (type) - return this; - - if (e2->op == TOKcomma) - { /* Rewrite to get rid of the comma from rvalue - */ - AssignExp *ea = new AssignExp(loc, e1, ((CommaExp *)e2)->e2); - ea->op = op; - Expression *e = new CommaExp(loc, ((CommaExp *)e2)->e1, ea); - return e->semantic(sc); - } - - /* Look for operator overloading of a[i]=value. - * Do it before semantic() otherwise the a[i] will have been - * converted to a.opIndex() already. - */ - if (e1->op == TOKarray) - { - ArrayExp *ae = (ArrayExp *)e1; - AggregateDeclaration *ad = NULL; - Identifier *id = Id::index; - - ae->e1 = ae->e1->semantic(sc); - ae->e1 = resolveProperties(sc, ae->e1); - Type *t1 = ae->e1->type->toBasetype(); - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - goto L1; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - L1: - // Rewrite (a[i] = value) to (a.opIndexAssign(value, i)) - if (search_function(ad, Id::indexass)) - { Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); - Expressions *a = (Expressions *)ae->arguments->copy(); - - a->insert(0, e2); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - else - { - // Rewrite (a[i] = value) to (a.opIndex(i, value)) - if (search_function(ad, id)) - { Expression *e = new DotIdExp(loc, ae->e1, id); - - if (1 || !global.params.useDeprecated) - { error("operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i)"); - return new ErrorExp(); - } - - e = new CallExp(loc, e, (Expression *)ae->arguments->data[0], e2); - e = e->semantic(sc); - return e; - } - } - } - } - /* Look for operator overloading of a[i..j]=value. - * Do it before semantic() otherwise the a[i..j] will have been - * converted to a.opSlice() already. - */ - if (e1->op == TOKslice) - { Type *t1; - SliceExp *ae = (SliceExp *)e1; - AggregateDeclaration *ad = NULL; - Identifier *id = Id::index; - - ae->e1 = ae->e1->semantic(sc); - ae->e1 = resolveProperties(sc, ae->e1); - t1 = ae->e1->type->toBasetype(); - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - goto L2; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - L2: - // Rewrite (a[i..j] = value) to (a.opIndexAssign(value, i, j)) - if (search_function(ad, Id::sliceass)) - { Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass); - Expressions *a = new Expressions(); - - a->push(e2); - if (ae->lwr) - { a->push(ae->lwr); - assert(ae->upr); - a->push(ae->upr); - } - else - assert(!ae->upr); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - } - } - - Expression *e = BinExp::semantic(sc); - if (e->op == TOKerror) - return e; - - if (e1->op == TOKdottd) - { // Rewrite a.b=e2, when b is a template, as a.b(e2) - Expression *e = new CallExp(loc, e1, e2); - e = e->semantic(sc); - return e; - } - - e2 = resolveProperties(sc, e2); - assert(e1->type); - - /* Rewrite tuple assignment as a tuple of assignments. - */ - if (e1->op == TOKtuple && e2->op == TOKtuple) - { TupleExp *tup1 = (TupleExp *)e1; - TupleExp *tup2 = (TupleExp *)e2; - size_t dim = tup1->exps->dim; - if (dim != tup2->exps->dim) - { - error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim); - } - else - { Expressions *exps = new Expressions; - exps->setDim(dim); - - for (size_t i = 0; i < dim; i++) - { Expression *ex1 = (Expression *)tup1->exps->data[i]; - Expression *ex2 = (Expression *)tup2->exps->data[i]; - exps->data[i] = (void *) new AssignExp(loc, ex1, ex2); - } - Expression *e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } - } - - // Determine if this is an initialization of a reference - int refinit = 0; - if (op == TOKconstruct && e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v->storage_class & (STCout | STCref)) - refinit = 1; - } - - Type *t1 = e1->type->toBasetype(); - - if (t1->ty == Tfunction) - { // Rewrite f=value to f(value) - Expression *e = new CallExp(loc, e1, e2); - e = e->semantic(sc); - return e; - } - - /* If it is an assignment from a 'foreign' type, - * check for operator overloading. - */ - if (t1->ty == Tclass || t1->ty == Tstruct) - { // Disallow assignment operator overloads for same type - if (/*op == TOKassign &&*/ // construction shouldn't be allowed, but OK to avoid breaking existing code - !e2->implicitConvTo(e1->type)) - { - Expression *e = op_overload(sc); - if (e) - return e; - } - } - - if (!e2->rvalue()) - return new ErrorExp(); - - if (e1->op == TOKarraylength) - { - // e1 is not an lvalue, but we let code generator handle it - ArrayLengthExp *ale = (ArrayLengthExp *)e1; - - ale->e1 = ale->e1->modifiableLvalue(sc, e1); - } - else if (e1->op == TOKslice) - ; - else - { // Try to do a decent error message with the expression - // before it got constant folded - if (op != TOKconstruct) - e1 = e1->modifiableLvalue(sc, e1old); - } - - // If it is a array, get the element type. Note that it may be - // multi-dimensional. - Type *telem = t1; - while (telem->ty == Tarray) - telem = telem->nextOf(); - - // Check for block assignment. If it is of type void[], void[][], etc, - // '= null' is the only allowable block assignment (Bug 7493) - if (e1->op == TOKslice && - t1->nextOf() && (telem->ty != Tvoid || e2->op == TOKnull) && - e2->implicitConvTo(t1->nextOf()) -// !(t1->nextOf()->equals(e2->type->nextOf())) - ) - { // memset - ismemset = 1; // make it easy for back end to tell what this is - e2 = e2->implicitCastTo(sc, t1->next); - } - else if (t1->ty == Tsarray && !refinit) - { - error("cannot assign to static array %s", e1->toChars()); - } - else - { - e2 = e2->implicitCastTo(sc, e1->type); - } - - /* Look for array operations - */ - if (e1->op == TOKslice && !ismemset && - (e2->op == TOKadd || e2->op == TOKmin || - e2->op == TOKmul || e2->op == TOKdiv || - e2->op == TOKmod || e2->op == TOKxor || - e2->op == TOKand || e2->op == TOKor || -#if DMDV2 - e2->op == TOKpow || -#endif - e2->op == TOKtilde || e2->op == TOKneg)) - { - type = e1->type; - return arrayOp(sc); - } - - if (e1->op == TOKvar && - (((VarExp *)e1)->var->storage_class & STCscope) && - op == TOKassign) - { - error("cannot rebind scope variables"); - } - - type = e1->type; - assert(type); - return this; -} - -Expression *AssignExp::checkToBoolean() -{ - // Things like: - // if (a = b) ... - // are usually mistakes. - - error("assignment cannot be used as a condition, perhaps == was meant?"); - return new ErrorExp(); -} - -/************************************************************/ - -ConstructExp::ConstructExp(Loc loc, Expression *e1, Expression *e2) - : AssignExp(loc, e1, e2) -{ - op = TOKconstruct; -} - -/************************************************************/ - -AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2) -{ -} - -Expression *AddAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if (e1->op == TOKslice) - { - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - else - { - e1 = e1->modifiableLvalue(sc, e1); - } - - if ((tb1->ty == Tarray || tb1->ty == Tsarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - tb1->nextOf()->equals(tb2->nextOf()) - ) - { - type = e1->type; - e = this; - } - else - { - e1->checkScalar(); - e1->checkNoBool(); - if (tb1->ty == Tpointer && tb2->isintegral()) - e = scaleFactor(sc); - else if (tb1->ty == Tbit || tb1->ty == Tbool) - { -#if 0 - // Need to rethink this - if (e1->op != TOKvar) - { // Rewrite e1+=e2 to (v=&e1),*v=*v+e2 - VarDeclaration *v; - Expression *ea; - Expression *ex; - - Identifier *id = Lexer::uniqueId("__name"); - - v = new VarDeclaration(loc, tb1->pointerTo(), id, NULL); - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - - ea = new AddrExp(loc, e1); - ea = new AssignExp(loc, new VarExp(loc, v), ea); - - ex = new VarExp(loc, v); - ex = new PtrExp(loc, ex); - e = new AddExp(loc, ex, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, ex->syntaxCopy(), e); - - e = new CommaExp(loc, ea, e); - } - else -#endif - { // Rewrite e1+=e2 to e1=e1+e2 - // BUG: doesn't account for side effects in e1 - // BUG: other assignment operators for bits aren't handled at all - e = new AddExp(loc, e1, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, e1->syntaxCopy(), e); - } - e = e->semantic(sc); - } - else - { - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - checkComplexAddAssign(); - if (type->isreal() || type->isimaginary()) - { - assert(global.errors || e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - } - return e; -} - -/************************************************************/ - -MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2) -{ -} - -Expression *MinAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] -= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - if (e1->type->ty == Tpointer && e2->type->isintegral()) - e = scaleFactor(sc); - else - { - e1 = e1->checkArithmetic(); - e2 = e2->checkArithmetic(); - checkComplexAddAssign(); - type = e1->type; - typeCombine(sc); - if (type->isreal() || type->isimaginary()) - { - assert(e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - return e; -} - -/************************************************************/ - -CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2) -{ -} - -Expression *CatAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { SliceExp *se = (SliceExp *)e1; - - if (se->e1->type->toBasetype()->ty == Tsarray) - { error("cannot append to static array %s", se->e1->type->toChars()); - return new ErrorExp(); - } - } - - e1 = e1->modifiableLvalue(sc, e1); - if (e1->op == TOKerror) - return e1; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if (!e2->rvalue()) - return new ErrorExp(); - - Type *tb1next = tb1->nextOf(); - - if ((tb1->ty == Tarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - (e2->implicitConvTo(e1->type) -#if DMDV2 - || tb2->nextOf()->implicitConvTo(tb1next) -#endif - ) - ) - { // Append array - e2 = e2->castTo(sc, e1->type); - type = e1->type; - e = this; -// Reenable when _d_arrayappendwd and cd are in the runtime. -/* } - - else if (tb1->ty == Tarray && - (tb1next->ty == Tchar || tb1next->ty == Twchar) && - e2->type->ty != tb1next->ty && - e2->implicitConvTo(Type::tdchar) - ) - { // Append dchar to char[] or wchar[] - e2 = e2->castTo(sc, Type::tdchar); - type = e1->type; - e = this; - - /* Do not allow appending wchar to char[] because if wchar happens - * to be a surrogate pair, nothing good can result. - */ - } - else if ((tb1->ty == Tarray) && - e2->implicitConvTo(tb1next) - ) - { // Append element - e2 = e2->castTo(sc, tb1next); - type = e1->type; - e = this; - } - else - { - if (tb1 != Type::terror && tb2 != Type::terror) - error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars()); - e = new ErrorExp(); - } - return e; -} - -/************************************************************/ - -MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2) -{ -} - -Expression *MulAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - -#if DMDV2 - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } -#endif - - if (e1->op == TOKslice) - { // T[] -= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - checkComplexMulAssign(); - if (e2->type->isfloating()) - { Type *t1; - Type *t2; - - t1 = e1->type; - t2 = e2->type; - if (t1->isreal()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - e2 = e2->castTo(sc, t1); - } - } - else if (t1->isimaginary()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - } - } - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - return this; -} - -/************************************************************/ - -DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2) -{ -} - -Expression *DivAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - -#if DMDV2 - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } -#endif - - if (e1->op == TOKslice) - { // T[] -= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - checkComplexMulAssign(); - if (e2->type->isimaginary()) - { Type *t1; - Type *t2; - - t1 = e1->type; - if (t1->isreal()) - { // x/iv = i(-x/v) - // Therefore, the result is 0 - e2 = new CommaExp(loc, e2, new RealExp(loc, ldouble(0), t1)); - e2->type = t1; - e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - else if (t1->isimaginary()) - { Expression *e; - - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - } - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - - return this; -} - -/************************************************************/ - -ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2) -{ -} - -Expression *ModAssignExp::semantic(Scope *sc) -{ - if (type) - return this; - BinExp::semantic(sc); - checkComplexMulAssign(); - return commonSemanticAssign(sc); -} - -/************************************************************/ - -ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2) -{ -} - -/************************************************************/ - -ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2) -{ -} - -/************************************************************/ - -UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2) -{ -} - -/************************************************************/ - -AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2) -{ -} - -Expression *AndAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************************************************/ - -OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2) -{ -} - -Expression *OrAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************************************************/ - -XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2) -{ -} - -Expression *XorAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************* AddExp *****************************/ - -AddExp::AddExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2) -{ -} - -Expression *AddExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("AddExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - BinExp::semanticp(sc); - - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if ((tb1->ty == Tarray || tb1->ty == Tsarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - tb1->nextOf()->equals(tb2->nextOf()) - ) - { - type = e1->type; - e = this; - } - else if (tb1->ty == Tpointer && e2->type->isintegral() || - tb2->ty == Tpointer && e1->type->isintegral()) - e = scaleFactor(sc); - else if (tb1->ty == Tpointer && tb2->ty == Tpointer) - { - incompatibleTypes(); - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if ((e1->type->isreal() && e2->type->isimaginary()) || - (e1->type->isimaginary() && e2->type->isreal())) - { - switch (type->toBasetype()->ty) - { - case Tfloat32: - case Timaginary32: - type = Type::tcomplex32; - break; - - case Tfloat64: - case Timaginary64: - type = Type::tcomplex64; - break; - - case Tfloat80: - case Timaginary80: - type = Type::tcomplex80; - break; - - default: - assert(0); - } - } - e = this; - } - return e; - } - return this; -} - -/************************************************************/ - -MinExp::MinExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmin, sizeof(MinExp), e1, e2) -{ -} - -Expression *MinExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - Type *t2; - -#if LOGSEMANTIC - printf("MinExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - BinExp::semanticp(sc); - - e = op_overload(sc); - if (e) - return e; - - e = this; - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if (t1->ty == Tpointer) - { - if (t2->ty == Tpointer) - { // Need to divide the result by the stride - // Replace (ptr - ptr) with (ptr - ptr) / stride - d_int64 stride; - Expression *e; - - typeCombine(sc); // make sure pointer types are compatible - type = Type::tptrdiff_t; - stride = t2->nextOf()->size(); - if (stride == 0) - { - e = new IntegerExp(loc, 0, Type::tptrdiff_t); - } - else - { - e = new DivExp(loc, this, new IntegerExp(0, stride, Type::tptrdiff_t)); - e->type = Type::tptrdiff_t; - } - return e; - } - else if (t2->isintegral()) - e = scaleFactor(sc); - else - { error("can't subtract %s from pointer", t2->toChars()); - return new ErrorExp(); - } - } - else if (t2->ty == Tpointer) - { - type = e2->type; - error("can't subtract pointer from %s", e1->type->toChars()); - return new ErrorExp(); - } - else - { - typeCombine(sc); - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if ((t1->isreal() && t2->isimaginary()) || - (t1->isimaginary() && t2->isreal())) - { - switch (type->ty) - { - case Tfloat32: - case Timaginary32: - type = Type::tcomplex32; - break; - - case Tfloat64: - case Timaginary64: - type = Type::tcomplex64; - break; - - case Tfloat80: - case Timaginary80: - type = Type::tcomplex80; - break; - - default: - assert(0); - } - } - } - return e; -} - -/************************* CatExp *****************************/ - -CatExp::CatExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcat, sizeof(CatExp), e1, e2) -{ -} - -Expression *CatExp::semantic(Scope *sc) -{ Expression *e; - - //printf("CatExp::semantic() %s\n", toChars()); - if (!type) - { - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - - /* BUG: Should handle things like: - * char c; - * c ~ ' ' - * ' ' ~ c; - */ - -#if 0 - e1->type->print(); - e2->type->print(); -#endif - if ((tb1->ty == Tsarray || tb1->ty == Tarray) && - e2->type->equals(tb1->next)) - { - type = tb1->nextOf()->arrayOf(); - if (tb2->ty == Tarray) - { // Make e2 into [e2] - e2 = new ArrayLiteralExp(e2->loc, e2); - e2->type = type; - } - return this; - } - else if ((tb2->ty == Tsarray || tb2->ty == Tarray) && - e1->type->equals(tb2->next)) - { - type = tb2->nextOf()->arrayOf(); - if (tb1->ty == Tarray) - { // Make e1 into [e1] - e1 = new ArrayLiteralExp(e1->loc, e1); - e1->type = type; - } - return this; - } - - typeCombine(sc); - - if (type->toBasetype()->ty == Tsarray) - type = type->toBasetype()->next->arrayOf(); -#if 0 - e1->type->print(); - e2->type->print(); - type->print(); - print(); -#endif - if (e1->op == TOKstring && e2->op == TOKstring) - e = optimize(WANTvalue); - else if (e1->type->equals(e2->type) && - (e1->type->toBasetype()->ty == Tarray || - e1->type->toBasetype()->ty == Tsarray)) - { - e = this; - } - else - { - //printf("(%s) ~ (%s)\n", e1->toChars(), e2->toChars()); - error("Can only concatenate arrays, not (%s ~ %s)", - e1->type->toChars(), e2->type->toChars()); - type = Type::tint32; - e = this; - } - e->type = e->type->semantic(loc, sc); - return e; - } - return this; -} - -/************************************************************/ - -MulExp::MulExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmul, sizeof(MulExp), e1, e2) -{ -} - -Expression *MulExp::semantic(Scope *sc) -{ Expression *e; - -#if 0 - printf("MulExp::semantic() %s\n", toChars()); -#endif - if (type) - { - return this; - } - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkArithmetic(); - if (!e2->isArrayOperand()) - e2->checkArithmetic(); - if (type->isfloating()) - { Type *t1 = e1->type; - Type *t2 = e2->type; - - if (t1->isreal()) - { - type = t2; - } - else if (t2->isreal()) - { - type = t1; - } - else if (t1->isimaginary()) - { - if (t2->isimaginary()) - { Expression *e; - - switch (t1->toBasetype()->ty) - { - case Timaginary32: type = Type::tfloat32; break; - case Timaginary64: type = Type::tfloat64; break; - case Timaginary80: type = Type::tfloat80; break; - default: assert(0); - } - - // iy * iv = -yv - e1->type = type; - e2->type = type; - e = new NegExp(loc, this); - e = e->semantic(sc); - return e; - } - else - type = t2; // t2 is complex - } - else if (t2->isimaginary()) - { - type = t1; // t1 is complex - } - } - return this; -} - -/************************************************************/ - -DivExp::DivExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2) -{ -} - -Expression *DivExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkArithmetic(); - if (!e2->isArrayOperand()) - e2->checkArithmetic(); - if (type->isfloating()) - { Type *t1 = e1->type; - Type *t2 = e2->type; - - if (t1->isreal()) - { - type = t2; - if (t2->isimaginary()) - { Expression *e; - - // x/iv = i(-x/v) - e2->type = t1; - e = new NegExp(loc, this); - e = e->semantic(sc); - return e; - } - } - else if (t2->isreal()) - { - type = t1; - } - else if (t1->isimaginary()) - { - if (t2->isimaginary()) - { - switch (t1->toBasetype()->ty) - { - case Timaginary32: type = Type::tfloat32; break; - case Timaginary64: type = Type::tfloat64; break; - case Timaginary80: type = Type::tfloat80; break; - default: assert(0); - } - } - else - type = t2; // t2 is complex - } - else if (t2->isimaginary()) - { - type = t1; // t1 is complex - } - } - return this; -} - -/************************************************************/ - -ModExp::ModExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2) -{ -} - -Expression *ModExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkArithmetic(); - if (!e2->isArrayOperand()) - e2->checkArithmetic(); - if (type->isfloating()) - { type = e1->type; - if (e2->type->iscomplex()) - { error("cannot perform modulo complex arithmetic"); - return new IntegerExp(0); - } - } - return this; -} - -/************************************************************/ - -ShlExp::ShlExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshl, sizeof(ShlExp), e1, e2) -{ -} - -Expression *ShlExp::semantic(Scope *sc) -{ Expression *e; - - //printf("ShlExp::semantic(), type = %p\n", type); - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); -#if !IN_LLVM - e2 = e2->castTo(sc, Type::tshiftcnt); -#else - e2 = e2->castTo(sc, e1->type); -#endif - type = e1->type; - } - return this; -} - -/************************************************************/ - -ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2) -{ -} - -Expression *ShrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); -#if !IN_LLVM - e2 = e2->castTo(sc, Type::tshiftcnt); -#else - e2 = e2->castTo(sc, e1->type); -#endif - type = e1->type; - } - return this; -} - -/************************************************************/ - -UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2) -{ -} - -Expression *UshrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); -#if !IN_LLVM - e2 = e2->castTo(sc, Type::tshiftcnt); -#else - e2 = e2->castTo(sc, e1->type); -#endif - type = e1->type; - } - return this; -} - -/************************************************************/ - -AndExp::AndExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKand, sizeof(AndExp), e1, e2) -{ -} - -Expression *AndExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkIntegral(); - if (!e2->isArrayOperand()) - e2->checkIntegral(); - } - } - return this; -} - -/************************************************************/ - -OrExp::OrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKor, sizeof(OrExp), e1, e2) -{ -} - -Expression *OrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkIntegral(); - if (!e2->isArrayOperand()) - e2->checkIntegral(); - } - } - return this; -} - -/************************************************************/ - -XorExp::XorExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKxor, sizeof(XorExp), e1, e2) -{ -} - -Expression *XorExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkIntegral(); - if (!e2->isArrayOperand()) - e2->checkIntegral(); - } - } - return this; -} - - -/************************************************************/ - -OrOrExp::OrOrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKoror, sizeof(OrOrExp), e1, e2) -{ -} - -Expression *OrOrExp::semantic(Scope *sc) -{ - unsigned cs1; - - // same as for AndAnd - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToPointer(); - e1 = e1->checkToBoolean(); - cs1 = sc->callSuper; - - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate e2 if we don't have to. - */ - e1 = e1->optimize(WANTflags); - if (e1->isBool(TRUE)) - { - return new IntegerExp(loc, 1, Type::tboolean); - } - } - - e2 = e2->semantic(sc); - sc->mergeCallSuper(loc, cs1); - e2 = resolveProperties(sc, e2); - e2 = e2->checkToPointer(); - - if (e2->type->ty == Tvoid) - type = Type::tvoid; - else - { - e2 = e2->checkToBoolean(); - type = Type::tboolean; - } - if (e2->op == TOKtype || e2->op == TOKimport) - { error("%s is not an expression", e2->toChars()); - return new ErrorExp(); - } - if (e1->op == TOKerror) - return e1; - if (e2->op == TOKerror) - return e2; - return this; -} - -Expression *OrOrExp::checkToBoolean() -{ - e2 = e2->checkToBoolean(); - return this; -} - -int OrOrExp::isBit() -{ - return TRUE; -} - -int OrOrExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return e1->hasSideEffect() || e2->hasSideEffect(); - } - else - { e1->checkSideEffect(1); - return e2->checkSideEffect(flag); - } -} - -/************************************************************/ - -AndAndExp::AndAndExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKandand, sizeof(AndAndExp), e1, e2) -{ -} - -Expression *AndAndExp::semantic(Scope *sc) -{ - unsigned cs1; - - // same as for OrOr - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToPointer(); - e1 = e1->checkToBoolean(); - cs1 = sc->callSuper; - - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate e2 if we don't have to. - */ - e1 = e1->optimize(WANTflags); - if (e1->isBool(FALSE)) - { - return new IntegerExp(loc, 0, Type::tboolean); - } - } - - e2 = e2->semantic(sc); - sc->mergeCallSuper(loc, cs1); - e2 = resolveProperties(sc, e2); - e2 = e2->checkToPointer(); - - if (e2->type->ty == Tvoid) - type = Type::tvoid; - else - { - e2 = e2->checkToBoolean(); - type = Type::tboolean; - } - if (e2->op == TOKtype || e2->op == TOKimport) - { error("%s is not an expression", e2->toChars()); - return new ErrorExp(); - } - if (e1->op == TOKerror) - return e1; - if (e2->op == TOKerror) - return e2; - return this; -} - -Expression *AndAndExp::checkToBoolean() -{ - e2 = e2->checkToBoolean(); - return this; -} - -int AndAndExp::isBit() -{ - return TRUE; -} - -int AndAndExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return e1->hasSideEffect() || e2->hasSideEffect(); - } - else - { - e1->checkSideEffect(1); - return e2->checkSideEffect(flag); - } -} - -/************************************************************/ - -InExp::InExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKin, sizeof(InExp), e1, e2) -{ -} - -Expression *InExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - //type = Type::tboolean; - Type *t2b = e2->type->toBasetype(); - switch (t2b->ty) - { - case Taarray: - { - TypeAArray *ta = (TypeAArray *)t2b; - -#if DMDV2 - // Special handling for array keys - if (!arrayTypeCompatible(e1->loc, e1->type, ta->index)) -#endif - { - // Convert key to type of key - e1 = e1->implicitCastTo(sc, ta->index); - } - - // Return type is pointer to value - type = ta->nextOf()->pointerTo(); - break; - } - - default: - error("rvalue of in expression must be an associative array, not %s", e2->type->toChars()); - case Terror: - return new ErrorExp(); - } - return this; -} - -int InExp::isBit() -{ - return FALSE; -} - - -/************************************************************/ - -/* This deletes the key e1 from the associative array e2 - */ - -RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2) -{ - type = Type::tvoid; -} - -void RemoveExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writestring(".remove("); - expToCBuffer(buf, hgs, e2, PREC_assign); - buf->writestring(")"); -} - -/************************************************************/ - -CmpExp::CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(CmpExp), e1, e2) -{ -} - -Expression *CmpExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("CmpExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - BinExp::semanticp(sc); - - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - if (t1->ty == Tclass && e2->op == TOKnull || - t2->ty == Tclass && e1->op == TOKnull) - { - error("do not use null when comparing class types"); - } - - e = op_overload(sc); - if (e) - { - if (!e->type->isscalar() && e->type->equals(e1->type)) - { - error("recursive opCmp expansion"); - e = new ErrorExp(); - } - else - { e = new CmpExp(op, loc, e, new IntegerExp(loc, 0, Type::tint32)); - e = e->semantic(sc); - } - return e; - } - - /* Disallow comparing T[]==T and T==T[] - */ - if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) || - e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) - { - incompatibleTypes(); - return new ErrorExp(); - } - - typeCombine(sc); - type = Type::tboolean; - - // Special handling for array comparisons - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if ((t1->ty == Tarray || t1->ty == Tsarray) && - (t2->ty == Tarray || t2->ty == Tsarray)) - { - if (!t1->next->equals(t2->next)) - error("array comparison type mismatch, %s vs %s", t1->next->toChars(), t2->next->toChars()); - e = this; - } - else if (t1->ty == Tstruct || t2->ty == Tstruct || - (t1->ty == Tclass && t2->ty == Tclass)) - { - if (t2->ty == Tstruct) - error("need member function opCmp() for %s %s to compare", t2->toDsymbol(sc)->kind(), t2->toChars()); - else - error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars()); - e = this; - } -#if 1 - else if (t1->iscomplex() || t2->iscomplex()) - { - error("compare not defined for complex operands"); - e = new IntegerExp(0); - } -#endif - else - e = this; - //printf("CmpExp: %s\n", e->toChars()); - return e; -} - -int CmpExp::isBit() -{ - return TRUE; -} - - -/************************************************************/ - -EqualExp::EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(EqualExp), e1, e2) -{ - assert(op == TOKequal || op == TOKnotequal); -} - -Expression *EqualExp::semantic(Scope *sc) -{ Expression *e; - - //printf("EqualExp::semantic('%s')\n", toChars()); - if (type) - return this; - - BinExp::semanticp(sc); - - /* Before checking for operator overloading, check to see if we're - * comparing the addresses of two statics. If so, we can just see - * if they are the same symbol. - */ - if (e1->op == TOKaddress && e2->op == TOKaddress) - { AddrExp *ae1 = (AddrExp *)e1; - AddrExp *ae2 = (AddrExp *)e2; - - if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar) - { VarExp *ve1 = (VarExp *)ae1->e1; - VarExp *ve2 = (VarExp *)ae2->e1; - - if (ve1->var == ve2->var /*|| ve1->var->toSymbol() == ve2->var->toSymbol()*/) - { - // They are the same, result is 'true' for ==, 'false' for != - e = new IntegerExp(loc, (op == TOKequal), Type::tboolean); - return e; - } - } - } - - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - if (t1->ty == Tclass && e2->op == TOKnull || - t2->ty == Tclass && e1->op == TOKnull) - { - error("use '%s' instead of '%s' when comparing with null", - Token::toChars(op == TOKequal ? TOKidentity : TOKnotidentity), - Token::toChars(op)); - } - - //if (e2->op != TOKnull) - { - e = op_overload(sc); - if (e) - { - if (op == TOKnotequal) - { - e = new NotExp(e->loc, e); - e = e->semantic(sc); - } - return e; - } - } - - /* Disallow comparing T[]==T and T==T[] - */ - if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) || - e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) - { - incompatibleTypes(); - return new ErrorExp(); - } - - e = typeCombine(sc); - type = Type::tboolean; - - // Special handling for array comparisons - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if ((t1->ty == Tarray || t1->ty == Tsarray) && - (t2->ty == Tarray || t2->ty == Tsarray)) - { - if (!t1->next->equals(t2->next)) - error("array comparison type mismatch, %s vs %s", t1->next->toChars(), t2->next->toChars()); - } - else - { - if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) - { - // Cast both to complex - e1 = e1->castTo(sc, Type::tcomplex80); - e2 = e2->castTo(sc, Type::tcomplex80); - } - } - return e; -} - -int EqualExp::isBit() -{ - return TRUE; -} - - - -/************************************************************/ - -IdentityExp::IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(IdentityExp), e1, e2) -{ -} - -Expression *IdentityExp::semantic(Scope *sc) -{ - if (type) - return this; - - BinExp::semanticp(sc); - type = Type::tboolean; - typeCombine(sc); - if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) - { - // Cast both to complex - e1 = e1->castTo(sc, Type::tcomplex80); - e2 = e2->castTo(sc, Type::tcomplex80); - } - return this; -} - -int IdentityExp::isBit() -{ - return TRUE; -} - - -/****************************************************************/ - -CondExp::CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2) - : BinExp(loc, TOKquestion, sizeof(CondExp), e1, e2) -{ - this->econd = econd; -} - -Expression *CondExp::syntaxCopy() -{ - return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy()); -} - - -Expression *CondExp::semantic(Scope *sc) -{ Type *t1; - Type *t2; - unsigned cs0; - unsigned cs1; - -#if LOGSEMANTIC - printf("CondExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - econd = econd->semantic(sc); - econd = resolveProperties(sc, econd); - econd = econd->checkToPointer(); - econd = econd->checkToBoolean(); - -#if 0 /* this cannot work right because the types of e1 and e2 - * both contribute to the type of the result. - */ - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate what we don't have to. - */ - econd = econd->optimize(WANTflags); - if (econd->isBool(TRUE)) - { - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - return e1; - } - else if (econd->isBool(FALSE)) - { - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - return e2; - } - } -#endif - - - cs0 = sc->callSuper; - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - cs1 = sc->callSuper; - sc->callSuper = cs0; - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - sc->mergeCallSuper(loc, cs1); - - - // If either operand is void, the result is void - t1 = e1->type; - t2 = e2->type; - if (t1->ty == Tvoid || t2->ty == Tvoid) - type = Type::tvoid; - else if (t1 == t2) - type = t1; - else - { - typeCombine(sc); - switch (e1->type->toBasetype()->ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - e2 = e2->castTo(sc, e1->type); - break; - } - switch (e2->type->toBasetype()->ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - e1 = e1->castTo(sc, e2->type); - break; - } - } -#if 0 - printf("res: %s\n", type->toChars()); - printf("e1 : %s\n", e1->type->toChars()); - printf("e2 : %s\n", e2->type->toChars()); -#endif - return this; -} - - -int CondExp::isLvalue() -{ - return e1->isLvalue() && e2->isLvalue(); -} - - -Expression *CondExp::toLvalue(Scope *sc, Expression *ex) -{ - PtrExp *e; - - // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) - e = new PtrExp(loc, this, type); - - e1 = e1->addressOf(sc); - e2 = e2->addressOf(sc); - - typeCombine(sc); - - type = e2->type; - return e; -} - -Expression *CondExp::modifiableLvalue(Scope *sc, Expression *e) -{ - error("conditional expression %s is not a modifiable lvalue", toChars()); - return this; -} - -void CondExp::checkEscape() -{ - e1->checkEscape(); - e2->checkEscape(); -} - -void CondExp::checkEscapeRef() -{ - e1->checkEscapeRef(); - e2->checkEscapeRef(); -} - - -Expression *CondExp::checkToBoolean() -{ - e1 = e1->checkToBoolean(); - e2 = e2->checkToBoolean(); - return this; -} - -int CondExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return econd->hasSideEffect() || - e1->hasSideEffect() || - e2->hasSideEffect(); - } - else - { - econd->checkSideEffect(1); - e1->checkSideEffect(flag); - return e2->checkSideEffect(flag); - } -} - -#if DMDV2 -int CondExp::canThrow() -{ - return econd->canThrow() || e1->canThrow() || e2->canThrow(); -} -#endif - -void CondExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, econd, PREC_oror); - buf->writestring(" ? "); - expToCBuffer(buf, hgs, e1, PREC_expr); - buf->writestring(" : "); - expToCBuffer(buf, hgs, e2, PREC_cond); -} - -/************************************************************/ - -#if IN_LLVM - -// Strictly LDC specific stuff - -GEPExp::GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx) - : UnaExp(loc, TOKgep, sizeof(GEPExp), e) -{ - index = idx; - ident = id; -} - -void GEPExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(ident->toChars()); -} - -Expression* GEPExp::toLvalue(Scope* sc, Expression* e) -{ - // GEP's are always lvalues, at least in the "LLVM sense" ... - return this; -} - -#endif diff --git a/dmd/expression.h b/dmd/expression.h deleted file mode 100644 index e8ffdcda..00000000 --- a/dmd/expression.h +++ /dev/null @@ -1,2063 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_EXPRESSION_H -#define DMD_EXPRESSION_H - -#include "mars.h" -#include "identifier.h" -#include "lexer.h" -#include "arraytypes.h" - -struct Type; -struct Scope; -struct TupleDeclaration; -struct VarDeclaration; -struct FuncDeclaration; -struct FuncLiteralDeclaration; -struct Declaration; -struct CtorDeclaration; -struct NewDeclaration; -struct Dsymbol; -struct Import; -struct Module; -struct ScopeDsymbol; -struct InlineCostState; -struct InlineDoState; -struct InlineScanState; -struct Expression; -struct Declaration; -struct AggregateDeclaration; -struct StructDeclaration; -struct TemplateInstance; -struct TemplateDeclaration; -struct ClassDeclaration; -struct HdrGenState; -struct BinExp; -struct AssignExp; -struct InterState; -struct OverloadSet; -struct Initializer; -struct StringExp; - -enum TOK; - -#if IN_DMD -// Back end -struct IRState; -struct dt_t; -struct elem; -struct Symbol; // back end symbol -#endif - -#ifdef IN_GCC -union tree_node; typedef union tree_node elem; -#endif - -#if IN_LLVM -struct IRState; -struct DValue; -namespace llvm { - class Constant; - class ConstantInt; - class StructType; -} -#endif - -void initPrecedence(); - -typedef int (*apply_fp_t)(Expression *, void *); - -Expression *resolveProperties(Scope *sc, Expression *e); -void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d); -Dsymbol *search_function(AggregateDeclaration *ad, Identifier *funcid); -void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Module* from); -void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); -void expandTuples(Expressions *exps); -FuncDeclaration *hasThis(Scope *sc); -Expression *fromConstInitializer(int result, Expression *e); -int arrayExpressionCanThrow(Expressions *exps); -TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s); - -/* Interpreter: what form of return value expression is required? - */ -enum CtfeGoal -{ ctfeNeedRvalue, // Must return an Rvalue - ctfeNeedLvalue, // Must return an Lvalue - ctfeNeedAnyValue, // Can return either an Rvalue or an Lvalue - ctfeNeedLvalueRef,// Must return a reference to an Lvalue (for ref types) - ctfeNeedNothing // The return value is not required -}; - -struct IntRange -{ uinteger_t imin; - uinteger_t imax; -}; - -struct Expression : Object -{ - Loc loc; // file location - enum TOK op; // handy to minimize use of dynamic_cast - Type *type; // !=NULL means that semantic() has been run - int size; // # of bytes in Expression so we can copy() it - - Expression(Loc loc, enum TOK op, int size); - Expression *copy(); - virtual Expression *syntaxCopy(); - virtual int apply(apply_fp_t fp, void *param); - virtual Expression *semantic(Scope *sc); - Expression *trySemantic(Scope *sc); - - int dyncast() { return DYNCAST_EXPRESSION; } // kludge for template.isExpression() - - void print(); - char *toChars(); - virtual void dump(int indent); - void error(const char *format, ...) IS_PRINTF(2); - void warning(const char *format, ...) IS_PRINTF(2); - virtual int rvalue(); - - static Expression *combine(Expression *e1, Expression *e2); - static Expressions *arraySyntaxCopy(Expressions *exps); - - virtual dinteger_t toInteger(); - virtual uinteger_t toUInteger(); - virtual real_t toReal(); - virtual real_t toImaginary(); - virtual complex_t toComplex(); - virtual StringExp *toString(); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toMangleBuffer(OutBuffer *buf); - virtual int isLvalue(); - virtual Expression *toLvalue(Scope *sc, Expression *e); - virtual Expression *modifiableLvalue(Scope *sc, Expression *e); - virtual Expression *implicitCastTo(Scope *sc, Type *t); - virtual MATCH implicitConvTo(Type *t); - virtual Expression *castTo(Scope *sc, Type *t); - virtual void checkEscape(); - virtual void checkEscapeRef(); - void checkScalar(); - void checkNoBool(); - Expression *checkIntegral(); - Expression *checkArithmetic(); - void checkDeprecated(Scope *sc, Dsymbol *s); - virtual Expression *checkToBoolean(); - Expression *checkToPointer(); - Expression *addressOf(Scope *sc); - Expression *deref(); - Expression *integralPromotions(Scope *sc); - - Expression *toDelegate(Scope *sc, Type *t); - - virtual Expression *optimize(int result); - #define WANTflags 1 - #define WANTvalue 2 - // A compile-time result is required. Give an error if not possible - #define WANTinterpret 4 - // Same as WANTvalue, but also expand variables as far as possible - #define WANTexpand 8 - - // Entry point for CTFE. - // A compile-time result is required. Give an error if not possible - Expression *ctfeInterpret(); - - // Implementation of CTFE for this expression - virtual Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - - virtual int isConst(); - virtual int isBool(int result); - virtual int isBit(); - bool hasSideEffect(); - virtual int checkSideEffect(int flag); - virtual int canThrow(); - - virtual int inlineCost3(InlineCostState *ics); - virtual Expression *doInline(InlineDoState *ids); - virtual Expression *inlineScan(InlineScanState *iss); - Expression *inlineCopy(Scope *sc); - - // For operator overloading - virtual int isCommutative(); - virtual Identifier *opId(); - virtual Identifier *opId_r(); - - // For array ops - virtual void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - virtual Expression *buildArrayLoop(Parameters *fparams); - int isArrayOperand(); - -#if IN_DMD - // Back end - virtual elem *toElem(IRState *irs); - virtual dt_t **toDt(dt_t **pdt); -#endif - -#if IN_LLVM - virtual DValue* toElem(IRState* irs); - DValue *toElemDtor(IRState *irs); - virtual llvm::Constant *toConstElem(IRState *irs); - virtual void cacheLvalue(IRState* irs); - - llvm::Value* cachedLvalue; - - virtual AssignExp* isAssignExp() { return NULL; } -#endif -}; - -struct IntegerExp : Expression -{ - dinteger_t value; - - IntegerExp(Loc loc, dinteger_t value, Type *type); - IntegerExp(dinteger_t value); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - char *toChars(); - void dump(int indent); - dinteger_t toInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - int isConst(); - int isBool(int result); - MATCH implicitConvTo(Type *t); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - Expression *toLvalue(Scope *sc, Expression *e); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct ErrorExp : IntegerExp -{ - ErrorExp(); - - Expression *implicitCastTo(Scope *sc, Type *t); - Expression *castTo(Scope *sc, Type *t); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct RealExp : Expression -{ - real_t value; - - RealExp(Loc loc, real_t value, Type *type); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - char *toChars(); - dinteger_t toInteger(); - uinteger_t toUInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - Expression *castTo(Scope *sc, Type *t); - int isConst(); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct ComplexExp : Expression -{ - complex_t value; - - ComplexExp(Loc loc, complex_t value, Type *type); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - char *toChars(); - dinteger_t toInteger(); - uinteger_t toUInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - Expression *castTo(Scope *sc, Type *t); - int isConst(); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - OutBuffer hexp; -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct IdentifierExp : Expression -{ - Identifier *ident; - Declaration *var; - - IdentifierExp(Loc loc, Identifier *ident); - IdentifierExp(Loc loc, Declaration *var); - Expression *semantic(Scope *sc); - char *toChars(); - void dump(int indent); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; - -struct DollarExp : IdentifierExp -{ - DollarExp(Loc loc); -}; - -struct DsymbolExp : Expression -{ - Dsymbol *s; - int hasOverloads; - - DsymbolExp(Loc loc, Dsymbol *s); - Expression *semantic(Scope *sc); - char *toChars(); - void dump(int indent); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; - -struct ThisExp : Expression -{ - Declaration *var; - - ThisExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - - int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct SuperExp : ThisExp -{ - SuperExp(Loc loc); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); -}; - -struct NullExp : Expression -{ - unsigned char committed; // !=0 if type is committed - - NullExp(Loc loc, Type *t = NULL); - Expression *semantic(Scope *sc); - int isBool(int result); - int isConst(); - StringExp *toString(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct StringExp : Expression -{ - void *string; // char, wchar, or dchar data - size_t len; // number of chars, wchars, or dchars - unsigned char sz; // 1: char, 2: wchar, 4: dchar - unsigned char committed; // !=0 if type is committed - unsigned char postfix; // 'c', 'w', 'd' - bool ownedByCtfe; // true = created in CTFE - - StringExp(Loc loc, char *s); - StringExp(Loc loc, void *s, size_t len); - StringExp(Loc loc, void *s, size_t len, unsigned char postfix); - //Expression *syntaxCopy(); - int equals(Object *o); - char *toChars(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - size_t length(); - StringExp *toString(); - StringExp *toUTF8(Scope *sc); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - int compare(Object *obj); - int isBool(int result); - int isLvalue(); - unsigned charAt(size_t i); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -// Tuple - -struct TupleExp : Expression -{ - Expressions *exps; - - TupleExp(Loc loc, Expressions *exps); - TupleExp(Loc loc, TupleDeclaration *tup); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - int equals(Object *o); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void checkEscape(); - int checkSideEffect(int flag); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - Expression *castTo(Scope *sc, Type *t); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ArrayLiteralExp : Expression -{ - Expressions *elements; - bool ownedByCtfe; // true = created in CTFE - - ArrayLiteralExp(Loc loc, Expressions *elements); - ArrayLiteralExp(Loc loc, Expression *e); - - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - int isBool(int result); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - int checkSideEffect(int flag); - StringExp *toString(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct AssocArrayLiteralExp : Expression -{ - Expressions *keys; - Expressions *values; - bool ownedByCtfe; // true = created in CTFE - - AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values); - - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - int isBool(int result); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct StructLiteralExp : Expression -{ - StructDeclaration *sd; // which aggregate this is for - Expressions *elements; // parallels sd->fields[] with - // NULL entries for fields to skip - Type *stype; // final type of result (can be different from sd's type) - -#if IN_DMD - Symbol *sym; // back end symbol to initialize with literal -#endif - size_t soffset; // offset from start of s - int fillHoles; // fill alignment 'holes' with zero - bool ownedByCtfe; // true = created in CTFE - - StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype = NULL); - - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - Expression *getField(Type *type, unsigned offset); - int getFieldIndex(Type *type, unsigned offset); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - Expression *toLvalue(Scope *sc, Expression *e); - - int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); - llvm::StructType *constType; -#endif -}; - -Expression *typeDotIdExp(Loc loc, Type *type, Identifier *ident); -#if IN_DMD -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif - -struct TypeExp : Expression -{ - TypeExp(Loc loc, Type *type); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ScopeExp : Expression -{ - ScopeDsymbol *sds; - - ScopeExp(Loc loc, ScopeDsymbol *sds); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct TemplateExp : Expression -{ - TemplateDeclaration *td; - - TemplateExp(Loc loc, TemplateDeclaration *td); - int rvalue(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct NewExp : Expression -{ - /* thisexp.new(newargs) newtype(arguments) - */ - Expression *thisexp; // if !NULL, 'this' for class being allocated - Expressions *newargs; // Array of Expression's to call new operator - Type *newtype; - Expressions *arguments; // Array of Expression's - - CtorDeclaration *member; // constructor function - NewDeclaration *allocator; // allocator function - int onstack; // allocate on stack - - NewExp(Loc loc, Expression *thisexp, Expressions *newargs, - Type *newtype, Expressions *arguments); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - Expression *optimize(int result); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - //int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct NewAnonClassExp : Expression -{ - /* thisexp.new(newargs) class baseclasses { } (arguments) - */ - Expression *thisexp; // if !NULL, 'this' for class being allocated - Expressions *newargs; // Array of Expression's to call new operator - ClassDeclaration *cd; // class being instantiated - Expressions *arguments; // Array of Expression's to call class constructor - - NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs, - ClassDeclaration *cd, Expressions *arguments); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#if DMDV2 -struct SymbolExp : Expression -{ - Declaration *var; - int hasOverloads; - - SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads); - - elem *toElem(IRState *irs); -}; -#endif - -// Offset from symbol - -struct SymOffExp : Expression -{ - Declaration *var; - unsigned offset; - Module* m; // starting point for overload resolution - - SymOffExp(Loc loc, Declaration *var, unsigned offset); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void checkEscape(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isConst(); - int isBool(int result); - Expression *doInline(InlineDoState *ids); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// Variable - -struct VarExp : Expression -{ - Declaration *var; - - VarExp(Loc loc, Declaration *var); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void dump(int indent); - char *toChars(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void checkEscape(); - void checkEscapeRef(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#endif - - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); - void cacheLvalue(IRState* irs); -#endif -}; - -#if DMDV2 -// Overload Set - -struct OverExp : Expression -{ - OverloadSet *vars; - - OverExp(OverloadSet *s); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; -#endif - -// Function/Delegate literal - -struct FuncExp : Expression -{ - FuncLiteralDeclaration *fd; - - FuncExp(Loc loc, FuncLiteralDeclaration *fd); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - char *toChars(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#endif - - int inlineCost3(InlineCostState *ics); - //Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -// Declaration of a symbol - -struct DeclarationExp : Expression -{ - Dsymbol *declaration; - - DeclarationExp(Loc loc, Dsymbol *declaration); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - - int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct TypeidExp : Expression -{ - Type *typeidType; - - TypeidExp(Loc loc, Type *typeidType); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#if DMDV2 -struct TraitsExp : Expression -{ - Identifier *ident; - Objects *args; - - TraitsExp(Loc loc, Identifier *ident, Objects *args); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; -#endif - -struct HaltExp : Expression -{ - HaltExp(Loc loc); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int checkSideEffect(int flag); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct IsExp : Expression -{ - /* is(targ id tok tspec) - * is(targ id == tok2) - */ - Type *targ; - Identifier *id; // can be NULL - enum TOK tok; // ':' or '==' - Type *tspec; // can be NULL - enum TOK tok2; // 'struct', 'union', 'typedef', etc. - - IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec, enum TOK tok2); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -/****************************************************************/ - -struct UnaExp : Expression -{ - Expression *e1; - - UnaExp(Loc loc, enum TOK op, int size, Expression *e1); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - void dump(int indent); - Expression *interpretCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *)); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - Expression *op_overload(Scope *sc); // doesn't need to be virtual -}; - -struct BinExp : Expression -{ - Expression *e1; - Expression *e2; - - BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - Expression *semanticp(Scope *sc); - Expression *commonSemanticAssign(Scope *sc); - Expression *commonSemanticAssignIntegral(Scope *sc); - int checkSideEffect(int flag); - void checkComplexMulAssign(); - void checkComplexAddAssign(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *scaleFactor(Scope *sc); - Expression *typeCombine(Scope *sc); - Expression *optimize(int result); - int isunsigned(); - void incompatibleTypes(); - void dump(int indent); - Expression *interpretCommon(InterState *istate, CtfeGoal goal, - Expression *(*fp)(Type *, Expression *, Expression *)); - Expression *interpretCommon2(InterState *istate, CtfeGoal goal, - Expression *(*fp)(Loc, TOK, Type *, Expression *, Expression *)); - Expression *interpretAssignCommon(InterState *istate, CtfeGoal goal, - Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); - Expression *interpretFourPointerRelation(InterState *istate, CtfeGoal goal); - Expression *arrayOp(Scope *sc); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - Expression *op_overload(Scope *sc); - -#if IN_DMD - elem *toElemBin(IRState *irs, int op); -#endif -}; - -struct BinAssignExp : BinExp -{ - BinAssignExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) - : BinExp(loc, op, size, e1, e2) - { - } - - Expression *semantic(Scope *sc); - int isLvalue(); -}; - -/****************************************************************/ - -struct CompileExp : UnaExp -{ - CompileExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct FileExp : UnaExp -{ - FileExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct AssertExp : UnaExp -{ - Expression *msg; - - AssertExp(Loc loc, Expression *e, Expression *msg = NULL); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct DotIdExp : UnaExp -{ - Identifier *ident; - - DotIdExp(Loc loc, Expression *e, Identifier *ident); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int i); -}; - -struct DotTemplateExp : UnaExp -{ - TemplateDeclaration *td; - - DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct DotVarExp : UnaExp -{ - Declaration *var; - - DotVarExp(Loc loc, Expression *e, Declaration *var); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); - void cacheLvalue(IRState* irs); -#endif -}; - -struct DotTemplateInstanceExp : UnaExp -{ - TemplateInstance *ti; - - DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); -}; - -struct DelegateExp : UnaExp -{ - FuncDeclaration *func; - Module* m; // starting point for overload resolution - int hasOverloads; - - DelegateExp(Loc loc, Expression *e, FuncDeclaration *func); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); - - int inlineCost3(InlineCostState *ics); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct DotTypeExp : UnaExp -{ - Dsymbol *sym; // symbol that represents a type - - DotTypeExp(Loc loc, Expression *e, Dsymbol *sym); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct CallExp : UnaExp -{ - Expressions *arguments; // function arguments - - CallExp(Loc loc, Expression *e, Expressions *exps); - CallExp(Loc loc, Expression *e); - CallExp(Loc loc, Expression *e, Expression *earg1); - CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2); - - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - - int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - void cacheLvalue(IRState* p); - DValue* toElem(IRState* irs); -#endif -}; - -struct AddrExp : UnaExp -{ - Module* m; // starting point for overload resolution - - AddrExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void checkEscape(); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct PtrExp : UnaExp -{ - PtrExp(Loc loc, Expression *e); - PtrExp(Loc loc, Expression *e, Type *t); - Expression *semantic(Scope *sc); - int isLvalue(); - void checkEscapeRef(); - Expression *toLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - -#if IN_LLVM - DValue* toElem(IRState* irs); - void cacheLvalue(IRState* irs); -#endif -}; - -struct NegExp : UnaExp -{ - NegExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - - // For operator overloading - Identifier *opId(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct UAddExp : UnaExp -{ - UAddExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - - // For operator overloading - Identifier *opId(); -}; - -struct ComExp : UnaExp -{ - ComExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - - // For operator overloading - Identifier *opId(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct NotExp : UnaExp -{ - NotExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBit(); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct BoolExp : UnaExp -{ - BoolExp(Loc loc, Expression *e, Type *type); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBit(); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct DeleteExp : UnaExp -{ - DeleteExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct CastExp : UnaExp -{ - // Possible to cast to one type while painting to another type - Type *to; // type to cast to - - CastExp(Loc loc, Expression *e, Type *t); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); - void checkEscape(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - - // For operator overloading - Identifier *opId(); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - - -struct SliceExp : UnaExp -{ - Expression *upr; // NULL if implicit 0 - Expression *lwr; // NULL if implicit [length - 1] - VarDeclaration *lengthVar; - - SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - void checkEscape(); - void checkEscapeRef(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void dump(int indent); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - int canThrow(); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct ArrayLengthExp : UnaExp -{ - ArrayLengthExp(Loc loc, Expression *e1); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// e1[a0,a1,a2,a3,...] - -struct ArrayExp : UnaExp -{ - Expressions *arguments; // Array of Expression's - - ArrayExp(Loc loc, Expression *e1, Expressions *arguments); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - // For operator overloading - Identifier *opId(); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); -}; - -/****************************************************************/ - -struct DotExp : BinExp -{ - DotExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct CommaExp : BinExp -{ - CommaExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - void checkEscape(); - void checkEscapeRef(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - int isBool(int result); - int checkSideEffect(int flag); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - void cacheLvalue(IRState* p); - DValue* toElem(IRState* irs); -#endif -}; - -struct IndexExp : BinExp -{ - VarDeclaration *lengthVar; - int modifiable; - - IndexExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - Expression *doInline(InlineDoState *ids); - -#if IN_DMD - elem *toElem(IRState *irs); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); - void cacheLvalue(IRState* irs); -#endif -}; - -/* For both i++ and i-- - */ -struct PostExp : BinExp -{ - PostExp(enum TOK op, Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Identifier *opId(); // For operator overloading -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct AssignExp : BinExp -{ int ismemset; // !=0 if setting the contents of an array - - AssignExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - Identifier *opId(); // For operator overloading - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif - - AssignExp* isAssignExp() { return this; } -}; - -struct ConstructExp : AssignExp -{ - ConstructExp(Loc loc, Expression *e1, Expression *e2); -}; - -#if IN_DMD -#define ASSIGNEXP_TOELEM elem *toElem(IRState *irs); -#elif IN_LLVM -#define ASSIGNEXP_TOELEM DValue* toElem(IRState *irs); -#else -#define ASSIGNEXP_TOELEM -#endif - -#define ASSIGNEXP(op) \ -struct op##AssignExp : BinAssignExp \ -{ \ - op##AssignExp(Loc loc, Expression *e1, Expression *e2); \ - S(Expression *semantic(Scope *sc);) \ - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); \ - X(void buildArrayIdent(OutBuffer *buf, Expressions *arguments);) \ - X(Expression *buildArrayLoop(Parameters *fparams);) \ - \ - Identifier *opId(); /* For operator overloading */ \ - \ - ASSIGNEXP_TOELEM \ -}; - -#define X(a) a -#define S(a) a -ASSIGNEXP(Add) -ASSIGNEXP(Min) -ASSIGNEXP(Mul) -ASSIGNEXP(Div) -ASSIGNEXP(Mod) -ASSIGNEXP(And) -ASSIGNEXP(Or) -ASSIGNEXP(Xor) -#undef S - -#if DMDV2 -#define S(a) a -ASSIGNEXP(Pow) -#undef S -#endif - -#undef X - -#define X(a) -#define S(a) - -ASSIGNEXP(Shl) -ASSIGNEXP(Shr) -ASSIGNEXP(Ushr) -#undef S - -#define S(a) a -ASSIGNEXP(Cat) - -#undef S -#undef X -#undef ASSIGNEXP -#undef ASSIGNEXP_TOELEM - -struct AddExp : BinExp -{ - AddExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - llvm::Constant* toConstElem(IRState* p); - DValue* toElem(IRState* irs); -#endif -}; - -struct MinExp : BinExp -{ - MinExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - llvm::Constant* toConstElem(IRState* p); - DValue* toElem(IRState* irs); -#endif -}; - -struct CatExp : BinExp -{ - CatExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct MulExp : BinExp -{ - MulExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct DivExp : BinExp -{ - DivExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ModExp : BinExp -{ - ModExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -#if DMDV2 -struct PowExp : BinExp -{ - PowExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); -}; -#endif - -struct ShlExp : BinExp -{ - ShlExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ShrExp : BinExp -{ - ShrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct UshrExp : BinExp -{ - UshrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct AndExp : BinExp -{ - AndExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct OrExp : BinExp -{ - OrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct XorExp : BinExp -{ - XorExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct OrOrExp : BinExp -{ - OrOrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct AndAndExp : BinExp -{ - AndAndExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct CmpExp : BinExp -{ - CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBit(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct InExp : BinExp -{ - InExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBit(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct RemoveExp : BinExp -{ - RemoveExp(Loc loc, Expression *e1, Expression *e2); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// == and != - -struct EqualExp : BinExp -{ - EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBit(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// === and !=== - -struct IdentityExp : BinExp -{ - IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -/****************************************************************/ - -struct CondExp : BinExp -{ - Expression *econd; - - CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void checkEscape(); - void checkEscapeRef(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - Expression *checkToBoolean(); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -#if DMDV2 -/****************************************************************/ - -struct DefaultInitExp : Expression -{ - enum TOK subop; // which of the derived classes this is - - DefaultInitExp(Loc loc, enum TOK subop, int size); - virtual Expression *resolve(Loc loc, Scope *sc) = 0; - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct FileInitExp : DefaultInitExp -{ - FileInitExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *resolve(Loc loc, Scope *sc); -}; - -struct LineInitExp : DefaultInitExp -{ - LineInitExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *resolve(Loc loc, Scope *sc); -}; -#endif - -/****************************************************************/ - -#if IN_LLVM - -// this stuff is strictly LDC - -// Special expression to represent a LLVM GetElementPtr instruction. -struct GEPExp : UnaExp -{ - unsigned index; - Identifier* ident; - - GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *toLvalue(Scope *sc, Expression *e); - - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -}; - -#endif - -/****************************************************************/ - -/* Special values used by the interpreter - */ -#define EXP_CANT_INTERPRET ((Expression *)1) -#define EXP_CONTINUE_INTERPRET ((Expression *)2) -#define EXP_BREAK_INTERPRET ((Expression *)3) -#define EXP_GOTO_INTERPRET ((Expression *)4) -#define EXP_VOID_INTERPRET ((Expression *)5) - -Expression *expType(Type *type, Expression *e); - -Expression *Neg(Type *type, Expression *e1); -Expression *Com(Type *type, Expression *e1); -Expression *Not(Type *type, Expression *e1); -Expression *Bool(Type *type, Expression *e1); -Expression *Cast(Type *type, Type *to, Expression *e1); -Expression *ArrayLength(Type *type, Expression *e1); -Expression *Ptr(Type *type, Expression *e1); - -Expression *Add(Type *type, Expression *e1, Expression *e2); -Expression *Min(Type *type, Expression *e1, Expression *e2); -Expression *Mul(Type *type, Expression *e1, Expression *e2); -Expression *Div(Type *type, Expression *e1, Expression *e2); -Expression *Mod(Type *type, Expression *e1, Expression *e2); -Expression *Shl(Type *type, Expression *e1, Expression *e2); -Expression *Shr(Type *type, Expression *e1, Expression *e2); -Expression *Ushr(Type *type, Expression *e1, Expression *e2); -Expression *And(Type *type, Expression *e1, Expression *e2); -Expression *Or(Type *type, Expression *e1, Expression *e2); -Expression *Xor(Type *type, Expression *e1, Expression *e2); -Expression *Index(Type *type, Expression *e1, Expression *e2); -Expression *Cat(Type *type, Expression *e1, Expression *e2); - -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2); - -Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr); - -// Const-folding functions used by CTFE - -void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex); -void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex); -void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex); - -int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len); -int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len); - - -#endif /* DMD_EXPRESSION_H */ diff --git a/dmd/func.c b/dmd/func.c deleted file mode 100644 index 540bb8ef..00000000 --- a/dmd/func.c +++ /dev/null @@ -1,3653 +0,0 @@ -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "expression.h" -#include "scope.h" -#include "mtype.h" -#include "aggregate.h" -#include "identifier.h" -#include "id.h" -#include "module.h" -#include "statement.h" -#include "template.h" -#include "hdrgen.h" - -#ifdef IN_GCC -#include "d-dmd-gcc.h" -#endif - -/********************************* FuncDeclaration ****************************/ - -FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type) - : Declaration(id) -{ - //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); - //printf("storage_class = x%x\n", storage_class); - this->storage_class = storage_class; - this->type = type; - this->loc = loc; - this->endloc = endloc; - fthrows = NULL; - frequire = NULL; - fdrequire = NULL; - fdensure = NULL; - outId = NULL; - vresult = NULL; - returnLabel = NULL; - scout = NULL; - fensure = NULL; - fbody = NULL; - localsymtab = NULL; - vthis = NULL; - v_arguments = NULL; -#if IN_GCC - v_argptr = NULL; -#endif - v_argsave = NULL; - parameters = NULL; - labtab = NULL; - overnext = NULL; - vtblIndex = -1; - hasReturnExp = 0; - naked = 0; - inlineStatusExp = ILSuninitialized; - inlineStatusStmt = ILSuninitialized; - inlineNest = 0; - inlineAsm = 0; - isArrayOp = 0; - semanticRun = PASSinit; - semantic3Errors = 0; -#if DMDV1 - nestedFrameRef = 0; -#endif - fes = NULL; - introducing = 0; - tintro = NULL; - /* The type given for "infer the return type" is a TypeFunction with - * NULL for the return type. - */ - inferRetType = (type && type->nextOf() == NULL); - hasReturnExp = 0; - nrvo_can = 1; - nrvo_var = NULL; -#if IN_DMD - shidden = NULL; -#endif - -#if DMDV2 - builtin = BUILTINunknown; - tookAddressOf = 0; - flags = 0; -#endif - -#if IN_LLVM - // LDC - isArrayOp = false; - allowInlining = false; - - availableExternally = true; // assume this unless proven otherwise - - // function types in ldc don't merge if the context parameter differs - // so we actually don't care about the function declaration, but only - // what kind of context parameter it has. - // however, this constructor is usually called from the parser, which - // unfortunately doesn't provide the information needed to get to the - // aggregate type. So we have to stick with the FuncDeclaration and - // just be sure we don't actually rely on the symbol it points to, - // but rather just the type of its context parameter. - // this means some function might have a function type pointing to - // another function declaration - - if (type) - { - assert(type->ty == Tfunction && "invalid function type"); - TypeFunction* tf = (TypeFunction*)type; - if (tf->funcdecl == NULL) - tf->funcdecl = this; - } -#endif -} - -Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) -{ - FuncDeclaration *f; - - //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncDeclaration *)s; - else - f = new FuncDeclaration(loc, endloc, ident, storage_class, type->syntaxCopy()); - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - -#if IN_LLVM - f->intrinsicName = intrinsicName; -#endif - - return f; -} - - -// Do the semantic analysis on the external interface to the function. - -void FuncDeclaration::semantic(Scope *sc) -{ TypeFunction *f; - AggregateDeclaration *ad; - StructDeclaration *sd; - ClassDeclaration *cd; - InterfaceDeclaration *id; - Dsymbol *pd; - -#if 0 - printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); - if (isFuncLiteralDeclaration()) - printf("\tFuncLiteralDeclaration()\n"); - printf("sc->parent = %s, parent = %s\n", sc->parent->toChars(), parent ? parent->toChars() : ""); - printf("type: %p, %s\n", type, type->toChars()); -#endif - - if (semanticRun != PASSinit && isFuncLiteralDeclaration()) - { - /* Member functions that have return types that are - * forward references can have semantic() run more than - * once on them. - * See test\interface2.d, test20 - */ - return; - } - parent = sc->parent; - Dsymbol *parent = toParent(); - - if (semanticRun >= PASSsemanticdone) - { - if (!parent->isClassDeclaration()) - return; - // need to re-run semantic() in order to set the class's vtbl[] - } - else - { - assert(semanticRun <= PASSsemantic); - semanticRun = PASSsemantic; - } - - unsigned dprogress_save = Module::dprogress; - - foverrides.setDim(0); // reset in case semantic() is being retried for this function - - if (!originalType) - originalType = type; - if (!type->deco) - { - type = type->semantic(loc, sc); - } - //type->print(); - if (type->ty != Tfunction) - { - error("%s must be a function", toChars()); - return; - } - f = (TypeFunction *)(type); - size_t nparams = Parameter::dim(f->parameters); - - linkage = sc->linkage; - protection = sc->protection; - - storage_class |= sc->stc; - ad = isThis(); - if (ad) - storage_class |= ad->storage_class & (STC_TYPECTOR | STCsynchronized); - //printf("function storage_class = x%x\n", storage_class); - - if (ident == Id::ctor && !isCtorDeclaration()) - error("_ctor is reserved for constructors"); - - if (isConst() || isAuto() || isScope()) - error("functions cannot be const or auto"); - - if (isAbstract() && !isVirtual()) - error("non-virtual functions cannot be abstract"); - - // https://github.com/donc/dmd/commit/9f7b2f8cfe5d7482f2de7f9678c176d54abe237f#commitcomment-321724 - //if (isOverride() && !isVirtual()) - //error("cannot override a non-virtual function"); - - if (isAbstract() && isFinal()) - error("cannot be both final and abstract"); -#if 0 - if (isAbstract() && fbody) - error("abstract functions cannot have bodies"); -#endif - -#if 0 - if (isStaticConstructor() || isStaticDestructor()) - { - if (!isStatic() || type->nextOf()->ty != Tvoid) - error("static constructors / destructors must be static void"); - if (f->arguments && f->arguments->dim) - error("static constructors / destructors must have empty parameter list"); - // BUG: check for invalid storage classes - } -#endif - -#ifdef IN_GCC - { - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - if (ad) - ad->methods.push(this); - } -#endif - sd = parent->isStructDeclaration(); - if (sd) - { - // Verify no constructors, destructors, etc. - if (isCtorDeclaration() || - isDtorDeclaration() - //|| isInvariantDeclaration() - //|| isUnitTestDeclaration() - ) - { - error("special member functions not allowed for %ss", sd->kind()); - } - -#if 0 - if (!sd->inv) - sd->inv = isInvariantDeclaration(); - - if (!sd->aggNew) - sd->aggNew = isNewDeclaration(); - - if (isDelete()) - { - if (sd->aggDelete) - error("multiple delete's for struct %s", sd->toChars()); - sd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - } - - id = parent->isInterfaceDeclaration(); - if (id) - { - storage_class |= STCabstract; - - if (isCtorDeclaration() || -#if DMDV2 - isPostBlitDeclaration() || -#endif - isDtorDeclaration() || - isInvariantDeclaration() || - isUnitTestDeclaration() || isNewDeclaration() || isDelete()) - error("special function not allowed in interface %s", id->toChars()); - if (fbody && isVirtual()) - error("function body is not abstract in interface %s", id->toChars()); - } - - /* Template member functions aren't virtual: - * interface TestInterface { void tpl(T)(); } - * and so won't work in interfaces - */ - if ((pd = toParent()) != NULL && - pd->isTemplateInstance() && - (pd = toParent2()) != NULL && - (id = pd->isInterfaceDeclaration()) != NULL) - { - error("template member functions are not allowed in interface %s", id->toChars()); - } - - cd = parent->isClassDeclaration(); - if (cd) - { int vi; - CtorDeclaration *ctor; - DtorDeclaration *dtor; - InvariantDeclaration *inv; - - if (isCtorDeclaration()) - { -// ctor = (CtorDeclaration *)this; -// if (!cd->ctor) -// cd->ctor = ctor; - goto Ldone; - } - -#if 0 - dtor = isDtorDeclaration(); - if (dtor) - { - if (cd->dtor) - error("multiple destructors for class %s", cd->toChars()); - cd->dtor = dtor; - } - - inv = isInvariantDeclaration(); - if (inv) - { - cd->inv = inv; - } - - if (isNewDeclaration()) - { - if (!cd->aggNew) - cd->aggNew = (NewDeclaration *)(this); - } - - if (isDelete()) - { - if (cd->aggDelete) - error("multiple delete's for class %s", cd->toChars()); - cd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - - if (storage_class & STCabstract) - cd->isabstract = 1; - - // if static function, do not put in vtbl[] - if (!isVirtual()) - { - //printf("\tnot virtual\n"); - goto Ldone; - } - // Suppress further errors if the return type is an error - if (type->nextOf() == Type::terror) - goto Ldone; - - /* Find index of existing function in base class's vtbl[] to override - * (the index will be the same as in cd's current vtbl[]) - */ - vi = cd->baseClass ? findVtblIndex(&cd->baseClass->vtbl, cd->baseClass->vtbl.dim) - : -1; - - switch (vi) - { - case -1: - /* Didn't find one, so - * This is an 'introducing' function which gets a new - * slot in the vtbl[]. - */ - - // Verify this doesn't override previous final function - if (cd->baseClass) - { Dsymbol *s = cd->baseClass->search(loc, ident, 0); - if (s) - { - FuncDeclaration *f = s->isFuncDeclaration(); - f = f->overloadExactMatch(type, getModule()); - if (f && f->isFinal() && f->prot() != PROTprivate) - error("cannot override final function %s", f->toPrettyChars()); - } - } - - if (isFinal()) - { - if (isOverride()) - error("does not override any function"); - cd->vtblFinal.push(this); - } - else - { - // Append to end of vtbl[] - //printf("\tintroducing function\n"); - introducing = 1; - vi = cd->vtbl.dim; - cd->vtbl.push(this); - vtblIndex = vi; - } - break; - - case -2: // can't determine because of fwd refs - cd->sizeok = SIZEOKfwd; // can't finish due to forward reference - Module::dprogress = dprogress_save; - return; - - default: - { FuncDeclaration *fdv = (FuncDeclaration *)cd->baseClass->vtbl[vi]; - // This function is covariant with fdv - if (fdv->isFinal()) - error("cannot override final function %s", fdv->toPrettyChars()); - -#if DMDV2 - if (!isOverride()) - warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); -#endif - - FuncDeclaration *fdc = ((Dsymbol *)cd->vtbl.data[vi])->isFuncDeclaration(); - if (fdc->toParent() == parent) - { - // If both are mixins, then error. - // If either is not, the one that is not overrides the other. - - // if (this is mixin) && (fdc is not mixin) then fdc overrides - if (!this->parent->isClassDeclaration() && fdc->parent->isClassDeclaration()) - break; - - if (!this->parent->isClassDeclaration() // if both are mixins then error -#if DMDV2 - && !isPostBlitDeclaration() -#endif - ) - error("multiple overrides of same function"); - } - cd->vtbl[vi] = this; - vtblIndex = vi; - - /* Remember which functions this overrides - */ - foverrides.push(fdv); - - /* This works by whenever this function is called, - * it actually returns tintro, which gets dynamically - * cast to type. But we know that tintro is a base - * of type, so we could optimize it by not doing a - * dynamic cast, but just subtracting the isBaseOf() - * offset if the value is != null. - */ - - if (fdv->tintro) - tintro = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) - { - tintro = fdv->type; - } - } - break; - } - } - - /* Go through all the interface bases. - * If this function is covariant with any members of those interface - * functions, set the tintro. - */ - for (int i = 0; i < cd->interfaces_dim; i++) - { - BaseClass *b = cd->interfaces[i]; - vi = findVtblIndex((Dsymbols *)&b->base->vtbl, b->base->vtbl.dim); - switch (vi) - { - case -1: - break; - - case -2: - cd->sizeok = SIZEOKfwd; // can't finish due to forward reference - Module::dprogress = dprogress_save; - return; - - default: - { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.tdata()[vi]; - Type *ti = NULL; - - /* Remember which functions this overrides - */ - foverrides.push(fdv); - -#if DMDV2 - /* Should we really require 'override' when implementing - * an interface function? - */ - //if (!isOverride()) - //warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); -#endif - - if (fdv->tintro) - ti = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - unsigned errors = global.startGagging(); // suppress printing of error messages - int offset; - int baseOf = fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset); - if (global.endGagging(errors)) - { - // any error in isBaseOf() is a forward reference error, so we bail out - cd->sizeok = SIZEOKfwd; // can't finish due to forward reference - Module::dprogress = dprogress_save; - return; - } - if (baseOf) - { - ti = fdv->type; - } - } - if (ti) - { - if (tintro) - { - if (!tintro->nextOf()->equals(ti->nextOf()) && - !tintro->nextOf()->isBaseOf(ti->nextOf(), NULL) && - !ti->nextOf()->isBaseOf(tintro->nextOf(), NULL)) - { - error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); - } - } - tintro = ti; - } - goto L2; - } - } - } - - if (introducing && isOverride()) - { - error("does not override any function"); - } - - L2: ; - } - else if (isOverride() && !parent->isTemplateInstance()) - error("override only applies to class member functions"); - - /* Do not allow template instances to add virtual functions - * to a class. - */ - if (isVirtual()) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - ClassDeclaration *cd = ti->tempdecl->isClassMember(); - if (cd) - { - error("cannot use template to add virtual function to class '%s'", cd->toChars()); - } - } - } - - if (isMain()) - { - // Check parameters to see if they are either () or (char[][] args) - switch (nparams) - { - case 0: - break; - - case 1: - { - Parameter *arg0 = Parameter::getNth(f->parameters, 0); - if (arg0->type->ty != Tarray || - arg0->type->nextOf()->ty != Tarray || - arg0->type->nextOf()->nextOf()->ty != Tchar || - arg0->storageClass & (STCout | STCref | STClazy)) - goto Lmainerr; - break; - } - - default: - goto Lmainerr; - } - - if (!f->nextOf()) - error("must return int or void"); - else if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) - error("must return int or void, not %s", f->nextOf()->toChars()); - if (f->varargs) - { - Lmainerr: - error("parameters must be main() or main(string[] args)"); - } - } - - if (ident == Id::assign && (sd || cd)) - { // Disallow identity assignment operator. - - // opAssign(...) - if (nparams == 0) - { if (f->varargs == 1) - goto Lassignerr; - } - else - { - Parameter *arg0 = Parameter::getNth(f->parameters, 0); - Type *t0 = arg0->type->toBasetype(); - Type *tb = sd ? sd->type : cd->type; - if (arg0->type->implicitConvTo(tb) || - (sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb)) - ) - { - if (nparams == 1) - goto Lassignerr; - Parameter *arg1 = Parameter::getNth(f->parameters, 1); - if (arg1->defaultArg) - goto Lassignerr; - } - } - } - - if (isVirtual() && semanticRun != PASSsemanticdone) - { - /* Rewrite contracts as nested functions, then call them. - * Doing it as nested functions means that overriding functions - * can call them. - */ - if (frequire) - { /* in { ... } - * becomes: - * void __require() { ... } - * __require(); - */ - Loc loc = frequire->loc; - TypeFunction *tf = new TypeFunction(NULL, Type::tvoid, 0, LINKd); - FuncDeclaration *fd = new FuncDeclaration(loc, loc, - Id::require, STCundefined, tf); - fd->fbody = frequire; - Statement *s1 = new ExpStatement(loc, fd); - Expression *e = new CallExp(loc, new VarExp(loc, fd), (Expressions *)NULL); - Statement *s2 = new ExpStatement(loc, e); - frequire = new CompoundStatement(loc, s1, s2); - fdrequire = fd; - } - - if (!outId && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid) - outId = Id::result; // provide a default - - if (fensure) - { /* out (result) { ... } - * becomes: - * tret __ensure(ref tret result) { ... } - * __ensure(result); - */ - Loc loc = fensure->loc; - Parameters *arguments = new Parameters(); - Parameter *a = NULL; - if (outId) - { a = new Parameter(STCref, f->nextOf(), outId, NULL); - arguments->push(a); - } - TypeFunction *tf = new TypeFunction(arguments, Type::tvoid, 0, LINKd); - FuncDeclaration *fd = new FuncDeclaration(loc, loc, - Id::ensure, STCundefined, tf); - fd->fbody = fensure; - Statement *s1 = new ExpStatement(loc, fd); - Expression *eresult = NULL; - if (outId) - eresult = new IdentifierExp(loc, outId); - Expression *e = new CallExp(loc, new VarExp(loc, fd), eresult); - Statement *s2 = new ExpStatement(loc, e); - fensure = new CompoundStatement(loc, s1, s2); - fdensure = fd; - } - } - -Ldone: - Module::dprogress++; - //LDC relies on semanticRun variable not being reset here - if(semanticRun < PASSsemanticdone) - semanticRun = PASSsemanticdone; - - /* Save scope for possible later use (if we need the - * function internals) - */ - scope = new Scope(*sc); - scope->setNoFree(); - return; - -Lassignerr: - error("identity assignment operator overload is illegal"); -} - -void FuncDeclaration::semantic2(Scope *sc) -{ -} - -// Do the semantic analysis on the internals of the function. - -void FuncDeclaration::semantic3(Scope *sc) -{ TypeFunction *f; - VarDeclaration *argptr = NULL; - VarDeclaration *_arguments = NULL; - int nerrors = global.errors; - - if (!parent) - { - if (global.errors) - return; - //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); - assert(0); - } - //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); - //fflush(stdout); - //printf("storage class = x%x %x\n", sc->stc, storage_class); - //{ static int x; if (++x == 2) *(char*)0=0; } - //printf("\tlinkage = %d\n", sc->linkage); - - //printf(" sc->incontract = %d\n", sc->incontract); - if (semanticRun >= PASSsemantic3) - return; - semanticRun = PASSsemantic3; - semantic3Errors = 0; - -#if IN_LLVM - if (!global.params.useAvailableExternally) - availableExternally = false; -#endif - if (!type || type->ty != Tfunction) - return; - f = (TypeFunction *)(type); - - // Check the 'throws' clause - if (fthrows) - { - for (int i = 0; i < fthrows->dim; i++) - { - Type *t = (Type *)fthrows->data[i]; - - t = t->semantic(loc, sc); - if (!t->isClassHandle()) - error("can only throw classes, not %s", t->toChars()); - } - } - - if (!fbody && inferRetType && !type->nextOf()) - { - error("has no function body with return type inference"); - return; - } - - if (frequire) - { - for (int i = 0; i < foverrides.dim; i++) - { - FuncDeclaration *fdv = (FuncDeclaration *)foverrides.data[i]; - - if (fdv->fbody && !fdv->frequire) - { - error("cannot have an in contract when overriden function %s does not have an in contract", fdv->toPrettyChars()); - break; - } - } - } - - frequire = mergeFrequire(frequire); - fensure = mergeFensure(fensure); - - if (fbody || frequire) - { - /* Symbol table into which we place parameters and nested functions, - * solely to diagnose name collisions. - */ - localsymtab = new DsymbolTable(); - - // Establish function scope - ScopeDsymbol *ss = new ScopeDsymbol(); - ss->parent = sc->scopesym; - Scope *sc2 = sc->push(ss); - sc2->func = this; - sc2->parent = this; - sc2->callSuper = 0; - sc2->sbreak = NULL; - sc2->scontinue = NULL; - sc2->sw = NULL; - sc2->fes = fes; - sc2->linkage = LINKd; - sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | - STCdeprecated | STCoverride | - STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref | - STCproperty | STCsafe | STCtrusted | STCsystem); - sc2->protection = PROTpublic; - sc2->explicitProtection = 0; - sc2->structalign = STRUCTALIGN_DEFAULT; - sc2->incontract = 0; - sc2->enclosingFinally = NULL; - sc2->enclosingScopeExit = NULL; - sc2->noctor = 0; - - // Declare 'this' - AggregateDeclaration *ad = isThis(); - if (ad) - { VarDeclaration *v; - - if (isFuncLiteralDeclaration() && isNested() && !sc->intypeof) - { - error("function literals cannot be class members"); - return; - } - else - { - assert(!isNested() || sc->intypeof); // can't be both member and nested - assert(ad->handle); - v = new ThisDeclaration(loc, ad->handle); - v->storage_class |= STCparameter | STCin; - v->semantic(sc2); - if (!sc2->insert(v)) - assert(0); - v->parent = this; - vthis = v; - } - } - else if (isNested()) - { - /* The 'this' for a nested function is the link to the - * enclosing function's stack frame. - * Note that nested functions and member functions are disjoint. - */ - VarDeclaration *v = new ThisDeclaration(loc, Type::tvoid->pointerTo()); - v->storage_class |= STCparameter | STCin; - v->semantic(sc2); - if (!sc2->insert(v)) - assert(0); - v->parent = this; - vthis = v; - } - - // Declare hidden variable _arguments[] and _argptr - if (f->varargs == 1) - { -#if TARGET_NET - varArgs(sc2, f, argptr, _arguments); -#else - Type *t; - -#if !IN_LLVM - if (global.params.is64bit) - { // Declare save area for varargs registers - Type *t = new TypeIdentifier(loc, Id::va_argsave_t); - t = t->semantic(loc, sc); - if (t == Type::terror) - { - error("must import std.c.stdarg to use variadic functions"); - return; - } - else - { - v_argsave = new VarDeclaration(loc, t, Id::va_argsave, NULL); - v_argsave->semantic(sc2); - sc2->insert(v_argsave); - v_argsave->parent = this; - } - } -#endif - - if (f->linkage == LINKd) - { // Declare _arguments[] - v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); - v_arguments->storage_class = STCparameter | STCin; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; - - t = Type::typeinfo->type->arrayOf(); - _arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - _arguments->semantic(sc2); - sc2->insert(_arguments); - _arguments->parent = this; - } - if (f->linkage == LINKd || (f->parameters && Parameter::dim(f->parameters))) - { // Declare _argptr -#if IN_GCC - t = d_gcc_builtin_va_list_d_type; -#else - t = Type::tvoid->pointerTo(); -#endif - argptr = new VarDeclaration(0, t, Id::_argptr, NULL); - argptr->semantic(sc2); - sc2->insert(argptr); - argptr->parent = this; - } -#endif - } - -#if IN_LLVM - // LDC make sure argument type is semanticed. - // Turns TypeTuple!(int, int) into two int parameters, for instance. - if (f->parameters) - { - for (size_t i = 0; i < Parameter::dim(f->parameters); i++) - { Parameter *arg = (Parameter *)Parameter::getNth(f->parameters, i); - Type* nw = arg->type->semantic(0, sc); - if (arg->type != nw) { - arg->type = nw; - // Examine this index again. - // This is important if it turned into a tuple. - // In particular, the empty tuple should be handled or the - // next parameter will be skipped. - // FIXME: Maybe we only need to do this for tuples, - // and can add tuple.length after decrement? - i--; - } - } - } -#endif - -#if 0 - // Propagate storage class from tuple parameters to their element-parameters. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Parameter *arg = (Parameter *)f->parameters->data[i]; - - //printf("[%d] arg->type->ty = %d %s\n", i, arg->type->ty, arg->type->toChars()); - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Parameter::dim(t->arguments); - for (size_t j = 0; j < dim; j++) - { Parameter *narg = Parameter::getNth(t->arguments, j); - narg->storageClass = arg->storageClass; - } - } - } - } -#endif - - /* Declare all the function parameters as variables - * and install them in parameters[] - */ - size_t nparams = Parameter::dim(f->parameters); - if (nparams) - { /* parameters[] has all the tuples removed, as the back end - * doesn't know about tuples - */ - parameters = new VarDeclarations(); - parameters->reserve(nparams); - for (size_t i = 0; i < nparams; i++) - { - Parameter *arg = Parameter::getNth(f->parameters, i); - Identifier *id = arg->ident; - if (!id) - { - /* Generate identifier for un-named parameter, - * because we need it later on. - */ - arg->ident = id = Identifier::generateId("_param_", i); - } - Type *vtype = arg->type; - VarDeclaration *v = new VarDeclaration(loc, vtype, id, NULL); - //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); - v->storage_class |= STCparameter; - if (f->varargs == 2 && i + 1 == nparams) - v->storage_class |= STCvariadic; - v->storage_class |= arg->storageClass & (STCin | STCout | STCref | STClazy); - if (v->storage_class & STClazy) - v->storage_class |= STCin; - v->semantic(sc2); - if (!sc2->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - else - parameters->push(v); - localsymtab->insert(v); - v->parent = this; - } - } - - // Declare the tuple symbols and put them in the symbol table, - // but not in parameters[]. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Parameter *arg = (*f->parameters)[i]; - - if (!arg->ident) - continue; // never used, so ignore - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Parameter::dim(t->arguments); - Objects *exps = new Objects(); - exps->setDim(dim); - for (size_t j = 0; j < dim; j++) - { Parameter *narg = Parameter::getNth(t->arguments, j); - assert(narg->ident); - VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); - assert(v); - Expression *e = new VarExp(v->loc, v); - (*exps)[j] = e; - } - assert(arg->ident); - TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); - //printf("declaring tuple %s\n", v->toChars()); - v->isexp = 1; - if (!sc2->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - localsymtab->insert(v); - v->parent = this; - } - } - } - - // Precondition invariant - Statement *fpreinv = NULL; - if (addPreInvariant()) - { - Expression *e = NULL; - if (isDtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - Expression *v = new ThisExp(0); - v->type = vthis->type; -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - Expression *se = new StringExp(0, (char *)"null this"); - se = se->semantic(sc); - se->type = Type::tchar->arrayOf(); - e = new AssertExp(loc, v, se); - } - if (e) - fpreinv = new ExpStatement(0, e); - } - - // Postcondition invariant - Statement *fpostinv = NULL; - if (addPostInvariant()) - { - Expression *e = NULL; - if (isCtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - Expression *v = new ThisExp(0); - v->type = vthis->type; -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - e = new AssertExp(0, v); - } - if (e) - fpostinv = new ExpStatement(0, e); - } - - if (fensure || addPostInvariant()) - { - if ((fensure && global.params.useOut) || fpostinv) - { returnLabel = new LabelDsymbol(Id::returnLabel); - } - - // scope of out contract (need for vresult->semantic) - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc2->scopesym; - scout = sc2->push(sym); - } - - if (fbody) - { - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc2->scopesym; - sc2 = sc2->push(sym); - - ClassDeclaration *cd = isClassMember(); - - /* If this is a class constructor - */ - if (isCtorDeclaration() && cd) - { - for (int i = 0; i < cd->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - - v->ctorinit = 0; - } - } - - if (inferRetType || f->retStyle() != RETstack) - nrvo_can = 0; - - fbody = fbody->semantic(sc2); - - if (inferRetType) - { // If no return type inferred yet, then infer a void - if (!type->nextOf()) - { - ((TypeFunction *)type)->next = Type::tvoid; - type = type->semantic(loc, sc); - } - f = (TypeFunction *)type; - } - - int offend = fbody ? fbody->blockExit(FALSE) & BEfallthru : TRUE; - - if (isStaticCtorDeclaration()) - { /* It's a static constructor. Ensure that all - * ctor consts were initialized. - */ - - Dsymbol *p = toParent(); - ScopeDsymbol *ad = p->isScopeDsymbol(); - if (!ad) - { - error("static constructor can only be member of struct/class/module, not %s %s", p->kind(), p->toChars()); - } - else - { - for (size_t i = 0; i < ad->members->dim; i++) - { Dsymbol *s = (Dsymbol *)ad->members->data[i]; - - s->checkCtorConstInit(); - } - } - } - - if (isCtorDeclaration() && cd) - { - //printf("callSuper = x%x\n", sc2->callSuper); - - // Verify that all the ctorinit fields got initialized - if (!(sc2->callSuper & CSXthis_ctor)) - { - for (size_t i = 0; i < cd->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - - if (v->ctorinit == 0 && v->isCtorinit()) - error("missing initializer for const field %s", v->toChars()); - } - } - - if (!(sc2->callSuper & CSXany_ctor) && - cd->baseClass && cd->baseClass->ctor) - { - sc2->callSuper = 0; - - // Insert implicit super() at start of fbody - Expression *e1 = new SuperExp(0); - Expression *e = new CallExp(0, e1); - - e = e->trySemantic(sc2); - if (!e) - error("no match for implicit super() call in constructor"); - else - { - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, s, fbody); - } - } - } - else if (fes) - { // For foreach(){} body, append a return 0; - Expression *e = new IntegerExp(0); - Statement *s = new ReturnStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - assert(!returnLabel); - } - else if (!hasReturnExp && type->nextOf()->ty != Tvoid) - error("expected to return a value of type %s", type->nextOf()->toChars()); - else if (!inlineAsm) - { -#if DMDV2 - int blockexit = fbody ? fbody->blockExit() : BEfallthru; - if (f->isnothrow && blockexit & BEthrow) - error("'%s' is nothrow yet may throw", toChars()); - - int offend = blockexit & BEfallthru; -#endif - if (type->nextOf()->ty != Tvoid) - { - if (offend) - { Expression *e; -#if DMDV1 - warning(loc, "no return exp; or assert(0); at end of function"); -#else - error("no return exp; or assert(0); at end of function"); -#endif - if (global.params.useAssert && - !global.params.useInline) - { /* Add an assert(0, msg); where the missing return - * should be. - */ - e = new AssertExp( - endloc, - new IntegerExp(0), - new StringExp(loc, (char *)"missing return expression") - ); - } - else - e = new HaltExp(endloc); - e = new CommaExp(0, e, type->nextOf()->defaultInit()); - e = e->semantic(sc2); - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - } - } - } - - sc2 = sc2->pop(); - } - - Statement *freq = frequire; - Statement *fens = fensure; - - /* Do the semantic analysis on the [in] preconditions and - * [out] postconditions. - */ - if (freq) - { /* frequire is composed of the [in] contracts - */ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc2->scopesym; - sc2 = sc2->push(sym); - sc2->incontract++; - - // BUG: need to error if accessing out parameters - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - // BUG: verify that all in and ref parameters are read - DsymbolTable *labtab_save = labtab; - labtab = NULL; // so in contract can't refer to out/body labels - freq = freq->semantic(sc2); - labtab = labtab_save; - - sc2->incontract--; - sc2 = sc2->pop(); - - if (!global.params.useIn) - freq = NULL; - } - - if (fens) - { /* fensure is composed of the [out] contracts - */ - if (type->nextOf()->ty == Tvoid && outId) - { - error("void functions have no result"); - } - - if (type->nextOf()->ty != Tvoid) - buildResultVar(); - - sc2 = scout; //push - sc2->incontract++; - - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - DsymbolTable *labtab_save = labtab; - labtab = NULL; // so out contract can't refer to in/body labels - fens = fens->semantic(sc2); - labtab = labtab_save; - - sc2->incontract--; - sc2 = sc2->pop(); - - if (!global.params.useOut) - fens = NULL; - } - - { - Statements *a = new Statements(); - - // Merge in initialization of 'out' parameters - if (parameters) - { for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - if (v->storage_class & STCout) - { - assert(v->init); - ExpInitializer *ie = v->init->isExpInitializer(); - assert(ie); - ie->exp->op = TOKassign; // construction occurred in parameter processing - a->push(new ExpStatement(0, ie->exp)); - } - } - } - -// we'll handle variadics ourselves -#if !IN_LLVM - if (argptr) - { // Initialize _argptr to point past non-variadic arg -#if IN_GCC - // Handled in FuncDeclaration::toObjFile - v_argptr = argptr; - v_argptr->init = new VoidInitializer(loc); -#else - Type *t = argptr->type; - if (global.params.is64bit) - { // Initialize _argptr to point to v_argsave - Expression *e1 = new VarExp(0, argptr); - Expression *e = new SymOffExp(0, v_argsave, 6*8 + 8*16); - e->type = argptr->type; - e = new AssignExp(0, e1, e); - e = e->semantic(sc); - a->push(new ExpStatement(0, e)); - } - else - { // Initialize _argptr to point past non-variadic arg - VarDeclaration *p; - unsigned offset = 0; - - Expression *e1 = new VarExp(0, argptr); - // Find the last non-ref parameter - if (parameters && parameters->dim) - { - int lastNonref = parameters->dim -1; - p = (VarDeclaration *)parameters->data[lastNonref]; - /* The trouble with out and ref parameters is that taking - * the address of it doesn't work, because later processing - * adds in an extra level of indirection. So we skip over them. - */ - while (p->storage_class & (STCout | STCref)) - { - --lastNonref; - offset += PTRSIZE; - if (lastNonref < 0) - { - p = v_arguments; - break; - } - p = (VarDeclaration *)parameters->data[lastNonref]; - } - } - else - p = v_arguments; // last parameter is _arguments[] - if (p->storage_class & STClazy) - // If the last parameter is lazy, it's the size of a delegate - offset += PTRSIZE * 2; - else - offset += p->type->size(); - offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1); // assume stack aligns on pointer size - Expression *e = new SymOffExp(0, p, offset); - e->type = Type::tvoidptr; - //e = e->semantic(sc); - e = new AssignExp(0, e1, e); - e->type = t; - a->push(new ExpStatement(0, e)); - } -#endif - } - - if (_arguments) - { - /* Advance to elements[] member of TypeInfo_Tuple with: - * _arguments = v_arguments.elements; - */ - Expression *e = new VarExp(0, v_arguments); - e = new DotIdExp(0, e, Id::elements); - Expression *e1 = new VarExp(0, _arguments); - e = new AssignExp(0, e1, e); - e->op = TOKconstruct; - e = e->semantic(sc2); - a->push(new ExpStatement(0, e)); - } - -#endif // !IN_LLVM - - // Merge contracts together with body into one compound statement - - if (freq || fpreinv) - { - if (!freq) - freq = fpreinv; - else if (fpreinv) - freq = new CompoundStatement(0, freq, fpreinv); - - freq->incontract = 1; - a->push(freq); - } - - if (fbody) - a->push(fbody); - - if (fens || fpostinv) - { - if (!fens) - fens = fpostinv; - else if (fpostinv) - fens = new CompoundStatement(0, fpostinv, fens); - - LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fens); - returnLabel->statement = ls; - a->push(returnLabel->statement); - - if (type->nextOf()->ty != Tvoid && vresult) - { - // Create: return vresult; - Expression *e = new VarExp(0, vresult); - if (tintro) - { e = e->implicitCastTo(sc, tintro->nextOf()); - e = e->semantic(sc); - } - ReturnStatement *s = new ReturnStatement(0, e); - a->push(s); - } - } - if (isMain() && type->nextOf()->ty == Tvoid) - { // Add a return 0; statement - Statement *s = new ReturnStatement(0, new IntegerExp(0)); - a->push(s); - } - - fbody = new CompoundStatement(0, a); -#if DMDV2 - /* Append destructor calls for parameters as finally blocks. - */ - if (parameters) - { for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = (*parameters)[i]; - - if (v->storage_class & (STCref | STCout)) - continue; - - /* Don't do this for static arrays, since static - * arrays are called by reference. Remove this - * when we change them to call by value. - */ - if (v->type->toBasetype()->ty == Tsarray) - continue; - - Expression *e = v->callScopeDtor(sc); - if (e) - { Statement *s = new ExpStatement(0, e); - s = s->semantic(sc); - if (fbody->blockExit() == BEfallthru) - fbody = new CompoundStatement(0, fbody, s); - else - fbody = new TryFinallyStatement(0, fbody, s); - } - } - } -#endif - - // wrap body of synchronized functions in a synchronized statement - if (isSynchronized()) - { - AggregateDeclaration *ad = isThis(); - ClassDeclaration *cd = ad ? ad->isClassDeclaration() : parent->isClassDeclaration(); - - Expression *sync; - if (isStatic()) - { - // static member functions synchronize on classinfo - sync = cd->type->dotExp(sc2, new TypeExp(loc, cd->type), Id::classinfo); - } - else - { - // non-static member functions synchronize on this - sync = new VarExp(loc, vthis); - } - - // we do not want to rerun semantics on the whole function, so we - // manually adjust all labels in the function that currently don't - // have an enclosingScopeExit to use the new SynchronizedStatement - Statement* nbody = new PeelStatement(fbody); - nbody = new SynchronizedStatement(loc, sync, nbody); - nbody = nbody->semantic(sc2); - - // LDC - LabelMap::iterator it, end = labmap.end(); - for (it = labmap.begin(); it != end; ++it) - if (it->second->enclosingScopeExit == NULL) - it->second->enclosingScopeExit = nbody; - - fbody = nbody; - } - } - - sc2->callSuper = 0; - sc2->pop(); - } - - if (global.gag && global.errors != nerrors) - semanticRun = PASSsemanticdone; // Ensure errors get reported again - else - { - semanticRun = PASSsemantic3done; - semantic3Errors = global.errors - nerrors; - } - //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); - //fflush(stdout); -} - -void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("FuncDeclaration::toCBuffer() '%s'\n", toChars()); - - type->toCBuffer(buf, ident, hgs); - bodyToCBuffer(buf, hgs); -} - - -void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (fbody && - (!hgs->hdrgen || hgs->tpltMember || canInline(1,1,1)) - ) - { buf->writenl(); - - // in{} - if (frequire) - { buf->writestring("in"); - buf->writenl(); - frequire->toCBuffer(buf, hgs); - } - - // out{} - if (fensure) - { buf->writestring("out"); - if (outId) - { buf->writebyte('('); - buf->writestring(outId->toChars()); - buf->writebyte(')'); - } - buf->writenl(); - fensure->toCBuffer(buf, hgs); - } - - if (frequire || fensure) - { buf->writestring("body"); - buf->writenl(); - } - - buf->writebyte('{'); - buf->writenl(); - fbody->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); - } - else - { buf->writeByte(';'); - buf->writenl(); - } -} - -/**************************************************** - * Declare result variable lazily. - */ - -void FuncDeclaration::buildResultVar() -{ - if (vresult) - return; - - assert(type->nextOf()); - assert(type->nextOf()->toBasetype()->ty != Tvoid); - TypeFunction *tf = (TypeFunction *)(type); - - Loc loc = this->loc; - - if (fensure) - loc = fensure->loc; - - if (!outId) - outId = Id::result; // provide a default - - VarDeclaration *v = new VarDeclaration(loc, type->nextOf(), outId, NULL); - v->noscope = 1; - v->storage_class |= STCresult; -#if DMDV2 - if (!isVirtual()) - v->storage_class |= STCconst; - if (tf->isref) - { - v->storage_class |= STCref | STCforeach; - } -#endif - v->semantic(scout); - if (!scout->insert(v)) - error("out result %s is already defined", v->toChars()); - v->parent = this; - vresult = v; - - // vresult gets initialized with the function return value - // in ReturnStatement::semantic() -} - -/**************************************************** - * Merge into this function the 'in' contracts of all it overrides. - * 'in's are OR'd together, i.e. only one of them needs to pass. - */ - -Statement *FuncDeclaration::mergeFrequire(Statement *sf) -{ - /* Implementing this is done by having the overriding function call - * nested functions (the fdrequire functions) nested inside the overridden - * function. This requires that the stack layout of the calling function's - * parameters and 'this' pointer be in the same place (as the nested - * function refers to them). - * This is easy for the parameters, as they are all on the stack in the same - * place by definition, since it's an overriding function. The problem is - * getting the 'this' pointer in the same place, since it is a local variable. - * We did some hacks in the code generator to make this happen: - * 1. always generate exception handler frame, or at least leave space for it - * in the frame (Windows 32 SEH only) - * 2. always generate an EBP style frame - * 3. since 'this' is passed in a register that is subsequently copied into - * a stack local, allocate that local immediately following the exception - * handler block, so it is always at the same offset from EBP. - */ - for (int i = 0; i < foverrides.dim; i++) - { - FuncDeclaration *fdv = foverrides[i]; - - /* The semantic pass on the contracts of the overridden functions must - * be completed before code generation occurs (bug 3602). - */ - if (fdv->fdrequire && fdv->fdrequire->semanticRun != PASSsemantic3done) - { - assert(fdv->scope); - Scope *sc = fdv->scope->push(); - sc->stc &= ~STCoverride; - fdv->semantic3(sc); - sc->pop(); - } - - sf = fdv->mergeFrequire(sf); - if (sf && fdv->fdrequire) - { - //printf("fdv->frequire: %s\n", fdv->frequire->toChars()); - /* Make the call: - * try { __require(); } - * catch { frequire; } - */ - Expression *eresult = NULL; - Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire), eresult); - Statement *s2 = new ExpStatement(loc, e); - - Catch *c = new Catch(loc, NULL, NULL, sf); - Catches *catches = new Catches(); - catches->push(c); - sf = new TryCatchStatement(loc, s2, catches); - } - else - return NULL; - } - return sf; -} - -/**************************************************** - * Merge into this function the 'out' contracts of all it overrides. - * 'out's are AND'd together, i.e. all of them need to pass. - */ - -Statement *FuncDeclaration::mergeFensure(Statement *sf) -{ - /* Same comments as for mergeFrequire(), except that we take care - * of generating a consistent reference to the 'result' local by - * explicitly passing 'result' to the nested function as a reference - * argument. - * This won't work for the 'this' parameter as it would require changing - * the semantic code for the nested function so that it looks on the parameter - * list for the 'this' pointer, something that would need an unknown amount - * of tweaking of various parts of the compiler that I'd rather leave alone. - */ - for (int i = 0; i < foverrides.dim; i++) - { - FuncDeclaration *fdv = foverrides[i]; - - /* The semantic pass on the contracts of the overridden functions must - * be completed before code generation occurs (bug 3602 and 5230). - */ - if (fdv->fdensure && fdv->fdensure->semanticRun != PASSsemantic3done) - { - assert(fdv->scope); - Scope *sc = fdv->scope->push(); - sc->stc &= ~STCoverride; - fdv->semantic3(sc); - sc->pop(); - } - - sf = fdv->mergeFensure(sf); - if (fdv->fdensure) - { - //printf("fdv->fensure: %s\n", fdv->fensure->toChars()); - // Make the call: __ensure(result) - Expression *eresult = NULL; - if (outId) - eresult = new IdentifierExp(loc, outId); - Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure), eresult); - Statement *s2 = new ExpStatement(loc, e); - - if (sf) - { - sf = new CompoundStatement(fensure->loc, s2, sf); - } - else - sf = s2; - } - } - return sf; -} - -/**************************************************** - * Determine if 'this' overrides fd. - * Return !=0 if it does. - */ - -int FuncDeclaration::overrides(FuncDeclaration *fd) -{ int result = 0; - - if (fd->ident == ident) - { - int cov = type->covariant(fd->type); - if (cov) - { ClassDeclaration *cd1 = toParent()->isClassDeclaration(); - ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration(); - - if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL)) - result = 1; - } - } - return result; -} - -/************************************************* - * Find index of function in vtbl[0..dim] that - * this function overrides. - * Prefer an exact match to a covariant one. - * Returns: - * -1 didn't find one - * -2 can't determine because of forward references - */ - -int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) -{ - FuncDeclaration *mismatch = NULL; - int exactvi = -1; - int bestvi = -1; - for (int vi = 0; vi < dim; vi++) - { - FuncDeclaration *fdv = (*vtbl)[vi]->isFuncDeclaration(); - if (fdv && fdv->ident == ident) - { - if (type->equals(fdv->type)) // if exact match - { - if (fdv->parent->isClassDeclaration()) - return vi; // no need to look further - - if (exactvi >= 0) - { - error("cannot determine overridden function"); - return exactvi; - } - exactvi = vi; - - bestvi = vi; - continue; - } - - int cov = type->covariant(fdv->type); - //printf("\tbaseclass cov = %d\n", cov); - switch (cov) - { - case 0: // types are distinct - break; - - case 1: - bestvi = vi; // covariant, but not identical - break; // keep looking for an exact match - - case 2: - mismatch = fdv; // overrides, but is not covariant - break; // keep looking for an exact match - - case 3: - return -2; // forward references - - default: - assert(0); - } - } - } - if (bestvi == -1 && mismatch) - { - //type->print(); - //mismatch->type->print(); - //printf("%s %s\n", type->deco, mismatch->type->deco); - error("of type %s overrides but is not covariant with %s of type %s", - type->toChars(), mismatch->toPrettyChars(), mismatch->type->toChars()); - } - return bestvi; -} - -/**************************************************** - * Overload this FuncDeclaration with the new one f. - * Return !=0 if successful; i.e. no conflict. - */ - -int FuncDeclaration::overloadInsert(Dsymbol *s) -{ - FuncDeclaration *f; - AliasDeclaration *a; - - //printf("FuncDeclaration::overloadInsert(%s)\n", s->toChars()); - a = s->isAliasDeclaration(); - if (a) - { - if (overnext) - return overnext->overloadInsert(a); - if (!a->aliassym && a->type->ty != Tident && a->type->ty != Tinstance) - { - //printf("\ta = '%s'\n", a->type->toChars()); - return FALSE; - } - overnext = a; - //printf("\ttrue: no conflict\n"); - return TRUE; - } - f = s->isFuncDeclaration(); - if (!f) - return FALSE; - - if (type && f->type && // can be NULL for overloaded constructors - f->type->covariant(type) && - !isFuncAliasDeclaration()) - { - //printf("\tfalse: conflict %s\n", kind()); - return FALSE; - } - - if (overnext) - return overnext->overloadInsert(f); - overnext = f; - //printf("\ttrue: no conflict\n"); - return TRUE; -} - -/******************************************** - * Find function in overload list that exactly matches t. - */ - -/*************************************************** - * Visit each overloaded function in turn, and call - * (*fp)(param, f) on it. - * Exit when no more, or (*fp)(param, f) returns 1. - * Returns: - * 0 continue - * 1 done - */ - -int overloadApply(Module* from, FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param) -{ - FuncDeclaration *f; - Declaration *d; - Declaration *next; - - for (d = fstart; d; d = next) - { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); - - if (fa) - { - if (fa->getModule() == from || fa->importprot != PROTprivate) - if (overloadApply(from, fa->funcalias, fp, param)) - return 1; - next = fa->overnext; - } - else - { - AliasDeclaration *a = d->isAliasDeclaration(); - - if (a) - { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - if (next == fstart) - break; - if (a->importprot == PROTprivate && a->getModule() != from) - if (FuncDeclaration* fd = next->isFuncDeclaration()) - next = fd->overnext; - } - else - { - f = d->isFuncDeclaration(); - if (!f) - { d->error("is aliased to a function"); - break; // BUG: should print error message? - } - if ((*fp)(param, f)) - return 1; - - next = f->overnext; - } - } - } - return 0; -} - -/******************************************** - * If there are no overloads of function f, return that function, - * otherwise return NULL. - */ - -static int fpunique(void *param, FuncDeclaration *f) -{ FuncDeclaration **pf = (FuncDeclaration **)param; - - if (*pf) - { *pf = NULL; - return 1; // ambiguous, done - } - else - { *pf = f; - return 0; - } -} - -FuncDeclaration *FuncDeclaration::isUnique() -{ FuncDeclaration *result = NULL; - - overloadApply(getModule(), this, &fpunique, &result); - return result; -} - -/******************************************** - * Find function in overload list that exactly matches t. - */ - -struct Param1 -{ - Type *t; // type to match - FuncDeclaration *f; // return value -}; - -int fp1(void *param, FuncDeclaration *f) -{ Param1 *p = (Param1 *)param; - Type *t = p->t; - - if (t->equals(f->type)) - { p->f = f; - return 1; - } - -#if DMDV2 - /* Allow covariant matches, if it's just a const conversion - * of the return type - */ - if (t->ty == Tfunction) - { TypeFunction *tf = (TypeFunction *)f->type; - if (tf->covariant(t) == 1 && - tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst) - { - p->f = f; - return 1; - } - } -#endif - return 0; -} - -FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t, Module* from) -{ - Param1 p; - p.t = t; - p.f = NULL; - overloadApply(from, this, &fp1, &p); - return p.f; -} - - -/******************************************** - * Decide which function matches the arguments best. - */ - -struct Param2 -{ - Match *m; -#if DMDV2 - Expression *ethis; -#endif - Expressions *arguments; -}; - -int fp2(void *param, FuncDeclaration *f) -{ Param2 *p = (Param2 *)param; - Match *m = p->m; - Expressions *arguments = p->arguments; - MATCH match; - - if (f != m->lastf) // skip duplicates - { - m->anyf = f; - TypeFunction *tf = (TypeFunction *)f->type; - match = (MATCH) tf->callMatch(arguments); - //printf("1match = %d\n", match); - if (match != MATCHnomatch) - { - if (match > m->last) - goto LfIsBetter; - - if (match < m->last) - goto LlastIsBetter; - - /* See if one of the matches overrides the other. - */ - if (m->lastf->overrides(f)) - goto LlastIsBetter; - else if (f->overrides(m->lastf)) - goto LfIsBetter; - -#if DMDV2 - /* Try to disambiguate using template-style partial ordering rules. - * In essence, if f() and g() are ambiguous, if f() can call g(), - * but g() cannot call f(), then pick f(). - * This is because f() is "more specialized." - */ - { - MATCH c1 = f->leastAsSpecialized(m->lastf); - MATCH c2 = m->lastf->leastAsSpecialized(f); - //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) - goto LfIsBetter; - if (c1 < c2) - goto LlastIsBetter; - } -#endif - Lambiguous: - m->nextf = f; - m->count++; - return 0; - - LfIsBetter: - m->last = match; - m->lastf = f; - m->count = 1; - return 0; - - LlastIsBetter: - return 0; - } - } - return 0; -} - - -void overloadResolveX(Match *m, FuncDeclaration *fstart, - Expression *ethis, Expressions *arguments, Module *from) -{ - Param2 p; - p.m = m; - p.arguments = arguments; - overloadApply(from, fstart, &fp2, &p); -} - - -FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, Module *from, int flags) -{ - TypeFunction *tf; - Match m; - -#if 0 -printf("FuncDeclaration::overloadResolve('%s')\n", toChars()); -if (arguments) -{ int i; - - for (i = 0; i < arguments->dim; i++) - { Expression *arg; - - arg = (Expression *)arguments->data[i]; - assert(arg->type); - printf("\t%s: ", arg->toChars()); - arg->type->print(); - } -} -#endif - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - overloadResolveX(&m, this, NULL, arguments, from); - - if (m.count == 1) // exactly one match - { - return m.lastf; - } - else - { - OutBuffer buf; - - if (arguments) - { - HdrGenState hgs; - - argExpTypesToCBuffer(&buf, arguments, &hgs); - } - - if (m.last == MATCHnomatch) - { - tf = (TypeFunction *)type; - - //printf("tf = %s, args = %s\n", tf->deco, ((Expression *)arguments->data[0])->type->deco); - error(loc, "%s does not match parameter types (%s)", - Parameter::argsTypesToChars(tf->parameters, tf->varargs), - buf.toChars()); - return m.anyf; // as long as it's not a FuncAliasDeclaration - } - else - { -#if 1 - TypeFunction *t1 = (TypeFunction *)m.lastf->type; - TypeFunction *t2 = (TypeFunction *)m.nextf->type; - - error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s", - buf.toChars(), - m.lastf->toPrettyChars(), Parameter::argsTypesToChars(t1->parameters, t1->varargs), - m.nextf->toPrettyChars(), Parameter::argsTypesToChars(t2->parameters, t2->varargs)); -#else - error(loc, "overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); -#endif - return m.lastf; - } - } -} - -/************************************* - * Determine partial specialization order of 'this' vs g. - * This is very similar to TemplateDeclaration::leastAsSpecialized(). - * Returns: - * match 'this' is at least as specialized as g - * 0 g is more specialized than 'this' - */ - -#if DMDV2 -MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) -{ -#define LOG_LEASTAS 0 - -#if LOG_LEASTAS - printf("%s.leastAsSpecialized(%s)\n", toChars(), g->toChars()); -#endif - - /* This works by calling g() with f()'s parameters, and - * if that is possible, then f() is at least as specialized - * as g() is. - */ - - TypeFunction *tf = (TypeFunction *)type; - TypeFunction *tg = (TypeFunction *)g->type; - size_t nfparams = Parameter::dim(tf->parameters); - size_t ngparams = Parameter::dim(tg->parameters); - MATCH match = MATCHexact; - - /* If both functions have a 'this' pointer, and the mods are not - * the same and g's is not const, then this is less specialized. - */ - if (needThis() && g->needThis()) - { - if (tf->mod != tg->mod) - { - if (tg->mod == MODconst) - match = MATCHconst; - else - return MATCHnomatch; - } - } - - /* Create a dummy array of arguments out of the parameters to f() - */ - Expressions args; - args.setDim(nfparams); - for (int u = 0; u < nfparams; u++) - { - Parameter *p = Parameter::getNth(tf->parameters, u); - Expression *e; - if (p->storageClass & (STCref | STCout)) - { - e = new IdentifierExp(0, p->ident); - e->type = p->type; - } - else - e = p->type->defaultInit(); - args.data[u] = e; - } - - MATCH m = (MATCH) tg->callMatch(NULL, &args); - if (m) - { - /* A variadic parameter list is less specialized than a - * non-variadic one. - */ - if (tf->varargs && !tg->varargs) - goto L1; // less specialized - -#if LOG_LEASTAS - printf(" matches %d, so is least as specialized\n", m); -#endif - return m; - } - L1: -#if LOG_LEASTAS - printf(" doesn't match, so is not as specialized\n"); -#endif - return MATCHnomatch; -} - -/******************************************* - * Given a symbol that could be either a FuncDeclaration or - * a function template, resolve it to a function symbol. - * sc instantiation scope - * loc instantiation location - * targsi initial list of template arguments - * ethis if !NULL, the 'this' pointer argument - * fargs arguments to function - * flags 1: do not issue error message on no match, just return NULL - */ - -FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, - Objects *tiargs, - Expression *ethis, - Expressions *arguments, - int flags) -{ - if (!s) - return NULL; // no match - FuncDeclaration *f = s->isFuncDeclaration(); - if (f) - f = f->overloadResolve(loc, ethis, arguments); - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - assert(td); - f = td->deduceFunctionTemplate(sc, loc, tiargs, NULL, arguments, flags); - } - return f; -} -#endif - -/******************************** - * Labels are in a separate scope, one per function. - */ - -LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident) -{ Dsymbol *s; - - if (!labtab) - labtab = new DsymbolTable(); // guess we need one - - s = labtab->lookup(ident); - if (!s) - { - s = new LabelDsymbol(ident); - labtab->insert(s); - } - return (LabelDsymbol *)s; -} - -/**************************************** - * If non-static member function that has a 'this' pointer, - * return the aggregate it is a member of. - * Otherwise, return NULL. - */ - -AggregateDeclaration *FuncDeclaration::isThis() -{ AggregateDeclaration *ad; - - //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); - ad = NULL; - if ((storage_class & STCstatic) == 0) - { - ad = isMember2(); - } - //printf("-FuncDeclaration::isThis() %p\n", ad); - return ad; -} - -AggregateDeclaration *FuncDeclaration::isMember2() -{ AggregateDeclaration *ad; - - //printf("+FuncDeclaration::isMember2() '%s'\n", toChars()); - ad = NULL; - for (Dsymbol *s = this; s; s = s->parent) - { -//printf("\ts = '%s', parent = '%s', kind = %s\n", s->toChars(), s->parent->toChars(), s->parent->kind()); - ad = s->isMember(); - if (ad) -{ //printf("test4\n"); - break; -} - if (!s->parent || - (!s->parent->isTemplateInstance())) -{ //printf("test5\n"); - break; -} - } - //printf("-FuncDeclaration::isMember2() %p\n", ad); - return ad; -} - -/***************************************** - * Determine lexical level difference from 'this' to nested function 'fd'. - * Error if this cannot call fd. - * Returns: - * 0 same level - * -1 increase nesting by 1 (fd is nested within 'this') - * >0 decrease nesting by number - */ - -int FuncDeclaration::getLevel(Loc loc, FuncDeclaration *fd) -{ int level; - Dsymbol *s; - Dsymbol *fdparent; - - //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars()); - fdparent = fd->toParent2(); - if (fdparent == this) - return -1; - s = this; - level = 0; - while (fd != s && fdparent != s->toParent2()) - { - //printf("\ts = '%s'\n", s->toChars()); - FuncDeclaration *thisfd = s->isFuncDeclaration(); - if (thisfd) - { if (!thisfd->isNested() && !thisfd->vthis) - goto Lerr; - } - else - { - ClassDeclaration *thiscd = s->isClassDeclaration(); - if (thiscd) - { if (!thiscd->isNested()) - goto Lerr; - } - else - goto Lerr; - } - - s = s->toParent2(); - assert(s); - level++; - } - return level; - -Lerr: - error(loc, "cannot access frame of function %s", fd->toChars()); - return 1; -} - -void FuncDeclaration::appendExp(Expression *e) -{ Statement *s; - - s = new ExpStatement(0, e); - appendState(s); -} - -void FuncDeclaration::appendState(Statement *s) -{ - if (!fbody) - { Statements *a; - - a = new Statements(); - fbody = new CompoundStatement(0, a); - } - CompoundStatement *cs = fbody->isCompoundStatement(); - cs->statements->push(s); -} - -const char *FuncDeclaration::toPrettyChars() -{ - if (isMain()) - return "D main"; - else - return Dsymbol::toPrettyChars(); -} - -int FuncDeclaration::isMain() -{ - return ident == Id::main && - linkage != LINKc && !isMember() && !isNested(); -} - -int FuncDeclaration::isWinMain() -{ - //printf("FuncDeclaration::isWinMain() %s\n", toChars()); -#if 0 - int x = ident == Id::WinMain && - linkage != LINKc && !isMember(); - printf("%s\n", x ? "yes" : "no"); - return x; -#else - return ident == Id::WinMain && - linkage != LINKc && !isMember(); -#endif -} - -int FuncDeclaration::isDllMain() -{ - return ident == Id::DllMain && - linkage != LINKc && !isMember(); -} - -int FuncDeclaration::isExport() -{ - return protection == PROTexport; -} - -int FuncDeclaration::isImportedSymbol() -{ - //printf("isImportedSymbol()\n"); - //printf("protection = %d\n", protection); - return (protection == PROTexport) && !fbody; -} - -// Determine if function goes into virtual function pointer table - -int FuncDeclaration::isVirtual() -{ -#if 0 - printf("FuncDeclaration::isVirtual(%s)\n", toChars()); - printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); - printf("result is %d\n", - isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration()); -#endif - return isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration(); -} - -// Determine if a function is pedantically virtual - -int FuncDeclaration::isVirtualMethod() -{ - //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars()); - if (!isVirtual()) - return 0; - // If it's a final method, and does not override anything, then it is not virtual - if (isFinal() && foverrides.dim == 0) - { - return 0; - } - return 1; -} - -int FuncDeclaration::isFinal() -{ - ClassDeclaration *cd; -#if 0 - printf("FuncDeclaration::isFinal(%s)\n", toChars()); - printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); - printf("result is %d\n", - isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - (cd = toParent()->isClassDeclaration()) != NULL && - cd->storage_class & STCfinal); -#endif - return isMember() && - (Declaration::isFinal() || - ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); -} - -int FuncDeclaration::isAbstract() -{ - return storage_class & STCabstract; -} - -int FuncDeclaration::isCodeseg() -{ - return TRUE; // functions are always in the code segment -} - -int FuncDeclaration::hasOverloads() -{ - return overnext != NULL; -} -// Determine if function needs -// a static frame pointer to its lexically enclosing function - -int FuncDeclaration::isNested() -{ - //if (!toParent()) - //printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent); - //printf("\ttoParent2() = '%s'\n", toParent2()->toChars()); - return ((storage_class & STCstatic) == 0) && toParent2() && - (toParent2()->isFuncDeclaration() != NULL); -} - -int FuncDeclaration::needThis() -{ - //printf("FuncDeclaration::needThis() '%s'\n", toChars()); - int i = isThis() != NULL; - //printf("\t%d\n", i); - if (!i && isFuncAliasDeclaration()) - i = ((FuncAliasDeclaration *)this)->funcalias->needThis(); - return i; -} - -int FuncDeclaration::addPreInvariant() -{ - AggregateDeclaration *ad = isThis(); - return (ad && - //ad->isClassDeclaration() && - global.params.useInvariants && - (protection == PROTpublic || protection == PROTexport) && - !naked); -} - -int FuncDeclaration::addPostInvariant() -{ - AggregateDeclaration *ad = isThis(); - return (ad && - ad->inv && - //ad->isClassDeclaration() && - global.params.useInvariants && - (protection == PROTpublic || protection == PROTexport) && - !naked); -} - -/********************************** - * Generate a FuncDeclaration for a runtime library function. - */ - -// -// LDC: Adjusted to give argument info to the runtime function decl. -// - -FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, const char *name) -{ - return genCfunc(args, treturn, Lexer::idPool(name)); -} - -FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, Identifier *id) -{ - FuncDeclaration *fd; - TypeFunction *tf; - Dsymbol *s; - static DsymbolTable *st = NULL; - - //printf("genCfunc(name = '%s')\n", id->toChars()); - //printf("treturn\n\t"); treturn->print(); - - // See if already in table - if (!st) - st = new DsymbolTable(); - s = st->lookup(id); - if (s) - { - fd = s->isFuncDeclaration(); - assert(fd); - assert(fd->type->nextOf()->equals(treturn)); - } - else - { - tf = new TypeFunction(args, treturn, 0, LINKc); - fd = new FuncDeclaration(0, 0, id, STCstatic, tf); - fd->protection = PROTpublic; - fd->linkage = LINKc; - - st->insert(fd); - } - return fd; -} - -const char *FuncDeclaration::kind() -{ - return "function"; -} - -/******************************* - * Look at all the variables in this function that are referenced - * by nested functions, and determine if a closure needs to be - * created for them. - */ - -#if DMDV2 -int FuncDeclaration::needsClosure() -{ - /* Need a closure for all the closureVars[] if any of the - * closureVars[] are accessed by a - * function that escapes the scope of this function. - * We take the conservative approach and decide that any function that: - * 1) is a virtual function - * 2) has its address taken - * 3) has a parent that escapes - * - * Note that since a non-virtual function can be called by - * a virtual one, if that non-virtual function accesses a closure - * var, the closure still has to be taken. Hence, we check for isThis() - * instead of isVirtual(). (thanks to David Friedman) - */ - - //printf("FuncDeclaration::needsClosure() %s\n", toChars()); - for (int i = 0; i < closureVars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)closureVars.data[i]; - assert(v->isVarDeclaration()); - //printf("\tv = %s\n", v->toChars()); - - for (int j = 0; j < v->nestedrefs.dim; j++) - { FuncDeclaration *f = (FuncDeclaration *)v->nestedrefs.data[j]; - assert(f != this); - - //printf("\t\tf = %s, %d, %p, %d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf); - if (f->isThis() || f->tookAddressOf) - goto Lyes; // assume f escapes this function's scope - - // Look to see if any parents of f that are below this escape - for (Dsymbol *s = f->parent; s && s != this; s = s->parent) - { - f = s->isFuncDeclaration(); - if (f && (f->isThis() || f->tookAddressOf)) - goto Lyes; - } - } - } - return 0; - -Lyes: - //printf("\tneeds closure\n"); - return 1; -} -#endif - -/*********************************************** - * Determine if function's variables are referenced by a function - * nested within it. - */ - -int FuncDeclaration::hasNestedFrameRefs() -{ -#if DMDV2 - if (closureVars.dim) -#else - if (nestedFrameRef) -#endif - return 1; - - /* If a virtual method has contracts, assume its variables are referenced - * by those contracts, even if they aren't. Because they might be referenced - * by the overridden or overriding function's contracts. - * This can happen because frequire and fensure are implemented as nested functions, - * and they can be called directly by an overriding function and the overriding function's - * context had better match, or Bugzilla 7337 will bite. - */ - if ((fdrequire || fdensure) && isVirtualMethod()) - return 1; - - if (foverrides.dim && isVirtualMethod()) - { - for (size_t i = 0; i < foverrides.dim; i++) - { - FuncDeclaration *fdv = foverrides.tdata()[i]; - if (fdv->hasNestedFrameRefs()) - return 1; - } - } - - return 0; -} - -/********************************************* - * Return the function's parameter list, and whether - * it is variadic or not. - */ - -Parameters *FuncDeclaration::getParameters(int *pvarargs) -{ Parameters *fparameters; - int fvarargs; - - if (type) - { - assert(type->ty == Tfunction); - TypeFunction *fdtype = (TypeFunction *)type; - fparameters = fdtype->parameters; - fvarargs = fdtype->varargs; - } - else // Constructors don't have type's - { CtorDeclaration *fctor = isCtorDeclaration(); - assert(fctor); - fparameters = fctor->arguments; - fvarargs = fctor->varargs; - } - if (pvarargs) - *pvarargs = fvarargs; - return fparameters; -} - - -/****************************** FuncAliasDeclaration ************************/ - -// Used as a way to import a set of functions from another scope into this one. - -FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) - : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, - (enum STC)funcalias->storage_class, funcalias->type) -{ - assert(funcalias != this); - this->funcalias = funcalias; - importprot = PROTundefined; -} - -const char *FuncAliasDeclaration::kind() -{ - return "function alias"; -} - - -/****************************** FuncLiteralDeclaration ************************/ - -FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, - enum TOK tok, ForeachStatement *fes) - : FuncDeclaration(loc, endloc, NULL, STCundefined, type) -{ - const char *id; - - if (fes) - id = "__foreachbody"; - else if (tok == TOKdelegate) - id = "__dgliteral"; - else - id = "__funcliteral"; - this->ident = Lexer::uniqueId(id); - this->tok = tok; - this->fes = fes; - //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); -} - -Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) -{ - FuncLiteralDeclaration *f; - - //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncLiteralDeclaration *)s; - else - { f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); - f->ident = ident; // keep old identifier - } - FuncDeclaration::syntaxCopy(f); - return f; -} - -int FuncLiteralDeclaration::isNested() -{ - //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); - return (tok == TOKdelegate); -} - -int FuncLiteralDeclaration::isVirtual() -{ - return FALSE; -} - -const char *FuncLiteralDeclaration::kind() -{ - // GCC requires the (char*) casts - return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; -} - -void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(kind()); - buf->writeByte(' '); - type->toCBuffer(buf, NULL, hgs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* CtorDeclaration ****************************/ - -CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::ctor, STCundefined, NULL) -{ - this->arguments = arguments; - this->varargs = varargs; - //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); -} - -Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) -{ - CtorDeclaration *f; - - f = new CtorDeclaration(loc, endloc, NULL, varargs); - - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - - f->arguments = Parameter::arraySyntaxCopy(arguments); - return f; -} - - -void CtorDeclaration::semantic(Scope *sc) -{ - //printf("CtorDeclaration::semantic() %s\n", toChars()); - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static constructor - - parent = sc->parent; - Dsymbol *parent = toParent(); - Type *tret; - ClassDeclaration *cd = parent->isClassDeclaration(); - if (!cd) - { - error("constructors are only for class definitions"); - fatal(); - tret = Type::tvoid; - } - else - tret = cd->type; //->referenceTo(); - if (!type) - type = new TypeFunction(arguments, tret, varargs, LINKd); -#if STRUCTTHISREF - if (ad && ad->isStructDeclaration()) - ((TypeFunction *)type)->isref = 1; -#endif - if (!originalType) - originalType = type; - - sc->flags |= SCOPEctor; - type = type->semantic(loc, sc); - sc->flags &= ~SCOPEctor; - - // Append: - // return this; - // to the function body - if (fbody && semanticRun < PASSsemantic) - { - Expression *e = new ThisExp(loc); - Statement *s = new ReturnStatement(loc, e); - fbody = new CompoundStatement(loc, fbody, s); - } - - FuncDeclaration::semantic(sc); - - sc->pop(); - - // See if it's the default constructor - if (cd && varargs == 0 && Parameter::dim(arguments) == 0) - cd->defaultCtor = this; -} - -const char *CtorDeclaration::kind() -{ - return "constructor"; -} - -char *CtorDeclaration::toChars() -{ - return (char *)"this"; -} - -int CtorDeclaration::isVirtual() -{ - return FALSE; -} - -int CtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int CtorDeclaration::addPostInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - - -void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this"); - Parameter::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - -/********************************* PostBlitDeclaration ****************************/ - -#if DMDV2 -PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::_postblit, STCundefined, NULL) -{ -} - -PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id) - : FuncDeclaration(loc, endloc, id, STCundefined, NULL) -{ -} - -Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, ident); - return FuncDeclaration::syntaxCopy(dd); -} - - -void PostBlitDeclaration::semantic(Scope *sc) -{ - //printf("PostBlitDeclaration::semantic() %s\n", toChars()); - //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); - //printf("stc = x%llx\n", sc->stc); - parent = sc->parent; - Dsymbol *parent = toParent(); - StructDeclaration *ad = parent->isStructDeclaration(); - if (!ad) - { - error("post blits are only for struct/union definitions, not %s %s", parent->kind(), parent->toChars()); - } - else if (ident == Id::_postblit && semanticRun < PASSsemantic) - ad->postblits.push(this); - - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not static - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int PostBlitDeclaration::overloadInsert(Dsymbol *s) -{ - return FALSE; // cannot overload postblits -} - -int PostBlitDeclaration::addPreInvariant() -{ - return FALSE; -} - -int PostBlitDeclaration::addPostInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - -int PostBlitDeclaration::isVirtual() -{ - return FALSE; -} - -void PostBlitDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this(this)"); - bodyToCBuffer(buf, hgs); -} -#endif - -/********************************* DtorDeclaration ****************************/ - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) -{ -} - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, Identifier *id) - : FuncDeclaration(loc, endloc, id, STCundefined, NULL) -{ -} - -Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - DtorDeclaration *dd = new DtorDeclaration(loc, endloc, ident); - return FuncDeclaration::syntaxCopy(dd); -} - - -void DtorDeclaration::semantic(Scope *sc) -{ - //printf("DtorDeclaration::semantic() %s\n", toChars()); - //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); - parent = sc->parent; - Dsymbol *parent = toParent(); - ClassDeclaration *cd = parent->isClassDeclaration(); - if (!cd) - { - error("destructors are only for class/struct/union definitions, not %s %s", parent->kind(), parent->toChars()); - fatal(); - } - else if (semanticRun < PASSsemantic) - cd->dtors.push(this); - - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static destructor - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int DtorDeclaration::overloadInsert(Dsymbol *s) -{ - return FALSE; // cannot overload destructors -} - -int DtorDeclaration::addPreInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - -int DtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -const char *DtorDeclaration::kind() -{ - return "destructor"; -} - -char *DtorDeclaration::toChars() -{ - return (char *)"~this"; -} - -int DtorDeclaration::isVirtual() -{ - // FALSE so that dtor's don't get put into the vtbl[] - return FALSE; -} - -void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticCtorDeclaration ****************************/ - -StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticCtor"), STCstatic, NULL) -{ -} - -Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - StaticCtorDeclaration *scd = new StaticCtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(scd); -} - - -void StaticCtorDeclaration::semantic(Scope *sc) -{ - //printf("StaticCtorDeclaration::semantic()\n"); - - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - /* If the static ctor appears within a template instantiation, - * it could get called multiple times by the module constructors - * for different modules. Thus, protect it with a gate. - */ - if (inTemplateInstance() && semanticRun < PASSsemantic) - { - /* Add this prefix to the function: - * static int gate; - * if (++gate != 1) return; - * Note that this is not thread safe; should not have threads - * during static construction. - */ - Identifier *id = Lexer::idPool("__gate"); - VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); - v->storage_class = STCstatic; - Statements *sa = new Statements(); - Statement *s = new ExpStatement(0, v); - sa->push(s); - Expression *e = new IdentifierExp(0, id); - e = new AddAssignExp(0, e, new IntegerExp(1)); - e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(1)); - s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); - sa->push(s); - if (fbody) - sa->push(fbody); - fbody = new CompoundStatement(0, sa); - } - - FuncDeclaration::semantic(sc); - - // We're going to need ModuleInfo - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { m->needmoduleinfo = 1; - //printf("module1 %s needs moduleinfo\n", m->toChars()); -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif - } -} - -AggregateDeclaration *StaticCtorDeclaration::isThis() -{ - return NULL; -} - -int StaticCtorDeclaration::isStaticConstructor() -{ - return TRUE; -} - -int StaticCtorDeclaration::isVirtual() -{ - return FALSE; -} - -bool StaticCtorDeclaration::hasStaticCtorOrDtor() -{ - return TRUE; -} - -int StaticCtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int StaticCtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen && !hgs->tpltMember) - { buf->writestring("static this();"); - buf->writenl(); - return; - } - buf->writestring("static this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticDtorDeclaration ****************************/ - -StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticDtor"), STCstatic, NULL) -{ - vgate = NULL; -} - -Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticDtorDeclaration *sdd; - - assert(!s); - sdd = new StaticDtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(sdd); -} - - -void StaticDtorDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd = sc->scopesym->isClassDeclaration(); - - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - /* If the static ctor appears within a template instantiation, - * it could get called multiple times by the module constructors - * for different modules. Thus, protect it with a gate. - */ - if (inTemplateInstance() && semanticRun < PASSsemantic) - { - /* Add this prefix to the function: - * static int gate; - * if (--gate != 0) return; - * Increment gate during constructor execution. - * Note that this is not thread safe; should not have threads - * during static destruction. - */ - Identifier *id = Lexer::idPool("__gate"); - VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); - v->storage_class = STCstatic; - Statements *sa = new Statements(); - Statement *s = new ExpStatement(0, v); - sa->push(s); - Expression *e = new IdentifierExp(0, id); - e = new AddAssignExp(0, e, new IntegerExp((uint64_t)-1)); - e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(0)); - s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); - sa->push(s); - if (fbody) - sa->push(fbody); - fbody = new CompoundStatement(0, sa); - vgate = v; - } - - FuncDeclaration::semantic(sc); - - // We're going to need ModuleInfo - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { m->needmoduleinfo = 1; - //printf("module2 %s needs moduleinfo\n", m->toChars()); -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif - } -} - -AggregateDeclaration *StaticDtorDeclaration::isThis() -{ - return NULL; -} - -int StaticDtorDeclaration::isStaticDestructor() -{ - return TRUE; -} - -int StaticDtorDeclaration::isVirtual() -{ - return FALSE; -} - -bool StaticDtorDeclaration::hasStaticCtorOrDtor() -{ - return TRUE; -} - -int StaticDtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int StaticDtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("static ~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* InvariantDeclaration ****************************/ - -InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL) -{ -} - -Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) -{ - InvariantDeclaration *id; - - assert(!s); - id = new InvariantDeclaration(loc, endloc); - FuncDeclaration::syntaxCopy(id); - return id; -} - - -void InvariantDeclaration::semantic(Scope *sc) -{ - parent = sc->parent; - Dsymbol *parent = toParent(); - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - if (!ad) - { - error("invariants are only for struct/union/class definitions"); - return; - } - else if (ad->inv && ad->inv != this && semanticRun < PASSsemantic) - { - error("more than one invariant for %s", ad->toChars()); - } - ad->inv = this; - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static invariant - sc->incontract++; - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int InvariantDeclaration::isVirtual() -{ - return FALSE; -} - -int InvariantDeclaration::addPreInvariant() -{ - return FALSE; -} - -int InvariantDeclaration::addPostInvariant() -{ - return FALSE; -} - -void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("invariant"); - bodyToCBuffer(buf, hgs); -} - - -/********************************* UnitTestDeclaration ****************************/ - -/******************************* - * Generate unique unittest function Id so we can have multiple - * instances per module. - */ - -static Identifier *unitTestId() -{ - return Lexer::uniqueId("__unittest"); -} - -UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL) -{ -} - -Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) -{ - UnitTestDeclaration *utd; - - assert(!s); - utd = new UnitTestDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(utd); -} - - -void UnitTestDeclaration::semantic(Scope *sc) -{ -#if IN_LLVM - if (global.params.useUnitTests && sc->module->isRoot) -#else - if (global.params.useUnitTests) -#endif - { - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - Scope *sc2 = sc->push(); - sc2->linkage = LINKd; - FuncDeclaration::semantic(sc2); - sc2->pop(); - } - -#if 0 - // We're going to need ModuleInfo even if the unit tests are not - // compiled in, because other modules may import this module and refer - // to this ModuleInfo. - // (This doesn't make sense to me?) - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { - //printf("module3 %s needs moduleinfo\n", m->toChars()); - m->needmoduleinfo = 1; - } -#endif -} - -AggregateDeclaration *UnitTestDeclaration::isThis() -{ - return NULL; -} - -int UnitTestDeclaration::isVirtual() -{ - return FALSE; -} - -int UnitTestDeclaration::addPreInvariant() -{ - return FALSE; -} - -int UnitTestDeclaration::addPostInvariant() -{ - return FALSE; -} - -void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("unittest"); - bodyToCBuffer(buf, hgs); -} - -/********************************* NewDeclaration ****************************/ - -NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) -{ - this->arguments = arguments; - this->varargs = varargs; -} - -Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) -{ - NewDeclaration *f; - - f = new NewDeclaration(loc, endloc, NULL, varargs); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Parameter::arraySyntaxCopy(arguments); - - return f; -} - - -void NewDeclaration::semantic(Scope *sc) -{ - //printf("NewDeclaration::semantic()\n"); - - parent = sc->parent; - Dsymbol *parent = toParent(); - ClassDeclaration *cd = parent->isClassDeclaration(); - if (!cd && !parent->isStructDeclaration()) - { - error("new allocators only are for class or struct definitions"); - } - Type *tret = Type::tvoid->pointerTo(); - if (!type) - type = new TypeFunction(arguments, tret, varargs, LINKd); - - type = type->semantic(loc, sc); - assert(type->ty == Tfunction); - - // Check that there is at least one argument of type size_t - TypeFunction *tf = (TypeFunction *)type; - if (Parameter::dim(tf->parameters) < 1) - { - error("at least one argument of type size_t expected"); - } - else - { - Parameter *a = Parameter::getNth(tf->parameters, 0); - if (!a->type->equals(Type::tsize_t)) - error("first argument must be type size_t, not %s", a->type->toChars()); - } - - FuncDeclaration::semantic(sc); -} - -const char *NewDeclaration::kind() -{ - return "allocator"; -} - -int NewDeclaration::isVirtual() -{ - return FALSE; -} - -int NewDeclaration::addPreInvariant() -{ - return FALSE; -} - -int NewDeclaration::addPostInvariant() -{ - return FALSE; -} - -void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("new"); - Parameter::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* DeleteDeclaration ****************************/ - -DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Parameters *arguments) - : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) -{ - this->arguments = arguments; -} - -Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) -{ - DeleteDeclaration *f; - - f = new DeleteDeclaration(loc, endloc, NULL); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Parameter::arraySyntaxCopy(arguments); - - return f; -} - - -void DeleteDeclaration::semantic(Scope *sc) -{ - //printf("DeleteDeclaration::semantic()\n"); - - parent = sc->parent; - Dsymbol *parent = toParent(); - ClassDeclaration *cd = parent->isClassDeclaration(); - if (!cd && !parent->isStructDeclaration()) - { - error("new allocators only are for class or struct definitions"); - } - if (!type) - type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); - - type = type->semantic(loc, sc); - assert(type->ty == Tfunction); - - // Check that there is only one argument of type void* - TypeFunction *tf = (TypeFunction *)type; - if (Parameter::dim(tf->parameters) != 1) - { - error("one argument of type void* expected"); - } - else - { - Parameter *a = Parameter::getNth(tf->parameters, 0); - if (!a->type->equals(Type::tvoid->pointerTo())) - error("one argument of type void* expected, not %s", a->type->toChars()); - } - - FuncDeclaration::semantic(sc); -} - -const char *DeleteDeclaration::kind() -{ - return "deallocator"; -} - -int DeleteDeclaration::isDelete() -{ - return TRUE; -} - -int DeleteDeclaration::isVirtual() -{ - return FALSE; -} - -int DeleteDeclaration::addPreInvariant() -{ - return FALSE; -} - -int DeleteDeclaration::addPostInvariant() -{ - return FALSE; -} - -void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("delete"); - Parameter::argsToCBuffer(buf, hgs, arguments, 0); - bodyToCBuffer(buf, hgs); -} - - - - diff --git a/dmd/gpl.txt b/dmd/gpl.txt deleted file mode 100644 index cc468912..00000000 --- a/dmd/gpl.txt +++ /dev/null @@ -1,248 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 1, February 1989 - - Copyright (C) 1989 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The license agreements of most software companies try to keep users -at the mercy of those companies. By contrast, our General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. The -General Public License applies to the Free Software Foundation's -software and to any other program whose authors commit to using it. -You can use it for your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Specifically, the General Public License is designed to make -sure that you have the freedom to give away or sell copies of free -software, that you receive source code or can get it if you want it, -that you can change the software or use pieces of it in new free -programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of a such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must tell them their rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any program or other work which -contains a notice placed by the copyright holder saying it may be -distributed under the terms of this General Public License. The -"Program", below, refers to any such program or work, and a "work based -on the Program" means either the Program or any work containing the -Program or a portion of it, either verbatim or with modifications. Each -licensee is addressed as "you". - - 1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this -General Public License and to the absence of any warranty; and give any -other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of -transferring a copy. - - 2. You may modify your copy or copies of the Program or any portion of -it, and copy and distribute such modifications under the terms of Paragraph -1 above, provided that you also do the following: - - a) cause the modified files to carry prominent notices stating that - you changed the files and the date of any change; and - - b) cause the whole of any work that you distribute or publish, that - in whole or in part contains the Program or any part thereof, either - with or without modifications, to be licensed at no charge to all - third parties under the terms of this General Public License (except - that you may choose to grant warranty protection to some or all - third parties, at your option). - - c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use - in the simplest and most usual way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this General - Public License. - - d) You may charge a fee for the physical act of transferring a - copy, and you may at your option offer warranty protection in - exchange for a fee. - -Mere aggregation of another independent work with the Program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other work under the scope of these terms. - - 3. You may copy and distribute the Program (or a portion or derivative of -it, under Paragraph 2) in object code or executable form under the terms of -Paragraphs 1 and 2 above provided that you also do one of the following: - - a) accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of - Paragraphs 1 and 2 above; or, - - b) accompany it with a written offer, valid for at least three - years, to give any third party free (except for a nominal charge - for the cost of distribution) a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of - Paragraphs 1 and 2 above; or, - - c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form alone.) - -Source code for a work means the preferred form of the work for making -modifications to it. For an executable file, complete source code means -all the source code for all modules it contains; but, as a special -exception, it need not include source code for modules which are standard -libraries that accompany the operating system on which the executable -file runs, or for standard header files or definitions files that -accompany that operating system. - - 4. You may not copy, modify, sublicense, distribute or transfer the -Program except as expressly provided under this General Public License. -Any attempt otherwise to copy, modify, sublicense, distribute or transfer -the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received -copies, or rights to use copies, from you under this General Public -License will not have their licenses terminated so long as such parties -remain in full compliance. - - 5. By copying, distributing or modifying the Program (or any work based -on the Program) you indicate your acceptance of this license to do so, -and all its terms and conditions. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the original -licensor to copy, distribute or modify the Program subject to these -terms and conditions. You may not impose any further restrictions on the -recipients' exercise of the rights granted herein. - - 7. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of the license which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -the license, you may choose any version ever published by the Free Software -Foundation. - - 8. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to humanity, the best way to achieve this is to make it -free software which everyone can redistribute and change under these -terms. - - To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey -the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19xx name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the -commands you use may be called something other than `show w' and `show -c'; they could even be mouse-clicks or menu items--whatever suits your -program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (a program to direct compilers to make passes - at assemblers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/dmd/hdrgen.c b/dmd/hdrgen.c deleted file mode 100644 index 6fa5af42..00000000 --- a/dmd/hdrgen.c +++ /dev/null @@ -1,100 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// Initial header generation implementation by Dave Fladebo -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Routines to emit header files - -#define PRETTY_PRINT -#define TEST_EMIT_ALL 0 // For Testing - -#define LOG 0 - -#include -#include -#include -#if __DMC__ -#include -#endif - -#include "rmem.h" - -#include "id.h" -#include "init.h" - -#include "attrib.h" -#include "cond.h" -#include "enum.h" -#include "import.h" -#include "module.h" -#include "mtype.h" -#include "scope.h" -#include "staticassert.h" -#include "template.h" -#include "utf.h" -#include "version.h" - -#include "declaration.h" -#include "aggregate.h" -#include "expression.h" -#include "statement.h" -#include "mtype.h" -#include "hdrgen.h" - -void argsToCBuffer(OutBuffer *buf, Array *arguments, HdrGenState *hgs); - -void Module::genhdrfile() -{ - OutBuffer hdrbufr; - - hdrbufr.printf("// D import file generated from '%s'", srcfile->toChars()); - hdrbufr.writenl(); - - HdrGenState hgs; - memset(&hgs, 0, sizeof(hgs)); - hgs.hdrgen = 1; - - toCBuffer(&hdrbufr, &hgs); - - // Transfer image to file - hdrfile->setbuffer(hdrbufr.data, hdrbufr.offset); - hdrbufr.data = NULL; - - char *pt = FileName::path(hdrfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - hdrfile->writev(); -} - - -void Module::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (md) - { - buf->writestring("module "); - buf->writestring(md->toChars()); - buf->writebyte(';'); - buf->writenl(); - } - - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - - s->toHBuffer(buf, hgs); - } -} - - -void Dsymbol::toHBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - toCBuffer(buf, hgs); -} - - -/*************************************/ diff --git a/dmd/hdrgen.h b/dmd/hdrgen.h deleted file mode 100644 index 44e3a5dd..00000000 --- a/dmd/hdrgen.h +++ /dev/null @@ -1,35 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// initial header generation implementation by Dave Fladebo -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include // memset() - -struct HdrGenState -{ - int hdrgen; // 1 if generating header file - int ddoc; // 1 if generating Ddoc file - int console; // 1 if writing to console - int tpltMember; - int inCallExp; - int inPtrExp; - int inSlcExp; - int inDotExp; - int inBinExp; - int inArrExp; - int emitInst; - struct - { - int init; - int decl; - } FLinit; - - HdrGenState() { memset(this, 0, sizeof(HdrGenState)); } -}; - - diff --git a/dmd/html.c b/dmd/html.c deleted file mode 100644 index 93b752ee..00000000 --- a/dmd/html.c +++ /dev/null @@ -1,757 +0,0 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gpl.txt. -// See the included readme.txt for details. - - -/* HTML parser - */ - -#include -#include -#include -#include -#include -#include - -#include "mars.h" -#include "html.h" - -#if MARS || IN_LLVM -#include -#include "root.h" -//#include "../mars/mars.h" -#else -#include "outbuf.h" -#include "msgs2.h" - -extern void html_err(const char *, unsigned, unsigned, ...); - -static char __file__[] = __FILE__; /* for tassert.h */ -#include "tassert.h" -#endif - -#if __GNUC__ -int memicmp(const char *s1, const char *s2, int n); -#if 0 -{ - int result = 0; - - for (int i = 0; i < n; i++) - { char c1 = s1[i]; - char c2 = s2[i]; - - result = c1 - c2; - if (result) - { - if ('A' <= c1 && c1 <= 'Z') - c1 += 'a' - 'A'; - if ('A' <= c2 && c2 <= 'Z') - c2 += 'a' - 'A'; - result = c1 - c2; - if (result) - break; - } - } - return result; -} -#endif -#endif - -extern int HtmlNamedEntity(unsigned char *p, int length); - -static int isLineSeparator(const unsigned char* p); - -/********************************** - * Determine if beginning of tag identifier - * or a continuation of a tag identifier. - */ - -inline int istagstart(int c) -{ - return (isalpha(c) || c == '_'); -} - -inline int istag(int c) -{ - return (isalnum(c) || c == '_'); -} - -/********************************************** - */ - -Html::Html(const char *sourcename, unsigned char *base, unsigned length) -{ - //printf("Html::Html()\n"); - this->sourcename = sourcename; - this->base = base; - p = base; - end = base + length; - linnum = 1; - dbuf = NULL; - inCode = 0; -} - -/********************************************** - * Print error & quit. - */ - -void Html::error(const char *format, ...) -{ - if (!global.gag) - { - fprintf(stderr, "%s(%d) : HTML Error: ", sourcename, linnum); - - va_list ap; - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); - - fprintf(stderr, "\n"); - fflush(stderr); - } - - global.errors++; -} - -/********************************************** - * Extract all the code from an HTML file, - * concatenate it all together, and store in buf. - */ - -void Html::extractCode(OutBuffer *buf) -{ - //printf("Html::extractCode()\n"); - dbuf = buf; // save for other routines - buf->reserve(end - p); - inCode = 0; - while (1) - { - //printf("p = %p, *p = x%x\n", p, *p); - switch (*p) - { -#if 0 // strings are not recognized outside of tags - case '"': - case '\'': - skipString(); - continue; -#endif - case '<': - if (p[1] == '!' && isCommentStart()) - { // Comments start with - * Netscape: comments nest - * w3c: whitespace can appear between -- and > of comment close - */ - -void Html::scanComment() -{ - // Most of the complexity is dealing with the case that - // an arbitrary amount of whitespace can appear between - // the -- and the > of a comment close. - int scangt = 0; - - //printf("scanComment()\n"); - if (*p == '\n') - { linnum++; - // Always extract new lines, so that D lexer counts the - // lines right. - dbuf->writeByte(*p); - } - while (1) - { - //scangt = 1; // IE 5.0 compatibility - p++; - switch (*p) - { - case '-': - if (p[1] == '-') - { - if (p[2] == '>') // optimize for most common case - { - p += 3; - break; - } - p++; - scangt = 1; - } - else - scangt = 0; - continue; - - case '>': - if (scangt) - { // found --> - p++; - break; - } - continue; - - case ' ': - case '\t': - case '\f': - case '\v': - // skip white space - continue; - - case '\r': - if (p[1] == '\n') - goto Ldefault; - case '\n': - linnum++; // remember to count lines - // Always extract new lines, so that D lexer counts the - // lines right. - dbuf->writeByte(*p); - continue; - - case 0: - case 0x1a: - error("end of file before closing --> of comment"); - break; - - default: - Ldefault: - scangt = 0; // it's not --> - continue; - } - break; - } - //printf("*p = '%c'\n", *p); -} - -/******************************************** - * Determine if we are at the start of a comment. - * Input: - * p is on the opening '<' - * Returns: - * 0 if not start of a comment - * 1 if start of a comment, p is adjusted to point past -- - */ - -int Html::isCommentStart() -#ifdef __DMC__ - __out(result) - { - if (result == 0) - ; - else if (result == 1) - { - assert(p[-2] == '-' && p[-1] == '-'); - } - else - assert(0); - } - __body -#endif /* __DMC__ */ - { unsigned char *s; - - if (p[0] == '<' && p[1] == '!') - { - for (s = p + 2; 1; s++) - { - switch (*s) - { - case ' ': - case '\t': - case '\r': - case '\f': - case '\v': - // skip white space, even though spec says no - // white space is allowed - continue; - - case '-': - if (s[1] == '-') - { - p = s + 2; - return 1; - } - goto No; - - default: - goto No; - } - } - } - No: - return 0; - } - -int Html::isCDATAStart() -{ - const char * CDATA_START_MARKER = "0) - { - /* Always extract new lines, so that D lexer counts the lines - * right. - */ - linnum++; - dbuf->writeByte('\n'); - p += lineSepLength; - continue; - } - else if (p[0] == ']' && p[1] == ']' && p[2] == '>') - { - /* end of CDATA section */ - p += 3; - return; - } - else if (inCode) - { - /* this CDATA section contains D code */ - dbuf->writeByte(*p); - } - - p++; - } -} - - -/******************************************** - * Convert an HTML character entity into a character. - * Forms are: - * &name; named entity - * &#ddd; decimal - * &#xhhhh; hex - * Input: - * p is on the & - */ - -int Html::charEntity() -{ int c = 0; - int v; - int hex; - unsigned char *pstart = p; - - //printf("Html::charEntity('%c')\n", *p); - if (p[1] == '#') - { - p++; - if (p[1] == 'x' || p[1] == 'X') - { p++; - hex = 1; - } - else - hex = 0; - if (p[1] == ';') - goto Linvalid; - while (1) - { - p++; - switch (*p) - { - case 0: - case 0x1a: - error("end of file before end of character entity"); - goto Lignore; - - case '\n': - case '\r': - case '<': // tag start - // Termination is assumed - break; - - case ';': - // Termination is explicit - p++; - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - v = *p - '0'; - goto Lvalue; - - case 'a': case 'b': case 'c': - case 'd': case 'e': case 'f': - if (!hex) - goto Linvalid; - v = (*p - 'a') + 10; - goto Lvalue; - - case 'A': case 'B': case 'C': - case 'D': case 'E': case 'F': - if (!hex) - goto Linvalid; - v = (*p - 'A') + 10; - goto Lvalue; - - Lvalue: - if (hex) - c = (c << 4) + v; - else - c = (c * 10) + v; - if (c > 0x10FFFF) - { - error("character entity out of range"); - goto Lignore; - } - continue; - - default: - Linvalid: - error("invalid numeric character reference"); - goto Lignore; - } - break; - } - } - else - { - // It's a named entity; gather all characters until ; - unsigned char *idstart = p + 1; - - while (1) - { - p++; - switch (*p) - { - case 0: - case 0x1a: - error("end of file before end of character entity"); - break; - - case '\n': - case '\r': - case '<': // tag start - // Termination is assumed - c = HtmlNamedEntity(idstart, p - idstart); - if (c == -1) - goto Lignore; - break; - - case ';': - // Termination is explicit - c = HtmlNamedEntity(idstart, p - idstart); - if (c == -1) - goto Lignore; - p++; - break; - - default: - continue; - } - break; - } - } - - // Kludge to convert non-breaking space to ascii space - if (c == 160) - c = ' '; - - return c; - -Lignore: - //printf("Lignore\n"); - p = pstart + 1; - return '&'; -} - -/** - * identify DOS, Linux, Mac, Next and Unicode line endings - * 0 if this is no line separator - * >0 the length of the separator - * Note: input has to be UTF-8 - */ -static int isLineSeparator(const unsigned char* p) -{ - // Linux - if( p[0]=='\n') - return 1; - - // Mac & Dos - if( p[0]=='\r') - return (p[1]=='\n') ? 2 : 1; - - // Unicode (line || paragraph sep.) - if( p[0]==0xE2 && p[1]==0x80 && (p[2]==0xA8 || p[2]==0xA9)) - return 3; - - // Next - if( p[0]==0xC2 && p[1]==0x85) - return 2; - - return 0; -} - diff --git a/dmd/html.h b/dmd/html.h deleted file mode 100644 index 98a5285b..00000000 --- a/dmd/html.h +++ /dev/null @@ -1,42 +0,0 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gpl.txt. -// See the included readme.txt for details. - -#ifndef DMD_HTML_H -#define DMD_HTML_H 1 - -struct OutBuffer; - -struct Html -{ - const char *sourcename; - - unsigned char *base; // pointer to start of buffer - unsigned char *end; // past end of buffer - unsigned char *p; // current character - unsigned linnum; // current line number - OutBuffer *dbuf; // code source buffer - int inCode; // !=0 if in code - - - Html(const char *sourcename, unsigned char *base, unsigned length); - - void error(const char *format, ...) IS_PRINTF(2); - void extractCode(OutBuffer *buf); - void skipTag(); - void skipString(); - unsigned char *skipWhite(unsigned char *q); - void scanComment(); - int isCommentStart(); - void scanCDATA(); - int isCDATAStart(); - int charEntity(); - static int namedEntity(unsigned char *p, int length); -}; - -#endif diff --git a/dmd/identifier.c b/dmd/identifier.c deleted file mode 100644 index 01413859..00000000 --- a/dmd/identifier.c +++ /dev/null @@ -1,101 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" -#include "identifier.h" -#include "mars.h" -#include "lexer.h" -#include "id.h" - -Identifier::Identifier(const char *string, int value) -{ - //printf("Identifier('%s', %d)\n", string, value); - this->string = string; - this->value = value; - this->len = strlen(string); -} - -hash_t Identifier::hashCode() -{ - return String::calcHash(string); -} - -int Identifier::equals(Object *o) -{ - return this == o || memcmp(string,o->toChars(),len+1) == 0; -} - -int Identifier::compare(Object *o) -{ - return memcmp(string, o->toChars(), len + 1); -} - -char *Identifier::toChars() -{ - return (char *)string; -} - -const char *Identifier::toHChars2() -{ - const char *p = NULL; - - if (this == Id::ctor) p = "this"; - else if (this == Id::dtor) p = "~this"; - else if (this == Id::classInvariant) p = "invariant"; - else if (this == Id::unitTest) p = "unittest"; - else if (this == Id::dollar) p = "$"; - else if (this == Id::withSym) p = "with"; - else if (this == Id::result) p = "result"; - else if (this == Id::returnLabel) p = "return"; - else - { p = toChars(); - if (*p == '_') - { - if (memcmp(p, "_staticCtor", 11) == 0) - p = "static this"; - else if (memcmp(p, "_staticDtor", 11) == 0) - p = "static ~this"; - } - } - - return p; -} - -void Identifier::print() -{ - fprintf(stdmsg, "%s",string); -} - -int Identifier::dyncast() -{ - return DYNCAST_IDENTIFIER; -} - - -Identifier *Identifier::generateId(const char *prefix) -{ - static size_t i; - - return generateId(prefix, ++i); -} - -Identifier *Identifier::generateId(const char *prefix, size_t i) -{ OutBuffer buf; - - buf.writestring(prefix); - buf.printf("%zu", i); - - char *id = buf.toChars(); - buf.data = NULL; - return Lexer::idPool(id); -} diff --git a/dmd/identifier.h b/dmd/identifier.h deleted file mode 100644 index 1abb3a41..00000000 --- a/dmd/identifier.h +++ /dev/null @@ -1,46 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_IDENTIFIER_H -#define DMD_IDENTIFIER_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#if IN_LLVM -namespace llvm -{ - class Value; -} -#endif - -struct Identifier : Object -{ - int value; - const char *string; - unsigned len; - - Identifier(const char *string, int value); - int equals(Object *o); - hash_t hashCode(); - int compare(Object *o); - void print(); - char *toChars(); - char *toHChars(); - const char *toHChars2(); - int dyncast(); - - static Identifier *generateId(const char *prefix); - static Identifier *generateId(const char *prefix, size_t i); -}; - -#endif /* DMD_IDENTIFIER_H */ diff --git a/dmd/idgen.c b/dmd/idgen.c deleted file mode 100644 index 0374f425..00000000 --- a/dmd/idgen.c +++ /dev/null @@ -1,378 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// http://www.dsource.org/projects/dmd/browser/branches/dmd-1.x/src/idgen.c -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Program to generate string files in d data structures. -// Saves much tedious typing, and eliminates typo problems. -// Generates: -// id.h -// id.c - -#include -#include -#include -#include -#include - -struct Msgtable -{ - const char *ident; // name to use in DMD source - const char *name; // name in D executable -}; - -Msgtable msgtable[] = -{ - { "IUnknown" }, - { "Object" }, - { "object" }, - { "max" }, - { "min" }, - { "This", "this" }, - { "ctor", "_ctor" }, - { "dtor", "_dtor" }, - { "classInvariant", "__invariant" }, - { "unitTest", "_unitTest" }, - { "require", "__require" }, - { "ensure", "__ensure" }, - { "init" }, - { "size" }, - { "__sizeof", "sizeof" }, - { "__xalignof", "alignof" }, - { "mangleof" }, - { "stringof" }, - { "tupleof" }, - { "length" }, - { "remove" }, - { "ptr" }, - { "funcptr" }, - { "dollar", "__dollar" }, - { "offset" }, - { "offsetof" }, - { "ModuleInfo" }, - { "ClassInfo" }, - { "classinfo" }, - { "typeinfo" }, - { "outer" }, - { "Exception" }, - { "Error" }, - { "withSym", "__withSym" }, - { "result", "__result" }, - { "returnLabel", "__returnLabel" }, - { "delegate" }, - { "line" }, - { "empty", "" }, - { "p" }, - { "coverage", "__coverage" }, - { "__vptr" }, - { "__monitor" }, - - { "TypeInfo" }, - { "TypeInfo_Class" }, - { "TypeInfo_Interface" }, - { "TypeInfo_Struct" }, - { "TypeInfo_Enum" }, - { "TypeInfo_Typedef" }, - { "TypeInfo_Pointer" }, - { "TypeInfo_Array" }, - { "TypeInfo_StaticArray" }, - { "TypeInfo_AssociativeArray" }, - { "TypeInfo_Function" }, - { "TypeInfo_Delegate" }, - { "TypeInfo_Tuple" }, - { "TypeInfo_Const" }, - { "TypeInfo_Invariant" }, - { "elements" }, - { "_arguments_typeinfo" }, - { "_arguments" }, - { "_argptr" }, - { "_match" }, - { "m_align" }, - - { "LINE", "__LINE__" }, - { "FILE", "__FILE__" }, - { "DATE", "__DATE__" }, - { "TIME", "__TIME__" }, - { "TIMESTAMP", "__TIMESTAMP__" }, - { "VENDOR", "__VENDOR__" }, - { "VERSIONX", "__VERSION__" }, - - { "nan" }, - { "infinity" }, - { "dig" }, - { "epsilon" }, - { "mant_dig" }, - { "max_10_exp" }, - { "max_exp" }, - { "min_10_exp" }, - { "min_exp" }, - { "re" }, - { "im" }, - - { "C" }, - { "D" }, - { "Windows" }, - { "Pascal" }, - { "System" }, - - { "exit" }, - { "success" }, - { "failure" }, - - { "keys" }, - { "values" }, - { "rehash" }, - - { "sort" }, - { "reverse" }, - { "dup" }, - { "idup" }, - - // For inline assembler - { "___out", "out" }, - { "___in", "in" }, - { "__int", "int" }, - { "__dollar", "$" }, - { "__LOCAL_SIZE" }, - - // For operator overloads - { "uadd", "opPos" }, - { "neg", "opNeg" }, - { "com", "opCom" }, - { "add", "opAdd" }, - { "add_r", "opAdd_r" }, - { "sub", "opSub" }, - { "sub_r", "opSub_r" }, - { "mul", "opMul" }, - { "mul_r", "opMul_r" }, - { "div", "opDiv" }, - { "div_r", "opDiv_r" }, - { "mod", "opMod" }, - { "mod_r", "opMod_r" }, - { "eq", "opEquals" }, - { "cmp", "opCmp" }, - { "iand", "opAnd" }, - { "iand_r", "opAnd_r" }, - { "ior", "opOr" }, - { "ior_r", "opOr_r" }, - { "ixor", "opXor" }, - { "ixor_r", "opXor_r" }, - { "shl", "opShl" }, - { "shl_r", "opShl_r" }, - { "shr", "opShr" }, - { "shr_r", "opShr_r" }, - { "ushr", "opUShr" }, - { "ushr_r", "opUShr_r" }, - { "cat", "opCat" }, - { "cat_r", "opCat_r" }, - { "assign", "opAssign" }, - { "addass", "opAddAssign" }, - { "subass", "opSubAssign" }, - { "mulass", "opMulAssign" }, - { "divass", "opDivAssign" }, - { "modass", "opModAssign" }, - { "andass", "opAndAssign" }, - { "orass", "opOrAssign" }, - { "xorass", "opXorAssign" }, - { "shlass", "opShlAssign" }, - { "shrass", "opShrAssign" }, - { "ushrass", "opUShrAssign" }, - { "catass", "opCatAssign" }, - { "postinc", "opPostInc" }, - { "postdec", "opPostDec" }, - { "index", "opIndex" }, - { "indexass", "opIndexAssign" }, - { "slice", "opSlice" }, - { "sliceass", "opSliceAssign" }, - { "call", "opCall" }, - { "cast", "opCast" }, - { "match", "opMatch" }, - { "next", "opNext" }, - { "opIn" }, - { "opIn_r" }, - - { "classNew", "new" }, - { "classDelete", "delete" }, - - // For foreach - { "apply", "opApply" }, - { "applyReverse", "opApplyReverse" }, - - { "adDup", "_adDupT" }, - { "adReverse", "_adReverse" }, - - // For internal functions - { "aaLen", "_aaLen" }, - { "aaKeys", "_aaKeys" }, - { "aaValues", "_aaValues" }, - { "aaRehash", "_aaRehash" }, - { "monitorenter", "_d_monitorenter" }, - { "monitorexit", "_d_monitorexit" }, - { "criticalenter", "_d_criticalenter" }, - { "criticalexit", "_d_criticalexit" }, - - // For pragma's - { "GNU_asm" }, - { "lib" }, - { "msg" }, - -#if IN_LLVM - // LDC-specific pragmas. - { "LDC_intrinsic" }, - { "LDC_no_typeinfo" }, - { "LDC_no_moduleinfo" }, - { "LDC_alloca" }, - { "LDC_va_start" }, - { "LDC_va_copy" }, - { "LDC_va_end" }, - { "LDC_va_arg" }, - { "LDC_verbose" }, - { "LDC_allow_inline" }, - { "LDC_inline_asm" }, - { "LDC_inline_ir" }, - { "LDC_fence" }, - { "LDC_atomic_load" }, - { "LDC_atomic_store" }, - { "LDC_atomic_cmp_xchg" }, - { "LDC_atomic_rmw" }, - { "LDC_global_crt_ctor" }, - { "LDC_global_crt_dtor" }, - - // Deprecated LDC pragmas lacking the vendor prefix. - { "intrinsic" }, - { "no_typeinfo" }, - { "no_moduleinfo" }, - { "Alloca", "alloca" }, - { "vastart", "va_start" }, - { "vacopy", "va_copy" }, - { "vaend", "va_end" }, - { "vaarg", "va_arg" }, - { "ldc" }, - { "allow_inline" }, - { "llvm_inline_asm" }, - { "llvm_inline_ir" }, - { "fence" }, - { "atomic_load" }, - { "atomic_store" }, - { "atomic_cmp_xchg" }, - { "atomic_rmw" }, -#endif - - // For special functions - { "tohash", "toHash" }, - { "tostring", "toString" }, - - // Special functions - //{ "alloca" }, - { "main" }, - { "WinMain" }, - { "DllMain" }, - - // varargs implementation - { "va_argsave_t", "__va_argsave_t" }, - { "va_argsave", "__va_argsave" }, - - // Builtin functions - { "std" }, - { "core" }, - { "math" }, - { "sin" }, - { "cos" }, - { "tan" }, - { "_sqrt", "sqrt" }, - { "_pow", "pow" }, - { "atan2" }, - { "rndtol" }, - { "expm1" }, - { "exp2" }, - { "yl2x" }, - { "yl2xp1" }, - { "fabs" }, - { "bitop" }, - { "bsf" }, - { "bsr" }, - { "bswap" }, -}; - - -int main() -{ - FILE *fp; - unsigned i; - - { - fp = fopen("id.h","w"); - if (!fp) - { printf("can't open id.h\n"); - exit(EXIT_FAILURE); - } - - fprintf(fp, "// File generated by idgen.c\n"); -#if __DMC__ - fprintf(fp, "#pragma once\n"); -#endif - fprintf(fp, "#ifndef DMD_ID_H\n"); - fprintf(fp, "#define DMD_ID_H 1\n"); - fprintf(fp, "struct Identifier;\n"); - fprintf(fp, "struct Id\n"); - fprintf(fp, "{\n"); - - for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++) - { const char *id = msgtable[i].ident; - - fprintf(fp," static Identifier *%s;\n", id); - } - - fprintf(fp, " static void initialize();\n"); - fprintf(fp, "};\n"); - fprintf(fp, "#endif\n"); - - fclose(fp); - } - - { - fp = fopen("id.c","w"); - if (!fp) - { printf("can't open id.c\n"); - exit(EXIT_FAILURE); - } - - fprintf(fp, "// File generated by idgen.c\n"); - fprintf(fp, "#include \"id.h\"\n"); - fprintf(fp, "#include \"identifier.h\"\n"); - fprintf(fp, "#include \"lexer.h\"\n"); - - for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++) - { const char *id = msgtable[i].ident; - const char *p = msgtable[i].name; - - if (!p) - p = id; - fprintf(fp,"Identifier *Id::%s;\n", id); - } - - fprintf(fp, "void Id::initialize()\n"); - fprintf(fp, "{\n"); - - for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++) - { const char *id = msgtable[i].ident; - const char *p = msgtable[i].name; - - if (!p) - p = id; - fprintf(fp," %s = Lexer::idPool(\"%s\");\n", id, p); - } - - fprintf(fp, "}\n"); - - fclose(fp); - } - - return EXIT_SUCCESS; -} diff --git a/dmd/impcnvgen.c b/dmd/impcnvgen.c deleted file mode 100644 index 6e7a1993..00000000 --- a/dmd/impcnvgen.c +++ /dev/null @@ -1,457 +0,0 @@ - -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mtype.h" - -enum TY impcnvResult[TMAX][TMAX]; -enum TY impcnvType1[TMAX][TMAX]; -enum TY impcnvType2[TMAX][TMAX]; -int impcnvWarn[TMAX][TMAX]; - -int integral_promotion(int t) -{ - switch (t) - { - case Tchar: - case Twchar: - case Tbit: - case Tbool: - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: return Tint32; - case Tdchar: return Tuns32; - default: return t; - } -} - -void init() -{ int i, j; - - // Set conversion tables - for (i = 0; i < TMAX; i++) - for (j = 0; j < TMAX; j++) - { impcnvResult[i][j] = Terror; - impcnvType1[i][j] = Terror; - impcnvType2[i][j] = Terror; - impcnvWarn[i][j] = 0; - } - -#define X(t1,t2, nt1,nt2, rt) \ - impcnvResult[t1][t2] = rt; \ - impcnvType1[t1][t2] = nt1; \ - impcnvType2[t1][t2] = nt2; - - /* ======================= */ - - X(Tbit,Tbit, Tint32,Tint32, Tint32) - X(Tbit,Tint8, Tint32,Tint32, Tint32) - X(Tbit,Tuns8, Tint32,Tint32, Tint32) - X(Tbit,Tint16, Tint32,Tint32, Tint32) - X(Tbit,Tuns16, Tint32,Tint32, Tint32) - X(Tbit,Tint32, Tint32,Tint32, Tint32) - X(Tbit,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tbit,Tint64, Tint64,Tint64, Tint64) - X(Tbit,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tbit,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tbit,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tbit,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tbit,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tbit,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tbit,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tbit,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tbit,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tbit,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tbool,Tbool, Tbool,Tbool, Tbool) - X(Tbool,Tint8, Tint32,Tint32, Tint32) - X(Tbool,Tuns8, Tint32,Tint32, Tint32) - X(Tbool,Tint16, Tint32,Tint32, Tint32) - X(Tbool,Tuns16, Tint32,Tint32, Tint32) - X(Tbool,Tint32, Tint32,Tint32, Tint32) - X(Tbool,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tbool,Tint64, Tint64,Tint64, Tint64) - X(Tbool,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tbool,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tbool,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tbool,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tbool,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tbool,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tbool,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tbool,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tbool,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tbool,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tint8,Tint8, Tint32,Tint32, Tint32) - X(Tint8,Tuns8, Tint32,Tint32, Tint32) - X(Tint8,Tint16, Tint32,Tint32, Tint32) - X(Tint8,Tuns16, Tint32,Tint32, Tint32) - X(Tint8,Tint32, Tint32,Tint32, Tint32) - X(Tint8,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tint8,Tint64, Tint64,Tint64, Tint64) - X(Tint8,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tint8,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tint8,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tint8,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tint8,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tint8,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tint8,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tint8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tint8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tint8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tuns8,Tuns8, Tint32,Tint32, Tint32) - X(Tuns8,Tint16, Tint32,Tint32, Tint32) - X(Tuns8,Tuns16, Tint32,Tint32, Tint32) - X(Tuns8,Tint32, Tint32,Tint32, Tint32) - X(Tuns8,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tuns8,Tint64, Tint64,Tint64, Tint64) - X(Tuns8,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tuns8,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tuns8,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tuns8,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tuns8,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tuns8,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tuns8,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tuns8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tuns8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tuns8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tint16,Tint16, Tint32,Tint32, Tint32) - X(Tint16,Tuns16, Tint32,Tint32, Tint32) - X(Tint16,Tint32, Tint32,Tint32, Tint32) - X(Tint16,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tint16,Tint64, Tint64,Tint64, Tint64) - X(Tint16,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tint16,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tint16,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tint16,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tint16,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tint16,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tint16,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tint16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tint16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tint16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tuns16,Tuns16, Tint32,Tint32, Tint32) - X(Tuns16,Tint32, Tint32,Tint32, Tint32) - X(Tuns16,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tuns16,Tint64, Tint64,Tint64, Tint64) - X(Tuns16,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tuns16,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tuns16,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tuns16,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tuns16,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tuns16,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tuns16,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tuns16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tuns16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tuns16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tint32,Tint32, Tint32,Tint32, Tint32) - X(Tint32,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tint32,Tint64, Tint64,Tint64, Tint64) - X(Tint32,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tint32,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tint32,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tint32,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tint32,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tint32,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tint32,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tint32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tint32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tint32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tuns32,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tuns32,Tint64, Tint64,Tint64, Tint64) - X(Tuns32,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tuns32,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tuns32,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tuns32,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tuns32,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tuns32,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tuns32,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tuns32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tuns32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tuns32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tint64,Tint64, Tint64,Tint64, Tint64) - X(Tint64,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tint64,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tint64,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tint64,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tint64,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tint64,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tint64,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tint64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tint64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tint64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tuns64,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tuns64,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tuns64,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tuns64,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tuns64,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tuns64,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tuns64,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tuns64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tuns64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tuns64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tfloat32,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tfloat32,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tfloat32,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - - X(Tfloat32,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tfloat32,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tfloat32,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - - X(Tfloat32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tfloat32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tfloat32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tfloat64,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tfloat64,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - - X(Tfloat64,Timaginary32, Tfloat64,Timaginary64, Tfloat64) - X(Tfloat64,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tfloat64,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - - X(Tfloat64,Tcomplex32, Tfloat64,Tcomplex64, Tcomplex64) - X(Tfloat64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tfloat64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tfloat80,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - - X(Tfloat80,Timaginary32, Tfloat80,Timaginary80, Tfloat80) - X(Tfloat80,Timaginary64, Tfloat80,Timaginary80, Tfloat80) - X(Tfloat80,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - - X(Tfloat80,Tcomplex32, Tfloat80,Tcomplex80, Tcomplex80) - X(Tfloat80,Tcomplex64, Tfloat80,Tcomplex80, Tcomplex80) - X(Tfloat80,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Timaginary32,Timaginary32, Timaginary32,Timaginary32, Timaginary32) - X(Timaginary32,Timaginary64, Timaginary64,Timaginary64, Timaginary64) - X(Timaginary32,Timaginary80, Timaginary80,Timaginary80, Timaginary80) - - X(Timaginary32,Tcomplex32, Timaginary32,Tcomplex32, Tcomplex32) - X(Timaginary32,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64) - X(Timaginary32,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Timaginary64,Timaginary64, Timaginary64,Timaginary64, Timaginary64) - X(Timaginary64,Timaginary80, Timaginary80,Timaginary80, Timaginary80) - - X(Timaginary64,Tcomplex32, Timaginary64,Tcomplex64, Tcomplex64) - X(Timaginary64,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64) - X(Timaginary64,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Timaginary80,Timaginary80, Timaginary80,Timaginary80, Timaginary80) - - X(Timaginary80,Tcomplex32, Timaginary80,Tcomplex80, Tcomplex80) - X(Timaginary80,Tcomplex64, Timaginary80,Tcomplex80, Tcomplex80) - X(Timaginary80,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tcomplex32,Tcomplex32, Tcomplex32,Tcomplex32, Tcomplex32) - X(Tcomplex32,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64) - X(Tcomplex32,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tcomplex64,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64) - X(Tcomplex64,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80) - -#undef X - -#define Y(t1,t2) impcnvWarn[t1][t2] = 1; - Y(Tint8, Tbit) - Y(Tuns8, Tbit) - Y(Tint16, Tbit) - Y(Tuns16, Tbit) - Y(Tint32, Tbit) - Y(Tuns32, Tbit) - Y(Tint64, Tbit) - Y(Tuns64, Tbit) - - Y(Tuns8, Tint8) - Y(Tint16, Tint8) - Y(Tuns16, Tint8) - Y(Tint32, Tint8) - Y(Tuns32, Tint8) - Y(Tint64, Tint8) - Y(Tuns64, Tint8) - - Y(Tint8, Tuns8) - Y(Tint16, Tuns8) - Y(Tuns16, Tuns8) - Y(Tint32, Tuns8) - Y(Tuns32, Tuns8) - Y(Tint64, Tuns8) - Y(Tuns64, Tuns8) - - Y(Tint8, Tchar) - Y(Tint16, Tchar) - Y(Tuns16, Tchar) - Y(Tint32, Tchar) - Y(Tuns32, Tchar) - Y(Tint64, Tchar) - Y(Tuns64, Tchar) - - Y(Tuns16, Tint16) - Y(Tint32, Tint16) - Y(Tuns32, Tint16) - Y(Tint64, Tint16) - Y(Tuns64, Tint16) - - Y(Tint16, Tuns16) - Y(Tint32, Tuns16) - Y(Tuns32, Tuns16) - Y(Tint64, Tuns16) - Y(Tuns64, Tuns16) - - Y(Tint16, Twchar) - Y(Tint32, Twchar) - Y(Tuns32, Twchar) - Y(Tint64, Twchar) - Y(Tuns64, Twchar) - -// Y(Tuns32, Tint32) - Y(Tint64, Tint32) - Y(Tuns64, Tint32) - -// Y(Tint32, Tuns32) - Y(Tint64, Tuns32) - Y(Tuns64, Tuns32) - - Y(Tint64, Tdchar) - Y(Tuns64, Tdchar) - -// Y(Tint64, Tuns64) -// Y(Tuns64, Tint64) - - for (i = 0; i < TMAX; i++) - for (j = 0; j < TMAX; j++) - { - if (impcnvResult[i][j] == Terror) - { - impcnvResult[i][j] = impcnvResult[j][i]; - impcnvType1[i][j] = impcnvType2[j][i]; - impcnvType2[i][j] = impcnvType1[j][i]; - } - } -} - -int main() -{ FILE *fp; - int i; - int j; - - init(); - - fp = fopen("impcnvtab.c","w"); - - fprintf(fp,"// This file is generated by impcnvgen.c\n"); - fprintf(fp,"#include \"mtype.h\"\n"); - - fprintf(fp,"unsigned char Type::impcnvResult[TMAX][TMAX] =\n{\n"); - for (i = 0; i < TMAX; i++) - { - for (j = 0; j < TMAX; j++) - { - fprintf(fp, "%d,",impcnvResult[i][j]); - } - fprintf(fp, "\n"); - } - fprintf(fp,"};\n"); - - fprintf(fp,"unsigned char Type::impcnvType1[TMAX][TMAX] =\n{\n"); - for (i = 0; i < TMAX; i++) - { - for (j = 0; j < TMAX; j++) - { - fprintf(fp, "%d,",impcnvType1[i][j]); - } - fprintf(fp, "\n"); - } - fprintf(fp,"};\n"); - - fprintf(fp,"unsigned char Type::impcnvType2[TMAX][TMAX] =\n{\n"); - for (i = 0; i < TMAX; i++) - { - for (j = 0; j < TMAX; j++) - { - fprintf(fp, "%d,",impcnvType2[i][j]); - } - fprintf(fp, "\n"); - } - fprintf(fp,"};\n"); - - fprintf(fp,"unsigned char Type::impcnvWarn[TMAX][TMAX] =\n{\n"); - for (i = 0; i < TMAX; i++) - { - for (j = 0; j < TMAX; j++) - { - fprintf(fp, "%d,",impcnvWarn[i][j]); - } - fprintf(fp, "\n"); - } - fprintf(fp,"};\n"); - - fclose(fp); - return EXIT_SUCCESS; -} diff --git a/dmd/imphint.c b/dmd/imphint.c deleted file mode 100644 index df86e01c..00000000 --- a/dmd/imphint.c +++ /dev/null @@ -1,84 +0,0 @@ - - -// Compiler implementation of the D programming language -// Copyright (c) 2010 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include - -#include "mars.h" - -/****************************************** - * Looks for undefined identifier s to see - * if it might be undefined because an import - * was not specified. - * Not meant to be a comprehensive list of names in each module, - * just the most common ones. - */ - -const char *importHint(const char *s) -{ -#if DMDV1 - static const char *modules[] = - { "tango.stdc.stdio", - "tango.io.Stdout", - "tango.math.Math", - }; - static const char *names[] = - { - "printf", NULL, - "Stdout", NULL, - "sin", "cos", "sqrt", "abs", NULL, - }; -#else - static const char *modules[] = - { "core.stdc.stdio", - "std.stdio", - "std.math", - }; - static const char *names[] = - { - "printf", NULL, - "writeln", NULL, - "sin", "cos", "sqrt", "fabs", NULL, - }; -#endif - int m = 0; - for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) - { - const char *p = names[n]; - if (p == NULL) - { m++; - continue; - } - assert(m < sizeof(modules)/sizeof(modules[0])); - if (strcmp(s, p) == 0) - return modules[m]; - } - return NULL; // didn't find it -} - -#if UNITTEST - -void unittest_importHint() -{ - const char *p; - - p = importHint("printf"); - assert(p); - p = importHint("fabs"); - assert(p); - p = importHint("xxxxx"); - assert(!p); -} - -#endif diff --git a/dmd/import.c b/dmd/import.c deleted file mode 100644 index 575fb340..00000000 --- a/dmd/import.c +++ /dev/null @@ -1,411 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" -#include "dsymbol.h" -#include "import.h" -#include "identifier.h" -#include "module.h" -#include "scope.h" -#include "hdrgen.h" -#include "mtype.h" -#include "declaration.h" -#include "id.h" -#include "attrib.h" - -/********************************* Import ****************************/ - -Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId, - int isstatic) - : Dsymbol() -{ - assert(id); - this->loc = loc; - this->packages = packages; - this->id = id; - this->aliasId = aliasId; - this->isstatic = isstatic; - protection = PROTundefined; - pkg = NULL; - mod = NULL; -} - -void Import::addAlias(Identifier *name, Identifier *alias) -{ - if (isstatic) - error("cannot have an import bind list"); - - names.push(name); - aliases.push(alias); -} - -const char *Import::kind() -{ - return isstatic ? (char *)"static import" : (char *)"import"; -} - -enum PROT Import::prot() -{ - return protection; -} - -Dsymbol *Import::syntaxCopy(Dsymbol *s) -{ - assert(!s); - - Import *si = new Import(loc, packages, id, aliasId, isstatic); - - for (size_t i = 0; i < names.dim; i++) - { - si->addAlias(names[i], aliases[i]); - } - - return si; -} - -void Import::load(Scope *sc) -{ - //printf("Import::load('%s')\n", toChars()); - - // See if existing module - DsymbolTable *dst = Package::resolve(packages, NULL, &pkg); -#if TARGET_NET //dot net needs modules and packages with same name -#else - if (pkg && pkg->isModule()) - { - ::error(loc, "can only import from a module, not from a member of module %s. Did you mean `import %s : %s`?", - pkg->toChars(), pkg->toPrettyChars(), id->toChars()); - mod = pkg->isModule(); // Error recovery - treat as import of that module - return; - } -#endif - Dsymbol *s = dst->lookup(id); - if (s) - { -#if TARGET_NET - mod = (Module *)s; -#else - if (s->isModule()) - mod = (Module *)s; - else - { - if (pkg) - { - ::error(loc, "can only import from a module, not from package %s.%s", - pkg->toPrettyChars(), id->toChars()); - } - else - { - ::error(loc, "can only import from a module, not from package %s", - id->toChars()); - } - } -#endif - } - - if (!mod) - { - // Load module - mod = Module::load(loc, packages, id); - if (mod) - { - dst->insert(id, mod); // id may be different from mod->ident, - // if so then insert alias - if (!mod->importedFrom) - mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule; - } - } - if (!pkg) - pkg = mod; - - //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); -} - -void escapePath(OutBuffer *buf, const char *fname) -{ - while (1) - { - switch (*fname) - { - case 0: - return; - case '(': - case ')': - case '\\': - buf->writebyte('\\'); - default: - buf->writebyte(*fname); - break; - } - fname++; - } -} - -void Import::importAll(Scope *sc) -{ - if (!mod) - { - load(sc); - mod->importAll(0); - - /* Default to private importing - */ - enum PROT prot = sc->protection; - if (!sc->explicitProtection) - prot = PROTprivate; - sc->scopesym->importScope(this, prot); - } -} - -void Import::semantic(Scope *sc) -{ - //printf("Import::semantic('%s')\n", toChars()); - - // Load if not already done so - if (!mod) - { load(sc); - if (mod) - mod->importAll(0); - } - - if (mod) - { -#if 0 - if (mod->loc.linnum != 0) - { /* If the line number is not 0, then this is not - * a 'root' module, i.e. it was not specified on the command line. - */ - mod->importedFrom = sc->module->importedFrom; - assert(mod->importedFrom); - } -#endif - - // Modules need a list of each imported module - //printf("%s imports %s\n", sc->module->toChars(), mod->toChars()); - sc->module->aimports.push(mod); - - /* Default to private importing - */ - enum PROT prot = sc->protection; - if (!sc->explicitProtection) - prot = PROTprivate; - for (Scope *scd = sc; scd; scd = scd->enclosing) - { - if (scd->scopesym) - { - scd->scopesym->importScope(this, prot); - break; - } - } - - mod->semantic(); - - if (mod->needmoduleinfo) - { //printf("module4 %s because of %s\n", sc->module->toChars(), mod->toChars()); - sc->module->needmoduleinfo = 1; - } - - if (aliasId) - { - AliasDeclaration *ad = new AliasDeclaration(loc, aliasId, mod); - sc->insert(ad); - ad->semantic(sc); - } - } - //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); - - if (global.params.moduleDeps != NULL && - // object self-imports itself, so skip that (Bugzilla 7547) - !(id == Id::object && sc->module->ident == Id::object)) - { - /* The grammar of the file is: - * ImportDeclaration - * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " - * ModuleAliasIdentifier ] "\n" - * - * BasicImportDeclaration - * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection - * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" - * - * FilePath - * - any string with '(', ')' and '\' escaped with the '\' character - */ - - OutBuffer *ob = global.params.moduleDeps; - - ob->writestring(sc->module->toPrettyChars()); - ob->writestring(" ("); - escapePath(ob, sc->module->srcfile->toChars()); - ob->writestring(") : "); - - ProtDeclaration::protectionToCBuffer(ob, sc->protection); - if (isstatic) - StorageClassDeclaration::stcToCBuffer(ob, STCstatic); - ob->writestring(": "); - - if (packages) - { - for (size_t i = 0; i < packages->dim; i++) - { - Identifier *pid = (*packages)[i]; - ob->printf("%s.", pid->toChars()); - } - } - - ob->writestring(id->toChars()); - ob->writestring(" ("); - if (mod) - escapePath(ob, mod->srcfile->toChars()); - else - ob->writestring("???"); - ob->writebyte(')'); - - for (size_t i = 0; i < names.dim; i++) - { - if (i == 0) - ob->writebyte(':'); - else - ob->writebyte(','); - - Identifier *name = names[i]; - Identifier *alias = aliases[i]; - - if (!alias) - { - ob->printf("%s", name->toChars()); - alias = name; - } - else - ob->printf("%s=%s", alias->toChars(), name->toChars()); - } - - if (aliasId) - ob->printf(" -> %s", aliasId->toChars()); - - ob->writenl(); - } - - //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); -} - -void Import::semantic2(Scope *sc) -{ - //printf("Import::semantic2('%s')\n", toChars()); - mod->semantic2(); - if (mod->needmoduleinfo) - { //printf("module5 %s because of %s\n", sc->module->toChars(), mod->toChars()); - sc->module->needmoduleinfo = 1; - } -} - -Dsymbol *Import::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags); - - if (!pkg) - { load(NULL); - mod->semantic(); - } - - if (names.dim) // selective import - { - for (size_t i = 0; i < names.dim; i++) - { - Identifier *name = (Identifier *)names[i]; - Identifier *alias = (Identifier *)aliases[i]; - - if (!alias) - alias = name; - - if (alias->equals(ident)) - return mod->search(loc, name, flags); - } - - // What should happen when renamed and selective imports are mixed? - // This makes the whole module available with the renamed id. - if (aliasId && aliasId->equals(ident)) - return mod; - } - else // non-selective import - { - // For renamed imports, only the alias name is visible. - if (aliasId) - { - if (aliasId->equals(ident)) - return mod; - return 0; - } - - // For non-static imports, prefer symbols in the module over the module name. - if (!isstatic) - { - Dsymbol *s = mod->search(loc, ident, flags); - if (s) - return s; - } - - // Make the start of the package name available. - if (pkg->ident->equals(ident)) - { - return pkg; - } - } - return 0; -} - -void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen && id == Id::object) - return; // object is imported by default - - if (isstatic) - buf->writestring("static "); - buf->writestring("import "); - if (aliasId) - { - buf->printf("%s = ", aliasId->toChars()); - } - if (packages && packages->dim) - { - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = (*packages)[i]; - - buf->printf("%s.", pid->toChars()); - } - } - buf->printf("%s", id->toChars()); - if (names.dim) - { - buf->writestring(" : "); - for (size_t i = 0; i < names.dim; i++) - { - Identifier *name = names[i]; - Identifier *alias = aliases[i]; - - if (alias) - buf->printf("%s = %s", alias->toChars(), name->toChars()); - else - buf->printf("%s", name->toChars()); - - if (i < names.dim - 1) - buf->writestring(", "); - } - } - buf->printf(";"); - buf->writenl(); -} - -char *Import::toChars() -{ - return id->toChars(); -} diff --git a/dmd/import.h b/dmd/import.h deleted file mode 100644 index e054bbb7..00000000 --- a/dmd/import.h +++ /dev/null @@ -1,63 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_IMPORT_H -#define DMD_IMPORT_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - - -struct Identifier; -struct Scope; -struct OutBuffer; -struct Module; -struct Package; -struct AliasDeclaration; -struct HdrGenState; - -struct Import : Dsymbol -{ - // isstatic import aliasId = packages.id; - Identifiers *packages; // array of Identifier's representing packages - Identifier *id; // module Identifier - Identifier *aliasId; - int isstatic; // !=0 if static import - enum PROT protection; - - // Pairs of alias=name to bind into current namespace - Identifiers names; - Identifiers aliases; - - Module *mod; - Package *pkg; // leftmost package/module - - Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId, - int isstatic); - void addAlias(Identifier *name, Identifier *alias); - - const char *kind(); - enum PROT prot(); - Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - void load(Scope *sc); - void importAll(Scope *sc); - void semantic(Scope *sc); - void semantic2(Scope *sc); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *toChars(); - - Import *isImport() { return this; } -}; - -#endif /* DMD_IMPORT_H */ diff --git a/dmd/init.c b/dmd/init.c deleted file mode 100644 index b58468a2..00000000 --- a/dmd/init.c +++ /dev/null @@ -1,845 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "init.h" -#include "expression.h" -#include "statement.h" -#include "identifier.h" -#include "declaration.h" -#include "aggregate.h" -#include "scope.h" -#include "mtype.h" -#include "hdrgen.h" - -/********************************** Initializer *******************************/ - -Initializer::Initializer(Loc loc) -{ - this->loc = loc; -} - -Initializer *Initializer::syntaxCopy() -{ - return this; -} - -Initializer *Initializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) -{ - return this; -} - -Type *Initializer::inferType(Scope *sc) -{ - error(loc, "cannot infer type from initializer"); - return Type::terror; -} - -Initializers *Initializer::arraySyntaxCopy(Initializers *ai) -{ Initializers *a = NULL; - - if (ai) - { - a = new Initializers(); - a->setDim(ai->dim); - for (size_t i = 0; i < a->dim; i++) - { Initializer *e = (*ai)[i]; - - e = e->syntaxCopy(); - (*a)[i] = e; - } - } - return a; -} - -char *Initializer::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - memset(&hgs, 0, sizeof(hgs)); - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); -} - -/********************************** VoidInitializer ***************************/ - -VoidInitializer::VoidInitializer(Loc loc) - : Initializer(loc) -{ - type = NULL; -} - - -Initializer *VoidInitializer::syntaxCopy() -{ - return new VoidInitializer(loc); -} - - -Initializer *VoidInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) -{ - //printf("VoidInitializer::semantic(t = %p)\n", t); - type = t; - return this; -} - - -Expression *VoidInitializer::toExpression() -{ - error(loc, "void initializer has no value"); - return new IntegerExp(0); -} - - -void VoidInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("void"); -} - - -/********************************** StructInitializer *************************/ - -StructInitializer::StructInitializer(Loc loc) - : Initializer(loc) -{ - ad = NULL; -#if IN_LLVM - ltype = NULL; -#endif -} - -Initializer *StructInitializer::syntaxCopy() -{ - StructInitializer *ai = new StructInitializer(loc); - - assert(field.dim == value.dim); - ai->field.setDim(field.dim); - ai->value.setDim(value.dim); - for (size_t i = 0; i < field.dim; i++) - { - ai->field[i] = field[i]; - - Initializer *init = value[i]; - init = init->syntaxCopy(); - ai->value[i] = init; - } - return ai; -} - -void StructInitializer::addInit(Identifier *field, Initializer *value) -{ - //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value); - this->field.push(field); - this->value.push(value); -} - -Initializer *StructInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) -{ - int errors = 0; - - //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars()); - vars.setDim(field.dim); - t = t->toBasetype(); - if (t->ty == Tstruct) - { - unsigned fieldi = 0; - - TypeStruct *ts = (TypeStruct *)t; - ad = ts->sym; - size_t nfields = ad->fields.dim; -#if DMDV2 - if (((StructDeclaration *)ad)->isnested) - nfields--; // don't count pointer to outer -#endif - for (size_t i = 0; i < field.dim; i++) - { - Identifier *id = field[i]; - Initializer *val = value[i]; - Dsymbol *s; - VarDeclaration *v; - - if (id == NULL) - { - if (fieldi >= nfields) - { error(loc, "too many initializers for %s", ad->toChars()); - errors = 1; - field.remove(i); - i--; - continue; - } - else - { - s = ad->fields[fieldi]; - } - } - else - { - //s = ad->symtab->lookup(id); - s = ad->search(loc, id, 0); - if (!s) - { - s = ad->search_correct(id); - if (s) - error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?", - id->toChars(), t->toChars(), s->kind(), s->toChars()); - else - error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars()); - errors = 1; - continue; - } - s = s->toAlias(); - - // Find out which field index it is - for (fieldi = 0; 1; fieldi++) - { - if (fieldi >= nfields) - { - error(loc, "%s.%s is not a per-instance initializable field", - t->toChars(), s->toChars()); - errors = 1; - break; - } - if (s == ad->fields[fieldi]) - break; - } - } - if (s && (v = s->isVarDeclaration()) != NULL) - { - val = val->semantic(sc, v->type, needInterpret); - value[i] = val; - vars[i] = v; - } - else - { error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars()); - errors = 1; - } - fieldi++; - } - } - else if (t->ty == Tdelegate && value.dim == 0) - { /* Rewrite as empty delegate literal { } - */ - Parameters *arguments = new Parameters; - Type *tf = new TypeFunction(arguments, NULL, 0, LINKd); - FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL); - fd->fbody = new CompoundStatement(loc, new Statements()); - fd->endloc = loc; - Expression *e = new FuncExp(loc, fd); - ExpInitializer *ie = new ExpInitializer(loc, e); - return ie->semantic(sc, t, needInterpret); - } - else - { - error(loc, "a struct is not a valid initializer for a %s", t->toChars()); - errors = 1; - } - if (errors) - { - field.setDim(0); - value.setDim(0); - vars.setDim(0); - } - return this; -} - -/*************************************** - * This works by transforming a struct initializer into - * a struct literal. In the future, the two should be the - * same thing. - */ -Expression *StructInitializer::toExpression() -{ Expression *e; - - //printf("StructInitializer::toExpression() %s\n", toChars()); - if (!ad) // if fwd referenced - { - return NULL; - } - StructDeclaration *sd = ad->isStructDeclaration(); - if (!sd) - return NULL; - Expressions *elements = new Expressions(); - size_t nfields = ad->fields.dim; -#if DMDV2 - if (sd->isnested) - nfields--; -#endif - elements->setDim(nfields); - for (size_t i = 0; i < elements->dim; i++) - { - (*elements)[i] = NULL; - } - unsigned fieldi = 0; - for (size_t i = 0; i < value.dim; i++) - { - Identifier *id = field[i]; - if (id) - { - Dsymbol * s = ad->search(loc, id, 0); - if (!s) - { - error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); - goto Lno; - } - s = s->toAlias(); - - // Find out which field index it is - for (fieldi = 0; 1; fieldi++) - { - if (fieldi >= nfields) - { - s->error("is not a per-instance initializable field"); - goto Lno; - } - if (s == ad->fields[fieldi]) - break; - } - } - else if (fieldi >= nfields) - { error(loc, "too many initializers for '%s'", ad->toChars()); - goto Lno; - } - Initializer *iz = value[i]; - if (!iz) - goto Lno; - Expression *ex = iz->toExpression(); - if (!ex) - goto Lno; - if ((*elements)[fieldi]) - { error(loc, "duplicate initializer for field '%s'", - ad->fields[fieldi]->toChars()); - goto Lno; - } - (*elements)[fieldi] = ex; - ++fieldi; - } - // Now, fill in any missing elements with default initializers. - // We also need to validate any anonymous unions - for (size_t i = 0; i < elements->dim; ) - { - VarDeclaration * vd = ad->fields[i]->isVarDeclaration(); - int unionSize = ad->numFieldsInUnion(i); - if (unionSize == 1) - { // Not a union -- default initialize if missing - if (!(*elements)[i]) - { // Default initialize - if (vd->init) - (*elements)[i] = vd->init->toExpression(); - else - (*elements)[i] = vd->type->defaultInit(); - } - } - else - { // anonymous union -- check for errors - int found = -1; // index of the first field with an initializer - for (size_t j = i; j < i + unionSize; ++j) - { - if (!(*elements)[j]) - continue; - if (found >= 0) - { - VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration(); - VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration(); - error(loc, "%s cannot have initializers for fields %s and %s in same union", - ad->toChars(), - v1->toChars(), v->toChars()); - goto Lno; - } - found = j; - } - if (found == -1) - { - error(loc, "no initializer for union that contains field %s", - vd->toChars()); - goto Lno; - } - } - i += unionSize; - } - e = new StructLiteralExp(loc, sd, elements); - e->type = sd->type; - return e; - -Lno: - delete elements; - return NULL; -} - - -void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("StructInitializer::toCBuffer()\n"); - buf->writebyte('{'); - for (size_t i = 0; i < field.dim; i++) - { - if (i > 0) - buf->writebyte(','); - Identifier *id = field[i]; - if (id) - { - buf->writestring(id->toChars()); - buf->writebyte(':'); - } - Initializer *iz = value[i]; - if (iz) - iz->toCBuffer(buf, hgs); - } - buf->writebyte('}'); -} - -/********************************** ArrayInitializer ************************************/ - -ArrayInitializer::ArrayInitializer(Loc loc) - : Initializer(loc) -{ - dim = 0; - type = NULL; - sem = 0; -} - -Initializer *ArrayInitializer::syntaxCopy() -{ - //printf("ArrayInitializer::syntaxCopy()\n"); - - ArrayInitializer *ai = new ArrayInitializer(loc); - - assert(index.dim == value.dim); - ai->index.setDim(index.dim); - ai->value.setDim(value.dim); - for (size_t i = 0; i < ai->value.dim; i++) - { Expression *e = index[i]; - if (e) - e = e->syntaxCopy(); - ai->index[i] = e; - - Initializer *init = value[i]; - init = init->syntaxCopy(); - ai->value[i] = init; - } - return ai; -} - -void ArrayInitializer::addInit(Expression *index, Initializer *value) -{ - this->index.push(index); - this->value.push(value); - dim = 0; - type = NULL; -} - -Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) -{ unsigned i; - unsigned length; - const unsigned amax = 0x80000000; - - //printf("ArrayInitializer::semantic(%s)\n", t->toChars()); - if (sem) // if semantic() already run - return this; - sem = 1; - type = t; - t = t->toBasetype(); - switch (t->ty) - { - case Tpointer: - case Tsarray: - case Tarray: - break; - - default: - error(loc, "cannot use array to initialize %s", type->toChars()); - goto Lerr; - } - - length = 0; - for (i = 0; i < index.dim; i++) - { - Expression *idx = index[i]; - if (idx) - { idx = idx->semantic(sc); - idx = idx->ctfeInterpret(); - index[i] = idx; - length = idx->toInteger(); - } - - Initializer *val = value[i]; - ExpInitializer *ei = val->isExpInitializer(); - if (ei && !idx) - ei->expandTuples = 1; - val = val->semantic(sc, t->nextOf(), needInterpret); - - ei = val->isExpInitializer(); - // found a tuple, expand it - if (ei && ei->exp->op == TOKtuple) - { - TupleExp *te = (TupleExp *)ei->exp; - index.remove(i); - value.remove(i); - - for (size_t j = 0; j < te->exps->dim; ++j) - { - Expression *e = (*te->exps)[j]; - index.insert(i + j, (Expression *)NULL); - value.insert(i + j, new ExpInitializer(e->loc, e)); - } - i--; - continue; - } - else - { - value[i] = val; - } - - length++; - if (length == 0) - { error(loc, "array dimension overflow"); - goto Lerr; - } - if (length > dim) - dim = length; - } - if (t->ty == Tsarray) - { - dinteger_t edim = ((TypeSArray *)t)->dim->toInteger(); - if (dim > edim) - { - error(loc, "array initializer has %u elements, but array length is %jd", dim, edim); - goto Lerr; - } - } - - if ((unsigned long) dim * t->nextOf()->size() >= amax) - { error(loc, "array dimension %u exceeds max of %u", dim, amax / t->nextOf()->size()); - goto Lerr; - } - return this; - -Lerr: - return new ExpInitializer(loc, new ErrorExp()); -} - -/******************************** - * If possible, convert array initializer to array literal. - */ - -Expression *ArrayInitializer::toExpression() -{ Expressions *elements; - - //printf("ArrayInitializer::toExpression(), dim = %d\n", dim); - //static int i; if (++i == 2) halt(); - - size_t edim; - Type *t = NULL; - if (type) - { - if (type == Type::terror) - return new ErrorExp(); - - t = type->toBasetype(); - switch (t->ty) - { - case Tsarray: - edim = ((TypeSArray *)t)->dim->toInteger(); - break; - - case Tpointer: - case Tarray: - edim = dim; - break; - - default: - assert(0); - } - } - else - { - edim = value.dim; - for (size_t i = 0, j = 0; i < value.dim; i++, j++) - { - if (index[i]) - j = index[i]->toInteger(); - if (j >= edim) - edim = j + 1; - } - } - - elements = new Expressions(); - elements->setDim(edim); - elements->zero(); - for (size_t i = 0, j = 0; i < value.dim; i++, j++) - { - if (index[i]) - j = (index[i])->toInteger(); - assert(j < edim); - Initializer *iz = value[i]; - if (!iz) - goto Lno; - Expression *ex = iz->toExpression(); - if (!ex) - { - goto Lno; - } - (*elements)[j] = ex; - } - - /* Fill in any missing elements with the default initializer - */ - { - Expression *init = NULL; - for (size_t i = 0; i < edim; i++) - { - if (!(*elements)[i]) - { - if (!type) - goto Lno; - if (!init) - init = t->next->defaultInit(); - (*elements)[i] = init; - } - } - - Expression *e = new ArrayLiteralExp(loc, elements); - e->type = type; - return e; - } - -Lno: - delete elements; - error(loc, "array initializers as expressions are not allowed"); - return new ErrorExp(); -} - - -/******************************** - * If possible, convert array initializer to associative array initializer. - */ - -Initializer *ArrayInitializer::toAssocArrayInitializer() -{ - Expression *e; - - //printf("ArrayInitializer::toAssocArrayInitializer()\n"); - //static int i; if (++i == 2) halt(); - Expressions *keys = new Expressions(); - keys->setDim(value.dim); - Expressions *values = new Expressions(); - values->setDim(value.dim); - - for (size_t i = 0; i < value.dim; i++) - { - e = index[i]; - if (!e) - goto Lno; - (*keys)[i] = e; - - Initializer *iz = value[i]; - if (!iz) - goto Lno; - e = iz->toExpression(); - if (!e) - goto Lno; - (*values)[i] = e; - } - e = new AssocArrayLiteralExp(loc, keys, values); - return new ExpInitializer(loc, e); - -Lno: - delete keys; - delete values; - error(loc, "not an associative array initializer"); - return this; -} - - -Type *ArrayInitializer::inferType(Scope *sc) -{ - for (size_t i = 0; i < value.dim; i++) - { - if (index.data[i]) - goto Laa; - } - if (value.dim) - { - Initializer *iz = (Initializer *)value.data[0]; - if (iz) - { Type *t = iz->inferType(sc); - t = new TypeSArray(t, new IntegerExp(value.dim)); - t = t->semantic(loc, sc); - return t; - } - } - -Laa: - /* It's possibly an associative array initializer - */ - Initializer *iz = (Initializer *)value.data[0]; - Expression *indexinit = (Expression *)index.data[0]; - if (iz && indexinit) - { Type *t = iz->inferType(sc); - indexinit = indexinit->semantic(sc); - Type *indext = indexinit->type; - t = new TypeAArray(t, indext); - type = t->semantic(loc, sc); - } - else - error(loc, "cannot infer type from this array initializer"); - return type; -} - - -void ArrayInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writebyte('['); - for (size_t i = 0; i < index.dim; i++) - { - if (i > 0) - buf->writebyte(','); - Expression *ex = index[i]; - if (ex) - { - ex->toCBuffer(buf, hgs); - buf->writebyte(':'); - } - Initializer *iz = value[i]; - if (iz) - iz->toCBuffer(buf, hgs); - } - buf->writebyte(']'); -} - - -/********************************** ExpInitializer ************************************/ - -ExpInitializer::ExpInitializer(Loc loc, Expression *exp) - : Initializer(loc) -{ - this->exp = exp; - this->expandTuples = 0; -} - -Initializer *ExpInitializer::syntaxCopy() -{ - return new ExpInitializer(loc, exp->syntaxCopy()); -} - -Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) -{ - //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); - exp = exp->semantic(sc); - if (exp->op == TOKerror) - return this; - - int olderrors = global.errors; - if (needInterpret) - exp = exp->ctfeInterpret(); - else - exp = exp->optimize(WANTvalue); - if (!global.gag && olderrors != global.errors) - return this; // Failed, suppress duplicate error messages - - if (exp->op == TOKtype) - exp->error("initializer must be an expression, not '%s'", exp->toChars()); - Type *tb = t->toBasetype(); - - if (exp->op == TOKtuple && - expandTuples && - !exp->implicitConvTo(t)) - return new ExpInitializer(loc, exp); - - /* Look for case of initializing a static array with a too-short - * string literal, such as: - * char[5] foo = "abc"; - * Allow this by doing an explicit cast, which will lengthen the string - * literal. - */ - if (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray) - { StringExp *se = (StringExp *)exp; - - if (!se->committed && se->type->ty == Tsarray && - ((TypeSArray *)se->type)->dim->toInteger() < - ((TypeSArray *)t)->dim->toInteger()) - { - exp = se->castTo(sc, t); - goto L1; - } - } - - // Look for the case of statically initializing an array - // with a single member. - if (tb->ty == Tsarray && - !tb->nextOf()->equals(exp->type->toBasetype()->nextOf()) && - exp->implicitConvTo(tb->nextOf()) - ) - { - t = tb->nextOf(); - } - - exp = exp->implicitCastTo(sc, t); - if (exp->op == TOKerror) - return this; -L1: - if (needInterpret) - exp = exp->ctfeInterpret(); - else - exp = exp->optimize(WANTvalue); - //printf("-ExpInitializer::semantic(): "); exp->print(); - return this; -} - -Type *ExpInitializer::inferType(Scope *sc) -{ - //printf("ExpInitializer::inferType() %s\n", toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - - // Give error for overloaded function addresses - if (exp->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)exp; - if ( -#if DMDV2 - se->hasOverloads && -#else - se->var->isFuncDeclaration() && -#endif - !se->var->isFuncDeclaration()->isUnique()) - exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); - } - - // Give error for overloaded function addresses - if (exp->op == TOKdelegate) - { DelegateExp *se = (DelegateExp *)exp; - if (se->hasOverloads && - se->func->isFuncDeclaration() && - !se->func->isFuncDeclaration()->isUnique()) - exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); - } - - Type *t = exp->type; - if (!t) - t = Initializer::inferType(sc); - return t; -} - -Expression *ExpInitializer::toExpression() -{ - return exp; -} - - -void ExpInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - exp->toCBuffer(buf, hgs); -} - - - diff --git a/dmd/init.h b/dmd/init.h deleted file mode 100644 index 08503335..00000000 --- a/dmd/init.h +++ /dev/null @@ -1,149 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef INIT_H -#define INIT_H - -#include "root.h" - -#include "mars.h" -#include "arraytypes.h" - -struct Identifier; -struct Expression; -struct Scope; -struct Type; -struct dt_t; -struct AggregateDeclaration; -struct VoidInitializer; -struct StructInitializer; -struct ArrayInitializer; -struct ExpInitializer; -struct HdrGenState; - -enum NeedInterpret { INITnointerpret, INITinterpret }; - -#if IN_LLVM -namespace llvm { - class StructType; -} -#endif - -struct Initializer : Object -{ - Loc loc; - - Initializer(Loc loc); - virtual Initializer *syntaxCopy(); - virtual Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); - virtual Type *inferType(Scope *sc); - virtual Expression *toExpression() = 0; - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; - char *toChars(); - - static Initializers *arraySyntaxCopy(Initializers *ai); - -#if IN_DMD - virtual dt_t *toDt(); -#endif - - virtual VoidInitializer *isVoidInitializer() { return NULL; } - virtual StructInitializer *isStructInitializer() { return NULL; } - virtual ArrayInitializer *isArrayInitializer() { return NULL; } - virtual ExpInitializer *isExpInitializer() { return NULL; } -}; - -struct VoidInitializer : Initializer -{ - Type *type; // type that this will initialize to - - VoidInitializer(Loc loc); - Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); - Expression *toExpression(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); -#endif - - virtual VoidInitializer *isVoidInitializer() { return this; } -}; - -struct StructInitializer : Initializer -{ - Identifiers field; // of Identifier *'s - Initializers value; // parallel array of Initializer *'s - - VarDeclarations vars; // parallel array of VarDeclaration *'s - AggregateDeclaration *ad; // which aggregate this is for - - StructInitializer(Loc loc); - Initializer *syntaxCopy(); - void addInit(Identifier *field, Initializer *value); - Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); - Expression *toExpression(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); -#endif - - StructInitializer *isStructInitializer() { return this; } -#if IN_LLVM - llvm::StructType *ltype; -#endif -}; - -struct ArrayInitializer : Initializer -{ - Expressions index; // indices - Initializers value; // of Initializer *'s - unsigned dim; // length of array being initialized - Type *type; // type that array will be used to initialize - int sem; // !=0 if semantic() is run - - ArrayInitializer(Loc loc); - Initializer *syntaxCopy(); - void addInit(Expression *index, Initializer *value); - Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); - Type *inferType(Scope *sc); - Expression *toExpression(); - Initializer *toAssocArrayInitializer(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); - dt_t *toDtBit(); // for bit arrays -#endif - - ArrayInitializer *isArrayInitializer() { return this; } -}; - -struct ExpInitializer : Initializer -{ - Expression *exp; - int expandTuples; - - ExpInitializer(Loc loc, Expression *exp); - Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); - Type *inferType(Scope *sc); - Expression *toExpression(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); -#endif - - virtual ExpInitializer *isExpInitializer() { return this; } -}; - -#endif diff --git a/dmd/inline.c b/dmd/inline.c deleted file mode 100644 index 78438659..00000000 --- a/dmd/inline.c +++ /dev/null @@ -1,1825 +0,0 @@ - -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Routines to perform function inlining - -#define LOG 0 - -#include -#include -#include -#include // memset() - -#include "id.h" -#include "init.h" -#include "declaration.h" -#include "aggregate.h" -#include "expression.h" -#include "statement.h" -#include "mtype.h" -#include "scope.h" - -/* ========== Compute cost of inlining =============== */ - -/* Walk trees to determine if inlining can be done, and if so, - * if it is too complex to be worth inlining or not. - */ - -struct InlineCostState -{ - int nested; - int hasthis; - int hdrscan; // !=0 if inline scan for 'header' content - FuncDeclaration *fd; -}; - -const int COST_MAX = 250; -const int STATEMENT_COST = 0x1000; -const int STATEMENT_COST_MAX = 250 * 0x1000; - -// STATEMENT_COST be power of 2 and greater than COST_MAX -//static assert((STATEMENT_COST & (STATEMENT_COST - 1)) == 0); -//static assert(STATEMENT_COST > COST_MAX); - -bool tooCostly(int cost) { return ((cost & (STATEMENT_COST - 1)) >= COST_MAX); } - -int expressionInlineCost(Expression *e, InlineCostState *ics); - -int Statement::inlineCost(InlineCostState *ics) -{ - //printf("Statement::inlineCost = %d\n", COST_MAX); - //printf("%p\n", isScopeStatement()); - //printf("%s\n", toChars()); - return COST_MAX; // default is we can't inline it -} - -int ExpStatement::inlineCost(InlineCostState *ics) -{ - return expressionInlineCost(exp, ics); - //return exp ? exp->inlineCost(ics) : 0; -} - -int CompoundStatement::inlineCost(InlineCostState *ics) -{ int cost = 0; - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - cost += s->inlineCost(ics); - if (tooCostly(cost)) - break; - } - } - //printf("CompoundStatement::inlineCost = %d\n", cost); - return cost; -} - -int UnrolledLoopStatement::inlineCost(InlineCostState *ics) -{ int cost = 0; - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - cost += s->inlineCost(ics); - if (tooCostly(cost)) - break; - } - } - return cost; -} - -int ScopeStatement::inlineCost(InlineCostState *ics) -{ - return statement ? 1 + statement->inlineCost(ics) : 1; -} - -int IfStatement::inlineCost(InlineCostState *ics) -{ - int cost; - -#if !IN_LLVM - /* Can't declare variables inside ?: expressions, so - * we cannot inline if a variable is declared. - */ - if (arg) - return COST_MAX; -#endif - - cost = expressionInlineCost(condition, ics); - -#if !IN_LLVM - /* Specifically allow: - * if (condition) - * return exp1; - * else - * return exp2; - * Otherwise, we can't handle return statements nested in if's. - */ - - if (elsebody && ifbody && - ifbody->isReturnStatement() && - elsebody->isReturnStatement()) - { - cost += ifbody->inlineCost(ics); - cost += elsebody->inlineCost(ics); - //printf("cost = %d\n", cost); - } - else -#endif - { - ics->nested += 1; - if (ifbody) - cost += ifbody->inlineCost(ics); - if (elsebody) - cost += elsebody->inlineCost(ics); - ics->nested -= 1; - } - //printf("IfStatement::inlineCost = %d\n", cost); - return cost; -} - -int ReturnStatement::inlineCost(InlineCostState *ics) -{ -#if !IN_LLVM - // Can't handle return statements nested in if's - if (ics->nested) - return COST_MAX; -#endif - return expressionInlineCost(exp, ics); -} - -#if DMDV2 -int ImportStatement::inlineCost(InlineCostState *ics) -{ - return 0; -} -#endif - -int ForStatement::inlineCost(InlineCostState *ics) -{ - //return COST_MAX; - int cost = STATEMENT_COST; - if (init) - cost += init->inlineCost(ics); - if (condition) - cost += expressionInlineCost(condition, ics); - if (increment) - cost += expressionInlineCost(increment, ics); - if (body) - cost += body->inlineCost(ics); - //printf("ForStatement: inlineCost = %d\n", cost); - return cost; -} - - -/* -------------------------- */ - -struct ICS2 -{ - int cost; - InlineCostState *ics; -}; - -int lambdaInlineCost(Expression *e, void *param) -{ - ICS2 *ics2 = (ICS2 *)param; - ics2->cost += e->inlineCost3(ics2->ics); - return (ics2->cost >= COST_MAX); -} - -int expressionInlineCost(Expression *e, InlineCostState *ics) -{ - //printf("expressionInlineCost()\n"); - //e->dump(0); - ICS2 ics2; - ics2.cost = 0; - ics2.ics = ics; - if (e) - e->apply(&lambdaInlineCost, &ics2); - return ics2.cost; -} - -int Expression::inlineCost3(InlineCostState *ics) -{ - return 1; -} - -int ThisExp::inlineCost3(InlineCostState *ics) -{ -#if !IN_LLVM - //printf("ThisExp::inlineCost3() %s\n", toChars()); - FuncDeclaration *fd = ics->fd; - if (!fd) - return COST_MAX; - if (!ics->hdrscan) - if (fd->isNested() || !ics->hasthis) - return COST_MAX; -#endif - return 1; -} - -int StructLiteralExp::inlineCost3(InlineCostState *ics) -{ - //printf("StructLiteralExp::inlineCost3() %s\n", toChars()); -#if DMDV2 - if (sd->isnested) - return COST_MAX; -#endif - return 1; -} - -int FuncExp::inlineCost3(InlineCostState *ics) -{ - //printf("FuncExp::inlineCost3()\n"); - // This breaks on LDC too, since nested functions have internal linkage - // and thus can't be referenced from other objects. - // Right now, this makes the function be output to the .obj file twice. - return COST_MAX; -} - -int DelegateExp::inlineCost3(InlineCostState *ics) -{ - //printf("DelegateExp::inlineCost3()\n"); - // This breaks on LDC too, since nested functions have internal linkage - // and thus can't be referenced from other objects. - return COST_MAX; -} - -int DeclarationExp::inlineCost3(InlineCostState *ics) -{ int cost = 0; - VarDeclaration *vd; - - //printf("DeclarationExp::inlineCost3()\n"); - vd = declaration->isVarDeclaration(); - if (vd) - { - TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); - if (td) - { -#if 1 - return COST_MAX; // finish DeclarationExp::doInline -#else - for (size_t i = 0; i < td->objects->dim; i++) - { Object *o = (*td->objects)[i]; - if (o->dyncast() != DYNCAST_EXPRESSION) - return COST_MAX; - Expression *eo = (Expression *)o; - if (eo->op != TOKdsymbol) - return COST_MAX; - } - return td->objects->dim; -#endif - } - // This breaks on LDC too, since nested static variables have internal - // linkage and thus can't be referenced from other objects. - if (!ics->hdrscan && vd->isDataseg()) - return COST_MAX; - cost += 1; - -#if DMDV2 - if (vd->edtor) // if destructor required - return COST_MAX; // needs work to make this work -#endif - // Scan initializer (vd->init) - if (vd->init) - { - ExpInitializer *ie = vd->init->isExpInitializer(); - - if (ie) - { - cost += expressionInlineCost(ie->exp, ics); - } - } - } - - // These can contain functions, which when copied, get output twice. - // These break on LDC too, since nested static variables and functions have - // internal linkage and thus can't be referenced from other objects. - if (declaration->isStructDeclaration() || - declaration->isClassDeclaration() || - declaration->isFuncDeclaration() || - declaration->isTypedefDeclaration() || -#if DMDV2 - declaration->isAttribDeclaration() || -#endif - declaration->isTemplateMixin()) - return COST_MAX; - - //printf("DeclarationExp::inlineCost3('%s')\n", toChars()); - return cost; -} - -int CallExp::inlineCost3(InlineCostState *ics) -{ - //printf("CallExp::inlineCost3() %s\n", toChars()); - // Bugzilla 3500: super.func() calls must be devirtualized, and the inliner - // can't handle that at present. - if (e1->op == TOKdotvar && ((DotVarExp *)e1)->e1->op == TOKsuper) - return COST_MAX; - - return 1; -} - - -/* ======================== Perform the inlining ============================== */ - -/* Inlining is done by: - * o Converting to an Expression - * o Copying the trees of the function to be inlined - * o Renaming the variables - */ - -struct InlineDoState -{ - VarDeclaration *vthis; - Dsymbols from; // old Dsymbols - Dsymbols to; // parallel array of new Dsymbols - Dsymbol *parent; // new parent - FuncDeclaration *fd; // function being inlined (old parent) -}; - -/* -------------------------------------------------------------------- */ - -Statement *Statement::doInlineStatement(InlineDoState *ids) -{ - assert(0); - return NULL; // default is we can't inline it -} - -Statement *ExpStatement::doInlineStatement(InlineDoState *ids) -{ -#if LOG - if (exp) printf("ExpStatement::doInlineStatement() '%s'\n", exp->toChars()); -#endif - return new ExpStatement(loc, exp ? exp->doInline(ids) : NULL); -} - -Statement *CompoundStatement::doInlineStatement(InlineDoState *ids) -{ - //printf("CompoundStatement::doInlineStatement() %d\n", statements->dim); - Statements *as = new Statements(); - as->reserve(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - as->push(s->doInlineStatement(ids)); - if (s->isReturnStatement()) - break; - - /* Check for: - * if (condition) - * return exp1; - * else - * return exp2; - */ - IfStatement *ifs = s->isIfStatement(); - if (ifs && ifs->elsebody && ifs->ifbody && - ifs->ifbody->isReturnStatement() && - ifs->elsebody->isReturnStatement() - ) - break; - } - else - as->push(NULL); - } - return new CompoundStatement(loc, as); -} - -Statement *UnrolledLoopStatement::doInlineStatement(InlineDoState *ids) -{ - //printf("UnrolledLoopStatement::doInlineStatement() %d\n", statements->dim); - Statements *as = new Statements(); - as->reserve(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - as->push(s->doInlineStatement(ids)); - if (s->isReturnStatement()) - break; - } - else - as->push(NULL); - } - return new UnrolledLoopStatement(loc, as); -} - -Statement *ScopeStatement::doInlineStatement(InlineDoState *ids) -{ - //printf("ScopeStatement::doInlineStatement() %d\n", statements->dim); - return statement ? new ScopeStatement(loc, statement->doInlineStatement(ids)) : this; -} - -Statement *IfStatement::doInlineStatement(InlineDoState *ids) -{ - assert(!arg); - - Expression *condition = this->condition ? this->condition->doInline(ids) : NULL; - Statement *ifbody = this->ifbody ? this->ifbody->doInlineStatement(ids) : NULL; - Statement *elsebody = this->elsebody ? this->elsebody->doInlineStatement(ids) : NULL; - - return new IfStatement(loc, arg, condition, ifbody, elsebody); -} - -Statement *ReturnStatement::doInlineStatement(InlineDoState *ids) -{ - //printf("ReturnStatement::doInlineStatement() '%s'\n", exp ? exp->toChars() : ""); - return new ReturnStatement(loc, exp ? exp->doInline(ids) : NULL); -} - -#if DMDV2 -Statement *ImportStatement::doInlineStatement(InlineDoState *ids) -{ - return NULL; -} -#endif - -Statement *ForStatement::doInlineStatement(InlineDoState *ids) -{ - //printf("ForStatement::doInlineStatement()\n"); - Statement *init = this->init ? this->init->doInlineStatement(ids) : NULL; - Expression *condition = this->condition ? this->condition->doInline(ids) : NULL; - Expression *increment = this->increment ? this->increment->doInline(ids) : NULL; - Statement *body = this->body ? this->body->doInlineStatement(ids) : NULL; - return new ForStatement(loc, init, condition, increment, body); -} - -/* -------------------------------------------------------------------- */ - -Expression *Statement::doInline(InlineDoState *ids) -{ - printf("Statement::doInline()\n%s\n", toChars()); - fflush(stdout); - assert(0); - return NULL; // default is we can't inline it -} - -Expression *ExpStatement::doInline(InlineDoState *ids) -{ -#if LOG - if (exp) printf("ExpStatement::doInline() '%s'\n", exp->toChars()); -#endif - return exp ? exp->doInline(ids) : NULL; -} - -Expression *CompoundStatement::doInline(InlineDoState *ids) -{ - Expression *e = NULL; - - //printf("CompoundStatement::doInline() %d\n", statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - Expression *e2 = s->doInline(ids); - e = Expression::combine(e, e2); - if (s->isReturnStatement()) - break; - - /* Check for: - * if (condition) - * return exp1; - * else - * return exp2; - */ - IfStatement *ifs = s->isIfStatement(); - if (ifs && ifs->elsebody && ifs->ifbody && - ifs->ifbody->isReturnStatement() && - ifs->elsebody->isReturnStatement() - ) - break; - - } - } - return e; -} - -Expression *UnrolledLoopStatement::doInline(InlineDoState *ids) -{ - Expression *e = NULL; - - //printf("UnrolledLoopStatement::doInline() %d\n", statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - Expression *e2 = s->doInline(ids); - e = Expression::combine(e, e2); - if (s->isReturnStatement()) - break; - } - } - return e; -} - -Expression *ScopeStatement::doInline(InlineDoState *ids) -{ - return statement ? statement->doInline(ids) : NULL; -} - -Expression *IfStatement::doInline(InlineDoState *ids) -{ - Expression *econd; - Expression *e1; - Expression *e2; - Expression *e; - - assert(!arg); - econd = condition->doInline(ids); - assert(econd); - if (ifbody) - e1 = ifbody->doInline(ids); - else - e1 = NULL; - if (elsebody) - e2 = elsebody->doInline(ids); - else - e2 = NULL; - if (e1 && e2) - { - e = new CondExp(econd->loc, econd, e1, e2); - e->type = e1->type; - } - else if (e1) - { - e = new AndAndExp(econd->loc, econd, e1); - e->type = Type::tvoid; - } - else if (e2) - { - e = new OrOrExp(econd->loc, econd, e2); - e->type = Type::tvoid; - } - else - { - e = econd; - } - return e; -} - -Expression *ReturnStatement::doInline(InlineDoState *ids) -{ - //printf("ReturnStatement::doInline() '%s'\n", exp ? exp->toChars() : ""); - return exp ? exp->doInline(ids) : 0; -} - -#if DMDV2 -Expression *ImportStatement::doInline(InlineDoState *ids) -{ - return NULL; -} -#endif - -/* --------------------------------------------------------------- */ - -/****************************** - * Perform doInline() on an array of Expressions. - */ - -Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids) -{ Expressions *newa = NULL; - - if (a) - { - newa = new Expressions(); - newa->setDim(a->dim); - - for (size_t i = 0; i < a->dim; i++) - { Expression *e = a->tdata()[i]; - - if (e) - e = e->doInline(ids); - newa->tdata()[i] = e; - } - } - return newa; -} - -Expression *Expression::doInline(InlineDoState *ids) -{ - //printf("Expression::doInline(%s): %s\n", Token::toChars(op), toChars()); - return copy(); -} - -Expression *SymOffExp::doInline(InlineDoState *ids) -{ - //printf("SymOffExp::doInline(%s)\n", toChars()); - for (size_t i = 0; i < ids->from.dim; i++) - { - if (var == ids->from.tdata()[i]) - { - SymOffExp *se = (SymOffExp *)copy(); - - se->var = (Declaration *)ids->to.tdata()[i]; - return se; - } - } - return this; -} - -Expression *VarExp::doInline(InlineDoState *ids) -{ - //printf("VarExp::doInline(%s)\n", toChars()); - for (size_t i = 0; i < ids->from.dim; i++) - { - if (var == ids->from.tdata()[i]) - { - VarExp *ve = (VarExp *)copy(); - - ve->var = (Declaration *)ids->to.tdata()[i]; - return ve; - } - } - return this; -} - -Expression *ThisExp::doInline(InlineDoState *ids) -{ - //if (!ids->vthis) - //error("no 'this' when inlining %s", ids->parent->toChars()); - if (!ids->vthis) - { - return this; - } - - VarExp *ve = new VarExp(loc, ids->vthis); - ve->type = type; - return ve; -} - -Expression *SuperExp::doInline(InlineDoState *ids) -{ - assert(ids->vthis); - - VarExp *ve = new VarExp(loc, ids->vthis); - ve->type = type; - return ve; -} - -Expression *DeclarationExp::doInline(InlineDoState *ids) -{ DeclarationExp *de = (DeclarationExp *)copy(); - VarDeclaration *vd; - - //printf("DeclarationExp::doInline(%s)\n", toChars()); - vd = declaration->isVarDeclaration(); - if (vd) - { -#if 0 - // Need to figure this out before inlining can work for tuples - TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); - if (td) - { - for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = td->objects->tdata()[i]; - assert(se->op == TOKdsymbol); - se->s; - } - return st->objects->dim; - } -#endif - if (vd->isStatic() || vd->isConst()) - ; - else - { - VarDeclaration *vto; - - vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; - vto->parent = ids->parent; -#if IN_DMD - vto->csym = NULL; - vto->isym = NULL; -#endif - - ids->from.push(vd); - ids->to.push(vto); - - if (vd->init) - { - if (vd->init->isVoidInitializer()) - { - vto->init = new VoidInitializer(vd->init->loc); - } - else - { - ExpInitializer *ie = vd->init->isExpInitializer(); - assert(ie); - vto->init = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); - } - } - de->declaration = (Dsymbol *) (void *)vto; - } - } - /* This needs work, like DeclarationExp::toElem(), if we are - * to handle TemplateMixin's. For now, we just don't inline them. - */ - return de; -} - -Expression *NewExp::doInline(InlineDoState *ids) -{ - //printf("NewExp::doInline(): %s\n", toChars()); - NewExp *ne = (NewExp *)copy(); - - if (thisexp) - ne->thisexp = thisexp->doInline(ids); - ne->newargs = arrayExpressiondoInline(ne->newargs, ids); - ne->arguments = arrayExpressiondoInline(ne->arguments, ids); - return ne; -} - -Expression *UnaExp::doInline(InlineDoState *ids) -{ - UnaExp *ue = (UnaExp *)copy(); - - ue->e1 = e1->doInline(ids); - return ue; -} - -Expression *AssertExp::doInline(InlineDoState *ids) -{ - AssertExp *ae = (AssertExp *)copy(); - - ae->e1 = e1->doInline(ids); - if (msg) - ae->msg = msg->doInline(ids); - return ae; -} - -Expression *BinExp::doInline(InlineDoState *ids) -{ - BinExp *be = (BinExp *)copy(); - - be->e1 = e1->doInline(ids); - be->e2 = e2->doInline(ids); - return be; -} - -Expression *CallExp::doInline(InlineDoState *ids) -{ - CallExp *ce; - - ce = (CallExp *)copy(); - ce->e1 = e1->doInline(ids); - ce->arguments = arrayExpressiondoInline(arguments, ids); - return ce; -} - - -Expression *IndexExp::doInline(InlineDoState *ids) -{ - IndexExp *are = (IndexExp *)copy(); - - are->e1 = e1->doInline(ids); - - if (lengthVar) - { //printf("lengthVar\n"); - VarDeclaration *vd = lengthVar; - ExpInitializer *ie; - ExpInitializer *ieto; - VarDeclaration *vto; - - vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; - vto->parent = ids->parent; -#if IN_DMD - vto->csym = NULL; - vto->isym = NULL; -#endif - - ids->from.push(vd); - ids->to.push(vto); - - if (vd->init && !vd->init->isVoidInitializer()) - { - ie = vd->init->isExpInitializer(); - assert(ie); - ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); - vto->init = ieto; - } - - are->lengthVar = (VarDeclaration *) (void *)vto; - } - are->e2 = e2->doInline(ids); - return are; -} - - -Expression *SliceExp::doInline(InlineDoState *ids) -{ - SliceExp *are = (SliceExp *)copy(); - - are->e1 = e1->doInline(ids); - - if (lengthVar) - { //printf("lengthVar\n"); - VarDeclaration *vd = lengthVar; - ExpInitializer *ie; - ExpInitializer *ieto; - VarDeclaration *vto; - - vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; - vto->parent = ids->parent; -#if IN_DMD - vto->csym = NULL; - vto->isym = NULL; -#endif - - ids->from.push(vd); - ids->to.push(vto); - - if (vd->init && !vd->init->isVoidInitializer()) - { - ie = vd->init->isExpInitializer(); - assert(ie); - ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); - vto->init = ieto; - } - - are->lengthVar = (VarDeclaration *) (void *)vto; - } - if (lwr) - are->lwr = lwr->doInline(ids); - if (upr) - are->upr = upr->doInline(ids); - return are; -} - - -Expression *TupleExp::doInline(InlineDoState *ids) -{ - TupleExp *ce; - - ce = (TupleExp *)copy(); - ce->exps = arrayExpressiondoInline(exps, ids); - return ce; -} - - -Expression *ArrayLiteralExp::doInline(InlineDoState *ids) -{ - ArrayLiteralExp *ce; - - ce = (ArrayLiteralExp *)copy(); - ce->elements = arrayExpressiondoInline(elements, ids); - return ce; -} - - -Expression *AssocArrayLiteralExp::doInline(InlineDoState *ids) -{ - AssocArrayLiteralExp *ce; - - ce = (AssocArrayLiteralExp *)copy(); - ce->keys = arrayExpressiondoInline(keys, ids); - ce->values = arrayExpressiondoInline(values, ids); - return ce; -} - - -Expression *StructLiteralExp::doInline(InlineDoState *ids) -{ - StructLiteralExp *ce; - - ce = (StructLiteralExp *)copy(); - ce->elements = arrayExpressiondoInline(elements, ids); - return ce; -} - - -Expression *ArrayExp::doInline(InlineDoState *ids) -{ - ArrayExp *ce; - - ce = (ArrayExp *)copy(); - ce->e1 = e1->doInline(ids); - ce->arguments = arrayExpressiondoInline(arguments, ids); - return ce; -} - - -Expression *CondExp::doInline(InlineDoState *ids) -{ - CondExp *ce = (CondExp *)copy(); - - ce->econd = econd->doInline(ids); - ce->e1 = e1->doInline(ids); - ce->e2 = e2->doInline(ids); - return ce; -} - - -/* ========== Walk the parse trees, and inline expand functions ============= */ - -/* Walk the trees, looking for functions to inline. - * Inline any that can be. - */ - -struct InlineScanState -{ - FuncDeclaration *fd; // function being scanned -}; - -Statement *Statement::inlineScan(InlineScanState *iss) -{ - return this; -} - -Statement *ExpStatement::inlineScan(InlineScanState *iss) -{ -#if LOG - printf("ExpStatement::inlineScan(%s)\n", toChars()); -#endif - if (exp) - { - exp = exp->inlineScan(iss); - - /* See if we can inline as a statement rather than as - * an Expression. - */ - if (exp && exp->op == TOKcall) - { - CallExp *ce = (CallExp *)exp; - if (ce->e1->op == TOKvar) - { - VarExp *ve = (VarExp *)ce->e1; - FuncDeclaration *fd = ve->var->isFuncDeclaration(); - - if (fd && fd != iss->fd && fd->canInline(0, 0, 1)) - { - Statement *s; - fd->expandInline(iss, NULL, ce->arguments, &s); - return s; - } - } - } - } - return this; -} - -Statement *CompoundStatement::inlineScan(InlineScanState *iss) -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - (*statements)[i] = s->inlineScan(iss); - } - return this; -} - -Statement *UnrolledLoopStatement::inlineScan(InlineScanState *iss) -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - (*statements)[i] = s->inlineScan(iss); - } - return this; -} - -Statement *ScopeStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - -Statement *WhileStatement::inlineScan(InlineScanState *iss) -{ - condition = condition->inlineScan(iss); - body = body ? body->inlineScan(iss) : NULL; - return this; -} - - -Statement *DoStatement::inlineScan(InlineScanState *iss) -{ - body = body ? body->inlineScan(iss) : NULL; - condition = condition->inlineScan(iss); - return this; -} - - -Statement *ForStatement::inlineScan(InlineScanState *iss) -{ - if (init) - init = init->inlineScan(iss); - if (condition) - condition = condition->inlineScan(iss); - if (increment) - increment = increment->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -Statement *ForeachStatement::inlineScan(InlineScanState *iss) -{ - aggr = aggr->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -#if DMDV2 -Statement *ForeachRangeStatement::inlineScan(InlineScanState *iss) -{ - lwr = lwr->inlineScan(iss); - upr = upr->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} -#endif - - -Statement *IfStatement::inlineScan(InlineScanState *iss) -{ - condition = condition->inlineScan(iss); - if (ifbody) - ifbody = ifbody->inlineScan(iss); - if (elsebody) - elsebody = elsebody->inlineScan(iss); - return this; -} - - -Statement *SwitchStatement::inlineScan(InlineScanState *iss) -{ - //printf("SwitchStatement::inlineScan()\n"); - condition = condition->inlineScan(iss); - body = body ? body->inlineScan(iss) : NULL; - if (sdefault) - sdefault = (DefaultStatement *)sdefault->inlineScan(iss); - if (cases) - { - for (size_t i = 0; i < cases->dim; i++) - { CaseStatement *s; - - s = cases->tdata()[i]; - cases->tdata()[i] = (CaseStatement *)s->inlineScan(iss); - } - } - return this; -} - - -Statement *CaseStatement::inlineScan(InlineScanState *iss) -{ - //printf("CaseStatement::inlineScan()\n"); - exp = exp->inlineScan(iss); - if (statement) - statement = statement->inlineScan(iss); - return this; -} - - -Statement *DefaultStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - - -Statement *ReturnStatement::inlineScan(InlineScanState *iss) -{ - //printf("ReturnStatement::inlineScan()\n"); - if (exp) - { - exp = exp->inlineScan(iss); - } - return this; -} - - -Statement *SynchronizedStatement::inlineScan(InlineScanState *iss) -{ - if (exp) - exp = exp->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -Statement *WithStatement::inlineScan(InlineScanState *iss) -{ - if (exp) - exp = exp->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -Statement *TryCatchStatement::inlineScan(InlineScanState *iss) -{ - if (body) - body = body->inlineScan(iss); - if (catches) - { - for (size_t i = 0; i < catches->dim; i++) - { Catch *c = catches->tdata()[i]; - - if (c->handler) - c->handler = c->handler->inlineScan(iss); - } - } - return this; -} - - -Statement *TryFinallyStatement::inlineScan(InlineScanState *iss) -{ - if (body) - body = body->inlineScan(iss); - if (finalbody) - finalbody = finalbody->inlineScan(iss); - return this; -} - - -Statement *ThrowStatement::inlineScan(InlineScanState *iss) -{ - if (exp) - exp = exp->inlineScan(iss); - return this; -} - - -Statement *VolatileStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - - -Statement *LabelStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - -/* -------------------------- */ - -void arrayInlineScan(InlineScanState *iss, Expressions *arguments) -{ - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; - - if (e) - { - e = e->inlineScan(iss); - arguments->tdata()[i] = e; - } - } - } -} - -Expression *Expression::inlineScan(InlineScanState *iss) -{ - return this; -} - -void scanVar(Dsymbol *s, InlineScanState *iss) -{ - VarDeclaration *vd = s->isVarDeclaration(); - if (vd) - { - TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); - if (td) - { - for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = (DsymbolExp *)td->objects->tdata()[i]; - assert(se->op == TOKdsymbol); - scanVar(se->s, iss); - } - } - else - { - // Scan initializer (vd->init) - if (vd->init) - { - ExpInitializer *ie = vd->init->isExpInitializer(); - - if (ie) - { -#if DMDV2 - if (vd->type) - { Type *tb = vd->type->toBasetype(); - if (tb->ty == Tstruct) - { StructDeclaration *sd = ((TypeStruct *)tb)->sym; - if (sd->cpctor) - { /* The problem here is that if the initializer is a - * function call that returns a struct S with a cpctor: - * S s = foo(); - * the postblit is done by the return statement in foo() - * in s2ir.c, the intermediate code generator. - * But, if foo() is inlined and now the code looks like: - * S s = x; - * the postblit is not there, because such assignments - * are rewritten as s.cpctor(&x) by the front end. - * So, the inlining won't get the postblit called. - * Work around by not inlining these cases. - * A proper fix would be to move all the postblit - * additions to the front end. - */ - return; - } - } - } -#endif - ie->exp = ie->exp->inlineScan(iss); - } - } - } - } -} - -Expression *DeclarationExp::inlineScan(InlineScanState *iss) -{ - //printf("DeclarationExp::inlineScan()\n"); - scanVar(declaration, iss); - return this; -} - -Expression *UnaExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - return this; -} - -Expression *AssertExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - if (msg) - msg = msg->inlineScan(iss); - return this; -} - -Expression *BinExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - e2 = e2->inlineScan(iss); - return this; -} - - -Expression *CallExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("CallExp::inlineScan()\n"); - e1 = e1->inlineScan(iss); - arrayInlineScan(iss, arguments); - - if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - FuncDeclaration *fd = ve->var->isFuncDeclaration(); - - if (fd && fd != iss->fd && fd->canInline(0, 0, 0)) - { - e = fd->expandInline(iss, NULL, arguments, NULL); - } - } - else if (e1->op == TOKdotvar) - { - DotVarExp *dve = (DotVarExp *)e1; - FuncDeclaration *fd = dve->var->isFuncDeclaration(); - - if (fd && fd != iss->fd && fd->canInline(1, 0, 0)) - { - if (dve->e1->op == TOKcall && - dve->e1->type->toBasetype()->ty == Tstruct) - { - /* To create ethis, we'll need to take the address - * of dve->e1, but this won't work if dve->e1 is - * a function call. - */ - ; - } - else - e = fd->expandInline(iss, dve->e1, arguments, NULL); - } - } - - return e; -} - - -Expression *SliceExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - if (lwr) - lwr = lwr->inlineScan(iss); - if (upr) - upr = upr->inlineScan(iss); - return this; -} - - -Expression *TupleExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("TupleExp::inlineScan()\n"); - arrayInlineScan(iss, exps); - - return e; -} - - -Expression *ArrayLiteralExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("ArrayLiteralExp::inlineScan()\n"); - arrayInlineScan(iss, elements); - - return e; -} - - -Expression *AssocArrayLiteralExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("AssocArrayLiteralExp::inlineScan()\n"); - arrayInlineScan(iss, keys); - arrayInlineScan(iss, values); - - return e; -} - - -Expression *StructLiteralExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("StructLiteralExp::inlineScan()\n"); - arrayInlineScan(iss, elements); - - return e; -} - - -Expression *ArrayExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("ArrayExp::inlineScan()\n"); - e1 = e1->inlineScan(iss); - arrayInlineScan(iss, arguments); - - return e; -} - - -Expression *CondExp::inlineScan(InlineScanState *iss) -{ - econd = econd->inlineScan(iss); - e1 = e1->inlineScan(iss); - e2 = e2->inlineScan(iss); - return this; -} - - -/* ========== =============== */ - -void FuncDeclaration::inlineScan() -{ - InlineScanState iss; - -#if LOG - printf("FuncDeclaration::inlineScan('%s')\n", toChars()); -#endif - memset(&iss, 0, sizeof(iss)); - iss.fd = this; - if (fbody && !naked) - { - inlineNest++; - fbody = fbody->inlineScan(&iss); - inlineNest--; - } -} - -int FuncDeclaration::canInline(int hasthis, int hdrscan, int statementsToo) -{ - InlineCostState ics; - int cost; - -#define CANINLINE_LOG 0 - -#if CANINLINE_LOG - printf("FuncDeclaration::canInline(hasthis = %d, statementsToo = %d, '%s')\n", hasthis, statementsToo, toChars()); -#endif - - if (needThis() && !hasthis) - return 0; - - if (inlineNest || (semanticRun < PASSsemantic3 && !hdrscan)) - { -#if CANINLINE_LOG - printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun); -#endif - return 0; - } - - switch (statementsToo ? inlineStatusStmt : inlineStatusExp) - { - case ILSyes: -#if CANINLINE_LOG - printf("\t1: yes %s\n", toChars()); -#endif - return 1; - - case ILSno: -#if CANINLINE_LOG - printf("\t1: no %s\n", toChars()); -#endif - return 0; - - case ILSuninitialized: - break; - - default: - assert(0); - } - - if (type) - { assert(type->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)(type); -#if IN_LLVM - // LDC: Only extern(C) varargs count. - if (tf->linkage != LINKd) -#endif - if (tf->varargs == 1) // no variadic parameter lists - goto Lno; - - /* Don't inline a function that returns non-void, but has - * no return expression. - * No statement inlining for non-voids. - */ - if (tf->next && tf->next->ty != Tvoid && - (!(hasReturnExp & 1) || statementsToo) && - !hdrscan) - goto Lno; - } -#if !IN_LLVM - // LDC: Only extern(C) varargs count, and ctors use extern(D). - else - { CtorDeclaration *ctor = isCtorDeclaration(); - - if (ctor && ctor->varargs == 1) - goto Lno; - } -#endif - - if ( - !fbody || - ident == Id::ensure || // ensure() has magic properties the inliner loses - (ident == Id::require && // require() has magic properties too - toParent()->isFuncDeclaration() && // see bug 7699 - toParent()->isFuncDeclaration()->needThis()) || - !hdrscan && - ( -#if 0 - isCtorDeclaration() || // cannot because need to convert: - // return; - // to: - // return this; -#endif - isSynchronized() || - isImportedSymbol() || -#if !IN_LLVM - hasNestedFrameRefs() || // no nested references to this frame -#endif // !IN_LLVM - (isVirtual() && !isFinal()) - )) - { - goto Lno; - } - -#if !IN_LLVM -#if !SARRAYVALUE - /* If any parameters are Tsarray's (which are passed by reference) - * or out parameters (also passed by reference), don't do inlining. - */ - if (parameters) - { - for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = parameters->tdata()[i]; - if (v->type->toBasetype()->ty == Tsarray) - goto Lno; - } - } -#endif -#endif - - memset(&ics, 0, sizeof(ics)); - ics.hasthis = hasthis; - ics.fd = this; - ics.hdrscan = hdrscan; - cost = fbody->inlineCost(&ics); -#if CANINLINE_LOG - printf("cost = %d for %s\n", cost, toChars()); -#endif - if (tooCostly(cost)) - goto Lno; - if (!statementsToo && cost > COST_MAX) - goto Lno; - - if (!hdrscan) - { - // Don't modify inlineStatus for header content scan - if (statementsToo) - inlineStatusStmt = ILSyes; - else - inlineStatusExp = ILSyes; - -#if !IN_LLVM - inlineScan(); // Don't scan recursively for header content scan -#endif - - if (inlineStatusExp == ILSuninitialized) - { - // Need to redo cost computation, as some statements or expressions have been inlined - memset(&ics, 0, sizeof(ics)); - ics.hasthis = hasthis; - ics.fd = this; - ics.hdrscan = hdrscan; - cost = fbody->inlineCost(&ics); - #if CANINLINE_LOG - printf("recomputed cost = %d for %s\n", cost, toChars()); - #endif - if (tooCostly(cost)) - goto Lno; - if (!statementsToo && cost > COST_MAX) - goto Lno; - - if (statementsToo) - inlineStatusStmt = ILSyes; - else - inlineStatusExp = ILSyes; - } - } -#if CANINLINE_LOG - printf("\t2: yes %s\n", toChars()); -#endif - return 1; - -Lno: - if (!hdrscan) // Don't modify inlineStatus for header content scan - { if (statementsToo) - inlineStatusStmt = ILSno; - else - inlineStatusExp = ILSno; - } -#if CANINLINE_LOG - printf("\t2: no %s\n", toChars()); -#endif - return 0; -} - -Expression *FuncDeclaration::expandInline(InlineScanState *iss, Expression *ethis, Expressions *arguments, Statement **ps) -{ - InlineDoState ids; - DeclarationExp *de; - Expression *e = NULL; - Statements *as = NULL; - -#if LOG || CANINLINE_LOG - printf("FuncDeclaration::expandInline('%s')\n", toChars()); -#endif - - memset(&ids, 0, sizeof(ids)); - ids.parent = iss->fd; - ids.fd = this; - - if (ps) - as = new Statements(); - - // Set up vthis - if (ethis) - { - VarDeclaration *vthis; - ExpInitializer *ei; - VarExp *ve; - -#if STRUCTTHISREF - if (ethis->type->ty == Tpointer) - { Type *t = ethis->type->nextOf(); - ethis = new PtrExp(ethis->loc, ethis); - ethis->type = t; - } - ei = new ExpInitializer(ethis->loc, ethis); - - vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); - if (ethis->type->ty != Tclass) - vthis->storage_class = STCref; - else - vthis->storage_class = STCin; -#else - if (ethis->type->ty != Tclass && ethis->type->ty != Tpointer) - { - ethis = ethis->addressOf(NULL); - } - - ei = new ExpInitializer(ethis->loc, ethis); - - vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); - vthis->storage_class = STCin; -#endif - vthis->linkage = LINKd; - vthis->parent = iss->fd; - - ve = new VarExp(vthis->loc, vthis); - ve->type = vthis->type; - - ei->exp = new AssignExp(vthis->loc, ve, ethis); - ei->exp->type = ve->type; -#if STRUCTTHISREF - if (ethis->type->ty != Tclass) - { /* This is a reference initialization, not a simple assignment. - */ - ei->exp->op = TOKconstruct; - } -#endif - - ids.vthis = vthis; - } - - // Set up parameters - if (ethis) - { - e = new DeclarationExp(0, ids.vthis); - e->type = Type::tvoid; - if (as) - as->push(new ExpStatement(e->loc, e)); - } - - if (arguments && arguments->dim) - { - assert(parameters->dim == arguments->dim); - - for (size_t i = 0; i < arguments->dim; i++) - { - VarDeclaration *vfrom = parameters->tdata()[i]; - VarDeclaration *vto; - Expression *arg = arguments->tdata()[i]; - ExpInitializer *ei; - VarExp *ve; - - ei = new ExpInitializer(arg->loc, arg); - - vto = new VarDeclaration(vfrom->loc, vfrom->type, vfrom->ident, ei); - vto->storage_class |= vfrom->storage_class & (STCin | STCout | STClazy | STCref); - vto->linkage = vfrom->linkage; - vto->parent = iss->fd; - //printf("vto = '%s', vto->storage_class = x%x\n", vto->toChars(), vto->storage_class); - //printf("vto->parent = '%s'\n", iss->fd->toChars()); - - ve = new VarExp(vto->loc, vto); - //ve->type = vto->type; - ve->type = arg->type; - - ei->exp = new AssignExp(vto->loc, ve, arg); - ei->exp->op = TOKconstruct; - ei->exp->type = ve->type; -//ve->type->print(); -//arg->type->print(); -//ei->exp->print(); - - ids.from.push(vfrom); - ids.to.push(vto); - - de = new DeclarationExp(0, vto); - de->type = Type::tvoid; - - if (as) - as->push(new ExpStatement(0, de)); - else - e = Expression::combine(e, de); - } - } - - if (ps) - { - inlineNest++; - Statement *s = fbody->doInlineStatement(&ids); - as->push(s); - *ps = new ScopeStatement(0, new CompoundStatement(0, as)); - inlineNest--; - } - else - { - inlineNest++; - Expression *eb = fbody->doInline(&ids); - e = Expression::combine(e, eb); - inlineNest--; - //eb->type->print(); - //eb->print(); - //eb->dump(0); - } - - /* There's a problem if what the function returns is used subsequently as an - * lvalue, as in a struct return that is then used as a 'this'. - * If we take the address of the return value, we will be taking the address - * of the original, not the copy. Fix this by assigning the return value to - * a temporary, then returning the temporary. If the temporary is used as an - * lvalue, it will work. - * This only happens with struct returns. - * See Bugzilla 2127 for an example. - */ - TypeFunction *tf = (TypeFunction*)type; - if (!ps && tf->next->ty == Tstruct) - { - /* Generate a new variable to hold the result and initialize it with the - * inlined body of the function: - * tret __inlineretval = e; - */ - ExpInitializer* ei = new ExpInitializer(loc, e); - - Identifier* tmp = Identifier::generateId("__inlineretval"); - VarDeclaration* vd = new VarDeclaration(loc, tf->next, tmp, ei); - vd->storage_class = 0; - vd->linkage = tf->linkage; - vd->parent = iss->fd; - - VarExp *ve = new VarExp(loc, vd); - ve->type = tf->next; - - ei->exp = new AssignExp(loc, ve, e); - ei->exp->op = TOKconstruct; - ei->exp->type = ve->type; - - DeclarationExp* de = new DeclarationExp(0, vd); - de->type = Type::tvoid; - - // Chain the two together: - // ( typeof(return) __inlineretval = ( inlined body )) , __inlineretval - e = Expression::combine(de, ve); - - //fprintf(stderr, "CallExp::inlineScan: e = "); e->print(); - } - - // Need to reevaluate whether parent can now be inlined - // in expressions, as we might have inlined statements - iss->fd->inlineStatusExp = ILSuninitialized; - return e; -} - - -/**************************************************** - * Perform the "inline copying" of a default argument for a function parameter. - */ - -Expression *Expression::inlineCopy(Scope *sc) -{ -#if 0 - /* See Bugzilla 2935 for explanation of why just a copy() is broken - */ - return copy(); -#else - if (op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)this; - - if (de->func->isNested()) - { /* See Bugzilla 4820 - * Defer checking until later if we actually need the 'this' pointer - */ - Expression *e = de->copy(); - return e; - } - } - - InlineCostState ics; - - memset(&ics, 0, sizeof(ics)); - ics.hdrscan = 1; // so DeclarationExp:: will work on 'statics' which are not - int cost = expressionInlineCost(this, &ics); - if (cost >= COST_MAX) - { error("cannot inline default argument %s", toChars()); - return new ErrorExp(); - } - InlineDoState ids; - memset(&ids, 0, sizeof(ids)); - ids.parent = sc->parent; - Expression *e = doInline(&ids); - return e; -#endif -} - diff --git a/dmd/interpret.c b/dmd/interpret.c deleted file mode 100644 index da2d1561..00000000 --- a/dmd/interpret.c +++ /dev/null @@ -1,7083 +0,0 @@ -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include // mem{cpy|set}() - -#include "rmem.h" - -#include "statement.h" -#include "expression.h" -#include "cond.h" -#include "init.h" -#include "staticassert.h" -#include "mtype.h" -#include "scope.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" -#include "utf.h" -#include "attrib.h" // for AttribDeclaration - -#include "template.h" -#include "port.h" -int RealEquals(real_t x1, real_t x2); - - -#define LOG 0 -#define LOGASSIGN 0 -#define SHOWPERFORMANCE 0 - -// Maximum allowable recursive function calls in CTFE -#define CTFE_RECURSION_LIMIT 1000 - -// The values of all CTFE variables. -struct CtfeStack -{ -private: - /* The stack. Every declaration we encounter is pushed here, - together with the VarDeclaration, and the previous - stack address of that variable, so that we can restore it - when we leave the stack frame. - Note that when a function is forward referenced, the interpreter must - run semantic3, and that may start CTFE again with a NULL istate. Thus - the stack might not be empty when CTFE begins. - - Ctfe Stack addresses are just 0-based integers, but we save - them as 'void *' because ArrayBase can only do pointers. - */ - Expressions values; // values on the stack - VarDeclarations vars; // corresponding variables - ArrayBase savedId; // id of the previous state of that var - - /* Global constants get saved here after evaluation, so we never - * have to redo them. This saves a lot of time and memory. - */ - Expressions globalValues; // values of global constants - size_t framepointer; // current frame pointer - size_t maxStackPointer; // most stack we've ever used -public: - CtfeStack() : framepointer(0), maxStackPointer(0) - { - } - size_t stackPointer() - { - return values.dim; - } - // Largest number of stack positions we've used - size_t maxStackUsage() - { - return maxStackPointer; - } - // return the previous frame - size_t startFrame() - { - size_t oldframe = framepointer; - framepointer = stackPointer(); - return oldframe; - } - void endFrame(size_t oldframe) - { - popAll(framepointer); - framepointer = oldframe; - } - Expression *getValue(VarDeclaration *v) - { - if (v->isDataseg() && !v->isCTFE()) - { - assert(v->ctfeAdrOnStack >= 0 && - v->ctfeAdrOnStack < globalValues.dim); - return globalValues[v->ctfeAdrOnStack]; - } - assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer()); - return values[v->ctfeAdrOnStack]; - } - void setValue(VarDeclaration *v, Expression *e) - { - assert(!v->isDataseg() || v->isCTFE()); - assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer()); - values[v->ctfeAdrOnStack] = e; - } - void push(VarDeclaration *v) - { - assert(!v->isDataseg() || v->isCTFE()); - if (v->ctfeAdrOnStack!= (size_t)-1 - && v->ctfeAdrOnStack >= framepointer) - { // Already exists in this frame, reuse it. - values[v->ctfeAdrOnStack] = NULL; - return; - } - savedId.push((void *)(v->ctfeAdrOnStack)); - v->ctfeAdrOnStack = values.dim; - vars.push(v); - values.push(NULL); - } - void pop(VarDeclaration *v) - { - assert(!v->isDataseg() || v->isCTFE()); - assert(!(v->storage_class & (STCref | STCout))); - int oldid = v->ctfeAdrOnStack; - v->ctfeAdrOnStack = (size_t)(savedId[oldid]); - if (v->ctfeAdrOnStack == values.dim - 1) - { - values.pop(); - vars.pop(); - savedId.pop(); - } - } - void popAll(size_t stackpointer) - { - if (stackPointer() > maxStackPointer) - maxStackPointer = stackPointer(); - assert(values.dim >= stackpointer && stackpointer >= 0); - for (size_t i = stackpointer; i < values.dim; ++i) - { - VarDeclaration *v = vars[i]; - v->ctfeAdrOnStack = (size_t)(savedId[i]); - } - values.setDim(stackpointer); - vars.setDim(stackpointer); - savedId.setDim(stackpointer); - } - void saveGlobalConstant(VarDeclaration *v, Expression *e) - { -#if DMDV2 - assert( v->init && (v->isConst() || v->isImmutable()) && !v->isCTFE()); -#else - assert( v->init && v->isConst() && !v->isCTFE()); -#endif - v->ctfeAdrOnStack = globalValues.dim; - globalValues.push(e); - } -}; - -CtfeStack ctfeStack; - - -struct InterState -{ - InterState *caller; // calling function's InterState - FuncDeclaration *fd; // function being interpreted - size_t framepointer; // frame pointer of previous frame - Statement *start; // if !=NULL, start execution at this statement - Statement *gotoTarget; /* target of EXP_GOTO_INTERPRET result; also - * target of labelled EXP_BREAK_INTERPRET or - * EXP_CONTINUE_INTERPRET. (NULL if no label). - */ - Expression *localThis; // value of 'this', or NULL if none - bool awaitingLvalueReturn; // Support for ref return values: - // Any return to this function should return an lvalue. - InterState(); -}; - -InterState::InterState() -{ - memset(this, 0, sizeof(InterState)); -} - -// Global status of the CTFE engine -struct CtfeStatus -{ - static int callDepth; // current number of recursive calls - static int stackTraceCallsToSuppress; /* When printing a stack trace, - * suppress this number of calls - */ - static int maxCallDepth; // highest number of recursive calls - static int numArrayAllocs; // Number of allocated arrays - static int numAssignments; // total number of assignments executed -}; - -int CtfeStatus::callDepth = 0; -int CtfeStatus::stackTraceCallsToSuppress = 0; -int CtfeStatus::maxCallDepth = 0; -int CtfeStatus::numArrayAllocs = 0; -int CtfeStatus::numAssignments = 0; - -// CTFE diagnostic information -void printCtfePerformanceStats() -{ -#if SHOWPERFORMANCE - printf(" ---- CTFE Performance ----\n"); - printf("max call depth = %d\tmax stack = %d\n", CtfeStatus::maxCallDepth, ctfeStack.maxStackUsage()); - printf("array allocs = %d\tassignments = %d\n\n", CtfeStatus::numArrayAllocs, CtfeStatus::numAssignments); -#endif -} - - -Expression * resolveReferences(Expression *e, Expression *thisval); -Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal); -VarDeclaration *findParentVar(Expression *e, Expression *thisval); -bool needToCopyLiteral(Expression *expr); -Expression *copyLiteral(Expression *e); -Expression *paintTypeOntoLiteral(Type *type, Expression *lit); -Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2); -Expression *evaluateIfBuiltin(InterState *istate, Loc loc, - FuncDeclaration *fd, Expressions *arguments, Expression *pthis); -Expression *scrubReturnValue(Loc loc, Expression *e); -bool isAssocArray(Type *t); -bool isPointer(Type *t); -Expression *ctfeEqual(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2); - -// CTFE only expressions -#define TOKclassreference ((TOK)(TOKMAX+1)) -#define TOKthrownexception ((TOK)(TOKMAX+2)) - -// Reference to a class, or an interface. We need this when we -// point to a base class (we must record what the type is). -struct ClassReferenceExp : Expression -{ - StructLiteralExp *value; - ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type) : Expression(loc, TOKclassreference, sizeof(ClassReferenceExp)) - { - assert(lit && lit->sd && lit->sd->isClassDeclaration()); - this->value = lit; - this->type = type; - } - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue) - { - //printf("ClassReferenceExp::interpret() %s\n", value->toChars()); - return this; - } - char *toChars() - { - return value->toChars(); - } - ClassDeclaration *originalClass() - { - return value->sd->isClassDeclaration(); - } - VarDeclaration *getFieldAt(int index) - { - ClassDeclaration *cd = originalClass(); - size_t fieldsSoFar = 0; - while (index - fieldsSoFar >= cd->fields.dim) - { fieldsSoFar += cd->fields.dim; - cd = cd->baseClass; - } - return cd->fields[index - fieldsSoFar]; - } - // Return index of the field, or -1 if not found - int getFieldIndex(Type *fieldtype, size_t fieldoffset) - { - ClassDeclaration *cd = originalClass(); - size_t fieldsSoFar = 0; - for (size_t j = 0; j < value->elements->dim; j++) - { while (j - fieldsSoFar >= cd->fields.dim) - { fieldsSoFar += cd->fields.dim; - cd = cd->baseClass; - } - Dsymbol *s = cd->fields[j - fieldsSoFar]; - VarDeclaration *v2 = s->isVarDeclaration(); - if (fieldoffset == v2->offset && - fieldtype->size() == v2->type->size()) - { return value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar); - } - } - return -1; - } - // Return index of the field, or -1 if not found - // Same as getFieldIndex, but checks for a direct match with the VarDeclaration - int findFieldIndexByName(VarDeclaration *v) - { - ClassDeclaration *cd = originalClass(); - size_t fieldsSoFar = 0; - for (size_t j = 0; j < value->elements->dim; j++) - { while (j - fieldsSoFar >= cd->fields.dim) - { fieldsSoFar += cd->fields.dim; - cd = cd->baseClass; - } - Dsymbol *s = cd->fields[j - fieldsSoFar]; - VarDeclaration *v2 = s->isVarDeclaration(); - if (v == v2) - { return value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar); - } - } - return -1; - } -}; - -struct VoidInitExp : Expression -{ - VarDeclaration *var; - - VoidInitExp(VarDeclaration *var, Type *type) - : Expression(var->loc, TOKvoid, sizeof(VoidInitExp)) - { - this->var = var; - this->type = var->type; - } - char *toChars() - { - return (char *)"void"; - } - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue) - { - error("CTFE internal error: trying to read uninitialized variable"); - assert(0); - return EXP_CANT_INTERPRET; - } -}; - -// Return index of the field, or -1 if not found -// Same as getFieldIndex, but checks for a direct match with the VarDeclaration -int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v) -{ - for (int i = 0; i < sd->fields.dim; ++i) - { - if (sd->fields[i] == v) - return i; - } - return -1; -} - -// Fake class which holds the thrown exception. Used for implementing exception handling. -struct ThrownExceptionExp : Expression -{ - ClassReferenceExp *thrown; // the thing being tossed - ThrownExceptionExp(Loc loc, ClassReferenceExp *victim) : Expression(loc, TOKthrownexception, sizeof(ThrownExceptionExp)) - { - this->thrown = victim; - this->type = type; - } - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue) - { - assert(0); // This should never be interpreted - return this; - } - char *toChars() - { - return (char *)"CTFE ThrownException"; - } - // Generate an error message when this exception is not caught - void generateUncaughtError() - { - thrown->error("Uncaught CTFE exception %s(%s)", thrown->type->toChars(), - thrown->value->elements->tdata()[0]->toChars()); - /* Also give the line where the throw statement was. We won't have it - * in the case where the ThrowStatement is generated internally - * (eg, in ScopeStatement) - */ - if (loc.filename && !loc.equals(thrown->loc)) - errorSupplemental(loc, "thrown from here"); - } -}; - -// True if 'e' is EXP_CANT_INTERPRET, or an exception -bool exceptionOrCantInterpret(Expression *e) -{ - if (e == EXP_CANT_INTERPRET) return true; - if (!e || e == EXP_GOTO_INTERPRET || e == EXP_VOID_INTERPRET - || e == EXP_BREAK_INTERPRET || e == EXP_CONTINUE_INTERPRET) - return false; - return e->op == TOKthrownexception; -} - - -// Used for debugging only -void showCtfeExpr(Expression *e, int level = 0) -{ - for (int i = level; i>0; --i) printf(" "); - Expressions *elements = NULL; - // We need the struct definition to detect block assignment - StructDeclaration *sd = NULL; - ClassDeclaration *cd = NULL; - if (e->op == TOKstructliteral) - { elements = ((StructLiteralExp *)e)->elements; - sd = ((StructLiteralExp *)e)->sd; - printf("STRUCT type = %s %p:\n", e->type->toChars(), - e); - } - else if (e->op == TOKclassreference) - { elements = ((ClassReferenceExp *)e)->value->elements; - cd = ((ClassReferenceExp *)e)->originalClass(); - printf("CLASS type = %s %p:\n", e->type->toChars(), - ((ClassReferenceExp *)e)->value); - } - else if (e->op == TOKarrayliteral) - { - elements = ((ArrayLiteralExp *)e)->elements; - printf("ARRAY LITERAL type=%s %p:\n", e->type->toChars(), - e); - } - else if (e->op == TOKassocarrayliteral) - { - printf("AA LITERAL type=%s %p:\n", e->type->toChars(), - e); - } - else if (e->op == TOKstring) - { - printf("STRING %s %p\n", e->toChars(), - ((StringExp *)e)->string); - } - else if (e->op == TOKslice) - { - printf("SLICE %p: %s\n", e, e->toChars()); - showCtfeExpr(((SliceExp *)e)->e1, level + 1); - } - else if (e->op == TOKvar) - { - printf("VAR %p %s\n", e, e->toChars()); - VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration(); - if (v && v->getValue()) - showCtfeExpr(v->getValue(), level + 1); - } - else if (isPointer(e->type)) - { - // This is potentially recursive. We mustn't try to print the thing we're pointing to. - if (e->op == TOKindex) - printf("POINTER %p into %p [%s]\n", e, ((IndexExp *)e)->e1, ((IndexExp *)e)->e2->toChars()); - else if (e->op == TOKdotvar) - printf("POINTER %p to %p .%s\n", e, ((DotVarExp *)e)->e1, ((DotVarExp *)e)->var->toChars()); - else - printf("POINTER %p: %s\n", e, e->toChars()); - } - else - printf("VALUE %p: %s\n", e, e->toChars()); - - if (elements) - { - size_t fieldsSoFar = 0; - for (size_t i = 0; i < elements->dim; i++) - { Expression *z = NULL; - Dsymbol *s = NULL; - if (i > 15) { - printf("...(total %d elements)\n", elements->dim); - return; - } - if (sd) - { s = sd->fields[i]; - z = (*elements)[i]; - } - else if (cd) - { while (i - fieldsSoFar >= cd->fields.dim) - { fieldsSoFar += cd->fields.dim; - cd = cd->baseClass; - for (int j = level; j>0; --j) printf(" "); - printf(" BASE CLASS: %s\n", cd->toChars()); - } - s = cd->fields[i - fieldsSoFar]; - size_t indx = (elements->dim - fieldsSoFar)- cd->fields.dim + i; - assert(indx >= 0); - assert(indx < elements->dim); - z = (*elements)[indx]; - } - if (!z) { - for (int j = level; j>0; --j) printf(" "); - printf(" void\n"); - continue; - } - - if (s) - { - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - // If it is a void assignment, use the default initializer - if ((v->type->ty != z->type->ty) && v->type->ty == Tsarray) - { - for (int j = level; --j;) printf(" "); - printf(" field: block initalized static array\n"); - continue; - } - } - showCtfeExpr(z, level + 1); - } - } -} - -/************************************* - * - * Entry point for CTFE. - * A compile-time result is required. Give an error if not possible - */ -Expression *Expression::ctfeInterpret() -{ - return optimize(WANTvalue | WANTinterpret); -} - -/************************************* - * Attempt to interpret a function given the arguments. - * Input: - * istate state for calling function (NULL if none) - * arguments function arguments - * thisarg 'this', if a needThis() function, NULL if not. - * - * Return result expression if successful, EXP_CANT_INTERPRET if not, - * or EXP_VOID_INTERPRET if function returned void. - */ - -Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments, Expression *thisarg) -{ -#if LOG - printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars()); -#endif - if (semanticRun == PASSsemantic3) - return EXP_CANT_INTERPRET; - - if (semanticRun < PASSsemantic3 && scope) - { - /* Forward reference - we need to run semantic3 on this function. - * If errors are gagged, and it's not part of a speculative - * template instance, we need to temporarily ungag errors. - */ - int olderrors = global.errors; - int oldgag = global.gag; - TemplateInstance *spec = isSpeculative(); - if (global.gag && !spec) - global.gag = 0; - semantic3(scope); - global.gag = oldgag; // regag errors - - // If it is a speculatively-instantiated template, and errors occur, - // we need to mark the template as having errors. - if (spec && global.errors != olderrors) - spec->errors = global.errors - olderrors; - if (olderrors != global.errors) // if errors compiling this function - return EXP_CANT_INTERPRET; - } - if (semanticRun < PASSsemantic3done) - return EXP_CANT_INTERPRET; - - Type *tb = type->toBasetype(); - assert(tb->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)tb; - Type *tret = tf->next->toBasetype(); - if (tf->varargs && arguments && - ((parameters && arguments->dim != parameters->dim) || (!parameters && arguments->dim))) - { - error("C-style variadic functions are not yet implemented in CTFE"); - return EXP_CANT_INTERPRET; - } - - // Nested functions always inherit the 'this' pointer from the parent, - // except for delegates. (Note that the 'this' pointer may be null). - // Func literals report isNested() even if they are in global scope, - // so we need to check that the parent is a function. - if (isNested() && toParent2()->isFuncDeclaration() && !thisarg && istate) - thisarg = istate->localThis; - - InterState istatex; - istatex.caller = istate; - istatex.fd = this; - istatex.localThis = thisarg; - istatex.framepointer = ctfeStack.startFrame(); - - Expressions vsave; // place to save previous parameter values - size_t dim = 0; - if (needThis() && !thisarg) - { // error, no this. Prevent segfault. - error("need 'this' to access member %s", toChars()); - return EXP_CANT_INTERPRET; - } - if (thisarg && !istate) - { // Check that 'this' aleady has a value - if (thisarg->interpret(istate) == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - } - static int evaluatingArgs = 0; - if (arguments) - { - dim = arguments->dim; - assert(!dim || (parameters && (parameters->dim == dim))); - vsave.setDim(dim); - - /* Evaluate all the arguments to the function, - * store the results in eargs[] - */ - Expressions eargs; - eargs.setDim(dim); - for (size_t i = 0; i < dim; i++) - { Expression *earg = (*arguments)[i]; - Parameter *arg = Parameter::getNth(tf->parameters, i); - - if (arg->storageClass & (STCout | STCref)) - { - if (!istate && (arg->storageClass & STCout)) - { // initializing an out parameter involves writing to it. - earg->error("global %s cannot be passed as an 'out' parameter at compile time", earg->toChars()); - return EXP_CANT_INTERPRET; - } - // Convert all reference arguments into lvalue references - ++evaluatingArgs; - earg = earg->interpret(istate, ctfeNeedLvalueRef); - --evaluatingArgs; - if (earg == EXP_CANT_INTERPRET) - return earg; - } - else if (arg->storageClass & STClazy) - { - } - else - { /* Value parameters - */ - Type *ta = arg->type->toBasetype(); - if (ta->ty == Tsarray && earg->op == TOKaddress) - { - /* Static arrays are passed by a simple pointer. - * Skip past this to get at the actual arg. - */ - earg = ((AddrExp *)earg)->e1; - } - ++evaluatingArgs; - earg = earg->interpret(istate); - --evaluatingArgs; - if (earg == EXP_CANT_INTERPRET) - return earg; - /* Struct literals are passed by value, but we don't need to - * copy them if they are passed as const - */ - if (earg->op == TOKstructliteral -#if DMDV2 - && !(arg->storageClass & (STCconst | STCimmutable)) -#endif - ) - earg = copyLiteral(earg); - } - if (earg->op == TOKthrownexception) - { - if (istate) - return earg; - ((ThrownExceptionExp *)earg)->generateUncaughtError(); - return EXP_CANT_INTERPRET; - } - eargs[i] = earg; - } - - for (size_t i = 0; i < dim; i++) - { Expression *earg = eargs[i]; - Parameter *arg = Parameter::getNth(tf->parameters, i); - VarDeclaration *v = (*parameters)[i]; -#if LOG - printf("arg[%d] = %s\n", i, earg->toChars()); -#endif - if (arg->storageClass & (STCout | STCref) && earg->op == TOKvar) - { - VarExp *ve = (VarExp *)earg; - VarDeclaration *v2 = ve->var->isVarDeclaration(); - if (!v2) - { - error("cannot interpret %s as a ref parameter", ve->toChars()); - return EXP_CANT_INTERPRET; - } - /* The push() isn't a variable we'll use, it's just a place - * to save the old value of v. - * Note that v might be v2! So we need to save v2's index - * before pushing. - */ - size_t oldadr = v2->ctfeAdrOnStack; - ctfeStack.push(v); - v->ctfeAdrOnStack = oldadr; - assert(v2->hasValue()); - } - else - { // Value parameters and non-trivial references - ctfeStack.push(v); - v->setValueWithoutChecking(earg); - } -#if LOG || LOGASSIGN - printf("interpreted arg[%d] = %s\n", i, earg->toChars()); - showCtfeExpr(earg); -#endif - } - } - - if (vresult) - ctfeStack.push(vresult); - - // Enter the function - ++CtfeStatus::callDepth; - if (CtfeStatus::callDepth > CtfeStatus::maxCallDepth) - CtfeStatus::maxCallDepth = CtfeStatus::callDepth; - - Expression *e = NULL; - while (1) - { - if (CtfeStatus::callDepth > CTFE_RECURSION_LIMIT) - { // This is a compiler error. It must not be suppressed. - global.gag = 0; - error("CTFE recursion limit exceeded"); - e = EXP_CANT_INTERPRET; - break; - } - e = fbody->interpret(&istatex); - if (e == EXP_CANT_INTERPRET) - { -#if LOG - printf("function body failed to interpret\n"); -#endif - } - - /* This is how we deal with a recursive statement AST - * that has arbitrary goto statements in it. - * Bubble up a 'result' which is the target of the goto - * statement, then go recursively down the AST looking - * for that statement, then execute starting there. - */ - if (e == EXP_GOTO_INTERPRET) - { - istatex.start = istatex.gotoTarget; // set starting statement - istatex.gotoTarget = NULL; - } - else - break; - } - assert(e != EXP_CONTINUE_INTERPRET && e != EXP_BREAK_INTERPRET); - - // Leave the function - --CtfeStatus::callDepth; - - ctfeStack.endFrame(istatex.framepointer); - - // If fell off the end of a void function, return void - if (!e && type->toBasetype()->nextOf()->ty == Tvoid) - return EXP_VOID_INTERPRET; - - // If result is void, return void - if (e == EXP_VOID_INTERPRET) - return e; - - // If it generated an exception, return it - if (exceptionOrCantInterpret(e)) - { - if (istate || e == EXP_CANT_INTERPRET) - return e; - ((ThrownExceptionExp *)e)->generateUncaughtError(); - return EXP_CANT_INTERPRET; - } - - // If we're about to leave CTFE, make sure we don't crash the - // compiler by returning a CTFE-internal expression. - if (!istate && !evaluatingArgs) - { - e = scrubReturnValue(loc, e); - } - return e; -} - -/******************************** Statement ***************************/ - -#define START() \ - if (istate->start) \ - { if (istate->start != this) \ - return NULL; \ - istate->start = NULL; \ - } - -/*********************************** - * Interpret the statement. - * Returns: - * NULL continue to next statement - * EXP_CANT_INTERPRET cannot interpret statement at compile time - * !NULL expression from return statement, or thrown exception - */ - -Expression *Statement::interpret(InterState *istate) -{ -#if LOG - printf("Statement::interpret()\n"); -#endif - START() - error("Statement %s cannot be interpreted at compile time", this->toChars()); - return EXP_CANT_INTERPRET; -} - -Expression *ExpStatement::interpret(InterState *istate) -{ -#if LOG - printf("ExpStatement::interpret(%s)\n", exp ? exp->toChars() : ""); -#endif - START() - if (exp) - { - Expression *e = exp->interpret(istate, ctfeNeedNothing); - if (e == EXP_CANT_INTERPRET) - { - //printf("-ExpStatement::interpret(): %p\n", e); - return EXP_CANT_INTERPRET; - } - if (e && e!= EXP_VOID_INTERPRET && e->op == TOKthrownexception) - return e; - } - return NULL; -} - -Expression *CompoundStatement::interpret(InterState *istate) -{ Expression *e = NULL; - -#if LOG - printf("CompoundStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statements) - { - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - - if (s) - { - e = s->interpret(istate); - if (e) - break; - } - } - } -#if LOG - printf("-CompoundStatement::interpret() %p\n", e); -#endif - return e; -} - -Expression *UnrolledLoopStatement::interpret(InterState *istate) -{ Expression *e = NULL; - -#if LOG - printf("UnrolledLoopStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statements) - { - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - - e = s->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_CONTINUE_INTERPRET) - { - if (istate->gotoTarget && istate->gotoTarget != this) - break; // continue at higher level - istate->gotoTarget = NULL; - e = NULL; - continue; - } - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - break; - } - if (e) - break; - } - } - return e; -} - -// For CTFE only. Returns true if 'e' is TRUE or a non-null pointer. -int isTrueBool(Expression *e) -{ - return e->isBool(TRUE) || ((e->type->ty == Tpointer || e->type->ty == Tclass) - && e->op != TOKnull); -} - -Expression *IfStatement::interpret(InterState *istate) -{ -#if LOG - printf("IfStatement::interpret(%s)\n", condition->toChars()); -#endif - - if (istate->start == this) - istate->start = NULL; - if (istate->start) - { - Expression *e = NULL; - if (ifbody) - e = ifbody->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - if (istate->start && elsebody) - e = elsebody->interpret(istate); - return e; - } - - Expression *e = condition->interpret(istate); - assert(e); - //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n"); - if (e != EXP_CANT_INTERPRET && (e && e->op != TOKthrownexception)) - { - if (isTrueBool(e)) - e = ifbody ? ifbody->interpret(istate) : NULL; - else if (e->isBool(FALSE)) - e = elsebody ? elsebody->interpret(istate) : NULL; - else - { - e = EXP_CANT_INTERPRET; - } - } - return e; -} - -Expression *ScopeStatement::interpret(InterState *istate) -{ -#if LOG - printf("ScopeStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - return statement ? statement->interpret(istate) : NULL; -} - -Expression *resolveSlice(Expression *e) -{ - if ( ((SliceExp *)e)->e1->op == TOKnull) - return ((SliceExp *)e)->e1; - return Slice(e->type, ((SliceExp *)e)->e1, - ((SliceExp *)e)->lwr, ((SliceExp *)e)->upr); -} - -/* Determine the array length, without interpreting it. - * e must be an array literal, or a slice - * It's very wasteful to resolve the slice when we only - * need the length. - */ -uinteger_t resolveArrayLength(Expression *e) -{ - if (e->op == TOKnull) - return 0; - if (e->op == TOKslice) - { uinteger_t ilo = ((SliceExp *)e)->lwr->toInteger(); - uinteger_t iup = ((SliceExp *)e)->upr->toInteger(); - return iup - ilo; - } - if (e->op == TOKstring) - { return ((StringExp *)e)->len; - } - if (e->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e; - return ale->elements ? ale->elements->dim : 0; - } - if (e->op == TOKassocarrayliteral) - { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e; - return ale->keys->dim; - } - assert(0); - return 0; -} - -Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) -{ - Loc loc = e1->loc; - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - Expression *e; - if (e2->op == TOKstring && e1->op == TOKarrayliteral && - t1->nextOf()->isintegral()) - { - // [chars] ~ string => string (only valid for CTFE) - StringExp *es1 = (StringExp *)e2; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1; - size_t len = es1->len + es2->elements->dim; - int sz = es1->sz; - - void *s = mem.malloc((len + 1) * sz); - memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz); - for (size_t i = 0; i < es2->elements->dim; i++) - { Expression *es2e = es2->elements->tdata()[i]; - if (es2e->op != TOKint64) - return EXP_CANT_INTERPRET; - dinteger_t v = es2e->toInteger(); - memcpy((unsigned char *)s + i * sz, &v, sz); - } - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - StringExp *es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = 0; - es->type = type; - e = es; - return e; - } - else if (e1->op == TOKstring && e2->op == TOKarrayliteral && - t2->nextOf()->isintegral()) - { - // string ~ [chars] => string (only valid for CTFE) - // Concatenate the strings - StringExp *es1 = (StringExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - size_t len = es1->len + es2->elements->dim; - int sz = es1->sz; - - void *s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - for (size_t i = 0; i < es2->elements->dim; i++) - { Expression *es2e = es2->elements->tdata()[i]; - if (es2e->op != TOKint64) - return EXP_CANT_INTERPRET; - dinteger_t v = es2e->toInteger(); - memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz); - } - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - StringExp *es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = 0; //es1->committed; - es->type = type; - e = es; - return e; - } - return Cat(type, e1, e2); -} - -bool scrubArray(Loc loc, Expressions *elems, bool structlit = false); - -/* All results destined for use outside of CTFE need to have their CTFE-specific - * features removed. - * In particular, all slices must be resolved. - */ -Expression *scrubReturnValue(Loc loc, Expression *e) -{ - if (e->op == TOKclassreference) - { - error(loc, "%s class literals cannot be returned from CTFE", ((ClassReferenceExp*)e)->originalClass()->toChars()); - return EXP_CANT_INTERPRET; - } - if (e->op == TOKvoid) - { - error(loc, "uninitialized variable '%s' cannot be returned from CTFE", ((VoidInitExp *)e)->var->toChars()); - e = new ErrorExp(); - } - if (e->op == TOKslice) - { - e = resolveSlice(e); - } - if (e->op == TOKstructliteral) - { - StructLiteralExp *se = (StructLiteralExp *)e; - se->ownedByCtfe = false; - if (!scrubArray(loc, se->elements, true)) - return EXP_CANT_INTERPRET; - } - if (e->op == TOKstring) - { - ((StringExp *)e)->ownedByCtfe = false; - } - if (e->op == TOKarrayliteral) - { - ((ArrayLiteralExp *)e)->ownedByCtfe = false; - if (!scrubArray(loc, ((ArrayLiteralExp *)e)->elements)) - return EXP_CANT_INTERPRET; - } - if (e->op == TOKassocarrayliteral) - { - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e; - aae->ownedByCtfe = false; - if (!scrubArray(loc, aae->keys)) - return EXP_CANT_INTERPRET; - if (!scrubArray(loc, aae->values)) - return EXP_CANT_INTERPRET; - } - return e; -} - -// Scrub all members of an array. Return false if error -bool scrubArray(Loc loc, Expressions *elems, bool structlit) -{ - for (size_t i = 0; i < elems->dim; i++) - { - Expression *m = elems->tdata()[i]; - if (!m) - continue; - if (m && m->op == TOKvoid && structlit) - m = NULL; - if (m) - m = scrubReturnValue(loc, m); - if (m == EXP_CANT_INTERPRET) - return false; - elems->tdata()[i] = m; - } - return true; -} - - -Expression *ReturnStatement::interpret(InterState *istate) -{ -#if LOG - printf("ReturnStatement::interpret(%s)\n", exp ? exp->toChars() : ""); -#endif - START() - if (!exp) - return EXP_VOID_INTERPRET; - assert(istate && istate->fd && istate->fd->type); -#if DMDV2 - /* If the function returns a ref AND it's been called from an assignment, - * we need to return an lvalue. Otherwise, just do an (rvalue) interpret. - */ - if (istate->fd->type && istate->fd->type->ty==Tfunction) - { - TypeFunction *tf = (TypeFunction *)istate->fd->type; - if (tf->isref && istate->caller && istate->caller->awaitingLvalueReturn) - { // We need to return an lvalue - Expression *e = exp->interpret(istate, ctfeNeedLvalue); - if (e == EXP_CANT_INTERPRET) - error("ref return %s is not yet supported in CTFE", exp->toChars()); - return e; - } - if (tf->next && (tf->next->ty == Tdelegate) && istate->fd->closureVars.dim > 0) - { - // To support this, we need to copy all the closure vars - // into the delegate literal. - error("closures are not yet supported in CTFE"); - return EXP_CANT_INTERPRET; - } - } -#endif - // We need to treat pointers specially, because TOKsymoff can be used to - // return a value OR a pointer - Expression *e; - if ( isPointer(exp->type) ) - e = exp->interpret(istate, ctfeNeedLvalue); - else - e = exp->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - if (needToCopyLiteral(e)) - e = copyLiteral(e); -#if LOGASSIGN - printf("RETURN %s\n", loc.toChars()); - showCtfeExpr(e); -#endif - return e; -} - -Expression *BreakStatement::interpret(InterState *istate) -{ -#if LOG - printf("BreakStatement::interpret()\n"); -#endif - START() - if (ident) - { LabelDsymbol *label = istate->fd->searchLabel(ident); - assert(label && label->statement); - Statement *s = label->statement; - if (s->isLabelStatement()) - s = s->isLabelStatement()->statement; - if (s->isScopeStatement()) - s = s->isScopeStatement()->statement; - istate->gotoTarget = s; - return EXP_BREAK_INTERPRET; - } - else - { - istate->gotoTarget = NULL; - return EXP_BREAK_INTERPRET; - } -} - -Expression *ContinueStatement::interpret(InterState *istate) -{ -#if LOG - printf("ContinueStatement::interpret()\n"); -#endif - START() - if (ident) - { LabelDsymbol *label = istate->fd->searchLabel(ident); - assert(label && label->statement); - Statement *s = label->statement; - if (s->isLabelStatement()) - s = s->isLabelStatement()->statement; - if (s->isScopeStatement()) - s = s->isScopeStatement()->statement; - istate->gotoTarget = s; - return EXP_CONTINUE_INTERPRET; - } - else - return EXP_CONTINUE_INTERPRET; -} - -Expression *WhileStatement::interpret(InterState *istate) -{ -#if LOG - printf("WhileStatement::interpret()\n"); -#endif - assert(0); // rewritten to ForStatement - return NULL; -} - -Expression *DoStatement::interpret(InterState *istate) -{ -#if LOG - printf("DoStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - while (1) - { - bool wasGoto = !!istate->start; - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (wasGoto && istate->start) - return NULL; - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - break; - } - if (e && e != EXP_CONTINUE_INTERPRET) - break; - if (istate->gotoTarget && istate->gotoTarget != this) - break; // continue at a higher level - - Lcontinue: - istate->gotoTarget = NULL; - e = condition->interpret(istate); - if (exceptionOrCantInterpret(e)) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (isTrueBool(e)) - { - } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); - } - return e; -} - -Expression *ForStatement::interpret(InterState *istate) -{ -#if LOG - printf("ForStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - if (init) - { - e = init->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - assert(!e); - } - while (1) - { - if (condition && !istate->start) - { - e = condition->interpret(istate); - if (exceptionOrCantInterpret(e)) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (e->isBool(FALSE)) - { e = NULL; - break; - } - assert( isTrueBool(e) ); - } - - bool wasGoto = !!istate->start; - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (wasGoto && istate->start) - return NULL; - - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - break; - } - if (e && e != EXP_CONTINUE_INTERPRET) - break; - - if (istate->gotoTarget && istate->gotoTarget != this) - break; // continue at a higher level - istate->gotoTarget = NULL; - - if (increment) - { - e = increment->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - } - } - return e; -} - -Expression *ForeachStatement::interpret(InterState *istate) -{ - assert(0); // rewritten to ForStatement - return NULL; -} - -#if DMDV2 -Expression *ForeachRangeStatement::interpret(InterState *istate) -{ - assert(0); // rewritten to ForStatement - return NULL; -} -#endif - -Expression *SwitchStatement::interpret(InterState *istate) -{ -#if LOG - printf("SwitchStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e = NULL; - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - return NULL; - } // else break at a higher level - } - return e; - } - - - Expression *econdition = condition->interpret(istate); - if (exceptionOrCantInterpret(econdition)) - return econdition; - if (econdition->op == TOKslice) - econdition = resolveSlice(econdition); - - Statement *s = NULL; - if (cases) - { - for (size_t i = 0; i < cases->dim; i++) - { - CaseStatement *cs = (*cases)[i]; - Expression * caseExp = cs->exp->interpret(istate); - if (exceptionOrCantInterpret(caseExp)) - return caseExp; - e = ctfeEqual(caseExp->loc, TOKequal, Type::tint32, econdition, caseExp); - if (exceptionOrCantInterpret(e)) - return e; - if (e->isBool(TRUE)) - { s = cs; - break; - } - } - } - if (!s) - { if (hasNoDefault) - error("no default or case for %s in switch statement", econdition->toChars()); - s = sdefault; - } - - assert(s); - istate->start = s; - e = body ? body->interpret(istate) : NULL; - assert(!istate->start); - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - } - return e; -} - -Expression *CaseStatement::interpret(InterState *istate) -{ -#if LOG - printf("CaseStatement::interpret(%s) this = %p\n", exp->toChars(), this); -#endif - if (istate->start == this) - istate->start = NULL; - if (statement) - return statement->interpret(istate); - else - return NULL; -} - -Expression *DefaultStatement::interpret(InterState *istate) -{ -#if LOG - printf("DefaultStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statement) - return statement->interpret(istate); - else - return NULL; -} - -Expression *GotoStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoStatement::interpret()\n"); -#endif - START() - assert(label && label->statement); - istate->gotoTarget = label->statement; - return EXP_GOTO_INTERPRET; -} - -Expression *GotoCaseStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoCaseStatement::interpret()\n"); -#endif - START() - assert(cs); - istate->gotoTarget = cs; - return EXP_GOTO_INTERPRET; -} - -Expression *GotoDefaultStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoDefaultStatement::interpret()\n"); -#endif - START() - assert(sw && sw->sdefault); - istate->gotoTarget = sw->sdefault; - return EXP_GOTO_INTERPRET; -} - -Expression *LabelStatement::interpret(InterState *istate) -{ -#if LOG - printf("LabelStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - return statement ? statement->interpret(istate) : NULL; -} - - -Expression *TryCatchStatement::interpret(InterState *istate) -{ -#if LOG - printf("TryCatchStatement::interpret()\n"); -#endif - START() - Expression *e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (!exceptionOrCantInterpret(e)) - return e; - // An exception was thrown - ThrownExceptionExp *ex = (ThrownExceptionExp *)e; - Type *extype = ex->thrown->originalClass()->type; - // Search for an appropriate catch clause. - for (size_t i = 0; i < catches->dim; i++) - { -#if DMDV1 - Catch *ca = (Catch *)catches->data[i]; -#else - Catch *ca = catches->tdata()[i]; -#endif - Type *catype = ca->type; - - if (catype->equals(extype) || catype->isBaseOf(extype, NULL)) - { // Execute the handler - if (ca->var) - { - ctfeStack.push(ca->var); - ca->var->setValue(ex->thrown); - } - return ca->handler ? ca->handler->interpret(istate) : NULL; - } - } - return e; -} - -bool isAnErrorException(ClassDeclaration *cd) -{ - return cd == ClassDeclaration::errorException || ClassDeclaration::errorException->isBaseOf(cd, NULL); -} - -ThrownExceptionExp *chainExceptions(ThrownExceptionExp *oldest, ThrownExceptionExp *newest) -{ -#if LOG - printf("Collided exceptions %s %s\n", oldest->thrown->toChars(), newest->thrown->toChars()); -#endif -#if DMDV2 - // Little sanity check to make sure it's really a Throwable - ClassReferenceExp *boss = oldest->thrown; - assert(boss->value->elements->tdata()[4]->type->ty == Tclass); - ClassReferenceExp *collateral = newest->thrown; - if (isAnErrorException(collateral->originalClass()) - && !isAnErrorException(boss->originalClass())) - { // The new exception bypass the existing chain - assert(collateral->value->elements->tdata()[5]->type->ty == Tclass); - collateral->value->elements->tdata()[5] = boss; - return newest; - } - while (boss->value->elements->tdata()[4]->op == TOKclassreference) - { - boss = (ClassReferenceExp *)(boss->value->elements->tdata()[4]); - } - boss->value->elements->tdata()[4] = collateral; - return oldest; -#else - // for D1, the newest exception just clobbers the older one - return newest; -#endif -} - - -Expression *TryFinallyStatement::interpret(InterState *istate) -{ -#if LOG - printf("TryFinallyStatement::interpret()\n"); -#endif - START() - Expression *e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - return e; - Expression *second = finalbody ? finalbody->interpret(istate) : NULL; - if (second == EXP_CANT_INTERPRET) - return second; - if (exceptionOrCantInterpret(second)) - { // Check for collided exceptions - if (exceptionOrCantInterpret(e)) - e = chainExceptions((ThrownExceptionExp *)e, (ThrownExceptionExp *)second); - else - e = second; - } - return e; -} - -Expression *ThrowStatement::interpret(InterState *istate) -{ -#if LOG - printf("ThrowStatement::interpret()\n"); -#endif - START() - Expression *e = exp->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - assert(e->op == TOKclassreference); - return new ThrownExceptionExp(loc, (ClassReferenceExp *)e); -} - -Expression *OnScopeStatement::interpret(InterState *istate) -{ - assert(0); - return EXP_CANT_INTERPRET; -} - -Expression *WithStatement::interpret(InterState *istate) -{ -#if LOG - printf("WithStatement::interpret()\n"); -#endif - START() - Expression *e = exp->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - if (wthis->type->ty == Tpointer && exp->type->ty != Tpointer) - { - e = new AddrExp(loc, e); - e->type = wthis->type; - } - ctfeStack.push(wthis); - wthis->setValue(e); - e = body ? body->interpret(istate) : EXP_VOID_INTERPRET; - ctfeStack.pop(wthis); - return e; -} - -Expression *AsmStatement::interpret(InterState *istate) -{ -#if LOG - printf("AsmStatement::interpret()\n"); -#endif - START() - error("asm statements cannot be interpreted at compile time"); - return EXP_CANT_INTERPRET; -} - -#if DMDV2 -Expression *ImportStatement::interpret(InterState *istate) -{ -#if LOG - printf("ImportStatement::interpret()\n"); -#endif - START(); - return NULL; -} -#endif - -/******************************** Expression ***************************/ - -Expression *Expression::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("Expression::interpret() %s\n", toChars()); - printf("type = %s\n", type->toChars()); - dump(0); -#endif - error("Cannot interpret %s at compile time", toChars()); - return EXP_CANT_INTERPRET; -} - -Expression *ThisExp::interpret(InterState *istate, CtfeGoal goal) -{ - while (istate && !istate->localThis) - istate = istate->caller; - if (istate && istate->localThis && istate->localThis->op == TOKstructliteral) - return istate->localThis; - if (istate && istate->localThis) - return istate->localThis->interpret(istate, goal); - error("value of 'this' is not known at compile time"); - return EXP_CANT_INTERPRET; -} - -Expression *NullExp::interpret(InterState *istate, CtfeGoal goal) -{ - return this; -} - -Expression *IntegerExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("IntegerExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *RealExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("RealExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *ComplexExp::interpret(InterState *istate, CtfeGoal goal) -{ - return this; -} - -Expression *StringExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("StringExp::interpret() %s\n", toChars()); -#endif - /* In both D1 and D2, attempts to modify string literals are prevented - * in BinExp::interpretAssignCommon. - * In D2, we also disallow casts of read-only literals to mutable, - * though it isn't strictly necessary. - */ -#if DMDV2 - // Fixed-length char arrays always get duped later anyway. - if (type->ty == Tsarray) - return this; - if (!(((TypeNext *)type)->next->mod & (MODconst | MODimmutable))) - { // It seems this happens only when there has been an explicit cast - error("cannot cast a read-only string literal to mutable in CTFE"); - return EXP_CANT_INTERPRET; - } -#endif - return this; -} - -Expression *FuncExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("FuncExp::interpret() %s\n", toChars()); -#endif - return this; -} - -/* Is it safe to convert from srcPointee* to destPointee* ? - * srcPointee is the genuine type (never void). - * destPointee may be void. - */ -bool isSafePointerCast(Type *srcPointee, Type *destPointee) -{ // It's OK if both are the same (modulo const) -#if DMDV2 - if (srcPointee->castMod(0) == destPointee->castMod(0)) - return true; -#else - if (srcPointee == destPointee) - return true; -#endif - // it's OK to cast to void* - if (destPointee->ty == Tvoid) - return true; - // It's OK if they are the same size integers, eg int* and uint* - return srcPointee->isintegral() && destPointee->isintegral() - && srcPointee->size() == destPointee->size(); -} - -Expression *SymOffExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("SymOffExp::interpret() %s\n", toChars()); -#endif - if (var->isFuncDeclaration() && offset == 0) - { - return this; - } - if (type->ty != Tpointer) - { // Probably impossible - error("Cannot interpret %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - Type *pointee = ((TypePointer *)type)->next; - Expression *val = getVarExp(loc, istate, var, goal); - if (val == EXP_CANT_INTERPRET) - return val; - if (val->type->ty == Tarray || val->type->ty == Tsarray) - { - // Check for unsupported type painting operations - Type *elemtype = ((TypeArray *)(val->type))->next; - - // It's OK to cast from fixed length to dynamic array, eg &int[3] to int[]* - if (val->type->ty == Tsarray && pointee->ty == Tarray - && elemtype->size() == pointee->nextOf()->size()) - { - Expression *e = new AddrExp(loc, val); - e->type = type; - return e; - } - if ( !isSafePointerCast(elemtype, pointee) ) - { // It's also OK to cast from &string to string*. - if ( offset == 0 && isSafePointerCast(var->type, pointee) ) - { - VarExp *ve = new VarExp(loc, var); - ve->type = type; - return ve; - } - error("reinterpreting cast from %s to %s is not supported in CTFE", - val->type->toChars(), type->toChars()); - return EXP_CANT_INTERPRET; - } - - TypeArray *tar = (TypeArray *)val->type; - dinteger_t sz = pointee->size(); - dinteger_t indx = offset/sz; - assert(sz * indx == offset); - Expression *aggregate = NULL; - if (val->op == TOKarrayliteral || val->op == TOKstring) - aggregate = val; - else if (val->op == TOKslice) - { - aggregate = ((SliceExp *)val)->e1; - Expression *lwr = ((SliceExp *)val)->lwr->interpret(istate); - indx += lwr->toInteger(); - } - if (aggregate) - { - IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t); - IndexExp *ie = new IndexExp(loc, aggregate, ofs); - ie->type = type; - return ie; - } - } - else if ( offset == 0 && isSafePointerCast(var->type, pointee) ) - { - VarExp *ve = new VarExp(loc, var); - ve->type = type; - return ve; - } - - error("Cannot convert &%s to %s at compile time", var->type->toChars(), type->toChars()); - return EXP_CANT_INTERPRET; -} - -Expression *AddrExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("AddrExp::interpret() %s\n", toChars()); -#endif - // For reference types, we need to return an lvalue ref. - TY tb = e1->type->toBasetype()->ty; - bool needRef = (tb == Tarray || tb == Taarray || tb == Tclass); - Expression *e = e1->interpret(istate, needRef ? ctfeNeedLvalueRef : ctfeNeedLvalue); - if (exceptionOrCantInterpret(e)) - return e; - // Return a simplified address expression - e = new AddrExp(loc, e); - e->type = type; - return e; -} - -Expression *DelegateExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("DelegateExp::interpret() %s\n", toChars()); -#endif - return this; -} - - -// ------------------------------------------------------------- -// Remove out, ref, and this -// ------------------------------------------------------------- -// The variable used in a dotvar, index, or slice expression, -// after 'out', 'ref', and 'this' have been removed. -Expression * resolveReferences(Expression *e, Expression *thisval) -{ - for(;;) - { - if (e->op == TOKthis) - { - assert(thisval); - assert(e != thisval); - e = thisval; - continue; - } - if (e->op == TOKvar) - { - VarExp *ve = (VarExp *)e; - VarDeclaration *v = ve->var->isVarDeclaration(); - assert(v); - if (v->type->ty == Tpointer) - break; - if (v->ctfeAdrOnStack == (size_t)-1) // If not on the stack, can't possibly be a ref. - break; - if (v->getValue() && (v->getValue()->op == TOKslice)) - { - SliceExp *se = (SliceExp *)v->getValue(); - if (se->e1->op == TOKarrayliteral || se->e1->op == TOKassocarrayliteral || se->e1->op == TOKstring) - break; - e = v->getValue(); - continue; - } - else if (v->getValue() && (v->getValue()->op==TOKindex || v->getValue()->op == TOKdotvar - || v->getValue()->op == TOKthis )) - { - e = v->getValue(); - continue; - } - } - break; - } - return e; -} - -Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal) -{ - Expression *e = EXP_CANT_INTERPRET; - VarDeclaration *v = d->isVarDeclaration(); -#if IN_LLVM - StaticStructInitDeclaration *s = d->isStaticStructInitDeclaration(); -#else - SymbolDeclaration *s = d->isSymbolDeclaration(); -#endif - if (v) - { -#if DMDV2 - /* Magic variable __ctfe always returns true when interpreting - */ - if (v->ident == Id::ctfe) - return new IntegerExp(loc, 1, Type::tbool); - if ((v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) && v->init && !v->hasValue()) -#else - if (v->isConst() && v->init) -#endif - { e = v->init->toExpression(); - if (e && (e->op == TOKconstruct || e->op == TOKblit)) - { AssignExp *ae = (AssignExp *)e; - e = ae->e2; - v->inuse++; - e = e->interpret(istate, ctfeNeedAnyValue); - v->inuse--; - if (e == EXP_CANT_INTERPRET && !global.gag && !CtfeStatus::stackTraceCallsToSuppress) - errorSupplemental(loc, "while evaluating %s.init", v->toChars()); - if (exceptionOrCantInterpret(e)) - return e; - e->type = v->type; - } - else - { - if (e && !e->type) - e->type = v->type; - if (e) - e = e->interpret(istate, ctfeNeedAnyValue); - if (e == EXP_CANT_INTERPRET && !global.gag && !CtfeStatus::stackTraceCallsToSuppress) - errorSupplemental(loc, "while evaluating %s.init", v->toChars()); - } - if (e && e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) - { - e = copyLiteral(e); - ctfeStack.saveGlobalConstant(v, e); - } - } - else if (v->isCTFE() && !v->hasValue()) - { - if (v->init && v->type->size() != 0) - { - if (v->init->isVoidInitializer()) - { - // var should have been initialized when it was created - error(loc, "CTFE internal error - trying to access uninitialized var"); - assert(0); - e = EXP_CANT_INTERPRET; - } - else - { - e = v->init->toExpression(); - e = e->interpret(istate); - } - } - else - e = v->type->defaultInitLiteral(loc); - } - else if (!v->isDataseg() && !v->isCTFE() && !istate) - { error(loc, "variable %s cannot be read at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } - else - { e = v->hasValue() ? v->getValue() : NULL; - if (!e && !v->isCTFE() && v->isDataseg()) - { error(loc, "static variable %s cannot be read at compile time", v->toChars()); - e = EXP_CANT_INTERPRET; - } - else if (!e) - { assert(!(v->init && v->init->isVoidInitializer())); - // CTFE initiated from inside a function - error(loc, "variable %s cannot be read at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } - else if (exceptionOrCantInterpret(e)) - return e; - else if (goal == ctfeNeedLvalue && v->isRef() && e->op == TOKindex) - { // If it is a foreach ref, resolve the index into a constant - IndexExp *ie = (IndexExp *)e; - Expression *w = ie->e2->interpret(istate); - if (w != ie->e2) - { - e = new IndexExp(ie->loc, ie->e1, w); - e->type = ie->type; - } - return e; - } - else if ((goal == ctfeNeedLvalue) - || e->op == TOKstring || e->op == TOKstructliteral || e->op == TOKarrayliteral - || e->op == TOKassocarrayliteral || e->op == TOKslice - || e->type->toBasetype()->ty == Tpointer) - return e; // it's already an Lvalue - else if (e->op == TOKvoid) - { - VoidInitExp *ve = (VoidInitExp *)e; - error(loc, "cannot read uninitialized variable %s in ctfe", v->toPrettyChars()); - errorSupplemental(ve->var->loc, "%s was uninitialized and used before set", ve->var->toChars()); - e = EXP_CANT_INTERPRET; - } - else - e = e->interpret(istate, goal); - } - if (!e) - e = EXP_CANT_INTERPRET; - } - else if (s) - { -#if !IN_LLVM - // Struct static initializers, for example - if (s->dsym->toInitializer() == s->sym) - { -#endif - e = s->dsym->type->defaultInitLiteral(loc); - e = e->semantic(NULL); - if (e->op == TOKerror) - e = EXP_CANT_INTERPRET; - else // Convert NULL to VoidExp - e = e->interpret(istate, goal); -#if !IN_LLVM - } - else - error(loc, "cannot interpret symbol %s at compile time", v->toChars()); -#endif - } - else - error(loc, "cannot interpret declaration %s at compile time", d->toChars()); - return e; -} - -Expression *VarExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("VarExp::interpret() %s\n", toChars()); -#endif - if (goal == ctfeNeedLvalueRef) - { - VarDeclaration *v = var->isVarDeclaration(); - if (v && !v->isDataseg() && !v->isCTFE() && !istate) - { error("variable %s cannot be referenced at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } - else if (v && !v->hasValue() && !v->isCTFE() && v->isDataseg()) - { error("static variable %s cannot be referenced at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } - return this; - } - Expression *e = getVarExp(loc, istate, var, goal); - // A VarExp may include an implicit cast. It must be done explicitly. - if (e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) - e = paintTypeOntoLiteral(type, e); - return e; -} - -Expression *DeclarationExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("DeclarationExp::interpret() %s\n", toChars()); -#endif - Expression *e; - VarDeclaration *v = declaration->isVarDeclaration(); - if (v) - { - if (v->toAlias()->isTupleDeclaration()) - { // Reserve stack space for all tuple members - TupleDeclaration *td =v->toAlias()->isTupleDeclaration(); - if (!td->objects) - return NULL; - for(int i= 0; i < td->objects->dim; ++i) - { - Object * o = td->objects->tdata()[i]; - Expression *ex = isExpression(o); - DsymbolExp *s = (ex && ex->op == TOKdsymbol) ? (DsymbolExp *)ex : NULL; - VarDeclaration *v2 = s ? s->s->isVarDeclaration() : NULL; - assert(v2); - if (!v2->isDataseg() || v2->isCTFE()) - ctfeStack.push(v2); - } - } - if (!v->isDataseg() || v->isCTFE()) - ctfeStack.push(v); - Dsymbol *s = v->toAlias(); - if (s == v && !v->isStatic() && v->init) - { - ExpInitializer *ie = v->init->isExpInitializer(); - if (ie) - e = ie->exp->interpret(istate); - else if (v->init->isVoidInitializer()) - { - e = v->type->voidInitLiteral(v); - // There is no AssignExp for void initializers, - // so set it here. - v->setValue(e); - } - else - { - error("Declaration %s is not yet implemented in CTFE", toChars()); - e = EXP_CANT_INTERPRET; - } - } - else if (s == v && !v->init && v->type->size()==0) - { // Zero-length arrays don't need an initializer - e = v->type->defaultInitLiteral(loc); - } -#if DMDV2 - else if (s == v && (v->isConst() || v->isImmutable()) && v->init) -#else - else if (s == v && v->isConst() && v->init) -#endif - { e = v->init->toExpression(); - if (!e) - e = EXP_CANT_INTERPRET; - else if (!e->type) - e->type = v->type; - } - else if (s->isTupleDeclaration() && !v->init) - e = NULL; - else if (v->isStatic() && !v->init) - e = NULL; // Just ignore static variables which aren't read or written yet - else - { - error("Static variable %s cannot be modified at compile time", v->toChars()); - e = EXP_CANT_INTERPRET; - } - } - else if (declaration->isAttribDeclaration() || - declaration->isTemplateMixin() || - declaration->isTupleDeclaration()) - { // Check for static struct declarations, which aren't executable - AttribDeclaration *ad = declaration->isAttribDeclaration(); - if (ad && ad->decl && ad->decl->dim == 1 - && ad->decl->tdata()[0]->isAggregateDeclaration()) - return NULL; // static struct declaration. Nothing to do. - - // These can be made to work, too lazy now - error("Declaration %s is not yet implemented in CTFE", toChars()); - e = EXP_CANT_INTERPRET; - } - else - { // Others should not contain executable code, so are trivial to evaluate - e = NULL; - } -#if LOG - printf("-DeclarationExp::interpret(%s): %p\n", toChars(), e); -#endif - return e; -} - -Expression *TupleExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("TupleExp::interpret() %s\n", toChars()); -#endif - Expressions *expsx = NULL; - - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - Expression *ex; - - ex = e->interpret(istate); - if (exceptionOrCantInterpret(ex)) - { delete expsx; - return ex; - } - - // A tuple of assignments can contain void (Bug 5676). - if (goal == ctfeNeedNothing) - continue; - if (ex == EXP_VOID_INTERPRET) - { - error("ICE: void element %s in tuple", e->toChars()); - assert(0); - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - ++CtfeStatus::numArrayAllocs; - expsx->setDim(exps->dim); - for (size_t j = 0; j < i; j++) - { - (*expsx)[j] = (*exps)[j]; - } - } - (*expsx)[i] = ex; - } - } - if (expsx) - { TupleExp *te = new TupleExp(loc, expsx); - expandTuples(te->exps); - te->type = new TypeTuple(te->exps); - return te; - } - return this; -} - -Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) -{ Expressions *expsx = NULL; - -#if LOG - printf("ArrayLiteralExp::interpret() %s\n", toChars()); -#endif - if (ownedByCtfe) // We've already interpreted all the elements - return copyLiteral(this); - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - Expression *ex; - - if (e->op == TOKindex) // segfault bug 6250 - assert( ((IndexExp*)e)->e1 != this); - ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerror; - if (ex->op == TOKthrownexception) - return ex; - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - ++CtfeStatus::numArrayAllocs; - expsx->setDim(elements->dim); - for (size_t j = 0; j < elements->dim; j++) - { - (*expsx)[j] = (*elements)[j]; - } - } - (*expsx)[i] = ex; - } - } - } - if (elements && expsx) - { - expandTuples(expsx); - if (expsx->dim != elements->dim) - goto Lerror; - ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx); - ae->type = type; - return copyLiteral(ae); - } -#if DMDV2 - if (((TypeNext *)type)->next->mod & (MODconst | MODimmutable)) - { // If it's immutable, we don't need to dup it - return this; - } -#endif - return copyLiteral(this); - -Lerror: - if (expsx) - delete expsx; - error("cannot interpret array literal"); - return EXP_CANT_INTERPRET; -} - -Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) -{ Expressions *keysx = keys; - Expressions *valuesx = values; - -#if LOG - printf("AssocArrayLiteralExp::interpret() %s\n", toChars()); -#endif - if (ownedByCtfe) // We've already interpreted all the elements - return copyLiteral(this); - for (size_t i = 0; i < keys->dim; i++) - { Expression *ekey = keys->tdata()[i]; - Expression *evalue = values->tdata()[i]; - Expression *ex; - - ex = ekey->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - if (ex->op == TOKthrownexception) - return ex; - - - /* If any changes, do Copy On Write - */ - if (ex != ekey) - { - if (keysx == keys) - keysx = (Expressions *)keys->copy(); - keysx->tdata()[i] = ex; - } - - ex = evalue->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - if (ex->op == TOKthrownexception) - return ex; - - /* If any changes, do Copy On Write - */ - if (ex != evalue) - { - if (valuesx == values) - valuesx = (Expressions *)values->copy(); - valuesx->tdata()[i] = ex; - } - } - if (keysx != keys) - expandTuples(keysx); - if (valuesx != values) - expandTuples(valuesx); - if (keysx->dim != valuesx->dim) - goto Lerr; - - /* Remove duplicate keys - */ - for (size_t i = 1; i < keysx->dim; i++) - { Expression *ekey = keysx->tdata()[i - 1]; - if (ekey->op == TOKslice) - ekey = resolveSlice(ekey); - for (size_t j = i; j < keysx->dim; j++) - { Expression *ekey2 = keysx->tdata()[j]; - Expression *ex = ctfeEqual(loc, TOKequal, Type::tbool, ekey, ekey2); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - if (ex->isBool(TRUE)) // if a match - { - // Remove ekey - if (keysx == keys) - keysx = (Expressions *)keys->copy(); - if (valuesx == values) - valuesx = (Expressions *)values->copy(); - keysx->remove(i - 1); - valuesx->remove(i - 1); - i -= 1; // redo the i'th iteration - break; - } - } - } - - if (keysx != keys || valuesx != values) - { - AssocArrayLiteralExp *ae; - ae = new AssocArrayLiteralExp(loc, keysx, valuesx); - ae->type = type; - ae->ownedByCtfe = true; - return ae; - } - return this; - -Lerr: - if (keysx != keys) - delete keysx; - if (valuesx != values) - delete values; - return EXP_CANT_INTERPRET; -} - -Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) -{ Expressions *expsx = NULL; - -#if LOG - printf("StructLiteralExp::interpret() %s\n", toChars()); -#endif - /* We don't know how to deal with overlapping fields - */ - if (sd->hasUnions) - { error("Unions with overlapping fields are not yet supported in CTFE"); - return EXP_CANT_INTERPRET; - } - if (ownedByCtfe) - return copyLiteral(this); - - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - if (!e) - continue; - - Expression *ex = e->interpret(istate); - if (exceptionOrCantInterpret(ex)) - { delete expsx; - return ex; - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - ++CtfeStatus::numArrayAllocs; - expsx->setDim(elements->dim); - for (size_t j = 0; j < elements->dim; j++) - { - (*expsx)[j] = (*elements)[j]; - } - } - (*expsx)[i] = ex; - } - } - } - if (elements && expsx) - { - expandTuples(expsx); - if (expsx->dim != elements->dim) - { delete expsx; - return EXP_CANT_INTERPRET; - } - StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx); - se->type = type; - se->ownedByCtfe = true; - return se; - } - return copyLiteral(this); -} - -/****************************** - * Helper for NewExp - * Create an array literal consisting of 'elem' duplicated 'dim' times. - */ -ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type, - Expression *elem, size_t dim) -{ - Expressions *elements = new Expressions(); - elements->setDim(dim); - bool mustCopy = needToCopyLiteral(elem); - for (size_t i = 0; i < dim; i++) - { if (mustCopy) - elem = copyLiteral(elem); - (*elements)[i] = elem; - } - ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements); - ae->type = type; - ae->ownedByCtfe = true; - return ae; -} - -/****************************** - * Helper for NewExp - * Create a string literal consisting of 'value' duplicated 'dim' times. - */ -StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type, - unsigned value, size_t dim, int sz) -{ - unsigned char *s; - s = (unsigned char *)mem.calloc(dim + 1, sz); - for (size_t elemi=0; elemitype = type; - se->sz = sz; - se->committed = true; - se->ownedByCtfe = true; - return se; -} - -// Create an array literal of type 'newtype' with dimensions given by -// 'arguments'[argnum..$] -Expression *recursivelyCreateArrayLiteral(Loc loc, Type *newtype, InterState *istate, - Expressions *arguments, int argnum) -{ - Expression *lenExpr = (((*arguments)[argnum]))->interpret(istate); - if (exceptionOrCantInterpret(lenExpr)) - return lenExpr; - size_t len = (size_t)(lenExpr->toInteger()); - Type *elemType = ((TypeArray *)newtype)->next; - if (elemType->ty == Tarray && argnum < arguments->dim - 1) - { - Expression *elem = recursivelyCreateArrayLiteral(loc, elemType, istate, - arguments, argnum + 1); - if (exceptionOrCantInterpret(elem)) - return elem; - - Expressions *elements = new Expressions(); - elements->setDim(len); - for (size_t i = 0; i < len; i++) - (*elements)[i] = copyLiteral(elem); - ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements); - ae->type = newtype; - ae->ownedByCtfe = true; - return ae; - } - assert(argnum == arguments->dim - 1); - if (elemType->ty == Tchar || elemType->ty == Twchar - || elemType->ty == Tdchar) - return createBlockDuplicatedStringLiteral(loc, newtype, - (unsigned)(elemType->defaultInitLiteral(loc)->toInteger()), - len, elemType->size()); - return createBlockDuplicatedArrayLiteral(loc, newtype, - elemType->defaultInitLiteral(loc), - len); -} - -Expression *NewExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("NewExp::interpret() %s\n", toChars()); -#endif - if (newtype->ty == Tarray && arguments) - return recursivelyCreateArrayLiteral(loc, newtype, istate, arguments, 0); - - if (newtype->toBasetype()->ty == Tstruct) - { - Expression *se = newtype->defaultInitLiteral(loc); -#if DMDV2 - if (member) - { - int olderrors = global.errors; - member->interpret(istate, arguments, se); - if (olderrors != global.errors) - { - error("cannot evaluate %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - } -#else // The above code would fail on D1 because it doesn't use STRUCTTHISREF, - // but that's OK because D1 doesn't have struct constructors anyway. - assert(!member); -#endif - Expression *e = new AddrExp(loc, copyLiteral(se)); - e->type = type; - return e; - } - if (newtype->toBasetype()->ty == Tclass) - { - ClassDeclaration *cd = ((TypeClass *)newtype->toBasetype())->sym; - size_t totalFieldCount = 0; - for (ClassDeclaration *c = cd; c; c = c->baseClass) - totalFieldCount += c->fields.dim; - Expressions *elems = new Expressions; - elems->setDim(totalFieldCount); - size_t fieldsSoFar = totalFieldCount; - for (ClassDeclaration *c = cd; c; c = c->baseClass) - { - fieldsSoFar -= c->fields.dim; - for (size_t i = 0; i < c->fields.dim; i++) - { - Dsymbol *s = c->fields[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - Expression *m = v->init ? v->init->toExpression() : v->type->defaultInitLiteral(loc); - if (exceptionOrCantInterpret(m)) - return m; - elems->tdata()[fieldsSoFar+i] = copyLiteral(m); - } - } - // Hack: we store a ClassDeclaration instead of a StructDeclaration. - // We probably won't get away with this. - StructLiteralExp *se = new StructLiteralExp(loc, (StructDeclaration *)cd, elems, newtype); - se->ownedByCtfe = true; - Expression *e = new ClassReferenceExp(loc, se, type); - if (member) - { // Call constructor - if (!member->fbody) - { - Expression *ctorfail = evaluateIfBuiltin(istate, loc, member, arguments, e); - if (ctorfail && exceptionOrCantInterpret(ctorfail)) - return ctorfail; - if (ctorfail) - return e; - member->error("%s cannot be constructed at compile time, because the constructor has no available source code", newtype->toChars()); - return EXP_CANT_INTERPRET; - } - Expression * ctorfail = member->interpret(istate, arguments, e); - if (exceptionOrCantInterpret(ctorfail)) - return ctorfail; - } - return e; - } - error("Cannot interpret %s at compile time", toChars()); - return EXP_CANT_INTERPRET; -} - -Expression *UnaExp::interpretCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *)) -{ Expression *e; - Expression *e1; - -#if LOG - printf("UnaExp::interpretCommon() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - e = (*fp)(type, e1); - return e; -} - -#define UNA_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ -{ \ - return interpretCommon(istate, goal, &op); \ -} - -UNA_INTERPRET(Neg) -UNA_INTERPRET(Com) -UNA_INTERPRET(Not) -UNA_INTERPRET(Bool) - -Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs) -{ - *ofs = 0; - if (e->op == TOKaddress) - e = ((AddrExp *)e)->e1; - if (e->op == TOKdotvar) - { - Expression *ex = ((DotVarExp *)e)->e1; - VarDeclaration *v = ((DotVarExp *)e)->var->isVarDeclaration(); - assert(v); - StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex; - // We can't use getField, because it makes a copy - int i = -1; - if (ex->op == TOKclassreference) - i = ((ClassReferenceExp *)ex)->getFieldIndex(e->type, v->offset); - else - i = se->getFieldIndex(e->type, v->offset); - assert(i != -1); - e = se->elements->tdata()[i]; - } - if (e->op == TOKindex) - { - IndexExp *ie = (IndexExp *)e; - // Note that each AA element is part of its own memory block - if ((ie->e1->type->ty == Tarray || ie->e1->type->ty == Tsarray - || ie->e1->op == TOKstring || ie->e1->op==TOKarrayliteral) && - ie->e2->op == TOKint64) - { - *ofs = ie->e2->toInteger(); - return ie->e1; - } - } - return e; -} - -// return e1 - e2 as an integer, or error if not possible -Expression *pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2) -{ - dinteger_t ofs1, ofs2; - Expression *agg1 = getAggregateFromPointer(e1, &ofs1); - Expression *agg2 = getAggregateFromPointer(e2, &ofs2); - if (agg1 == agg2) - { - Type *pointee = ((TypePointer *)agg1->type)->next; - dinteger_t sz = pointee->size(); - return new IntegerExp(loc, (ofs1-ofs2)*sz, type); - } - else if (agg1->op == TOKstring && agg2->op == TOKstring) - { - if (((StringExp *)agg1)->string == ((StringExp *)agg2)->string) - { - Type *pointee = ((TypePointer *)agg1->type)->next; - dinteger_t sz = pointee->size(); - return new IntegerExp(loc, (ofs1-ofs2)*sz, type); - } - } -#if LOGASSIGN - printf("FAILED POINTER DIFF\n"); - showCtfeExpr(agg1); - showCtfeExpr(agg2); -#endif - error(loc, "%s - %s cannot be interpreted at compile time: cannot subtract " - "pointers to two different memory blocks", - e1->toChars(), e2->toChars()); - return EXP_CANT_INTERPRET; -} - -// Return eptr op e2, where eptr is a pointer, e2 is an integer, -// and op is TOKadd or TOKmin -Expression *pointerArithmetic(Loc loc, enum TOK op, Type *type, - Expression *eptr, Expression *e2) -{ - if (eptr->type->nextOf()->ty == Tvoid) - { - error(loc, "cannot perform arithmetic on void* pointers at compile time"); - return EXP_CANT_INTERPRET; - } - dinteger_t ofs1, ofs2; - if (eptr->op == TOKaddress) - eptr = ((AddrExp *)eptr)->e1; - Expression *agg1 = getAggregateFromPointer(eptr, &ofs1); - if (agg1->op != TOKstring && agg1->op != TOKarrayliteral) - { - error(loc, "cannot perform pointer arithmetic on non-arrays at compile time"); - return EXP_CANT_INTERPRET; - } - ofs2 = e2->toInteger(); - Type *pointee = ((TypePointer *)agg1->type)->next; - dinteger_t sz = pointee->size(); - Expression *dollar = ArrayLength(Type::tsize_t, agg1); - assert(dollar != EXP_CANT_INTERPRET); - dinteger_t len = dollar->toInteger(); - - Expression *val = agg1; - TypeArray *tar = (TypeArray *)val->type; - dinteger_t indx = ofs1; - if (op == TOKadd || op == TOKaddass || op == TOKplusplus) - indx = indx + ofs2/sz; - else if (op == TOKmin || op == TOKminass || op == TOKminusminus) - indx -= ofs2/sz; - else - { - error(loc, "CTFE Internal compiler error: bad pointer operation"); - return EXP_CANT_INTERPRET; - } - if (val->op != TOKarrayliteral && val->op != TOKstring) - { - error(loc, "CTFE Internal compiler error: pointer arithmetic %s", val->toChars()); - return EXP_CANT_INTERPRET; - } - if (indx < 0 || indx > len) - { - error(loc, "cannot assign pointer to index %lld inside memory block [0..%lld]", indx, len); - return EXP_CANT_INTERPRET; - } - - IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t); - IndexExp *ie = new IndexExp(loc, val, ofs); - ie->type = type; - return ie; -} - -typedef Expression *(*fp_t)(Type *, Expression *, Expression *); - -Expression *BinExp::interpretCommon(InterState *istate, CtfeGoal goal, fp_t fp) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("BinExp::interpretCommon() %s\n", toChars()); -#endif - if (this->e1->type->ty == Tpointer && this->e2->type->ty == Tpointer && op == TOKmin) - { - e1 = this->e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - e2 = this->e2->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e2)) - return e2; - return pointerDifference(loc, type, e1, e2); - } - if (this->e1->type->ty == Tpointer && this->e2->type->isintegral()) - { - e1 = this->e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - e2 = this->e2->interpret(istate); - if (exceptionOrCantInterpret(e2)) - return e2; - return pointerArithmetic(loc, op, type, e1, e2); - } - if (this->e2->type->ty == Tpointer && this->e1->type->isintegral() && op==TOKadd) - { - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - e2 = this->e2->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e2)) - return e1; - return pointerArithmetic(loc, op, type, e2, e1); - } - if (this->e1->type->ty == Tpointer || this->e2->type->ty == Tpointer) - { - error("pointer expression %s cannot be interpreted at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->isConst() != 1) - goto Lcant; - - e2 = this->e2->interpret(istate); - if (exceptionOrCantInterpret(e2)) - return e2; - if (e2->isConst() != 1) - goto Lcant; - - e = (*fp)(type, e1, e2); - if (e == EXP_CANT_INTERPRET) - error("%s cannot be interpreted at compile time", toChars()); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define BIN_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ -{ \ - return interpretCommon(istate, goal, &op); \ -} - -BIN_INTERPRET(Add) -BIN_INTERPRET(Min) -BIN_INTERPRET(Mul) -BIN_INTERPRET(Div) -BIN_INTERPRET(Mod) -BIN_INTERPRET(Shl) -BIN_INTERPRET(Shr) -BIN_INTERPRET(Ushr) -BIN_INTERPRET(And) -BIN_INTERPRET(Or) -BIN_INTERPRET(Xor) -#if DMDV2 -BIN_INTERPRET(Pow) -#endif - - -typedef Expression *(*fp2_t)(Loc loc, enum TOK, Type *, Expression *, Expression *); - -/** Return true if agg1 and agg2 are pointers to the same memory block -*/ -bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2) -{ - // Note that type painting can occur with VarExp, so we - // must compare the variables being pointed to. - return agg1 == agg2 || - (agg1->op == TOKvar && agg2->op == TOKvar && - ((VarExp *)agg1)->var == ((VarExp *)agg2)->var); -} - -// Return 1 if true, 0 if false -// -1 if comparison is illegal because they point to non-comparable memory blocks -int comparePointers(Loc loc, enum TOK op, Type *type, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2) -{ - if ( pointToSameMemoryBlock(agg1, agg2) ) - { - dinteger_t cm = ofs1 - ofs2; - dinteger_t n; - dinteger_t zero = 0; - switch(op) - { - case TOKlt: n = (ofs1 < ofs2); break; - case TOKle: n = (ofs1 <= ofs2); break; - case TOKgt: n = (ofs1 > ofs2); break; - case TOKge: n = (ofs1 >= ofs2); break; - case TOKidentity: - case TOKequal: n = (ofs1 == ofs2); break; - case TOKnotidentity: - case TOKnotequal: n = (ofs1 != ofs2); break; - default: - assert(0); - } - return n; - } - bool null1 = ( agg1->op == TOKnull ); - bool null2 = ( agg2->op == TOKnull ); - - int cmp; - if (null1 || null2) - { - switch (op) - { - case TOKlt: cmp = null1 && !null2; break; - case TOKgt: cmp = !null1 && null2; break; - case TOKle: cmp = null1; break; - case TOKge: cmp = null2; break; - case TOKidentity: - case TOKequal: - case TOKnotidentity: // 'cmp' gets inverted below - case TOKnotequal: - cmp = (null1 == null2); - break; - } - } - else - { - switch(op) - { - case TOKidentity: - case TOKequal: - case TOKnotidentity: // 'cmp' gets inverted below - case TOKnotequal: - cmp = 0; - break; - default: - return -1; // memory blocks are different - } - } - if (op == TOKnotidentity || op == TOKnotequal) - cmp ^= 1; - return cmp; -} - - -int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2); - -/* Conceptually the same as memcmp(e1, e2). - * e1 and e2 may be strings, arrayliterals, or slices. - * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. - * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. - */ -int ctfeCmpArrays(Loc loc, Expression *e1, Expression *e2, uinteger_t len) -{ - // Resolve slices, if necessary - uinteger_t lo1 = 0; - uinteger_t lo2 = 0; - - Expression *x = e1; - if (x->op == TOKslice) - { lo1 = ((SliceExp *)x)->lwr->toInteger(); - x = ((SliceExp*)x)->e1; - } - StringExp *se1 = (x->op == TOKstring) ? (StringExp *)x : 0; - ArrayLiteralExp *ae1 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : 0; - - x = e2; - if (x->op == TOKslice) - { lo2 = ((SliceExp *)x)->lwr->toInteger(); - x = ((SliceExp*)x)->e1; - } - StringExp *se2 = (x->op == TOKstring) ? (StringExp *)x : 0; - ArrayLiteralExp *ae2 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : 0; - - // Now both must be either TOKarrayliteral or TOKstring - if (se1 && se2) - return sliceCmpStringWithString(se1, se2, lo1, lo2, len); - if (se1 && ae2) - return sliceCmpStringWithArray(se1, ae2, lo1, lo2, len); - if (se2 && ae1) - return -sliceCmpStringWithArray(se2, ae1, lo2, lo1, len); - - assert (ae1 && ae2); - // Comparing two array literals. This case is potentially recursive. - // If they aren't strings, we just need an equality check rather than - // a full cmp. - bool needCmp = ae1->type->nextOf()->isintegral(); - for (size_t i = 0; i < len; i++) - { Expression *ee1 = (*ae1->elements)[lo1 + i]; - Expression *ee2 = (*ae2->elements)[lo2 + i]; - if (needCmp) - { int c = ee1->toInteger() - ee2->toInteger(); - if (c) - return c; - } - else - { if (ctfeRawCmp(loc, ee1, ee2)) - return 1; - } - } - return 0; -} - -bool isArray(Expression *e) -{ - return e->op == TOKarrayliteral || e->op == TOKstring || - e->op == TOKslice || e->op == TOKnull; -} - -/* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. - * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. - */ -int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2) -{ - if (e1->op == TOKclassreference || e2->op == TOKclassreference) - { if (e1->op == TOKclassreference && e2->op == TOKclassreference && - ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value) - return 0; - return 1; - } - if (e1->op == TOKnull && e2->op == TOKnull) - return 0; - - if (e1->type->ty == Tpointer && e2->type->ty == Tpointer) - { // Can only be an equality test. - if (e1->op == TOKnull && e2->op == TOKnull) - return 0; - dinteger_t ofs1, ofs2; - Expression *agg1 = getAggregateFromPointer(e1, &ofs1); - Expression *agg2 = getAggregateFromPointer(e2, &ofs2); - if ((agg1 == agg2) || (agg1->op == TOKvar && agg2->op == TOKvar && - ((VarExp *)agg1)->var == ((VarExp *)agg2)->var)) - { if (ofs1 == ofs2) - return 0; - } - return 1; - } - if (isArray(e1) && isArray(e2)) - { - uinteger_t len1 = resolveArrayLength(e1); - uinteger_t len2 = resolveArrayLength(e2); - if (len1 != len2) // only for equality - return len1 - len2; - if (len1 == 0 || len2 == 0) - return len1 - len2; // Equal - both are empty - return ctfeCmpArrays(loc, e1, e2, len1); - } - if (e1->type->isintegral()) - { - return e1->toInteger() - e2->toInteger(); - } - real_t r1; - real_t r2; - if (e1->type->isreal()) - { - r1 = e1->toReal(); - r2 = e2->toReal(); - goto L1; - } - else if (e1->type->isimaginary()) - { - r1 = e1->toImaginary(); - r2 = e2->toImaginary(); - L1: -#if __DMC__ - return (r1 != r2); -#else - if (Port::isNan(r1) || Port::isNan(r2)) // if unordered - { - return 1; - } - else - { - return (r1 != r2); - } -#endif - } - else if (e1->type->iscomplex()) - { - return e1->toComplex() != e2->toComplex(); - } - - if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) - { StructLiteralExp *es1 = (StructLiteralExp *)e1; - StructLiteralExp *es2 = (StructLiteralExp *)e2; - // For structs, we only need to return 0 or 1 (< and > aren't legal). - - if (es1->sd != es2->sd) - return 1; - else if ((!es1->elements || !es1->elements->dim) && - (!es2->elements || !es2->elements->dim)) - return 0; // both arrays are empty - else if (!es1->elements || !es2->elements) - return 1; - else if (es1->elements->dim != es2->elements->dim) - return 1; - else - { - for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (*es1->elements)[i]; - Expression *ee2 = (*es2->elements)[i]; - - if (ee1 == ee2) - continue; - if (!ee1 || !ee2) - return 1; - int cmp = ctfeRawCmp(loc, ee1, ee2); - if (cmp) - return 1; - } - return 0; // All elements are equal - } - } - error(loc, "CTFE internal error: bad compare"); - assert(0); - return 0; -} - -// As Equal, but resolves slices before comparing -Expression *ctfeEqual(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) -{ - int cmp = !ctfeRawCmp(loc, e1, e2); - if (op == TOKnotequal) - cmp ^= 1; - return new IntegerExp(loc, cmp, type); -} - -Expression *ctfeIdentity(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) -{ - int cmp; - if (e1->op == TOKnull) - { - cmp = (e2->op == TOKnull); - } - else if (e2->op == TOKnull) - { - cmp = 0; - } - else if (e1->op == TOKsymoff && e2->op == TOKsymoff) - { - SymOffExp *es1 = (SymOffExp *)e1; - SymOffExp *es2 = (SymOffExp *)e2; - cmp = (es1->var == es2->var && es1->offset == es2->offset); - } - else if (e1->type->isreal()) - cmp = RealEquals(e1->toReal(), e2->toReal()); - else if (e1->type->isimaginary()) - cmp = RealEquals(e1->toImaginary(), e2->toImaginary()); - else if (e1->type->iscomplex()) - { complex_t v1 = e1->toComplex(); - complex_t v2 = e2->toComplex(); - cmp = RealEquals(creall(v1), creall(v2)) && - RealEquals(cimagl(v1), cimagl(v1)); - } - else - cmp = !ctfeRawCmp(loc, e1, e2); - - if (op == TOKnotidentity || op == TOKnotequal) - cmp ^= 1; - return new IntegerExp(loc, cmp, type); -} - -Expression *ctfeCmp(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) -{ - return Cmp(op, type, e1, e2); -} - -Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("BinExp::interpretCommon2() %s\n", toChars()); -#endif - if (this->e1->type->ty == Tpointer && this->e2->type->ty == Tpointer) - { - e1 = this->e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - e2 = this->e2->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e2)) - return e2; - dinteger_t ofs1, ofs2; - Expression *agg1 = getAggregateFromPointer(e1, &ofs1); - Expression *agg2 = getAggregateFromPointer(e2, &ofs2); - int cmp = comparePointers(loc, op, type, agg1, ofs1, agg2, ofs2); - if (cmp == -1) - { - char dir = (op == TOKgt || op == TOKge) ? '<' : '>'; - error("The ordering of pointers to unrelated memory blocks is indeterminate in CTFE." - " To check if they point to the same memory block, use both > and < inside && or ||, " - "eg (%s && %s %c= %s + 1)", - toChars(), this->e1->toChars(), dir, this->e2->toChars()); - return EXP_CANT_INTERPRET; - } - return new IntegerExp(loc, cmp, type); - } - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKslice) - e1 = resolveSlice(e1); - - if (e1->isConst() != 1 && - e1->op != TOKnull && - e1->op != TOKstring && - e1->op != TOKarrayliteral && - e1->op != TOKstructliteral && - e1->op != TOKclassreference) - { - error("cannot compare %s at compile time", e1->toChars()); - goto Lcant; - } - - e2 = this->e2->interpret(istate); - if (exceptionOrCantInterpret(e2)) - return e2; - if (e2->op == TOKslice) - e2 = resolveSlice(e2); - if (e2->isConst() != 1 && - e2->op != TOKnull && - e2->op != TOKstring && - e2->op != TOKarrayliteral && - e2->op != TOKstructliteral && - e2->op != TOKclassreference) - { - error("cannot compare %s at compile time", e2->toChars()); - goto Lcant; - } - e = (*fp)(loc, op, type, e1, e2); - if (e == EXP_CANT_INTERPRET) - error("%s cannot be interpreted at compile time", toChars()); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define BIN_INTERPRET2(op, opfunc) \ -Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ -{ \ - return interpretCommon2(istate, goal, &opfunc); \ -} - -BIN_INTERPRET2(Equal, ctfeEqual) -BIN_INTERPRET2(Identity, ctfeIdentity) -BIN_INTERPRET2(Cmp, ctfeCmp) - -/* Helper functions for BinExp::interpretAssignCommon - */ - -/*************************************** - * Duplicate the elements array, then set field 'indexToChange' = newelem. - */ -Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem) -{ - Expressions *expsx = new Expressions(); - ++CtfeStatus::numArrayAllocs; - expsx->setDim(oldelems->dim); - for (size_t j = 0; j < expsx->dim; j++) - { - if (j == indexToChange) - (*expsx)[j] = newelem; - else - (*expsx)[j] = oldelems->tdata()[j]; - } - return expsx; -} - -// Create a new struct literal, which is the same as se except that se.field[offset] = elem -Expression * modifyStructField(Type *type, StructLiteralExp *se, size_t offset, Expression *newval) -{ - int fieldi = se->getFieldIndex(newval->type, offset); - if (fieldi == -1) - return EXP_CANT_INTERPRET; - /* Create new struct literal reflecting updated fieldi - */ - Expressions *expsx = changeOneElement(se->elements, fieldi, newval); - StructLiteralExp * ee = new StructLiteralExp(se->loc, se->sd, expsx); - ee->type = se->type; - ee->ownedByCtfe = 1; - return ee; -} - -/******************************** - * Given an array literal arr (either arrayliteral, stringliteral, or assocArrayLiteral), - * set arr[index] = newval and return the new array. - * - */ -Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae, Expression *index, Expression *newval) -{ - /* Create new associative array literal reflecting updated key/value - */ - Expressions *keysx = aae->keys; - Expressions *valuesx = aae->values; - int updated = 0; - for (size_t j = valuesx->dim; j; ) - { j--; - Expression *ekey = aae->keys->tdata()[j]; - Expression *ex = ctfeEqual(loc, TOKequal, Type::tbool, ekey, index); - if (exceptionOrCantInterpret(ex)) - return ex; - if (ex->isBool(TRUE)) - { valuesx->tdata()[j] = newval; - updated = 1; - } - } - if (!updated) - { // Append index/newval to keysx[]/valuesx[] - valuesx->push(newval); - keysx->push(index); - } - return newval; -} - -// Return true if e is derived from UnaryExp. -// Consider moving this function into Expression. -UnaExp *isUnaExp(Expression *e) -{ - switch (e->op) - { - case TOKdotvar: - case TOKindex: - case TOKslice: - case TOKcall: - case TOKdot: - case TOKdotti: - case TOKdottype: - case TOKcast: - return (UnaExp *)e; - default: - break; - } - return NULL; -} - -// Returns the variable which is eventually modified, or NULL if an rvalue. -// thisval is the current value of 'this'. -VarDeclaration * findParentVar(Expression *e, Expression *thisval) -{ - for (;;) - { - e = resolveReferences(e, thisval); - if (e->op == TOKvar) - break; - if (e->op == TOKindex) - e = ((IndexExp*)e)->e1; - else if (e->op == TOKdotvar) - e = ((DotVarExp *)e)->e1; - else if (e->op == TOKdotti) - e = ((DotTemplateInstanceExp *)e)->e1; - else if (e->op == TOKslice) - e = ((SliceExp*)e)->e1; - else - return NULL; - } - VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration(); - assert(v); - return v; -} - -// Given expr, which evaluates to an array/AA/string literal, -// return true if it needs to be copied -bool needToCopyLiteral(Expression *expr) -{ - for (;;) - { - switch (expr->op) - { - case TOKarrayliteral: - return !((ArrayLiteralExp *)expr)->ownedByCtfe; - case TOKassocarrayliteral: - return !((AssocArrayLiteralExp *)expr)->ownedByCtfe; - case TOKstructliteral: - return !((StructLiteralExp *)expr)->ownedByCtfe; - case TOKstring: - case TOKthis: - case TOKvar: - return false; - case TOKassign: - return false; - case TOKindex: - case TOKdotvar: - case TOKslice: - case TOKcast: - expr = ((UnaExp *)expr)->e1; - continue; - case TOKcat: - return needToCopyLiteral(((BinExp *)expr)->e1) || - needToCopyLiteral(((BinExp *)expr)->e2); - case TOKcatass: - expr = ((BinExp *)expr)->e2; - continue; - default: - return false; - } - } -} - -Expressions *copyLiteralArray(Expressions *oldelems) -{ - if (!oldelems) - return oldelems; - CtfeStatus::numArrayAllocs++; - Expressions *newelems = new Expressions(); - newelems->setDim(oldelems->dim); - for (size_t i = 0; i < oldelems->dim; i++) - newelems->tdata()[i] = copyLiteral(oldelems->tdata()[i]); - return newelems; -} - - - -// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral. -// This value will be used for in-place modification. -Expression *copyLiteral(Expression *e) -{ - if (e->op == TOKstring) // syntaxCopy doesn't make a copy for StringExp! - { - StringExp *se = (StringExp *)e; - unsigned char *s; - s = (unsigned char *)mem.calloc(se->len + 1, se->sz); - memcpy(s, se->string, se->len * se->sz); - StringExp *se2 = new StringExp(se->loc, s, se->len); - se2->committed = se->committed; - se2->postfix = se->postfix; - se2->type = se->type; - se2->sz = se->sz; - se2->ownedByCtfe = true; - return se2; - } - else if (e->op == TOKarrayliteral) - { - ArrayLiteralExp *ae = (ArrayLiteralExp *)e; - ArrayLiteralExp *r = new ArrayLiteralExp(e->loc, - copyLiteralArray(ae->elements)); - r->type = e->type; - r->ownedByCtfe = true; - return r; - } - else if (e->op == TOKassocarrayliteral) - { - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e; - AssocArrayLiteralExp *r = new AssocArrayLiteralExp(e->loc, - copyLiteralArray(aae->keys), copyLiteralArray(aae->values)); - r->type = e->type; - r->ownedByCtfe = true; - return r; - } - /* syntaxCopy doesn't work for struct literals, because of a nasty special - * case: block assignment is permitted inside struct literals, eg, - * an int[4] array can be initialized with a single int. - */ - else if (e->op == TOKstructliteral) - { - StructLiteralExp *se = (StructLiteralExp *)e; - Expressions *oldelems = se->elements; - Expressions * newelems = new Expressions(); - newelems->setDim(oldelems->dim); - for (size_t i = 0; i < newelems->dim; i++) - { - Expression *m = oldelems->tdata()[i]; - // We need the struct definition to detect block assignment - AggregateDeclaration *sd = se->sd; - Dsymbol *s = sd->fields[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - // If it is a void assignment, use the default initializer - if (!m) - m = v->type->voidInitLiteral(v); - if (m->op == TOKslice) - m = resolveSlice(m); - if ((v->type->ty != m->type->ty) && v->type->ty == Tsarray) - { - // Block assignment from inside struct literals - TypeSArray *tsa = (TypeSArray *)v->type; - uinteger_t length = tsa->dim->toInteger(); - m = createBlockDuplicatedArrayLiteral(e->loc, v->type, m, (size_t)length); - } - else if (v->type->ty != Tarray && v->type->ty!=Taarray) // NOTE: do not copy array references - m = copyLiteral(m); - newelems->tdata()[i] = m; - } -#if DMDV2 - StructLiteralExp *r = new StructLiteralExp(e->loc, se->sd, newelems, se->stype); -#else - StructLiteralExp *r = new StructLiteralExp(e->loc, se->sd, newelems); -#endif - r->type = e->type; - r->ownedByCtfe = true; - return r; - } - else if (e->op == TOKfunction || e->op == TOKdelegate - || e->op == TOKsymoff || e->op == TOKnull - || e->op == TOKvar - || e->op == TOKint64 || e->op == TOKfloat64 - || e->op == TOKchar || e->op == TOKcomplex80 - || e->op == TOKvoid) - { // Simple value types - Expression *r = e->syntaxCopy(); - r->type = e->type; - return r; - } - else if ( isPointer(e->type) ) - { // For pointers, we only do a shallow copy. - Expression *r; - if (e->op == TOKaddress) - r = new AddrExp(e->loc, ((AddrExp *)e)->e1); - else if (e->op == TOKindex) - r = new IndexExp(e->loc, ((IndexExp *)e)->e1, ((IndexExp *)e)->e2); - else if (e->op == TOKdotvar) - r = new DotVarExp(e->loc, ((DotVarExp *)e)->e1, - ((DotVarExp *)e)->var -#if DMDV2 - , ((DotVarExp *)e)->hasOverloads -#endif - ); - else - assert(0); - r->type = e->type; - return r; - } - else if (e->op == TOKslice) - { // Array slices only do a shallow copy - Expression *r = new SliceExp(e->loc, ((SliceExp *)e)->e1, - ((SliceExp *)e)->lwr, ((SliceExp *)e)->upr); - r->type = e->type; - return r; - } - else if (e->op == TOKclassreference) - return new ClassReferenceExp(e->loc, ((ClassReferenceExp *)e)->value, e->type); - else - { - e->error("Internal Compiler Error: CTFE literal %s", e->toChars()); - assert(0); - return e; - } -} - -/* Deal with type painting. - * Type painting is a major nuisance: we can't just set - * e->type = type, because that would change the original literal. - * But, we can't simply copy the literal either, because that would change - * the values of any pointers. - */ -Expression *paintTypeOntoLiteral(Type *type, Expression *lit) -{ - if (lit->type == type) - return lit; - Expression *e; - if (lit->op == TOKslice) - { - SliceExp *se = (SliceExp *)lit; - e = new SliceExp(lit->loc, se->e1, se->lwr, se->upr); - } - else if (lit->op == TOKindex) - { - IndexExp *ie = (IndexExp *)lit; - e = new IndexExp(lit->loc, ie->e1, ie->e2); - } - else if (lit->op == TOKarrayliteral) - { - e = new SliceExp(lit->loc, lit, - new IntegerExp(0, 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit)); - } - else if (lit->op == TOKstring) - { - // For strings, we need to introduce another level of indirection - e = new SliceExp(lit->loc, lit, - new IntegerExp(0, 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit)); - } - else if (lit->op == TOKassocarrayliteral) - { - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)lit; - // TODO: we should be creating a reference to this AAExp, not - // just a ref to the keys and values. - bool wasOwned = aae->ownedByCtfe; - aae = new AssocArrayLiteralExp(lit->loc, aae->keys, aae->values); - aae->ownedByCtfe = wasOwned; - e = aae; - } - else - { // Can't type paint from struct to struct*; this needs another - // level of indirection - if (lit->op == TOKstructliteral && isPointer(type) ) - lit->error("CTFE internal error painting %s", type->toChars()); - e = copyLiteral(lit); - } - e->type = type; - return e; -} - - -Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e) -{ - if (e->op == TOKnull) - return paintTypeOntoLiteral(to, e); - if (e->op == TOKclassreference) - { // Disallow reinterpreting class casts. Do this by ensuring that - // the original class can implicitly convert to the target class - ClassDeclaration *originalClass = ((ClassReferenceExp *)e)->originalClass(); - if (originalClass->type->implicitConvTo(to)) - return paintTypeOntoLiteral(to, e); - else - return new NullExp(loc, to); - } - Expression *r = Cast(type, to, e); - if (r == EXP_CANT_INTERPRET) - error(loc, "cannot cast %s to %s at compile time", e->toChars(), to->toChars()); - if (e->op == TOKarrayliteral) - ((ArrayLiteralExp *)e)->ownedByCtfe = true; - if (e->op == TOKstring) - ((StringExp *)e)->ownedByCtfe = true; - return r; -} - -/* Set dest = src, where both dest and src are container value literals - * (ie, struct literals, or static arrays (can be an array literal or a string) - * Assignment is recursively in-place. - * Purpose: any reference to a member of 'dest' will remain valid after the - * assignment. - */ -void assignInPlace(Expression *dest, Expression *src) -{ - assert(dest->op == TOKstructliteral || dest->op == TOKarrayliteral || - dest->op == TOKstring); - Expressions *oldelems; - Expressions *newelems; - if (dest->op == TOKstructliteral) - { - assert(dest->op == src->op); - oldelems = ((StructLiteralExp *)dest)->elements; - newelems = ((StructLiteralExp *)src)->elements; - } - else if (dest->op == TOKarrayliteral && src->op==TOKarrayliteral) - { - oldelems = ((ArrayLiteralExp *)dest)->elements; - newelems = ((ArrayLiteralExp *)src)->elements; - } - else if (dest->op == TOKstring && src->op == TOKstring) - { - sliceAssignStringFromString((StringExp *)dest, (StringExp *)src, 0); - return; - } - else if (dest->op == TOKarrayliteral && src->op == TOKstring) - { - sliceAssignArrayLiteralFromString((ArrayLiteralExp *)dest, (StringExp *)src, 0); - return; - } - else if (src->op == TOKarrayliteral && dest->op == TOKstring) - { - sliceAssignStringFromArrayLiteral((StringExp *)dest, (ArrayLiteralExp *)src, 0); - return; - } - else assert(0); - - assert(oldelems->dim == newelems->dim); - - for (size_t i= 0; i < oldelems->dim; ++i) - { - Expression *e = newelems->tdata()[i]; - Expression *o = oldelems->tdata()[i]; - if (e->op == TOKstructliteral) - { - assert(o->op == e->op); - assignInPlace(o, e); - } - else if (e->type->ty == Tsarray && o->type->ty == Tsarray && e->op != TOKvoid) - { - assignInPlace(o, e); - } - else - { - oldelems->tdata()[i] = newelems->tdata()[i]; - } - } -} - -void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val, bool wantRef) -{ - assert( ae->type->ty == Tsarray || ae->type->ty == Tarray); -#if DMDV2 - Type *desttype = ((TypeArray *)ae->type)->next->castMod(0); - bool directblk = (val->type->toBasetype()->castMod(0)) == desttype; -#else - Type *desttype = ((TypeArray *)ae->type)->next; - bool directblk = (val->type->toBasetype()) == desttype; -#endif - - bool cow = !(val->op == TOKstructliteral || val->op == TOKarrayliteral - || val->op == TOKstring); - - for (size_t k = 0; k < ae->elements->dim; k++) - { - if (!directblk && ae->elements->tdata()[k]->op == TOKarrayliteral) - { - recursiveBlockAssign((ArrayLiteralExp *)ae->elements->tdata()[k], val, wantRef); - } - else - { - if (wantRef || cow) - ae->elements->tdata()[k] = val; - else - assignInPlace(ae->elements->tdata()[k], val); - } - } -} - - -Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_t fp, int post) -{ -#if LOG - printf("BinExp::interpretAssignCommon() %s\n", toChars()); -#endif - Expression *returnValue = EXP_CANT_INTERPRET; - Expression *e1 = this->e1; - if (!istate) - { - error("value of %s is not known at compile time", e1->toChars()); - return returnValue; - } - ++CtfeStatus::numAssignments; - /* Before we begin, we need to know if this is a reference assignment - * (dynamic array, AA, or class) or a value assignment. - * Determining this for slice assignments are tricky: we need to know - * if it is a block assignment (a[] = e) rather than a direct slice - * assignment (a[] = b[]). Note that initializers of multi-dimensional - * static arrays can have 2D block assignments (eg, int[7][7] x = 6;). - * So we need to recurse to determine if it is a block assignment. - */ - bool isBlockAssignment = false; - if (e1->op == TOKslice) - { - // a[] = e can have const e. So we compare the naked types. - Type *desttype = e1->type->toBasetype(); -#if DMDV2 - Type *srctype = e2->type->toBasetype()->castMod(0); -#else - Type *srctype = e2->type->toBasetype(); -#endif - while ( desttype->ty == Tsarray || desttype->ty == Tarray) - { - desttype = ((TypeArray *)desttype)->next; -#if DMDV2 - if (srctype == desttype->castMod(0)) -#else - if (srctype == desttype) -#endif - { - isBlockAssignment = true; - break; - } - } - } - bool wantRef = false; - if (!fp && this->e1->type->toBasetype() == this->e2->type->toBasetype() && - (e1->type->toBasetype()->ty == Tarray || isAssocArray(e1->type) - || e1->type->toBasetype()->ty == Tclass) - // e = *x is never a reference, because *x is always a value - && this->e2->op != TOKstar - ) - { -#if DMDV2 - wantRef = true; -#else - /* D1 doesn't have const in the type system. But there is still a - * vestigal const in the form of static const variables. - * Problematic code like: - * const int [] x = [1,2,3]; - * int [] y = x; - * can be dealt with by making this a non-ref assign (y = x.dup). - * Otherwise it's a big mess. - */ - VarDeclaration * targetVar = findParentVar(e2, istate->localThis); - if (!(targetVar && targetVar->isConst())) - wantRef = true; - // slice assignment of static arrays is not reference assignment - if ((e1->op==TOKslice) && ((SliceExp *)e1)->e1->type->ty == Tsarray) - wantRef = false; -#endif - // If it is assignment from a ref parameter, it's not a ref assignment - if (this->e2->op == TOKvar) - { - VarDeclaration *v = ((VarExp *)this->e2)->var->isVarDeclaration(); - if (v && (v->storage_class & (STCref | STCout))) - wantRef = false; - } - } - if (isBlockAssignment && (e2->type->toBasetype()->ty == Tarray || e2->type->toBasetype()->ty == Tsarray)) - { - wantRef = true; - } - // If it is a construction of a ref variable, it is a ref assignment - if (op == TOKconstruct && this->e1->op==TOKvar - && ((VarExp*)this->e1)->var->storage_class & STCref) - { - wantRef = true; - } - - if (fp) - { - while (e1->op == TOKcast) - { CastExp *ce = (CastExp *)e1; - e1 = ce->e1; - } - } - if (exceptionOrCantInterpret(e1)) - return e1; - - // First, deal with this = e; and call() = e; - if (e1->op == TOKthis) - { - e1 = istate->localThis; - } - if (e1->op == TOKcall) - { - bool oldWaiting = istate->awaitingLvalueReturn; - istate->awaitingLvalueReturn = true; - e1 = e1->interpret(istate); - istate->awaitingLvalueReturn = oldWaiting; - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKarrayliteral || e1->op == TOKstring) - { - // f() = e2, when f returns an array, is always a slice assignment. - // Convert into arr[0..arr.length] = e2 - e1 = new SliceExp(loc, e1, - new IntegerExp(0, 0, Type::tsize_t), - ArrayLength(Type::tsize_t, e1)); - e1->type = type; - } - } - if (e1->op == TOKstar) - { - e1 = e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - if (!(e1->op == TOKvar || e1->op == TOKdotvar || e1->op == TOKindex - || e1->op == TOKslice)) - { - error("cannot dereference invalid pointer %s", - this->e1->toChars()); - return EXP_CANT_INTERPRET; - } - } - - if (!(e1->op == TOKarraylength || e1->op == TOKvar || e1->op == TOKdotvar - || e1->op == TOKindex || e1->op == TOKslice)) - { - error("CTFE internal error: unsupported assignment %s", toChars()); - return EXP_CANT_INTERPRET; - } - - Expression * newval = NULL; - - if (!wantRef) - { // We need to treat pointers specially, because TOKsymoff can be used to - // return a value OR a pointer - assert(e1); - assert(e1->type); - if ( isPointer(e1->type) && (e2->op == TOKsymoff || e2->op==TOKaddress || e2->op==TOKvar)) - newval = this->e2->interpret(istate, ctfeNeedLvalue); - else - newval = this->e2->interpret(istate); - if (exceptionOrCantInterpret(newval)) - return newval; - } - // ---------------------------------------------------- - // Deal with read-modify-write assignments. - // Set 'newval' to the final assignment value - // Also determine the return value (except for slice - // assignments, which are more complicated) - // ---------------------------------------------------- - - if (fp || e1->op == TOKarraylength) - { - // If it isn't a simple assignment, we need the existing value - Expression * oldval = e1->interpret(istate); - if (exceptionOrCantInterpret(oldval)) - return oldval; - while (oldval->op == TOKvar) - { - oldval = resolveReferences(oldval, istate->localThis); - oldval = oldval->interpret(istate); - if (exceptionOrCantInterpret(oldval)) - return oldval; - } - - if (fp) - { - // ~= can create new values (see bug 6052) - if (op == TOKcatass) - { - // We need to dup it. We can skip this if it's a dynamic array, - // because it gets copied later anyway - if (newval->type->ty != Tarray) - newval = copyLiteral(newval); - if (newval->op == TOKslice) - newval = resolveSlice(newval); - // It becomes a reference assignment - wantRef = true; - } - if (oldval->op == TOKslice) - oldval = resolveSlice(oldval); - if (this->e1->type->ty == Tpointer && this->e2->type->isintegral() - && (op==TOKaddass || op == TOKminass || - op == TOKplusplus || op == TOKminusminus)) - { - oldval = this->e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(oldval)) - return oldval; - newval = this->e2->interpret(istate); - if (exceptionOrCantInterpret(newval)) - return newval; - newval = pointerArithmetic(loc, op, type, oldval, newval); - } - else if (this->e1->type->ty == Tpointer) - { - error("pointer expression %s cannot be interpreted at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - else - { - newval = (*fp)(type, oldval, newval); - } - if (newval == EXP_CANT_INTERPRET) - { - error("Cannot interpret %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - if (exceptionOrCantInterpret(newval)) - return newval; - // Determine the return value - returnValue = ctfeCast(loc, type, type, post ? oldval : newval); - if (exceptionOrCantInterpret(returnValue)) - return returnValue; - } - else - returnValue = newval; - if (e1->op == TOKarraylength) - { - size_t oldlen = oldval->toInteger(); - size_t newlen = newval->toInteger(); - if (oldlen == newlen) // no change required -- we're done! - return returnValue; - // Now change the assignment from arr.length = n into arr = newval - e1 = ((ArrayLengthExp *)e1)->e1; - if (oldlen != 0) - { // Get the old array literal. - oldval = e1->interpret(istate); - while (oldval->op == TOKvar) - { oldval = resolveReferences(oldval, istate->localThis); - oldval = oldval->interpret(istate); - } - } - if (oldval->op == TOKslice) - oldval = resolveSlice(oldval); - Type *t = e1->type->toBasetype(); - if (t->ty == Tarray) - { - Type *elemType= NULL; - elemType = ((TypeArray *)t)->next; - assert(elemType); - Expression *defaultElem = elemType->defaultInitLiteral(loc); - - Expressions *elements = new Expressions(); - elements->setDim(newlen); - size_t copylen = oldlen < newlen ? oldlen : newlen; - if (oldval->op == TOKstring) - { - StringExp *oldse = (StringExp *)oldval; - unsigned char *s = (unsigned char *)mem.calloc(newlen + 1, oldse->sz); - memcpy(s, oldse->string, copylen * oldse->sz); - unsigned defaultValue = (unsigned)(defaultElem->toInteger()); - for (size_t elemi = copylen; elemi < newlen; ++elemi) - { - switch (oldse->sz) - { - case 1: s[elemi] = defaultValue; break; - case 2: ((unsigned short *)s)[elemi] = defaultValue; break; - case 4: ((unsigned *)s)[elemi] = defaultValue; break; - default: assert(0); - } - } - StringExp *se = new StringExp(loc, s, newlen); - se->type = t; - se->sz = oldse->sz; - se->committed = oldse->committed; - se->ownedByCtfe = true; - newval = se; - } - else - { - if (oldlen !=0) - assert(oldval->op == TOKarrayliteral); - ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval; - for (size_t i = 0; i < copylen; i++) - (*elements)[i] = ae->elements->tdata()[i]; - if (elemType->ty == Tstruct || elemType->ty == Tsarray) - { /* If it is an aggregate literal representing a value type, - * we need to create a unique copy for each element - */ - for (size_t i = copylen; i < newlen; i++) - (*elements)[i] = copyLiteral(defaultElem); - } - else - { - for (size_t i = copylen; i < newlen; i++) - (*elements)[i] = defaultElem; - } - ArrayLiteralExp *aae = new ArrayLiteralExp(0, elements); - aae->type = t; - newval = aae; - aae->ownedByCtfe = true; - } - // We have changed it into a reference assignment - // Note that returnValue is still the new length. - wantRef = true; - if (e1->op == TOKstar) - { // arr.length+=n becomes (t=&arr, *(t).length=*(t).length+n); - e1 = e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - } - } - else - { - error("%s is not yet supported at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - - } - } - else if (!wantRef && e1->op != TOKslice) - { /* Look for special case of struct being initialized with 0. - */ - if (type->toBasetype()->ty == Tstruct && newval->op == TOKint64) - { - newval = type->defaultInitLiteral(loc); - if (newval->op != TOKstructliteral) - { - error("nested structs with constructors are not yet supported in CTFE (Bug 6419)"); - return EXP_CANT_INTERPRET; - } - } - newval = ctfeCast(loc, type, type, newval); - if (exceptionOrCantInterpret(newval)) - return newval; - returnValue = newval; - } - if (exceptionOrCantInterpret(newval)) - return newval; - - // ------------------------------------------------- - // Make sure destination can be modified - // ------------------------------------------------- - // Make sure we're not trying to modify a global or static variable - // We do this by locating the ultimate parent variable which gets modified. - VarDeclaration * ultimateVar = findParentVar(e1, istate->localThis); - if (ultimateVar && ultimateVar->isDataseg() && !ultimateVar->isCTFE()) - { // Can't modify global or static data - error("%s cannot be modified at compile time", ultimateVar->toChars()); - return EXP_CANT_INTERPRET; - } - - e1 = resolveReferences(e1, istate->localThis); - - // Unless we have a simple var assignment, we're - // only modifying part of the variable. So we need to make sure - // that the parent variable exists. - if (e1->op != TOKvar && ultimateVar && !ultimateVar->getValue()) - ultimateVar->setValue(copyLiteral(ultimateVar->type->defaultInitLiteral(loc))); - - // --------------------------------------- - // Deal with reference assignment - // (We already have 'newval' for arraylength operations) - // --------------------------------------- - if (wantRef && !fp && this->e1->op != TOKarraylength) - { - newval = this->e2->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(newval)) - return newval; - // If it is an assignment from a array function parameter passed by - // reference, resolve the reference. (This should NOT happen for - // non-reference types). - if (newval->op == TOKvar && (newval->type->ty == Tarray || - newval->type->ty == Tclass)) - { - newval = newval->interpret(istate); - } - - if (newval->op == TOKassocarrayliteral || newval->op == TOKstring || - newval->op==TOKarrayliteral) - { - if (needToCopyLiteral(newval)) - newval = copyLiteral(newval); - } - returnValue = newval; - } - - // --------------------------------------- - // Deal with AA index assignment - // --------------------------------------- - /* This needs special treatment if the AA doesn't exist yet. - * There are two special cases: - * (1) If the AA is itself an index of another AA, we may need to create - * multiple nested AA literals before we can insert the new value. - * (2) If the ultimate AA is null, no insertion happens at all. Instead, we - * create nested AA literals, and change it into a assignment. - */ - if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) - { - IndexExp *ie = (IndexExp *)e1; - int depth = 0; // how many nested AA indices are there? - while (ie->e1->op == TOKindex && ((IndexExp *)ie->e1)->e1->type->toBasetype()->ty == Taarray) - { - ie = (IndexExp *)ie->e1; - ++depth; - } - Expression *aggregate = resolveReferences(ie->e1, istate->localThis); - Expression *oldagg = aggregate; - // Get the AA to be modified. (We do an LvalueRef interpret, unless it - // is a simple ref parameter -- in which case, we just want the value) - aggregate = aggregate->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - if (aggregate->op == TOKassocarrayliteral) - { // Normal case, ultimate parent AA already exists - // We need to walk from the deepest index up, checking that an AA literal - // already exists on each level. - Expression *index = ((IndexExp *)e1)->e2->interpret(istate); - if (exceptionOrCantInterpret(index)) - return index; - if (index->op == TOKslice) // only happens with AA assignment - index = resolveSlice(index); - AssocArrayLiteralExp *existingAA = (AssocArrayLiteralExp *)aggregate; - while (depth > 0) - { // Walk the syntax tree to find the indexExp at this depth - IndexExp *xe = (IndexExp *)e1; - for (int d= 0; d < depth; ++d) - xe = (IndexExp *)xe->e1; - - Expression *indx = xe->e2->interpret(istate); - if (exceptionOrCantInterpret(indx)) - return indx; - if (indx->op == TOKslice) // only happens with AA assignment - indx = resolveSlice(indx); - - // Look up this index in it up in the existing AA, to get the next level of AA. - AssocArrayLiteralExp *newAA = (AssocArrayLiteralExp *)findKeyInAA(loc, existingAA, indx); - if (exceptionOrCantInterpret(newAA)) - return newAA; - if (!newAA) - { // Doesn't exist yet, create an empty AA... - Expressions *valuesx = new Expressions(); - Expressions *keysx = new Expressions(); - newAA = new AssocArrayLiteralExp(loc, keysx, valuesx); - newAA->type = xe->type; - newAA->ownedByCtfe = true; - //... and insert it into the existing AA. - existingAA->keys->push(indx); - existingAA->values->push(newAA); - } - existingAA = newAA; - --depth; - } - if (assignAssocArrayElement(loc, existingAA, index, newval) == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - return returnValue; - } - else - { /* The AA is currently null. 'aggregate' is actually a reference to - * whatever contains it. It could be anything: var, dotvarexp, ... - * We rewrite the assignment from: aggregate[i][j] = newval; - * into: aggregate = [i:[j: newval]]; - */ - while (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) - { - Expression *index = ((IndexExp *)e1)->e2->interpret(istate); - if (exceptionOrCantInterpret(index)) - return index; - if (index->op == TOKslice) // only happens with AA assignment - index = resolveSlice(index); - Expressions *valuesx = new Expressions(); - Expressions *keysx = new Expressions(); - valuesx->push(newval); - keysx->push(index); - AssocArrayLiteralExp *newaae = new AssocArrayLiteralExp(loc, keysx, valuesx); - newaae->ownedByCtfe = true; - newaae->type = e1->type; - newval = newaae; - e1 = ((IndexExp *)e1)->e1; - } - // We must return to the original aggregate, in case it was a reference - wantRef = true; - e1 = oldagg; - // fall through -- let the normal assignment logic take care of it - } - } - - // --------------------------------------- - // Deal with dotvar expressions - // --------------------------------------- - // Because structs are not reference types, dotvar expressions can be - // collapsed into a single assignment. - if (!wantRef && e1->op == TOKdotvar) - { - // Strip of all of the leading dotvars, unless we started with a call - // or a ref parameter - // (in which case, we already have the lvalue). - if (this->e1->op != TOKcall && !(this->e1->op==TOKvar - && ((VarExp*)this->e1)->var->storage_class & (STCref | STCout))) - e1 = e1->interpret(istate, isPointer(type)? ctfeNeedLvalueRef : ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKstructliteral && newval->op == TOKstructliteral) - { - assignInPlace(e1, newval); - return returnValue; - } - } -#if LOGASSIGN - if (wantRef) - printf("REF ASSIGN: %s=%s\n", e1->toChars(), newval->toChars()); - else - printf("ASSIGN: %s=%s\n", e1->toChars(), newval->toChars()); - showCtfeExpr(newval); -#endif - - /* Assignment to variable of the form: - * v = newval - */ - if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (wantRef) - { - v->setValueNull(); - v->setValue(newval); - } - else if (e1->type->toBasetype()->ty == Tstruct) - { - // In-place modification - if (newval->op != TOKstructliteral) - { - error("CTFE internal error assigning struct"); - return EXP_CANT_INTERPRET; - } - newval = copyLiteral(newval); - if (v->getValue()) - assignInPlace(v->getValue(), newval); - else - v->setValue(newval); - } - else - { - TY tyE1 = e1->type->toBasetype()->ty; - if (tyE1 == Tarray || tyE1 == Taarray) - { // arr op= arr - v->setValue(newval); - } - else - { - v->setValue(newval); - } - } - } - else if (e1->op == TOKdotvar) - { - /* Assignment to member variable of the form: - * e.v = newval - */ - Expression *exx = ((DotVarExp *)e1)->e1; - if (wantRef && exx->op != TOKstructliteral) - { - exx = exx->interpret(istate); - if (exceptionOrCantInterpret(exx)) - return exx; - } - if (exx->op != TOKstructliteral && exx->op != TOKclassreference) - { - error("CTFE internal error: Dotvar assignment"); - return EXP_CANT_INTERPRET; - } - VarDeclaration *member = ((DotVarExp *)e1)->var->isVarDeclaration(); - if (!member) - { - error("CTFE internal error: Dotvar assignment"); - return EXP_CANT_INTERPRET; - } - StructLiteralExp *se = exx->op == TOKstructliteral - ? (StructLiteralExp *)exx - : ((ClassReferenceExp *)exx)->value; - int fieldi = exx->op == TOKstructliteral - ? findFieldIndexByName(se->sd, member) - : ((ClassReferenceExp *)exx)->findFieldIndexByName(member); - if (fieldi == -1) - { - error("CTFE internal error: cannot find field %s in %s", member->toChars(), exx->toChars()); - return EXP_CANT_INTERPRET; - } - assert(fieldi >= 0 && fieldi < se->elements->dim); - // If it's a union, set all other members of this union to void - if (exx->op == TOKstructliteral) - { - assert(se->sd); - int unionStart = se->sd->firstFieldInUnion(fieldi); - int unionSize = se->sd->numFieldsInUnion(fieldi); - for(int i = unionStart; i < unionStart + unionSize; ++i) - { if (i == fieldi) - continue; - Expression **el = &se->elements->tdata()[i]; - if ((*el)->op != TOKvoid) - *el = (*el)->type->voidInitLiteral(member); - } - } - - if (newval->op == TOKstructliteral) - assignInPlace(se->elements->tdata()[fieldi], newval); - else - se->elements->tdata()[fieldi] = newval; - return returnValue; - } - else if (e1->op == TOKindex) - { - /* Assignment to array element of the form: - * aggregate[i] = newval - * aggregate is not AA (AAs were dealt with already). - */ - IndexExp *ie = (IndexExp *)e1; - assert(ie->e1->type->toBasetype()->ty != Taarray); - uinteger_t destarraylen = 0; - - // Set the $ variable, and find the array literal to modify - if (ie->e1->type->toBasetype()->ty != Tpointer) - { - Expression *oldval = ie->e1->interpret(istate); - if (oldval->op == TOKnull) - { - error("cannot index null array %s", ie->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (oldval->op != TOKarrayliteral && oldval->op != TOKstring - && oldval->op != TOKslice) - { - error("cannot determine length of %s at compile time", - ie->e1->toChars()); - return EXP_CANT_INTERPRET; - } - destarraylen = resolveArrayLength(oldval); - if (ie->lengthVar) - { - IntegerExp *dollarExp = new IntegerExp(loc, destarraylen, Type::tsize_t); - ctfeStack.push(ie->lengthVar); - ie->lengthVar->setValue(dollarExp); - } - } - Expression *index = ie->e2->interpret(istate); - if (ie->lengthVar) - ctfeStack.pop(ie->lengthVar); // $ is defined only inside [] - if (exceptionOrCantInterpret(index)) - return index; - - assert (index->op != TOKslice); // only happens with AA assignment - - ArrayLiteralExp *existingAE = NULL; - StringExp *existingSE = NULL; - - Expression *aggregate = resolveReferences(ie->e1, istate->localThis); - - // Set the index to modify, and check that it is in range - dinteger_t indexToModify = index->toInteger(); - if (ie->e1->type->toBasetype()->ty == Tpointer) - { - dinteger_t ofs; - aggregate = aggregate->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - if (aggregate->op == TOKnull) - { - error("cannot index through null pointer %s", ie->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (aggregate->op == TOKint64) - { - error("cannot index through invalid pointer %s of value %s", - ie->e1->toChars(), aggregate->toChars()); - return EXP_CANT_INTERPRET; - } - aggregate = getAggregateFromPointer(aggregate, &ofs); - indexToModify += ofs; - if (aggregate->op != TOKslice && aggregate->op != TOKstring && - aggregate->op != TOKarrayliteral && aggregate->op != TOKassocarrayliteral) - { - if (indexToModify != 0) - { - error("pointer index [%lld] lies outside memory block [0..1]", indexToModify); - return EXP_CANT_INTERPRET; - } - // It is equivalent to *aggregate = newval. - // Aggregate could be varexp, a dotvar, ... - // TODO: we could support this - error("indexed assignment of non-array pointers is not yet supported at compile time; use *%s = %s instead", - ie->e1->toChars(), e2->toChars()); - return EXP_CANT_INTERPRET; - } - destarraylen = resolveArrayLength(aggregate); - } - if (indexToModify >= destarraylen) - { - error("array index %lld is out of bounds [0..%lld]", indexToModify, - destarraylen); - return EXP_CANT_INTERPRET; - } - - /* The only possible indexable LValue aggregates are array literals, and - * slices of array literals. - */ - if (aggregate->op == TOKindex || aggregate->op == TOKdotvar || - aggregate->op == TOKslice || aggregate->op == TOKcall || - aggregate->op == TOKstar) - { - Expression *origagg = aggregate; - aggregate = aggregate->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - // The array could be an index of an AA. Resolve it if so. - if (aggregate->op == TOKindex && - ((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral) - { - IndexExp *ix = (IndexExp *)aggregate; - aggregate = findKeyInAA(loc, (AssocArrayLiteralExp *)ix->e1, ix->e2); - if (!aggregate) - { - error("key %s not found in associative array %s", - ix->e2->toChars(), ix->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - } - } - if (aggregate->op == TOKvar) - { - VarExp *ve = (VarExp *)aggregate; - VarDeclaration *v = ve->var->isVarDeclaration(); - aggregate = v->getValue(); - if (aggregate->op == TOKnull) - { - // This would be a runtime segfault - error("cannot index null array %s", v->toChars()); - return EXP_CANT_INTERPRET; - } - } - if (aggregate->op == TOKslice) - { - SliceExp *sexp = (SliceExp *)aggregate; - aggregate = sexp->e1; - Expression *lwr = sexp->lwr->interpret(istate); - indexToModify += lwr->toInteger(); - } - if (aggregate->op == TOKarrayliteral) - existingAE = (ArrayLiteralExp *)aggregate; - else if (aggregate->op == TOKstring) - existingSE = (StringExp *)aggregate; - else - { - error("CTFE internal compiler error %s", aggregate->toChars()); - return EXP_CANT_INTERPRET; - } - if (!wantRef && newval->op == TOKslice) - { - newval = resolveSlice(newval); - if (newval == EXP_CANT_INTERPRET) - { - error("Compiler error: CTFE index assign %s", toChars()); - assert(0); - } - } - if (wantRef && newval->op == TOKindex - && ((IndexExp *)newval)->e1 == aggregate) - { // It's a circular reference, resolve it now - newval = newval->interpret(istate); - } - - if (existingAE) - { - if (newval->op == TOKstructliteral) - assignInPlace((Expression *)(existingAE->elements->tdata()[indexToModify]), newval); - else - existingAE->elements->tdata()[indexToModify] = newval; - return returnValue; - } - if (existingSE) - { - unsigned char *s = (unsigned char *)existingSE->string; - if (!existingSE->ownedByCtfe) - { - error("cannot modify read-only string literal %s", ie->e1->toChars()); - return EXP_CANT_INTERPRET; - } - unsigned value = newval->toInteger(); - switch (existingSE->sz) - { - case 1: s[indexToModify] = value; break; - case 2: ((unsigned short *)s)[indexToModify] = value; break; - case 4: ((unsigned *)s)[indexToModify] = value; break; - default: - assert(0); - break; - } - return returnValue; - } - else - { - error("Index assignment %s is not yet supported in CTFE ", toChars()); - return EXP_CANT_INTERPRET; - } - return returnValue; - } - else if (e1->op == TOKslice) - { - // ------------------------------ - // aggregate[] = newval - // aggregate[low..upp] = newval - // ------------------------------ - SliceExp * sexp = (SliceExp *)e1; - // Set the $ variable - Expression *oldval = sexp->e1; - bool assignmentToSlicedPointer = false; - if (isPointer(oldval->type)) - { // Slicing a pointer - oldval = oldval->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(oldval)) - return oldval; - dinteger_t ofs; - oldval = getAggregateFromPointer(oldval, &ofs); - assignmentToSlicedPointer = true; - } else - oldval = oldval->interpret(istate); - - if (oldval->op != TOKarrayliteral && oldval->op != TOKstring - && oldval->op != TOKslice && oldval->op != TOKnull) - { - if (assignmentToSlicedPointer) - { - error("pointer %s cannot be sliced at compile time (it does not point to an array)", - sexp->e1->toChars()); - } - else - error("CTFE ICE: cannot resolve array length"); - return EXP_CANT_INTERPRET; - } - uinteger_t dollar = resolveArrayLength(oldval); - if (sexp->lengthVar) - { - Expression *arraylen = new IntegerExp(loc, dollar, Type::tsize_t); - ctfeStack.push(sexp->lengthVar); - sexp->lengthVar->setValue(arraylen); - } - - Expression *upper = NULL; - Expression *lower = NULL; - if (sexp->upr) - upper = sexp->upr->interpret(istate); - if (exceptionOrCantInterpret(upper)) - { - if (sexp->lengthVar) - ctfeStack.pop(sexp->lengthVar); // $ is defined only in [L..U] - return upper; - } - if (sexp->lwr) - lower = sexp->lwr->interpret(istate); - if (sexp->lengthVar) - ctfeStack.pop(sexp->lengthVar); // $ is defined only in [L..U] - if (exceptionOrCantInterpret(lower)) - return lower; - - size_t dim = dollar; - size_t upperbound = upper ? upper->toInteger() : dim; - int lowerbound = lower ? lower->toInteger() : 0; - - if (!assignmentToSlicedPointer && (((int)lowerbound < 0) || (upperbound > dim))) - { - error("Array bounds [0..%d] exceeded in slice [%d..%d]", - dim, lowerbound, upperbound); - return EXP_CANT_INTERPRET; - } - if (upperbound == lowerbound) - return newval; - - Expression *aggregate = resolveReferences(((SliceExp *)e1)->e1, istate->localThis); - dinteger_t firstIndex = lowerbound; - - ArrayLiteralExp *existingAE = NULL; - StringExp *existingSE = NULL; - - /* The only possible slicable LValue aggregates are array literals, - * and slices of array literals. - */ - - if (aggregate->op == TOKindex || aggregate->op == TOKdotvar || - aggregate->op == TOKslice || - aggregate->op == TOKstar || aggregate->op == TOKcall) - { - aggregate = aggregate->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - // The array could be an index of an AA. Resolve it if so. - if (aggregate->op == TOKindex && - ((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral) - { - IndexExp *ix = (IndexExp *)aggregate; - aggregate = findKeyInAA(loc, (AssocArrayLiteralExp *)ix->e1, ix->e2); - if (!aggregate) - { - error("key %s not found in associative array %s", - ix->e2->toChars(), ix->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - } - } - if (aggregate->op == TOKvar) - { - VarExp *ve = (VarExp *)(aggregate); - VarDeclaration *v = ve->var->isVarDeclaration(); - aggregate = v->getValue(); - } - if (aggregate->op == TOKslice) - { // Slice of a slice --> change the bounds - SliceExp *sexpold = (SliceExp *)aggregate; - dinteger_t hi = upperbound + sexpold->lwr->toInteger(); - firstIndex = lowerbound + sexpold->lwr->toInteger(); - if (hi > sexpold->upr->toInteger()) - { - error("slice [%d..%d] exceeds array bounds [0..%lld]", - lowerbound, upperbound, - sexpold->upr->toInteger() - sexpold->lwr->toInteger()); - return EXP_CANT_INTERPRET; - } - aggregate = sexpold->e1; - } - if ( isPointer(aggregate->type) ) - { // Slicing a pointer --> change the bounds - aggregate = sexp->e1->interpret(istate, ctfeNeedLvalue); - dinteger_t ofs; - aggregate = getAggregateFromPointer(aggregate, &ofs); - if (aggregate->op == TOKnull) - { - error("cannot slice null pointer %s", sexp->e1->toChars()); - return EXP_CANT_INTERPRET; - } - dinteger_t hi = upperbound + ofs; - firstIndex = lowerbound + ofs; - if (firstIndex < 0 || hi > dim) - { - error("slice [lld..%lld] exceeds memory block bounds [0..%lld]", - firstIndex, hi, dim); - return EXP_CANT_INTERPRET; - } - } - if (aggregate->op == TOKarrayliteral) - existingAE = (ArrayLiteralExp *)aggregate; - else if (aggregate->op == TOKstring) - existingSE = (StringExp *)aggregate; - if (existingSE && !existingSE->ownedByCtfe) - { error("cannot modify read-only string literal %s", sexp->e1->toChars()); - return EXP_CANT_INTERPRET; - } - - if (!wantRef && newval->op == TOKslice) - { - newval = resolveSlice(newval); - if (newval == EXP_CANT_INTERPRET) - { - error("Compiler error: CTFE slice %s", toChars()); - assert(0); - } - } - if (wantRef && newval->op == TOKindex - && ((IndexExp *)newval)->e1 == aggregate) - { // It's a circular reference, resolve it now - newval = newval->interpret(istate); - } - - // For slice assignment, we check that the lengths match. - size_t srclen = 0; - if (newval->op == TOKarrayliteral) - srclen = ((ArrayLiteralExp *)newval)->elements->dim; - else if (newval->op == TOKstring) - srclen = ((StringExp *)newval)->len; - if (!isBlockAssignment && srclen != (upperbound - lowerbound)) - { - error("Array length mismatch assigning [0..%d] to [%d..%d]", srclen, lowerbound, upperbound); - return EXP_CANT_INTERPRET; - } - - if (!isBlockAssignment && newval->op == TOKarrayliteral && existingAE) - { - Expressions *oldelems = existingAE->elements; - Expressions *newelems = ((ArrayLiteralExp *)newval)->elements; - for (size_t j = 0; j < newelems->dim; j++) - { - oldelems->tdata()[j + firstIndex] = newelems->tdata()[j]; - } - return newval; - } - else if (newval->op == TOKstring && existingSE) - { - sliceAssignStringFromString((StringExp *)existingSE, (StringExp *)newval, firstIndex); - return newval; - } - else if (newval->op == TOKstring && existingAE - && existingAE->type->isString()) - { /* Mixed slice: it was initialized as an array literal of chars. - * Now a slice of it is being set with a string. - */ - sliceAssignArrayLiteralFromString(existingAE, (StringExp *)newval, firstIndex); - return newval; - } - else if (newval->op == TOKarrayliteral && existingSE) - { /* Mixed slice: it was initialized as a string literal. - * Now a slice of it is being set with an array literal. - */ - sliceAssignStringFromArrayLiteral(existingSE, (ArrayLiteralExp *)newval, firstIndex); - return newval; - } - else if (existingSE) - { // String literal block slice assign - unsigned value = newval->toInteger(); - unsigned char *s = (unsigned char *)existingSE->string; - for (size_t j = 0; j < upperbound-lowerbound; j++) - { - switch (existingSE->sz) - { - case 1: s[j+firstIndex] = value; break; - case 2: ((unsigned short *)s)[j+firstIndex] = value; break; - case 4: ((unsigned *)s)[j+firstIndex] = value; break; - default: - assert(0); - break; - } - } - if (goal == ctfeNeedNothing) - return NULL; // avoid creating an unused literal - SliceExp *retslice = new SliceExp(loc, existingSE, - new IntegerExp(loc, firstIndex, Type::tsize_t), - new IntegerExp(loc, firstIndex + upperbound-lowerbound, Type::tsize_t)); - retslice->type = this->type; - return retslice->interpret(istate); - } - else if (existingAE) - { - /* Block assignment, initialization of static arrays - * x[] = e - * x may be a multidimensional static array. (Note that this - * only happens with array literals, never with strings). - */ - Expressions * w = existingAE->elements; - assert( existingAE->type->ty == Tsarray || - existingAE->type->ty == Tarray); -#if DMDV2 - Type *desttype = ((TypeArray *)existingAE->type)->next->castMod(0); - bool directblk = (e2->type->toBasetype()->castMod(0)) == desttype; -#else - Type *desttype = ((TypeArray *)existingAE->type)->next; - bool directblk = (e2->type->toBasetype()) == desttype; -#endif - bool cow = !(newval->op == TOKstructliteral || newval->op == TOKarrayliteral - || newval->op == TOKstring); - for (size_t j = 0; j < upperbound-lowerbound; j++) - { - if (!directblk) - // Multidimensional array block assign - recursiveBlockAssign((ArrayLiteralExp *)w->tdata()[j+firstIndex], newval, wantRef); - else - { - if (wantRef || cow) - existingAE->elements->tdata()[j+firstIndex] = newval; - else - assignInPlace(existingAE->elements->tdata()[j+firstIndex], newval); - } - } - if (goal == ctfeNeedNothing) - return NULL; // avoid creating an unused literal - SliceExp *retslice = new SliceExp(loc, existingAE, - new IntegerExp(loc, firstIndex, Type::tsize_t), - new IntegerExp(loc, firstIndex + upperbound-lowerbound, Type::tsize_t)); - retslice->type = this->type; - return retslice->interpret(istate); - } - else - error("Slice operation %s cannot be evaluated at compile time", toChars()); - } - else - { - error("%s cannot be evaluated at compile time", toChars()); - } - return returnValue; -} - -Expression *AssignExp::interpret(InterState *istate, CtfeGoal goal) -{ - return interpretAssignCommon(istate, goal, NULL); -} - -#define BIN_ASSIGN_INTERPRET_CTFE(op, ctfeOp) \ -Expression *op##AssignExp::interpret(InterState *istate, CtfeGoal goal) \ -{ \ - return interpretAssignCommon(istate, goal, &ctfeOp); \ -} - -#define BIN_ASSIGN_INTERPRET(op) BIN_ASSIGN_INTERPRET_CTFE(op, op) - -BIN_ASSIGN_INTERPRET(Add) -BIN_ASSIGN_INTERPRET(Min) -BIN_ASSIGN_INTERPRET_CTFE(Cat, ctfeCat) -BIN_ASSIGN_INTERPRET(Mul) -BIN_ASSIGN_INTERPRET(Div) -BIN_ASSIGN_INTERPRET(Mod) -BIN_ASSIGN_INTERPRET(Shl) -BIN_ASSIGN_INTERPRET(Shr) -BIN_ASSIGN_INTERPRET(Ushr) -BIN_ASSIGN_INTERPRET(And) -BIN_ASSIGN_INTERPRET(Or) -BIN_ASSIGN_INTERPRET(Xor) -#if DMDV2 -BIN_ASSIGN_INTERPRET(Pow) -#endif - -Expression *PostExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("PostExp::interpret() %s\n", toChars()); -#endif - Expression *e; - if (op == TOKplusplus) - e = interpretAssignCommon(istate, goal, &Add, 1); - else - e = interpretAssignCommon(istate, goal, &Min, 1); -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("PostExp::interpret() CANT\n"); -#endif - return e; -} - -/* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison; - * -1 if e is a p1 < p2 or p1 <= p2 pointer comparison; - * 0 otherwise - */ -int isPointerCmpExp(Expression *e, Expression **p1, Expression **p2) -{ - int ret = 1; - while (e->op == TOKnot) - { ret *= -1; - e = ((NotExp *)e)->e1; - } - switch(e->op) - { - case TOKlt: - case TOKle: - ret *= -1; - /* fall through */ - case TOKgt: - case TOKge: - *p1 = ((BinExp *)e)->e1; - *p2 = ((BinExp *)e)->e2; - if ( !(isPointer((*p1)->type) && isPointer((*p2)->type)) ) - ret = 0; - break; - default: - ret = 0; - break; - } - return ret; -} - -/** Negate a relational operator, eg >= becomes < - */ -TOK reverseRelation(TOK op) -{ - switch(op) - { - case TOKge: return TOKlt; - case TOKgt: return TOKle; - case TOKle: return TOKgt; - case TOKlt: return TOKge; - default: - return assert(0), TOKreserved; - } -} - -/** If this is a four pointer relation, evaluate it, else return NULL. - * - * This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2) - * where p1, p2 are expressions yielding pointers to memory block p, - * and q1, q2 are expressions yielding pointers to memory block q. - * This expression is valid even if p and q are independent memory - * blocks and are therefore not normally comparable; the && form returns true - * if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns - * true if [p1..p2] lies outside [q1..q2], and false otherwise. - * - * Within the expression, any ordering of p1, p2, q1, q2 is permissible; - * the comparison operators can be any of >, <, <=, >=, provided that - * both directions (p > q and p < q) are checked. Additionally the - * relational sub-expressions can be negated, eg - * ( !(q1 < p1) && p2 <= q2 ) is valid. - */ -Expression *BinExp::interpretFourPointerRelation(InterState *istate, CtfeGoal goal) -{ - assert(op == TOKandand || op == TOKoror); - - /* It can only be an isInside expression, if both e1 and e2 are - * directional pointer comparisons. - * Note that this check can be made statically; it does not depends on - * any runtime values. This allows a JIT implementation to compile a - * special AndAndPossiblyInside, keeping the normal AndAnd case efficient. - */ - - // Save the pointer expressions and the comparison directions, - // so we can use them later. - Expression *p1, *p2, *p3, *p4; - int dir1 = isPointerCmpExp(e1, &p1, &p2); - int dir2 = isPointerCmpExp(e2, &p3, &p4); - if ( dir1 == 0 || dir2 == 0 ) - return NULL; - - //printf("FourPointerRelation %s\n", toChars()); - - // Evaluate the first two pointers - p1 = p1->interpret(istate); - if (exceptionOrCantInterpret(p1)) - return p1; - p2 = p2->interpret(istate); - if (exceptionOrCantInterpret(p1)) - return p1; - dinteger_t ofs1, ofs2; - Expression *agg1 = getAggregateFromPointer(p1, &ofs1); - Expression *agg2 = getAggregateFromPointer(p2, &ofs2); - - if ( !pointToSameMemoryBlock(agg1, agg2) - && agg1->op != TOKnull && agg2->op != TOKnull) - { // Here it is either CANT_INTERPRET, - // or an IsInside comparison returning FALSE. - p3 = p3->interpret(istate); - if (p3 == EXP_CANT_INTERPRET) - return p3; - // Note that it is NOT legal for it to throw an exception! - Expression *except = NULL; - if (exceptionOrCantInterpret(p3)) - except = p3; - else - { - p4 = p4->interpret(istate); - if (p4 == EXP_CANT_INTERPRET) - return p4; - if (exceptionOrCantInterpret(p3)) - except = p4; - } - if (except) - { error("Comparison %s of pointers to unrelated memory blocks remains " - "indeterminate at compile time " - "because exception %s was thrown while evaluating %s", - this->e1->toChars(), except->toChars(), this->e2->toChars()); - return EXP_CANT_INTERPRET; - } - dinteger_t ofs3,ofs4; - Expression *agg3 = getAggregateFromPointer(p3, &ofs3); - Expression *agg4 = getAggregateFromPointer(p4, &ofs4); - // The valid cases are: - // p1 > p2 && p3 > p4 (same direction, also for < && <) - // p1 > p2 && p3 < p4 (different direction, also < && >) - // Changing any > into >= doesnt affect the result - if ( (dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) - && pointToSameMemoryBlock(agg2, agg3)) - || (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) - && pointToSameMemoryBlock(agg2, agg4)) ) - { // it's a legal two-sided comparison - return new IntegerExp(loc, (op == TOKandand) ? 0 : 1, type); - } - // It's an invalid four-pointer comparison. Either the second - // comparison is in the same direction as the first, or else - // more than two memory blocks are involved (either two independent - // invalid comparisons are present, or else agg3 == agg4). - error("Comparison %s of pointers to unrelated memory blocks is " - "indeterminate at compile time, even when combined with %s.", - e1->toChars(), e2->toChars()); - return EXP_CANT_INTERPRET; - } - // The first pointer expression didn't need special treatment, so we - // we need to interpret the entire expression exactly as a normal && or ||. - // This is easy because we haven't evaluated e2 at all yet, and we already - // know it will return a bool. - // But we mustn't evaluate the pointer expressions in e1 again, in case - // they have side-effects. - bool nott = false; - Expression *e = e1; - while (e->op == TOKnot) - { nott= !nott; - e = ((NotExp *)e)->e1; - } - TOK cmpop = e->op; - if (nott) - cmpop = reverseRelation(cmpop); - int cmp = comparePointers(loc, cmpop, e1->type, agg1, ofs1, agg2, ofs2); - // We already know this is a valid comparison. - assert(cmp >= 0); - if ( (op == TOKandand && cmp == 1) || (op == TOKoror && cmp == 0) ) - return e2->interpret(istate); - return new IntegerExp(loc, (op == TOKandand) ? 0 : 1, type); -} - -Expression *AndAndExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("AndAndExp::interpret() %s\n", toChars()); -#endif - - // Check for an insidePointer expression, evaluate it if so - Expression *e = interpretFourPointerRelation(istate, goal); - if (e) - return e; - - e = e1->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - - int result; - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - result = 0; - else if (isTrueBool(e)) - { - e = e2->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - if (e == EXP_VOID_INTERPRET) - { - assert(type->ty == Tvoid); - return NULL; - } - if (e->isBool(FALSE)) - result = 0; - else if (isTrueBool(e)) - result = 1; - else - { - error("%s does not evaluate to a boolean", e->toChars()); - e = EXP_CANT_INTERPRET; - } - } - else - { - error("%s cannot be interpreted as a boolean", e->toChars()); - e = EXP_CANT_INTERPRET; - } - } - if (e != EXP_CANT_INTERPRET && goal != ctfeNeedNothing) - e = new IntegerExp(loc, result, type); - return e; -} - -Expression *OrOrExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("OrOrExp::interpret() %s\n", toChars()); -#endif - - // Check for an insidePointer expression, evaluate it if so - Expression *e = interpretFourPointerRelation(istate, goal); - if (e) - return e; - - e = e1->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - - int result; - if (e != EXP_CANT_INTERPRET) - { - if (isTrueBool(e)) - result = 1; - else if (e->isBool(FALSE)) - { - e = e2->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - - if (e == EXP_VOID_INTERPRET) - { - assert(type->ty == Tvoid); - return NULL; - } - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - result = 0; - else if (isTrueBool(e)) - result = 1; - else - { - error("%s cannot be interpreted as a boolean", e->toChars()); - e = EXP_CANT_INTERPRET; - } - } - } - else - { - error("%s cannot be interpreted as a boolean", e->toChars()); - e = EXP_CANT_INTERPRET; - } - } - if (e != EXP_CANT_INTERPRET && goal != ctfeNeedNothing) - e = new IntegerExp(loc, result, type); - return e; -} - -// Print a stack trace, starting from callingExp which called fd. -// To shorten the stack trace, try to detect recursion. -void showCtfeBackTrace(InterState *istate, CallExp * callingExp, FuncDeclaration *fd) -{ - if (CtfeStatus::stackTraceCallsToSuppress > 0) - { - --CtfeStatus::stackTraceCallsToSuppress; - return; - } - errorSupplemental(callingExp->loc, "called from here: %s", callingExp->toChars()); - // Quit if it's not worth trying to compress the stack trace - if (CtfeStatus::callDepth < 6 || global.params.verbose) - return; - // Recursion happens if the current function already exists in the call stack. - int numToSuppress = 0; - int recurseCount = 0; - int depthSoFar = 0; - InterState *lastRecurse = istate; - for (InterState * cur = istate; cur; cur = cur->caller) - { - if (cur->fd == fd) - { ++recurseCount; - numToSuppress = depthSoFar; - lastRecurse = cur; - } - ++depthSoFar; - } - // We need at least three calls to the same function, to make compression worthwhile - if (recurseCount < 2) - return; - // We found a useful recursion. Print all the calls involved in the recursion - errorSupplemental(fd->loc, "%d recursive calls to function %s", recurseCount, fd->toChars()); - for (InterState *cur = istate; cur->fd != fd; cur = cur->caller) - { - errorSupplemental(cur->fd->loc, "recursively called from function %s", cur->fd->toChars()); - } - // We probably didn't enter the recursion in this function. - // Go deeper to find the real beginning. - InterState * cur = istate; - while (lastRecurse->caller && cur->fd == lastRecurse->caller->fd) - { - cur = cur->caller; - lastRecurse = lastRecurse->caller; - ++numToSuppress; - } - CtfeStatus::stackTraceCallsToSuppress = numToSuppress; -} - -Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("CallExp::interpret() %s\n", toChars()); -#endif - - Expression * pthis = NULL; - FuncDeclaration *fd = NULL; - Expression *ecall = e1; - if (ecall->op == TOKcall) - { - ecall = e1->interpret(istate); - if (exceptionOrCantInterpret(ecall)) - return ecall; - } - if (ecall->op == TOKstar) - { // Calling a function pointer - Expression * pe = ((PtrExp*)ecall)->e1; - if (pe->op == TOKvar) { - VarDeclaration *vd = ((VarExp *)((PtrExp*)ecall)->e1)->var->isVarDeclaration(); - if (vd && vd->getValue() && vd->getValue()->op == TOKsymoff) - fd = ((SymOffExp *)vd->getValue())->var->isFuncDeclaration(); - else - { - ecall = getVarExp(loc, istate, vd, goal); - if (exceptionOrCantInterpret(ecall)) - return ecall; - - if (ecall->op == TOKsymoff) - fd = ((SymOffExp *)ecall)->var->isFuncDeclaration(); - } - } - else if (pe->op == TOKsymoff) - fd = ((SymOffExp *)pe)->var->isFuncDeclaration(); - else - ecall = ((PtrExp*)ecall)->e1->interpret(istate); - - } - if (exceptionOrCantInterpret(ecall)) - return ecall; - - if (ecall->op == TOKindex) - { ecall = e1->interpret(istate); - if (exceptionOrCantInterpret(ecall)) - return ecall; - } - - if (ecall->op == TOKdotvar && !((DotVarExp*)ecall)->var->isFuncDeclaration()) - { ecall = e1->interpret(istate); - if (exceptionOrCantInterpret(ecall)) - return ecall; - } - - if (ecall->op == TOKdotvar) - { // Calling a member function - pthis = ((DotVarExp*)e1)->e1; - fd = ((DotVarExp*)e1)->var->isFuncDeclaration(); - } - else if (ecall->op == TOKvar) - { - VarDeclaration *vd = ((VarExp *)ecall)->var->isVarDeclaration(); - if (vd && vd->getValue()) - ecall = vd->getValue(); - else // Calling a function - fd = ((VarExp *)e1)->var->isFuncDeclaration(); - } - if (ecall->op == TOKdelegate) - { // Calling a delegate - fd = ((DelegateExp *)ecall)->func; - pthis = ((DelegateExp *)ecall)->e1; - } - else if (ecall->op == TOKfunction) - { // Calling a delegate literal - fd = ((FuncExp*)ecall)->fd; - } - else if (ecall->op == TOKstar && ((PtrExp*)ecall)->e1->op==TOKfunction) - { // Calling a function literal - fd = ((FuncExp*)((PtrExp*)ecall)->e1)->fd; - } - - TypeFunction *tf = fd ? (TypeFunction *)(fd->type) : NULL; - if (!tf) - { // DAC: This should never happen, it's an internal compiler error. - //printf("ecall=%s %d %d\n", ecall->toChars(), ecall->op, TOKcall); - if (ecall->op == TOKidentifier) - error("cannot evaluate %s at compile time. Circular reference?", toChars()); - else - error("CTFE internal error: cannot evaluate %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - if (!fd) - { - error("cannot evaluate %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - if (pthis) - { // Member function call - Expression *oldpthis; - if (pthis->op == TOKthis) - { - pthis = istate ? istate->localThis : NULL; - oldpthis = pthis; - } - else - { - if (pthis->op == TOKcomma) - pthis = pthis->interpret(istate); - if (exceptionOrCantInterpret(pthis)) - return pthis; - // Evaluate 'this' - oldpthis = pthis; - if (pthis->op != TOKvar) - pthis = pthis->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(pthis)) - return pthis; - } - if (fd->isVirtual()) - { // Make a virtual function call. - Expression *thisval = pthis; - if (pthis->op == TOKvar) - { assert(((VarExp*)thisval)->var->isVarDeclaration()); - thisval = ((VarExp*)thisval)->var->isVarDeclaration()->getValue(); - } - // Get the function from the vtable of the original class - ClassDeclaration *cd; - if (thisval && thisval->op == TOKnull) - { - error("function call through null class reference %s", pthis->toChars()); - return EXP_CANT_INTERPRET; - } - if (oldpthis->op == TOKsuper) - { assert(oldpthis->type->ty == Tclass); - cd = ((TypeClass *)oldpthis->type)->sym; - } - else - { - assert(thisval && thisval->op == TOKclassreference); - cd = ((ClassReferenceExp *)thisval)->originalClass(); - } - // We can't just use the vtable index to look it up, because - // vtables for interfaces don't get populated until the glue layer. - fd = cd->findFunc(fd->ident, (TypeFunction *)fd->type); - - assert(fd); - } - } - if (fd && fd->semanticRun >= PASSsemantic3done && fd->semantic3Errors) - { - error("CTFE failed because of previous errors in %s", fd->toChars()); - return EXP_CANT_INTERPRET; - } - // Check for built-in functions - Expression *eresult = evaluateIfBuiltin(istate, loc, fd, arguments, pthis); - if (eresult) - return eresult; - - // Inline .dup. Special case because it needs the return type. - if (!pthis && fd->ident == Id::adDup && arguments && arguments->dim == 2) - { - e = (*arguments)[1]; - e = e->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - if (e != EXP_CANT_INTERPRET) - { - if (e->op == TOKslice) - e= resolveSlice(e); - e = paintTypeOntoLiteral(type, copyLiteral(e)); - } - return e; - } - if (!fd->fbody) - { - error("%s cannot be interpreted at compile time," - " because it has no available source code", fd->toChars()); - return EXP_CANT_INTERPRET; - } - eresult = fd->interpret(istate, arguments, pthis); - if (eresult == EXP_CANT_INTERPRET) - { // Print a stack trace. - if (!global.gag) - showCtfeBackTrace(istate, this, fd); - } - else if (eresult == EXP_VOID_INTERPRET) - ; - else - eresult->loc = loc; - return eresult; -} - -Expression *CommaExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("CommaExp::interpret() %s\n", toChars()); -#endif - - CommaExp * firstComma = this; - while (firstComma->e1->op == TOKcomma) - firstComma = (CommaExp *)firstComma->e1; - - // If it creates a variable, and there's no context for - // the variable to be created in, we need to create one now. - InterState istateComma; - if (!istate && firstComma->e1->op == TOKdeclaration) - { - ctfeStack.startFrame(); - istate = &istateComma; - } - - Expression *e = EXP_CANT_INTERPRET; - - // If the comma returns a temporary variable, it needs to be an lvalue - // (this is particularly important for struct constructors) - if (e1->op == TOKdeclaration && e2->op == TOKvar - && ((DeclarationExp *)e1)->declaration == ((VarExp*)e2)->var - && ((VarExp*)e2)->var->storage_class & STCctfe) // same as Expression::isTemp - { - VarExp* ve = (VarExp *)e2; - VarDeclaration *v = ve->var->isVarDeclaration(); - ctfeStack.push(v); - if (!v->init && !v->getValue()) - { - v->setValue(copyLiteral(v->type->defaultInitLiteral(loc))); - } - if (!v->getValue()) { - Expression *newval = v->init->toExpression(); - // Bug 4027. Copy constructors are a weird case where the - // initializer is a void function (the variable is modified - // through a reference parameter instead). - newval = newval->interpret(istate); - if (exceptionOrCantInterpret(newval)) - { - if (istate == &istateComma) - ctfeStack.endFrame(0); - return newval; - } - if (newval != EXP_VOID_INTERPRET) - { - // v isn't necessarily null. - v->setValueWithoutChecking(copyLiteral(newval)); - } - } - if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef) - e = e2; - else - e = e2->interpret(istate, goal); - } - else - { - e = e1->interpret(istate, ctfeNeedNothing); - if (!exceptionOrCantInterpret(e)) - e = e2->interpret(istate, goal); - } - // If we created a temporary stack frame, end it now. - if (istate == &istateComma) - ctfeStack.endFrame(0); - return e; -} - -Expression *CondExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("CondExp::interpret() %s\n", toChars()); -#endif - Expression *e; - if ( isPointer(econd->type) ) - { - e = econd->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e)) - return e; - if (e->op != TOKnull) - e = new IntegerExp(loc, 1, Type::tbool); - } - else - e = econd->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - if (isTrueBool(e)) - e = e1->interpret(istate, goal); - else if (e->isBool(FALSE)) - e = e2->interpret(istate, goal); - else - { - error("%s does not evaluate to boolean result at compile time", - econd->toChars()); - e = EXP_CANT_INTERPRET; - } - return e; -} - -Expression *ArrayLengthExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e; - Expression *e1; - -#if LOG - printf("ArrayLengthExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - assert(e1); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKslice - || e1->op == TOKassocarrayliteral || e1->op == TOKnull) - { - e = new IntegerExp(loc, resolveArrayLength(e1), type); - } - else - { - error("%s cannot be evaluated at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - return e; -} - -/* Given an AA literal 'ae', and a key 'e2': - * Return ae[e2] if present, or NULL if not found. - * Return EXP_CANT_INTERPRET on error. - */ -Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2) -{ - /* Search the keys backwards, in case there are duplicate keys - */ - for (size_t i = ae->keys->dim; i;) - { - i--; - Expression *ekey = ae->keys->tdata()[i]; - Expression *ex = ctfeEqual(loc, TOKequal, Type::tbool, ekey, e2); - if (ex == EXP_CANT_INTERPRET) - return ex; - if (ex->isBool(TRUE)) - { - return ae->values->tdata()[i]; - } - } - return NULL; -} - -/* Same as for constfold.Index, except that it only works for static arrays, - * dynamic arrays, and strings. We know that e1 is an - * interpreted CTFE expression, so it cannot have side-effects. - */ -Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx) -{ //printf("ctfeIndex(e1 = %s)\n", e1->toChars()); - assert(e1->type); - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - if (indx >= es1->len) - { - error(loc, "string index %ju is out of bounds [0 .. %zu]", indx, es1->len); - return EXP_CANT_INTERPRET; - } - else - return new IntegerExp(loc, es1->charAt(indx), type); - } - assert(e1->op == TOKarrayliteral); - ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - if (indx >= ale->elements->dim) - { - error(loc, "array index %ju is out of bounds %s[0 .. %u]", indx, e1->toChars(), ale->elements->dim); - return EXP_CANT_INTERPRET; - } - Expression *e = ale->elements->tdata()[indx]; - return paintTypeOntoLiteral(type, e); -} - -Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) -{ - Expression *e1 = NULL; - Expression *e2; - -#if LOG - printf("IndexExp::interpret() %s\n", toChars()); -#endif - if (this->e1->type->toBasetype()->ty == Tpointer) - { - // Indexing a pointer. Note that there is no $ in this case. - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - e2 = this->e2->interpret(istate); - if (exceptionOrCantInterpret(e2)) - return e2; - dinteger_t indx = e2->toInteger(); - - dinteger_t ofs; - Expression *agg = getAggregateFromPointer(e1, &ofs); - - if (agg->op == TOKnull) - { - error("cannot index null pointer %s", this->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if ( agg->op == TOKarrayliteral || agg->op == TOKstring) - { - dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); - //Type *pointee = ((TypePointer *)agg->type)->next; - if ((indx + ofs) < 0 || (indx+ofs) > len) - { - error("pointer index [%lld] exceeds allocated memory block [0..%lld]", - indx+ofs, len); - return EXP_CANT_INTERPRET; - } - return ctfeIndex(loc, type, agg, indx+ofs); - } - else - { // Pointer to a non-array variable - if ((indx + ofs) != 0) - { - error("pointer index [%lld] lies outside memory block [0..1]", - indx+ofs); - return EXP_CANT_INTERPRET; - } - return agg->interpret(istate); - } - } - e1 = this->e1; - if (!(e1->op == TOKarrayliteral && ((ArrayLiteralExp *)e1)->ownedByCtfe)) - e1 = e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - - if (e1->op == TOKnull) - { - if (goal == ctfeNeedLvalue && e1->type->ty == Taarray) - return paintTypeOntoLiteral(type, e1); - error("cannot index null array %s", this->e1->toChars()); - return EXP_CANT_INTERPRET; - } - /* Set the $ variable. - * Note that foreach uses indexing but doesn't need $ - */ - if (lengthVar && (e1->op == TOKstring || e1->op == TOKarrayliteral - || e1->op == TOKslice)) - { - uinteger_t dollar = resolveArrayLength(e1); - Expression *dollarExp = new IntegerExp(loc, dollar, Type::tsize_t); - ctfeStack.push(lengthVar); - lengthVar->setValue(dollarExp); - } - - e2 = this->e2->interpret(istate); - if (lengthVar) - ctfeStack.pop(lengthVar); // $ is defined only inside [] - if (exceptionOrCantInterpret(e2)) - return e2; - if (e1->op == TOKslice && e2->op == TOKint64) - { - // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx'] - uinteger_t indx = e2->toInteger(); - uinteger_t ilo = ((SliceExp *)e1)->lwr->toInteger(); - uinteger_t iup = ((SliceExp *)e1)->upr->toInteger(); - - if (indx > iup - ilo) - { - error("index %llu exceeds array length %llu", indx, iup - ilo); - return EXP_CANT_INTERPRET; - } - indx += ilo; - e1 = ((SliceExp *)e1)->e1; - e2 = new IntegerExp(e2->loc, indx, e2->type); - } - Expression *e = NULL; - if ((goal == ctfeNeedLvalue && type->ty != Taarray && type->ty != Tarray - && type->ty != Tsarray && type->ty != Tstruct && type->ty != Tclass) - || (goal == ctfeNeedLvalueRef && type->ty != Tsarray && type->ty != Tstruct) - ) - { // Pointer or reference of a scalar type - e = new IndexExp(loc, e1, e2); - e->type = type; - return e; - } - if (e1->op == TOKassocarrayliteral) - { - if (e2->op == TOKslice) - e2 = resolveSlice(e2); - e = findKeyInAA(loc, (AssocArrayLiteralExp *)e1, e2); - if (!e) - { - error("key %s not found in associative array %s", - e2->toChars(), this->e1->toChars()); - return EXP_CANT_INTERPRET; - } - } - else - { - if (e2->op != TOKint64) - { - e1->error("CTFE internal error: non-integral index [%s]", this->e2->toChars()); - return EXP_CANT_INTERPRET; - } - e = ctfeIndex(loc, type, e1, e2->toInteger()); - } - if (exceptionOrCantInterpret(e)) - return e; - if (goal == ctfeNeedRvalue && (e->op == TOKslice || e->op == TOKdotvar)) - e = e->interpret(istate); - if (goal == ctfeNeedRvalue && e->op == TOKvoid) - { - error("%s is used before initialized", toChars()); - errorSupplemental(e->loc, "originally uninitialized here"); - return EXP_CANT_INTERPRET; - } - e = paintTypeOntoLiteral(type, e); - return e; -} - - -Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) -{ - Expression *e1; - Expression *lwr; - Expression *upr; - -#if LOG - printf("SliceExp::interpret() %s\n", toChars()); -#endif - - if (this->e1->type->toBasetype()->ty == Tpointer) - { - // Slicing a pointer. Note that there is no $ in this case. - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKint64) - { - error("cannot slice invalid pointer %s of value %s", - this->e1->toChars(), e1->toChars()); - return EXP_CANT_INTERPRET; - } - - /* Evaluate lower and upper bounds of slice - */ - lwr = this->lwr->interpret(istate); - if (exceptionOrCantInterpret(lwr)) - return lwr; - upr = this->upr->interpret(istate); - if (exceptionOrCantInterpret(upr)) - return upr; - uinteger_t ilwr; - uinteger_t iupr; - ilwr = lwr->toInteger(); - iupr = upr->toInteger(); - Expression *e; - dinteger_t ofs; - Expression *agg = getAggregateFromPointer(e1, &ofs); - if (agg->op == TOKnull) - { - if (iupr == ilwr) - { - e = new NullExp(loc); - e->type = type; - return e; - } - error("cannot slice null pointer %s", this->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (agg->op != TOKarrayliteral && agg->op != TOKstring) - { - error("pointer %s cannot be sliced at compile time (it does not point to an array)", - this->e1->toChars()); - return EXP_CANT_INTERPRET; - } - assert(agg->op == TOKarrayliteral || agg->op == TOKstring); - dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); - //Type *pointee = ((TypePointer *)agg->type)->next; - if ((ilwr + ofs) < 0 || (iupr+ofs) > (len + 1) || iupr < ilwr) - { - error("pointer slice [%lld..%lld] exceeds allocated memory block [0..%lld]", - ilwr+ofs, iupr+ofs, len); - return EXP_CANT_INTERPRET; - } - e = new SliceExp(loc, agg, lwr, upr); - e->type = type; - return e; - } - if (goal == ctfeNeedRvalue && this->e1->op == TOKstring) - e1 = this->e1; // Will get duplicated anyway - else - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKvar) - e1 = e1->interpret(istate); - - if (!this->lwr) - { - if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef) - return e1; - return paintTypeOntoLiteral(type, e1); - } - - /* Set the $ variable - */ - if (e1->op != TOKarrayliteral && e1->op != TOKstring && - e1->op != TOKnull && e1->op != TOKslice) - { - error("Cannot determine length of %s at compile time", e1->toChars()); - return EXP_CANT_INTERPRET; - } - uinteger_t dollar = resolveArrayLength(e1); - if (lengthVar) - { - IntegerExp *dollarExp = new IntegerExp(loc, dollar, Type::tsize_t); - ctfeStack.push(lengthVar); - lengthVar->setValue(dollarExp); - } - - /* Evaluate lower and upper bounds of slice - */ - lwr = this->lwr->interpret(istate); - if (exceptionOrCantInterpret(lwr)) - { - if (lengthVar) - ctfeStack.pop(lengthVar);; // $ is defined only inside [L..U] - return lwr; - } - upr = this->upr->interpret(istate); - if (lengthVar) - ctfeStack.pop(lengthVar); // $ is defined only inside [L..U] - if (exceptionOrCantInterpret(upr)) - return upr; - - Expression *e; - uinteger_t ilwr; - uinteger_t iupr; - ilwr = lwr->toInteger(); - iupr = upr->toInteger(); - if (e1->op == TOKnull) - { - if (ilwr== 0 && iupr == 0) - return e1; - e1->error("slice [%llu..%llu] is out of bounds", ilwr, iupr); - return EXP_CANT_INTERPRET; - } - if (e1->op == TOKslice) - { - SliceExp *se = (SliceExp *)e1; - // Simplify slice of slice: - // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr'] - uinteger_t lo1 = se->lwr->toInteger(); - uinteger_t up1 = se->upr->toInteger(); - if (ilwr > iupr || iupr > up1 - lo1) - { - error("slice[%llu..%llu] exceeds array bounds[%llu..%llu]", - ilwr, iupr, lo1, up1); - return EXP_CANT_INTERPRET; - } - ilwr += lo1; - iupr += lo1; - e = new SliceExp(loc, se->e1, - new IntegerExp(loc, ilwr, lwr->type), - new IntegerExp(loc, iupr, upr->type)); - e->type = type; - return e; - } - if (e1->op == TOKarrayliteral - || e1->op == TOKstring) - { - if (iupr < ilwr || ilwr < 0 || iupr > dollar) - { - error("slice [%lld..%lld] exceeds array bounds [0..%lld]", - ilwr, iupr, dollar); - return EXP_CANT_INTERPRET; - } - } - e = new SliceExp(loc, e1, lwr, upr); - e->type = type; - return e; -} - -Expression *InExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("InExp::interpret() %s\n", toChars()); -#endif - Expression *e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - Expression *e2 = this->e2->interpret(istate); - if (exceptionOrCantInterpret(e2)) - return e2; - if (e2->op == TOKnull) - return new NullExp(loc, type); - if (e2->op != TOKassocarrayliteral) - { - error(" %s cannot be interpreted at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - if (e1->op == TOKslice) - e1 = resolveSlice(e1); - e = findKeyInAA(loc, (AssocArrayLiteralExp *)e2, e1); - if (exceptionOrCantInterpret(e)) - return e; - if (!e) - return new NullExp(loc, type); - e = new IndexExp(loc, e2, e1); - e->type = type; - return e; -} - -Expression *CatExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("CatExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKslice) - { - e1 = resolveSlice(e1); - } - e2 = this->e2->interpret(istate); - if (exceptionOrCantInterpret(e2)) - return e2; - if (e2->op == TOKslice) - e2 = resolveSlice(e2); - e = ctfeCat(type, e1, e2); - if (e == EXP_CANT_INTERPRET) - { error("%s cannot be interpreted at compile time", toChars()); - return e; - } - // We know we still own it, because we interpreted both e1 and e2 - if (e->op == TOKarrayliteral) - ((ArrayLiteralExp *)e)->ownedByCtfe = true; - if (e->op == TOKstring) - ((StringExp *)e)->ownedByCtfe = true; - return e; -} - - -// Return true if t is a pointer (not a function pointer) -bool isPointer(Type *t) -{ - Type * tb = t->toBasetype(); - return tb->ty == Tpointer && tb->nextOf()->ty != Tfunction; -} - -// Return true if t is an AA, or AssociativeArray!(key, value) -bool isAssocArray(Type *t) -{ - t = t->toBasetype(); - if (t->ty == Taarray) - return true; -#if DMDV2 - if (t->ty != Tstruct) - return false; - StructDeclaration *sym = ((TypeStruct *)t)->sym; - if (sym->ident == Id::AssociativeArray && sym->parent && - sym->parent->parent && - sym->parent->parent->ident == Id::object) - { - return true; - } -#endif - return false; -} - -// Given a template AA type, extract the corresponding built-in AA type -TypeAArray *toBuiltinAAType(Type *t) -{ - t = t->toBasetype(); - if (t->ty == Taarray) - return (TypeAArray *)t; -#if DMDV2 - assert(t->ty == Tstruct); - StructDeclaration *sym = ((TypeStruct *)t)->sym; - assert(sym->ident == Id::AssociativeArray); - TemplateInstance *tinst = sym->parent->isTemplateInstance(); - assert(tinst); - return new TypeAArray((Type *)(tinst->tiargs->tdata()[1]), (Type *)(tinst->tiargs->tdata()[0])); -#else - assert(0); - return NULL; -#endif -} - -Expression *CastExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e; - Expression *e1; - -#if LOG - printf("CastExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate, goal); - if (exceptionOrCantInterpret(e1)) - return e1; - // If the expression has been cast to void, do nothing. - if (to->ty == Tvoid && goal == ctfeNeedNothing) - return e1; - if (to->ty == Tpointer && e1->op != TOKnull) - { - Type *pointee = ((TypePointer *)type)->next; - // Implement special cases of normally-unsafe casts -#if DMDV2 - if (pointee->ty == Taarray && e1->op == TOKaddress - && isAssocArray(((AddrExp*)e1)->e1->type)) - { // cast from template AA pointer to true AA pointer is OK. - return paintTypeOntoLiteral(to, e1); - } -#endif - if (e1->op == TOKint64) - { // Happens with Windows HANDLEs, for example. - return paintTypeOntoLiteral(to, e1); - } - bool castBackFromVoid = false; - if (e1->type->ty == Tarray || e1->type->ty == Tsarray || e1->type->ty == Tpointer) - { - // Check for unsupported type painting operations - // For slices, we need the type being sliced, - // since it may have already been type painted - Type *elemtype = e1->type->nextOf(); - if (e1->op == TOKslice) - elemtype = ((SliceExp *)e1)->e1->type->nextOf(); - // Allow casts from X* to void *, and X** to void** for any X. - // But don't allow cast from X* to void**. - // So, we strip all matching * from source and target to find X. - // Allow casts to X* from void* only if the 'void' was originally an X; - // we check this later on. - Type *ultimatePointee = pointee; - Type *ultimateSrc = elemtype; - while (ultimatePointee->ty == Tpointer && ultimateSrc->ty == Tpointer) - { - ultimatePointee = ultimatePointee->nextOf(); - ultimateSrc = ultimateSrc->nextOf(); - } - if (ultimatePointee->ty != Tvoid && ultimateSrc->ty != Tvoid - && !isSafePointerCast(elemtype, pointee)) - { - error("reinterpreting cast from %s* to %s* is not supported in CTFE", - elemtype->toChars(), pointee->toChars()); - return EXP_CANT_INTERPRET; - } - if (ultimateSrc->ty == Tvoid) - castBackFromVoid = true; - } - - if (e1->op == TOKslice) - { - if ( ((SliceExp *)e1)->e1->op == TOKnull) - { - return paintTypeOntoLiteral(type, ((SliceExp *)e1)->e1); - } - e = new IndexExp(loc, ((SliceExp *)e1)->e1, ((SliceExp *)e1)->lwr); - e->type = type; - return e; - } - if (e1->op == TOKarrayliteral || e1->op == TOKstring) - { - e = new IndexExp(loc, e1, new IntegerExp(loc, 0, Type::tsize_t)); - e->type = type; - return e; - } - if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type != e1->type) - { // type painting operation - IndexExp *ie = (IndexExp *)e1; - e = new IndexExp(e1->loc, ie->e1, ie->e2); - if (castBackFromVoid) - { - // get the original type. For strings, it's just the type... - Type *origType = ie->e1->type->nextOf(); - // ..but for arrays of type void*, it's the type of the element - Expression *xx = NULL; - if (ie->e1->op == TOKarrayliteral && ie->e2->op == TOKint64) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)ie->e1; - uinteger_t indx = ie->e2->toInteger(); - if (indx < ale->elements->dim) - xx = ale->elements->tdata()[indx]; - } - if (xx && xx->op == TOKindex) - origType = ((IndexExp *)xx)->e1->type->nextOf(); - else if (xx && xx->op == TOKaddress) - origType= ((AddrExp *)xx)->e1->type; - else if (xx && xx->op == TOKvar) - origType = ((VarExp *)xx)->var->type; - if (!isSafePointerCast(origType, pointee)) - { - error("using void* to reinterpret cast from %s* to %s* is not supported in CTFE", - origType->toChars(), pointee->toChars()); - return EXP_CANT_INTERPRET; - } - } - e->type = type; - return e; - } - if (e1->op == TOKaddress) - { - Type *origType = ((AddrExp *)e1)->type; - if (isSafePointerCast(origType, pointee)) - { - e = new AddrExp(loc, ((AddrExp *)e1)->e1); - e->type = type; - return e; - } - } - if (e1->op == TOKvar) - { // type painting operation - Type *origType = ((VarExp *)e1)->var->type; - if (castBackFromVoid && !isSafePointerCast(origType, pointee)) - { - error("using void* to reinterpret cast from %s* to %s* is not supported in CTFE", - origType->toChars(), pointee->toChars()); - return EXP_CANT_INTERPRET; - } - e = new VarExp(loc, ((VarExp *)e1)->var); - e->type = type; - return e; - } - - // Check if we have a null pointer (eg, inside a struct) - e1 = e1->interpret(istate); - if (e1->op != TOKnull) - { - error("pointer cast from %s to %s is not supported at compile time", - e1->type->toChars(), to->toChars()); - return EXP_CANT_INTERPRET; - } - } - if (to->ty == Tarray && e1->op == TOKslice) - { // Note that the slice may be void[], so when checking for dangerous - // casts, we need to use the original type, which is se->e1. - SliceExp *se = (SliceExp *)e1; - if ( !isSafePointerCast( se->e1->type->nextOf(), to->nextOf() ) ) - { - error("array cast from %s to %s is not supported at compile time", - se->e1->type->toChars(), to->toChars()); - return EXP_CANT_INTERPRET; - } - e1 = new SliceExp(e1->loc, se->e1, se->lwr, se->upr); - e1->type = to; - return e1; - } - // Disallow array type painting, except for conversions between built-in - // types of identical size. - if ((to->ty == Tsarray || to->ty == Tarray) && - (e1->type->ty == Tsarray || e1->type->ty == Tarray) && - !isSafePointerCast(e1->type->nextOf(), to->nextOf()) ) - { - error("array cast from %s to %s is not supported at compile time", e1->type->toChars(), to->toChars()); - return EXP_CANT_INTERPRET; - } - if (to->ty == Tsarray && e1->op == TOKslice) - e1 = resolveSlice(e1); - if (to->toBasetype()->ty == Tbool && e1->type->ty==Tpointer) - { - return new IntegerExp(loc, e1->op != TOKnull, to); - } - return ctfeCast(loc, type, to, e1); -} - -Expression *AssertExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e; - Expression *e1; - -#if LOG - printf("AssertExp::interpret() %s\n", toChars()); -#endif -#if DMDV2 - e1 = this->e1->interpret(istate); -#else - // Deal with pointers (including compiler-inserted assert(&this, "null this")) - if ( isPointer(this->e1->type) ) - { - e1 = this->e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op != TOKnull) - return new IntegerExp(loc, 1, Type::tbool); - } - else - e1 = this->e1->interpret(istate); -#endif - if (exceptionOrCantInterpret(e1)) - return e1; - if (isTrueBool(e1)) - { - } - else if (e1->isBool(FALSE)) - { - if (msg) - { - e = msg->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - error("%s", e->toChars()); - } - else - error("%s failed", toChars()); - goto Lcant; - } - else - { - error("%s is not a compile-time boolean expression", e1->toChars()); - goto Lcant; - } - return e1; - -Lcant: - return EXP_CANT_INTERPRET; -} - -Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("PtrExp::interpret() %s\n", toChars()); -#endif - // Constant fold *(&structliteral + offset) - if (e1->op == TOKadd) - { AddExp *ae = (AddExp *)e1; - if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) - { AddrExp *ade = (AddrExp *)ae->e1; - Expression *ex = ade->e1; - ex = ex->interpret(istate); - if (exceptionOrCantInterpret(ex)) - return ex; - if (ex->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ex; - dinteger_t offset = ae->e2->toInteger(); - e = se->getField(type, offset); - if (!e) - e = EXP_CANT_INTERPRET; - return e; - } - } - e = Ptr(type, e1); - } -#if DMDV2 -#else // this is required for D1, where structs return *this instead of 'this'. - else if (e1->op == TOKthis) - { - if(istate->localThis) - return istate->localThis->interpret(istate); - } -#endif - else - { // It's possible we have an array bounds error. We need to make sure it - // errors with this line number, not the one where the pointer was set. - e = e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e)) - return e; - if (!(e->op == TOKvar || e->op == TOKdotvar || e->op == TOKindex - || e->op == TOKslice || e->op == TOKaddress)) - { - error("dereference of invalid pointer '%s'", e->toChars()); - return EXP_CANT_INTERPRET; - } - if (goal != ctfeNeedLvalue) - { - if (e->op == TOKindex && e->type->ty == Tpointer) - { - IndexExp *ie = (IndexExp *)e; - // Is this a real index to an array of pointers, or just a CTFE pointer? - // If the index has the same levels of indirection, it's an index - int srcLevels = 0; - int destLevels = 0; - for(Type *xx = ie->e1->type; xx->ty == Tpointer; xx = xx->nextOf()) - ++srcLevels; - for(Type *xx = e->type->nextOf(); xx->ty == Tpointer; xx = xx->nextOf()) - ++destLevels; - bool isGenuineIndex = (srcLevels == destLevels); - - if ((ie->e1->op == TOKarrayliteral || ie->e1->op == TOKstring) - && ie->e2->op == TOKint64) - { - Expression *dollar = ArrayLength(Type::tsize_t, ie->e1); - dinteger_t len = dollar->toInteger(); - dinteger_t indx = ie->e2->toInteger(); - assert(indx >=0 && indx <= len); // invalid pointer - if (indx == len) - { - error("dereference of pointer %s one past end of memory block limits [0..%lld]", - toChars(), len); - return EXP_CANT_INTERPRET; - } - e = ctfeIndex(loc, type, ie->e1, indx); - if (isGenuineIndex) - { - if (e->op == TOKindex) - e = e->interpret(istate, goal); - else if (e->op == TOKaddress) - e = paintTypeOntoLiteral(type, ((AddrExp *)e)->e1); - } - return e; - } - if (ie->e1->op == TOKassocarrayliteral) - { - e = findKeyInAA(loc, (AssocArrayLiteralExp *)ie->e1, ie->e2); - assert(e != EXP_CANT_INTERPRET); - e = paintTypeOntoLiteral(type, e); - if (isGenuineIndex) - { - if (e->op == TOKindex) - e = e->interpret(istate, goal); - else if (e->op == TOKaddress) - e = paintTypeOntoLiteral(type, ((AddrExp *)e)->e1); - } - return e; - } - } - if (e->op == TOKstructliteral) - return e; - e = e1->interpret(istate, goal); - if (e->op == TOKaddress) - { - e = ((AddrExp*)e)->e1; - if (e->op == TOKdotvar || e->op == TOKindex) - e = e->interpret(istate, goal); - } - else if (e->op == TOKvar) - { - e = e->interpret(istate, goal); - } - if (exceptionOrCantInterpret(e)) - return e; - } - else if (e->op == TOKaddress) - e = ((AddrExp*)e)->e1; // *(&x) ==> x - else if (e->op == TOKnull) - { - error("dereference of null pointer '%s'", e1->toChars()); - return EXP_CANT_INTERPRET; - } - e->type = type; - } - -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); -#endif - return e; -} - -Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("DotVarExp::interpret() %s\n", toChars()); -#endif - - Expression *ex = e1->interpret(istate); - if (exceptionOrCantInterpret(ex)) - return ex; - if (ex != EXP_CANT_INTERPRET) - { - #if DMDV2 - // Special case for template AAs: AA.var returns the AA itself. - // ie AA.p ----> AA. This is a hack, to get around the - // corresponding hack in the AA druntime implementation. - if (isAssocArray(ex->type)) - return ex; - #endif - if (ex->op == TOKaddress) - ex = ((AddrExp *)ex)->e1; - VarDeclaration *v = var->isVarDeclaration(); - if (!v) - error("CTFE internal error: %s", toChars()); - if (ex->op == TOKnull && ex->type->toBasetype()->ty == Tclass) - { error("class '%s' is null and cannot be dereferenced", e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (ex->op == TOKstructliteral || ex->op == TOKclassreference) - { - StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex; - // We can't use getField, because it makes a copy - int i = -1; - if (ex->op == TOKclassreference) - i = ((ClassReferenceExp *)ex)->findFieldIndexByName(v); - else - i = findFieldIndexByName(se->sd, v); - if (i == -1) - { - error("couldn't find field %s of type %s in %s", v->toChars(), type->toChars(), se->toChars()); - return EXP_CANT_INTERPRET; - } - e = se->elements->tdata()[i]; - if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef) - { - // If it is an lvalue literal, return it... - if (e->op == TOKstructliteral) - return e; - if ((type->ty == Tsarray || goal == ctfeNeedLvalue) && ( - e->op == TOKarrayliteral || - e->op == TOKassocarrayliteral || e->op == TOKstring || - e->op == TOKclassreference || e->op == TOKslice)) - return e; - /* Element is an allocated pointer, which was created in - * CastExp. - */ - if (goal == ctfeNeedLvalue && e->op == TOKindex && - e->type == type && - isPointer(type) ) - return e; - // ...Otherwise, just return the (simplified) dotvar expression - e = new DotVarExp(loc, ex, v); - e->type = type; - return e; - } - if (!e) - { - error("couldn't find field %s in %s", v->toChars(), type->toChars()); - e = EXP_CANT_INTERPRET; - } - // If it is an rvalue literal, return it... - if (e->op == TOKstructliteral || e->op == TOKarrayliteral || - e->op == TOKassocarrayliteral || e->op == TOKstring) - return e; - if (e->op == TOKvoid) - { - VoidInitExp *ve = (VoidInitExp *)e; - error("cannot read uninitialized variable %s in ctfe", toChars()); - ve->var->error("was uninitialized and used before set"); - return EXP_CANT_INTERPRET; - } - if ( isPointer(type) ) - { - return paintTypeOntoLiteral(type, e); - } - if (e->op == TOKvar) - { // Don't typepaint twice, since that might cause an erroneous copy - e = getVarExp(loc, istate, ((VarExp *)e)->var, goal); - if (e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) - e = paintTypeOntoLiteral(type, e); - return e; - } - return e->interpret(istate, goal); - } - else - error("%s.%s is not yet implemented at compile time", e1->toChars(), var->toChars()); - } - -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("DotVarExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); -#endif - return e; -} - -Expression *RemoveExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("RemoveExp::interpret() %s\n", toChars()); -#endif - Expression *agg = e1->interpret(istate); - if (exceptionOrCantInterpret(agg)) - return agg; - Expression *index = e2->interpret(istate); - if (exceptionOrCantInterpret(index)) - return index; - if (agg->op == TOKnull) - return EXP_VOID_INTERPRET; - assert(agg->op == TOKassocarrayliteral); - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)agg; - Expressions *keysx = aae->keys; - Expressions *valuesx = aae->values; - size_t removed = 0; - for (size_t j = 0; j < valuesx->dim; ++j) - { Expression *ekey = keysx->tdata()[j]; - Expression *ex = ctfeEqual(loc, TOKequal, Type::tbool, ekey, index); - if (exceptionOrCantInterpret(ex)) - return ex; - if (ex->isBool(TRUE)) - ++removed; - else if (removed != 0) - { keysx->tdata()[j - removed] = ekey; - valuesx->tdata()[j - removed] = valuesx->tdata()[j]; - } - } - valuesx->dim = valuesx->dim - removed; - keysx->dim = keysx->dim - removed; - return new IntegerExp(loc, removed?1:0, Type::tbool); -} - - -/******************************* Special Functions ***************************/ - -Expression *interpret_length(InterState *istate, Expression *earg) -{ - //printf("interpret_length()\n"); - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (exceptionOrCantInterpret(earg)) - return earg; - dinteger_t len = 0; - if (earg->op == TOKassocarrayliteral) - len = ((AssocArrayLiteralExp *)earg)->keys->dim; - else assert(earg->op == TOKnull); - Expression *e = new IntegerExp(earg->loc, len, Type::tsize_t); - return e; -} - -Expression *interpret_keys(InterState *istate, Expression *earg, Type *elemType) -{ -#if LOG - printf("interpret_keys()\n"); -#endif - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (exceptionOrCantInterpret(earg)) - return earg; - if (earg->op == TOKnull) - return new NullExp(earg->loc); - if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray) - return NULL; - assert(earg->op == TOKassocarrayliteral); - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, aae->keys); - ae->ownedByCtfe = aae->ownedByCtfe; - ae->type = new TypeSArray(elemType, new IntegerExp(aae->keys->dim)); - return copyLiteral(ae); -} - -Expression *interpret_values(InterState *istate, Expression *earg, Type *elemType) -{ -#if LOG - printf("interpret_values()\n"); -#endif - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (exceptionOrCantInterpret(earg)) - return earg; - if (earg->op == TOKnull) - return new NullExp(earg->loc); - if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray) - return NULL; - assert(earg->op == TOKassocarrayliteral); - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, aae->values); - ae->ownedByCtfe = aae->ownedByCtfe; - ae->type = new TypeSArray(elemType, new IntegerExp(aae->values->dim)); - //printf("result is %s\n", e->toChars()); - return copyLiteral(ae); -} - -// signature is int delegate(ref Value) OR int delegate(ref Key, ref Value) -Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *deleg) -{ aa = aa->interpret(istate); - if (exceptionOrCantInterpret(aa)) - return aa; - if (aa->op != TOKassocarrayliteral) - return new IntegerExp(deleg->loc, 0, Type::tsize_t); - - FuncDeclaration *fd = NULL; - Expression *pthis = NULL; - if (deleg->op == TOKdelegate) - { - fd = ((DelegateExp *)deleg)->func; - pthis = ((DelegateExp *)deleg)->e1; - } - else if (deleg->op == TOKfunction) - fd = ((FuncExp*)deleg)->fd; - - assert(fd && fd->fbody); - assert(fd->parameters); - int numParams = fd->parameters->dim; - assert(numParams == 1 || numParams==2); - - Type *valueType = fd->parameters->tdata()[numParams-1]->type; - Type *keyType = numParams == 2 ? fd->parameters->tdata()[0]->type - : Type::tsize_t; - Expressions args; - args.setDim(numParams); - - AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)aa; - if (!ae->keys || ae->keys->dim == 0) - return new IntegerExp(deleg->loc, 0, Type::tsize_t); - Expression *eresult; - - for (size_t i = 0; i < ae->keys->dim; ++i) - { - Expression *ekey = ae->keys->tdata()[i]; - Expression *evalue = ae->values->tdata()[i]; - args[numParams - 1] = evalue; - if (numParams == 2) args[0] = ekey; - - eresult = fd->interpret(istate, &args, pthis); - if (exceptionOrCantInterpret(eresult)) - return eresult; - - assert(eresult->op == TOKint64); - if (((IntegerExp *)eresult)->value != 0) - return eresult; - } - return eresult; -} - -// Helper function: given a function of type A[] f(...), -// return A. -Type *returnedArrayElementType(FuncDeclaration *fd) -{ - assert(fd->type->ty == Tfunction); - assert(fd->type->nextOf()->ty == Tarray); - return ((TypeFunction *)fd->type)->nextOf()->nextOf(); -} - -/* Decoding UTF strings for foreach loops. Duplicates the functionality of - * the twelve _aApplyXXn functions in aApply.d in the runtime. - */ -Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *deleg, bool rvs) -{ -#if LOG - printf("foreachApplyUtf(%s, %s)\n", str->toChars(), deleg->toChars()); -#endif - FuncDeclaration *fd = NULL; - Expression *pthis = NULL; - if (deleg->op == TOKdelegate) - { - fd = ((DelegateExp *)deleg)->func; - pthis = ((DelegateExp *)deleg)->e1; - } - else if (deleg->op == TOKfunction) - fd = ((FuncExp*)deleg)->fd; - - assert(fd && fd->fbody); - assert(fd->parameters); - int numParams = fd->parameters->dim; - assert(numParams == 1 || numParams==2); - Type *charType = fd->parameters->tdata()[numParams-1]->type; - Type *indexType = numParams == 2 ? fd->parameters->tdata()[0]->type - : Type::tsize_t; - uinteger_t len = resolveArrayLength(str); - if (len == 0) - return new IntegerExp(deleg->loc, 0, indexType); - - if (str->op == TOKslice) - str = resolveSlice(str); - - StringExp *se = NULL; - ArrayLiteralExp *ale = NULL; - if (str->op == TOKstring) - se = (StringExp *) str; - else if (str->op == TOKarrayliteral) - ale = (ArrayLiteralExp *)str; - else - { str->error("CTFE internal error: cannot foreach %s", str->toChars()); - return EXP_CANT_INTERPRET; - } - Expressions args; - args.setDim(numParams); - - Expression *eresult; - - // Buffers for encoding; also used for decoding array literals - unsigned char utf8buf[4]; - unsigned short utf16buf[2]; - - size_t start = rvs ? len : 0; - size_t end = rvs ? 0: len; - for (size_t indx = start; indx != end;) - { - // Step 1: Decode the next dchar from the string. - - const char *errmsg = NULL; // Used for reporting decoding errors - dchar_t rawvalue; // Holds the decoded dchar - size_t currentIndex = indx; // The index of the decoded character - - if (ale) - { // If it is an array literal, copy the code points into the buffer - int buflen = 1; // #code points in the buffer - size_t n = 1; // #code points in this char - size_t sz = ale->type->nextOf()->size(); - - switch(sz) - { - case 1: - if (rvs) - { // find the start of the string - --indx; - buflen = 1; - while (indx > 0 && buflen < 4) - { Expression * r = ale->elements->tdata()[indx]; - assert(r->op == TOKint64); - unsigned char x = (unsigned char)(((IntegerExp *)r)->value); - if ( (x & 0xC0) != 0x80) - break; - ++buflen; - } - } - else - buflen = (indx + 4 > len) ? len - indx : 4; - for (int i=0; i < buflen; ++i) - { - Expression * r = ale->elements->tdata()[indx + i]; - assert(r->op == TOKint64); - utf8buf[i] = (unsigned char)(((IntegerExp *)r)->value); - } - n = 0; - errmsg = utf_decodeChar(&utf8buf[0], buflen, &n, &rawvalue); - break; - case 2: - if (rvs) - { // find the start of the string - --indx; - buflen = 1; - Expression * r = ale->elements->tdata()[indx]; - assert(r->op == TOKint64); - unsigned short x = (unsigned short)(((IntegerExp *)r)->value); - if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF) - { - --indx; - ++buflen; - } - } - else - buflen = (indx + 2 > len) ? len - indx : 2; - for (int i=0; i < buflen; ++i) - { - Expression * r = ale->elements->tdata()[indx + i]; - assert(r->op == TOKint64); - utf16buf[i] = (unsigned short)(((IntegerExp *)r)->value); - } - n = 0; - errmsg = utf_decodeWchar(&utf16buf[0], buflen, &n, &rawvalue); - break; - case 4: - { - if (rvs) - --indx; - - Expression * r = ale->elements->tdata()[indx]; - assert(r->op == TOKint64); - rawvalue = ((IntegerExp *)r)->value; - n = 1; - } - break; - default: - assert(0); - } - if (!rvs) - indx += n; - } - else - { // String literals - size_t saveindx; // used for reverse iteration - - switch (se->sz) - { - case 1: - if (rvs) - { // find the start of the string - unsigned char *s = (unsigned char *)se->string; - --indx; - while (indx > 0 && ((s[indx]&0xC0)==0x80)) - --indx; - saveindx = indx; - } - errmsg = utf_decodeChar((unsigned char *)se->string, se->len, &indx, &rawvalue); - if (rvs) - indx = saveindx; - break; - case 2: - if (rvs) - { // find the start - unsigned short *s = (unsigned short *)se->string; - --indx; - if (s[indx] >= 0xDC00 && s[indx]<= 0xDFFF) - --indx; - saveindx = indx; - } - errmsg = utf_decodeWchar((unsigned short *)se->string, se->len, &indx, &rawvalue); - if (rvs) - indx = saveindx; - break; - case 4: - if (rvs) - --indx; - rawvalue = ((unsigned *)(se->string))[indx]; - if (!rvs) - ++indx; - break; - default: - assert(0); - } - } - if (errmsg) - { deleg->error("%s", errmsg); - return EXP_CANT_INTERPRET; - } - - // Step 2: encode the dchar in the target encoding - - int charlen = 1; // How many codepoints are involved? - switch(charType->size()) - { - case 1: - charlen = utf_codeLengthChar(rawvalue); - utf_encodeChar(&utf8buf[0], rawvalue); - break; - case 2: - charlen = utf_codeLengthWchar(rawvalue); - utf_encodeWchar(&utf16buf[0], rawvalue); - break; - case 4: - break; - default: - assert(0); - } - if (rvs) - currentIndex = indx; - - // Step 3: call the delegate once for each code point - - // The index only needs to be set once - if (numParams == 2) - args[0] = new IntegerExp(deleg->loc, currentIndex, indexType); - - Expression *val = NULL; - - for (int k= 0; k < charlen; ++k) - { - dchar_t codepoint; - switch(charType->size()) - { - case 1: - codepoint = utf8buf[k]; - break; - case 2: - codepoint = utf16buf[k]; - break; - case 4: - codepoint = rawvalue; - break; - default: - assert(0); - } - val = new IntegerExp(str->loc, codepoint, charType); - - args[numParams - 1] = val; - - eresult = fd->interpret(istate, &args, pthis); - if (exceptionOrCantInterpret(eresult)) - return eresult; - assert(eresult->op == TOKint64); - if (((IntegerExp *)eresult)->value != 0) - return eresult; - } - } - return eresult; -} - -/* If this is a built-in function, return the interpreted result, - * Otherwise, return NULL. - */ -Expression *evaluateIfBuiltin(InterState *istate, Loc loc, - FuncDeclaration *fd, Expressions *arguments, Expression *pthis) -{ - Expression *e = NULL; - int nargs = arguments ? arguments->dim : 0; -#if DMDV2 - if (pthis && isAssocArray(pthis->type)) - { - if (fd->ident == Id::length && nargs==0) - return interpret_length(istate, pthis); - else if (fd->ident == Id::keys && nargs==0) - return interpret_keys(istate, pthis, returnedArrayElementType(fd)); - else if (fd->ident == Id::values && nargs==0) - return interpret_values(istate, pthis, returnedArrayElementType(fd)); - else if (fd->ident == Id::rehash && nargs==0) - return pthis->interpret(istate, ctfeNeedLvalue); // rehash is a no-op - } - if (!pthis) - { - enum BUILTIN b = fd->isBuiltin(); - if (b) - { Expressions args; - args.setDim(nargs); - for (size_t i = 0; i < args.dim; i++) - { - Expression *earg = (*arguments)[i]; - earg = earg->interpret(istate); - if (exceptionOrCantInterpret(earg)) - return earg; - args[i] = earg; - } - e = eval_builtin(loc, b, &args); - if (!e) - e = EXP_CANT_INTERPRET; - } - } - /* Horrid hack to retrieve the builtin AA functions after they've been - * mashed by the inliner. - */ - if (!pthis) - { - Expression *firstarg = nargs > 0 ? (Expression *)(arguments->data[0]) : NULL; - // Check for the first parameter being a templatized AA. Hack: we assume that - // template AA.var is always the AA data itself. - Expression *firstdotvar = (firstarg && firstarg->op == TOKdotvar) - ? ((DotVarExp *)firstarg)->e1 : NULL; - if (nargs==3 && isAssocArray(firstarg->type) && !strcmp(fd->ident->string, "_aaApply")) - return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2])); - if (nargs==3 && isAssocArray(firstarg->type) &&!strcmp(fd->ident->string, "_aaApply2")) - return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2])); - if (firstdotvar && isAssocArray(firstdotvar->type)) - { if (fd->ident == Id::aaLen && nargs == 1) - return interpret_length(istate, firstdotvar->interpret(istate)); - else if (fd->ident == Id::aaKeys && nargs == 2) - { - Expression *trueAA = firstdotvar->interpret(istate); - return interpret_keys(istate, trueAA, toBuiltinAAType(trueAA->type)->index); - } - else if (fd->ident == Id::aaValues && nargs == 3) - { - Expression *trueAA = firstdotvar->interpret(istate); - return interpret_values(istate, trueAA, toBuiltinAAType(trueAA->type)->nextOf()); - } - else if (fd->ident == Id::aaRehash && nargs == 2) - { - return firstdotvar->interpret(istate, ctfeNeedLvalue); - } - } - } -#endif -#if DMDV1 - if (!pthis) - { - Expression *firstarg = nargs > 0 ? (Expression *)(arguments->data[0]) : NULL; - if (firstarg && firstarg->type->toBasetype()->ty == Taarray) - { - TypeAArray *firstAAtype = (TypeAArray *)firstarg->type; - if (fd->ident == Id::aaLen && nargs == 1) - return interpret_length(istate, firstarg); - else if (fd->ident == Id::aaKeys) - return interpret_keys(istate, firstarg, firstAAtype->index); - else if (fd->ident == Id::aaValues) - return interpret_values(istate, firstarg, firstAAtype->nextOf()); - else if (nargs==2 && fd->ident == Id::aaRehash) - return firstarg->interpret(istate, ctfeNeedLvalue); //no-op - else if (nargs==3 && !strcmp(fd->ident->string, "_aaApply")) - return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2])); - else if (nargs==3 && !strcmp(fd->ident->string, "_aaApply2")) - return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2])); - } - } -#endif -#if DMDV2 - if (pthis && !fd->fbody && fd->isCtorDeclaration() && fd->parent && fd->parent->parent && fd->parent->parent->ident == Id::object) - { - if (pthis->op == TOKclassreference && fd->parent->ident == Id::Throwable) - { // At present, the constructors just copy their arguments into the struct. - // But we might need some magic if stack tracing gets added to druntime. - StructLiteralExp *se = ((ClassReferenceExp *)pthis)->value; - assert(arguments->dim <= se->elements->dim); - for (int i = 0; i < arguments->dim; ++i) - { - Expression *e = (*arguments)[i]->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - se->elements->tdata()[i] = e; - } - return EXP_VOID_INTERPRET; - } - } -#endif - if (nargs == 1 && !pthis && - (fd->ident == Id::criticalenter || fd->ident == Id::criticalexit)) - { // Support synchronized{} as a no-op - return EXP_VOID_INTERPRET; - } - if (!pthis) - { - size_t idlen = strlen(fd->ident->string); - if (nargs == 2 && (idlen == 10 || idlen == 11) - && !strncmp(fd->ident->string, "_aApply", 7)) - { // Functions from aApply.d and aApplyR.d in the runtime - bool rvs = (idlen == 11); // true if foreach_reverse - char c = fd->ident->string[idlen-3]; // char width: 'c', 'w', or 'd' - char s = fd->ident->string[idlen-2]; // string width: 'c', 'w', or 'd' - char n = fd->ident->string[idlen-1]; // numParams: 1 or 2. - // There are 12 combinations - if ( (n == '1' || n == '2') && - (c == 'c' || c == 'w' || c == 'd') && - (s == 'c' || s == 'w' || s == 'd') && c != s) - { Expression *str = (*arguments)[0]; - str = str->interpret(istate); - if (exceptionOrCantInterpret(str)) - return str; - return foreachApplyUtf(istate, str, (*arguments)[1], rvs); - } - } - } - return e; -} - -/*************************** CTFE Sanity Checks ***************************/ - -/* Setter functions for CTFE variable values. - * These functions exist to check for compiler CTFE bugs. - */ - -bool isCtfeValueValid(Expression *newval) -{ - if ( -#if DMDV2 - newval->type->ty == Tnull || -#endif - isPointer(newval->type) ) - { - if (newval->op == TOKaddress || newval->op == TOKnull || - newval->op == TOKstring) - return true; - if (newval->op == TOKindex) - { - Expression *g = ((IndexExp *)newval)->e1; - if (g->op == TOKarrayliteral || g->op == TOKstring || - g->op == TOKassocarrayliteral) - return true; - } - if (newval->op == TOKvar) - return true; - if (newval->type->nextOf()->ty == Tarray && newval->op == TOKslice) - return true; - if (newval->op == TOKint64) - return true; // Result of a cast, but cannot be dereferenced - // else it must be a reference - } - if (newval->op == TOKclassreference || (newval->op == TOKnull && newval->type->ty == Tclass)) - return true; - if (newval->op == TOKvar) - { - VarExp *ve = (VarExp *)newval; - VarDeclaration *vv = ve->var->isVarDeclaration(); - // Must not be a reference to a reference - if (!(vv && vv->getValue() && vv->getValue()->op == TOKvar)) - return true; - } - if (newval->op == TOKdotvar) - { - if (((DotVarExp *)newval)->e1->op == TOKstructliteral) - { - assert(((StructLiteralExp *)((DotVarExp *)newval)->e1)->ownedByCtfe); - return true; - } - } - if (newval->op == TOKindex) - { - IndexExp *ie = (IndexExp *)newval; - if (ie->e2->op == TOKint64) - { - if (ie->e1->op == TOKarrayliteral || ie->e1->op == TOKstring) - return true; - } - if (ie->e1->op == TOKassocarrayliteral) - return true; - // BUG: Happens ONLY in ref foreach. Should tighten this. - if (ie->e2->op == TOKvar) - return true; - } - if (newval->op == TOKfunction) return true; // function/delegate literal - if (newval->op == TOKdelegate) return true; - if (newval->op == TOKsymoff) // function pointer - { - if (((SymOffExp *)newval)->var->isFuncDeclaration()) - return true; - } - if (newval->op == TOKint64 || newval->op == TOKfloat64 || - newval->op == TOKchar || newval->op == TOKcomplex80) - return true; - - // References - - if (newval->op == TOKstructliteral) - assert(((StructLiteralExp *)newval)->ownedByCtfe); - if (newval->op == TOKarrayliteral) - assert(((ArrayLiteralExp *)newval)->ownedByCtfe); - if (newval->op == TOKassocarrayliteral) - assert(((AssocArrayLiteralExp *)newval)->ownedByCtfe); - - if ((newval->op ==TOKarrayliteral) || ( newval->op==TOKstructliteral) || - (newval->op==TOKstring) || (newval->op == TOKassocarrayliteral) || - (newval->op == TOKnull)) - { return true; - } - // Dynamic arrays passed by ref may be null. When this happens - // they may originate from an index or dotvar expression. - if (newval->type->ty == Tarray || newval->type->ty == Taarray) - if (newval->op == TOKdotvar || newval->op == TOKindex) - return true; // actually must be null - - if (newval->op == TOKslice) - { - SliceExp *se = (SliceExp *)newval; - assert(se->lwr && se->lwr != EXP_CANT_INTERPRET && se->lwr->op == TOKint64); - assert(se->upr && se->upr != EXP_CANT_INTERPRET && se->upr->op == TOKint64); - assert(se->e1->op == TOKarrayliteral || se->e1->op == TOKstring); - if (se->e1->op == TOKarrayliteral) - assert(((ArrayLiteralExp *)se->e1)->ownedByCtfe); - return true; - } - if (newval->op == TOKvoid) - { - return true; - } - newval->error("CTFE internal error: illegal value %s\n", newval->toChars()); - return false; -} - -bool VarDeclaration::hasValue() -{ - if (ctfeAdrOnStack == (size_t)-1) - return false; - return NULL != getValue(); -} - -Expression *VarDeclaration::getValue() -{ - return ctfeStack.getValue(this); -} - -void VarDeclaration::setValueNull() -{ - ctfeStack.setValue(this, NULL); -} - -// Don't check for validity -void VarDeclaration::setValueWithoutChecking(Expression *newval) -{ - ctfeStack.setValue(this, newval); -} - -void VarDeclaration::setValue(Expression *newval) -{ - assert(isCtfeValueValid(newval)); - ctfeStack.setValue(this, newval); -} - - -Expression *Type::voidInitLiteral(VarDeclaration *var) -{ - return new VoidInitExp(var, this); -} - -Expression *TypeSArray::voidInitLiteral(VarDeclaration *var) -{ - return createBlockDuplicatedArrayLiteral(var->loc, this, next->voidInitLiteral(var), dim->toInteger()); -} - -Expression *TypeStruct::voidInitLiteral(VarDeclaration *var) -{ - Expressions *exps = new Expressions(); - exps->setDim(sym->fields.dim); - for (size_t i = 0; i < sym->fields.dim; i++) - { - //(*exps)[i] = new VoidInitExp(var, sym->fields[i]->type); - (*exps)[i] = sym->fields[i]->type->voidInitLiteral(var); - } - StructLiteralExp *se = new StructLiteralExp(var->loc, sym, exps); - se->type = this; - se->ownedByCtfe = true; - return se; -} diff --git a/dmd/json.c b/dmd/json.c deleted file mode 100644 index d3efacf5..00000000 --- a/dmd/json.c +++ /dev/null @@ -1,462 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// This implements the JSON capability. - -#include -#include -#include -#include -#include - -#include "rmem.h" -#include "root.h" - -#include "mars.h" -#include "dsymbol.h" -#include "macro.h" -#include "template.h" -#include "lexer.h" -#include "aggregate.h" -#include "declaration.h" -#include "enum.h" -#include "id.h" -#include "module.h" -#include "scope.h" -#include "hdrgen.h" -#include "json.h" -#include "mtype.h" -#include "attrib.h" -#include "cond.h" - -const char Pname[] = "name"; -const char Pkind[] = "kind"; -const char Pfile[] = "file"; -const char Pline[] = "line"; -const char Ptype[] = "type"; -const char Pcomment[] = "comment"; -const char Pmembers[] = "members"; -const char Pprotection[] = "protection"; -const char* Pprotectionnames[] = {NULL, "none", "private", "package", "protected", "public", "export"}; - -void JsonRemoveComma(OutBuffer *buf); - -void json_generate(Modules *modules) -{ OutBuffer buf; - - buf.writestring("[\n"); - for (size_t i = 0; i < modules->dim; i++) - { Module *m = modules->tdata()[i]; - if (global.params.verbose) - printf("json gen %s\n", m->toChars()); - m->toJsonBuffer(&buf); - buf.writestring(",\n"); - } - JsonRemoveComma(&buf); - buf.writestring("]\n"); - - // Write buf to file - char *arg = global.params.xfilename; - if (!arg || !*arg) - { // Generate lib file name from first obj name - char *n = global.params.objfiles->tdata()[0]; - - n = FileName::name(n); - FileName *fn = FileName::forceExt(n, global.json_ext); - arg = fn->toChars(); - } - else if (arg[0] == '-' && arg[1] == 0) - { // Write to stdout; assume it succeeds - int n = fwrite(buf.data, 1, buf.offset, stdout); - assert(n == buf.offset); // keep gcc happy about return values - return; - } -// if (!FileName::absolute(arg)) -// arg = FileName::combine(dir, arg); - FileName *jsonfilename = FileName::defaultExt(arg, global.json_ext); - File *jsonfile = new File(jsonfilename); - assert(jsonfile); - jsonfile->setbuffer(buf.data, buf.offset); - jsonfile->ref = 1; - char *pt = FileName::path(jsonfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - jsonfile->writev(); -} - - -/********************************* - * Encode string into buf, and wrap it in double quotes. - */ -void JsonString(OutBuffer *buf, const char *s) -{ - buf->writeByte('\"'); - for (; *s; s++) - { - unsigned char c = (unsigned char) *s; - switch (c) - { - case '\n': - buf->writestring("\\n"); - break; - - case '\r': - buf->writestring("\\r"); - break; - - case '\t': - buf->writestring("\\t"); - break; - - case '\"': - buf->writestring("\\\""); - break; - - case '\\': - buf->writestring("\\\\"); - break; - - case '/': - buf->writestring("\\/"); - break; - - case '\b': - buf->writestring("\\b"); - break; - - case '\f': - buf->writestring("\\f"); - break; - - default: - if (c < 0x20) - buf->printf("\\u%04x", c); - else - // Note that UTF-8 chars pass through here just fine - buf->writeByte(c); - break; - } - } - buf->writeByte('\"'); -} - -void JsonProperty(OutBuffer *buf, const char *name, const char *value) -{ - JsonString(buf, name); - buf->writestring(" : "); - JsonString(buf, value); - buf->writestring(",\n"); -} - -void JsonProperty(OutBuffer *buf, const char *name, int value) -{ - JsonString(buf, name); - buf->writestring(" : "); - buf->printf("%d", value); - buf->writestring(",\n"); -} - -void JsonRemoveComma(OutBuffer *buf) -{ - if (buf->offset >= 2 && - buf->data[buf->offset - 2] == ',' && - buf->data[buf->offset - 1] == '\n') - buf->offset -= 2; -} - -void Dsymbol::toJsonBuffer(OutBuffer *buf) -{ -} - -void Module::toJsonBuffer(OutBuffer *buf) -{ - buf->writestring("{\n"); - - if (md) - JsonProperty(buf, Pname, md->toChars()); - - JsonProperty(buf, Pkind, kind()); - - JsonProperty(buf, Pfile, srcfile->toChars()); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - JsonString(buf, Pmembers); - buf->writestring(" : [\n"); - - size_t offset = buf->offset; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); - } - - JsonRemoveComma(buf); - buf->writestring("]\n"); - - buf->writestring("}\n"); -} - -void AttribDeclaration::toJsonBuffer(OutBuffer *buf) -{ - //printf("AttribDeclaration::toJsonBuffer()\n"); - - Dsymbols *d = include(NULL, NULL); - - if (d) - { - size_t offset = buf->offset; - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - //printf("AttribDeclaration::toJsonBuffer %s\n", s->toChars()); - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); - } - JsonRemoveComma(buf); - } -} - - -void ConditionalDeclaration::toJsonBuffer(OutBuffer *buf) -{ - //printf("ConditionalDeclaration::toJsonBuffer()\n"); - if (condition->inc) - { - AttribDeclaration::toJsonBuffer(buf); - } -} - - -void InvariantDeclaration::toJsonBuffer(OutBuffer *buf) { } -void DtorDeclaration::toJsonBuffer(OutBuffer *buf) { } -void StaticCtorDeclaration::toJsonBuffer(OutBuffer *buf) { } -void StaticDtorDeclaration::toJsonBuffer(OutBuffer *buf) { } -void ClassInfoDeclaration::toJsonBuffer(OutBuffer *buf) { } -void ModuleInfoDeclaration::toJsonBuffer(OutBuffer *buf) { } -void TypeInfoDeclaration::toJsonBuffer(OutBuffer *buf) { } -void UnitTestDeclaration::toJsonBuffer(OutBuffer *buf) { } -#if DMDV2 -void PostBlitDeclaration::toJsonBuffer(OutBuffer *buf) { } -#endif - -void Declaration::toJsonBuffer(OutBuffer *buf) -{ - //printf("Declaration::toJsonBuffer()\n"); - buf->writestring("{\n"); - - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); - - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); - - if (type) - JsonProperty(buf, Ptype, type->toChars()); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - TypedefDeclaration *td = isTypedefDeclaration(); - if (td) - { - JsonProperty(buf, "base", td->basetype->toChars()); - } - - JsonRemoveComma(buf); - buf->writestring("}\n"); -} - -void AggregateDeclaration::toJsonBuffer(OutBuffer *buf) -{ - //printf("AggregateDeclaration::toJsonBuffer()\n"); - buf->writestring("{\n"); - - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); - - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - ClassDeclaration *cd = isClassDeclaration(); - if (cd) - { - if (cd->baseClass) - { - JsonProperty(buf, "base", cd->baseClass->toChars()); - } - if (cd->interfaces_dim) - { - JsonString(buf, "interfaces"); - buf->writestring(" : [\n"); - size_t offset = buf->offset; - for (size_t i = 0; i < cd->interfaces_dim; i++) - { BaseClass *b = cd->interfaces[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - JsonString(buf, b->base->toChars()); - } - JsonRemoveComma(buf); - buf->writestring("],\n"); - } - } - - if (members) - { - JsonString(buf, Pmembers); - buf->writestring(" : [\n"); - size_t offset = buf->offset; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); - } - JsonRemoveComma(buf); - buf->writestring("]\n"); - } - JsonRemoveComma(buf); - - buf->writestring("}\n"); -} - -void TemplateDeclaration::toJsonBuffer(OutBuffer *buf) -{ - //printf("TemplateDeclaration::toJsonBuffer()\n"); - - buf->writestring("{\n"); - - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); - - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - JsonString(buf, Pmembers); - buf->writestring(" : [\n"); - size_t offset = buf->offset; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); - } - JsonRemoveComma(buf); - buf->writestring("]\n"); - - buf->writestring("}\n"); -} - -void EnumDeclaration::toJsonBuffer(OutBuffer *buf) -{ - //printf("EnumDeclaration::toJsonBuffer()\n"); - if (isAnonymous()) - { - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->toJsonBuffer(buf); - buf->writestring(",\n"); - } - JsonRemoveComma(buf); - } - return; - } - - buf->writestring("{\n"); - - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); - - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - if (memtype) - JsonProperty(buf, "base", memtype->toChars()); - - if (members) - { - JsonString(buf, Pmembers); - buf->writestring(" : [\n"); - size_t offset = buf->offset; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); - } - JsonRemoveComma(buf); - buf->writestring("]\n"); - } - JsonRemoveComma(buf); - - buf->writestring("}\n"); -} - -void EnumMember::toJsonBuffer(OutBuffer *buf) -{ - //printf("EnumMember::toJsonBuffer()\n"); - buf->writestring("{\n"); - - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); - - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - JsonRemoveComma(buf); - buf->writestring("}\n"); -} - - diff --git a/dmd/json.h b/dmd/json.h deleted file mode 100644 index 2c7e2e60..00000000 --- a/dmd/json.h +++ /dev/null @@ -1,24 +0,0 @@ - - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_JSON_H -#define DMD_JSON_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "arraytypes.h" - -void json_generate(Modules *); - -#endif /* DMD_JSON_H */ - diff --git a/dmd/lexer.c b/dmd/lexer.c deleted file mode 100644 index 98de26e8..00000000 --- a/dmd/lexer.c +++ /dev/null @@ -1,3227 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#if __sun && __SVR4 -#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more, LDC#313 -#endif - -#if IN_LLVM -#include -#endif - -#include - -/* Lexical Analyzer */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include // for time() and ctime() - -#include "rmem.h" - -#include "stringtable.h" - -#include "lexer.h" -#include "utf.h" -#include "identifier.h" -#include "id.h" -#include "module.h" - -#if _WIN32 && __DMC__ -// from \dm\src\include\setlocal.h -extern "C" char * __cdecl __locale_decpoint; -#endif - -extern int HtmlNamedEntity(unsigned char *p, int length); - -#define LS 0x2028 // UTF line separator -#define PS 0x2029 // UTF paragraph separator - -void unittest_lexer(); - -/******************************************** - * Do our own char maps - */ - -static unsigned char cmtable[256]; - -const int CMoctal = 0x1; -const int CMhex = 0x2; -const int CMidchar = 0x4; - -inline unsigned char isoctal (unsigned char c) { return cmtable[c] & CMoctal; } -inline unsigned char ishex (unsigned char c) { return cmtable[c] & CMhex; } -inline unsigned char isidchar(unsigned char c) { return cmtable[c] & CMidchar; } - -static void cmtable_init() -{ - for (unsigned c = 0; c < sizeof(cmtable) / sizeof(cmtable[0]); c++) - { - if ('0' <= c && c <= '7') - cmtable[c] |= CMoctal; - if (isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')) - cmtable[c] |= CMhex; - if (isalnum(c) || c == '_') - cmtable[c] |= CMidchar; - } -} - - -/************************* Token **********************************************/ - -const char *Token::tochars[TOKMAX]; - -void *Token::operator new(size_t size) -{ Token *t; - - if (Lexer::freelist) - { - t = Lexer::freelist; - Lexer::freelist = t->next; - return t; - } - - return ::operator new(size); -} - -#ifdef DEBUG -void Token::print() -{ - fprintf(stdmsg, "%s\n", toChars()); -} -#endif - -const char *Token::toChars() -{ const char *p; - static char buffer[3 + 3 * sizeof(float80value) + 1]; - - p = buffer; - switch (value) - { - case TOKint32v: - sprintf(buffer,"%d",(d_int32)int64value); - break; - - case TOKuns32v: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - sprintf(buffer,"%uU",(d_uns32)uns64value); - break; - - case TOKint64v: - sprintf(buffer,"%jdL",(intmax_t)int64value); - break; - - case TOKuns64v: - sprintf(buffer,"%juUL",(uintmax_t)uns64value); - break; - -#if IN_GCC - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - float80value.format(buffer, sizeof(buffer)); - break; - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - float80value.format(buffer, sizeof(buffer)); - // %% buffer - strcat(buffer, "i"); - break; -#else - case TOKfloat32v: - sprintf(buffer,"%Lgf", float80value); - break; - - case TOKfloat64v: - sprintf(buffer,"%Lg", float80value); - break; - - case TOKfloat80v: - sprintf(buffer,"%LgL", float80value); - break; - - case TOKimaginary32v: - sprintf(buffer,"%Lgfi", float80value); - break; - - case TOKimaginary64v: - sprintf(buffer,"%Lgi", float80value); - break; - - case TOKimaginary80v: - sprintf(buffer,"%LgLi", float80value); - break; -#endif - - case TOKstring: -#if CSTRINGS - p = string; -#else - { OutBuffer buf; - - buf.writeByte('"'); - for (size_t i = 0; i < len; ) - { unsigned c; - - utf_decodeChar((unsigned char *)ustring, len, &i, &c); - switch (c) - { - case 0: - break; - - case '"': - case '\\': - buf.writeByte('\\'); - default: - if (isprint(c)) - buf.writeByte(c); - else if (c <= 0x7F) - buf.printf("\\x%02x", c); - else if (c <= 0xFFFF) - buf.printf("\\u%04x", c); - else - buf.printf("\\U%08x", c); - continue; - } - break; - } - buf.writeByte('"'); - if (postfix) - buf.writeByte('"'); - buf.writeByte(0); - p = (char *)buf.extractData(); - } -#endif - break; - - case TOKidentifier: - case TOKenum: - case TOKstruct: - case TOKimport: - case BASIC_TYPES: - p = ident->toChars(); - break; - - default: - p = toChars(value); - break; - } - return p; -} - -const char *Token::toChars(enum TOK value) -{ const char *p; - static char buffer[3 + 3 * sizeof(value) + 1]; - - p = tochars[value]; - if (!p) - { sprintf(buffer,"TOK%d",value); - p = buffer; - } - return p; -} - -/*************************** Lexer ********************************************/ - -Token *Lexer::freelist = NULL; -StringTable Lexer::stringtable; -OutBuffer Lexer::stringbuffer; - -Lexer::Lexer(Module *mod, - unsigned char *base, unsigned begoffset, unsigned endoffset, - int doDocComment, int commentToken) - : loc(mod, 1) -{ - //printf("Lexer::Lexer(%p,%d)\n",base,length); - //printf("lexer.mod = %p, %p\n", mod, this->loc.mod); - memset(&token,0,sizeof(token)); - this->base = base; - this->end = base + endoffset; - p = base + begoffset; - this->mod = mod; - this->doDocComment = doDocComment; - this->anyToken = 0; - this->commentToken = commentToken; - //initKeywords(); - - /* If first line starts with '#!', ignore the line - */ - - if (p[0] == '#' && p[1] =='!') - { - p += 2; - while (1) - { unsigned char c = *p; - switch (c) - { - case '\n': - p++; - break; - - case '\r': - p++; - if (*p == '\n') - p++; - break; - - case 0: - case 0x1A: - break; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - break; - } - p++; - continue; - } - break; - } - loc.linnum = 2; - } -} - - -void Lexer::error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(tokenLoc(), format, ap); - va_end(ap); -} - -void Lexer::error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end(ap); -} - -TOK Lexer::nextToken() -{ Token *t; - - if (token.next) - { - t = token.next; - memcpy(&token,t,sizeof(Token)); - t->next = freelist; - freelist = t; - } - else - { - scan(&token); - } - //token.print(); - return token.value; -} - -Token *Lexer::peek(Token *ct) -{ Token *t; - - if (ct->next) - t = ct->next; - else - { - t = new Token(); - scan(t); - t->next = NULL; - ct->next = t; - } - return t; -} - -/*********************** - * Look ahead at next token's value. - */ - -TOK Lexer::peekNext() -{ - return peek(&token)->value; -} - -/*********************** - * Look 2 tokens ahead at value. - */ - -TOK Lexer::peekNext2() -{ - Token *t = peek(&token); - return peek(t)->value; -} - -/********************************* - * tk is on the opening (. - * Look ahead and return token that is past the closing ). - */ - -Token *Lexer::peekPastParen(Token *tk) -{ - //printf("peekPastParen()\n"); - int parens = 1; - int curlynest = 0; - while (1) - { - tk = peek(tk); - //tk->print(); - switch (tk->value) - { - case TOKlparen: - parens++; - continue; - - case TOKrparen: - --parens; - if (parens) - continue; - tk = peek(tk); - break; - - case TOKlcurly: - curlynest++; - continue; - - case TOKrcurly: - if (--curlynest >= 0) - continue; - break; - - case TOKsemicolon: - if (curlynest) - continue; - break; - - case TOKeof: - break; - - default: - continue; - } - return tk; - } -} - -/********************************** - * Determine if string is a valid Identifier. - * Placed here because of commonality with Lexer functionality. - * Returns: - * 0 invalid - */ - -int Lexer::isValidIdentifier(char *p) -{ - size_t len; - size_t idx; - - if (!p || !*p) - goto Linvalid; - - if (*p >= '0' && *p <= '9') // beware of isdigit() on signed chars - goto Linvalid; - - len = strlen(p); - idx = 0; - while (p[idx]) - { dchar_t dc; - - const char *q = utf_decodeChar((unsigned char *)p, len, &idx, &dc); - if (q) - goto Linvalid; - - if (!((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_')) - goto Linvalid; - } - return 1; - -Linvalid: - return 0; -} - -/**************************** - * Turn next token in buffer into a token. - */ - -void Lexer::scan(Token *t) -{ - unsigned lastLine = loc.linnum; - unsigned linnum; - - t->blockComment = NULL; - t->lineComment = NULL; - while (1) - { - t->ptr = p; - //printf("p = %p, *p = '%c'\n",p,*p); - switch (*p) - { - case 0: - case 0x1A: - t->value = TOKeof; // end of file - return; - - case ' ': - case '\t': - case '\v': - case '\f': - p++; - continue; // skip white space - - case '\r': - p++; - if (*p != '\n') // if CR stands by itself - loc.linnum++; - continue; // skip white space - - case '\n': - p++; - loc.linnum++; - continue; // skip white space - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - t->value = number(t); - return; - -#if CSTRINGS - case '\'': - t->value = charConstant(t, 0); - return; - - case '"': - t->value = stringConstant(t,0); - return; - - case 'l': - case 'L': - if (p[1] == '\'') - { - p++; - t->value = charConstant(t, 1); - return; - } - else if (p[1] == '"') - { - p++; - t->value = stringConstant(t, 1); - return; - } -#else - case '\'': - t->value = charConstant(t,0); - return; - - case 'r': - if (p[1] != '"') - goto case_ident; - p++; - case '`': - t->value = wysiwygStringConstant(t, *p); - return; - - case 'x': - if (p[1] != '"') - goto case_ident; - p++; - t->value = hexStringConstant(t); - return; - -#if DMDV2 - case 'q': - if (p[1] == '"') - { - p++; - t->value = delimitedStringConstant(t); - return; - } - else if (p[1] == '{') - { - p++; - t->value = tokenStringConstant(t); - return; - } - else - goto case_ident; -#endif - - case '"': - t->value = escapeStringConstant(t,0); - return; - -#if ! TEXTUAL_ASSEMBLY_OUT - case '\\': // escaped string literal - { unsigned c; - unsigned char *pstart = p; - - stringbuffer.reset(); - do - { - p++; - switch (*p) - { - case 'u': - case 'U': - case '&': - c = escapeSequence(); - stringbuffer.writeUTF8(c); - break; - - default: - c = escapeSequence(); - stringbuffer.writeByte(c); - break; - } - } while (*p == '\\'); - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - t->postfix = 0; - t->value = TOKstring; -#if DMDV2 - if (!global.params.useDeprecated) - error("Escape String literal %.*s is deprecated, use double quoted string literal \"%.*s\" instead", p - pstart, pstart, p - pstart, pstart); -#endif - return; - } -#endif - - case 'l': - case 'L': -#endif - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'm': case 'n': case 'o': -#if DMDV2 - case 'p': /*case 'q': case 'r':*/ case 's': case 't': -#else - case 'p': case 'q': /*case 'r':*/ case 's': case 't': -#endif - case 'u': case 'v': case 'w': /*case 'x':*/ case 'y': - case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': - case 'Z': - case '_': - case_ident: - { unsigned char c; - - while (1) - { - c = *++p; - if (isidchar(c)) - continue; - else if (c & 0x80) - { unsigned char *s = p; - unsigned u = decodeUTF(); - if (isUniAlpha(u)) - continue; - error("char 0x%04x not allowed in identifier", u); - p = s; - } - break; - } - - StringValue *sv = stringtable.update((char *)t->ptr, p - t->ptr); - Identifier *id = (Identifier *) sv->ptrvalue; - if (!id) - { id = new Identifier(sv->toDchars(),TOKidentifier); - sv->ptrvalue = id; - } - t->ident = id; - t->value = (enum TOK) id->value; - anyToken = 1; - if (*t->ptr == '_') // if special identifier token - { - static char date[11+1]; - static char time[8+1]; - static char timestamp[24+1]; - - if (!date[0]) // lazy evaluation - { time_t t; - char *p; - - ::time(&t); - p = ctime(&t); - assert(p); - sprintf(date, "%.6s %.4s", p + 4, p + 20); - sprintf(time, "%.8s", p + 11); - sprintf(timestamp, "%.24s", p); - } - -#if DMDV1 - if (mod && id == Id::FILE) - { - t->ustring = (unsigned char *)(loc.filename ? loc.filename : mod->ident->toChars()); - goto Lstr; - } - else if (mod && id == Id::LINE) - { - t->value = TOKint64v; - t->uns64value = loc.linnum; - } - else -#endif - if (id == Id::DATE) - { - t->ustring = (unsigned char *)date; - goto Lstr; - } - else if (id == Id::TIME) - { - t->ustring = (unsigned char *)time; - goto Lstr; - } - else if (id == Id::VENDOR) - { - t->ustring = (unsigned char *)"LDC"; - goto Lstr; - } - else if (id == Id::TIMESTAMP) - { - t->ustring = (unsigned char *)timestamp; - Lstr: - t->value = TOKstring; - t->postfix = 0; - t->len = strlen((char *)t->ustring); - } - else if (id == Id::VERSIONX) - { unsigned major = 0; - unsigned minor = 0; - - for (const char *p = global.version + 1; 1; p++) - { - char c = *p; - if (isdigit((unsigned char)c)) - minor = minor * 10 + c - '0'; - else if (c == '.') - { major = minor; - minor = 0; - } - else - break; - } - t->value = TOKint64v; - t->uns64value = major * 1000 + minor; - } -#if DMDV2 - else if (id == Id::EOFX) - { - t->value = TOKeof; - // Advance scanner to end of file - while (!(*p == 0 || *p == 0x1A)) - p++; - } -#endif - } - //printf("t->value = %d\n",t->value); - return; - } - - case '/': - p++; - switch (*p) - { - case '=': - p++; - t->value = TOKdivass; - return; - - case '*': - p++; - linnum = loc.linnum; - while (1) - { - while (1) - { unsigned char c = *p; - switch (c) - { - case '/': - break; - - case '\n': - loc.linnum++; - p++; - continue; - - case '\r': - p++; - if (*p != '\n') - loc.linnum++; - continue; - - case 0: - case 0x1A: - error("unterminated /* */ comment"); - p = end; - t->value = TOKeof; - return; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - loc.linnum++; - } - p++; - continue; - } - break; - } - p++; - if (p[-2] == '*' && p - 3 != t->ptr) - break; - } - if (commentToken) - { - t->value = TOKcomment; - return; - } - else if (doDocComment && t->ptr[2] == '*' && p - 4 != t->ptr) - { // if /** but not /**/ - getDocComment(t, lastLine == linnum); - } - continue; - - case '/': // do // style comments - linnum = loc.linnum; - while (1) - { unsigned char c = *++p; - switch (c) - { - case '\n': - break; - - case '\r': - if (p[1] == '\n') - p++; - break; - - case 0: - case 0x1A: - if (commentToken) - { - p = end; - t->value = TOKcomment; - return; - } - if (doDocComment && t->ptr[2] == '/') - getDocComment(t, lastLine == linnum); - p = end; - t->value = TOKeof; - return; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - break; - } - continue; - } - break; - } - - if (commentToken) - { - p++; - loc.linnum++; - t->value = TOKcomment; - return; - } - if (doDocComment && t->ptr[2] == '/') - getDocComment(t, lastLine == linnum); - - p++; - loc.linnum++; - continue; - - case '+': - { int nest; - - linnum = loc.linnum; - p++; - nest = 1; - while (1) - { unsigned char c = *p; - switch (c) - { - case '/': - p++; - if (*p == '+') - { - p++; - nest++; - } - continue; - - case '+': - p++; - if (*p == '/') - { - p++; - if (--nest == 0) - break; - } - continue; - - case '\r': - p++; - if (*p != '\n') - loc.linnum++; - continue; - - case '\n': - loc.linnum++; - p++; - continue; - - case 0: - case 0x1A: - error("unterminated /+ +/ comment"); - p = end; - t->value = TOKeof; - return; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - loc.linnum++; - } - p++; - continue; - } - break; - } - if (commentToken) - { - t->value = TOKcomment; - return; - } - if (doDocComment && t->ptr[2] == '+' && p - 4 != t->ptr) - { // if /++ but not /++/ - getDocComment(t, lastLine == linnum); - } - continue; - } - } - t->value = TOKdiv; - return; - - case '.': - p++; - if (isdigit(*p)) - { /* Note that we don't allow ._1 and ._ as being - * valid floating point numbers. - */ - p--; - t->value = inreal(t); - } - else if (p[0] == '.') - { - if (p[1] == '.') - { p += 2; - t->value = TOKdotdotdot; - } - else - { p++; - t->value = TOKslice; - } - } - else - t->value = TOKdot; - return; - - case '&': - p++; - if (*p == '=') - { p++; - t->value = TOKandass; - } - else if (*p == '&') - { p++; - t->value = TOKandand; - } - else - t->value = TOKand; - return; - - case '|': - p++; - if (*p == '=') - { p++; - t->value = TOKorass; - } - else if (*p == '|') - { p++; - t->value = TOKoror; - } - else - t->value = TOKor; - return; - - case '-': - p++; - if (*p == '=') - { p++; - t->value = TOKminass; - } -#if 0 - else if (*p == '>') - { p++; - t->value = TOKarrow; - } -#endif - else if (*p == '-') - { p++; - t->value = TOKminusminus; - } - else - t->value = TOKmin; - return; - - case '+': - p++; - if (*p == '=') - { p++; - t->value = TOKaddass; - } - else if (*p == '+') - { p++; - t->value = TOKplusplus; - } - else - t->value = TOKadd; - return; - - case '<': - p++; - if (*p == '=') - { p++; - t->value = TOKle; // <= - } - else if (*p == '<') - { p++; - if (*p == '=') - { p++; - t->value = TOKshlass; // <<= - } - else - t->value = TOKshl; // << - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKleg; // <>= - } - else - t->value = TOKlg; // <> - } - else - t->value = TOKlt; // < - return; - - case '>': - p++; - if (*p == '=') - { p++; - t->value = TOKge; // >= - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKshrass; // >>= - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKushrass; // >>>= - } - else - t->value = TOKushr; // >>> - } - else - t->value = TOKshr; // >> - } - else - t->value = TOKgt; // > - return; - - case '!': - p++; - if (*p == '=') - { p++; - if (*p == '=' && global.params.Dversion == 1) - { p++; - t->value = TOKnotidentity; // !== - } - else - t->value = TOKnotequal; // != - } - else if (*p == '<') - { p++; - if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKunord; // !<>= - } - else - t->value = TOKue; // !<> - } - else if (*p == '=') - { p++; - t->value = TOKug; // !<= - } - else - t->value = TOKuge; // !< - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKul; // !>= - } - else - t->value = TOKule; // !> - } - else - t->value = TOKnot; // ! - return; - - case '=': - p++; - if (*p == '=') - { p++; - if (*p == '=' && global.params.Dversion == 1) - { p++; - t->value = TOKidentity; // === - } - else - t->value = TOKequal; // == - } -#if DMDV2 - else if (*p == '>') - { p++; - t->value = TOKgoesto; // => - } -#endif - else - t->value = TOKassign; // = - return; - - case '~': - p++; - if (*p == '=') - { p++; - t->value = TOKcatass; // ~= - } - else - t->value = TOKtilde; // ~ - return; - -#if DMDV2 - case '^': - p++; - if (*p == '^') - { p++; - if (*p == '=') - { p++; - t->value = TOKpowass; // ^^= - } - else - t->value = TOKpow; // ^^ - } - else if (*p == '=') - { p++; - t->value = TOKxorass; // ^= - } - else - t->value = TOKxor; // ^ - return; -#endif - -#define SINGLE(c,tok) case c: p++; t->value = tok; return; - - SINGLE('(', TOKlparen) - SINGLE(')', TOKrparen) - SINGLE('[', TOKlbracket) - SINGLE(']', TOKrbracket) - SINGLE('{', TOKlcurly) - SINGLE('}', TOKrcurly) - SINGLE('?', TOKquestion) - SINGLE(',', TOKcomma) - SINGLE(';', TOKsemicolon) - SINGLE(':', TOKcolon) - SINGLE('$', TOKdollar) - SINGLE('@', TOKat) -#undef SINGLE - -#define DOUBLE(c1,tok1,c2,tok2) \ - case c1: \ - p++; \ - if (*p == c2) \ - { p++; \ - t->value = tok2; \ - } \ - else \ - t->value = tok1; \ - return; - - DOUBLE('*', TOKmul, '=', TOKmulass) - DOUBLE('%', TOKmod, '=', TOKmodass) -#if DMDV1 - DOUBLE('^', TOKxor, '=', TOKxorass) -#endif -#undef DOUBLE - - case '#': - p++; - pragma(); - continue; - - default: - { unsigned c = *p; - - if (c & 0x80) - { c = decodeUTF(); - - // Check for start of unicode identifier - if (isUniAlpha(c)) - goto case_ident; - - if (c == PS || c == LS) - { - loc.linnum++; - p++; - continue; - } - } - if (c < 0x80 && isprint(c)) - error("unsupported char '%c'", c); - else - error("unsupported char 0x%02x", c); - p++; - continue; - } - } - } -} - -/******************************************* - * Parse escape sequence. - */ - -unsigned Lexer::escapeSequence() -{ unsigned c = *p; - -#ifdef TEXTUAL_ASSEMBLY_OUT - return c; -#endif - int n; - int ndigits; - - switch (c) - { - case '\'': - case '"': - case '?': - case '\\': - Lconsume: - p++; - break; - - case 'a': c = 7; goto Lconsume; - case 'b': c = 8; goto Lconsume; - case 'f': c = 12; goto Lconsume; - case 'n': c = 10; goto Lconsume; - case 'r': c = 13; goto Lconsume; - case 't': c = 9; goto Lconsume; - case 'v': c = 11; goto Lconsume; - - case 'u': - ndigits = 4; - goto Lhex; - case 'U': - ndigits = 8; - goto Lhex; - case 'x': - ndigits = 2; - Lhex: - p++; - c = *p; - if (ishex(c)) - { unsigned v; - - n = 0; - v = 0; - while (1) - { - if (isdigit(c)) - c -= '0'; - else if (islower(c)) - c -= 'a' - 10; - else - c -= 'A' - 10; - v = v * 16 + c; - c = *++p; - if (++n == ndigits) - break; - if (!ishex(c)) - { error("escape hex sequence has %d hex digits instead of %d", n, ndigits); - break; - } - } - if (ndigits != 2 && !utf_isValidDchar(v)) - { error("invalid UTF character \\U%08x", v); - v = '?'; // recover with valid UTF character - } - c = v; - } - else - error("undefined escape hex sequence \\%c\n",c); - break; - - case '&': // named character entity - for (unsigned char *idstart = ++p; 1; p++) - { - switch (*p) - { - case ';': - c = HtmlNamedEntity(idstart, p - idstart); - if (c == ~0) - { error("unnamed character entity &%.*s;", (int)(p - idstart), idstart); - c = ' '; - } - p++; - break; - - default: - if (isalpha(*p) || - (p != idstart + 1 && isdigit(*p))) - continue; - error("unterminated named entity"); - break; - } - break; - } - break; - - case 0: - case 0x1A: // end of file - c = '\\'; - break; - - default: - if (isoctal(c)) - { unsigned v; - - n = 0; - v = 0; - do - { - v = v * 8 + (c - '0'); - c = *++p; - } while (++n < 3 && isoctal(c)); - c = v; - if (c > 0xFF) - error("0%03o is larger than a byte", c); - } - else - error("undefined escape sequence \\%c\n",c); - break; - } - return c; -} - -/************************************** - */ - -TOK Lexer::wysiwygStringConstant(Token *t, int tc) -{ unsigned c; - Loc start = loc; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - switch (c) - { - case '\n': - loc.linnum++; - break; - - case '\r': - if (*p == '\n') - continue; // ignore - c = '\n'; // treat EndOfLine as \n character - loc.linnum++; - break; - - case 0: - case 0x1A: - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; - - case '"': - case '`': - if (c == tc) - { - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - } - break; - - default: - if (c & 0x80) - { p--; - unsigned u = decodeUTF(); - p++; - if (u == PS || u == LS) - loc.linnum++; - stringbuffer.writeUTF8(u); - continue; - } - break; - } - stringbuffer.writeByte(c); - } -} - -/************************************** - * Lex hex strings: - * x"0A ae 34FE BD" - */ - -TOK Lexer::hexStringConstant(Token *t) -{ unsigned c; - Loc start = loc; - unsigned n = 0; - unsigned v; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - switch (c) - { - case ' ': - case '\t': - case '\v': - case '\f': - continue; // skip white space - - case '\r': - if (*p == '\n') - continue; // ignore - // Treat isolated '\r' as if it were a '\n' - case '\n': - loc.linnum++; - continue; - - case 0: - case 0x1A: - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; - - case '"': - if (n & 1) - { error("odd number (%d) of hex characters in hex string", n); - stringbuffer.writeByte(v); - } - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - - default: - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'a' && c <= 'f') - c -= 'a' - 10; - else if (c >= 'A' && c <= 'F') - c -= 'A' - 10; - else if (c & 0x80) - { p--; - unsigned u = decodeUTF(); - p++; - if (u == PS || u == LS) - loc.linnum++; - else - error("non-hex character \\u%04x", u); - } - else - error("non-hex character '%c'", c); - if (n & 1) - { v = (v << 4) | c; - stringbuffer.writeByte(v); - } - else - v = c; - n++; - break; - } - } -} - - -#if DMDV2 -/************************************** - * Lex delimited strings: - * q"(foo(xxx))" // "foo(xxx)" - * q"[foo(]" // "foo(" - * q"/foo]/" // "foo]" - * q"HERE - * foo - * HERE" // "foo\n" - * Input: - * p is on the " - */ - -TOK Lexer::delimitedStringConstant(Token *t) -{ unsigned c; - Loc start = loc; - unsigned delimleft = 0; - unsigned delimright = 0; - unsigned nest = 1; - unsigned nestcount; - Identifier *hereid = NULL; - unsigned blankrol = 0; - unsigned startline = 0; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - //printf("c = '%c'\n", c); - switch (c) - { - case '\n': - Lnextline: - loc.linnum++; - startline = 1; - if (blankrol) - { blankrol = 0; - continue; - } - if (hereid) - { - stringbuffer.writeUTF8(c); - continue; - } - break; - - case '\r': - if (*p == '\n') - continue; // ignore - c = '\n'; // treat EndOfLine as \n character - goto Lnextline; - - case 0: - case 0x1A: - goto Lerror; - - default: - if (c & 0x80) - { p--; - c = decodeUTF(); - p++; - if (c == PS || c == LS) - goto Lnextline; - } - break; - } - if (delimleft == 0) - { delimleft = c; - nest = 1; - nestcount = 1; - if (c == '(') - delimright = ')'; - else if (c == '{') - delimright = '}'; - else if (c == '[') - delimright = ']'; - else if (c == '<') - delimright = '>'; - else if (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c))) - { // Start of identifier; must be a heredoc - Token t; - p--; - scan(&t); // read in heredoc identifier - if (t.value != TOKidentifier) - { error("identifier expected for heredoc, not %s", t.toChars()); - delimright = c; - } - else - { hereid = t.ident; - //printf("hereid = '%s'\n", hereid->toChars()); - blankrol = 1; - } - nest = 0; - } - else - { delimright = c; - nest = 0; -#if DMDV2 - if (isspace(c)) - error("delimiter cannot be whitespace"); -#endif - } - } - else - { - if (blankrol) - { error("heredoc rest of line should be blank"); - blankrol = 0; - continue; - } - if (nest == 1) - { - if (c == delimleft) - nestcount++; - else if (c == delimright) - { nestcount--; - if (nestcount == 0) - goto Ldone; - } - } - else if (c == delimright) - goto Ldone; - if (startline && isalpha(c) -#if DMDV2 - && hereid -#endif - ) - { Token t; - unsigned char *psave = p; - p--; - scan(&t); // read in possible heredoc identifier - //printf("endid = '%s'\n", t.ident->toChars()); - if (t.value == TOKidentifier && t.ident->equals(hereid)) - { /* should check that rest of line is blank - */ - goto Ldone; - } - p = psave; - } - stringbuffer.writeUTF8(c); - startline = 0; - } - } - -Ldone: - if (*p == '"') - p++; - else - error("delimited string must end in %c\"", delimright); - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - -Lerror: - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; -} - -/************************************** - * Lex delimited strings: - * q{ foo(xxx) } // " foo(xxx) " - * q{foo(} // "foo(" - * q{{foo}"}"} // "{foo}"}"" - * Input: - * p is on the q - */ - -TOK Lexer::tokenStringConstant(Token *t) -{ - unsigned nest = 1; - Loc start = loc; - unsigned char *pstart = ++p; - - while (1) - { Token tok; - - scan(&tok); - switch (tok.value) - { - case TOKlcurly: - nest++; - continue; - - case TOKrcurly: - if (--nest == 0) - goto Ldone; - continue; - - case TOKeof: - goto Lerror; - - default: - continue; - } - } - -Ldone: - t->len = p - 1 - pstart; - t->ustring = (unsigned char *)mem.malloc(t->len + 1); - memcpy(t->ustring, pstart, t->len); - t->ustring[t->len] = 0; - stringPostfix(t); - return TOKstring; - -Lerror: - error("unterminated token string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; -} - -#endif - - -/************************************** - */ - -TOK Lexer::escapeStringConstant(Token *t, int wide) -{ unsigned c; - Loc start = loc; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - switch (c) - { -#if !( TEXTUAL_ASSEMBLY_OUT ) - case '\\': - switch (*p) - { - case 'u': - case 'U': - case '&': - c = escapeSequence(); - stringbuffer.writeUTF8(c); - continue; - - default: - c = escapeSequence(); - break; - } - break; -#endif - case '\n': - loc.linnum++; - break; - - case '\r': - if (*p == '\n') - continue; // ignore - c = '\n'; // treat EndOfLine as \n character - loc.linnum++; - break; - - case '"': - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - - case 0: - case 0x1A: - p--; - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; - - default: - if (c & 0x80) - { - p--; - c = decodeUTF(); - if (c == LS || c == PS) - { c = '\n'; - loc.linnum++; - } - p++; - stringbuffer.writeUTF8(c); - continue; - } - break; - } - stringbuffer.writeByte(c); - } -} - -/************************************** - */ - -TOK Lexer::charConstant(Token *t, int wide) -{ - unsigned c; - TOK tk = TOKcharv; - - //printf("Lexer::charConstant\n"); - p++; - c = *p++; - switch (c) - { -#if ! TEXTUAL_ASSEMBLY_OUT - case '\\': - switch (*p) - { - case 'u': - t->uns64value = escapeSequence(); - tk = TOKwcharv; - break; - - case 'U': - case '&': - t->uns64value = escapeSequence(); - tk = TOKdcharv; - break; - - default: - t->uns64value = escapeSequence(); - break; - } - break; -#endif - case '\n': - L1: - loc.linnum++; - case '\r': - case 0: - case 0x1A: - case '\'': - error("unterminated character constant"); - return tk; - - default: - if (c & 0x80) - { - p--; - c = decodeUTF(); - p++; - if (c == LS || c == PS) - goto L1; - if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE)) - tk = TOKwcharv; - else - tk = TOKdcharv; - } - t->uns64value = c; - break; - } - - if (*p != '\'') - { error("unterminated character constant"); - return tk; - } - p++; - return tk; -} - -/*************************************** - * Get postfix of string literal. - */ - -void Lexer::stringPostfix(Token *t) -{ - switch (*p) - { - case 'c': - case 'w': - case 'd': - t->postfix = *p; - p++; - break; - - default: - t->postfix = 0; - break; - } -} - -/*************************************** - * Read \u or \U unicode sequence - * Input: - * u 'u' or 'U' - */ - -#if 0 -unsigned Lexer::wchar(unsigned u) -{ - unsigned value; - unsigned n; - unsigned char c; - unsigned nchars; - - nchars = (u == 'U') ? 8 : 4; - value = 0; - for (n = 0; 1; n++) - { - ++p; - if (n == nchars) - break; - c = *p; - if (!ishex(c)) - { error("\\%c sequence must be followed by %d hex characters", u, nchars); - break; - } - if (isdigit(c)) - c -= '0'; - else if (islower(c)) - c -= 'a' - 10; - else - c -= 'A' - 10; - value <<= 4; - value |= c; - } - return value; -} -#endif - -/************************************** - * Read in a number. - * If it's an integer, store it in tok.TKutok.Vlong. - * integers can be decimal, octal or hex - * Handle the suffixes U, UL, LU, L, etc. - * If it's double, store it in tok.TKutok.Vdouble. - * Returns: - * TKnum - * TKdouble,... - */ - -TOK Lexer::number(Token *t) -{ - // We use a state machine to collect numbers - enum STATE { STATE_initial, STATE_0, STATE_decimal, STATE_octal, STATE_octale, - STATE_hex, STATE_binary, STATE_hex0, STATE_binary0, - STATE_hexh, STATE_error }; - enum STATE state; - - enum FLAGS - { FLAGS_decimal = 1, // decimal - FLAGS_unsigned = 2, // u or U suffix - FLAGS_long = 4, // l or L suffix - }; - enum FLAGS flags = FLAGS_decimal; - - int base; - unsigned c; - unsigned char *start; - TOK result; - - //printf("Lexer::number()\n"); - state = STATE_initial; - base = 0; - stringbuffer.reset(); - start = p; - while (1) - { - c = *p; - switch (state) - { - case STATE_initial: // opening state - if (c == '0') - state = STATE_0; - else - state = STATE_decimal; - break; - - case STATE_0: - flags = (FLAGS) (flags & ~FLAGS_decimal); - switch (c) - { -#if ZEROH - case 'H': // 0h - case 'h': - goto hexh; -#endif - case 'X': - case 'x': - state = STATE_hex0; - break; - - case '.': - if (p[1] == '.') // .. is a separate token - goto done; - case 'i': - case 'f': - case 'F': - goto real; -#if ZEROH - case 'E': - case 'e': - goto case_hex; -#endif - case 'B': - case 'b': - state = STATE_binary0; - break; - - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - state = STATE_octal; - break; - -#if ZEROH - case '8': case '9': case 'A': - case 'C': case 'D': case 'F': - case 'a': case 'c': case 'd': case 'f': - case_hex: - state = STATE_hexh; - break; -#endif - case '_': - state = STATE_octal; - p++; - continue; - - case 'L': - if (p[1] == 'i') - goto real; - goto done; - - default: - goto done; - } - break; - - case STATE_decimal: // reading decimal number - if (!isdigit(c)) - { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (c == '.' && p[1] != '.') - { -#if DMDV2 - if (isalpha(p[1]) || p[1] == '_') - goto done; -#endif - goto real; - } - else if (c == 'i' || c == 'f' || c == 'F' || - c == 'e' || c == 'E') - { - real: // It's a real number. Back up and rescan as a real - p = start; - return inreal(t); - } - else if (c == 'L' && p[1] == 'i') - goto real; - goto done; - } - break; - - case STATE_hex0: // reading hex number - case STATE_hex: - if (!ishex(c)) - { - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (c == '.' && p[1] != '.') - goto real; - if (c == 'P' || c == 'p' || c == 'i') - goto real; - if (state == STATE_hex0) - error("Hex digit expected, not '%c'", c); - goto done; - } - state = STATE_hex; - break; - -#if ZEROH - hexh: - state = STATE_hexh; - case STATE_hexh: // parse numbers like 0FFh - if (!ishex(c)) - { - if (c == 'H' || c == 'h') - { - p++; - base = 16; - goto done; - } - else - { - // Check for something like 1E3 or 0E24 - if (memchr((char *)stringbuffer.data, 'E', stringbuffer.offset) || - memchr((char *)stringbuffer.data, 'e', stringbuffer.offset)) - goto real; - error("Hex digit expected, not '%c'", c); - goto done; - } - } - break; -#endif - - case STATE_octal: // reading octal number - case STATE_octale: // reading octal number with non-octal digits - if (!isoctal(c)) - { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (c == '.' && p[1] != '.') - goto real; - if (c == 'i') - goto real; - if (isdigit(c)) - { - state = STATE_octale; - } - else - goto done; - } - break; - - case STATE_binary0: // starting binary number - case STATE_binary: // reading binary number - if (c != '0' && c != '1') - { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (state == STATE_binary0) - { error("binary digit expected"); - state = STATE_error; - break; - } - else - goto done; - } - state = STATE_binary; - break; - - case STATE_error: // for error recovery - if (!isdigit(c)) // scan until non-digit - goto done; - break; - - default: - assert(0); - } - stringbuffer.writeByte(c); - p++; - } -done: - stringbuffer.writeByte(0); // terminate string - if (state == STATE_octale) - error("Octal digit expected"); - - uinteger_t n; // unsigned >=64 bit integer type - - if (stringbuffer.offset == 2 && (state == STATE_decimal || state == STATE_0)) - n = stringbuffer.data[0] - '0'; - else - { - // Convert string to integer -#if __DMC__ - errno = 0; - n = strtoull((char *)stringbuffer.data,NULL,base); - if (errno == ERANGE) - error("integer overflow"); -#else - // Not everybody implements strtoull() - char *p = (char *)stringbuffer.data; - int r = 10, d; - - if (*p == '0') - { - if (p[1] == 'x' || p[1] == 'X') - p += 2, r = 16; - else if (p[1] == 'b' || p[1] == 'B') - p += 2, r = 2; - else if (isdigit((unsigned char)p[1])) - p += 1, r = 8; - } - - n = 0; - while (1) - { - if (*p >= '0' && *p <= '9') - d = *p - '0'; - else if (*p >= 'a' && *p <= 'z') - d = *p - 'a' + 10; - else if (*p >= 'A' && *p <= 'Z') - d = *p - 'A' + 10; - else - break; - if (d >= r) - break; - uinteger_t n2 = n * r; - //printf("n2 / r = %llx, n = %llx\n", n2/r, n); - if (n2 / r != n || n2 + d < n) - { - error ("integer overflow"); - break; - } - - n = n2 + d; - p++; - } -#endif - if (sizeof(n) > 8 && - n > 0xFFFFFFFFFFFFFFFFULL) // if n needs more than 64 bits - error("integer overflow"); - } - - // Parse trailing 'u', 'U', 'l' or 'L' in any combination - const unsigned char *psuffix = p; - while (1) - { unsigned char f; - - switch (*p) - { case 'U': - case 'u': - f = FLAGS_unsigned; - goto L1; - - case 'l': - if (1 || !global.params.useDeprecated) - error("'l' suffix is deprecated, use 'L' instead"); - case 'L': - f = FLAGS_long; - L1: - p++; - if (flags & f) - error("unrecognized token"); - flags = (FLAGS) (flags | f); - continue; - default: - break; - } - break; - } - -#if DMDV2 - if (state == STATE_octal && n >= 8 && !global.params.useDeprecated) - error("octal literals 0%llo%.*s are deprecated, use std.conv.octal!%llo%.*s instead", - n, p - psuffix, psuffix, n, p - psuffix, psuffix); -#endif - - switch (flags) - { - case 0: - /* Octal or Hexadecimal constant. - * First that fits: int, uint, long, ulong - */ - if (n & 0x8000000000000000LL) - result = TOKuns64v; - else if (n & 0xFFFFFFFF00000000LL) - result = TOKint64v; - else if (n & 0x80000000) - result = TOKuns32v; - else - result = TOKint32v; - break; - - case FLAGS_decimal: - /* First that fits: int, long, long long - */ - if (n & 0x8000000000000000LL) - { error("signed integer overflow"); - result = TOKuns64v; - } - else if (n & 0xFFFFFFFF80000000LL) - result = TOKint64v; - else - result = TOKint32v; - break; - - case FLAGS_unsigned: - case FLAGS_decimal | FLAGS_unsigned: - /* First that fits: uint, ulong - */ - if (n & 0xFFFFFFFF00000000LL) - result = TOKuns64v; - else - result = TOKuns32v; - break; - - case FLAGS_decimal | FLAGS_long: - if (n & 0x8000000000000000LL) - { error("signed integer overflow"); - result = TOKuns64v; - } - else - result = TOKint64v; - break; - - case FLAGS_long: - if (n & 0x8000000000000000LL) - result = TOKuns64v; - else - result = TOKint64v; - break; - - case FLAGS_unsigned | FLAGS_long: - case FLAGS_decimal | FLAGS_unsigned | FLAGS_long: - result = TOKuns64v; - break; - - default: - #ifdef DEBUG - printf("%x\n",flags); - #endif - assert(0); - } - t->uns64value = n; - return result; -} - -/************************************** - * Read in characters, converting them to real. - * Bugs: - * Exponent overflow not detected. - * Too much requested precision is not detected. - */ - -TOK Lexer::inreal(Token *t) -#ifdef __DMC__ -__in -{ - assert(*p == '.' || isdigit(*p)); -} -__out (result) -{ - switch (result) - { - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - break; - - default: - assert(0); - } -} -__body -#endif /* __DMC__ */ -{ int dblstate; - unsigned c; - char hex; // is this a hexadecimal-floating-constant? - TOK result; - - //printf("Lexer::inreal()\n"); - stringbuffer.reset(); - dblstate = 0; - hex = 0; -Lnext: - while (1) - { - // Get next char from input - c = *p++; - //printf("dblstate = %d, c = '%c'\n", dblstate, c); - while (1) - { - switch (dblstate) - { - case 0: // opening state - if (c == '0') - dblstate = 9; - else if (c == '.') - dblstate = 3; - else - dblstate = 1; - break; - - case 9: - dblstate = 1; - if (c == 'X' || c == 'x') - { hex++; - break; - } - case 1: // digits to left of . - case 3: // digits to right of . - case 7: // continuing exponent digits - if (!isdigit(c) && !(hex && isxdigit(c))) - { - if (c == '_') - goto Lnext; // ignore embedded '_' - dblstate++; - continue; - } - break; - - case 2: // no more digits to left of . - if (c == '.') - { dblstate++; - break; - } - case 4: // no more digits to right of . - if ((c == 'E' || c == 'e') || - hex && (c == 'P' || c == 'p')) - { dblstate = 5; - hex = 0; // exponent is always decimal - break; - } - if (hex) - error("binary-exponent-part required"); - goto done; - - case 5: // looking immediately to right of E - dblstate++; - if (c == '-' || c == '+') - break; - case 6: // 1st exponent digit expected - if (!isdigit(c)) - error("exponent expected"); - dblstate++; - break; - - case 8: // past end of exponent digits - goto done; - } - break; - } - stringbuffer.writeByte(c); - } -done: - p--; - - stringbuffer.writeByte(0); - -#if _WIN32 && __DMC__ - char *save = __locale_decpoint; - __locale_decpoint = "."; -#endif -#ifdef IN_GCC - t->float80value = real_t::parse((char *)stringbuffer.data, real_t::LongDouble); -#else - t->float80value = strtold((char *)stringbuffer.data, NULL); -#endif - errno = 0; - float strtofres; - double strtodres; - switch (*p) - { - case 'F': - case 'f': -#ifdef IN_GCC - real_t::parse((char *)stringbuffer.data, real_t::Float); -#else - strtofres = strtof((char *)stringbuffer.data, NULL); -#ifdef IN_LLVM -#ifdef _MSC_VER -#define HUGE_VALF HUGE_VAL -#endif - // LDC change: don't error on gradual underflow - if (errno == ERANGE && - strtofres != 0 && strtofres != HUGE_VALF && strtofres != -HUGE_VALF) - errno = 0; -#endif -#endif - result = TOKfloat32v; - p++; - break; - - default: -#ifdef IN_GCC - real_t::parse((char *)stringbuffer.data, real_t::Double); -#else - strtodres = strtod((char *)stringbuffer.data, NULL); -#if IN_LLVM - // LDC change: don't error on gradual underflow - if (errno == ERANGE && - strtodres != 0 && strtodres != HUGE_VAL && strtodres != -HUGE_VAL) - errno = 0; -#endif -#endif - result = TOKfloat64v; - break; - - case 'l': - if (!global.params.useDeprecated) - error("'l' suffix is deprecated, use 'L' instead"); - case 'L': - result = TOKfloat80v; - p++; - break; - } - if (*p == 'i' || *p == 'I') - { - if (!global.params.useDeprecated && *p == 'I') - error("'I' suffix is deprecated, use 'i' instead"); - p++; - switch (result) - { - case TOKfloat32v: - result = TOKimaginary32v; - break; - case TOKfloat64v: - result = TOKimaginary64v; - break; - case TOKfloat80v: - result = TOKimaginary80v; - break; - } - } -#if _WIN32 && __DMC__ - __locale_decpoint = save; -#endif - if (errno == ERANGE) - error("number is not representable"); - return result; -} - -/********************************************* - * Do pragma. - * Currently, the only pragma supported is: - * #line linnum [filespec] - */ - -void Lexer::pragma() -{ - Token tok; - int linnum; - char *filespec = NULL; - Loc loc = this->loc; - - scan(&tok); - if (tok.value != TOKidentifier || tok.ident != Id::line) - goto Lerr; - - scan(&tok); - if (tok.value == TOKint32v || tok.value == TOKint64v) - { linnum = tok.uns64value - 1; - if (linnum != tok.uns64value - 1) - error("line number out of range"); - } - else - goto Lerr; - - while (1) - { - switch (*p) - { - case 0: - case 0x1A: - case '\n': - Lnewline: - this->loc.linnum = linnum; - if (filespec) - this->loc.filename = filespec; - return; - - case '\r': - p++; - if (*p != '\n') - { p--; - goto Lnewline; - } - continue; - - case ' ': - case '\t': - case '\v': - case '\f': - p++; - continue; // skip white space - - case '_': - if (mod && memcmp(p, "__FILE__", 8) == 0) - { - p += 8; - filespec = mem.strdup(loc.filename ? loc.filename : mod->ident->toChars()); - continue; - } - goto Lerr; - - case '"': - if (filespec) - goto Lerr; - stringbuffer.reset(); - p++; - while (1) - { unsigned c; - - c = *p; - switch (c) - { - case '\n': - case '\r': - case 0: - case 0x1A: - goto Lerr; - - case '"': - stringbuffer.writeByte(0); - filespec = mem.strdup((char *)stringbuffer.data); - p++; - break; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - goto Lerr; - } - stringbuffer.writeByte(c); - p++; - continue; - } - break; - } - continue; - - default: - if (*p & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - goto Lnewline; - } - goto Lerr; - } - } - -Lerr: - error(loc, "#line integer [\"filespec\"]\\n expected"); -} - - -/******************************************** - * Decode UTF character. - * Issue error messages for invalid sequences. - * Return decoded character, advance p to last character in UTF sequence. - */ - -unsigned Lexer::decodeUTF() -{ - dchar_t u; - unsigned char c; - unsigned char *s = p; - size_t len; - size_t idx; - const char *msg; - - c = *s; - assert(c & 0x80); - - // Check length of remaining string up to 6 UTF-8 characters - for (len = 1; len < 6 && s[len]; len++) - ; - - idx = 0; - msg = utf_decodeChar(s, len, &idx, &u); - p += idx - 1; - if (msg) - { - error("%s", msg); - } - return u; -} - - -/*************************************************** - * Parse doc comment embedded between t->ptr and p. - * Remove trailing blanks and tabs from lines. - * Replace all newlines with \n. - * Remove leading comment character from each line. - * Decide if it's a lineComment or a blockComment. - * Append to previous one for this token. - */ - -void Lexer::getDocComment(Token *t, unsigned lineComment) -{ - /* ct tells us which kind of comment it is: '/', '*', or '+' - */ - unsigned char ct = t->ptr[2]; - - /* Start of comment text skips over / * *, / + +, or / / / - */ - unsigned char *q = t->ptr + 3; // start of comment text - - unsigned char *qend = p; - if (ct == '*' || ct == '+') - qend -= 2; - - /* Scan over initial row of ****'s or ++++'s or ////'s - */ - for (; q < qend; q++) - { - if (*q != ct) - break; - } - - /* Remove trailing row of ****'s or ++++'s - */ - if (ct != '/') - { - for (; q < qend; qend--) - { - if (qend[-1] != ct) - break; - } - } - - /* Comment is now [q .. qend]. - * Canonicalize it into buf[]. - */ - OutBuffer buf; - int linestart = 0; - - for (; q < qend; q++) - { - unsigned char c = *q; - - switch (c) - { - case '*': - case '+': - if (linestart && c == ct) - { linestart = 0; - /* Trim preceding whitespace up to preceding \n - */ - while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t')) - buf.offset--; - continue; - } - break; - - case ' ': - case '\t': - break; - - case '\r': - if (q[1] == '\n') - continue; // skip the \r - goto Lnewline; - - default: - if (c == 226) - { - // If LS or PS - if (q[1] == 128 && - (q[2] == 168 || q[2] == 169)) - { - q += 2; - goto Lnewline; - } - } - linestart = 0; - break; - - Lnewline: - c = '\n'; // replace all newlines with \n - case '\n': - linestart = 1; - - /* Trim trailing whitespace - */ - while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t')) - buf.offset--; - - break; - } - buf.writeByte(c); - } - - // Always end with a newline - if (!buf.offset || buf.data[buf.offset - 1] != '\n') - buf.writeByte('\n'); - - buf.writeByte(0); - - // It's a line comment if the start of the doc comment comes - // after other non-whitespace on the same line. - unsigned char** dc = (lineComment && anyToken) - ? &t->lineComment - : &t->blockComment; - - // Combine with previous doc comment, if any - if (*dc) - *dc = combineComments(*dc, (unsigned char *)buf.data); - else - *dc = (unsigned char *)buf.extractData(); -} - -/******************************************** - * Combine two document comments into one, - * separated by a newline. - */ - -unsigned char *Lexer::combineComments(unsigned char *c1, unsigned char *c2) -{ - //printf("Lexer::combineComments('%s', '%s')\n", c1, c2); - - unsigned char *c = c2; - - if (c1) - { c = c1; - if (c2) - { size_t len1 = strlen((char *)c1); - size_t len2 = strlen((char *)c2); - - c = (unsigned char *)mem.malloc(len1 + 1 + len2 + 1); - memcpy(c, c1, len1); - if (len1 && c1[len1 - 1] != '\n') - { c[len1] = '\n'; - len1++; - } - memcpy(c + len1, c2, len2); - c[len1 + len2] = 0; - } - } - return c; -} - -/******************************************* - * Search actual location of current token - * even when infinite look-ahead was done. - */ -Loc Lexer::tokenLoc() -{ - Loc result = this->loc; - Token* last = &token; - while (last->next) - last = last->next; - - unsigned char* start = token.ptr; - unsigned char* stop = last->ptr; - - for (unsigned char* p = start; p < stop; ++p) - { - switch (*p) - { - case '\n': - result.linnum--; - break; - case '\r': - if (p[1] != '\n') - result.linnum--; - break; - default: - break; - } - } - return result; -} - -/******************************************** - * Create an identifier in the string table. - */ - -Identifier *Lexer::idPool(const char *s) -{ - size_t len = strlen(s); - StringValue *sv = stringtable.update(s, len); - Identifier *id = (Identifier *) sv->ptrvalue; - if (!id) - { - id = new Identifier(sv->toDchars(), TOKidentifier); - sv->ptrvalue = id; - } - return id; -} - -/********************************************* - * Create a unique identifier using the prefix s. - */ - -Identifier *Lexer::uniqueId(const char *s, int num) -{ char buffer[32]; - size_t slen = strlen(s); - - assert(slen + sizeof(num) * 3 + 1 <= sizeof(buffer)); - sprintf(buffer, "%s%d", s, num); - return idPool(buffer); -} - -Identifier *Lexer::uniqueId(const char *s) -{ - static int num; - return uniqueId(s, ++num); -} - -/**************************************** - */ - -struct Keyword -{ const char *name; - enum TOK value; -}; - -static Keyword keywords[] = -{ -// { "", TOK }, - - { "this", TOKthis }, - { "super", TOKsuper }, - { "assert", TOKassert }, - { "null", TOKnull }, - { "true", TOKtrue }, - { "false", TOKfalse }, - { "cast", TOKcast }, - { "new", TOKnew }, - { "delete", TOKdelete }, - { "throw", TOKthrow }, - { "module", TOKmodule }, - { "pragma", TOKpragma }, - { "typeof", TOKtypeof }, - { "typeid", TOKtypeid }, - - { "template", TOKtemplate }, - - { "void", TOKvoid }, - { "byte", TOKint8 }, - { "ubyte", TOKuns8 }, - { "short", TOKint16 }, - { "ushort", TOKuns16 }, - { "int", TOKint32 }, - { "uint", TOKuns32 }, - { "long", TOKint64 }, - { "ulong", TOKuns64 }, - { "cent", TOKcent, }, - { "ucent", TOKucent, }, - { "float", TOKfloat32 }, - { "double", TOKfloat64 }, - { "real", TOKfloat80 }, - - { "bool", TOKbool }, - { "char", TOKchar }, - { "wchar", TOKwchar }, - { "dchar", TOKdchar }, - - { "ifloat", TOKimaginary32 }, - { "idouble", TOKimaginary64 }, - { "ireal", TOKimaginary80 }, - - { "cfloat", TOKcomplex32 }, - { "cdouble", TOKcomplex64 }, - { "creal", TOKcomplex80 }, - - { "delegate", TOKdelegate }, - { "function", TOKfunction }, - - { "is", TOKis }, - { "if", TOKif }, - { "else", TOKelse }, - { "while", TOKwhile }, - { "for", TOKfor }, - { "do", TOKdo }, - { "switch", TOKswitch }, - { "case", TOKcase }, - { "default", TOKdefault }, - { "break", TOKbreak }, - { "continue", TOKcontinue }, - { "synchronized", TOKsynchronized }, - { "return", TOKreturn }, - { "goto", TOKgoto }, - { "try", TOKtry }, - { "catch", TOKcatch }, - { "finally", TOKfinally }, - { "with", TOKwith }, - { "asm", TOKasm }, - { "foreach", TOKforeach }, - { "foreach_reverse", TOKforeach_reverse }, - { "scope", TOKscope }, - - { "struct", TOKstruct }, - { "class", TOKclass }, - { "interface", TOKinterface }, - { "union", TOKunion }, - { "enum", TOKenum }, - { "import", TOKimport }, - { "mixin", TOKmixin }, - { "static", TOKstatic }, - { "final", TOKfinal }, - { "const", TOKconst }, - { "typedef", TOKtypedef }, - { "alias", TOKalias }, - { "override", TOKoverride }, - { "abstract", TOKabstract }, - { "volatile", TOKvolatile }, - { "debug", TOKdebug }, - { "deprecated", TOKdeprecated }, - { "in", TOKin }, - { "out", TOKout }, - { "inout", TOKinout }, - { "lazy", TOKlazy }, - { "auto", TOKauto }, - - { "align", TOKalign }, - { "extern", TOKextern }, - { "private", TOKprivate }, - { "package", TOKpackage }, - { "protected", TOKprotected }, - { "public", TOKpublic }, - { "export", TOKexport }, - - { "body", TOKbody }, - { "invariant", TOKinvariant }, - { "unittest", TOKunittest }, - { "version", TOKversion }, - //{ "manifest", TOKmanifest }, - - // Added after 1.0 - { "__argTypes", TOKargTypes }, - { "ref", TOKref }, - { "macro", TOKmacro }, -#if DMDV2 - { "pure", TOKpure }, - { "nothrow", TOKnothrow }, - { "__thread", TOKtls }, - { "__gshared", TOKgshared }, - { "__traits", TOKtraits }, - { "__vector", TOKvector }, - { "__overloadset", TOKoverloadset }, - { "__FILE__", TOKfile }, - { "__LINE__", TOKline }, - { "shared", TOKshared }, - { "immutable", TOKimmutable }, -#endif -}; - -int Token::isKeyword() -{ - for (unsigned u = 0; u < sizeof(keywords) / sizeof(keywords[0]); u++) - { - if (keywords[u].value == value) - return 1; - } - return 0; -} - -void Lexer::initKeywords() -{ - unsigned nkeywords = sizeof(keywords) / sizeof(keywords[0]); - - stringtable.init(6151); - - if (global.params.Dversion == 1) - nkeywords -= 2; - - cmtable_init(); - - for (unsigned u = 0; u < nkeywords; u++) - { - //printf("keyword[%d] = '%s'\n",u, keywords[u].name); - const char *s = keywords[u].name; - enum TOK v = keywords[u].value; - StringValue *sv = stringtable.insert(s, strlen(s)); - sv->ptrvalue = (void *) new Identifier(sv->toDchars(),v); - - //printf("tochars[%d] = '%s'\n",v, s); - Token::tochars[v] = s; - } - - Token::tochars[TOKeof] = "EOF"; - Token::tochars[TOKlcurly] = "{"; - Token::tochars[TOKrcurly] = "}"; - Token::tochars[TOKlparen] = "("; - Token::tochars[TOKrparen] = ")"; - Token::tochars[TOKlbracket] = "["; - Token::tochars[TOKrbracket] = "]"; - Token::tochars[TOKsemicolon] = ";"; - Token::tochars[TOKcolon] = ":"; - Token::tochars[TOKcomma] = ","; - Token::tochars[TOKdot] = "."; - Token::tochars[TOKxor] = "^"; - Token::tochars[TOKxorass] = "^="; - Token::tochars[TOKassign] = "="; - Token::tochars[TOKconstruct] = "="; -#if DMDV2 - Token::tochars[TOKblit] = "="; -#endif - Token::tochars[TOKlt] = "<"; - Token::tochars[TOKgt] = ">"; - Token::tochars[TOKle] = "<="; - Token::tochars[TOKge] = ">="; - Token::tochars[TOKequal] = "=="; - Token::tochars[TOKnotequal] = "!="; - Token::tochars[TOKnotidentity] = "!is"; - Token::tochars[TOKtobool] = "!!"; - - Token::tochars[TOKunord] = "!<>="; - Token::tochars[TOKue] = "!<>"; - Token::tochars[TOKlg] = "<>"; - Token::tochars[TOKleg] = "<>="; - Token::tochars[TOKule] = "!>"; - Token::tochars[TOKul] = "!>="; - Token::tochars[TOKuge] = "!<"; - Token::tochars[TOKug] = "!<="; - - Token::tochars[TOKnot] = "!"; - Token::tochars[TOKtobool] = "!!"; - Token::tochars[TOKshl] = "<<"; - Token::tochars[TOKshr] = ">>"; - Token::tochars[TOKushr] = ">>>"; - Token::tochars[TOKadd] = "+"; - Token::tochars[TOKmin] = "-"; - Token::tochars[TOKmul] = "*"; - Token::tochars[TOKdiv] = "/"; - Token::tochars[TOKmod] = "%"; - Token::tochars[TOKslice] = ".."; - Token::tochars[TOKdotdotdot] = "..."; - Token::tochars[TOKand] = "&"; - Token::tochars[TOKandand] = "&&"; - Token::tochars[TOKor] = "|"; - Token::tochars[TOKoror] = "||"; - Token::tochars[TOKarray] = "[]"; - Token::tochars[TOKindex] = "[i]"; - Token::tochars[TOKaddress] = "&"; - Token::tochars[TOKstar] = "*"; - Token::tochars[TOKtilde] = "~"; - Token::tochars[TOKdollar] = "$"; - Token::tochars[TOKcast] = "cast"; - Token::tochars[TOKplusplus] = "++"; - Token::tochars[TOKminusminus] = "--"; - Token::tochars[TOKpreplusplus] = "++"; - Token::tochars[TOKpreminusminus] = "--"; - Token::tochars[TOKtype] = "type"; - Token::tochars[TOKquestion] = "?"; - Token::tochars[TOKneg] = "-"; - Token::tochars[TOKuadd] = "+"; - Token::tochars[TOKvar] = "var"; - Token::tochars[TOKaddass] = "+="; - Token::tochars[TOKminass] = "-="; - Token::tochars[TOKmulass] = "*="; - Token::tochars[TOKdivass] = "/="; - Token::tochars[TOKmodass] = "%="; - Token::tochars[TOKshlass] = "<<="; - Token::tochars[TOKshrass] = ">>="; - Token::tochars[TOKushrass] = ">>>="; - Token::tochars[TOKandass] = "&="; - Token::tochars[TOKorass] = "|="; - Token::tochars[TOKcatass] = "~="; - Token::tochars[TOKcat] = "~"; - Token::tochars[TOKcall] = "call"; - Token::tochars[TOKidentity] = "is"; - Token::tochars[TOKnotidentity] = "!is"; - - Token::tochars[TOKorass] = "|="; - Token::tochars[TOKidentifier] = "identifier"; -#if DMDV2 - Token::tochars[TOKat] = "@"; - Token::tochars[TOKpow] = "^^"; - Token::tochars[TOKpowass] = "^^="; - Token::tochars[TOKgoesto] = "=>"; - Token::tochars[TOKpound] = "#"; -#endif - - // For debugging - Token::tochars[TOKerror] = "error"; - Token::tochars[TOKdotexp] = "dotexp"; - Token::tochars[TOKdotti] = "dotti"; - Token::tochars[TOKdotvar] = "dotvar"; - Token::tochars[TOKdottype] = "dottype"; - Token::tochars[TOKsymoff] = "symoff"; - Token::tochars[TOKarraylength] = "arraylength"; - Token::tochars[TOKarrayliteral] = "arrayliteral"; - Token::tochars[TOKassocarrayliteral] = "assocarrayliteral"; - Token::tochars[TOKstructliteral] = "structliteral"; - Token::tochars[TOKstring] = "string"; - Token::tochars[TOKdsymbol] = "symbol"; - Token::tochars[TOKtuple] = "tuple"; - Token::tochars[TOKdeclaration] = "declaration"; - Token::tochars[TOKdottd] = "dottd"; - Token::tochars[TOKon_scope_exit] = "scope(exit)"; - Token::tochars[TOKon_scope_success] = "scope(success)"; - Token::tochars[TOKon_scope_failure] = "scope(failure)"; - -#if UNITTEST - unittest_lexer(); -#endif -} - -#if UNITTEST - -void unittest_lexer() -{ - //printf("unittest_lexer()\n"); - - /* Not much here, just trying things out. - */ - const unsigned char text[] = "int"; - Lexer lex1(NULL, (unsigned char *)text, 0, sizeof(text), 0, 0); - TOK tok; - tok = lex1.nextToken(); - //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOKint32); - assert(tok == TOKint32); - tok = lex1.nextToken(); - assert(tok == TOKeof); - tok = lex1.nextToken(); - assert(tok == TOKeof); -} - -#endif diff --git a/dmd/lexer.h b/dmd/lexer.h deleted file mode 100644 index b8b51d7a..00000000 --- a/dmd/lexer.h +++ /dev/null @@ -1,321 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_LEXER_H -#define DMD_LEXER_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "mars.h" - -struct StringTable; -struct Identifier; -struct Module; - -/* Tokens: - ( ) - [ ] - { } - < > <= >= == != === !== - << >> <<= >>= >>> >>>= - + - += -= - * / % *= /= %= - & | ^ &= |= ^= - = ! ~ @ - ^^ ^^= - ++ -- - . -> : , - ? && || - */ - -enum TOK -{ - TOKreserved, - - // Other - TOKlparen, TOKrparen, - TOKlbracket, TOKrbracket, - TOKlcurly, TOKrcurly, - TOKcolon, TOKneg, - TOKsemicolon, TOKdotdotdot, - TOKeof, TOKcast, - TOKnull, TOKassert, - TOKtrue, TOKfalse, - TOKarray, TOKcall, - TOKaddress, - TOKtype, TOKthrow, - TOKnew, TOKdelete, - TOKstar, TOKsymoff, - TOKvar, TOKdotvar, - TOKdotti, TOKdotexp, - TOKdottype, TOKslice, - TOKarraylength, TOKversion, - TOKmodule, TOKdollar, - TOKtemplate, TOKdottd, - TOKdeclaration, TOKtypeof, - TOKpragma, TOKdsymbol, - TOKtypeid, TOKuadd, - TOKremove, - TOKnewanonclass, TOKcomment, - TOKarrayliteral, TOKassocarrayliteral, - TOKstructliteral, - - // Operators - TOKlt, TOKgt, - TOKle, TOKge, - TOKequal, TOKnotequal, - TOKidentity, TOKnotidentity, - TOKindex, TOKis, - TOKtobool, - -// 60 - // NCEG floating point compares - // !<>= <> <>= !> !>= !< !<= !<> - TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue, - - TOKshl, TOKshr, - TOKshlass, TOKshrass, - TOKushr, TOKushrass, - TOKcat, TOKcatass, // ~ ~= - TOKadd, TOKmin, TOKaddass, TOKminass, - TOKmul, TOKdiv, TOKmod, - TOKmulass, TOKdivass, TOKmodass, - TOKand, TOKor, TOKxor, - TOKandass, TOKorass, TOKxorass, - TOKassign, TOKnot, TOKtilde, - TOKplusplus, TOKminusminus, TOKconstruct, TOKblit, - TOKdot, TOKarrow, TOKcomma, - TOKquestion, TOKandand, TOKoror, - TOKpreplusplus, TOKpreminusminus, - -// 106 - // Numeric literals - TOKint32v, TOKuns32v, - TOKint64v, TOKuns64v, - TOKfloat32v, TOKfloat64v, TOKfloat80v, - TOKimaginary32v, TOKimaginary64v, TOKimaginary80v, - - // Char constants - TOKcharv, TOKwcharv, TOKdcharv, - - // Leaf operators - TOKidentifier, TOKstring, - TOKthis, TOKsuper, - TOKhalt, TOKtuple, - TOKerror, - - // Basic types - TOKvoid, - TOKint8, TOKuns8, - TOKint16, TOKuns16, - TOKint32, TOKuns32, - TOKint64, TOKuns64, - TOKfloat32, TOKfloat64, TOKfloat80, - TOKimaginary32, TOKimaginary64, TOKimaginary80, - TOKcomplex32, TOKcomplex64, TOKcomplex80, - TOKchar, TOKwchar, TOKdchar, TOKbit, TOKbool, - TOKcent, TOKucent, - -// 152 - // Aggregates - TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport, - TOKtypedef, TOKalias, TOKoverride, TOKdelegate, TOKfunction, - TOKmixin, - - TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport, - TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile, - TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy, - TOKauto, TOKpackage, TOKmanifest, TOKimmutable, - - // Statements - TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch, - TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith, - TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally, - TOKasm, TOKforeach, TOKforeach_reverse, - TOKscope, - TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success, - - // Contracts - TOKbody, TOKinvariant, - - // Testing - TOKunittest, - - // Added after 1.0 - TOKargTypes, - TOKref, - TOKmacro, - TOKat, -#if DMDV2 - TOKtraits, - TOKoverloadset, - TOKpure, - TOKnothrow, - TOKtls, - TOKgshared, - TOKline, - TOKfile, - TOKshared, - TOKpow, - TOKpowass, - TOKgoesto, - TOKvector, - TOKpound, -#endif - -// LDC specific -#if IN_LLVM - TOKgep, -#endif - - TOKMAX -}; - -#define TOKwild TOKinout - -#define BASIC_TYPES \ - TOKwchar: case TOKdchar: \ - case TOKbit: case TOKbool: case TOKchar: \ - case TOKint8: case TOKuns8: \ - case TOKint16: case TOKuns16: \ - case TOKint32: case TOKuns32: \ - case TOKint64: case TOKuns64: \ - case TOKfloat32: case TOKfloat64: case TOKfloat80: \ - case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: \ - case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: \ - case TOKvoid - -#define BASIC_TYPES_X(t) \ - TOKvoid: t = Type::tvoid; goto LabelX; \ - case TOKint8: t = Type::tint8; goto LabelX; \ - case TOKuns8: t = Type::tuns8; goto LabelX; \ - case TOKint16: t = Type::tint16; goto LabelX; \ - case TOKuns16: t = Type::tuns16; goto LabelX; \ - case TOKint32: t = Type::tint32; goto LabelX; \ - case TOKuns32: t = Type::tuns32; goto LabelX; \ - case TOKint64: t = Type::tint64; goto LabelX; \ - case TOKuns64: t = Type::tuns64; goto LabelX; \ - case TOKfloat32: t = Type::tfloat32; goto LabelX; \ - case TOKfloat64: t = Type::tfloat64; goto LabelX; \ - case TOKfloat80: t = Type::tfloat80; goto LabelX; \ - case TOKimaginary32: t = Type::timaginary32; goto LabelX; \ - case TOKimaginary64: t = Type::timaginary64; goto LabelX; \ - case TOKimaginary80: t = Type::timaginary80; goto LabelX; \ - case TOKcomplex32: t = Type::tcomplex32; goto LabelX; \ - case TOKcomplex64: t = Type::tcomplex64; goto LabelX; \ - case TOKcomplex80: t = Type::tcomplex80; goto LabelX; \ - case TOKbool: t = Type::tbool; goto LabelX; \ - case TOKchar: t = Type::tchar; goto LabelX; \ - case TOKwchar: t = Type::twchar; goto LabelX; \ - case TOKdchar: t = Type::tdchar; goto LabelX; \ - LabelX - -struct Token -{ - Token *next; - unsigned char *ptr; // pointer to first character of this token within buffer - enum TOK value; - unsigned char *blockComment; // doc comment string prior to this token - unsigned char *lineComment; // doc comment for previous token - union - { - // Integers - d_int64 int64value; - d_uns64 uns64value; - - // Floats -#ifdef IN_GCC - // real_t float80value; // can't use this in a union! -#else - d_float80 float80value; -#endif - - struct - { unsigned char *ustring; // UTF8 string - unsigned len; - unsigned char postfix; // 'c', 'w', 'd' - }; - - Identifier *ident; - }; -#ifdef IN_GCC - real_t float80value; // can't use this in a union! -#endif - - static const char *tochars[TOKMAX]; - static void *operator new(size_t sz); - - int isKeyword(); - void print(); - const char *toChars(); - static const char *toChars(enum TOK); -}; - -struct Lexer -{ - static StringTable stringtable; - static OutBuffer stringbuffer; - static Token *freelist; - - Loc loc; // for error messages - - unsigned char *base; // pointer to start of buffer - unsigned char *end; // past end of buffer - unsigned char *p; // current character - Token token; - Module *mod; - int doDocComment; // collect doc comment information - int anyToken; // !=0 means seen at least one token - int commentToken; // !=0 means comments are TOKcomment's - - Lexer(Module *mod, - unsigned char *base, unsigned begoffset, unsigned endoffset, - int doDocComment, int commentToken); - - static void initKeywords(); - static Identifier *idPool(const char *s); - static Identifier *uniqueId(const char *s); - static Identifier *uniqueId(const char *s, int num); - - TOK nextToken(); - TOK peekNext(); - TOK peekNext2(); - void scan(Token *t); - Token *peek(Token *t); - Token *peekPastParen(Token *t); - unsigned escapeSequence(); - TOK wysiwygStringConstant(Token *t, int tc); - TOK hexStringConstant(Token *t); -#if DMDV2 - TOK delimitedStringConstant(Token *t); - TOK tokenStringConstant(Token *t); -#endif - TOK escapeStringConstant(Token *t, int wide); - TOK charConstant(Token *t, int wide); - void stringPostfix(Token *t); - unsigned wchar(unsigned u); - TOK number(Token *t); - TOK inreal(Token *t); - void error(const char *format, ...) IS_PRINTF(2); - void error(Loc loc, const char *format, ...) IS_PRINTF(3); - void pragma(); - unsigned decodeUTF(); - void getDocComment(Token *t, unsigned lineComment); - - static int isValidIdentifier(char *p); - static unsigned char *combineComments(unsigned char *c1, unsigned char *c2); - - Loc tokenLoc(); -}; - -#endif /* DMD_LEXER_H */ diff --git a/dmd/macro.c b/dmd/macro.c deleted file mode 100644 index 398ba77f..00000000 --- a/dmd/macro.c +++ /dev/null @@ -1,449 +0,0 @@ - -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -/* Simple macro text processor. - */ - -#include -#include -#include -#include -#include - -#include "rmem.h" -#include "root.h" - -#include "macro.h" - -#define isidstart(c) (isalpha(c) || (c) == '_') -#define isidchar(c) (isalnum(c) || (c) == '_') - -unsigned char *memdup(unsigned char *p, size_t len) -{ - return (unsigned char *)memcpy(mem.malloc(len), p, len); -} - -Macro::Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen) -{ - next = NULL; - -#if 1 - this->name = name; - this->namelen = namelen; - - this->text = text; - this->textlen = textlen; -#else - this->name = name; - this->namelen = namelen; - - this->text = text; - this->textlen = textlen; -#endif - inuse = 0; -} - - -Macro *Macro::search(unsigned char *name, size_t namelen) -{ Macro *table; - - //printf("Macro::search(%.*s)\n", namelen, name); - for (table = this; table; table = table->next) - { - if (table->namelen == namelen && - memcmp(table->name, name, namelen) == 0) - { - //printf("\tfound %d\n", table->textlen); - break; - } - } - return table; -} - -Macro *Macro::define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen) -{ - //printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text); - - Macro *table; - - //assert(ptable); - for (table = *ptable; table; table = table->next) - { - if (table->namelen == namelen && - memcmp(table->name, name, namelen) == 0) - { - table->text = text; - table->textlen = textlen; - return table; - } - } - table = new Macro(name, namelen, text, textlen); - table->next = *ptable; - *ptable = table; - return table; -} - -/********************************************************** - * Given buffer p[0..end], extract argument marg[0..marglen]. - * Params: - * n 0: get entire argument - * 1..9: get nth argument - * -1: get 2nd through end - */ - -unsigned extractArgN(unsigned char *p, unsigned end, unsigned char **pmarg, unsigned *pmarglen, int n) -{ - /* Scan forward for matching right parenthesis. - * Nest parentheses. - * Skip over $( and $) - * Skip over "..." and '...' strings inside HTML tags. - * Skip over comments. - * Skip over previous macro insertions - * Set marglen. - */ - unsigned parens = 1; - unsigned char instring = 0; - unsigned incomment = 0; - unsigned intag = 0; - unsigned inexp = 0; - unsigned argn = 0; - - unsigned v = 0; - - Largstart: -#if 1 - // Skip first space, if any, to find the start of the macro argument - if (v < end && isspace(p[v])) - v++; -#else - // Skip past spaces to find the start of the macro argument - for (; v < end && isspace(p[v]); v++) - ; -#endif - *pmarg = p + v; - - for (; v < end; v++) - { unsigned char c = p[v]; - - switch (c) - { - case ',': - if (!inexp && !instring && !incomment && parens == 1) - { - argn++; - if (argn == 1 && n == -1) - { v++; - goto Largstart; - } - if (argn == n) - break; - if (argn + 1 == n) - { v++; - goto Largstart; - } - } - continue; - - case '(': - if (!inexp && !instring && !incomment) - parens++; - continue; - - case ')': - if (!inexp && !instring && !incomment && --parens == 0) - { - break; - } - continue; - - case '"': - case '\'': - if (!inexp && !incomment && intag) - { - if (c == instring) - instring = 0; - else if (!instring) - instring = c; - } - continue; - - case '<': - if (!inexp && !instring && !incomment) - { - if (v + 6 < end && - p[v + 1] == '!' && - p[v + 2] == '-' && - p[v + 3] == '-') - { - incomment = 1; - v += 3; - } - else if (v + 2 < end && - isalpha(p[v + 1])) - intag = 1; - } - continue; - - case '>': - if (!inexp) - intag = 0; - continue; - - case '-': - if (!inexp && - !instring && - incomment && - v + 2 < end && - p[v + 1] == '-' && - p[v + 2] == '>') - { - incomment = 0; - v += 2; - } - continue; - - case 0xFF: - if (v + 1 < end) - { - if (p[v + 1] == '{') - inexp++; - else if (p[v + 1] == '}') - inexp--; - } - continue; - - default: - continue; - } - break; - } - if (argn == 0 && n == -1) - *pmarg = p + v; - *pmarglen = p + v - *pmarg; - //printf("extractArg%d('%.*s') = '%.*s'\n", n, end, p, *pmarglen, *pmarg); - return v; -} - - -/***************************************************** - * Expand macro in place in buf. - * Only look at the text in buf from start to end. - */ - -void Macro::expand(OutBuffer *buf, unsigned start, unsigned *pend, - unsigned char *arg, unsigned arglen) -{ -#if 0 - printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, *pend, arglen, arg); - printf("Buf is: '%.*s'\n", *pend - start, buf->data + start); -#endif - - static int nest; - if (nest > 100) // limit recursive expansion - return; - nest++; - - unsigned end = *pend; - assert(start <= end); - assert(end <= buf->offset); - - /* First pass - replace $0 - */ - arg = memdup(arg, arglen); - for (unsigned u = start; u + 1 < end; ) - { - unsigned char *p = buf->data; // buf->data is not loop invariant - - /* Look for $0, but not $$0, and replace it with arg. - */ - if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+')) - { - if (u > start && p[u - 1] == '$') - { // Don't expand $$0, but replace it with $0 - buf->remove(u - 1, 1); - end--; - u += 1; // now u is one past the closing '1' - continue; - } - - unsigned char c = p[u + 1]; - int n = (c == '+') ? -1 : c - '0'; - - unsigned char *marg; - unsigned marglen; - extractArgN(arg, arglen, &marg, &marglen, n); - if (marglen == 0) - { // Just remove macro invocation - //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg); - buf->remove(u, 2); - end -= 2; - } - else if (c == '+') - { - // Replace '$+' with 'arg' - //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg); - buf->remove(u, 2); - buf->insert(u, marg, marglen); - end += marglen - 2; - - // Scan replaced text for further expansion - unsigned mend = u + marglen; - expand(buf, u, &mend, NULL, 0); - end += mend - (u + marglen); - u = mend; - } - else - { - // Replace '$1' with '\xFF{arg\xFF}' - //printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], marglen, marg); - buf->data[u] = 0xFF; - buf->data[u + 1] = '{'; - buf->insert(u + 2, marg, marglen); - buf->insert(u + 2 + marglen, "\xFF}", 2); - end += -2 + 2 + marglen + 2; - - // Scan replaced text for further expansion - unsigned mend = u + 2 + marglen; - expand(buf, u + 2, &mend, NULL, 0); - end += mend - (u + 2 + marglen); - u = mend; - } - //printf("u = %d, end = %d\n", u, end); - //printf("#%.*s#\n", end, &buf->data[0]); - continue; - } - - u++; - } - - /* Second pass - replace other macros - */ - for (unsigned u = start; u + 4 < end; ) - { - unsigned char *p = buf->data; // buf->data is not loop invariant - - /* A valid start of macro expansion is $(c, where c is - * an id start character, and not $$(c. - */ - if (p[u] == '$' && p[u + 1] == '(' && isidstart(p[u + 2])) - { - //printf("\tfound macro start '%c'\n", p[u + 2]); - unsigned char *name = p + u + 2; - unsigned namelen = 0; - - unsigned char *marg; - unsigned marglen; - - unsigned v; - /* Scan forward to find end of macro name and - * beginning of macro argument (marg). - */ - for (v = u + 2; v < end; v++) - { unsigned char c = p[v]; - - if (!isidchar(c)) - { // We've gone past the end of the macro name. - namelen = v - (u + 2); - break; - } - } - - v += extractArgN(p + v, end - v, &marg, &marglen, 0); - assert(v <= end); - - if (v < end) - { // v is on the closing ')' - if (u > start && p[u - 1] == '$') - { // Don't expand $$(NAME), but replace it with $(NAME) - buf->remove(u - 1, 1); - end--; - u = v; // now u is one past the closing ')' - continue; - } - - Macro *m = search(name, namelen); - if (m) - { -#if 0 - if (m->textlen && m->text[0] == ' ') - { m->text++; - m->textlen--; - } -#endif - if (m->inuse && marglen == 0) - { // Remove macro invocation - buf->remove(u, v + 1 - u); - end -= v + 1 - u; - } - else if (m->inuse && arglen == marglen && memcmp(arg, marg, arglen) == 0) - { // Recursive expansion; just leave in place - - } - else - { - //printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", m->namelen, m->name, marglen, marg, m->textlen, m->text); -#if 1 - marg = memdup(marg, marglen); - // Insert replacement text - buf->spread(v + 1, 2 + m->textlen + 2); - buf->data[v + 1] = 0xFF; - buf->data[v + 2] = '{'; - memcpy(buf->data + v + 3, m->text, m->textlen); - buf->data[v + 3 + m->textlen] = 0xFF; - buf->data[v + 3 + m->textlen + 1] = '}'; - - end += 2 + m->textlen + 2; - - // Scan replaced text for further expansion - m->inuse++; - unsigned mend = v + 1 + 2+m->textlen+2; - expand(buf, v + 1, &mend, marg, marglen); - end += mend - (v + 1 + 2+m->textlen+2); - m->inuse--; - - buf->remove(u, v + 1 - u); - end -= v + 1 - u; - u += mend - (v + 1); -#else - // Insert replacement text - buf->insert(v + 1, m->text, m->textlen); - end += m->textlen; - - // Scan replaced text for further expansion - m->inuse++; - unsigned mend = v + 1 + m->textlen; - expand(buf, v + 1, &mend, marg, marglen); - end += mend - (v + 1 + m->textlen); - m->inuse--; - - buf->remove(u, v + 1 - u); - end -= v + 1 - u; - u += mend - (v + 1); -#endif - mem.free(marg); - //printf("u = %d, end = %d\n", u, end); - //printf("#%.*s#\n", end - u, &buf->data[u]); - continue; - } - } - else - { - // Replace $(NAME) with nothing - buf->remove(u, v + 1 - u); - end -= (v + 1 - u); - continue; - } - } - } - u++; - } - mem.free(arg); - *pend = end; - nest--; -} diff --git a/dmd/macro.h b/dmd/macro.h deleted file mode 100644 index 7c939621..00000000 --- a/dmd/macro.h +++ /dev/null @@ -1,45 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_MACRO_H -#define DMD_MACRO_H 1 - -#include -#include -#include -#include - -#include "root.h" - - -struct Macro -{ - private: - Macro *next; // next in list - - unsigned char *name; // macro name - size_t namelen; // length of macro name - - unsigned char *text; // macro replacement text - size_t textlen; // length of replacement text - - int inuse; // macro is in use (don't expand) - - Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen); - Macro *search(unsigned char *name, size_t namelen); - - public: - static Macro *define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen); - - void expand(OutBuffer *buf, unsigned start, unsigned *pend, - unsigned char *arg, unsigned arglen); -}; - -#endif diff --git a/dmd/mangle.c b/dmd/mangle.c deleted file mode 100644 index bd089803..00000000 --- a/dmd/mangle.c +++ /dev/null @@ -1,300 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include - -#include "root.h" - -#include "init.h" -#include "declaration.h" -#include "aggregate.h" -#include "mtype.h" -#include "attrib.h" -#include "template.h" -#include "id.h" -#include "module.h" - -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -char *cpp_mangle(Dsymbol *s); -#endif - -char *mangle(Declaration *sthis) -{ - OutBuffer buf; - char *id; - Dsymbol *s; - - //printf("::mangle(%s), type %s\n", sthis->toChars(), sthis->type->toChars()); - s = sthis; - do - { - //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); - if (s->ident) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (s != sthis && fd) - { - id = mangle(fd); - buf.prependstring(id); - goto L1; - } - else - { - id = s->ident->toChars(); - int len = strlen(id); - char tmp[sizeof(len) * 3 + 1]; - buf.prependstring(id); - sprintf(tmp, "%d", len); - buf.prependstring(tmp); - } - } - else - buf.prependstring("0"); - s = s->parent; - } while (s); - -// buf.prependstring("_D"); -L1: - //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); - //printf("sthis->type = %s\n", sthis->type->toChars()); - FuncDeclaration *fd = sthis->isFuncDeclaration(); - if (fd && (fd->needThis() || fd->isNested())) - buf.writeByte(Type::needThisPrefix()); - if (sthis->type->deco) - buf.writestring(sthis->type->deco); - else - { -#ifdef DEBUG - if (!fd->inferRetType) - printf("%s\n", fd->toChars()); -#endif - assert(fd && fd->inferRetType); - } - - id = buf.toChars(); - buf.data = NULL; - return id; -} - -char *Declaration::mangle() -#if __DMC__ - __out(result) - { - int len = strlen(result); - - assert(len > 0); - //printf("mangle: '%s' => '%s'\n", toChars(), result); - for (int i = 0; i < len; i++) - { - assert(result[i] == '_' || - result[i] == '@' || - isalnum(result[i]) || result[i] & 0x80); - } - } - __body -#endif - { - //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", this, toChars(), parent ? parent->toChars() : "null", linkage); - if (!parent || parent->isModule()) // if at global scope - { - // If it's not a D declaration, no mangling - switch (linkage) - { - case LINKd: - break; - -#if IN_LLVM - case LINKintrinsic: -#endif - case LINKc: - case LINKwindows: - case LINKpascal: - return ident->toChars(); - - case LINKcpp: -#if DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS) - return cpp_mangle(this); -#else - // Windows C++ mangling is done by C++ back end - return ident->toChars(); -#endif - - case LINKdefault: - error("forward declaration"); - return ident->toChars(); - - default: - fprintf(stdmsg, "'%s', linkage = %d\n", toChars(), linkage); - assert(0); - } - } - char *p = ::mangle(this); - OutBuffer buf; - buf.writestring("_D"); - buf.writestring(p); - p = buf.toChars(); - buf.data = NULL; - //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d) = %s\n", this, toChars(), parent ? parent->toChars() : "null", linkage, p); - return p; - } - -char *FuncDeclaration::mangle() -#if __DMC__ - __out(result) - { - assert(strlen(result) > 0); - } - __body -#endif - { - if (isMain()) - return (char *)"_Dmain"; - - if (isWinMain() || isDllMain()) - return ident->toChars(); - - assert(this); - return Declaration::mangle(); - } - -char *StructDeclaration::mangle() -{ - //printf("StructDeclaration::mangle() '%s'\n", toChars()); - return Dsymbol::mangle(); -} - - -char *TypedefDeclaration::mangle() -{ - //printf("TypedefDeclaration::mangle() '%s'\n", toChars()); - return Dsymbol::mangle(); -} - - -char *ClassDeclaration::mangle() -{ - Dsymbol *parentsave = parent; - - //printf("ClassDeclaration::mangle() %s.%s\n", parent->toChars(), toChars()); - - /* These are reserved to the compiler, so keep simple - * names for them. - */ - if (ident == Id::Exception) - { if (parent->ident == Id::object) - parent = NULL; - } - else if (ident == Id::TypeInfo || -// ident == Id::Exception || - ident == Id::TypeInfo_Struct || - ident == Id::TypeInfo_Class || - ident == Id::TypeInfo_Typedef || - ident == Id::TypeInfo_Tuple || - this == object || - this == classinfo || - this == Module::moduleinfo || - memcmp(ident->toChars(), "TypeInfo_", 9) == 0 - ) - parent = NULL; - - char *id = Dsymbol::mangle(); - parent = parentsave; - return id; -} - - -char *TemplateInstance::mangle() -{ - OutBuffer buf; - -#if 0 - printf("TemplateInstance::mangle() %s", toChars()); - if (parent) - printf(" parent = %s %s", parent->kind(), parent->toChars()); - printf("\n"); -#endif - char *id = ident ? ident->toChars() : toChars(); - if (!tempdecl) - error("is not defined"); - else - { - Dsymbol *par = isnested || isTemplateMixin() ? parent : tempdecl->parent; - if (par) - { - char *p = par->mangle(); - if (p[0] == '_' && p[1] == 'D') - p += 2; - buf.writestring(p); - } - } - buf.printf("%zu%s", strlen(id), id); - id = buf.toChars(); - buf.data = NULL; - //printf("TemplateInstance::mangle() %s = %s\n", toChars(), id); - return id; -} - - -char *TemplateMixin::mangle() -{ - OutBuffer buf; - char *id; - -#if 0 - printf("TemplateMixin::mangle() %s", toChars()); - if (parent) - printf(" parent = %s %s", parent->kind(), parent->toChars()); - printf("\n"); -#endif - id = ident ? ident->toChars() : toChars(); - if (parent) - { - char *p = parent->mangle(); - if (p[0] == '_' && p[1] == 'D') - p += 2; - buf.writestring(p); - } - buf.printf("%zu%s", strlen(id), id); - id = buf.toChars(); - buf.data = NULL; - //printf("TemplateMixin::mangle() %s = %s\n", toChars(), id); - return id; -} - -char *Dsymbol::mangle() -{ - OutBuffer buf; - char *id; - -#if 0 - printf("Dsymbol::mangle() '%s'", toChars()); - if (parent) - printf(" parent = %s %s", parent->kind(), parent->toChars()); - printf("\n"); -#endif - id = ident ? ident->toChars() : toChars(); - if (parent) - { - char *p = parent->mangle(); - if (p[0] == '_' && p[1] == 'D') - p += 2; - buf.writestring(p); - } - buf.printf("%zu%s", strlen(id), id); - id = buf.toChars(); - buf.data = NULL; - //printf("Dsymbol::mangle() %s = %s\n", toChars(), id); - return id; -} - - diff --git a/dmd/mars.c b/dmd/mars.c deleted file mode 100644 index 15c0281a..00000000 --- a/dmd/mars.c +++ /dev/null @@ -1,396 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include -#include -#if IN_LLVM -#include -#endif - -#if POSIX -#include -#endif - -#include "rmem.h" -#include "root.h" - -#include "mars.h" -#include "module.h" -#include "mtype.h" -#include "id.h" -#include "cond.h" -#include "expression.h" -#include "lexer.h" -#include "json.h" - -#if WINDOWS_SEH -#include -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); -#endif - - -int response_expand(int *pargc, char ***pargv); -void browse(const char *url); -void getenv_setargv(const char *envvar, int *pargc, char** *pargv); - -void obj_start(char *srcfile); -void obj_end(Library *library, File *objfile); - -void printCtfePerformanceStats(); - -Global global; - -Global::Global() -{ - mars_ext = "d"; - sym_ext = "d"; - hdr_ext = "di"; - doc_ext = "html"; - ddoc_ext = "ddoc"; - json_ext = "json"; - map_ext = "map"; - -// LDC - ll_ext = "ll"; - bc_ext = "bc"; - s_ext = "s"; - obj_ext = "o"; - obj_ext_alt = "obj"; - - copyright = "Copyright (c) 1999-2012 by Digital Mars and Tomas Lindquist Olsen"; - written = "written by Walter Bright and Tomas Lindquist Olsen"; - version = "v1.075"; - ldc_version = "trunk"; - llvm_version = "LLVM "LDC_LLVM_VERSION_STRING; - global.structalign = STRUCTALIGN_DEFAULT; - - // This should only be used as a global, so the other fields are - // automatically initialized to zero when the program is loaded. - // In particular, DO NOT zero-initialize .params here (like DMD - // does) because command-line options initialize some of those - // fields to non-zero defaults, and do so from constructors that - // may run before this one. -} - -unsigned Global::startGagging() -{ - ++gag; - return gaggedErrors; -} - -bool Global::endGagging(unsigned oldGagged) -{ - bool anyErrs = (gaggedErrors != oldGagged); - --gag; - // Restore the original state of gagged errors; set total errors - // to be original errors + new ungagged errors. - errors -= (gaggedErrors - oldGagged); - gaggedErrors = oldGagged; - return anyErrs; -} - -bool Global::isSpeculativeGagging() -{ - return gag && gag == speculativeGag; -} - - -char *Loc::toChars() const -{ - OutBuffer buf; - - if (filename) - { - buf.printf("%s", filename); - } - - if (linnum) - buf.printf("(%d)", linnum); - buf.writeByte(0); - return (char *)buf.extractData(); -} - -Loc::Loc(Module *mod, unsigned linnum) -{ - this->linnum = linnum; - this->filename = mod ? mod->srcfile->toChars() : NULL; -} - -bool Loc::equals(const Loc& loc) -{ - return linnum == loc.linnum && FileName::equals(filename, loc.filename); -} - -/************************************** - * Print error message - */ - -void error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end( ap ); -} - -void warning(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - vwarning(loc, format, ap); - va_end( ap ); -} - -/************************************** - * Print supplementary message about the last error - * Used for backtraces, etc - */ -void errorSupplemental(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verrorSupplemental(loc, format, ap); - va_end( ap ); -} - -void verror(Loc loc, const char *format, va_list ap, const char *p1, const char *p2) -{ - if (!global.gag) - { - char *p = loc.toChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Error: "); - if (p1) - fprintf(stdmsg, "%s ", p1); - if (p2) - fprintf(stdmsg, "%s ", p2); -#if _MSC_VER - // MS doesn't recognize %zu format - OutBuffer tmp; - tmp.vprintf(format, ap); - fprintf(stdmsg, "%s", tmp.toChars()); -#else - vfprintf(stdmsg, format, ap); -#endif - fprintf(stdmsg, "\n"); - fflush(stdmsg); - if (global.errors >= 20) // moderate blizzard of cascading messages - fatal(); -//halt(); - } - else - { - global.gaggedErrors++; - } - global.errors++; -} - -// Doesn't increase error count, doesn't print "Error:". -void verrorSupplemental(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - { - fprintf(stdmsg, "%s: ", loc.toChars()); -#if _MSC_VER - // MS doesn't recognize %zu format - OutBuffer tmp; - tmp.vprintf(format, ap); - fprintf(stdmsg, "%s", tmp.toChars()); -#else - vfprintf(stdmsg, format, ap); -#endif - fprintf(stdmsg, "\n"); - fflush(stdmsg); - } -} - -void vwarning(Loc loc, const char *format, va_list ap) -{ - if (global.params.warnings && !global.gag) - { - char *p = loc.toChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Warning: "); -#if _MSC_VER - // MS doesn't recognize %zu format - OutBuffer tmp; - tmp.vprintf(format, ap); - fprintf(stdmsg, "%s", tmp.toChars()); -#else - vfprintf(stdmsg, format, ap); -#endif - fprintf(stdmsg, "\n"); - fflush(stdmsg); -//halt(); - if (global.params.warnings == 1) - global.warnings++; // warnings don't count if gagged - } -} - -/*************************************** - * Call this after printing out fatal error messages to clean up and exit - * the compiler. - */ - -void fatal() -{ -#if 0 - halt(); -#endif - exit(EXIT_FAILURE); -} - -/************************************** - * Try to stop forgetting to remove the breakpoints from - * release builds. - */ -void halt() -{ -#ifdef DEBUG - *(volatile char*)0=0; -#endif -} - -/*********************************** - * Parse and append contents of environment variable envvar - * to argc and argv[]. - * The string is separated into arguments, processing \ and ". - */ - -void getenv_setargv(const char *envvar, int *pargc, char** *pargv) -{ - char *p; - - int instring; - int slash; - char c; - - char *env = getenv(envvar); - if (!env) - return; - - env = mem.strdup(env); // create our own writable copy - - int argc = *pargc; - Strings *argv = new Strings(); - argv->setDim(argc); - - size_t argc_left = 0; - for (size_t i = 0; i < argc; i++) { - if (!strcmp((*pargv)[i], "-run") || !strcmp((*pargv)[i], "--run")) { - // HACK: set flag to indicate we saw '-run' here - global.params.run = true; - // Don't eat -run yet so the program arguments don't get changed - argc_left = argc - i; - argc = i; - *pargv = &(*pargv)[i]; - argv->setDim(i); - break; - } else { - argv->data[i] = (void *)(*pargv)[i]; - } - } - // HACK to stop required values from command line being drawn from DFLAGS - argv->push((char*)""); - argc++; - - size_t j = 1; // leave argv[0] alone - while (1) - { - int wildcard = 1; // do wildcard expansion - switch (*env) - { - case ' ': - case '\t': - env++; - break; - - case 0: - goto Ldone; - - case '"': - wildcard = 0; - default: - argv->push(env); // append - //argv->insert(j, env); // insert at position j - j++; - argc++; - p = env; - slash = 0; - instring = 0; - c = 0; - - while (1) - { - c = *env++; - switch (c) - { - case '"': - p -= (slash >> 1); - if (slash & 1) - { p--; - goto Laddc; - } - instring ^= 1; - slash = 0; - continue; - - case ' ': - case '\t': - if (instring) - goto Laddc; - *p = 0; - //if (wildcard) - //wildcardexpand(); // not implemented - break; - - case '\\': - slash++; - *p++ = c; - continue; - - case 0: - *p = 0; - //if (wildcard) - //wildcardexpand(); // not implemented - goto Ldone; - - default: - Laddc: - slash = 0; - *p++ = c; - continue; - } - break; - } - } - } - -Ldone: - assert(argc == argv->dim); - argv->reserve(argc_left); - for (int i = 0; i < argc_left; i++) - argv->data[argc++] = (void *)(*pargv)[i]; - - *pargc = argc; - *pargv = argv->tdata(); -} diff --git a/dmd/mars.h b/dmd/mars.h deleted file mode 100644 index eb67e031..00000000 --- a/dmd/mars.h +++ /dev/null @@ -1,528 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_MARS_H -#define DMD_MARS_H - -#ifdef __DMC__ -#pragma once -#endif - -/* -It is very important to use version control macros correctly - the -idea is that host and target are independent. If these are done -correctly, cross compilers can be built. -The host compiler and host operating system are also different, -and are predefined by the host compiler. The ones used in -dmd are: - -Macros defined by the compiler, not the code: - - Compiler: - __DMC__ Digital Mars compiler - _MSC_VER Microsoft compiler - __GNUC__ Gnu compiler - __clang__ Clang compiler - - Host operating system: - _WIN32 Microsoft NT, Windows 95, Windows 98, Win32s, - Windows 2000, Win XP, Vista - _WIN64 Windows for AMD64 - linux Linux - __APPLE__ Mac OSX - __FreeBSD__ FreeBSD - __OpenBSD__ OpenBSD - __sun&&__SVR4 Solaris, OpenSolaris (yes, both macros are necessary) - -For the target systems, there are the target operating system and -the target object file format: - - Target operating system: - TARGET_WINDOS Covers 32 bit windows and 64 bit windows - TARGET_LINUX Covers 32 and 64 bit linux - TARGET_OSX Covers 32 and 64 bit Mac OSX - TARGET_FREEBSD Covers 32 and 64 bit FreeBSD - TARGET_OPENBSD Covers 32 and 64 bit OpenBSD - TARGET_SOLARIS Covers 32 and 64 bit Solaris - TARGET_NET Covers .Net - - It is expected that the compiler for each platform will be able - to generate 32 and 64 bit code from the same compiler binary. - - Target object module format: - OMFOBJ Intel Object Module Format, used on Windows - ELFOBJ Elf Object Module Format, used on linux, FreeBSD, OpenBSD and Solaris - MACHOBJ Mach-O Object Module Format, used on Mac OSX - - There are currently no macros for byte endianness order. - */ - - -#include -#include -#include -#include -#include - -#if IN_LLVM -#include "llvm/ADT/Triple.h" -#endif - -#ifdef __DMC__ -#ifdef DEBUG -#undef assert -#define assert(e) (static_cast((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt()))) -#endif -#endif - -#ifndef IS_PRINTF -# ifdef __GNUC__ -# define IS_PRINTF(FMTARG) __attribute__((__format__ (__printf__, (FMTARG), (FMTARG)+1) )) -# else -# define IS_PRINTF(FMTARG) -# endif -#endif - -#ifndef IS_VPRINTF -# ifdef __GNUC__ -# define IS_VPRINTF(FMTARG) __attribute__((__format__ (__printf__, (FMTARG), 0) )) -# else -# define IS_VPRINTF(FMTARG) -# endif -#endif - -#ifdef IN_GCC -/* Changes for the GDC compiler by David Friedman */ -#endif - -#define DMDV2 0 // Version 2.0 features -#define STRUCTTHISREF DMDV2 // if 'this' for struct is a reference, not a pointer -#define SNAN_DEFAULT_INIT DMDV2 // if floats are default initialized to signalling NaN -#define SARRAYVALUE DMDV2 // static arrays are value types -#define MODULEINFO_IS_STRUCT DMDV2 // if ModuleInfo is a struct rather than a class - -// Set if C++ mangling is done by the front end -#define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS)) - -/* Other targets are TARGET_LINUX, TARGET_OSX, TARGET_FREEBSD, TARGET_OPENBSD and - * TARGET_SOLARIS, which are - * set on the command line via the compiler makefile. - */ - -#if _WIN32 -#ifndef TARGET_WINDOS -#define TARGET_WINDOS 1 // Windows dmd generates Windows targets -#endif -#ifndef OMFOBJ -#define OMFOBJ TARGET_WINDOS -#endif -#endif - -#if TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -#ifndef ELFOBJ -#define ELFOBJ 1 -#endif -#endif - -#if TARGET_OSX -#ifndef MACHOBJ -#define MACHOBJ 1 -#endif -#endif - - -struct OutBuffer; - -#if IN_LLVM -enum OUTPUTFLAG -{ - OUTPUTFLAGno, - OUTPUTFLAGdefault, // for the .o default - OUTPUTFLAGset // for -output -}; - -enum OS -{ - OSinvalid = llvm::Triple::UnknownOS, - OSLinux = llvm::Triple::Linux, - OSHaiku = llvm::Triple::Haiku, - OSWindows = llvm::Triple::Win32, - OSMacOSX = llvm::Triple::MacOSX, - OSFreeBSD = llvm::Triple::FreeBSD, - OSSolaris = llvm::Triple::Solaris, -}; -#endif - -typedef unsigned char ubyte; - -// Can't include arraytypes.h here, need to declare these directly. -template struct ArrayBase; -//typedef ArrayBase Identifiers; -typedef ArrayBase Strings; - -// Put command line switches in here -struct Param -{ - bool obj; // write object file - bool link; // perform link - bool verbose; // verbose compile - ubyte symdebug; // insert debug symbolic information -#if !IN_LLVM - // LDC uses a different mechanism - bool optimize; // run optimizer - char optimizeLevel; // optimization level -#endif - char vtls; // identify thread local variables -// KN Start merge conflict - bool is64bit; // generate 64 bit code - bool useDeprecated; // allow use of deprecated features - bool useAssert; // generate runtime code for assert()'s - bool useInvariants; // generate class invariant checks - bool useIn; // generate precondition checks - bool useOut; // generate postcondition checks - bool useArrayBounds; // generate array bounds checks - bool useSwitchError; // check for switches without a default - bool useUnitTests; // generate unittest code - bool useInline; // inline expand functions - ubyte warnings; // enable warnings -// KN End merge conflict -#if 0 - char symdebug; // insert debug symbolic information - char alwaysframe; // always emit standard stack frame - char optimize; // run optimizer - char map; // generate linker .map file - char cpu; // target CPU - char is64bit; // generate 64 bit code - char isLinux; // generate code for linux - char isOSX; // generate code for Mac OSX - char isWindows; // generate code for Windows - char isFreeBSD; // generate code for FreeBSD - char isOPenBSD; // generate code for OpenBSD - char isSolaris; // generate code for Solaris - char scheduler; // which scheduler to use - char useDeprecated; // allow use of deprecated features - char useAssert; // generate runtime code for assert()'s - char useInvariants; // generate class invariant checks - char useIn; // generate precondition checks - char useOut; // generate postcondition checks - char useArrayBounds; // 0: no array bounds checks - // 1: array bounds checks for safe functions only - // 2: array bounds checks for all functions - char noboundscheck; // no array bounds checking at all - char useSwitchError; // check for switches without a default - char useUnitTests; // generate unittest code - char useInline; // inline expand functions - char release; // build release version - char preservePaths; // !=0 means don't strip path from source file - char warnings; // 0: enable warnings -#endif - // 1: warnings as errors - // 2: informational warnings (no errors) - ubyte Dversion; // D version number - bool ignoreUnsupportedPragmas; // rather than error on them - char safe; // enforce safe memory model - - char *argv0; // program name - Strings *imppath; // array of char*'s of where to look for import modules - Strings *fileImppath; // array of char*'s of where to look for file import modules - char *objdir; // .obj/.lib file output directory - char *objname; // .obj file output name - - bool doDocComments; // process embedded documentation comments - char *docdir; // write documentation file to docdir directory - char *docname; // write documentation file to docname - Strings *ddocfiles; // macro include files for Ddoc - - bool doHdrGeneration; // process embedded documentation comments - char *hdrdir; // write 'header' file to docdir directory - char *hdrname; // write 'header' file to docname - - bool doXGeneration; // write JSON file - char *xfilename; // write JSON file to xfilename - - unsigned debuglevel; // debug level - Strings *debugids; // debug identifiers - - unsigned versionlevel; // version level - Strings *versionids; // version identifiers - - bool dump_source; - - Strings *defaultlibnames; // default libraries for non-debug builds - Strings *debuglibnames; // default libraries for debug builds - - char *moduleDepsFile; // filename for deps output - OutBuffer *moduleDeps; // contents to be written to deps file - - // Hidden debug switches - bool debuga; - bool debugb; - bool debugc; - bool debugf; - bool debugr; - bool debugw; - bool debugx; - bool debugy; - - bool run; // run resulting executable - - // Linker stuff - Strings *objfiles; - Strings *linkswitches; - Strings *libfiles; - char *deffile; - char *resfile; - char *exefile; - char *mapfile; - -#if IN_LLVM - // LDC stuff - OUTPUTFLAG output_ll; - OUTPUTFLAG output_bc; - OUTPUTFLAG output_s; - OUTPUTFLAG output_o; - bool useInlineAsm; - bool verbose_cg; - bool useAvailableExternally; - - // target stuff - llvm::Triple targetTriple; - - // Codegen cl options - bool singleObj; - bool disableRedZone; -#endif -}; - -typedef unsigned structalign_t; -#define STRUCTALIGN_DEFAULT ~0 // magic value means "match whatever the underlying C compiler does" -// other values are all powers of 2 - -struct Global -{ - const char *mars_ext; - const char *sym_ext; - const char *obj_ext; -#if IN_LLVM - const char *obj_ext_alt; - const char *ll_ext; - const char *bc_ext; - const char *s_ext; -#endif - const char *lib_ext; - const char *dll_ext; - const char *doc_ext; // for Ddoc generated files - const char *ddoc_ext; // for Ddoc macro include files - const char *hdr_ext; // for D 'header' import files - const char *json_ext; // for JSON files - const char *map_ext; // for .map files - const char *copyright; - const char *written; - Strings *path; // Array of char*'s which form the import lookup path - Strings *filePath; // Array of char*'s which form the file import lookup path - - structalign_t structalign; // default alignment for struct fields - - const char *version; - char *ldc_version; - char *llvm_version; - - Param params; - unsigned errors; // number of errors reported so far - unsigned warnings; // number of warnings reported so far - unsigned gag; // !=0 means gag reporting of errors & warnings - unsigned gaggedErrors; // number of errors reported while gagged - - /* Gagging can either be speculative (is(typeof()), etc) - * or because of forward references - */ - unsigned speculativeGag; // == gag means gagging is for is(typeof); - bool isSpeculativeGagging(); - - // Start gagging. Return the current number of gagged errors - unsigned startGagging(); - - /* End gagging, restoring the old gagged state. - * Return true if errors occured while gagged. - */ - bool endGagging(unsigned oldGagged); - - Global(); -}; - -extern Global global; - -/* Set if Windows Structured Exception Handling C extensions are supported. - * Apparently, VC has dropped support for these? - */ -#define WINDOWS_SEH (_WIN32 && __DMC__) - -#include "longdouble.h" - -#ifdef __DMC__ - #include - typedef _Complex long double complex_t; -#else - #ifndef IN_GCC - #include "complex_t.h" - #endif - #ifdef __APPLE__ - //#include "complex.h"//This causes problems with include the c++ and not the C "complex.h" - #endif -#endif - -// Be careful not to care about sign when using dinteger_t -//typedef uint64_t integer_t; -typedef uint64_t dinteger_t; // use this instead of integer_t to - // avoid conflicts with system #include's - -// Signed and unsigned variants -typedef int64_t sinteger_t; -typedef uint64_t uinteger_t; - -typedef int8_t d_int8; -typedef uint8_t d_uns8; -typedef int16_t d_int16; -typedef uint16_t d_uns16; -typedef int32_t d_int32; -typedef uint32_t d_uns32; -typedef int64_t d_int64; -typedef uint64_t d_uns64; - -typedef float d_float32; -typedef double d_float64; -typedef longdouble d_float80; - -typedef d_uns8 d_char; -typedef d_uns16 d_wchar; -typedef d_uns32 d_dchar; - -#ifdef IN_GCC -#include "d-gcc-real.h" -#else -typedef longdouble real_t; -#endif - -// Modify OutBuffer::writewchar to write the correct size of wchar -#if _WIN32 -#define writewchar writeword -#else -// This needs a configuration test... -#define writewchar write4 -#endif - -#ifdef IN_GCC -#include "d-gcc-complex_t.h" -#endif - -struct Module; - -//typedef unsigned Loc; // file location -struct Loc -{ - const char *filename; - unsigned linnum; - - Loc() - { - linnum = 0; - filename = NULL; - } - - Loc(int x) - { - linnum = x; - filename = NULL; - } - - Loc(Module *mod, unsigned linnum); - - char *toChars() const; - bool equals(const Loc& loc); -}; - -#ifndef GCC_SAFE_DMD -#define TRUE 1 -#define FALSE 0 -#endif - -#define INTERFACE_OFFSET 0 // if 1, put classinfo as first entry - // in interface vtbl[]'s -#define INTERFACE_VIRTUAL 0 // 1 means if an interface appears - // in the inheritance graph multiple - // times, only one is used - -enum LINK -{ - LINKdefault, - LINKd, - LINKc, - LINKcpp, - LINKwindows, - LINKpascal, - -#if IN_LLVM - LINKintrinsic, -#endif -}; - -enum DYNCAST -{ - DYNCAST_OBJECT, - DYNCAST_EXPRESSION, - DYNCAST_DSYMBOL, - DYNCAST_TYPE, - DYNCAST_IDENTIFIER, - DYNCAST_TUPLE, -}; - -enum MATCH -{ - MATCHnomatch, // no match - MATCHconvert, // match with conversions -#if DMDV2 - MATCHconst, // match with conversion to const -#endif - MATCHexact // exact match -}; - -typedef uint64_t StorageClass; - - -void warning(Loc loc, const char *format, ...) IS_PRINTF(2); -void error(Loc loc, const char *format, ...) IS_PRINTF(2); -void errorSupplemental(Loc loc, const char *format, ...); -void verror(Loc loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL); -void vwarning(Loc loc, const char *format, va_list); -void verrorSupplemental(Loc loc, const char *format, va_list); - -#if defined(__GNUC__) || defined(__clang__) -__attribute__((noreturn)) -#endif -void fatal(); - -void err_nomem(); -#if IN_LLVM -void error(const char *format, ...) IS_PRINTF(1); -#else -void inifile(char *argv0, const char *inifile); -#endif -void halt(); - -const char *importHint(const char *s); - -/*** Where to send error messages ***/ -#if IN_GCC || IN_LLVM -#define stdmsg stderr -#else -#define stdmsg stderr -#endif - -#endif /* DMD_MARS_H */ diff --git a/dmd/mem.c b/dmd/mem.c deleted file mode 100644 index 35aec3cf..00000000 --- a/dmd/mem.c +++ /dev/null @@ -1,269 +0,0 @@ - -/* Copyright (c) 2000 Digital Mars */ -/* All Rights Reserved */ - -#include -#include -#include -#include - -#include "rmem.h" - -#if USE_BOEHM_GC - // I needed to perfix the dir after upgrading to gc 7.0 - #include "gc/gc.h" -#endif - -/* This implementation of the storage allocator uses the standard C allocation package. - */ - -Mem mem; - -#if USE_BOEHM_GC - -static bool gc_was_init = false; - -void Mem::init() -{ - GC_init(); - gc_was_init = true; -} - -char *Mem::strdup(const char *s) -{ - char *p; - - if (s) - { - p = GC_strdup(s); - if (p) - return p; - error(); - } - return NULL; -} - -void *Mem::malloc(size_t size) -{ void *p; - - if (!size) - p = NULL; - else - { - p = GC_malloc(size); - if (!p) - error(); - } - return p; -} - -void *Mem::calloc(size_t size, size_t n) -{ void *p; - - if (!size || !n) - p = NULL; - else - { - p = GC_malloc(size * n); - if (!p) - error(); - memset(p, 0, size * n); - } - return p; -} - -void *Mem::realloc(void *p, size_t size) -{ - if (!size) - { if (p) - { GC_free(p); - p = NULL; - } - } - else if (!p) - { - p = GC_malloc(size); - if (!p) - error(); - } - else - { - p = GC_realloc(p, size); - if (!p) - error(); - } - return p; -} - -void Mem::free(void *p) -{ - if (p) - GC_free(p); -} - -void *Mem::mallocdup(void *o, size_t size) -{ void *p; - - if (!size) - p = NULL; - else - { - p = GC_malloc(size); - if (!p) - error(); - else - memcpy(p,o,size); - } - return p; -} - -void Mem::error() -{ - printf("Error: out of memory\n"); - exit(EXIT_FAILURE); -} - -void Mem::fullcollect() -{ - GC_gcollect(); -} - -void Mem::mark(void *pointer) -{ - (void) pointer; // necessary for VC /W4 -} - -/* =================================================== */ - -void * operator new(size_t m_size) -{ - // without this we segfault with gc 7.0 - if (!gc_was_init) { - mem.init(); - } - void *p = GC_malloc(m_size); - if (p) - return p; - printf("Error: out of memory\n"); - exit(EXIT_FAILURE); - return p; -} - -void operator delete(void *p) -{ - GC_free(p); -} - -#elif !USE_BOEHM_GC - -void Mem::init() -{ -} - -char *Mem::strdup(const char *s) -{ - char *p; - - if (s) - { - p = ::strdup(s); - if (p) - return p; - error(); - } - return NULL; -} - -void *Mem::malloc(size_t size) -{ void *p; - - if (!size) - p = NULL; - else - { - p = ::malloc(size); - if (!p) - error(); - } - return p; -} - -void *Mem::calloc(size_t size, size_t n) -{ void *p; - - if (!size || !n) - p = NULL; - else - { - p = ::malloc(size * n); - if (!p) - error(); - memset(p, 0, size * n); - } - return p; -} - -void *Mem::realloc(void *p, size_t size) -{ - if (!size) - { if (p) - { ::free(p); - p = NULL; - } - } - else if (!p) - { - p = ::malloc(size); - if (!p) - error(); - } - else - { - p = ::realloc(p, size); - if (!p) - error(); - } - return p; -} - -void Mem::free(void *p) -{ - if (p) - ::free(p); -} - -void *Mem::mallocdup(void *o, size_t size) -{ void *p; - - if (!size) - p = NULL; - else - { - p = ::malloc(size); - if (!p) - error(); - else - memcpy(p,o,size); - } - return p; -} - -void Mem::error() -{ - printf("Error: out of memory\n"); - exit(EXIT_FAILURE); -} - -void Mem::fullcollect() -{ -} - -void Mem::mark(void *pointer) -{ -} - -void Mem::setStackBottom(void */*stackbottom*/) -{ -} - -#endif // USE_BOEHM_GC diff --git a/dmd/mem.h b/dmd/mem.h deleted file mode 100644 index 85ebda62..00000000 --- a/dmd/mem.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2000-2001 by Chromium Communications -// All Rights Reserved - -#ifndef ROOT_MEM_H -#define ROOT_MEM_H - -#include // for size_t - -typedef void (*FINALIZERPROC)(void* pObj, void* pClientData); - -struct GC; // thread specific allocator - -struct Mem -{ - GC *gc; // pointer to our thread specific allocator - Mem() { gc = NULL; } - - void init(); - - // Derive from Mem to get these storage allocators instead of global new/delete - void * operator new(size_t m_size); - void * operator new(size_t m_size, Mem *mem); - void * operator new(size_t m_size, GC *gc); - void operator delete(void *p); - - void * operator new[](size_t m_size); - void operator delete[](void *p); - - char *strdup(const char *s); - void *malloc(size_t size); - void *malloc_uncollectable(size_t size); - void *calloc(size_t size, size_t n); - void *realloc(void *p, size_t size); - void free(void *p); - void free_uncollectable(void *p); - void *mallocdup(void *o, size_t size); - void error(); - void check(void *p); // validate pointer - void fullcollect(); // do full garbage collection - void fullcollectNoStack(); // do full garbage collection, no scan stack - void mark(void *pointer); - void addroots(char* pStart, char* pEnd); - void removeroots(char* pStart); - void setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData); - void setStackBottom(void *bottom); - GC *getThreadGC(); // get apartment allocator for this thread -}; - -extern Mem mem; - -#endif /* ROOT_MEM_H */ diff --git a/dmd/module.c b/dmd/module.c deleted file mode 100644 index 50723083..00000000 --- a/dmd/module.c +++ /dev/null @@ -1,1257 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#if defined(_MSC_VER) || defined(__MINGW32__) -#include -#endif - -#ifdef IN_GCC -#include "gdc_alloca.h" -#endif - -#include "rmem.h" - -#include "mars.h" -#include "module.h" -#include "parse.h" -#include "scope.h" -#include "identifier.h" -#include "id.h" -#include "import.h" -#include "dsymbol.h" -#include "hdrgen.h" -#include "lexer.h" - -#define MARS 1 -#include "html.h" - -#ifdef IN_GCC -#include "d-dmd-gcc.h" -#endif - -#if IN_LLVM -#include "llvm/Type.h" -#include "llvm/LLVMContext.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Support/CommandLine.h" -#include - -// stricmp -#if __GNUC__ && !_WIN32 -#include "gnuc.h" -#endif - -static llvm::cl::opt preservePaths("op", - llvm::cl::desc("Do not strip paths from source file"), - llvm::cl::ZeroOrMore); - -static llvm::cl::opt fqnNames("oq", - llvm::cl::desc("Write object files with fully qualified names"), - llvm::cl::ZeroOrMore); -#endif - -ClassDeclaration *Module::moduleinfo; - -Module *Module::rootModule; -DsymbolTable *Module::modules; -Modules Module::amodules; - -Dsymbols Module::deferred; // deferred Dsymbol's needing semantic() run on them -unsigned Module::dprogress; - -void Module::init() -{ - modules = new DsymbolTable(); -} - -Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen) - : Package(ident) -{ - FileName *srcfilename; - FileName *objfilename; - FileName *symfilename; - -// printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars()); - this->arg = filename; - md = NULL; - errors = 0; - numlines = 0; - members = NULL; - isHtml = 0; - isDocFile = 0; - needmoduleinfo = 0; -#ifdef IN_GCC - strictlyneedmoduleinfo = 0; -#endif - selfimports = 0; - insearch = 0; - searchCacheIdent = NULL; - searchCacheSymbol = NULL; - searchCacheFlags = 0; - semanticstarted = 0; - semanticRun = 0; - decldefs = NULL; - vmoduleinfo = NULL; -#if IN_DMD - massert = NULL; - munittest = NULL; - marray = NULL; - sictor = NULL; - sctor = NULL; - sdtor = NULL; - stest = NULL; - sfilename = NULL; -#endif - root = 0; - importedFrom = NULL; - srcfile = NULL; - objfile = NULL; - docfile = NULL; - hdrfile = NULL; - - debuglevel = 0; - debugids = NULL; - debugidsNot = NULL; - versionlevel = 0; - versionids = NULL; - versionidsNot = NULL; - - macrotable = NULL; - escapetable = NULL; - safe = FALSE; -#if IN_DMD - doppelganger = 0; - cov = NULL; - covb = NULL; -#endif - - srcfilename = FileName::defaultExt(filename, global.mars_ext); - if (!srcfilename->equalsExt(global.mars_ext) && - !srcfilename->equalsExt(global.hdr_ext) && - !srcfilename->equalsExt("dd")) - { - if (srcfilename->equalsExt("html") || - srcfilename->equalsExt("htm") || - srcfilename->equalsExt("xhtml")) - isHtml = 1; - else - { error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); - fatal(); - } - } - srcfile = new File(srcfilename); - -#if IN_LLVM - // LDC - llvmForceLogging = false; - moduleInfoVar = NULL; - moduleInfoType = llvm::StructType::create(llvm::getGlobalContext()); - this->doDocComment = doDocComment; - this->doHdrGen = doHdrGen; - this->isRoot = false; - this->arrayfuncs.init(); -#endif -} - -#if IN_LLVM -File* Module::buildFilePath(const char* forcename, const char* path, const char* ext) -{ - const char *argobj; - if (forcename) - argobj = forcename; - else - { - if (preservePaths) - argobj = (char*)this->arg; - else - argobj = FileName::name((char*)this->arg); - - if (fqnNames) - { - if(md) - argobj = FileName::replaceName((char*)argobj, md->toChars()); - else - argobj = FileName::replaceName((char*)argobj, toChars()); - - // add ext, otherwise forceExt will make nested.module into nested.bc - size_t len = strlen(argobj); - size_t extlen = strlen(ext); - char* s = (char *)alloca(len + 1 + extlen + 1); - memcpy(s, argobj, len); - s[len] = '.'; - memcpy(s + len + 1, ext, extlen + 1); - s[len+1+extlen] = 0; - argobj = s; - } - } - - if (!FileName::absolute(argobj)) - { - argobj = FileName::combine(path, argobj); - } - - FileName::ensurePathExists(FileName::path(argobj)); - -// always append the extension! otherwise hard to make output switches consistent -// if (forcename) -// return new File(argobj); -// else - // allow for .o and .obj on windows -#if _WIN32 - if (ext == global.params.objdir && FileName::ext(argobj) - && stricmp(FileName::ext(argobj), global.obj_ext_alt) == 0) - return new File((char*)argobj); -#endif - return new File(FileName::forceExt(argobj, ext)); -} - -static void check_and_add_output_file(Module* NewMod, const std::string& str) -{ - typedef std::map map_t; - static map_t files; - - map_t::iterator i = files.find(str); - if (i != files.end()) - { - Module* ThisMod = i->second; - error("Output file '%s' for module '%s' collides with previous module '%s'. See the -oq option", - str.c_str(), NewMod->toPrettyChars(), ThisMod->toPrettyChars()); - fatal(); - } - files.insert(std::make_pair(str, NewMod)); -} - -void Module::buildTargetFiles(bool singleObj) -{ - if(objfile && - (!doDocComment || docfile) && - (!doHdrGen || hdrfile)) - return; - - if(!objfile) - { - if (global.params.output_bc) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.bc_ext); - else if (global.params.output_ll) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.ll_ext); - else if (global.params.output_s) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.s_ext); - else - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, - global.params.targetTriple.isOSWindows() ? global.obj_ext_alt : global.obj_ext); - } - if(doDocComment && !docfile) - docfile = Module::buildFilePath(global.params.docname, global.params.docdir, global.doc_ext); - if(doHdrGen && !hdrfile) - hdrfile = Module::buildFilePath(global.params.hdrname, global.params.hdrdir, global.hdr_ext); - - // safety check: never allow obj, doc or hdr file to have the source file's name - if(stricmp(FileName::name(objfile->name->str), FileName::name((char*)this->arg)) == 0) - { - error("Output object files with the same name as the source file are forbidden"); - fatal(); - } - if(docfile && stricmp(FileName::name(docfile->name->str), FileName::name((char*)this->arg)) == 0) - { - error("Output doc files with the same name as the source file are forbidden"); - fatal(); - } - if(hdrfile && stricmp(FileName::name(hdrfile->name->str), FileName::name((char*)this->arg)) == 0) - { - error("Output header files with the same name as the source file are forbidden"); - fatal(); - } - - // LDC - // another safety check to make sure we don't overwrite previous output files - if (!singleObj) - check_and_add_output_file(this, objfile->name->str); - if (docfile) - check_and_add_output_file(this, docfile->name->str); - if (hdrfile) - check_and_add_output_file(this, hdrfile->name->str); -} -#endif - -void Module::deleteObjFile() -{ - if (global.params.obj) - objfile->remove(); - //if (global.params.llvmBC) - //bcfile->remove(); - if (doDocComment && docfile) - docfile->remove(); -} - -Module::~Module() -{ -#if IN_LLVM - delete moduleInfoType; -#endif -} - -const char *Module::kind() -{ - return "module"; -} - -Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) -{ Module *m; - char *filename; - - //printf("Module::load(ident = '%s')\n", ident->toChars()); - - // Build module filename by turning: - // foo.bar.baz - // into: - // foo\bar\baz - filename = ident->toChars(); - if (packages && packages->dim) - { - OutBuffer buf; - - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = (*packages)[i]; - - buf.writestring(pid->toChars()); -#if _WIN32 - buf.writeByte('\\'); -#else - buf.writeByte('/'); -#endif - } - buf.writestring(filename); - buf.writeByte(0); - filename = (char *)buf.extractData(); - } - - m = new Module(filename, ident, 0, 0); - m->loc = loc; - - /* Search along global.path for .di file, then .d file. - */ - char *result = NULL; - FileName *fdi = FileName::forceExt(filename, global.hdr_ext); - FileName *fd = FileName::forceExt(filename, global.mars_ext); - char *sdi = fdi->toChars(); - char *sd = fd->toChars(); - - if (FileName::exists(sdi)) - result = sdi; - else if (FileName::exists(sd)) - result = sd; - else if (FileName::absolute(filename)) - ; - else if (!global.path) - ; - else - { - for (size_t i = 0; i < global.path->dim; i++) - { - char *p = (*global.path)[i]; - char *n = FileName::combine(p, sdi); - if (FileName::exists(n)) - { result = n; - break; - } - mem.free(n); - n = FileName::combine(p, sd); - if (FileName::exists(n)) - { result = n; - break; - } - mem.free(n); - } - } - if (result) - m->srcfile = new File(result); - - if (global.params.verbose) - { - printf("import "); - if (packages) - { - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = (*packages)[i]; - printf("%s.", pid->toChars()); - } - } - printf("%s\t(%s)\n", ident->toChars(), m->srcfile->toChars()); - } - - if (!m->read(loc)) - return NULL; - - m->parse(); - -#ifdef IN_GCC - d_gcc_magic_module(m); -#endif - - return m; -} - -bool Module::read(Loc loc) -{ - //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars()); - if (srcfile->read()) - { error(loc, "is in file '%s' which cannot be read", srcfile->toChars()); - if (!global.gag) - { /* Print path - */ - if (global.path) - { - for (size_t i = 0; i < global.path->dim; i++) - { - char *p = (*global.path)[i]; - fprintf(stdmsg, "import path[%llu] = %s\n", (ulonglong)i, p); - } - } - else - fprintf(stdmsg, "Specify path to file '%s' with -I switch\n", srcfile->toChars()); - fatal(); - } - return false; - } - return true; -} - -inline unsigned readwordLE(unsigned short *p) -{ -#if LITTLE_ENDIAN - return *p; -#else - return (((unsigned char *)p)[1] << 8) | ((unsigned char *)p)[0]; -#endif -} - -inline unsigned readwordBE(unsigned short *p) -{ - return (((unsigned char *)p)[0] << 8) | ((unsigned char *)p)[1]; -} - -inline unsigned readlongLE(unsigned *p) -{ -#if LITTLE_ENDIAN - return *p; -#else - return ((unsigned char *)p)[0] | - (((unsigned char *)p)[1] << 8) | - (((unsigned char *)p)[2] << 16) | - (((unsigned char *)p)[3] << 24); -#endif -} - -inline unsigned readlongBE(unsigned *p) -{ - return ((unsigned char *)p)[3] | - (((unsigned char *)p)[2] << 8) | - (((unsigned char *)p)[1] << 16) | - (((unsigned char *)p)[0] << 24); -} - -#if IN_LLVM -void Module::parse(bool gen_docs) -#else -void Module::parse() -#endif -{ - //printf("Module::parse()\n"); - - char *srcname = srcfile->name->toChars(); - //printf("Module::parse(srcname = '%s')\n", srcname); - - unsigned char *buf = srcfile->buffer; - unsigned buflen = srcfile->len; - - if (buflen >= 2) - { - /* Convert all non-UTF-8 formats to UTF-8. - * BOM : http://www.unicode.org/faq/utf_bom.html - * 00 00 FE FF UTF-32BE, big-endian - * FF FE 00 00 UTF-32LE, little-endian - * FE FF UTF-16BE, big-endian - * FF FE UTF-16LE, little-endian - * EF BB BF UTF-8 - */ - - unsigned le; - unsigned bom = 1; // assume there's a BOM - if (buf[0] == 0xFF && buf[1] == 0xFE) - { - if (buflen >= 4 && buf[2] == 0 && buf[3] == 0) - { // UTF-32LE - le = 1; - - Lutf32: - OutBuffer dbuf; - unsigned *pu = (unsigned *)(buf); - unsigned *pumax = &pu[buflen / 4]; - - if (buflen & 3) - { error("odd length of UTF-32 char source %u", buflen); - fatal(); - } - - dbuf.reserve(buflen / 4); - for (pu += bom; pu < pumax; pu++) - { unsigned u; - - u = le ? readlongLE(pu) : readlongBE(pu); - if (u & ~0x7F) - { - if (u > 0x10FFFF) - { error("UTF-32 value %08x greater than 0x10FFFF", u); - fatal(); - } - dbuf.writeUTF8(u); - } - else - dbuf.writeByte(u); - } - dbuf.writeByte(0); // add 0 as sentinel for scanner - buflen = dbuf.offset - 1; // don't include sentinel in count - buf = (unsigned char *) dbuf.extractData(); - } - else - { // UTF-16LE (X86) - // Convert it to UTF-8 - le = 1; - - Lutf16: - OutBuffer dbuf; - unsigned short *pu = (unsigned short *)(buf); - unsigned short *pumax = &pu[buflen / 2]; - - if (buflen & 1) - { error("odd length of UTF-16 char source %u", buflen); - fatal(); - } - - dbuf.reserve(buflen / 2); - for (pu += bom; pu < pumax; pu++) - { unsigned u; - - u = le ? readwordLE(pu) : readwordBE(pu); - if (u & ~0x7F) - { if (u >= 0xD800 && u <= 0xDBFF) - { unsigned u2; - - if (++pu > pumax) - { error("surrogate UTF-16 high value %04x at EOF", u); - fatal(); - } - u2 = le ? readwordLE(pu) : readwordBE(pu); - if (u2 < 0xDC00 || u2 > 0xDFFF) - { error("surrogate UTF-16 low value %04x out of range", u2); - fatal(); - } - u = (u - 0xD7C0) << 10; - u |= (u2 - 0xDC00); - } - else if (u >= 0xDC00 && u <= 0xDFFF) - { error("unpaired surrogate UTF-16 value %04x", u); - fatal(); - } - else if (u == 0xFFFE || u == 0xFFFF) - { error("illegal UTF-16 value %04x", u); - fatal(); - } - dbuf.writeUTF8(u); - } - else - dbuf.writeByte(u); - } - dbuf.writeByte(0); // add 0 as sentinel for scanner - buflen = dbuf.offset - 1; // don't include sentinel in count - buf = (unsigned char *) dbuf.extractData(); - } - } - else if (buf[0] == 0xFE && buf[1] == 0xFF) - { // UTF-16BE - le = 0; - goto Lutf16; - } - else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) - { // UTF-32BE - le = 0; - goto Lutf32; - } - else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) - { // UTF-8 - - buf += 3; - buflen -= 3; - } - else - { - /* There is no BOM. Make use of Arcane Jill's insight that - * the first char of D source must be ASCII to - * figure out the encoding. - */ - - bom = 0; - if (buflen >= 4) - { if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0) - { // UTF-32LE - le = 1; - goto Lutf32; - } - else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) - { // UTF-32BE - le = 0; - goto Lutf32; - } - } - if (buflen >= 2) - { - if (buf[1] == 0) - { // UTF-16LE - le = 1; - goto Lutf16; - } - else if (buf[0] == 0) - { // UTF-16BE - le = 0; - goto Lutf16; - } - } - - // It's UTF-8 - if (buf[0] >= 0x80) - { error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); - fatal(); - } - } - } - -#ifdef IN_GCC - // dump utf-8 encoded source - if (global.params.dump_source) - { // %% srcname could contain a path ... - d_gcc_dump_source(srcname, "utf-8", buf, buflen); - } -#endif - - /* If it starts with the string "Ddoc", then it's a documentation - * source file. - */ - if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0) - { - comment = buf + 4; - isDocFile = 1; - return; - } - if (isHtml) - { - OutBuffer *dbuf = new OutBuffer(); - Html h(srcname, buf, buflen); - h.extractCode(dbuf); - buf = dbuf->data; - buflen = dbuf->offset; -#ifdef IN_GCC - // dump extracted source - if (global.params.dump_source) - d_gcc_dump_source(srcname, "d.utf-8", buf, buflen); -#endif - } -#if IN_LLVM - Parser p(this, buf, buflen, gen_docs); -#else - Parser p(this, buf, buflen, docfile != NULL); -#endif - p.nextToken(); - members = p.parseModule(); - - ::free(srcfile->buffer); - srcfile->buffer = NULL; - srcfile->len = 0; - - md = p.md; - numlines = p.loc.linnum; - - DsymbolTable *dst; - - if (md) - { this->ident = md->id; - this->safe = md->safe; - Package *ppack = NULL; - dst = Package::resolve(md->packages, &this->parent, &ppack); - if (ppack && ppack->isModule()) - { - error(loc, "package name '%s' in file %s conflicts with usage as a module name in file %s", - ppack->toChars(), srcname, ppack->isModule()->srcfile->toChars()); - dst = modules; - } - } - else - { - dst = modules; - - /* Check to see if module name is a valid identifier - */ - if (!Lexer::isValidIdentifier(this->ident->toChars())) - error("has non-identifier characters in filename, use module declaration instead"); - } - - // Update global list of modules - if (!dst->insert(this)) - { - Dsymbol *prev = dst->lookup(ident); - assert(prev); - Module *mprev = prev->isModule(); - if (mprev) - error(loc, "from file %s conflicts with another module %s from file %s", - srcname, mprev->toChars(), mprev->srcfile->toChars()); - else - { - Package *pkg = prev->isPackage(); - assert(pkg); - error(pkg->loc, "from file %s conflicts with package name %s", - srcname, pkg->toChars()); - } - } - else - { - amodules.push(this); - } -} - -void Module::importAll(Scope *prevsc) -{ - //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent); - - if (scope) - return; // already done - - if (isDocFile) - { - error("is a Ddoc file, cannot import it"); - return; - } - - /* Note that modules get their own scope, from scratch. - * This is so regardless of where in the syntax a module - * gets imported, it is unaffected by context. - * Ignore prevsc. - */ - Scope *sc = Scope::createGlobal(this); // create root scope - - // Add import of "object", even for the "object" module. - // If it isn't there, some compiler rewrites, like - // classinst == classinst -> .object.opEquals(classinst, classinst) - // would fail inside object.d. - if (members->dim == 0 || ((*members)[0])->ident != Id::object) - { - Import *im = new Import(0, NULL, Id::object, NULL, 0); - members->shift(im); - } - - if (!symtab) - { - // Add all symbols into module's symbol table - symtab = new DsymbolTable(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->addMember(NULL, sc->scopesym, 1); - } - } - // anything else should be run after addMember, so version/debug symbols are defined - - /* Set scope for the symbols so that if we forward reference - * a symbol, it can possibly be resolved on the spot. - * If this works out well, it can be extended to all modules - * before any semantic() on any of them. - */ - setScope(sc); // remember module scope for semantic - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->setScope(sc); - } - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->importAll(sc); - } - - sc = sc->pop(); - sc->pop(); // 2 pops because Scope::createGlobal() created 2 -} - -void Module::semantic() -{ - if (semanticstarted) - return; - - //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); - semanticstarted = 1; - - // Note that modules get their own scope, from scratch. - // This is so regardless of where in the syntax a module - // gets imported, it is unaffected by context. - Scope *sc = scope; // see if already got one from importAll() - if (!sc) - { printf("test2\n"); - Scope::createGlobal(this); // create root scope - } - - //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage); - -#if 0 - // Add import of "object" if this module isn't "object" - if (ident != Id::object) - { - Import *im = new Import(0, NULL, Id::object, NULL, 0); - members->shift(im); - } - - // Add all symbols into module's symbol table - symtab = new DsymbolTable(); - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - s->addMember(NULL, sc->scopesym, 1); - } - - /* Set scope for the symbols so that if we forward reference - * a symbol, it can possibly be resolved on the spot. - * If this works out well, it can be extended to all modules - * before any semantic() on any of them. - */ - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - s->setScope(sc); - } -#endif - - // Do semantic() on members that don't depend on others - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - - //printf("\tModule('%s'): '%s'.semantic0()\n", toChars(), s->toChars()); - s->semantic0(sc); - } - - // Pass 1 semantic routines: do public side of the definition - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - - //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars()); - s->semantic(sc); - runDeferredSemantic(); - } - - if (!scope) - { sc = sc->pop(); - sc->pop(); // 2 pops because Scope::createGlobal() created 2 - } - semanticRun = semanticstarted; - //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); -} - -void Module::semantic2() -{ - if (deferred.dim) - { - for (size_t i = 0; i < deferred.dim; i++) - { - Dsymbol *sd = deferred[i]; - - sd->error("unable to resolve forward reference in definition"); - } - return; - } - //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent); - if (semanticstarted >= 2) - return; - assert(semanticstarted == 1); - semanticstarted = 2; - - // Note that modules get their own scope, from scratch. - // This is so regardless of where in the syntax a module - // gets imported, it is unaffected by context. - Scope *sc = Scope::createGlobal(this); // create root scope - //printf("Module = %p\n", sc.scopesym); - - // Pass 2 semantic routines: do initializers and function bodies - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = (*members)[i]; - s->semantic2(sc); - } - - sc = sc->pop(); - sc->pop(); - semanticRun = semanticstarted; - //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); -} - -void Module::semantic3() -{ - //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent); - if (semanticstarted >= 3) - return; - assert(semanticstarted == 2); - semanticstarted = 3; - - // Note that modules get their own scope, from scratch. - // This is so regardless of where in the syntax a module - // gets imported, it is unaffected by context. - Scope *sc = Scope::createGlobal(this); // create root scope - //printf("Module = %p\n", sc.scopesym); - - // Pass 3 semantic routines: do initializers and function bodies - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = (*members)[i]; - //printf("Module %s: %s.semantic3()\n", toChars(), s->toChars()); - s->semantic3(sc); - } - - sc = sc->pop(); - sc->pop(); - semanticRun = semanticstarted; -} - -void Module::inlineScan() -{ - if (semanticstarted >= 4) - return; - assert(semanticstarted == 3); - semanticstarted = 4; - - // Note that modules get their own scope, from scratch. - // This is so regardless of where in the syntax a module - // gets imported, it is unaffected by context. - //printf("Module = %p\n", sc.scopesym); - - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - //if (global.params.verbose) - //printf("inline scan symbol %s\n", s->toChars()); - - s->inlineScan(); - } - semanticRun = semanticstarted; -} - -/**************************************************** - */ - -// is this used anywhere? -/* -void Module::gensymfile() -{ - OutBuffer buf; - HdrGenState hgs; - - //printf("Module::gensymfile()\n"); - - buf.printf("// Sym file generated from '%s'", srcfile->toChars()); - buf.writenl(); - - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - - s->toCBuffer(&buf, &hgs); - } - - // Transfer image to file - symfile->setbuffer(buf.data, buf.offset); - buf.data = NULL; - - symfile->writev(); -}*/ - -/********************************** - * Determine if we need to generate an instance of ModuleInfo - * for this Module. - */ - -int Module::needModuleInfo() -{ - //printf("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov); - return needmoduleinfo; -} - -Dsymbol *Module::search(Loc loc, Identifier *ident, int flags) -{ - /* Since modules can be circularly referenced, - * need to stop infinite recursive searches. - * This is done with the cache. - */ - - //printf("%s Module::search('%s', flags = %d) insearch = %d\n", toChars(), ident->toChars(), flags, insearch); - Dsymbol *s; - if (insearch) - s = NULL; - else if (searchCacheIdent == ident && searchCacheFlags == flags) - { - s = searchCacheSymbol; - //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", toChars(), ident->toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol->toChars() : "null"); - } - else - { - insearch = 1; - s = ScopeDsymbol::search(loc, ident, flags); - insearch = 0; - - searchCacheIdent = ident; - searchCacheSymbol = s; - searchCacheFlags = flags; - } - return s; -} - -Dsymbol *Module::symtabInsert(Dsymbol *s) -{ - searchCacheIdent = 0; // symbol is inserted, so invalidate cache - return Package::symtabInsert(s); -} - -void Module::clearCache() -{ - for (size_t i = 0; i < amodules.dim; i++) - { Module *m = amodules[i]; - m->searchCacheIdent = NULL; - } -} - -/******************************************* - * Can't run semantic on s now, try again later. - */ - -void Module::addDeferredSemantic(Dsymbol *s) -{ - // Don't add it if it is already there - for (size_t i = 0; i < deferred.dim; i++) - { - Dsymbol *sd = deferred[i]; - - if (sd == s) - return; - } - - //printf("Module::addDeferredSemantic('%s')\n", s->toChars()); - deferred.push(s); -} - - -/****************************************** - * Run semantic() on deferred symbols. - */ - -void Module::runDeferredSemantic() -{ - if (dprogress == 0) - return; - - static int nested; - if (nested) - return; - //if (deferred.dim) printf("+Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); - nested++; - - size_t len; - do - { - dprogress = 0; - len = deferred.dim; - if (!len) - break; - - Dsymbol **todo; - Dsymbol *tmp; - if (len == 1) - { - todo = &tmp; - } - else - { - todo = (Dsymbol **)alloca(len * sizeof(Dsymbol *)); - assert(todo); - } - memcpy(todo, deferred.tdata(), len * sizeof(Dsymbol *)); - deferred.setDim(0); - - for (size_t i = 0; i < len; i++) - { - Dsymbol *s = todo[i]; - - s->semantic(NULL); - //printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars()); - } - //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress); - } while (deferred.dim < len || dprogress); // while making progress - nested--; - //printf("-Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); -} - -/************************************ - * Recursively look at every module this module imports, - * return TRUE if it imports m. - * Can be used to detect circular imports. - */ - -int Module::imports(Module *m) -{ - //printf("%s Module::imports(%s)\n", toChars(), m->toChars()); - int aimports_dim = aimports.dim; -#if 0 - for (size_t i = 0; i < aimports.dim; i++) - { Module *mi = (Module *)aimports.data[i]; - printf("\t[%d] %s\n", i, mi->toChars()); - } -#endif - for (size_t i = 0; i < aimports.dim; i++) - { Module *mi = aimports[i]; - if (mi == m) - return TRUE; - if (!mi->insearch) - { - mi->insearch = 1; - int r = mi->imports(m); - if (r) - return r; - } - } - return FALSE; -} - -/************************************* - * Return !=0 if module imports itself. - */ - -int Module::selfImports() -{ - //printf("Module::selfImports() %s\n", toChars()); - if (!selfimports) - { - for (size_t i = 0; i < amodules.dim; i++) - { Module *mi = amodules[i]; - //printf("\t[%d] %s\n", i, mi->toChars()); - mi->insearch = 0; - } - - selfimports = imports(this) + 1; - - for (size_t i = 0; i < amodules.dim; i++) - { Module *mi = amodules[i]; - //printf("\t[%d] %s\n", i, mi->toChars()); - mi->insearch = 0; - } - } - return selfimports - 1; -} - - -/* =========================== ModuleDeclaration ===================== */ - -ModuleDeclaration::ModuleDeclaration(Identifiers *packages, Identifier *id) -{ - this->packages = packages; - this->id = id; -} - -char *ModuleDeclaration::toChars() -{ - OutBuffer buf; - - if (packages && packages->dim) - { - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = (*packages)[i]; - - buf.writestring(pid->toChars()); - buf.writeByte('.'); - } - } - buf.writestring(id->toChars()); - buf.writeByte(0); - return (char *)buf.extractData(); -} - -/* =========================== Package ===================== */ - -Package::Package(Identifier *ident) - : ScopeDsymbol(ident) -{ -} - - -const char *Package::kind() -{ - return "package"; -} - - -DsymbolTable *Package::resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg) -{ - DsymbolTable *dst = Module::modules; - Dsymbol *parent = NULL; - - //printf("Package::resolve()\n"); - if (ppkg) - *ppkg = NULL; - - if (packages) - { - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = (*packages)[i]; - Dsymbol *p; - - p = dst->lookup(pid); - if (!p) - { - p = new Package(pid); - dst->insert(p); - p->parent = parent; - ((ScopeDsymbol *)p)->symtab = new DsymbolTable(); - } - else - { - assert(p->isPackage()); - // It might already be a module, not a package, but that needs - // to be checked at a higher level, where a nice error message - // can be generated. - // dot net needs modules and packages with same name - } - parent = p; - dst = ((Package *)p)->symtab; - if (ppkg && !*ppkg) - *ppkg = (Package *)p; -#if TARGET_NET -#else - if (p->isModule()) - { // Return the module so that a nice error message can be generated - if (ppkg) - *ppkg = (Package *)p; - break; - } -#endif - } - if (pparent) - { - *pparent = parent; - } - } - return dst; -} diff --git a/dmd/module.h b/dmd/module.h deleted file mode 100644 index dabc9a31..00000000 --- a/dmd/module.h +++ /dev/null @@ -1,225 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_MODULE_H -#define DMD_MODULE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "dsymbol.h" - -struct ModuleInfoDeclaration; -struct ClassDeclaration; -struct ModuleDeclaration; -struct Macro; -struct Escape; -struct VarDeclaration; -struct Library; - -// Back end -#if IN_LLVM -class Ir; -struct DValue; -typedef DValue elem; -namespace llvm { - class LLVMContext; - class Module; - class GlobalVariable; - class StructType; -} -#else - -#ifdef IN_GCC -union tree_node; typedef union tree_node elem; -#else -struct elem; -#endif -#endif - -struct Package : ScopeDsymbol -{ - Package(Identifier *ident); - const char *kind(); - - static DsymbolTable *resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg); - - Package *isPackage() { return this; } - - virtual void semantic(Scope *sc) { } -}; - -struct Module : Package -{ - static Module *rootModule; - static DsymbolTable *modules; // symbol table of all modules - static Modules amodules; // array of all modules - static Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them - static unsigned dprogress; // progress resolving the deferred list - static void init(); - - static ClassDeclaration *moduleinfo; - - - const char *arg; // original argument name - ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration - File *srcfile; // input source file - - File *objfile; // output object file - File *docfile; // output doc file - File *hdrfile; // output hdr file - - unsigned errors; // if any errors in file - unsigned numlines; // number of lines in source file - int isHtml; // if it is an HTML file - int isDocFile; // if it is a documentation input file, not D source - int needmoduleinfo; -#ifdef IN_GCC - int strictlyneedmoduleinfo; -#endif - - int selfimports; // 0: don't know, 1: does not, 2: does - int selfImports(); // returns !=0 if module imports itself - - int insearch; - Identifier *searchCacheIdent; - Dsymbol *searchCacheSymbol; // cached value of search - int searchCacheFlags; // cached flags - - int semanticstarted; // has semantic() been started? - int semanticRun; // has semantic() been done? - int root; // != 0 if this is a 'root' module, - // i.e. a module that will be taken all the - // way to an object file - Module *importedFrom; // module from command line we're imported from, - // i.e. a module that will be taken all the - // way to an object file - - Dsymbols *decldefs; // top level declarations for this Module - - Modules aimports; // all imported modules - - ModuleInfoDeclaration *vmoduleinfo; - - unsigned debuglevel; // debug level - Strings *debugids; // debug identifiers - Strings *debugidsNot; // forward referenced debug identifiers - - unsigned versionlevel; // version level - Strings *versionids; // version identifiers - Strings *versionidsNot; // forward referenced version identifiers - - Macro *macrotable; // document comment macros - struct Escape *escapetable; // document comment escapes - - int doDocComment; // enable generating doc comments for this module - int doHdrGen; // enable generating header file for this module - - bool safe; // TRUE if module is marked as 'safe' - - Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen); - ~Module(); - - static Module *load(Loc loc, Identifiers *packages, Identifier *ident); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); - const char *kind(); - bool read(Loc loc); // read file, returns 'true' if succeed, 'false' otherwise. -#if IN_LLVM - void parse(bool gen_docs = false); // syntactic parse -#else - void setDocfile(); // set docfile member - void parse(); // syntactic parse -#endif - void importAll(Scope *sc); - void semantic(); // semantic analysis - void semantic2(); // pass 2 semantic analysis - void semantic3(); // pass 3 semantic analysis - void inlineScan(); // scan for functions to inline - void setHdrfile(); // set hdrfile member - void genhdrfile(); // generate D import file - void genobjfile(int multiobj); -// void gensymfile(); - void gendocfile(); - int needModuleInfo(); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - Dsymbol *symtabInsert(Dsymbol *s); - void deleteObjFile(); - void addDeferredSemantic(Dsymbol *s); - static void runDeferredSemantic(); - static void clearCache(); - int imports(Module *m); - - // Back end -#if IN_DMD - int doppelganger; // sub-module - Symbol *cov; // private uint[] __coverage; - unsigned *covb; // bit array of valid code line numbers - - Symbol *sictor; // module order independent constructor - Symbol *sctor; // module constructor - Symbol *sdtor; // module destructor - Symbol *stest; // module unit test - - Symbol *sfilename; // symbol for filename - - Symbol *massert; // module assert function - Symbol *toModuleAssert(); // get module assert function - - Symbol *munittest; // module unittest failure function - Symbol *toModuleUnittest(); // get module unittest failure function - - Symbol *marray; // module array bounds function - Symbol *toModuleArray(); // get module array bounds function - - - static Symbol *gencritsec(); - elem *toEfilename(); - elem *toEmodulename(); - - Symbol *toSymbol(); -#endif - void genmoduleinfo(); - -#if IN_LLVM - // LDC - llvm::Module* genLLVMModule(llvm::LLVMContext& context, Ir* sir); - void buildTargetFiles(bool singleObj); - File* buildFilePath(const char* forcename, const char* path, const char* ext); - Module *isModule() { return this; } - llvm::GlobalVariable* moduleInfoSymbol(); - - bool llvmForceLogging; - llvm::GlobalVariable* moduleInfoVar; - llvm::StructType* moduleInfoType; - - // array ops emitted in this module already - StringTable arrayfuncs; - - bool isRoot; -#endif -}; - - -struct ModuleDeclaration -{ - Identifier *id; - Identifiers *packages; // array of Identifier's representing packages - bool safe; - - ModuleDeclaration(Identifiers *packages, Identifier *id); - - char *toChars(); -}; - -#endif /* DMD_MODULE_H */ diff --git a/dmd/mtype.c b/dmd/mtype.c deleted file mode 100644 index 5c0c246d..00000000 --- a/dmd/mtype.c +++ /dev/null @@ -1,6089 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// http://www.dsource.org/projects/dmd/browser/branches/dmd-1.x/src/mtype.c -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more -#define __USE_ISOC99 1 // so signbit() gets defined - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#ifdef __DMC__ -#include -#else -#include -#endif - -#include -#include -#include - -#if _MSC_VER -#include -#include -#include -#elif __DMC__ -#include -#elif __MINGW32__ -#include -#endif - -#include "rmem.h" -#include "port.h" - -#include "dsymbol.h" -#include "mtype.h" -#include "scope.h" -#include "init.h" -#include "expression.h" -#include "attrib.h" -#include "declaration.h" -#include "template.h" -#include "id.h" -#include "enum.h" -#include "import.h" -#include "aggregate.h" -#include "hdrgen.h" - -#if IN_LLVM -//#include "gen/tollvm.h" -Ir* Type::sir = NULL; -unsigned GetTypeAlignment(Ir* ir, Type* t); -#endif - -FuncDeclaration *hasThis(Scope *sc); - - -#define LOGDOTEXP 0 // log ::dotExp() -#define LOGDEFAULTINIT 0 // log ::defaultInit() - -// Allow implicit conversion of T[] to T* -#define IMPLICIT_ARRAY_TO_PTR global.params.useDeprecated - -/* These have default values for 32 bit code, they get - * adjusted for 64 bit code. - */ - -int PTRSIZE = 4; - -/* REALSIZE = size a real consumes in memory - * REALPAD = 'padding' added to the CPU real size to bring it up to REALSIZE - * REALALIGNSIZE = alignment for reals - */ -#if TARGET_OSX -int REALSIZE = 16; -int REALPAD = 6; -int REALALIGNSIZE = 16; -#elif TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -int REALSIZE = 12; -int REALPAD = 2; -int REALALIGNSIZE = 4; -#else -int REALSIZE = 10; -int REALPAD = 0; -int REALALIGNSIZE = 2; -#endif - -int Tsize_t = Tuns32; -int Tptrdiff_t = Tint32; - -/***************************** Type *****************************/ - -ClassDeclaration *Type::typeinfo; -ClassDeclaration *Type::typeinfoclass; -ClassDeclaration *Type::typeinfointerface; -ClassDeclaration *Type::typeinfostruct; -ClassDeclaration *Type::typeinfotypedef; -ClassDeclaration *Type::typeinfopointer; -ClassDeclaration *Type::typeinfoarray; -ClassDeclaration *Type::typeinfostaticarray; -ClassDeclaration *Type::typeinfoassociativearray; -ClassDeclaration *Type::typeinfoenum; -ClassDeclaration *Type::typeinfofunction; -ClassDeclaration *Type::typeinfodelegate; -ClassDeclaration *Type::typeinfotypelist; - -Type *Type::tvoidptr; -Type *Type::tstring; -Type *Type::basic[TMAX]; -unsigned char Type::mangleChar[TMAX]; -StringTable Type::stringtable; - -#if IN_LLVM -StringTable Type::deco_stringtable; -#endif - - -Type::Type(TY ty, Type *next) -{ - this->ty = ty; - this->mod = 0; - this->next = next; - this->deco = NULL; -#if DMDV2 - this->cto = NULL; - this->ito = NULL; - this->sto = NULL; - this->scto = NULL; - this->wto = NULL; - this->swto = NULL; -#endif - this->pto = NULL; - this->rto = NULL; - this->arrayof = NULL; - this->vtinfo = NULL; -#if IN_DMD - this->ctype = NULL; -#endif - -#if IN_LLVM - this->irtype = NULL; -#endif -} - -Type *Type::syntaxCopy() -{ - print(); - fprintf(stdmsg, "ty = %d\n", ty); - assert(0); - return this; -} - -int Type::equals(Object *o) -{ Type *t; - - t = (Type *)o; - //printf("Type::equals(%s, %s)\n", toChars(), t->toChars()); - if (this == o || - (t && deco == t->deco) && // deco strings are unique - deco != NULL) // and semantic() has been run - { - //printf("deco = '%s', t->deco = '%s'\n", deco, t->deco); - return 1; - } - //if (deco && t && t->deco) printf("deco = '%s', t->deco = '%s'\n", deco, t->deco); - return 0; -} - -char Type::needThisPrefix() -{ - return 'M'; // name mangling prefix for functions needing 'this' -} - -#if IN_LLVM -void Type::init(Ir* _sir) -#else -void Type::init() -#endif -{ - stringtable.init(1543); - deco_stringtable.init(); - Lexer::initKeywords(); - - mangleChar[Tarray] = 'A'; - mangleChar[Tsarray] = 'G'; - mangleChar[Taarray] = 'H'; - mangleChar[Tpointer] = 'P'; - mangleChar[Treference] = 'R'; - mangleChar[Tfunction] = 'F'; - mangleChar[Tident] = 'I'; - mangleChar[Tclass] = 'C'; - mangleChar[Tstruct] = 'S'; - mangleChar[Tenum] = 'E'; - mangleChar[Ttypedef] = 'T'; - mangleChar[Tdelegate] = 'D'; - - mangleChar[Tnone] = 'n'; - mangleChar[Tvoid] = 'v'; - mangleChar[Tint8] = 'g'; - mangleChar[Tuns8] = 'h'; - mangleChar[Tint16] = 's'; - mangleChar[Tuns16] = 't'; - mangleChar[Tint32] = 'i'; - mangleChar[Tuns32] = 'k'; - mangleChar[Tint64] = 'l'; - mangleChar[Tuns64] = 'm'; - mangleChar[Tfloat32] = 'f'; - mangleChar[Tfloat64] = 'd'; - mangleChar[Tfloat80] = 'e'; - - mangleChar[Timaginary32] = 'o'; - mangleChar[Timaginary64] = 'p'; - mangleChar[Timaginary80] = 'j'; - mangleChar[Tcomplex32] = 'q'; - mangleChar[Tcomplex64] = 'r'; - mangleChar[Tcomplex80] = 'c'; - - mangleChar[Tbool] = 'b'; - mangleChar[Tascii] = 'a'; - mangleChar[Twchar] = 'u'; - mangleChar[Tdchar] = 'w'; - - // '@' shouldn't appear anywhere in the deco'd names - mangleChar[Tbit] = '@'; - mangleChar[Tinstance] = '@'; - mangleChar[Terror] = '@'; - mangleChar[Ttypeof] = '@'; - mangleChar[Ttuple] = 'B'; - mangleChar[Tslice] = '@'; - mangleChar[Treturn] = '@'; - - for (size_t i = 0; i < TMAX; i++) - { if (!mangleChar[i]) - fprintf(stdmsg, "ty = %zd\n", i); - assert(mangleChar[i]); - } - - // Set basic types - static TY basetab[] = - { Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64, - Tfloat32, Tfloat64, Tfloat80, - Timaginary32, Timaginary64, Timaginary80, - Tcomplex32, Tcomplex64, Tcomplex80, - Tbool, - Tascii, Twchar, Tdchar }; - - for (size_t i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++) - basic[basetab[i]] = new TypeBasic(basetab[i]); - basic[Terror] = new TypeError(); - - tvoidptr = tvoid->pointerTo(); - tstring = tchar->arrayOf(); - - // LDC - sir = _sir; - - // set size_t / ptrdiff_t types and pointer size - if (global.params.is64bit) - { - Tsize_t = Tuns64; - Tptrdiff_t = Tint64; - PTRSIZE = 8; - } - else - { - Tsize_t = Tuns32; - Tptrdiff_t = Tint32; - PTRSIZE = 4; - } - - // set real size and padding - if (global.params.targetTriple.getArch() == llvm::Triple::x86) - { - REALSIZE = 12; - REALPAD = 2; - } - else if (global.params.targetTriple.getArch() == llvm::Triple::x86_64) - { - REALSIZE = 16; - REALPAD = 6; - } - else - { - REALSIZE = 8; - REALPAD = 0; - } -} - -d_uns64 Type::size() -{ - return size(0); -} - -d_uns64 Type::size(Loc loc) -{ - error(loc, "no size for type %s", toChars()); - return 1; -} - -unsigned Type::alignsize() -{ - return size(0); -} - -Type *Type::semantic(Loc loc, Scope *sc) -{ - if (next) - next = next->semantic(loc,sc); - return merge(); -} - -Type *Type::trySemantic(Loc loc, Scope *sc) -{ - //printf("+trySemantic(%s) %d\n", toChars(), global.errors); - unsigned errors = global.startGagging(); - Type *t = semantic(loc, sc); - if (global.endGagging(errors)) // if any errors happened - { - t = NULL; - } - //printf("-trySemantic(%s) %d\n", toChars(), global.errors); - return t; -} -Type *Type::pointerTo() -{ - if (ty == Terror) - return this; - if (!pto) - { Type *t; - - t = new TypePointer(this); - pto = t->merge(); - } - return pto; -} - -Type *Type::referenceTo() -{ - if (ty == Terror) - return this; - if (!rto) - { Type *t; - - t = new TypeReference(this); - rto = t->merge(); - } - return rto; -} - -Type *Type::arrayOf() -{ - if (ty == Terror) - return this; - if (!arrayof) - { Type *t; - - t = new TypeDArray(this); - arrayof = t->merge(); - } - return arrayof; -} - -Dsymbol *Type::toDsymbol(Scope *sc) -{ - return NULL; -} - -/******************************* - * If this is a shell around another type, - * get that other type. - */ - -Type *Type::toBasetype() -{ - return this; -} - -/******************************** - * Name mangling. - */ - -void Type::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - buf->writeByte(mangleChar[ty]); - if (next) - { - assert(next != this); - //printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this->ty, next, next->ty); - next->toDecoBuffer(buf, mangle); - } -} - -/******************************** - * For pretty-printing a type. - */ - -char *Type::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - buf = new OutBuffer(); - toCBuffer(buf, NULL, &hgs); - return buf->toChars(); -} - -void Type::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - toCBuffer2(buf, hgs, 0); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -void Type::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring(toChars()); -} - -void Type::toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { const char *p; - - switch (this->mod) - { - case 0: - toCBuffer2(buf, hgs, this->mod); - break; - case MODconst: - p = "const("; - goto L1; - case MODimmutable: - p = "invariant("; - L1: buf->writestring(p); - toCBuffer2(buf, hgs, this->mod); - buf->writeByte(')'); - break; - default: - assert(0); - } - } -} - - -/************************************ - */ - -Type *Type::merge() -{ - if (ty == Terror) return this; - //printf("merge(%s)\n", toChars()); - Type *t = this; - assert(t); - if (!deco) - { - if (next) - next = next->merge(); - - OutBuffer buf; - toDecoBuffer(&buf, false); - StringValue *sv = stringtable.update((char *)buf.data, buf.offset); - if (sv->ptrvalue) - { t = (Type *) sv->ptrvalue; - assert(t->deco); - //printf("old value, deco = '%s' %p\n", t->deco, t->deco); - } - else - { - sv->ptrvalue = this; - - // we still need deco strings to be unique - // or Type::equals fails, which breaks a bunch of stuff, - // like covariant member function overloads. - OutBuffer mangle; - toDecoBuffer(&mangle, true); - StringValue* sv2 = deco_stringtable.update((char *)mangle.data, mangle.offset); - if (sv2->ptrvalue) - { Type* t2 = (Type *) sv2->ptrvalue; - assert(t2->deco); - deco = t2->deco; - } - else - { - sv2->ptrvalue = this; - deco = (char *)sv2->toDchars(); - } - //printf("new value, deco = '%s' %p\n", t->deco, t->deco); - } - } - return t; -} - -/************************************* - * This version does a merge even if the deco is already computed. - * Necessary for types that have a deco, but are not merged. - */ -Type *Type::merge2() -{ - //printf("merge2(%s)\n", toChars()); - Type *t = this; - assert(t); - if (!t->deco) - return t->merge(); - - StringValue *sv = deco_stringtable.lookup((char *)t->deco, strlen(t->deco)); - if (sv && sv->ptrvalue) - { t = (Type *) sv->ptrvalue; - assert(t->deco); - } - else - assert(0); - return t; -} - -int Type::isbit() -{ - return FALSE; -} - -int Type::isintegral() -{ - return FALSE; -} - -int Type::isfloating() -{ - return FALSE; -} - -int Type::isreal() -{ - return FALSE; -} - -int Type::isimaginary() -{ - return FALSE; -} - -int Type::iscomplex() -{ - return FALSE; -} - -int Type::isscalar() -{ - return FALSE; -} - -int Type::isunsigned() -{ - return FALSE; -} - -ClassDeclaration *Type::isClassHandle() -{ - return NULL; -} - -int Type::isscope() -{ - return FALSE; -} - -int Type::isString() -{ - return FALSE; -} - -int Type::checkBoolean() -{ - return isscalar(); -} - -/********************************* - * Check type to see if it is based on a deprecated symbol. - */ - -void Type::checkDeprecated(Loc loc, Scope *sc) -{ - for (Type *t = this; t; t = t->next) - { - Dsymbol *s = t->toDsymbol(sc); - if (s) - s->checkDeprecated(loc, sc); - } -} - - -Expression *Type::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("Type::defaultInit() '%s'\n", toChars()); -#endif - return NULL; -} - -/*************************************** - * Use when we prefer the default initializer to be a literal, - * rather than a global immutable variable. - */ -Expression *Type::defaultInitLiteral(Loc loc) -{ -#if LOGDEFAULTINIT - printf("Type::defaultInitLiteral() '%s'\n", toChars()); -#endif - return defaultInit(loc); -} - -int Type::isZeroInit(Loc loc) -{ - return 0; // assume not -} - -int Type::isBaseOf(Type *t, int *poffset) -{ - return 0; // assume not -} - -/******************************** - * Determine if 'this' can be implicitly converted - * to type 'to'. - * Returns: - * 0 can't convert - * 1 can convert using implicit conversions - * 2 this and to are the same type - */ - -MATCH Type::implicitConvTo(Type *to) -{ - //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to); - //printf("\tthis->next=%p, to->next=%p\n", this->next, to->next); - if (this == to) - return MATCHexact; -// if (to->ty == Tvoid) -// return 1; - return MATCHnomatch; -} - -Expression *Type::getProperty(Loc loc, Identifier *ident) -{ Expression *e; - -#if LOGDOTEXP - printf("Type::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars()); -#endif - if (ident == Id::__sizeof) - { - e = new IntegerExp(loc, size(loc), Type::tsize_t); - } - else if (ident == Id::size) - { - error(loc, ".size property should be replaced with .sizeof"); - e = new ErrorExp(); - } - else if (ident == Id::__xalignof) - { - e = new IntegerExp(loc, alignsize(), Type::tsize_t); - } - else if (ident == Id::typeinfo) - { - if (!global.params.useDeprecated) - error(loc, ".typeinfo deprecated, use typeid(type)"); - e = getTypeInfo(NULL); - } - else if (ident == Id::init) - { - if (ty == Tvoid) - error(loc, "void does not have an initializer"); - if (ty == Tfunction) - error(loc, "function does not have an initializer"); - e = defaultInit(loc); - } - else if (ident == Id::mangleof) - { const char *s; - if (!deco) - { s = toChars(); - error(loc, "forward reference of type %s.mangleof", s); - } - else - s = deco; - e = new StringExp(loc, (char *)s, strlen(s), 'c'); - Scope sc; - e = e->semantic(&sc); - } - else if (ident == Id::stringof) - { char *s = toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - Scope sc; - e = e->semantic(&sc); - } - else - { - Dsymbol *s = NULL; - if (ty == Tstruct || ty == Tclass || ty == Tenum || ty == Ttypedef) - s = toDsymbol(NULL); - if (s) - s = s->search_correct(ident); - if (this != Type::terror) - { - if (s) - error(loc, "no property '%s' for type '%s', did you mean '%s'?", ident->toChars(), toChars(), s->toChars()); - else - error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars()); - } - e = new ErrorExp(); - } - return e; -} - -Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ VarDeclaration *v = NULL; - -#if LOGDOTEXP - printf("Type::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (e->op == TOKdotvar) - { - DotVarExp *dv = (DotVarExp *)e; - v = dv->var->isVarDeclaration(); - } - else if (e->op == TOKvar) - { - VarExp *ve = (VarExp *)e; - v = ve->var->isVarDeclaration(); - } - if (v) - { - if (ident == Id::offset) - { - if (!global.params.useDeprecated) - error(e->loc, ".offset deprecated, use .offsetof"); - goto Loffset; - } - else if (ident == Id::offsetof) - { - Loffset: - if (v->storage_class & STCfield) - { - e = new IntegerExp(e->loc, v->offset, Type::tsize_t); - return e; - } - } - else if (ident == Id::init) - { -#if 0 - if (v->init) - { - if (v->init->isVoidInitializer()) - error(e->loc, "%s.init is void", v->toChars()); - else - { Loc loc = e->loc; - e = v->init->toExpression(); - if (e->op == TOKassign || e->op == TOKconstruct) - { - e = ((AssignExp *)e)->e2; - - /* Take care of case where we used a 0 - * to initialize the struct. - */ - if (e->type == Type::tint32 && - e->isBool(0) && - v->type->toBasetype()->ty == Tstruct) - { - e = v->type->defaultInit(loc); - } - } - e = e->ctfeInterpret(); -// if (!e->isConst()) -// error(loc, ".init cannot be evaluated at compile time"); - } - return e; - } -#endif - Expression *ex = defaultInit(e->loc); - return ex; - } - } - if (ident == Id::typeinfo) - { - if (!global.params.useDeprecated) - error(e->loc, ".typeinfo deprecated, use typeid(type)"); - e = getTypeInfo(sc); - return e; - } - if (ident == Id::stringof) - { char *s = e->toChars(); - e = new StringExp(e->loc, s, strlen(s), 'c'); - Scope sc; - e = e->semantic(&sc); - return e; - } - return getProperty(e->loc, ident); -} - -structalign_t Type::memalign(structalign_t salign) -{ - return salign; -} - -void Type::error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); -} - -void Type::warning(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::vwarning(loc, format, ap); - va_end( ap ); -} - -Identifier *Type::getTypeInfoIdent(int internal) -{ - // _init_10TypeInfo_%s - OutBuffer buf; - Identifier *id; - char *name; - int len; - - //toTypeInfoBuffer(&buf); - if (internal) - { buf.writeByte(mangleChar[ty]); - if (ty == Tarray) - buf.writeByte(mangleChar[((TypeArray *)this)->next->ty]); - } - else - toDecoBuffer(&buf, true); - len = buf.offset; - name = (char *)alloca(19 + sizeof(len) * 3 + len + 1); - buf.writeByte(0); - sprintf(name, "_D%dTypeInfo_%s6__initZ", 9 + len, buf.data); -// LDC -// it is not clear where the underscore that's stripped here is added back in -// if (global.params.isWindows) -// name++; // C mangling will add it back in - //printf("name = %s\n", name); - id = Lexer::idPool(name); - return id; -} - -TypeBasic *Type::isTypeBasic() -{ - return NULL; -} - - -void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ - //printf("Type::resolve() %s, %d\n", toChars(), ty); - Type *t = semantic(loc, sc); - *pt = t; - *pe = NULL; - *ps = NULL; -} - -/******************************* - * If one of the subtypes of this type is a TypeIdentifier, - * i.e. it's an unresolved type, return that type. - */ - -Type *Type::reliesOnTident() -{ - if (!next) - return NULL; - else - return next->reliesOnTident(); -} - -/******************************** - * We've mistakenly parsed this as a type. - * Redo it as an Expression. - * NULL if cannot. - */ - -Expression *Type::toExpression() -{ - return NULL; -} - -/*************************************** - * Return !=0 if type has pointers that need to - * be scanned by the GC during a collection cycle. - */ - -int Type::hasPointers() -{ - return FALSE; -} - -/* ============================= TypeError =========================== */ - -TypeError::TypeError() - : Type(Terror, NULL) -{ -} - -void TypeError::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->writestring("_error_"); -} - -d_uns64 TypeError::size(Loc loc) { return 1; } -Expression *TypeError::getProperty(Loc loc, Identifier *ident) { return new ErrorExp(); } -Expression *TypeError::dotExp(Scope *sc, Expression *e, Identifier *ident) { return new ErrorExp(); } -Expression *TypeError::defaultInit(Loc loc) { return new ErrorExp(); } -Expression *TypeError::defaultInitLiteral(Loc loc) { return new ErrorExp(); } - -/* ============================= TypeBasic =========================== */ - -TypeBasic::TypeBasic(TY ty) - : Type(ty, NULL) -{ const char *c; - const char *d; - unsigned flags; - -#define TFLAGSintegral 1 -#define TFLAGSfloating 2 -#define TFLAGSunsigned 4 -#define TFLAGSreal 8 -#define TFLAGSimaginary 0x10 -#define TFLAGScomplex 0x20 - - flags = 0; - switch (ty) - { - case Tvoid: d = Token::toChars(TOKvoid); - c = "void"; - break; - - case Tint8: d = Token::toChars(TOKint8); - c = "byte"; - flags |= TFLAGSintegral; - break; - - case Tuns8: d = Token::toChars(TOKuns8); - c = "ubyte"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tint16: d = Token::toChars(TOKint16); - c = "short"; - flags |= TFLAGSintegral; - break; - - case Tuns16: d = Token::toChars(TOKuns16); - c = "ushort"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tint32: d = Token::toChars(TOKint32); - c = "int"; - flags |= TFLAGSintegral; - break; - - case Tuns32: d = Token::toChars(TOKuns32); - c = "uint"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tfloat32: d = Token::toChars(TOKfloat32); - c = "float"; - flags |= TFLAGSfloating | TFLAGSreal; - break; - - case Tint64: d = Token::toChars(TOKint64); - c = "long"; - flags |= TFLAGSintegral; - break; - - case Tuns64: d = Token::toChars(TOKuns64); - c = "ulong"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tfloat64: d = Token::toChars(TOKfloat64); - c = "double"; - flags |= TFLAGSfloating | TFLAGSreal; - break; - - case Tfloat80: d = Token::toChars(TOKfloat80); - c = "real"; - flags |= TFLAGSfloating | TFLAGSreal; - break; - - case Timaginary32: d = Token::toChars(TOKimaginary32); - c = "ifloat"; - flags |= TFLAGSfloating | TFLAGSimaginary; - break; - - case Timaginary64: d = Token::toChars(TOKimaginary64); - c = "idouble"; - flags |= TFLAGSfloating | TFLAGSimaginary; - break; - - case Timaginary80: d = Token::toChars(TOKimaginary80); - c = "ireal"; - flags |= TFLAGSfloating | TFLAGSimaginary; - break; - - case Tcomplex32: d = Token::toChars(TOKcomplex32); - c = "cfloat"; - flags |= TFLAGSfloating | TFLAGScomplex; - break; - - case Tcomplex64: d = Token::toChars(TOKcomplex64); - c = "cdouble"; - flags |= TFLAGSfloating | TFLAGScomplex; - break; - - case Tcomplex80: d = Token::toChars(TOKcomplex80); - c = "creal"; - flags |= TFLAGSfloating | TFLAGScomplex; - break; - - - case Tbool: d = "bool"; - c = d; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tascii: d = Token::toChars(TOKchar); - c = "char"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Twchar: d = Token::toChars(TOKwchar); - c = "wchar"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tdchar: d = Token::toChars(TOKdchar); - c = "dchar"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - default: assert(0); - } - this->dstring = d; - this->cstring = c; - this->flags = flags; - merge(); -} - -Type *TypeBasic::syntaxCopy() -{ - // No semantic analysis done on basic types, no need to copy - return this; -} - - -char *TypeBasic::toChars() -{ - return (char *)dstring; -} - -void TypeBasic::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - //printf("TypeBasic::toCBuffer2(mod = %d, this->mod = %d)\n", mod, this->mod); - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring(dstring); -} - -d_uns64 TypeBasic::size(Loc loc) -{ unsigned size; - - //printf("TypeBasic::size()\n"); - switch (ty) - { - case Tint8: - case Tuns8: size = 1; break; - case Tint16: - case Tuns16: size = 2; break; - case Tint32: - case Tuns32: - case Tfloat32: - case Timaginary32: - size = 4; break; - case Tint64: - case Tuns64: - case Tfloat64: - case Timaginary64: - size = 8; break; - case Tfloat80: - case Timaginary80: - size = REALSIZE; break; - case Tcomplex32: - size = 8; break; - case Tcomplex64: - size = 16; break; - case Tcomplex80: - size = REALSIZE * 2; break; - - case Tvoid: - //size = Type::size(); // error message - size = 1; - break; - - case Tbool: size = 1; break; - case Tascii: size = 1; break; - case Twchar: size = 2; break; - case Tdchar: size = 4; break; - - default: - assert(0); - break; - } - //printf("TypeBasic::size() = %d\n", size); - return size; -} - -unsigned TypeBasic::alignsize() -{ -#if IN_LLVM - if (ty == Tvoid) - return 1; - return GetTypeAlignment(sir, this); -#else - unsigned sz; - - switch (ty) - { - case Tfloat80: - case Timaginary80: - case Tcomplex80: - sz = REALALIGNSIZE; - break; - -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - case Tint64: - case Tuns64: - sz = global.params.is64bit ? 8 : 4; - break; - - case Tfloat64: - case Timaginary64: - sz = global.params.is64bit ? 8 : 4; - break; - - case Tcomplex32: - sz = 4; - break; - - case Tcomplex64: - sz = global.params.is64bit ? 8 : 4; - break; -#endif - - default: - sz = size(0); - break; - } - return sz; -#endif -} - -#if IN_LLVM -unsigned TypeBasic::memalign(unsigned salign) -{ - if (global.params.targetTriple.getArch() == llvm::Triple::x86_64 && - (ty == Tfloat80 || ty == Timaginary80)) - { - return 16; - } - return Type::memalign(salign); -} -#endif - -Expression *TypeBasic::getProperty(Loc loc, Identifier *ident) -{ - Expression *e; - d_int64 ivalue; -#ifdef IN_GCC - real_t fvalue; -#else - d_float80 fvalue; -#endif - - //printf("TypeBasic::getProperty('%s')\n", ident->toChars()); - if (ident == Id::max) - { - switch (ty) - { - case Tint8: ivalue = 0x7F; goto Livalue; - case Tuns8: ivalue = 0xFF; goto Livalue; - case Tint16: ivalue = 0x7FFFUL; goto Livalue; - case Tuns16: ivalue = 0xFFFFUL; goto Livalue; - case Tint32: ivalue = 0x7FFFFFFFUL; goto Livalue; - case Tuns32: ivalue = 0xFFFFFFFFUL; goto Livalue; - case Tint64: ivalue = 0x7FFFFFFFFFFFFFFFLL; goto Livalue; - case Tuns64: ivalue = 0xFFFFFFFFFFFFFFFFULL; goto Livalue; - case Tbool: ivalue = 1; goto Livalue; - case Tchar: ivalue = 0xFF; goto Livalue; - case Twchar: ivalue = 0xFFFFUL; goto Livalue; - case Tdchar: ivalue = 0x10FFFFUL; goto Livalue; - - case Tcomplex32: - case Timaginary32: - case Tfloat32: fvalue = FLT_MAX; goto Lfvalue; - case Tcomplex64: - case Timaginary64: - case Tfloat64: fvalue = DBL_MAX; goto Lfvalue; - case Tcomplex80: - case Timaginary80: - case Tfloat80: fvalue = Port::ldbl_max; goto Lfvalue; - } - } - else if (ident == Id::min) - { - switch (ty) - { - case Tint8: ivalue = -128; goto Livalue; - case Tuns8: ivalue = 0; goto Livalue; - case Tint16: ivalue = -32768; goto Livalue; - case Tuns16: ivalue = 0; goto Livalue; - case Tint32: ivalue = -2147483647L - 1; goto Livalue; - case Tuns32: ivalue = 0; goto Livalue; - case Tint64: ivalue = (-9223372036854775807LL-1LL); goto Livalue; - case Tuns64: ivalue = 0; goto Livalue; - case Tbool: ivalue = 0; goto Livalue; - case Tchar: ivalue = 0; goto Livalue; - case Twchar: ivalue = 0; goto Livalue; - case Tdchar: ivalue = 0; goto Livalue; - - case Tcomplex32: - case Timaginary32: - case Tfloat32: fvalue = FLT_MIN; goto Lfvalue; - case Tcomplex64: - case Timaginary64: - case Tfloat64: fvalue = DBL_MIN; goto Lfvalue; - case Tcomplex80: - case Timaginary80: - case Tfloat80: fvalue = LDBL_MIN; goto Lfvalue; - } - } - else if (ident == Id::nan) - { - switch (ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - case Timaginary32: - case Timaginary64: - case Timaginary80: - case Tfloat32: - case Tfloat64: - case Tfloat80: - { - fvalue = Port::nan; - goto Lfvalue; - } - } - } - else if (ident == Id::infinity) - { - switch (ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - case Timaginary32: - case Timaginary64: - case Timaginary80: - case Tfloat32: - case Tfloat64: - case Tfloat80: - fvalue = Port::infinity; - goto Lfvalue; - } - } - else if (ident == Id::dig) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_DIG; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_DIG; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_DIG; goto Lint; - } - } - else if (ident == Id::epsilon) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: fvalue = FLT_EPSILON; goto Lfvalue; - case Tcomplex64: - case Timaginary64: - case Tfloat64: fvalue = DBL_EPSILON; goto Lfvalue; - case Tcomplex80: - case Timaginary80: - case Tfloat80: fvalue = LDBL_EPSILON; goto Lfvalue; - } - } - else if (ident == Id::mant_dig) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MANT_DIG; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MANT_DIG; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MANT_DIG; goto Lint; - } - } - else if (ident == Id::max_10_exp) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MAX_10_EXP; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MAX_10_EXP; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MAX_10_EXP; goto Lint; - } - } - else if (ident == Id::max_exp) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MAX_EXP; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MAX_EXP; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MAX_EXP; goto Lint; - } - } - else if (ident == Id::min_10_exp) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MIN_10_EXP; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MIN_10_EXP; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MIN_10_EXP; goto Lint; - } - } - else if (ident == Id::min_exp) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MIN_EXP; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MIN_EXP; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MIN_EXP; goto Lint; - } - } - -Ldefault: - return Type::getProperty(loc, ident); - -Livalue: - e = new IntegerExp(loc, ivalue, this); - return e; - -Lfvalue: - if (isreal() || isimaginary()) - e = new RealExp(loc, fvalue, this); - else - { - complex_t cvalue; - -#if __DMC__ - //((real_t *)&cvalue)[0] = fvalue; - //((real_t *)&cvalue)[1] = fvalue; - cvalue = fvalue + fvalue * I; -#else - cvalue.re = fvalue; - cvalue.im = fvalue; -#endif - //for (size_t i = 0; i < 20; i++) - // printf("%02x ", ((unsigned char *)&cvalue)[i]); - //printf("\n"); - e = new ComplexExp(loc, cvalue, this); - } - return e; - -Lint: - e = new IntegerExp(loc, ivalue, Type::tint32); - return e; -} - -Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - Type *t; - - if (ident == Id::re) - { - switch (ty) - { - case Tcomplex32: t = tfloat32; goto L1; - case Tcomplex64: t = tfloat64; goto L1; - case Tcomplex80: t = tfloat80; goto L1; - L1: - e = e->castTo(sc, t); - break; - - case Tfloat32: - case Tfloat64: - case Tfloat80: - break; - - case Timaginary32: t = tfloat32; goto L2; - case Timaginary64: t = tfloat64; goto L2; - case Timaginary80: t = tfloat80; goto L2; - L2: - e = new RealExp(e->loc, ldouble(0.0), t); - break; - - default: - return Type::getProperty(e->loc, ident); - } - } - else if (ident == Id::im) - { Type *t2; - - switch (ty) - { - case Tcomplex32: t = timaginary32; t2 = tfloat32; goto L3; - case Tcomplex64: t = timaginary64; t2 = tfloat64; goto L3; - case Tcomplex80: t = timaginary80; t2 = tfloat80; goto L3; - L3: - e = e->castTo(sc, t); - e->type = t2; - break; - - case Timaginary32: t = tfloat32; goto L4; - case Timaginary64: t = tfloat64; goto L4; - case Timaginary80: t = tfloat80; goto L4; - L4: - e->type = t; - break; - - case Tfloat32: - case Tfloat64: - case Tfloat80: - e = new RealExp(e->loc, ldouble(0.0), this); - break; - - default: - return Type::getProperty(e->loc, ident); - } - } - else - { - return Type::dotExp(sc, e, ident); - } - return e; -} - -Expression *TypeBasic::defaultInit(Loc loc) -{ dinteger_t value = 0; - -#if LOGDEFAULTINIT - printf("TypeBasic::defaultInit() '%s'\n", toChars()); -#endif - switch (ty) - { - case Tchar: - value = 0xFF; - break; - - case Twchar: - case Tdchar: - value = 0xFFFF; - break; - - case Timaginary32: - case Timaginary64: - case Timaginary80: - case Tfloat32: - case Tfloat64: - case Tfloat80: - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - return getProperty(loc, Id::nan); - - case Tvoid: - error(loc, "void does not have a default initializer"); - return new ErrorExp(); - } - return new IntegerExp(loc, value, this); -} - -int TypeBasic::isZeroInit(Loc loc) -{ - switch (ty) - { - case Tchar: - case Twchar: - case Tdchar: - case Timaginary32: - case Timaginary64: - case Timaginary80: - case Tfloat32: - case Tfloat64: - case Tfloat80: - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - return 0; // no - } - return 1; // yes -} - -int TypeBasic::isbit() -{ - return 0; -} - -int TypeBasic::isintegral() -{ - //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags); - return flags & TFLAGSintegral; -} - -int TypeBasic::isfloating() -{ - return flags & TFLAGSfloating; -} - -int TypeBasic::isreal() -{ - return flags & TFLAGSreal; -} - -int TypeBasic::isimaginary() -{ - return flags & TFLAGSimaginary; -} - -int TypeBasic::iscomplex() -{ - return flags & TFLAGScomplex; -} - -int TypeBasic::isunsigned() -{ - return flags & TFLAGSunsigned; -} - -int TypeBasic::isscalar() -{ - return flags & (TFLAGSintegral | TFLAGSfloating); -} - -MATCH TypeBasic::implicitConvTo(Type *to) -{ - //printf("TypeBasic::implicitConvTo(%s) from %s\n", to->toChars(), toChars()); - if (this == to) - return MATCHexact; - -#if DMDV2 - if (ty == to->ty) - { - return (mod == to->mod) ? MATCHexact : MATCHconst; - } -#endif - - if (ty == Tvoid || to->ty == Tvoid) - return MATCHnomatch; - if (to->ty == Tbool) - return MATCHnomatch; - if (!to->isTypeBasic()) - return MATCHnomatch; - - TypeBasic *tob = (TypeBasic *)to; - if (flags & TFLAGSintegral) - { - // Disallow implicit conversion of integers to imaginary or complex - if (tob->flags & (TFLAGSimaginary | TFLAGScomplex)) - return MATCHnomatch; - -#if DMDV2 - // If converting from integral to integral - if (1 && tob->flags & TFLAGSintegral) - { d_uns64 sz = size(0); - d_uns64 tosz = tob->size(0); - - /* Can't convert to smaller size - */ - if (sz > tosz) - return MATCHnomatch; - - /* Can't change sign if same size - */ - /*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned) - return MATCHnomatch;*/ - } -#endif - } - else if (flags & TFLAGSfloating) - { - // Disallow implicit conversion of floating point to integer - if (tob->flags & TFLAGSintegral) - return MATCHnomatch; - - assert(tob->flags & TFLAGSfloating); - - // Disallow implicit conversion from complex to non-complex - if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex)) - return MATCHnomatch; - - // Disallow implicit conversion of real or imaginary to complex - if (flags & (TFLAGSreal | TFLAGSimaginary) && - tob->flags & TFLAGScomplex) - return MATCHnomatch; - - // Disallow implicit conversion to-from real and imaginary - if ((flags & (TFLAGSreal | TFLAGSimaginary)) != - (tob->flags & (TFLAGSreal | TFLAGSimaginary))) - return MATCHnomatch; - } - return MATCHconvert; -} - -TypeBasic *TypeBasic::isTypeBasic() -{ - return (TypeBasic *)this; -} - -/***************************** TypeArray *****************************/ - -TypeArray::TypeArray(TY ty, Type *next) - : Type(ty, next) -{ -} - -Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ - Type *n = this->next->toBasetype(); // uncover any typedef's - -#if LOGDOTEXP - printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (ident == Id::reverse && (n->ty == Tchar || n->ty == Twchar)) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *adReverseChar_fd = NULL; - if(!adReverseChar_fd) { - Parameters* args = new Parameters; - Type* arrty = Type::tchar->arrayOf(); - args->push(new Parameter(STCin, arrty, NULL, NULL)); - adReverseChar_fd = FuncDeclaration::genCfunc(args, arrty, "_adReverseChar"); - } - static FuncDeclaration *adReverseWchar_fd = NULL; - if(!adReverseWchar_fd) { - Parameters* args = new Parameters; - Type* arrty = Type::twchar->arrayOf(); - args->push(new Parameter(STCin, arrty, NULL, NULL)); - adReverseWchar_fd = FuncDeclaration::genCfunc(args, arrty, "_adReverseWchar"); - } - - if(n->ty == Twchar) - ec = new VarExp(0, adReverseWchar_fd); - else - ec = new VarExp(0, adReverseChar_fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - arguments->push(e); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else if (ident == Id::sort && (n->ty == Tchar || n->ty == Twchar)) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *adSortChar_fd = NULL; - if(!adSortChar_fd) { - Parameters* args = new Parameters; - Type* arrty = Type::tchar->arrayOf(); - args->push(new Parameter(STCin, arrty, NULL, NULL)); - adSortChar_fd = FuncDeclaration::genCfunc(args, arrty, "_adSortChar"); - } - static FuncDeclaration *adSortWchar_fd = NULL; - if(!adSortWchar_fd) { - Parameters* args = new Parameters; - Type* arrty = Type::twchar->arrayOf(); - args->push(new Parameter(STCin, arrty, NULL, NULL)); - adSortWchar_fd = FuncDeclaration::genCfunc(args, arrty, "_adSortWchar"); - } - - if(n->ty == Twchar) - ec = new VarExp(0, adSortWchar_fd); - else - ec = new VarExp(0, adSortChar_fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - arguments->push(e); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else if (ident == Id::reverse || ident == Id::dup) - { - Expression *ec; - Expressions *arguments; - int size = next->size(e->loc); - int dup; - - assert(size); - dup = (ident == Id::dup); - //LDC: Build arguments. - static FuncDeclaration *adDup_fd = NULL; - if(!adDup_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL)); - args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); - adDup_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adDup); - } - static FuncDeclaration *adReverse_fd = NULL; - if(!adReverse_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); - args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); - adReverse_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adReverse); - } - - if(dup) - ec = new VarExp(0, adDup_fd); - else - ec = new VarExp(0, adReverse_fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - if (dup) - arguments->push(getTypeInfo(sc)); - - // LDC repaint array type to void[] - if (n->ty != Tvoid) { - e = new CastExp(e->loc, e, e->type); - e->type = Type::tvoid->arrayOf(); - } - arguments->push(e); - - if (!dup) - arguments->push(new IntegerExp(0, size, Type::tsize_t)); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else if (ident == Id::sort) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *adSort_fd = NULL; - if(!adSort_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); - args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL)); - adSort_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSort"); - } - - ec = new VarExp(0, adSort_fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - - // LDC repaint array type to void[] - if (n->ty != Tvoid) { - e = new CastExp(e->loc, e, e->type); - e->type = Type::tvoid->arrayOf(); - } - arguments->push(e); - // LDC, we don't support the getInternalTypeInfo - // optimization arbitrarily, not yet at least... - arguments->push(n->getTypeInfo(sc)); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else - { - e = Type::dotExp(sc, e, ident); - } - return e; -} - - -/***************************** TypeSArray *****************************/ - -TypeSArray::TypeSArray(Type *t, Expression *dim) - : TypeArray(Tsarray, t) -{ - //printf("TypeSArray(%s)\n", dim->toChars()); - this->dim = dim; -} - -Type *TypeSArray::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - Expression *e = dim->syntaxCopy(); - t = new TypeSArray(t, e); - return t; -} - -d_uns64 TypeSArray::size(Loc loc) -{ dinteger_t sz; - - if (!dim) - return Type::size(loc); - sz = dim->toInteger(); - { dinteger_t n, n2; - - n = next->size(); - n2 = n * sz; - if (n && (n2 / n) != sz) - goto Loverflow; - sz = n2; - } - return sz; - -Loverflow: - error(loc, "index %jd overflow for static array", sz); - return 1; -} - -unsigned TypeSArray::alignsize() -{ - return next->alignsize(); -} - -/************************** - * This evaluates exp while setting length to be the number - * of elements in the tuple t. - */ -Expression *semanticLength(Scope *sc, Type *t, Expression *exp) -{ - if (t->ty == Ttuple) - { ScopeDsymbol *sym = new ArrayScopeSymbol((TypeTuple *)t); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - exp = exp->semantic(sc); - - sc->pop(); - } - else - exp = exp->semantic(sc); - return exp; -} - -Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp) -{ - ScopeDsymbol *sym = new ArrayScopeSymbol(s); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - exp = exp->semantic(sc); - - sc->pop(); - return exp; -} - -void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ - //printf("TypeSArray::resolve() %s\n", toChars()); - next->resolve(loc, sc, pe, pt, ps); - //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt); - if (*pe) - { // It's really an index expression - Expression *e; - e = new IndexExp(loc, *pe, dim); - *pe = e; - } - else if (*ps) - { Dsymbol *s = *ps; - TupleDeclaration *td = s->isTupleDeclaration(); - if (td) - { - ScopeDsymbol *sym = new ArrayScopeSymbol(td); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - dim = dim->semantic(sc); - dim = dim->ctfeInterpret(); - uinteger_t d = dim->toUInteger(); - - sc = sc->pop(); - - if (d >= td->objects->dim) - { error(loc, "tuple index %ju exceeds length %u", d, td->objects->dim); - goto Ldefault; - } - Object *o = (Object *)td->objects->data[(size_t)d]; - if (o->dyncast() == DYNCAST_DSYMBOL) - { - *ps = (Dsymbol *)o; - return; - } - if (o->dyncast() == DYNCAST_EXPRESSION) - { - *ps = NULL; - *pe = (Expression *)o; - return; - } - if (o->dyncast() == DYNCAST_TYPE) - { - *ps = NULL; - *pt = (Type *)o; - return; - } - - /* Create a new TupleDeclaration which - * is a slice [d..d+1] out of the old one. - * Do it this way because TemplateInstance::semanticTiargs() - * can handle unresolved Objects this way. - */ - Objects *objects = new Objects; - objects->setDim(1); - objects->data[0] = o; - - TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects); - *ps = tds; - } - else - goto Ldefault; - } - else - { - Ldefault: - Type::resolve(loc, sc, pe, pt, ps); - } -} - -Type *TypeSArray::semantic(Loc loc, Scope *sc) -{ - //printf("TypeSArray::semantic() %s\n", toChars()); - - Type *t; - Expression *e; - Dsymbol *s; - next->resolve(loc, sc, &e, &t, &s); - if (dim && s && s->isTupleDeclaration()) - { TupleDeclaration *sd = s->isTupleDeclaration(); - - dim = semanticLength(sc, sd, dim); - dim = dim->ctfeInterpret(); - uinteger_t d = dim->toUInteger(); - - if (d >= sd->objects->dim) - { error(loc, "tuple index %ju exceeds %u", d, sd->objects->dim); - return Type::terror; - } - Object *o = (*sd->objects)[(size_t)d]; - if (o->dyncast() != DYNCAST_TYPE) - { error(loc, "%s is not a type", toChars()); - return Type::terror; - } - t = (Type *)o; - return t; - } - - next = next->semantic(loc,sc); - Type *tbn = next->toBasetype(); - - if (dim) - { dinteger_t n, n2; - - int errors = global.errors; - dim = semanticLength(sc, tbn, dim); - if (errors != global.errors) - goto Lerror; - - dim = dim->ctfeInterpret(); - if (sc && sc->parameterSpecialization && dim->op == TOKvar && - ((VarExp *)dim)->var->storage_class & STCtemplateparameter) - { - /* It could be a template parameter N which has no value yet: - * template Foo(T : T[N], size_t N); - */ - return this; - } - dinteger_t d1 = dim->toInteger(); - dim = dim->implicitCastTo(sc, tsize_t); - dim = dim->optimize(WANTvalue); - dinteger_t d2 = dim->toInteger(); - - if (dim->op == TOKerror) - goto Lerror; - - if (d1 != d2) - goto Loverflow; - - if (tbn->isintegral() || - tbn->isfloating() || - tbn->ty == Tpointer || - tbn->ty == Tarray || - tbn->ty == Tsarray || - tbn->ty == Taarray || - tbn->ty == Tclass) - { - /* Only do this for types that don't need to have semantic() - * run on them for the size, since they may be forward referenced. - */ - n = tbn->size(loc); - n2 = n * d2; - if ((int)n2 < 0) - goto Loverflow; - if (n2 >= 0x1000000) // put a 'reasonable' limit on it - goto Loverflow; - if (n && n2 / n != d2) - { - Loverflow: - error(loc, "index %jd overflow for static array", d1); - goto Lerror; - } - } - } - switch (tbn->ty) - { - case Ttuple: - { // Index the tuple to get the type - assert(dim); - TypeTuple *tt = (TypeTuple *)tbn; - uinteger_t d = dim->toUInteger(); - - if (d >= tt->arguments->dim) - { error(loc, "tuple index %ju exceeds %u", d, tt->arguments->dim); - goto Lerror; - } - Parameter *arg = tt->arguments->tdata()[(size_t)d]; - return arg->type; - } - case Tfunction: - case Tnone: - error(loc, "can't have array of %s", tbn->toChars()); - goto Lerror; - } - if (tbn->isscope()) - { error(loc, "cannot have array of auto %s", tbn->toChars()); - goto Lerror; - } - return merge(); - -Lerror: - return Type::terror; -} - -void TypeSArray::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - buf->writeByte(mangleChar[ty]); - if (dim) - buf->printf("%ju", dim->toInteger()); - if (next) - next->toDecoBuffer(buf, mangle); -} - -void TypeSArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - next->toCBuffer2(buf, hgs, this->mod); - buf->printf("[%s]", dim->toChars()); -} - -Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (ident == Id::length) - { - e = dim; - } - else if (ident == Id::ptr) - { - e = e->castTo(sc, next->pointerTo()); - } - else - { - e = TypeArray::dotExp(sc, e, ident); - } - return e; -} - -int TypeSArray::isString() -{ - TY nty = next->toBasetype()->ty; - return nty == Tchar || nty == Twchar || nty == Tdchar; -} - -structalign_t TypeSArray::memalign(structalign_t salign) -{ - return next->memalign(salign); -} - -MATCH TypeSArray::implicitConvTo(Type *to) -{ - //printf("TypeSArray::implicitConvTo()\n"); - - // Allow implicit conversion of static array to pointer or dynamic array - if ((IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer) && - (to->next->ty == Tvoid || next->equals(to->next) - /*|| to->next->isBaseOf(next)*/)) - { - return MATCHconvert; - } - if (to->ty == Tarray) - { int offset = 0; - - if (next->equals(to->next) || - (to->next->isBaseOf(next, &offset) && offset == 0) || - to->next->ty == Tvoid) - return MATCHconvert; - } -#if 0 - if (to->ty == Tsarray) - { - TypeSArray *tsa = (TypeSArray *)to; - - if (next->equals(tsa->next) && dim->equals(tsa->dim)) - { - return MATCHconvert; - } - } -#endif - return Type::implicitConvTo(to); -} - -Expression *TypeSArray::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeSArray::defaultInit() '%s'\n", toChars()); -#endif - return next->defaultInit(loc); -} - -int TypeSArray::isZeroInit(Loc loc) -{ - return next->isZeroInit(loc); -} - -Expression *TypeSArray::defaultInitLiteral(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars()); -#endif - size_t d = dim->toInteger(); - Expression *elementinit = next->defaultInitLiteral(loc); - Expressions *elements = new Expressions(); - elements->setDim(d); - for (size_t i = 0; i < d; i++) - elements->data[i] = elementinit; - ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); - ae->type = this; - return ae; -} - -Expression *TypeSArray::toExpression() -{ - Expression *e = next->toExpression(); - if (e) - { Expressions *arguments = new Expressions(); - arguments->push(dim); - e = new ArrayExp(dim->loc, e, arguments); - } - return e; -} - -int TypeSArray::hasPointers() -{ - /* Don't want to do this, because: - * struct S { T* array[0]; } - * may be a variable length struct. - */ - //if (dim->toInteger() == 0) - //return FALSE; - - if (next->ty == Tvoid) - // Arrays of void contain arbitrary data, which may include pointers - return TRUE; - else - return next->hasPointers(); -} - -/***************************** TypeDArray *****************************/ - -TypeDArray::TypeDArray(Type *t) - : TypeArray(Tarray, t) -{ - //printf("TypeDArray(t = %p)\n", t); -} - -Type *TypeDArray::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - t = new TypeDArray(t); - return t; -} - -d_uns64 TypeDArray::size(Loc loc) -{ - //printf("TypeDArray::size()\n"); - return PTRSIZE * 2; -} - -unsigned TypeDArray::alignsize() -{ - // A DArray consists of two ptr-sized values, so align it on pointer size - // boundary - return PTRSIZE; -} - -Type *TypeDArray::semantic(Loc loc, Scope *sc) -{ Type *tn = next; - - tn = next->semantic(loc,sc); - Type *tbn = tn->toBasetype(); - switch (tbn->ty) - { - case Tfunction: - case Tnone: - case Ttuple: - error(loc, "can't have array of %s", tbn->toChars()); - tn = next = tint32; - break; - } - if (tn->isscope()) - error(loc, "cannot have array of scope %s", tn->toChars()); - if (next != tn) - //deco = NULL; // redo - return tn->arrayOf(); - return merge(); -} - -void TypeDArray::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - buf->writeByte(mangleChar[ty]); - if (next) - next->toDecoBuffer(buf, mangle); -} - -void TypeDArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - next->toCBuffer2(buf, hgs, this->mod); - buf->writestring("[]"); -} - -Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (ident == Id::length) - { - if (e->op == TOKstring) - { StringExp *se = (StringExp *)e; - - return new IntegerExp(se->loc, se->len, Type::tindex); - } - if (e->op == TOKnull) - return new IntegerExp(e->loc, 0, Type::tindex); - e = new ArrayLengthExp(e->loc, e); - e->type = Type::tsize_t; - return e; - } - else if (ident == Id::ptr) - { - e = e->castTo(sc, next->pointerTo()); - return e; - } - else - { - e = TypeArray::dotExp(sc, e, ident); - } - return e; -} - -int TypeDArray::isString() -{ - TY nty = next->toBasetype()->ty; - return nty == Tchar || nty == Twchar || nty == Tdchar; -} - -MATCH TypeDArray::implicitConvTo(Type *to) -{ - //printf("TypeDArray::implicitConvTo()\n"); - - // Allow implicit conversion of array to pointer - if (IMPLICIT_ARRAY_TO_PTR && - to->ty == Tpointer && - (to->next->ty == Tvoid || next->equals(to->next) /*|| to->next->isBaseOf(next)*/)) - { - return MATCHconvert; - } - - if (to->ty == Tarray) - { int offset = 0; - - if ((to->next->isBaseOf(next, &offset) && offset == 0) || - to->next->ty == Tvoid) - return MATCHconvert; - } - return Type::implicitConvTo(to); -} - -Expression *TypeDArray::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeDArray::defaultInit() '%s'\n", toChars()); -#endif - return new NullExp(loc, this); -} - -int TypeDArray::isZeroInit(Loc loc) -{ - return 1; -} - -int TypeDArray::checkBoolean() -{ - return TRUE; -} - -int TypeDArray::hasPointers() -{ - return TRUE; -} - -/***************************** TypeAArray *****************************/ - -TypeAArray::TypeAArray(Type *t, Type *index) - : TypeArray(Taarray, t) -{ - this->index = index; - this->key = NULL; -} - -Type *TypeAArray::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - Type *ti = index->syntaxCopy(); - if (t == next && ti == index) - t = this; - else - t = new TypeAArray(t, ti); - return t; -} - -d_uns64 TypeAArray::size(Loc loc) -{ - return PTRSIZE /* * 2*/; -} - - -Type *TypeAArray::semantic(Loc loc, Scope *sc) -{ - //printf("TypeAArray::semantic() %s index->ty = %d\n", toChars(), index->ty); - - // Deal with the case where we thought the index was a type, but - // in reality it was an expression. - if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray) - { - Expression *e; - Type *t; - Dsymbol *s; - - index->resolve(loc, sc, &e, &t, &s); - if (e) - { // It was an expression - - // Rewrite as a static array - TypeSArray *tsa; - - tsa = new TypeSArray(next, e); - return tsa->semantic(loc,sc); - } - else if (t) - index = t; - else - index->error(loc, "index is not a type or an expression"); - } - else - index = index->semantic(loc,sc); - - // Compute key type; the purpose of the key type is to - // minimize the permutations of runtime library - // routines as much as possible. - key = index->toBasetype(); - switch (key->ty) - { -#if 0 - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: - key = tint32; - break; -#endif - - case Tsarray: -#if 0 - // Convert to Tarray - key = key->next->arrayOf(); -#endif - break; - case Tbool: - case Tfunction: - case Tvoid: - case Tnone: - case Ttuple: - error(loc, "can't have associative array key of %s", key->toChars()); - break; - } - next = next->semantic(loc,sc); - switch (next->toBasetype()->ty) - { - case Tfunction: - case Tvoid: - case Tnone: - error(loc, "can't have associative array of %s", next->toChars()); - break; - } - if (next->isscope()) - error(loc, "cannot have array of auto %s", next->toChars()); - - return merge(); -} - -void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ - //printf("TypeAArray::resolve() %s\n", toChars()); - - // Deal with the case where we thought the index was a type, but - // in reality it was an expression. - if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray) - { - Expression *e; - Type *t; - Dsymbol *s; - - index->resolve(loc, sc, &e, &t, &s); - if (e) - { // It was an expression - - // Rewrite as a static array - - TypeSArray *tsa = new TypeSArray(next, e); - return tsa->resolve(loc, sc, pe, pt, ps); - } - else if (t) - index = t; - else - index->error(loc, "index is not a type or an expression"); - } - Type::resolve(loc, sc, pe, pt, ps); -} - - -Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (ident == Id::length) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *aaLen_fd = NULL; - if(!aaLen_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->pointerTo(), NULL, NULL)); // FIXME: Real parameter type is AA. - aaLen_fd = FuncDeclaration::genCfunc(args, Type::tsize_t, Id::aaLen); - } - - ec = new VarExp(0, aaLen_fd); - arguments = new Expressions(); - arguments->push(e); - e = new CallExp(e->loc, ec, arguments); - e->type = aaLen_fd->type->next; - } - else if (ident == Id::keys) - { - Expression *ec; - Expressions *arguments; - int size = key->size(e->loc); - - assert(size); - //LDC: Build arguments. - static FuncDeclaration *aaKeys_fd = NULL; - if(!aaKeys_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->pointerTo(), NULL, NULL)); // FIXME: Real parameter type is AA. - args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); - aaKeys_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::aaKeys); - } - - ec = new VarExp(0, aaKeys_fd); - arguments = new Expressions(); - arguments->push(e); - arguments->push(new IntegerExp(0, size, Type::tsize_t)); - e = new CallExp(e->loc, ec, arguments); - e->type = index->arrayOf(); - } - else if (ident == Id::values) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *aaValues_fd = NULL; - if(!aaValues_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->pointerTo(), NULL, NULL)); // FIXME: Real parameter type is AA. - args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); - args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); - aaValues_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::aaValues); - } - - ec = new VarExp(0, aaValues_fd); - arguments = new Expressions(); - arguments->push(e); - size_t keysize = key->size(e->loc); - if (global.params.is64bit) - keysize = (keysize + 15) & ~15; - else - keysize = (keysize + PTRSIZE - 1) & ~(PTRSIZE - 1); - arguments->push(new IntegerExp(0, keysize, Type::tsize_t)); - arguments->push(new IntegerExp(0, next->size(e->loc), Type::tsize_t)); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else if (ident == Id::rehash) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *aaRehash_fd = NULL; - if(!aaRehash_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->pointerTo(), NULL, NULL)); // FIXME: Real parameter type is AA*. - args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL)); - aaRehash_fd = FuncDeclaration::genCfunc(args, Type::tvoidptr, Id::aaRehash); - } - - ec = new VarExp(0, aaRehash_fd); - arguments = new Expressions(); - arguments->push(e->addressOf(sc)); - arguments->push(key->getTypeInfo(sc)); // LDC doesn't support getInternalTypeInfo, see above - e = new CallExp(e->loc, ec, arguments); - e->type = this; - } - else - { - e = Type::dotExp(sc, e, ident); - } - return e; -} - -void TypeAArray::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - buf->writeByte(mangleChar[ty]); - index->toDecoBuffer(buf, mangle); - next->toDecoBuffer(buf, mangle); -} - -void TypeAArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - next->toCBuffer2(buf, hgs, this->mod); - buf->writeByte('['); - index->toCBuffer2(buf, hgs, 0); - buf->writeByte(']'); -} - -Expression *TypeAArray::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeAArray::defaultInit() '%s'\n", toChars()); -#endif - return new NullExp(loc, this); -} - -int TypeAArray::isZeroInit(Loc loc) -{ - return TRUE; -} - -int TypeAArray::checkBoolean() -{ - return TRUE; -} - -Expression *TypeAArray::toExpression() -{ - Expression *e = next->toExpression(); - if (e) - { - Expression *ei = index->toExpression(); - if (ei) - { - Expressions *arguments = new Expressions(); - arguments->push(ei); - return new ArrayExp(0, e, arguments); - } - } - return NULL; -} - -int TypeAArray::hasPointers() -{ - return TRUE; -} - -/***************************** TypePointer *****************************/ - -TypePointer::TypePointer(Type *t) - : Type(Tpointer, t) -{ -} - -Type *TypePointer::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - t = new TypePointer(t); - return t; -} - -Type *TypePointer::semantic(Loc loc, Scope *sc) -{ - if (deco) - return this; - - //printf("TypePointer::semantic()\n"); - Type *n = next->semantic(loc, sc); - switch (n->toBasetype()->ty) - { - case Ttuple: - error(loc, "can't have pointer to %s", n->toChars()); - n = tint32; - break; - } - if (n != next) - deco = NULL; - next = n; - return merge(); -} - - -d_uns64 TypePointer::size(Loc loc) -{ - return PTRSIZE; -} - -void TypePointer::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - //printf("TypePointer::toCBuffer2() next = %d\n", next->ty); - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - next->toCBuffer2(buf, hgs, this->mod); - if (next->ty != Tfunction) - buf->writeByte('*'); -} - -MATCH TypePointer::implicitConvTo(Type *to) -{ - //printf("TypePointer::implicitConvTo()\n"); - - if (this == to) - return MATCHexact; - if (to->ty == Tpointer && to->next) - { - if (to->next->ty == Tvoid) - return MATCHconvert; - -#if 0 - if (to->next->isBaseOf(next)) - return MATCHconvert; -#endif - - if (next->ty == Tfunction && to->next->ty == Tfunction) - { TypeFunction *tf; - TypeFunction *tfto; - - tf = (TypeFunction *)(next); - tfto = (TypeFunction *)(to->next); - return tfto->equals(tf) ? MATCHexact : MATCHnomatch; - } - } -// if (to->ty == Tvoid) -// return MATCHconvert; - return MATCHnomatch; -} - -int TypePointer::isscalar() -{ - return TRUE; -} - -Expression *TypePointer::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypePointer::defaultInit() '%s'\n", toChars()); -#endif - return new NullExp(loc, this); -} - -int TypePointer::isZeroInit(Loc loc) -{ - return 1; -} - -int TypePointer::hasPointers() -{ - return TRUE; -} - - -/***************************** TypeReference *****************************/ - -TypeReference::TypeReference(Type *t) - : Type(Treference, t) -{ - // BUG: what about references to static arrays? -} - -Type *TypeReference::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - t = new TypeReference(t); - return t; -} - -d_uns64 TypeReference::size(Loc loc) -{ - return PTRSIZE; -} - -void TypeReference::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - next->toCBuffer2(buf, hgs, this->mod); - buf->writeByte('&'); -} - -Expression *TypeReference::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - - // References just forward things along - return next->dotExp(sc, e, ident); -} - -Expression *TypeReference::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeReference::defaultInit() '%s'\n", toChars()); -#endif - return new NullExp(loc, this); -} - -int TypeReference::isZeroInit(Loc loc) -{ - return 1; -} - - -/***************************** TypeFunction *****************************/ - -TypeFunction::TypeFunction(Parameters *parameters, Type *treturn, int varargs, enum LINK linkage) - : Type(Tfunction, treturn) -{ -//if (!treturn) *(char*)0=0; -// assert(treturn); - this->parameters = parameters; - this->varargs = varargs; - this->linkage = linkage; - this->inuse = 0; - -#if IN_LLVM - this->funcdecl = NULL; -#endif -} - -Type *TypeFunction::syntaxCopy() -{ - Type *treturn = next ? next->syntaxCopy() : NULL; - Parameters *params = Parameter::arraySyntaxCopy(parameters); - Type *t = new TypeFunction(params, treturn, varargs, linkage); - return t; -} - -/******************************* - * Returns: - * 0 types are distinct - * 1 this is covariant with t - * 2 arguments match as far as overloading goes, - * but types are not covariant - * 3 cannot determine covariance because of forward references - */ - -int Type::covariant(Type *t) -{ -#if 0 - printf("Type::covariant(t = %s) %s\n", t->toChars(), toChars()); - printf("deco = %p, %p\n", deco, t->deco); - printf("ty = %d\n", next->ty); -#endif - - int inoutmismatch = 0; - - if (equals(t)) - goto Lcovariant; - if (ty != Tfunction || t->ty != Tfunction) - goto Ldistinct; - - { - TypeFunction *t1 = (TypeFunction *)this; - TypeFunction *t2 = (TypeFunction *)t; - - if (t1->varargs != t2->varargs) - goto Ldistinct; - - if (t1->parameters && t2->parameters) - { - size_t dim = Parameter::dim(t1->parameters); - if (dim != Parameter::dim(t2->parameters)) - goto Ldistinct; - - for (size_t i = 0; i < dim; i++) - { Parameter *arg1 = Parameter::getNth(t1->parameters, i); - Parameter *arg2 = Parameter::getNth(t2->parameters, i); - - if (!arg1->type->equals(arg2->type)) - goto Ldistinct; - if (arg1->storageClass != arg2->storageClass) - inoutmismatch = 1; - } - } - else if (t1->parameters != t2->parameters) - { - size_t dim1 = !t1->parameters ? 0 : t1->parameters->dim; - size_t dim2 = !t2->parameters ? 0 : t2->parameters->dim; - if (dim1 || dim2) - goto Ldistinct; - } - - // The argument lists match - if (inoutmismatch) - goto Lnotcovariant; - if (t1->linkage != t2->linkage) - goto Lnotcovariant; - - // Return types - Type *t1n = t1->next; - Type *t2n = t2->next; - - if (!t1n || !t2n) // happens with return type inference - goto Lnotcovariant; - - if (t1n->equals(t2n)) - goto Lcovariant; - if (t1n->ty == Tclass && t2n->ty == Tclass) - { - ClassDeclaration *cd = ((TypeClass *)t1n)->sym; - ClassDeclaration *cd2 = ((TypeClass *)t2n)->sym; - if (cd == cd2) - goto Lcovariant; - - // If t1n is forward referenced: -#if 0 - if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) -#else - if (!cd->isBaseInfoComplete()) -#endif - { - return 3; // forward references - } - } - if (t1n->implicitConvTo(t2n)) - goto Lcovariant; - - goto Lnotcovariant; - } - -Lcovariant: - //printf("\tcovaraint: 1\n"); - return 1; - -Ldistinct: - //printf("\tcovaraint: 0\n"); - return 0; - -Lnotcovariant: - //printf("\tcovaraint: 2\n"); - return 2; -} - -void TypeFunction::toDecoBuffer(OutBuffer *buf, bool mangle) -{ unsigned char mc; - - //printf("TypeFunction::toDecoBuffer() this = %p %s\n", this, toChars()); - //static int nest; if (++nest == 50) *(char*)0=0; - if (inuse) - { inuse = 2; // flag error to caller - return; - } - inuse++; - switch (linkage) - { - case LINKd: mc = 'F'; break; - case LINKc: mc = 'U'; break; - case LINKwindows: mc = 'W'; break; - case LINKpascal: mc = 'V'; break; - case LINKcpp: mc = 'R'; break; - - // LDC - case LINKintrinsic: mc = 'Q'; break; - - default: - assert(0); - } - buf->writeByte(mc); - - // LDC: if we're not producing a mangle string, add the this - // type to prevent merging different member function - if (!mangle && funcdecl) - { - if (funcdecl->needThis()) - { - AggregateDeclaration* ad = funcdecl->isMember2(); - buf->writeByte('M'); - ad->type->toDecoBuffer(buf, false); - } - /* BUG This causes problems with delegate types - On the other hand, the llvm type for nested functions *is* different - so not doing anything here may be lead to bugs! - A sane solution would be DtoType(Dsymbol)... - if (funcdecl->isNested()) - { - buf->writeByte('M'); - if (funcdecl->toParent2() && funcdecl->toParent2()->isFuncDeclaration()) - { - FuncDeclaration* fd = funcdecl->toParent2()->isFuncDeclaration(); - fd->type->toDecoBuffer(buf, false); - } - }*/ - } - - // Write argument types - Parameter::argsToDecoBuffer(buf, parameters, mangle); - //if (buf->data[buf->offset - 1] == '@') halt(); - buf->writeByte('Z' - varargs); // mark end of arg list - next->toDecoBuffer(buf, mangle); - inuse--; -} - -void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - toCBufferWithAttributes(buf, ident, hgs, this, NULL); -} - -void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TypeFunction *attrs, TemplateDeclaration *td) -{ - const char *p = NULL; - - if (inuse) - { inuse = 2; // flag error to caller - return; - } - inuse++; - if (hgs->ddoc != 1) - { - switch (linkage) - { - case LINKd: p = NULL; break; - case LINKc: p = "C "; break; - case LINKwindows: p = "Windows "; break; - case LINKpascal: p = "Pascal "; break; - case LINKcpp: p = "C++ "; break; - - // LDC - case LINKintrinsic: p = "Intrinsic"; break; - - default: - assert(0); - } - if (!hgs->hdrgen && p) - { - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - } - } - if (next && (!ident || ident->toHChars2() == ident->toChars())) - { next->toCBuffer2(buf, hgs, 0); - } - - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toHChars2()); - } - if (td) - { buf->writeByte('('); - for (size_t i = 0; i < td->origParameters->dim; i++) - { - TemplateParameter *tp = td->origParameters->tdata()[i]; - if (i) - buf->writestring(", "); - tp->toCBuffer(buf, hgs); - } - buf->writeByte(')'); - } - Parameter::argsToCBuffer(buf, hgs, parameters, varargs); - inuse--; -} - -// kind is inserted before the argument list and will usually be "function" or "delegate". -void functionToCBuffer2(TypeFunction *t, OutBuffer *buf, HdrGenState *hgs, int mod, const char *kind) -{ - if (hgs->ddoc != 1) - { - const char *p = NULL; - switch (t->linkage) - { - case LINKd: p = NULL; break; - case LINKc: p = "C"; break; - case LINKwindows: p = "Windows"; break; - case LINKpascal: p = "Pascal"; break; - case LINKcpp: p = "C++"; break; -#if IN_LLVM - case LINKintrinsic: p = "Intrinsic"; break; -#endif - default: - assert(0); - } - if (!hgs->hdrgen && p) - { - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - } - } - if (t->next) - { - t->next->toCBuffer2(buf, hgs, 0); - buf->writeByte(' '); - } - buf->writestring(kind); - Parameter::argsToCBuffer(buf, hgs, t->parameters, t->varargs); -} - -void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - //printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref); - if (inuse) - { inuse = 2; // flag error to caller - return; - } - inuse++; - - functionToCBuffer2(this, buf, hgs, mod, "function"); - - inuse--; -} - -Type *TypeFunction::semantic(Loc loc, Scope *sc) -{ - if (deco) // if semantic() already run - { - //printf("already done\n"); - return this; - } - //printf("TypeFunction::semantic() this = %p\n", this); - //printf("TypeFunction::semantic() %s, sc->stc = %x\n", toChars(), sc->stc); - - /* Copy in order to not mess up original. - * This can produce redundant copies if inferring return type, - * as semantic() will get called again on this. - */ - TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction)); - memcpy(tf, this, sizeof(TypeFunction)); - if (parameters) - { tf->parameters = (Parameters *)parameters->copy(); - for (size_t i = 0; i < parameters->dim; i++) - { Parameter *arg = parameters->tdata()[i]; - Parameter *cpy = (Parameter *)mem.malloc(sizeof(Parameter)); - memcpy(cpy, arg, sizeof(Parameter)); - tf->parameters->tdata()[i] = cpy; - } - } - - if(tf->linkage == LINKd) - tf->linkage = sc->linkage; - - if (tf->next) - { - tf->next = tf->next->semantic(loc,sc); -#if !SARRAYVALUE - if (tf->next->toBasetype()->ty == Tsarray) - { error(loc, "functions cannot return static array %s", tf->next->toChars()); - tf->next = Type::terror; - } -#endif - if (tf->next->toBasetype()->ty == Tfunction) - { error(loc, "functions cannot return a function"); - tf->next = Type::terror; - } - if (tf->next->toBasetype()->ty == Ttuple) - { error(loc, "functions cannot return a tuple"); - tf->next = Type::terror; - } - if (tf->next->isscope() && !(sc->flags & SCOPEctor)) - error(loc, "functions cannot return scope %s", tf->next->toChars()); - } - - if (tf->parameters) - { - /* Create a scope for evaluating the default arguments for the parameters - */ - Scope *argsc = sc->push(); - argsc->stc = 0; // don't inherit storage class - argsc->protection = PROTpublic; - argsc->func = NULL; - - size_t dim = Parameter::dim(tf->parameters); - for (size_t i = 0; i < dim; i++) - { Parameter *fparam = Parameter::getNth(tf->parameters, i); - - tf->inuse++; - fparam->type = fparam->type->semantic(loc, argsc); - if (tf->inuse == 1) tf->inuse--; - - // each function needs its own copy of a tuple arg, since - // they mustn't share arg flags like inreg, ... - if (fparam->type->ty == Ttuple) { - fparam->type = fparam->type->syntaxCopy(); - tf->inuse++; - fparam->type = fparam->type->semantic(loc,sc); - if (tf->inuse == 1) tf->inuse--; - } - - Type *t = fparam->type->toBasetype(); - - if (fparam->storageClass & (STCout | STCref | STClazy)) - { - if (t->ty == Tsarray) - error(loc, "cannot have out or ref parameter of type %s", t->toChars()); - } - if (!(fparam->storageClass & STClazy) && t->ty == Tvoid) - error(loc, "cannot have parameter of type %s", fparam->type->toChars()); - - if (fparam->defaultArg) - { Expression *e = fparam->defaultArg; - e = e->semantic(argsc); - e = resolveProperties(argsc, e); - if (e->op == TOKfunction) // see Bugzilla 4820 - { FuncExp *fe = (FuncExp *)e; - if (fe->fd) - { // Replace function literal with a function symbol, - // since default arg expression must be copied when used - // and copying the literal itself is wrong. - e = new VarExp(e->loc, fe->fd); - e = new AddrExp(e->loc, e); - e = e->semantic(argsc); - } - } - e = e->implicitCastTo(argsc, fparam->type); - fparam->defaultArg = e; - } - - /* If fparam after semantic() turns out to be a tuple, the number of parameters may - * change. - */ - if (t->ty == Ttuple) - { - // Propagate storage class from tuple parameters to their element-parameters. - TypeTuple *tt = (TypeTuple *)t; - if (tt->arguments) - { - size_t tdim = tt->arguments->dim; - for (size_t j = 0; j < tdim; j++) - { Parameter *narg = (Parameter *)tt->arguments->data[j]; - narg->storageClass = fparam->storageClass; - } - } - - /* Reset number of parameters, and back up one to do this arg again, - * now that it is the first element of a tuple - */ - dim = Parameter::dim(tf->parameters); - i--; - continue; - } - } - argsc->pop(); - } - if (tf->next) - tf->deco = tf->merge()->deco; - - if (tf->inuse) - { error(loc, "recursive type"); - tf->inuse = 0; - return terror; - } - - if (tf->varargs == 1 && tf->linkage != LINKd && Parameter::dim(tf->parameters) == 0) - error(loc, "variadic functions with non-D linkage must have at least one parameter"); - - /* Don't return merge(), because arg identifiers and default args - * can be different - * even though the types match - */ - return tf; -} - -/******************************** - * 'args' are being matched to function 'this' - * Determine match level. - * Returns: - * MATCHxxxx - */ - -int TypeFunction::callMatch(Expressions *args) -{ - //printf("TypeFunction::callMatch()\n"); - int match = MATCHexact; // assume exact match - - size_t nparams = Parameter::dim(parameters); - size_t nargs = args ? args->dim : 0; - if (nparams == nargs) - ; - else if (nargs > nparams) - { - if (varargs == 0) - goto Nomatch; // too many args; no match - match = MATCHconvert; // match ... with a "conversion" match level - } - - for (size_t u = 0; u < nparams; u++) - { int m; - Expression *arg; - - // BUG: what about out and ref? - - Parameter *p = Parameter::getNth(parameters, u); - assert(p); - if (u >= nargs) - { - if (p->defaultArg) - continue; - if (varargs == 2 && u + 1 == nparams) - goto L1; - goto Nomatch; // not enough arguments - } - arg = (*args)[u]; - assert(arg); - if (p->storageClass & STClazy && p->type->ty == Tvoid && arg->type->ty != Tvoid) - m = MATCHconvert; - else - m = arg->implicitConvTo(p->type); - /* prefer matching the element type rather than the array - * type when more arguments are present with T[]... - */ - if (varargs == 2 && u + 1 == nparams && nargs > nparams) - goto L1; - - //printf("\tm = %d\n", m); - if (m == MATCHnomatch) // if no match - { - L1: - if (varargs == 2 && u + 1 == nparams) // if last varargs param - { Type *tb = p->type->toBasetype(); - TypeSArray *tsa; - dinteger_t sz; - - switch (tb->ty) - { - case Tsarray: - tsa = (TypeSArray *)tb; - sz = tsa->dim->toInteger(); - if (sz != nargs - u) - goto Nomatch; - case Tarray: - for (; u < nargs; u++) - { - arg = (*args)[u]; - assert(arg); -#if 1 - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type *tret = p->isLazyArray(); - if (tret) - { - if (tb->next->equals(arg->type)) - { m = MATCHexact; - } - else - { - m = arg->implicitConvTo(tret); - if (m == MATCHnomatch) - { - if (tret->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - } - } - else - m = arg->implicitConvTo(tb->next); -#else - m = arg->implicitConvTo(tb->next); -#endif - if (m == 0) - goto Nomatch; - if (m < match) - match = m; - } - goto Ldone; - - case Tclass: - // Should see if there's a constructor match? - // Or just leave it ambiguous? - goto Ldone; - - default: - goto Nomatch; - } - } - goto Nomatch; - } - if (m < match) - match = m; // pick worst match - } - -Ldone: - //printf("match = %d\n", match); - return match; - -Nomatch: - //printf("no match\n"); - return MATCHnomatch; -} - -Type *TypeFunction::reliesOnTident() -{ - if (parameters) - { - for (size_t i = 0; i < parameters->dim; i++) - { Parameter *arg = (Parameter *)parameters->data[i]; - Type *t = arg->type->reliesOnTident(); - if (t) - return t; - } - } - return next->reliesOnTident(); -} - -Expression *TypeFunction::defaultInit(Loc loc) -{ - error(loc, "function does not have a default initializer"); - return new ErrorExp(); -} - -/***************************** TypeDelegate *****************************/ - -TypeDelegate::TypeDelegate(Type *t) - : Type(Tfunction, t) -{ - ty = Tdelegate; -} - -Type *TypeDelegate::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - t = new TypeDelegate(t); - return t; -} - -Type *TypeDelegate::semantic(Loc loc, Scope *sc) -{ - if (deco) // if semantic() already run - { - //printf("already done\n"); - return this; - } - next = next->semantic(loc,sc); - return merge(); -} - -d_uns64 TypeDelegate::size(Loc loc) -{ - return PTRSIZE * 2; -} - -// LDC added, no reason to align to 2*PTRSIZE -unsigned TypeDelegate::alignsize() -{ - // A Delegate consists of two ptr values, so align it on pointer size - // boundary -#if DMDV1 - // See Bugzilla 942 for discussion - if (!global.params.is64bit) - return PTRSIZE * 2; -#endif - return PTRSIZE; -} - -void TypeDelegate::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - - functionToCBuffer2((TypeFunction *)next, buf, hgs, mod, "delegate"); -} - -Expression *TypeDelegate::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeDelegate::defaultInit() '%s'\n", toChars()); -#endif - return new NullExp(loc, this); -} - -int TypeDelegate::isZeroInit(Loc loc) -{ - return 1; -} - -int TypeDelegate::checkBoolean() -{ - return TRUE; -} - -Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (ident == Id::ptr) - { -#if IN_LLVM - e = new GEPExp(e->loc, e, ident, 0); -#endif - e->type = tvoidptr; - return e; - } - else if (ident == Id::funcptr) - { - if (!e->isLvalue()) - { - Identifier *idtmp = Lexer::uniqueId("__dgtmp"); - VarDeclaration *tmp = new VarDeclaration(e->loc, this, idtmp, new ExpInitializer(0, e)); - tmp->storage_class |= STCctfe; - e = new DeclarationExp(e->loc, tmp); - e = new CommaExp(e->loc, e, new VarExp(e->loc, tmp)); - e = e->semantic(sc); - } -#if IN_LLVM - e = new GEPExp(e->loc, e, ident, 1); -#else - e = e->addressOf(sc); - e->type = tvoidptr; - e = new AddExp(e->loc, e, new IntegerExp(PTRSIZE)); - e->type = tvoidptr; - e = new PtrExp(e->loc, e); -#endif - e->type = next->pointerTo(); - return e; - } - else - { - e = Type::dotExp(sc, e, ident); - } - return e; -} - -int TypeDelegate::hasPointers() -{ - return TRUE; -} - - - -/***************************** TypeQualified *****************************/ - -TypeQualified::TypeQualified(TY ty, Loc loc) - : Type(ty, NULL) -{ - this->loc = loc; -} - -void TypeQualified::syntaxCopyHelper(TypeQualified *t) -{ - //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t->toChars(), toChars()); - idents.setDim(t->idents.dim); - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id = t->idents[i]; - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; - - ti = (TemplateInstance *)ti->syntaxCopy(NULL); - id = (Identifier *)ti; - } - idents[i] = id; - } -} - - -void TypeQualified::addIdent(Identifier *ident) -{ - idents.push(ident); -} - -void TypeQualified::toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs) -{ - for (size_t i = 0; i < idents.dim; i++) - { Identifier *id = idents[i]; - - buf->writeByte('.'); - - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; - ti->toCBuffer(buf, hgs); - } - else - buf->writestring(id->toChars()); - } -} - -d_uns64 TypeQualified::size(Loc loc) -{ - error(this->loc, "size of type %s is not known", toChars()); - return 1; -} - -/************************************* - * Takes an array of Identifiers and figures out if - * it represents a Type or an Expression. - * Output: - * if expression, *pe is set - * if type, *pt is set - */ - -void TypeQualified::resolveHelper(Loc loc, Scope *sc, - Dsymbol *s, Dsymbol *scopesym, - Expression **pe, Type **pt, Dsymbol **ps) -{ - VarDeclaration *v; - EnumMember *em; - TupleDeclaration *td; - Type *t; - Expression *e; - -#if 0 - printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, toChars()); - if (scopesym) - printf("\tscopesym = '%s'\n", scopesym->toChars()); -#endif - *pe = NULL; - *pt = NULL; - *ps = NULL; - if (s) - { - //printf("\t1: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - s->checkDeprecated(loc, sc); // check for deprecated aliases - s = s->toAlias(); - //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id = idents[i]; - Dsymbol *sm = s->searchX(loc, sc, id); - //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - //printf("getType = '%s'\n", s->getType()->toChars()); - if (!sm) - { - v = s->isVarDeclaration(); - if (v && id == Id::length) - { - if (v->isSameAsInitializer() && v->getExpInitializer()) - { e = v->getExpInitializer()->exp; - } - else - e = new VarExp(loc, v); - t = e->type; - if (!t) - goto Lerror; - goto L3; - } - else if (v && (id == Id::stringof || id == Id::offsetof)) - { - e = new DsymbolExp(loc, s); - do - { - id = idents.tdata()[i]; - e = new DotIdExp(loc, e, id); - } while (++i < idents.dim); - e = e->semantic(sc); - *pe = e; - return; - } - - t = s->getType(); - if (!t && s->isDeclaration()) - { t = s->isDeclaration()->type; - if (!t && s->isTupleDeclaration()) - { - e = new TupleExp(loc, s->isTupleDeclaration()); - e = e->semantic(sc); - t = e->type; - } - } - if (t) - { - sm = t->toDsymbol(sc); - if (sm) - { sm = sm->search(loc, id, 0); - if (sm) - goto L2; - } - //e = t->getProperty(loc, id); - e = new TypeExp(loc, t); - e = t->dotExp(sc, e, id); - i++; - L3: - for (; i < idents.dim; i++) - { - id = idents.tdata()[i]; - //printf("e: '%s', id: '%s', type = %p\n", e->toChars(), id->toChars(), e->type); - e = e->type->dotExp(sc, e, id); - } - if (e->op == TOKtype) - *pt = e->type; - else - *pe = e; - } - else - { - Lerror: - if (id->dyncast() == DYNCAST_DSYMBOL) - { // searchX already handles errors for template instances - assert(global.errors); - } - else - { - sm = s->search_correct(id); - if (sm) - error(loc, "identifier '%s' of '%s' is not defined, did you mean '%s %s'?", - id->toChars(), toChars(), sm->kind(), sm->toChars()); - else - error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars()); - } - *pe = new ErrorExp(); - } - return; - } - L2: - s = sm->toAlias(); - } - - v = s->isVarDeclaration(); - if (v) - { - // It's not a type, it's an expression - if (v->isSameAsInitializer() && v->getExpInitializer()) - { - ExpInitializer *ei = v->getExpInitializer(); - assert(ei); - *pe = ei->exp->copy(); // make copy so we can change loc - (*pe)->loc = loc; - } - else - { -#if 0 - WithScopeSymbol *withsym; - if (scopesym && (withsym = scopesym->isWithScopeSymbol()) != NULL) - { - // Same as wthis.ident - e = new VarExp(loc, withsym->withstate->wthis); - e = new DotIdExp(loc, e, ident); - //assert(0); // BUG: should handle this - } - else -#endif - *pe = new VarExp(loc, v); - } - return; - } - em = s->isEnumMember(); - if (em) - { - // It's not a type, it's an expression - *pe = em->value->copy(); - return; - } - -L1: - t = s->getType(); - if (!t) - { - // If the symbol is an import, try looking inside the import - Import *si; - - si = s->isImport(); - if (si) - { - s = si->search(loc, s->ident, 0); - if (s && s != si) - goto L1; - s = si; - } - *ps = s; - return; - } - if (t->ty == Tinstance && t != this && !t->deco) - { error(loc, "forward reference to '%s'", t->toChars()); - return; - } - - if (t != this) - { - if (t->reliesOnTident()) - { - if (s->scope) - t = t->semantic(loc, s->scope); - else - { - /* Attempt to find correct scope in which to evaluate t. - * Not sure if this is right or not, or if we should just - * give forward reference error if s->scope is not set. - */ - for (Scope *scx = sc; 1; scx = scx->enclosing) - { - if (!scx) - { error(loc, "forward reference to '%s'", t->toChars()); - return; - } - if (scx->scopesym == scopesym) - { - t = t->semantic(loc, scx); - break; - } - } - } - } - } - if (t->ty == Ttuple) - *pt = t; - else if (t->ty == Ttypeof) - *pt = t->semantic(loc, sc); - else - *pt = t->merge(); - } - - if (!s) - { - const char *p = toChars(); - const char *n = importHint(p); - if (n) - error(loc, "'%s' is not defined, perhaps you need to import %s; ?", p, n); - else - { - Identifier *id = new Identifier(p, TOKidentifier); - s = sc->search_correct(id); - if (s) - error(loc, "undefined identifier %s, did you mean %s %s?", p, s->kind(), s->toChars()); - else - error(loc, "undefined identifier %s", p); - } - *pt = Type::terror; - } -} - -/***************************** TypeIdentifier *****************************/ - -TypeIdentifier::TypeIdentifier(Loc loc, Identifier *ident) - : TypeQualified(Tident, loc) -{ - this->ident = ident; -} - - -Type *TypeIdentifier::syntaxCopy() -{ - TypeIdentifier *t; - - t = new TypeIdentifier(loc, ident); - t->syntaxCopyHelper(this); - return t; -} - -void TypeIdentifier::toDecoBuffer(OutBuffer *buf, bool mangle) -{ unsigned len; - char *name; - - name = ident->toChars(); - len = strlen(name); - buf->printf("%c%d%s", mangleChar[ty], len, name); - //buf->printf("%c%s", mangleChar[ty], name); -} - -void TypeIdentifier::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring(this->ident->toChars()); - toCBuffer2Helper(buf, hgs); -} - -/************************************* - * Takes an array of Identifiers and figures out if - * it represents a Type or an Expression. - * Output: - * if expression, *pe is set - * if type, *pt is set - */ - -void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ Dsymbol *s; - Dsymbol *scopesym; - - //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, toChars()); - s = sc->search(loc, ident, &scopesym); - resolveHelper(loc, sc, s, scopesym, pe, pt, ps); -} - -/***************************************** - * See if type resolves to a symbol, if so, - * return that symbol. - */ - -Dsymbol *TypeIdentifier::toDsymbol(Scope *sc) -{ - //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); - if (!sc) - return NULL; - //printf("ident = '%s'\n", ident->toChars()); - - Dsymbol *scopesym; - Dsymbol *s = sc->search(loc, ident, &scopesym); - if (s) - { - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id = (Identifier *)idents.data[i]; - s = s->searchX(loc, sc, id); - if (!s) // failed to find a symbol - { //printf("\tdidn't find a symbol\n"); - break; - } - } - } - return s; -} - -Type *TypeIdentifier::semantic(Loc loc, Scope *sc) -{ - Type *t; - Expression *e; - Dsymbol *s; - - //printf("TypeIdentifier::semantic(%s)\n", toChars()); - resolve(loc, sc, &e, &t, &s); - if (t) - { - //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco); - - if (t->ty == Ttypedef) - { TypeTypedef *tt = (TypeTypedef *)t; - - if (tt->sym->sem == 1) - error(loc, "circular reference of typedef %s", tt->toChars()); - } - } - else - { -#ifdef DEBUG - if (!global.gag) - printf("1: "); -#endif - if (s) - { - s->error(loc, "is used as a type"); - } - else - error(loc, "%s is used as a type", toChars()); - t = tvoid; - } - //t->print(); - return t; -} - -Type *TypeIdentifier::reliesOnTident() -{ - return this; -} - -Expression *TypeIdentifier::toExpression() -{ - Expression *e = new IdentifierExp(loc, ident); - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id = (Identifier *)idents.data[i]; - e = new DotIdExp(loc, e, id); - } - - return e; -} - -/***************************** TypeInstance *****************************/ - -TypeInstance::TypeInstance(Loc loc, TemplateInstance *tempinst) - : TypeQualified(Tinstance, loc) -{ - this->tempinst = tempinst; -} - -Type *TypeInstance::syntaxCopy() -{ - //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim); - TypeInstance *t; - - t = new TypeInstance(loc, (TemplateInstance *)tempinst->syntaxCopy(NULL)); - t->syntaxCopyHelper(this); - return t; -} - - -void TypeInstance::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - tempinst->toCBuffer(buf, hgs); - toCBuffer2Helper(buf, hgs); -} - -void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ - // Note close similarity to TypeIdentifier::resolve() - - Dsymbol *s; - - *pe = NULL; - *pt = NULL; - *ps = NULL; - -#if 0 - if (!idents.dim) - { - error(loc, "template instance '%s' has no identifier", toChars()); - return; - } -#endif - //id = (Identifier *)idents.data[0]; - //printf("TypeInstance::resolve(sc = %p, idents = '%s')\n", sc, id->toChars()); - s = tempinst; - if (s) - s->semantic(sc); - resolveHelper(loc, sc, s, NULL, pe, pt, ps); - //printf("pt = '%s'\n", (*pt)->toChars()); -} - -Type *TypeInstance::semantic(Loc loc, Scope *sc) -{ - Type *t; - Expression *e; - Dsymbol *s; - - //printf("TypeInstance::semantic(%s)\n", toChars()); - - if (sc->parameterSpecialization) - { - unsigned errors = global.startGagging(); - - resolve(loc, sc, &e, &t, &s); - - if (global.endGagging(errors)) - { - return this; - } - } - else - resolve(loc, sc, &e, &t, &s); - - if (!t) - { -#if 0 - if (s) printf("s = %s\n", s->kind()); - printf("2: e:%p s:%p ", e, s); -#endif - error(loc, "%s is used as a type", toChars()); - t = terror; - } - return t; -} - -Dsymbol *TypeInstance::toDsymbol(Scope *sc) -{ - Type *t; - Expression *e; - Dsymbol *s; - - //printf("TypeInstance::semantic(%s)\n", toChars()); - - if (sc->parameterSpecialization) - { - unsigned errors = global.startGagging(); - - resolve(loc, sc, &e, &t, &s); - - if (global.endGagging(errors)) - return NULL; - } - else - resolve(loc, sc, &e, &t, &s); - - return s; -} - - -/***************************** TypeTypeof *****************************/ - -TypeTypeof::TypeTypeof(Loc loc, Expression *exp) - : TypeQualified(Ttypeof, loc) -{ - this->exp = exp; - inuse = 0; -} - -Type *TypeTypeof::syntaxCopy() -{ - //printf("TypeTypeof::syntaxCopy() %s\n", toChars()); - TypeTypeof *t; - - t = new TypeTypeof(loc, exp->syntaxCopy()); - t->syntaxCopyHelper(this); - return t; -} - -Dsymbol *TypeTypeof::toDsymbol(Scope *sc) -{ - Type *t; - - t = semantic(loc, sc); - if (t == this) - return NULL; - return t->toDsymbol(sc); -} - -void TypeTypeof::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring("typeof("); - exp->toCBuffer(buf, hgs); - buf->writeByte(')'); - toCBuffer2Helper(buf, hgs); -} - -void TypeTypeof::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - assert(0); -} - -Type *TypeTypeof::semantic(Loc loc, Scope *sc) -{ Expression *e; - Type *t; - - //printf("TypeTypeof::semantic() %p\n", this); - - //static int nest; if (++nest == 50) *(char*)0=0; - if (inuse) - { - inuse = 2; - error(loc, "circular typeof definition"); - return Type::terror; - } - inuse++; - -#if 0 - /* Special case for typeof(this) and typeof(super) since both - * should work even if they are not inside a non-static member function - */ - if (exp->op == TOKthis || exp->op == TOKsuper) - { - // Find enclosing struct or class - for (Dsymbol *s = sc->parent; 1; s = s->parent) - { - ClassDeclaration *cd; - StructDeclaration *sd; - - if (!s) - { - error(loc, "%s is not in a struct or class scope", exp->toChars()); - goto Lerr; - } - cd = s->isClassDeclaration(); - if (cd) - { - if (exp->op == TOKsuper) - { - cd = cd->baseClass; - if (!cd) - { error(loc, "class %s has no 'super'", s->toChars()); - goto Lerr; - } - } - t = cd->type; - break; - } - sd = s->isStructDeclaration(); - if (sd) - { - if (exp->op == TOKsuper) - { - error(loc, "struct %s has no 'super'", sd->toChars()); - goto Lerr; - } - t = sd->type->pointerTo(); - break; - } - } - } - else -#endif - { - Scope *sc2 = sc->push(); - sc2->intypeof++; - unsigned oldspecgag = global.speculativeGag; - if (global.gag) - global.speculativeGag = global.gag; - exp = exp->semantic(sc2); - global.speculativeGag = oldspecgag; -#if DMDV2 - if (exp->type && exp->type->ty == Tfunction && - ((TypeFunction *)exp->type)->isproperty) - exp = resolveProperties(sc2, exp); -#endif - sc2->pop(); - if (exp->op == TOKtype) - { - error(loc, "argument %s to typeof is not an expression", exp->toChars()); - goto Lerr; - } - t = exp->type; - if (!t) - { - error(loc, "expression (%s) has no type", exp->toChars()); - goto Lerr; - } - if (t->ty == Ttypeof) - { error(loc, "forward reference to %s", toChars()); - goto Lerr; - } - } - - if (idents.dim) - { - Dsymbol *s = t->toDsymbol(sc); - for (size_t i = 0; i < idents.dim; i++) - { - if (!s) - break; - Identifier *id = (Identifier *)idents.data[i]; - s = s->searchX(loc, sc, id); - } - if (s) - { - t = s->getType(); - if (!t) - { error(loc, "%s is not a type", s->toChars()); - goto Lerr; - } - } - else - { error(loc, "cannot resolve .property for %s", toChars()); - goto Lerr; - } - } - inuse--; - return t; - -Lerr: - inuse--; - return terror; -} - -d_uns64 TypeTypeof::size(Loc loc) -{ - if (exp->type) - return exp->type->size(loc); - else - return TypeQualified::size(loc); -} - - - -/***************************** TypeEnum *****************************/ - -TypeEnum::TypeEnum(EnumDeclaration *sym) - : Type(Tenum, NULL) -{ - this->sym = sym; -} - -char *TypeEnum::toChars() -{ - return sym->toChars(); -} - -Type *TypeEnum::syntaxCopy() -{ - return this; -} - -Type *TypeEnum::semantic(Loc loc, Scope *sc) -{ - //sym->semantic(sc); - return merge(); -} - -d_uns64 TypeEnum::size(Loc loc) -{ - if (!sym->memtype) - { - error(loc, "enum %s is forward referenced", sym->toChars()); - return 4; - } - return sym->memtype->size(loc); -} - -unsigned TypeEnum::alignsize() -{ - if (!sym->memtype) - { -#ifdef DEBUG - printf("1: "); -#endif - error(0, "enum %s is forward referenced", sym->toChars()); - return 4; - } - return sym->memtype->alignsize(); -} - -Dsymbol *TypeEnum::toDsymbol(Scope *sc) -{ - return sym; -} - -Type *TypeEnum::toBasetype() -{ - if (sym->scope) - { // Enum is forward referenced. We don't need to resolve the whole thing, - // just the base type - if (sym->memtype) - { sym->memtype = sym->memtype->semantic(sym->loc, sym->scope); - } - else - { if (!sym->isAnonymous()) - sym->memtype = Type::tint32; - } - } - if (!sym->memtype) - { -#ifdef DEBUG - printf("2: "); -#endif - error(sym->loc, "enum %s is forward referenced", sym->toChars()); - return terror; - } - return sym->memtype->toBasetype(); -} - -void TypeEnum::toDecoBuffer(OutBuffer *buf, bool mangle) -{ char *name; - - name = sym->mangle(); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - buf->printf("%c%s", mangleChar[ty], name); -} - -void TypeEnum::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring(sym->toChars()); -} - -Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ - EnumMember *m; - Dsymbol *s; - Expression *em; - -#if LOGDOTEXP - printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars()); -#endif - if (!sym->symtab) - goto Lfwd; - s = sym->symtab->lookup(ident); - if (!s) - { - if (ident == Id::max || - ident == Id::min || - ident == Id::init || - ident == Id::mangleof || - !sym->memtype - ) - { - return getProperty(e->loc, ident); - } - return sym->memtype->dotExp(sc, e, ident); - } - m = s->isEnumMember(); - em = m->value->copy(); - em->loc = e->loc; - return em; - -Lfwd: - error(e->loc, "forward reference of enum %s.%s", toChars(), ident->toChars()); - return new IntegerExp(0, 0, Type::terror); -} - -Expression *TypeEnum::getProperty(Loc loc, Identifier *ident) -{ Expression *e; - - if (ident == Id::max) - { - if (!sym->symtab) - goto Lfwd; - e = new IntegerExp(0, sym->maxval, this); - } - else if (ident == Id::min) - { - if (!sym->symtab) - goto Lfwd; - e = new IntegerExp(0, sym->minval, this); - } - else if (ident == Id::init) - { - if (!sym->symtab) - goto Lfwd; - e = defaultInit(loc); - } - else if (ident == Id::stringof) - { char *s = toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - Scope sc; - e = e->semantic(&sc); - } - else if (ident == Id::mangleof) - { - e = Type::getProperty(loc, ident); - } - else - { - if (!sym->memtype) - goto Lfwd; - e = sym->memtype->getProperty(loc, ident); - } - return e; - -Lfwd: - error(loc, "forward reference of %s.%s", toChars(), ident->toChars()); - return new IntegerExp(0, 0, this); -} - -int TypeEnum::isintegral() -{ - return 1; -} - -int TypeEnum::isfloating() -{ - return 0; -} - -int TypeEnum::isunsigned() -{ - return sym->memtype->isunsigned(); -} - -int TypeEnum::isscalar() -{ - return 1; - //return sym->memtype->isscalar(); -} - -MATCH TypeEnum::implicitConvTo(Type *to) -{ MATCH m; - - //printf("TypeEnum::implicitConvTo()\n"); - if (this->equals(to)) - m = MATCHexact; // exact match - else if (sym->memtype->implicitConvTo(to)) - m = MATCHconvert; // match with conversions - else - m = MATCHnomatch; // no match - return m; -} - -Expression *TypeEnum::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeEnum::defaultInit() '%s'\n", toChars()); -#endif - // Initialize to first member of enum - Expression *e; - e = new IntegerExp(loc, sym->defaultval, this); - return e; -} - -int TypeEnum::isZeroInit(Loc loc) -{ - //printf("TypeEnum::isZeroInit() '%s'\n", toChars()); - if (!sym->isdone && sym->scope) - { // Enum is forward referenced. We need to resolve the whole thing. - sym->semantic(NULL); - } - if (!sym->isdone) - { -#ifdef DEBUG - printf("3: "); -#endif - error(loc, "enum %s is forward referenced", sym->toChars()); - return 0; - } - return (sym->defaultval == 0); -} - -int TypeEnum::hasPointers() -{ - return toBasetype()->hasPointers(); -} - -/***************************** TypeTypedef *****************************/ - -TypeTypedef::TypeTypedef(TypedefDeclaration *sym) - : Type(Ttypedef, NULL) -{ - this->sym = sym; -} - -Type *TypeTypedef::syntaxCopy() -{ - return this; -} - -char *TypeTypedef::toChars() -{ - return sym->toChars(); -} - -Type *TypeTypedef::semantic(Loc loc, Scope *sc) -{ - //printf("TypeTypedef::semantic(%s), sem = %d\n", toChars(), sym->sem); - int errors = global.errors; - sym->semantic(sc); - if (errors != global.errors) - return terror; - return merge(); -} - -d_uns64 TypeTypedef::size(Loc loc) -{ - return sym->basetype->size(loc); -} - -unsigned TypeTypedef::alignsize() -{ - return sym->basetype->alignsize(); -} - -Dsymbol *TypeTypedef::toDsymbol(Scope *sc) -{ - return sym; -} - -void TypeTypedef::toDecoBuffer(OutBuffer *buf, bool mangle) -{ unsigned len; - char *name; - - name = sym->mangle(); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - //len = strlen(name); - //buf->printf("%c%d%s", mangleChar[ty], len, name); - buf->printf("%c%s", mangleChar[ty], name); -} - -void TypeTypedef::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - //printf("TypeTypedef::toCBuffer2() '%s'\n", sym->toChars()); - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring(sym->toChars()); -} - -Expression *TypeTypedef::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeTypedef::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars()); -#endif - if (ident == Id::init) - { - return Type::dotExp(sc, e, ident); - } - return sym->basetype->dotExp(sc, e, ident); -} - -Expression *TypeTypedef::getProperty(Loc loc, Identifier *ident) -{ - if (ident == Id::init) - { - return Type::getProperty(loc, ident); - } - return sym->basetype->getProperty(loc, ident); -} - -int TypeTypedef::isbit() -{ - return sym->basetype->isbit(); -} - -int TypeTypedef::isintegral() -{ - //printf("TypeTypedef::isintegral()\n"); - //printf("sym = '%s'\n", sym->toChars()); - //printf("basetype = '%s'\n", sym->basetype->toChars()); - return sym->basetype->isintegral(); -} - -int TypeTypedef::isfloating() -{ - return sym->basetype->isfloating(); -} - -int TypeTypedef::isreal() -{ - return sym->basetype->isreal(); -} - -int TypeTypedef::isimaginary() -{ - return sym->basetype->isimaginary(); -} - -int TypeTypedef::iscomplex() -{ - return sym->basetype->iscomplex(); -} - -int TypeTypedef::isunsigned() -{ - return sym->basetype->isunsigned(); -} - -int TypeTypedef::isscalar() -{ - return sym->basetype->isscalar(); -} - -int TypeTypedef::checkBoolean() -{ - return sym->basetype->checkBoolean(); -} - -Type *TypeTypedef::toBasetype() -{ - if (sym->inuse) - { - sym->error("circular definition"); - sym->basetype = Type::terror; - return Type::terror; - } - sym->inuse = 1; - Type *t = sym->basetype->toBasetype(); - sym->inuse = 0; - return t; -} - -MATCH TypeTypedef::implicitConvTo(Type *to) -{ MATCH m; - - //printf("TypeTypedef::implicitConvTo()\n"); - if (this->equals(to)) - m = MATCHexact; // exact match - else if (sym->basetype->implicitConvTo(to)) - m = MATCHconvert; // match with conversions - else - m = MATCHnomatch; // no match - return m; -} - -Expression *TypeTypedef::defaultInit(Loc loc) -{ Expression *e; - Type *bt; - -#if LOGDEFAULTINIT - printf("TypeTypedef::defaultInit() '%s'\n", toChars()); -#endif - if (sym->init) - { - //sym->init->toExpression()->print(); - return sym->init->toExpression(); - } - bt = sym->basetype; - e = bt->defaultInit(loc); - e->type = this; - while (bt->ty == Tsarray) - { - e->type = bt->next; - bt = bt->next->toBasetype(); - } - return e; -} - -int TypeTypedef::isZeroInit(Loc loc) -{ - if (sym->init) - { - if (sym->init->isVoidInitializer()) - return 1; // initialize voids to 0 - Expression *e = sym->init->toExpression(); - if (e && e->isBool(FALSE)) - return 1; - return 0; // assume not - } - if (sym->inuse) - { - sym->error("circular definition"); - sym->basetype = Type::terror; - } - sym->inuse = 1; - int result = sym->basetype->isZeroInit(loc); - sym->inuse = 0; - return result; -} - -int TypeTypedef::hasPointers() -{ - return toBasetype()->hasPointers(); -} - -/***************************** TypeStruct *****************************/ - -TypeStruct::TypeStruct(StructDeclaration *sym) - : Type(Tstruct, NULL) -{ - this->sym = sym; - - // LDC - this->unaligned = 0; -} - -char *TypeStruct::toChars() -{ - //printf("sym.parent: %s, deco = %s\n", sym->parent->toChars(), deco); - TemplateInstance *ti = sym->parent->isTemplateInstance(); - if (ti && ti->toAlias() == sym) - return ti->toChars(); - return sym->toChars(); -} - -Type *TypeStruct::syntaxCopy() -{ - return this; -} - -Type *TypeStruct::semantic(Loc loc, Scope *sc) -{ - //printf("TypeStruct::semantic('%s')\n", sym->toChars()); - - /* Cannot do semantic for sym because scope chain may not - * be right. - */ - //sym->semantic(sc); - - return merge(); -} - -d_uns64 TypeStruct::size(Loc loc) -{ - return sym->size(loc); -} - -unsigned TypeStruct::alignsize() -{ unsigned sz; - - sym->size(0); // give error for forward references - sz = sym->alignsize; - if (sym->structalign == STRUCTALIGN_DEFAULT) - { - if (sz > 8) - sz = 8; - } - else if (sz > sym->structalign) - sz = sym->structalign; - return sz; -} - -Dsymbol *TypeStruct::toDsymbol(Scope *sc) -{ - return sym; -} - -void TypeStruct::toDecoBuffer(OutBuffer *buf, bool mangle) -{ unsigned len; - char *name; - - name = sym->mangle(); - //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", toChars(), name); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - //len = strlen(name); - //buf->printf("%c%d%s", mangleChar[ty], len, name); - buf->printf("%c%s", mangleChar[ty], name); -} - -void TypeStruct::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - TemplateInstance *ti = sym->parent->isTemplateInstance(); - if (ti && ti->toAlias() == sym) - buf->writestring(ti->toChars()); - else - buf->writestring(sym->toChars()); -} - -Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ - Expression *b; - VarDeclaration *v; - Dsymbol *s; - DotVarExp *de; - Declaration *d; - -#if LOGDOTEXP - printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (!sym->members) - { - error(e->loc, "struct %s is forward referenced", sym->toChars()); - return new ErrorExp(); - } - - /* If e.tupleof - */ - if (ident == Id::tupleof) - { - /* Create a TupleExp out of the fields of the struct e: - * (e.field0, e.field1, e.field2, ...) - */ - e = e->semantic(sc); // do this before turning on noaccesscheck - e->type->size(); // do semantic of type - Expressions *exps = new Expressions; - exps->reserve(sym->fields.dim); - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields[i]; - Expression *fe = new DotVarExp(e->loc, e, v); - exps->push(fe); - } - e = new TupleExp(e->loc, exps); - sc = sc->push(); - sc->noaccesscheck = 1; - e = e->semantic(sc); - sc->pop(); - return e; - } - - if (e->op == TOKdotexp) - { DotExp *de = (DotExp *)e; - - if (de->e1->op == TOKimport) - { - ScopeExp *se = (ScopeExp *)de->e1; - - s = se->sds->search(e->loc, ident, 0); - e = de->e1; - goto L1; - } - } - - s = sym->search(e->loc, ident, 0); -L1: - if (!s) - { - //return getProperty(e->loc, ident); - return Type::dotExp(sc, e, ident); - } - if (!s->isFuncDeclaration()) // because of overloading - s->checkDeprecated(e->loc, sc); - s = s->toAlias(); - - v = s->isVarDeclaration(); - if (v && v->isSameAsInitializer() && v->type->toBasetype()->ty != Tsarray) - { ExpInitializer *ei = v->getExpInitializer(); - - if (ei) - { e = ei->exp->copy(); // need to copy it if it's a StringExp - e = e->semantic(sc); - return e; - } - } - - if (s->getType()) - { - //return new DotTypeExp(e->loc, e, s); - return new TypeExp(e->loc, s->getType()); - } - - EnumMember *em = s->isEnumMember(); - if (em) - { - assert(em->value); - return em->value->copy(); - } - - TemplateMixin *tm = s->isTemplateMixin(); - if (tm) - { - Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm)); - de->type = e->type; - return de; - } - - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td) - { - e = new DotTemplateExp(e->loc, e, td); - e->semantic(sc); - return e; - } - - TemplateInstance *ti = s->isTemplateInstance(); - if (ti) - { if (!ti->semanticRun) - { - if (global.errors) - return new ErrorExp(); // TemplateInstance::semantic() will fail anyway - ti->semantic(sc); - } - s = ti->inst->toAlias(); - if (!s->isTemplateInstance()) - goto L1; - Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti)); - de->type = e->type; - return de; - } - - if (s->isImport() || s->isModule() || s->isPackage()) - { - e = new DsymbolExp(e->loc, s); - e = e->semantic(sc); - return e; - } - - d = s->isDeclaration(); -#ifdef DEBUG - if (!d) - printf("d = %s '%s'\n", s->kind(), s->toChars()); -#endif - assert(d); - - if (e->op == TOKtype) - { FuncDeclaration *fd = sc->func; - - if (d->needThis() && fd && fd->vthis && - fd->toParent2()->isStructDeclaration() == sym) - { - e = new DotVarExp(e->loc, new ThisExp(e->loc), d); - e = e->semantic(sc); - return e; - } - if (d->isTupleDeclaration()) - { - e = new TupleExp(e->loc, d->isTupleDeclaration()); - e = e->semantic(sc); - return e; - } - return new VarExp(e->loc, d); - } - - if (d->isDataseg()) - { - // (e, d) - VarExp *ve; - - accessCheck(e->loc, sc, e, d); - ve = new VarExp(e->loc, d); - e = new CommaExp(e->loc, e, ve); - e = e->semantic(sc); - return e; - } - - if (v) - { - if (v->toParent() != sym) - sym->error(e->loc, "'%s' is not a member", v->toChars()); - - // *(&e + offset) - accessCheck(e->loc, sc, e, d); -#if 0 - b = new AddrExp(e->loc, e); - b->type = e->type->pointerTo(); - b = new AddExp(e->loc, b, new IntegerExp(e->loc, v->offset, Type::tint32)); - b->type = v->type->pointerTo(); - e = new PtrExp(e->loc, b); - e->type = v->type; - return e; -#endif - } - - de = new DotVarExp(e->loc, e, d); - return de->semantic(sc); -} - -structalign_t TypeStruct::memalign(structalign_t salign) -{ - sym->size(0); // give error for forward references - return sym->structalign; -} - -Expression *TypeStruct::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeStruct::defaultInit() '%s'\n", toChars()); -#endif - Declaration *d = new StaticStructInitDeclaration(sym->loc, sym); - assert(d); - d->type = this; - return new VarExp(sym->loc, d); -} - -/*************************************** - * Use when we prefer the default initializer to be a literal, - * rather than a global immutable variable. - */ -Expression *TypeStruct::defaultInitLiteral(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars()); -#endif - Expressions *structelems = new Expressions(); - structelems->setDim(sym->fields.dim); - for (size_t j = 0; j < structelems->dim; j++) - { - VarDeclaration *vd = sym->fields[j]; - Expression *e; - if (vd->init) - { if (vd->init->isVoidInitializer()) - e = NULL; - else - e = vd->init->toExpression(); - } - else - e = vd->type->defaultInitLiteral(loc); - (*structelems)[j] = e; - } - StructLiteralExp *structinit = new StructLiteralExp(loc, (StructDeclaration *)sym, structelems); - // Why doesn't the StructLiteralExp constructor do this, when - // sym->type != NULL ? - structinit->type = sym->type; - return structinit; -} - - -int TypeStruct::isZeroInit(Loc loc) -{ - return sym->zeroInit; -} - -int TypeStruct::checkBoolean() -{ - return FALSE; -} - -int TypeStruct::hasPointers() -{ - StructDeclaration *s = sym; - - sym->size(0); // give error for forward references - if (s->members) - { - for (size_t i = 0; i < s->members->dim; i++) - { - Dsymbol *sm = (Dsymbol *)s->members->data[i]; - if (sm->hasPointers()) - return TRUE; - } - } - return FALSE; -} - - -/***************************** TypeClass *****************************/ - -TypeClass::TypeClass(ClassDeclaration *sym) - : Type(Tclass, NULL) -{ - this->sym = sym; -} - -char *TypeClass::toChars() -{ - return (char *)sym->toPrettyChars(); -} - -Type *TypeClass::syntaxCopy() -{ - return this; -} - -Type *TypeClass::semantic(Loc loc, Scope *sc) -{ - //printf("TypeClass::semantic(%s)\n", sym->toChars()); - if (deco) - return this; - //printf("\t%s\n", merge()->deco); - return merge(); -} - -d_uns64 TypeClass::size(Loc loc) -{ - return PTRSIZE; -} - -Dsymbol *TypeClass::toDsymbol(Scope *sc) -{ - return sym; -} - -void TypeClass::toDecoBuffer(OutBuffer *buf, bool mangle) -{ unsigned len; - char *name; - - name = sym->mangle(); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - //printf("TypeClass::toDecoBuffer('%s') = '%s'\n", toChars(), name); - //len = strlen(name); - //buf->printf("%c%d%s", mangleChar[ty], len, name); - buf->printf("%c%s", mangleChar[ty], name); -} - -void TypeClass::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring(sym->toChars()); -} - -Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ - VarDeclaration *v; - Dsymbol *s; - DotVarExp *de; - -#if LOGDOTEXP - printf("TypeClass::dotExp(e='%s', ident='%s')\n", e->toChars(), ident->toChars()); -#endif - - if (e->op == TOKdotexp) - { DotExp *de = (DotExp *)e; - - if (de->e1->op == TOKimport) - { - ScopeExp *se = (ScopeExp *)de->e1; - - s = se->sds->search(e->loc, ident, 0); - e = de->e1; - goto L1; - } - } - - if (ident == Id::tupleof) - { - /* Create a TupleExp - */ - e = e->semantic(sc); // do this before turning on noaccesscheck - e->type->size(); // do semantic of type - Expressions *exps = new Expressions; - exps->reserve(sym->fields.dim); - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields[i]; - // Don't include hidden 'this' pointer - if (v->isThisDeclaration()) - continue; - Expression *fe = new DotVarExp(e->loc, e, v); - exps->push(fe); - } - e = new TupleExp(e->loc, exps); - sc = sc->push(); - sc->noaccesscheck = 1; - e = e->semantic(sc); - sc->pop(); - return e; - } - - s = sym->search(e->loc, ident, 0); -L1: - if (!s) - { - // See if it's a base class - if (Dsymbol *cbase = sym->searchBase(e->loc, ident)) - { - e = new DotTypeExp(0, e, cbase); - return e; - } - - if (ident == Id::classinfo) - { - assert(ClassDeclaration::classinfo); - Type *t = ClassDeclaration::classinfo->type; - if (e->op == TOKtype || e->op == TOKdottype) - { - /* For type.classinfo, we know the classinfo - * at compile time. - */ - if (!sym->vclassinfo) - sym->vclassinfo = new ClassInfoDeclaration(sym); - e = new VarExp(e->loc, sym->vclassinfo); - e = e->addressOf(sc); - e->type = t; // do this so we don't get redundant dereference - } - else - { - /* For class objects, the classinfo reference is the first - * entry in the vtbl[] - */ -#if IN_LLVM - - Type* ct; - if (sym->isInterfaceDeclaration()) { - ct = t->pointerTo()->pointerTo()->pointerTo(); - } - else { - ct = t->pointerTo()->pointerTo(); - } - - e = e->castTo(sc, ct); - e = new PtrExp(e->loc, e); - e->type = ct->next; - e = new PtrExp(e->loc, e); - e->type = ct->next->next; - - if (sym->isInterfaceDeclaration()) - { - if (sym->isCOMinterface()) - { /* COM interface vtbl[]s are different in that the - * first entry is always pointer to QueryInterface(). - * We can't get a .classinfo for it. - */ - error(e->loc, "no .classinfo for COM interface objects"); - } - /* For an interface, the first entry in the vtbl[] - * is actually a pointer to an instance of struct Interface. - * The first member of Interface is the .classinfo, - * so add an extra pointer indirection. - */ - e = new PtrExp(e->loc, e); - e->type = ct->next->next->next; - } - } - -#else - - e = new PtrExp(e->loc, e); - e->type = t->pointerTo(); - if (sym->isInterfaceDeclaration()) - { - if (sym->isCOMinterface()) - { /* COM interface vtbl[]s are different in that the - * first entry is always pointer to QueryInterface(). - * We can't get a .classinfo for it. - */ - error(e->loc, "no .classinfo for COM interface objects"); - } - /* For an interface, the first entry in the vtbl[] - * is actually a pointer to an instance of struct Interface. - * The first member of Interface is the .classinfo, - * so add an extra pointer indirection. - */ - e->type = e->type->pointerTo(); - e = new PtrExp(e->loc, e); - e->type = t->pointerTo(); - } - e = new PtrExp(e->loc, e, t); - } - -#endif // !LDC - - return e; - } - - if (ident == Id::__vptr) - { /* The pointer to the vtbl[] - * *cast(void***)e - */ - e = e->castTo(sc, tvoidptr->pointerTo()->pointerTo()); - e = new PtrExp(e->loc, e); - e = e->semantic(sc); - return e; - } - - if (ident == Id::__monitor) - { /* The handle to the monitor (call it a void*) - * *(cast(void**)e + 1) - */ - e = e->castTo(sc, tvoidptr->pointerTo()); - e = new AddExp(e->loc, e, new IntegerExp(1)); - e = new PtrExp(e->loc, e); - e = e->semantic(sc); - return e; - } - - if (ident == Id::typeinfo) - { - if (!global.params.useDeprecated) - error(e->loc, ".typeinfo deprecated, use typeid(type)"); - return getTypeInfo(sc); - } - if (ident == Id::outer && sym->vthis) - { - s = sym->vthis; - } - else - { - //return getProperty(e->loc, ident); - return Type::dotExp(sc, e, ident); - } - } - if (!s->isFuncDeclaration()) // because of overloading - s->checkDeprecated(e->loc, sc); - s = s->toAlias(); - v = s->isVarDeclaration(); - if (v && v->isSameAsInitializer() && v->type->toBasetype()->ty != Tsarray) - { ExpInitializer *ei = v->getExpInitializer(); - - if (ei) - { e = ei->exp->copy(); // need to copy it if it's a StringExp - e = e->semantic(sc); - return e; - } - } - - if (s->getType()) - { -// if (e->op == TOKtype) - return new TypeExp(e->loc, s->getType()); -// return new DotTypeExp(e->loc, e, s); - } - - EnumMember *em = s->isEnumMember(); - if (em) - { - assert(em->value); - return em->value->copy(); - } - - TemplateMixin *tm = s->isTemplateMixin(); - if (tm) - { - Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm)); - de->type = e->type; - return de; - } - - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td) - { - e = new DotTemplateExp(e->loc, e, td); - e->semantic(sc); - return e; - } - - TemplateInstance *ti = s->isTemplateInstance(); - if (ti) - { if (!ti->semanticRun) - { - if (global.errors) - return new ErrorExp(); // TemplateInstance::semantic() will fail anyway - ti->semantic(sc); - } - s = ti->inst->toAlias(); - if (!s->isTemplateInstance()) - goto L1; - Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti)); - de->type = e->type; - return de; - } - -#if 0 // shouldn't this be here? - if (s->isImport() || s->isModule() || s->isPackage()) - { - e = new DsymbolExp(e->loc, s, 0); - e = e->semantic(sc); - return e; - } -#endif - - Declaration *d = s->isDeclaration(); - if (!d) - { - e->error("%s.%s is not a declaration", e->toChars(), ident->toChars()); - return new ErrorExp(); - } - - if (e->op == TOKtype) - { - /* It's: - * Class.d - */ - if (d->isTupleDeclaration()) - { - e = new TupleExp(e->loc, d->isTupleDeclaration()); - e = e->semantic(sc); - return e; - } - else if (d->needThis() && (hasThis(sc) || !(sc->intypeof || d->isFuncDeclaration()))) - { - if (sc->func) - { - ClassDeclaration *thiscd; - thiscd = sc->func->toParent()->isClassDeclaration(); - - if (thiscd) - { - ClassDeclaration *cd = e->type->isClassHandle(); - - if (cd == thiscd) - { - e = new ThisExp(e->loc); - e = new DotTypeExp(e->loc, e, cd); - DotVarExp *de = new DotVarExp(e->loc, e, d); - e = de->semantic(sc); - return e; - } - else if ((!cd || !cd->isBaseOf(thiscd, NULL)) && - !d->isFuncDeclaration()) - e->error("'this' is required, but %s is not a base class of %s", e->type->toChars(), thiscd->toChars()); - } - } - - /* Rewrite as: - * this.d - */ - DotVarExp *de = new DotVarExp(e->loc, new ThisExp(e->loc), d); - e = de->semantic(sc); - return e; - } - else - { - VarExp *ve = new VarExp(e->loc, d); - return ve; - } - } - - if (d->isDataseg()) - { - // (e, d) - VarExp *ve; - - accessCheck(e->loc, sc, e, d); - ve = new VarExp(e->loc, d); - e = new CommaExp(e->loc, e, ve); - e = e->semantic(sc); - return e; - } - - if (d->parent && d->toParent()->isModule()) - { - // (e, d) - VarExp *ve = new VarExp(e->loc, d); - e = new CommaExp(e->loc, e, ve); - e->type = d->type; - return e; - } - - de = new DotVarExp(e->loc, e, d); - return de->semantic(sc); -} - -ClassDeclaration *TypeClass::isClassHandle() -{ - return sym; -} - -int TypeClass::isscope() -{ - return sym->isscope; -} - -int TypeClass::isBaseOf(Type *t, int *poffset) -{ - if (t->ty == Tclass) - { ClassDeclaration *cd; - - cd = ((TypeClass *)t)->sym; - if (sym->isBaseOf(cd, poffset)) - return 1; - } - return 0; -} - -MATCH TypeClass::implicitConvTo(Type *to) -{ - //printf("TypeClass::implicitConvTo('%s')\n", to->toChars()); - if (this == to) - return MATCHexact; - - ClassDeclaration *cdto = to->isClassHandle(); - if (cdto && cdto->isBaseOf(sym, NULL)) - { //printf("'to' is base\n"); - return MATCHconvert; - } - - if (global.params.Dversion == 1) - { - // Allow conversion to (void *) - if (to->ty == Tpointer && to->next->ty == Tvoid) - return MATCHconvert; - } - - return MATCHnomatch; -} - -Expression *TypeClass::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeClass::defaultInit() '%s'\n", toChars()); -#endif - return new NullExp(loc, this); -} - -int TypeClass::isZeroInit(Loc loc) -{ - return 1; -} - -int TypeClass::checkBoolean() -{ - return TRUE; -} - -int TypeClass::hasPointers() -{ - return TRUE; -} - -/***************************** TypeTuple *****************************/ - -TypeTuple::TypeTuple(Parameters *arguments) - : Type(Ttuple, NULL) -{ - //printf("TypeTuple(this = %p)\n", this); - this->arguments = arguments; - //printf("TypeTuple() %s\n", toChars()); -#ifdef DEBUG - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { - Parameter *arg = (Parameter *)arguments->data[i]; - assert(arg && arg->type); - } - } -#endif -} - -/**************** - * Form TypeTuple from the types of the expressions. - * Assume exps[] is already tuple expanded. - */ - -TypeTuple::TypeTuple(Expressions *exps) - : Type(Ttuple, NULL) -{ - Parameters *arguments = new Parameters; - if (exps) - { - arguments->setDim(exps->dim); - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - if (e->type->ty == Ttuple) - e->error("cannot form tuple of tuples"); - Parameter *arg = new Parameter(STCin, e->type, NULL, NULL); - arguments->data[i] = (void *)arg; - } - } - this->arguments = arguments; -} - -/******************************************* - * Type tuple with 0, 1 or 2 types in it. - */ -TypeTuple::TypeTuple() - : Type(Ttuple, NULL) -{ - arguments = new Parameters(); -} - -TypeTuple::TypeTuple(Type *t1) - : Type(Ttuple, NULL) -{ - arguments = new Parameters(); - arguments->push(new Parameter(0, t1, NULL, NULL)); -} - -TypeTuple::TypeTuple(Type *t1, Type *t2) - : Type(Ttuple, NULL) -{ - arguments = new Parameters(); - arguments->push(new Parameter(0, t1, NULL, NULL)); - arguments->push(new Parameter(0, t2, NULL, NULL)); -} -Type *TypeTuple::syntaxCopy() -{ - Parameters *args = Parameter::arraySyntaxCopy(arguments); - Type *t = new TypeTuple(args); - return t; -} - -Type *TypeTuple::semantic(Loc loc, Scope *sc) -{ - //printf("TypeTuple::semantic(this = %p)\n", this); - //printf("TypeTuple::semantic() %s\n", toChars()); - if (!deco) - deco = merge()->deco; - - /* Don't return merge(), because a tuple with one type has the - * same deco as that type. - */ - return this; -} - -int TypeTuple::equals(Object *o) -{ Type *t; - - t = (Type *)o; - //printf("TypeTuple::equals(%s, %s)\n", toChars(), t->toChars()); - if (this == t) - { - return 1; - } - if (t->ty == Ttuple) - { TypeTuple *tt = (TypeTuple *)t; - - if (arguments->dim == tt->arguments->dim) - { - for (size_t i = 0; i < tt->arguments->dim; i++) - { Parameter *arg1 = (Parameter *)arguments->data[i]; - Parameter *arg2 = (Parameter *)tt->arguments->data[i]; - - if (!arg1->type->equals(arg2->type)) - return 0; - } - return 1; - } - } - return 0; -} - -Type *TypeTuple::reliesOnTident() -{ - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { - Parameter *arg = (Parameter *)arguments->data[i]; - Type *t = arg->type->reliesOnTident(); - if (t) - return t; - } - } - return NULL; -} - -void TypeTuple::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - Parameter::argsToCBuffer(buf, hgs, arguments, 0); -} - -void TypeTuple::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - //printf("TypeTuple::toDecoBuffer() this = %p\n", this); - OutBuffer buf2; - Parameter::argsToDecoBuffer(&buf2, arguments, mangle); - unsigned len = buf2.offset; - buf->printf("%c%d%.*s", mangleChar[ty], len, len, (char *)buf2.extractData()); -} - -Expression *TypeTuple::getProperty(Loc loc, Identifier *ident) -{ Expression *e; - -#if LOGDOTEXP - printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars()); -#endif - if (ident == Id::length) - { - e = new IntegerExp(loc, arguments->dim, Type::tsize_t); - } - else - { - error(loc, "no property '%s' for tuple '%s'", ident->toChars(), toChars()); - e = new IntegerExp(loc, 1, Type::tint32); - } - return e; -} - -/***************************** TypeSlice *****************************/ - -/* This is so we can slice a TypeTuple */ - -TypeSlice::TypeSlice(Type *next, Expression *lwr, Expression *upr) - : Type(Tslice, next) -{ - //printf("TypeSlice[%s .. %s]\n", lwr->toChars(), upr->toChars()); - this->lwr = lwr; - this->upr = upr; -} - -Type *TypeSlice::syntaxCopy() -{ - Type *t = new TypeSlice(next->syntaxCopy(), lwr->syntaxCopy(), upr->syntaxCopy()); - return t; -} - -Type *TypeSlice::semantic(Loc loc, Scope *sc) -{ - //printf("TypeSlice::semantic() %s\n", toChars()); - next = next->semantic(loc, sc); - //printf("next: %s\n", next->toChars()); - - Type *tbn = next->toBasetype(); - if (tbn->ty != Ttuple) - { error(loc, "can only slice tuple types, not %s", tbn->toChars()); - return Type::terror; - } - TypeTuple *tt = (TypeTuple *)tbn; - - lwr = semanticLength(sc, tbn, lwr); - lwr = lwr->ctfeInterpret(); - uinteger_t i1 = lwr->toUInteger(); - - upr = semanticLength(sc, tbn, upr); - upr = upr->ctfeInterpret(); - uinteger_t i2 = upr->toUInteger(); - - if (!(i1 <= i2 && i2 <= tt->arguments->dim)) - { error(loc, "slice [%ju..%ju] is out of range of [0..%u]", i1, i2, tt->arguments->dim); - return Type::terror; - } - - Parameters *args = new Parameters; - args->reserve(i2 - i1); - for (size_t i = i1; i < i2; i++) - { Parameter *arg = (Parameter *)tt->arguments->data[i]; - args->push(arg); - } - - Type *t = (new TypeTuple(args))->semantic(loc, sc); - return t; -} - -void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ - next->resolve(loc, sc, pe, pt, ps); - if (*pe) - { // It's really a slice expression - Expression *e; - e = new SliceExp(loc, *pe, lwr, upr); - *pe = e; - } - else if (*ps) - { Dsymbol *s = *ps; - TupleDeclaration *td = s->isTupleDeclaration(); - if (td) - { - /* It's a slice of a TupleDeclaration - */ - ScopeDsymbol *sym = new ArrayScopeSymbol(td); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - lwr = lwr->semantic(sc); - lwr = lwr->ctfeInterpret(); - uinteger_t i1 = lwr->toUInteger(); - - upr = upr->semantic(sc); - upr = upr->ctfeInterpret(); - uinteger_t i2 = upr->toUInteger(); - - sc = sc->pop(); - - if (!(i1 <= i2 && i2 <= td->objects->dim)) - { error(loc, "slice [%ju..%ju] is out of range of [0..%u]", i1, i2, td->objects->dim); - goto Ldefault; - } - - if (i1 == 0 && i2 == td->objects->dim) - { - *ps = td; - return; - } - - /* Create a new TupleDeclaration which - * is a slice [i1..i2] out of the old one. - */ - Objects *objects = new Objects; - objects->setDim(i2 - i1); - for (size_t i = 0; i < objects->dim; i++) - { - objects->data[i] = td->objects->data[(size_t)i1 + i]; - } - - TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects); - *ps = tds; - } - else - goto Ldefault; - } - else - { - Ldefault: - Type::resolve(loc, sc, pe, pt, ps); - } -} - -void TypeSlice::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - next->toCBuffer2(buf, hgs, this->mod); - - buf->printf("[%s .. ", lwr->toChars()); - buf->printf("%s]", upr->toChars()); -} - -/***************************** Parameter *****************************/ - -Parameter::Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg) -{ - this->type = type; - this->ident = ident; - this->storageClass = storageClass; - this->defaultArg = defaultArg; -} - -Parameter *Parameter::syntaxCopy() -{ - Parameter *a = new Parameter(storageClass, - type ? type->syntaxCopy() : NULL, - ident, - defaultArg ? defaultArg->syntaxCopy() : NULL); - return a; -} - -Parameters *Parameter::arraySyntaxCopy(Parameters *args) -{ Parameters *a = NULL; - - if (args) - { - a = new Parameters(); - a->setDim(args->dim); - for (size_t i = 0; i < a->dim; i++) - { Parameter *arg = (*args)[i]; - - arg = arg->syntaxCopy(); - (*a)[i] = arg; - } - } - return a; -} - -char *Parameter::argsTypesToChars(Parameters *args, int varargs) -{ - OutBuffer *buf = new OutBuffer(); - - HdrGenState hgs; - argsToCBuffer(buf, &hgs, args, varargs); - - return buf->toChars(); -} - -void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *arguments, int varargs) -{ - buf->writeByte('('); - if (arguments) - { - OutBuffer argbuf; - - for (size_t i = 0; i < arguments->dim; i++) - { - if (i) - buf->writestring(", "); - Parameter *arg = (Parameter *)arguments->data[i]; - if (arg->storageClass & STCout) - buf->writestring("out "); - else if (arg->storageClass & STCref) - buf->writestring((global.params.Dversion == 1) - ? (char *)"inout " : (char *)"ref "); - else if (arg->storageClass & STClazy) - buf->writestring("lazy "); - argbuf.reset(); - arg->type->toCBuffer(&argbuf, arg->ident, hgs); - if (arg->defaultArg) - { - argbuf.writestring(" = "); - arg->defaultArg->toCBuffer(&argbuf, hgs); - } - buf->write(&argbuf); - } - if (varargs) - { - if (arguments->dim && varargs == 1) - buf->writeByte(','); - buf->writestring("..."); - } - } - buf->writeByte(')'); -} - -static const int mangleFlag = 0x01; - -static int argsToDecoBufferDg(void *ctx, size_t n, Parameter *arg, int flags) -{ - arg->toDecoBuffer((OutBuffer *)ctx, flags & mangleFlag); - return 0; -} - -void Parameter::argsToDecoBuffer(OutBuffer *buf, Parameters *arguments, bool mangle) -{ - //printf("Parameter::argsToDecoBuffer()\n"); - // Write argument types - foreach(arguments, &argsToDecoBufferDg, buf); -} - -/**************************************** - * Determine if parameter list is really a template parameter list - * (i.e. it has auto or alias parameters) - */ - -static int isTPLDg(void *ctx, size_t n, Parameter *arg, int) -{ - if (arg->storageClass & (STCalias | STCauto | STCstatic)) - return 1; - return 0; -} - -int Parameter::isTPL(Parameters *arguments) -{ - //printf("Parameter::isTPL()\n"); - return foreach(arguments, &isTPLDg, NULL); -} - -/**************************************************** - * Determine if parameter is a lazy array of delegates. - * If so, return the return type of those delegates. - * If not, return NULL. - */ - -Type *Parameter::isLazyArray() -{ -// if (inout == Lazy) - { - Type *tb = type->toBasetype(); - if (tb->ty == Tsarray || tb->ty == Tarray) - { - Type *tel = tb->next->toBasetype(); - if (tel->ty == Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)tel; - TypeFunction *tf = (TypeFunction *)td->next; - - if (!tf->varargs && Parameter::dim(tf->parameters) == 0) - { - return tf->next; // return type of delegate - } - } - } - } - return NULL; -} - -void Parameter::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - switch (storageClass & (STCin | STCout | STCref | STClazy)) - { case 0: - case STCin: - break; - case STCout: - buf->writeByte('J'); - break; - case STCref: - buf->writeByte('K'); - break; - case STClazy: - buf->writeByte('L'); - break; - default: -#ifdef DEBUG - printf("storageClass = x%llx\n", storageClass & (STCin | STCout | STCref | STClazy)); - halt(); -#endif - assert(0); - } - type->toDecoBuffer(buf, mangle); -} - -/*************************************** - * Determine number of arguments, folding in tuples. - */ - -static int dimDg(void *ctx, size_t n, Parameter *, int) -{ - ++*(size_t *)ctx; - return 0; -} - -size_t Parameter::dim(Parameters *args) -{ - size_t n = 0; - foreach(args, &dimDg, &n); - return n; -} - -/*************************************** - * Get nth Parameter, folding in tuples. - * Returns: - * Parameter* nth Parameter - * NULL not found, *pn gets incremented by the number - * of Parameters - */ - -struct GetNthParamCtx -{ - size_t nth; - Parameter *arg; -}; - -static int getNthParamDg(void *ctx, size_t n, Parameter *arg, int) -{ - GetNthParamCtx *p = (GetNthParamCtx *)ctx; - if (n == p->nth) - { p->arg = arg; - return 1; - } - return 0; -} - -Parameter *Parameter::getNth(Parameters *args, size_t nth, size_t *pn) -{ - GetNthParamCtx ctx = { nth, NULL }; - int res = foreach(args, &getNthParamDg, &ctx); - return res ? ctx.arg : NULL; -} - -/*************************************** - * Expands tuples in args in depth first order. Calls - * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter. - * If dg returns !=0, stops and returns that value else returns 0. - * Use this function to avoid the O(N + N^2/2) complexity of - * calculating dim and calling N times getNth. - */ - -int Parameter::foreach(Parameters *args, Parameter::ForeachDg dg, void *ctx, size_t *pn, int flags) -{ - assert(dg); - if (!args) - return 0; - - size_t n = pn ? *pn : 0; // take over index - int result = 0; - for (size_t i = 0; i < args->dim; i++) - { Parameter *arg = args->tdata()[i]; - Type *t = arg->type->toBasetype(); - - if (t->ty == Ttuple) - { TypeTuple *tu = (TypeTuple *)t; - result = foreach(tu->arguments, dg, ctx, &n, flags); - } - else - result = dg(ctx, n++, arg, flags); - - if (result) - break; - } - - if (pn) - *pn = n; // update index - return result; -} diff --git a/dmd/mtype.h b/dmd/mtype.h deleted file mode 100644 index e699be9d..00000000 --- a/dmd/mtype.h +++ /dev/null @@ -1,861 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_MTYPE_H -#define DMD_MTYPE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "stringtable.h" - -#include "arraytypes.h" -#include "expression.h" - -#if IN_LLVM -#include "../ir/irfuncty.h" -namespace llvm { class Type; } -class Ir; -class IrType; -#endif - -struct Scope; -struct Identifier; -struct Expression; -struct StructDeclaration; -struct ClassDeclaration; -struct VarDeclaration; -struct EnumDeclaration; -struct TypedefDeclaration; -struct TypeInfoDeclaration; -struct Dsymbol; -struct TemplateInstance; -struct CppMangleState; -enum LINK; - -struct TypeBasic; -struct HdrGenState; -struct Parameter; - -// Back end -#if IN_GCC -union tree_node; typedef union tree_node TYPE; -typedef TYPE type; -#else -typedef struct TYPE type; -#endif -struct Symbol; -struct TypeTuple; - -enum TY -{ - Tarray, // dynamic array - Tsarray, // static array - Taarray, // associative array - Tpointer, - Treference, - Tfunction, - Tident, - Tclass, - Tstruct, - Tenum, - Ttypedef, - Tdelegate, - - Tnone, - Tvoid, - Tint8, - Tuns8, - Tint16, - Tuns16, - Tint32, - Tuns32, - Tint64, - Tuns64, - Tfloat32, - Tfloat64, - Tfloat80, - - Timaginary32, - Timaginary64, - Timaginary80, - - Tcomplex32, - Tcomplex64, - Tcomplex80, - - Tbit, - Tbool, - Tchar, - Twchar, - Tdchar, - - Terror, - Tinstance, - Ttypeof, - Ttuple, - Tslice, - Treturn, - TMAX, - Tnull -}; - -#define Tascii Tchar - -extern int Tsize_t; -extern int Tptrdiff_t; - - -struct Type : Object -{ - TY ty; - unsigned char mod; // modifiers MODxxxx - /* pick this order of numbers so switch statements work better - */ - #define MODconst 1 // type is const - #define MODimmutable 4 // type is immutable - #define MODshared 2 // type is shared - #define MODwild 8 // type is wild - #define MODmutable 0x10 // type is mutable (only used in wildcard matching) - char *deco; - Type *pto; // merged pointer to this type - Type *rto; // reference to this type - Type *arrayof; // array of this type - TypeInfoDeclaration *vtinfo; // TypeInfo object for this Type - -#if IN_DMD - type *ctype; // for back end -#endif - - #define tvoid basic[Tvoid] - #define tint8 basic[Tint8] - #define tuns8 basic[Tuns8] - #define tint16 basic[Tint16] - #define tuns16 basic[Tuns16] - #define tint32 basic[Tint32] - #define tuns32 basic[Tuns32] - #define tint64 basic[Tint64] - #define tuns64 basic[Tuns64] - #define tfloat32 basic[Tfloat32] - #define tfloat64 basic[Tfloat64] - #define tfloat80 basic[Tfloat80] - - #define timaginary32 basic[Timaginary32] - #define timaginary64 basic[Timaginary64] - #define timaginary80 basic[Timaginary80] - - #define tcomplex32 basic[Tcomplex32] - #define tcomplex64 basic[Tcomplex64] - #define tcomplex80 basic[Tcomplex80] - - #define tbit basic[Tbit] - #define tbool basic[Tbool] - #define tchar basic[Tchar] - #define twchar basic[Twchar] - #define tdchar basic[Tdchar] - - // Some special types - #define tshiftcnt tint32 // right side of shift expression -// #define tboolean tint32 // result of boolean expression - #define tboolean tbool // result of boolean expression - #define tindex tsize_t // array/ptr index - static Type *tvoidptr; // void* - static Type *tstring; // immutable(char)[] - #define terror basic[Terror] // for error recovery - - #define tsize_t basic[Tsize_t] // matches size_t alias - #define tptrdiff_t basic[Tptrdiff_t] // matches ptrdiff_t alias - #define thash_t tsize_t // matches hash_t alias - - static ClassDeclaration *typeinfo; - static ClassDeclaration *typeinfoclass; - static ClassDeclaration *typeinfointerface; - static ClassDeclaration *typeinfostruct; - static ClassDeclaration *typeinfotypedef; - static ClassDeclaration *typeinfopointer; - static ClassDeclaration *typeinfoarray; - static ClassDeclaration *typeinfostaticarray; - static ClassDeclaration *typeinfoassociativearray; - static ClassDeclaration *typeinfoenum; - static ClassDeclaration *typeinfofunction; - static ClassDeclaration *typeinfodelegate; - static ClassDeclaration *typeinfotypelist; - - static Type *basic[TMAX]; - static unsigned char mangleChar[TMAX]; - static StringTable stringtable; -#if IN_LLVM - static StringTable deco_stringtable; -#endif - - // These tables are for implicit conversion of binary ops; - // the indices are the type of operand one, followed by operand two. - static unsigned char impcnvResult[TMAX][TMAX]; - static unsigned char impcnvType1[TMAX][TMAX]; - static unsigned char impcnvType2[TMAX][TMAX]; - - // If !=0, give warning on implicit conversion - static unsigned char impcnvWarn[TMAX][TMAX]; - - Type(TY ty, Type *next); - virtual Type *syntaxCopy(); - int equals(Object *o); - int dyncast() { return DYNCAST_TYPE; } // kludge for template.isType() - int covariant(Type *t); - char *toChars(); - static char needThisPrefix(); -#if IN_LLVM - static void init(Ir*); -#else - static void init(); -#endif - d_uns64 size(); - virtual d_uns64 size(Loc loc); - virtual unsigned alignsize(); - virtual Type *semantic(Loc loc, Scope *sc); - Type *trySemantic(Loc loc, Scope *sc); - // append the mangleof or a string uniquely identifying this type to buf - virtual void toDecoBuffer(OutBuffer *buf, bool mangle); - Type *merge(); - Type *merge2(); - virtual void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - virtual void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod); - virtual int isbit(); - virtual int isintegral(); - virtual int isfloating(); // real, imaginary, or complex - virtual int isreal(); - virtual int isimaginary(); - virtual int iscomplex(); - virtual int isscalar(); - virtual int isunsigned(); - virtual int isscope(); - virtual int isString(); - virtual int checkBoolean(); // if can be converted to boolean value - void checkDeprecated(Loc loc, Scope *sc); - Type *pointerTo(); - Type *referenceTo(); - Type *arrayOf(); - virtual Dsymbol *toDsymbol(Scope *sc); - virtual Type *toBasetype(); - virtual int isBaseOf(Type *t, int *poffset); - virtual MATCH implicitConvTo(Type *to); - virtual ClassDeclaration *isClassHandle(); - virtual Expression *getProperty(Loc loc, Identifier *ident); - virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - virtual structalign_t memalign(structalign_t salign); - virtual Expression *defaultInit(Loc loc = 0); - virtual Expression *defaultInitLiteral(Loc loc); - virtual Expression *voidInitLiteral(VarDeclaration *var); - virtual int isZeroInit(Loc loc = 0); // if initializer is 0 -#if IN_DMD - virtual dt_t **toDt(dt_t **pdt); -#endif - Identifier *getTypeInfoIdent(int internal); - virtual MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Expression *getInternalTypeInfo(Scope *sc); - Expression *getTypeInfo(Scope *sc); - virtual TypeInfoDeclaration *getTypeInfoDeclaration(); - virtual int builtinTypeInfo(); - virtual Type *reliesOnTident(); - virtual Expression *toExpression(); - virtual int hasPointers(); - virtual TypeTuple *toArgTypes(); - Type *next; - Type *nextOf() { return next; } - - static void error(Loc loc, const char *format, ...) IS_PRINTF(2); - static void warning(Loc loc, const char *format, ...) IS_PRINTF(2); - -#if IN_DMD - // For backend - virtual unsigned totym(); - virtual type *toCtype(); - virtual type *toCParamtype(); - virtual Symbol *toSymbol(); -#endif - - // For eliminating dynamic_cast - virtual TypeBasic *isTypeBasic(); - -#if IN_LLVM - static Ir* sir; - IrType* irtype; -#endif -}; - -struct TypeError : Type -{ - TypeError(); - - void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - - d_uns64 size(Loc loc); - Expression *getProperty(Loc loc, Identifier *ident); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - Expression *defaultInitLiteral(Loc loc); - TypeTuple *toArgTypes(); -}; - -#if DMDV2 -struct TypeNext : Type -{ - Type *next; - - TypeNext(TY ty, Type *next); - void toDecoBuffer(OutBuffer *buf, int flag); - void checkDeprecated(Loc loc, Scope *sc); - Type *reliesOnTident(); - int hasWild(); - unsigned wildMatch(Type *targ); - Type *nextOf(); - Type *makeConst(); - Type *makeInvariant(); - Type *makeShared(); - Type *makeSharedConst(); - Type *makeWild(); - Type *makeSharedWild(); - Type *makeMutable(); - MATCH constConv(Type *to); - void transitive(); -}; -#endif - -struct TypeBasic : Type -{ - const char *dstring; - const char *cstring; - unsigned flags; - - TypeBasic(TY ty); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); -#if IN_LLVM - unsigned memalign(unsigned salign); -#endif - Expression *getProperty(Loc loc, Identifier *ident); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - char *toChars(); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - int isintegral(); - int isbit(); - int isfloating(); - int isreal(); - int isimaginary(); - int iscomplex(); - int isscalar(); - int isunsigned(); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - int builtinTypeInfo(); - TypeTuple *toArgTypes(); - - // For eliminating dynamic_cast - TypeBasic *isTypeBasic(); -}; - -struct TypeArray : Type -{ - TypeArray(TY ty, Type *next); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); -}; - -// Static array, one with a fixed dimension -struct TypeSArray : TypeArray -{ - Expression *dim; - - TypeSArray(Type *t, Expression *dim); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toDecoBuffer(OutBuffer *buf, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int isString(); - int isZeroInit(Loc loc); - structalign_t memalign(structalign_t salign); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - Expression *defaultInitLiteral(Loc loc); - Expression *voidInitLiteral(VarDeclaration *var); -#if IN_DMD - dt_t **toDt(dt_t **pdt); - dt_t **toDtElem(dt_t **pdt, Expression *e); -#endif - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Expression *toExpression(); - int hasPointers(); - TypeTuple *toArgTypes(); - -#if IN_DMD - type *toCtype(); - type *toCParamtype(); -#endif -}; - -// Dynamic array, no dimension -struct TypeDArray : TypeArray -{ - TypeDArray(Type *t); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - Type *semantic(Loc loc, Scope *sc); - void toDecoBuffer(OutBuffer *buf, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int isString(); - int isZeroInit(Loc loc); - int checkBoolean(); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int builtinTypeInfo(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeAArray : TypeArray -{ - Type *index; // key type for type checking - Type *key; // actual key type - - TypeAArray(Type *t, Type *index); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toDecoBuffer(OutBuffer *buf, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - int isZeroInit(Loc loc); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Expression *toExpression(); - int hasPointers(); - TypeTuple *toArgTypes(); - -#if IN_DMD - // Back end - Symbol *aaGetSymbol(const char *func, int flags); - - type *toCtype(); -#endif -}; - -struct TypePointer : Type -{ - TypePointer(Type *t); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - MATCH implicitConvTo(Type *to); - int isscalar(); - // LDC: pointers are unsigned - int isunsigned() { return TRUE; }; - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeReference : Type -{ - TypeReference(Type *t); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); -}; - -enum RET -{ - RETregs = 1, // returned in registers - RETstack = 2, // returned on stack -}; - -struct TypeFunction : Type -{ - Parameters *parameters; // function parameters - int varargs; // 1: T t, ...) style for variable number of arguments - // if extern (C) then this is C style va_args - // if extern (D) then D style va_args - // 2: T t ...) style for variable number of arguments - // where the args are stored in a local, and a - // dynamic array is passed to the function - enum LINK linkage; // calling convention - - int inuse; - - TypeFunction(Parameters *parameters, Type *treturn, int varargs, enum LINK linkage); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - void toDecoBuffer(OutBuffer *buf, bool mangle); - void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - void toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TypeFunction *attrs, TemplateDeclaration *td); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Type *reliesOnTident(); - - int callMatch(Expressions *toargs); -#if IN_DMD - type *toCtype(); -#endif - - enum RET retStyle(); - -#if IN_DMD - unsigned totym(); -#elif IN_LLVM - // LDC - IrFuncTy fty; - - FuncDeclaration* funcdecl; -#endif - - Expression *defaultInit(Loc loc); -}; - -struct TypeDelegate : Type -{ - TypeDelegate(Type *t); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - unsigned alignsize(); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int hasPointers(); - TypeTuple *toArgTypes(); - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeQualified : Type -{ - Loc loc; - Identifiers idents; // array of Identifier's representing ident.ident.ident etc. - - TypeQualified(TY ty, Loc loc); - void syntaxCopyHelper(TypeQualified *t); - void addIdent(Identifier *ident); - void toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs); - d_uns64 size(Loc loc); - void resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym, - Expression **pe, Type **pt, Dsymbol **ps); -}; - -struct TypeIdentifier : TypeQualified -{ - Identifier *ident; - - TypeIdentifier(Loc loc, Identifier *ident); - Type *syntaxCopy(); - //char *toChars(); - void toDecoBuffer(OutBuffer *buf, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Dsymbol *toDsymbol(Scope *sc); - Type *semantic(Loc loc, Scope *sc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - Type *reliesOnTident(); - Expression *toExpression(); -}; - -/* Similar to TypeIdentifier, but with a TemplateInstance as the root - */ -struct TypeInstance : TypeQualified -{ - TemplateInstance *tempinst; - - TypeInstance(Loc loc, TemplateInstance *tempinst); - Type *syntaxCopy(); - //char *toChars(); - //void toDecoBuffer(OutBuffer *buf, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); -}; - -struct TypeTypeof : TypeQualified -{ - Expression *exp; - int inuse; - - TypeTypeof(Loc loc, Expression *exp); - Type *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void toDecoBuffer(OutBuffer *buf, bool mangle); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); -}; - -struct TypeStruct : Type -{ - StructDeclaration *sym; - - TypeStruct(StructDeclaration *sym); - d_uns64 size(Loc loc); - unsigned alignsize(); - char *toChars(); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - structalign_t memalign(structalign_t salign); - Expression *defaultInit(Loc loc); - Expression *defaultInitLiteral(Loc loc); - Expression *voidInitLiteral(VarDeclaration *var); - int isZeroInit(Loc loc); - int checkBoolean(); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); -#elif IN_LLVM - // LDC - // cache the hasUnalignedFields check - // 0 = not checked, 1 = aligned, 2 = unaligned - int unaligned; -#endif -}; - -struct TypeEnum : Type -{ - EnumDeclaration *sym; - - TypeEnum(EnumDeclaration *sym); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - char *toChars(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *getProperty(Loc loc, Identifier *ident); - int isintegral(); - int isfloating(); - int isscalar(); - int isunsigned(); - MATCH implicitConvTo(Type *to); - Type *toBasetype(); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeTypedef : Type -{ - TypedefDeclaration *sym; - - TypeTypedef(TypedefDeclaration *sym); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - char *toChars(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *getProperty(Loc loc, Identifier *ident); - int isbit(); - int isintegral(); - int isfloating(); - int isreal(); - int isimaginary(); - int iscomplex(); - int isscalar(); - int isunsigned(); - int checkBoolean(); - Type *toBasetype(); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); - -#if IN_DMD - type *toCtype(); - type *toCParamtype(); -#endif -}; - -struct TypeClass : Type -{ - ClassDeclaration *sym; - - TypeClass(ClassDeclaration *sym); - d_uns64 size(Loc loc); - char *toChars(); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - ClassDeclaration *isClassHandle(); - int isBaseOf(Type *t, int *poffset); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - int isscope(); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); - int builtinTypeInfo(); -#if DMDV2 - Type *toHeadMutable(); - MATCH constConv(Type *to); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif -#endif - -#if IN_DMD - type *toCtype(); - - Symbol *toSymbol(); -#endif -}; - -struct TypeTuple : Type -{ - Parameters *arguments; // types making up the tuple - - TypeTuple(Parameters *arguments); - TypeTuple(Expressions *exps); - TypeTuple(); - TypeTuple(Type *t1); - TypeTuple(Type *t1, Type *t2); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - int equals(Object *o); - Type *reliesOnTident(); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void toDecoBuffer(OutBuffer *buf, bool mangle); - Expression *getProperty(Loc loc, Identifier *ident); - TypeInfoDeclaration *getTypeInfoDeclaration(); -}; - -struct TypeSlice : Type -{ - Expression *lwr; - Expression *upr; - - TypeSlice(Type *next, Expression *lwr, Expression *upr); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); -}; - -/**************************************************************/ - -//enum InOut { None, In, Out, InOut, Lazy }; - -struct Parameter : Object -{ - //enum InOut inout; - StorageClass storageClass; - Type *type; - Identifier *ident; - Expression *defaultArg; - - Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg); - Parameter *syntaxCopy(); - Type *isLazyArray(); - void toDecoBuffer(OutBuffer *buf, bool mangle); - static Parameters *arraySyntaxCopy(Parameters *args); - static char *argsTypesToChars(Parameters *args, int varargs); - static void argsCppMangle(OutBuffer *buf, CppMangleState *cms, Parameters *arguments, int varargs); - static void argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *arguments, int varargs); - static void argsToDecoBuffer(OutBuffer *buf, Parameters *arguments, bool mangle); - static int isTPL(Parameters *arguments); - static size_t dim(Parameters *arguments); - static Parameter *getNth(Parameters *arguments, size_t nth, size_t *pn = NULL); - - typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param, int flags); - static int foreach(Parameters *args, ForeachDg dg, void *ctx, size_t *pn=NULL, int flags = 0); -}; - -extern int PTRSIZE; -extern int REALSIZE; -extern int REALPAD; -extern int Tsize_t; -extern int Tptrdiff_t; - -int arrayTypeCompatible(Loc loc, Type *t1, Type *t2); - -#endif /* DMD_MTYPE_H */ diff --git a/dmd/opover.c b/dmd/opover.c deleted file mode 100644 index eaa7841c..00000000 --- a/dmd/opover.c +++ /dev/null @@ -1,787 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include // memset() -#if _MSC_VER -#include -#else -#include -#endif - -#include "rmem.h" - -//#include "port.h" -#include "mtype.h" -#include "init.h" -#include "expression.h" -#include "id.h" -#include "declaration.h" -#include "aggregate.h" -#include "template.h" -#include "scope.h" - -static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id); -static void inferApplyArgTypesX(Module* from, FuncDeclaration *fstart, Parameters *arguments); -static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments); -static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments); - -/******************************** Expression **************************/ - - -/*********************************** - * Determine if operands of binary op can be reversed - * to fit operator overload. - */ - -int Expression::isCommutative() -{ - return FALSE; // default is no reverse -} - -/*********************************** - * Get Identifier for operator overload. - */ - -Identifier *Expression::opId() -{ - assert(0); - return NULL; -} - -/*********************************** - * Get Identifier for reverse operator overload, - * NULL if not supported for this operator. - */ - -Identifier *Expression::opId_r() -{ - return NULL; -} - -/************************* Operators *****************************/ - -Identifier *UAddExp::opId() { return Id::uadd; } - -Identifier *NegExp::opId() { return Id::neg; } - -Identifier *ComExp::opId() { return Id::com; } - -Identifier *CastExp::opId() { return Id::cast; } - -Identifier *InExp::opId() { return Id::opIn; } -Identifier *InExp::opId_r() { return Id::opIn_r; } - -Identifier *PostExp::opId() { return (op == TOKplusplus) - ? Id::postinc - : Id::postdec; } - -int AddExp::isCommutative() { return TRUE; } -Identifier *AddExp::opId() { return Id::add; } -Identifier *AddExp::opId_r() { return Id::add_r; } - -Identifier *MinExp::opId() { return Id::sub; } -Identifier *MinExp::opId_r() { return Id::sub_r; } - -int MulExp::isCommutative() { return TRUE; } -Identifier *MulExp::opId() { return Id::mul; } -Identifier *MulExp::opId_r() { return Id::mul_r; } - -Identifier *DivExp::opId() { return Id::div; } -Identifier *DivExp::opId_r() { return Id::div_r; } - -Identifier *ModExp::opId() { return Id::mod; } -Identifier *ModExp::opId_r() { return Id::mod_r; } - -Identifier *ShlExp::opId() { return Id::shl; } -Identifier *ShlExp::opId_r() { return Id::shl_r; } - -Identifier *ShrExp::opId() { return Id::shr; } -Identifier *ShrExp::opId_r() { return Id::shr_r; } - -Identifier *UshrExp::opId() { return Id::ushr; } -Identifier *UshrExp::opId_r() { return Id::ushr_r; } - -int AndExp::isCommutative() { return TRUE; } -Identifier *AndExp::opId() { return Id::iand; } -Identifier *AndExp::opId_r() { return Id::iand_r; } - -int OrExp::isCommutative() { return TRUE; } -Identifier *OrExp::opId() { return Id::ior; } -Identifier *OrExp::opId_r() { return Id::ior_r; } - -int XorExp::isCommutative() { return TRUE; } -Identifier *XorExp::opId() { return Id::ixor; } -Identifier *XorExp::opId_r() { return Id::ixor_r; } - -Identifier *CatExp::opId() { return Id::cat; } -Identifier *CatExp::opId_r() { return Id::cat_r; } - -Identifier * AssignExp::opId() { return Id::assign; } -Identifier * AddAssignExp::opId() { return Id::addass; } -Identifier * MinAssignExp::opId() { return Id::subass; } -Identifier * MulAssignExp::opId() { return Id::mulass; } -Identifier * DivAssignExp::opId() { return Id::divass; } -Identifier * ModAssignExp::opId() { return Id::modass; } -Identifier * AndAssignExp::opId() { return Id::andass; } -Identifier * OrAssignExp::opId() { return Id::orass; } -Identifier * XorAssignExp::opId() { return Id::xorass; } -Identifier * ShlAssignExp::opId() { return Id::shlass; } -Identifier * ShrAssignExp::opId() { return Id::shrass; } -Identifier *UshrAssignExp::opId() { return Id::ushrass; } -Identifier * CatAssignExp::opId() { return Id::catass; } - -int EqualExp::isCommutative() { return TRUE; } -Identifier *EqualExp::opId() { return Id::eq; } - -int CmpExp::isCommutative() { return TRUE; } -Identifier *CmpExp::opId() { return Id::cmp; } - -Identifier *ArrayExp::opId() { return Id::index; } - - -/************************************ - * Operator overload. - * Check for operator overload, if so, replace - * with function call. - * Return NULL if not an operator overload. - */ - -Expression *UnaExp::op_overload(Scope *sc) -{ - //printf("UnaExp::op_overload() (%s)\n", toChars()); - AggregateDeclaration *ad; - Dsymbol *fd; - Type *t1 = e1->type->toBasetype(); - - if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - goto L1; - } - else if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - - L1: - fd = search_function(ad, opId()); - if (fd) - { - if (op == TOKarray) - { - /* Rewrite op e1[arguments] as: - * e1.fd(arguments) - */ - Expression *e = new DotIdExp(loc, e1, fd->ident); - ArrayExp *ae = (ArrayExp *)this; - e = new CallExp(loc, e, ae->arguments); - e = e->semantic(sc); - return e; - } - else - { - // Rewrite +e1 as e1.add() - return build_overload(loc, sc, e1, NULL, fd->ident); - } - } - -#if DMDV2 - // Didn't find it. Forward to aliasthis - if (ad->aliasthis) - { - /* Rewrite op(e1) as: - * op(e1.aliasthis) - */ - Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->semantic(sc); - return e; - } -#endif - } - return NULL; -} - - -Expression *BinExp::op_overload(Scope *sc) -{ - //printf("BinExp::op_overload() (%s)\n", toChars()); - - AggregateDeclaration *ad; - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - Identifier *id = opId(); - Identifier *id_r = opId_r(); - - Match m; - Expressions args1; - Expressions args2; - int argsset = 0; - - AggregateDeclaration *ad1; - if (t1->ty == Tclass) - ad1 = ((TypeClass *)t1)->sym; - else if (t1->ty == Tstruct) - ad1 = ((TypeStruct *)t1)->sym; - else - ad1 = NULL; - - AggregateDeclaration *ad2; - if (t2->ty == Tclass) - ad2 = ((TypeClass *)t2)->sym; - else if (t2->ty == Tstruct) - ad2 = ((TypeStruct *)t2)->sym; - else - ad2 = NULL; - - Dsymbol *s = NULL; - Dsymbol *s_r = NULL; - FuncDeclaration *fd = NULL; - TemplateDeclaration *td = NULL; - if (ad1 && id) - { - s = search_function(ad1, id); - } - if (ad2 && id_r) - { - s_r = search_function(ad2, id_r); - } - - if (s || s_r) - { - /* Try: - * a.opfunc(b) - * b.opfunc_r(a) - * and see which is better. - */ - Expression *e; - FuncDeclaration *lastf; - - args1.setDim(1); - args1.data[0] = (void*) e1; - args2.setDim(1); - args2.data[0] = (void*) e2; - argsset = 1; - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - - if (s) - { - fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2, sc->module); - } - else - { td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, NULL, &args2); - } - } - - lastf = m.lastf; - - if (s_r) - { - fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args1, sc->module); - } - else - { td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, NULL, &args1); - } - } - - if (m.count > 1) - { - // Error, ambiguous - error("overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); - } - else if (m.last == MATCHnomatch) - { - m.lastf = m.anyf; - } - - if (op == TOKplusplus || op == TOKminusminus) - // Kludge because operator overloading regards e++ and e-- - // as unary, but it's implemented as a binary. - // Rewrite (e1 ++ e2) as e1.postinc() - // Rewrite (e1 -- e2) as e1.postdec() - e = build_overload(loc, sc, e1, NULL, id); - else if (lastf && m.lastf == lastf || m.last == MATCHnomatch) - // Rewrite (e1 op e2) as e1.opfunc(e2) - e = build_overload(loc, sc, e1, e2, id); - else - // Rewrite (e1 op e2) as e2.opfunc_r(e1) - e = build_overload(loc, sc, e2, e1, id_r); - return e; - } - - if (isCommutative()) - { - s = NULL; - s_r = NULL; - if (ad1 && id_r) - { - s_r = search_function(ad1, id_r); - } - if (ad2 && id) - { - s = search_function(ad2, id); - } - - if (s || s_r) - { - /* Try: - * a.opfunc_r(b) - * b.opfunc(a) - * and see which is better. - */ - FuncDeclaration *lastf; - - if (!argsset) - { args1.setDim(1); - args1.data[0] = (void*) e1; - args2.setDim(1); - args2.data[0] = (void*) e2; - } - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - - if (s_r) - { - fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2, sc->module); - } - else - { td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, NULL, &args2); - } - } - lastf = m.lastf; - - if (s) - { - fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args1, sc->module); - } - else - { td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, NULL, &args1); - } - } - - if (m.count > 1) - { - // Error, ambiguous - error("overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); - } - else if (m.last == MATCHnomatch) - { - m.lastf = m.anyf; - } - - Expression *e; - if (lastf && m.lastf == lastf || - id_r && m.last == MATCHnomatch) - // Rewrite (e1 op e2) as e1.opfunc_r(e2) - e = build_overload(loc, sc, e1, e2, id_r); - else - // Rewrite (e1 op e2) as e2.opfunc(e1) - e = build_overload(loc, sc, e2, e1, id); - - // When reversing operands of comparison operators, - // need to reverse the sense of the op - switch (op) - { - case TOKlt: op = TOKgt; break; - case TOKgt: op = TOKlt; break; - case TOKle: op = TOKge; break; - case TOKge: op = TOKle; break; - - // Floating point compares - case TOKule: op = TOKuge; break; - case TOKul: op = TOKug; break; - case TOKuge: op = TOKule; break; - case TOKug: op = TOKul; break; - - // These are symmetric - case TOKunord: - case TOKlg: - case TOKleg: - case TOKue: - break; - } - - return e; - } - } - -#if DMDV2 - // Try alias this on first operand - if (ad1 && ad1->aliasthis) - { - /* Rewrite (e1 op e2) as: - * (e1.aliasthis op e2) - */ - Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e1 = e1; - e = e->semantic(sc); - return e; - } - - // Try alias this on second operand - if (ad2 && ad2->aliasthis) - { - /* Rewrite (e1 op e2) as: - * (e1 op e2.aliasthis) - */ - Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e2 = e2; - e = e->semantic(sc); - return e; - } -#endif - return NULL; -} - -/*********************************** - * Utility to build a function call out of this reference and argument. - */ - -Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id) -{ - Expression *e; - - //printf("build_overload(id = '%s')\n", id->toChars()); - //earg->print(); - //earg->type->print(); - e = new DotIdExp(loc, ethis, id); - - if (earg) - e = new CallExp(loc, e, earg); - else - e = new CallExp(loc, e); - - e = e->semantic(sc); - return e; -} - -/*************************************** - * Search for function funcid in aggregate ad. - */ - -Dsymbol *search_function(AggregateDeclaration *ad, Identifier *funcid) -{ - Dsymbol *s; - FuncDeclaration *fd; - TemplateDeclaration *td; - - s = ad->search(0, funcid, 0); - if (s) - { Dsymbol *s2; - - //printf("search_function: s = '%s'\n", s->kind()); - s2 = s->toAlias(); - //printf("search_function: s2 = '%s'\n", s2->kind()); - fd = s2->isFuncDeclaration(); - if (fd && fd->type->ty == Tfunction) - return fd; - - td = s2->isTemplateDeclaration(); - if (td) - return td; - } - return NULL; -} - - -/***************************************** - * Given array of arguments and an aggregate type, - * if any of the argument types are missing, attempt to infer - * them from the aggregate type. - */ - -void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Module* from) -{ - if (!arguments || !arguments->dim) - return; - - /* Return if no arguments need types. - */ - for (size_t u = 0; 1; u++) - { if (u == arguments->dim) - return; - Parameter *arg = (Parameter *)arguments->data[u]; - if (!arg->type) - break; - } - - AggregateDeclaration *ad; - - Parameter *arg = (Parameter *)arguments->data[0]; - Type *taggr = aggr->type; - if (!taggr) - return; - Type *tab = taggr->toBasetype(); - switch (tab->ty) - { - case Tarray: - case Tsarray: - case Ttuple: - if (arguments->dim == 2) - { - if (!arg->type) - arg->type = Type::tsize_t; // key type - arg = (Parameter *)arguments->data[1]; - } - if (!arg->type && tab->ty != Ttuple) - arg->type = tab->nextOf(); // value type - break; - - case Taarray: - { TypeAArray *taa = (TypeAArray *)tab; - - if (arguments->dim == 2) - { - if (!arg->type) - arg->type = taa->index; // key type - arg = (Parameter *)arguments->data[1]; - } - if (!arg->type) - arg->type = taa->next; // value type - break; - } - - case Tclass: - ad = ((TypeClass *)tab)->sym; - goto Laggr; - - case Tstruct: - ad = ((TypeStruct *)tab)->sym; - goto Laggr; - - Laggr: -#if 0 - if (arguments->dim == 1) - { - if (!arg->type) - { - /* Look for an opNext() overload - */ - Dsymbol *s = search_function(ad, Id::next); - fd = s ? s->isFuncDeclaration() : NULL; - if (!fd) - goto Lapply; - arg->type = fd->type->next; - } - break; - } -#endif - Lapply: - { /* Look for an - * int opApply(int delegate(ref Type [, ...]) dg); - * overload - */ - Dsymbol *s = search_function(ad, - (op == TOKforeach_reverse) ? Id::applyReverse - : Id::apply); - if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - inferApplyArgTypesX(from, fd, arguments); - } - break; - } - - case Tdelegate: - { - if (0 && aggr->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)aggr; - - FuncDeclaration *fd = de->func->isFuncDeclaration(); - if (fd) - inferApplyArgTypesX(from, fd, arguments); - } - else - { - inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments); - } - break; - } - - default: - break; // ignore error, caught later - } -} - -/******************************** - * Recursive helper function, - * analogous to func.overloadResolveX(). - */ - -int fp3(void *param, FuncDeclaration *f) -{ - Parameters *arguments = (Parameters *)param; - TypeFunction *tf = (TypeFunction *)f->type; - if (inferApplyArgTypesY(tf, arguments) == 1) - return 0; - if (arguments->dim == 0) - return 1; - return 0; -} - -static void inferApplyArgTypesX(Module* from, FuncDeclaration *fstart, Parameters *arguments) -{ - overloadApply(from, fstart, &fp3, arguments); -} - -#if 0 -static void inferApplyArgTypesX(FuncDeclaration *fstart, Parameters *arguments) -{ - Declaration *d; - Declaration *next; - - for (d = fstart; d; d = next) - { - FuncDeclaration *f; - FuncAliasDeclaration *fa; - AliasDeclaration *a; - - fa = d->isFuncAliasDeclaration(); - if (fa) - { - inferApplyArgTypesX(fa->funcalias, arguments); - next = fa->overnext; - } - else if ((f = d->isFuncDeclaration()) != NULL) - { - next = f->overnext; - - TypeFunction *tf = (TypeFunction *)f->type; - if (inferApplyArgTypesY(tf, arguments) == 1) - continue; - if (arguments->dim == 0) - return; - } - else if ((a = d->isAliasDeclaration()) != NULL) - { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - if (next == fstart) - break; - } - else - { d->error("is aliased to a function"); - break; - } - } -} -#endif - -/****************************** - * Infer arguments from type of function. - * Returns: - * 0 match for this function - * 1 no match for this function - */ - -static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments) -{ size_t nparams; - Parameter *p; - - if (Parameter::dim(tf->parameters) != 1) - goto Lnomatch; - p = Parameter::getNth(tf->parameters, 0); - if (p->type->ty != Tdelegate) - goto Lnomatch; - tf = (TypeFunction *)p->type->nextOf(); - assert(tf->ty == Tfunction); - - /* We now have tf, the type of the delegate. Match it against - * the arguments, filling in missing argument types. - */ - nparams = Parameter::dim(tf->parameters); - if (nparams == 0 || tf->varargs) - goto Lnomatch; // not enough parameters - if (arguments->dim != nparams) - goto Lnomatch; // not enough parameters - - for (size_t u = 0; u < nparams; u++) - { - Parameter *arg = (Parameter *)arguments->data[u]; - Parameter *param = Parameter::getNth(tf->parameters, u); - if (arg->type) - { if (!arg->type->equals(param->type)) - { - /* Cannot resolve argument types. Indicate an - * error by setting the number of arguments to 0. - */ - arguments->dim = 0; - goto Lmatch; - } - continue; - } - arg->type = param->type; - } - Lmatch: - return 0; - - Lnomatch: - return 1; -} - -/************************************** - */ - -static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments) -{ - FuncDeclaration *fd; - - assert(td); - fd = td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); - if (!fd) - return; - m->anyf = fd; - if (m->last >= MATCHexact) - { - m->nextf = fd; - m->count++; - } - else - { - m->last = MATCHexact; - m->lastf = fd; - m->count = 1; - } -} - diff --git a/dmd/optimize.c b/dmd/optimize.c deleted file mode 100644 index 5bfc0d0c..00000000 --- a/dmd/optimize.c +++ /dev/null @@ -1,896 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include - -#if __DMC__ -#include -#endif - -#include "lexer.h" -#include "mtype.h" -#include "expression.h" -#include "declaration.h" -#include "aggregate.h" -#include "init.h" - - -#ifdef IN_GCC -#include "d-gcc-real.h" - -/* %% fix? */ -extern "C" bool real_isnan (const real_t *); -#endif - -static real_t zero; // work around DMC bug for now - - -/************************************* - * If expression is a variable with a const initializer, - * return that initializer. - */ - -Expression *fromConstInitializer(int result, Expression *e1) -{ - //printf("fromConstInitializer(%s)\n", e1->toChars()); - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && !v->originalType && v->scope) // semantic() not yet run - v->semantic (v->scope); - if (!v || !v->type) - return e1; - Type * tb = v->type->toBasetype(); - if (v->isConst() && v->init - && (result & WANTinterpret || (tb->isscalar() || - ((result & WANTexpand) && (tb->ty != Tsarray && tb->ty != Tstruct)))) - ) - { Expression *ei = v->init->toExpression(); - if (ei && ei->type) - e1 = ei; - } - } - return e1; -} - - -Expression *Expression::optimize(int result) -{ - //printf("Expression::optimize(result = x%x) %s\n", result, toChars()); - return this; -} - -Expression *VarExp::optimize(int result) -{ - return fromConstInitializer(result, this); - return this; -} - -Expression *TupleExp::optimize(int result) -{ - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - exps->data[i] = (void *)e; - } - return this; -} - -Expression *ArrayLiteralExp::optimize(int result) -{ - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - elements->data[i] = (void *)e; - } - } - return this; -} - -Expression *AssocArrayLiteralExp::optimize(int result) -{ - assert(keys->dim == values->dim); - for (size_t i = 0; i < keys->dim; i++) - { Expression *e = (Expression *)keys->data[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - keys->data[i] = (void *)e; - - e = (Expression *)values->data[i]; - e = e->optimize(WANTvalue | (result & WANTinterpret)); - values->data[i] = (void *)e; - } - return this; -} - -Expression *StructLiteralExp::optimize(int result) -{ - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - if (!e) - continue; - e = e->optimize(WANTvalue | (result & WANTinterpret)); - (*elements)[i] = e; - } - } - return this; -} - -Expression *TypeExp::optimize(int result) -{ - return this; -} - -Expression *UnaExp::optimize(int result) -{ - e1 = e1->optimize(result); - return this; -} - -Expression *NegExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Neg(type, e1); - } - else - e = this; - return e; -} - -Expression *ComExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Com(type, e1); - } - else - e = this; - return e; -} - -Expression *NotExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Not(type, e1); - } - else - e = this; - return e; -} - -Expression *BoolExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Bool(type, e1); - } - else - e = this; - return e; -} - -Expression *AddrExp::optimize(int result) -{ Expression *e; - - //printf("AddrExp::optimize(result = %d) %s\n", result, toChars()); - // never try to interpret: it could change the semantics by turning - // const p = &s; into an something like const p = &(Struct()); - e1 = e1->optimize(result & ~WANTinterpret); - // Convert &*ex to ex - if (e1->op == TOKstar) - { Expression *ex; - - ex = ((PtrExp *)e1)->e1; - if (type->equals(ex->type)) - e = ex; - else - { - e = ex->copy(); - e->type = type; - } - return e; - } -#if !IN_LLVM - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - if (!ve->var->isOut() && !ve->var->isRef() && - !ve->var->isImportedSymbol()) - { - e = new SymOffExp(loc, ve->var, 0); - e->type = type; - return e; - } - } - if (e1->op == TOKindex) - { // Convert &array[n] to &array+n - IndexExp *ae = (IndexExp *)e1; - - if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) - { - dinteger_t index = ae->e2->toInteger(); - VarExp *ve = (VarExp *)ae->e1; - if (ve->type->ty == Tsarray && ve->type->next->ty != Tbit - && !ve->var->isImportedSymbol()) - { - TypeSArray *ts = (TypeSArray *)ve->type; - dinteger_t dim = ts->dim->toInteger(); - if (index < 0 || index >= dim) - error("array index %jd is out of bounds [0..%jd]", index, dim); - e = new SymOffExp(loc, ve->var, index * ts->next->size()); - e->type = type; - return e; - } - } - } -#endif - return this; -} - -Expression *PtrExp::optimize(int result) -{ - //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars()); - e1 = e1->optimize(result); - // Convert *&ex to ex - if (e1->op == TOKaddress) - { Expression *e; - Expression *ex; - - ex = ((AddrExp *)e1)->e1; - if (type->equals(ex->type)) - e = ex; - else - { - e = ex->copy(); - e->type = type; - } - return e; - } - // Constant fold *(&structliteral + offset) - if (e1->op == TOKadd) - { - Expression *e; - e = Ptr(type, e1); - if (e != EXP_CANT_INTERPRET) - return e; - } - - return this; -} - -Expression *DotVarExp::optimize(int result) -{ - //printf("DotVarExp::optimize(result = x%x) %s\n", result, toChars()); - e1 = e1->optimize(result); - -#if DMDV2 - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - Expression *e = expandVar(result, v); - if (e && e->op == TOKstructliteral) - { StructLiteralExp *sle = (StructLiteralExp *)e; - VarDeclaration *vf = var->isVarDeclaration(); - if (vf) - { - e = sle->getField(type, vf->offset); - if (e && e != EXP_CANT_INTERPRET) - return e; - } - } - } - else -#endif - if (e1->op == TOKstructliteral) - { StructLiteralExp *sle = (StructLiteralExp *)e1; - VarDeclaration *vf = var->isVarDeclaration(); - if (vf) - { - Expression *e = sle->getField(type, vf->offset); - if (e && e != EXP_CANT_INTERPRET) - return e; - } - } - - return this; -} - -Expression *NewExp::optimize(int result) -{ - if (thisexp) - thisexp = thisexp->optimize(WANTvalue); - - // Optimize parameters - if (newargs) - { - for (size_t i = 0; i < newargs->dim; i++) - { Expression *e = newargs->tdata()[i]; - - e = e->optimize(WANTvalue); - newargs->tdata()[i] = e; - } - } - - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; - - e = e->optimize(WANTvalue); - arguments->tdata()[i] = e; - } - } - return this; -} - -Expression *CallExp::optimize(int result) -{ - //printf("CallExp::optimize(result = %d) %s\n", result, toChars()); - Expression *e = this; - - // Optimize parameters - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; - - e = e->optimize(WANTvalue); - arguments->tdata()[i] = e; - } - } - - e1 = e1->optimize(result); - if (result & WANTinterpret) - { - Expression *eresult = interpret(NULL); - if (eresult == EXP_CANT_INTERPRET) - return e; - if (eresult && eresult != EXP_VOID_INTERPRET) - e = eresult; - else - error("cannot evaluate %s at compile time", toChars()); - } - return e; -} - - -Expression *CastExp::optimize(int result) -{ - //printf("CastExp::optimize(result = %d) %s\n", result, toChars()); - //printf("from %s to %s\n", type->toChars(), to->toChars()); - //printf("from %s\n", type->toChars()); - //printf("e1->type %s\n", e1->type->toChars()); - //printf("type = %p\n", type); - assert(type); - enum TOK op1 = e1->op; - - e1 = e1->optimize(result); - if (result & WANTinterpret) - e1 = fromConstInitializer(result, e1); - - if ((e1->op == TOKstring || e1->op == TOKarrayliteral) && - (type->ty == Tpointer || type->ty == Tarray) && - type->next->equals(e1->type->next) - ) - { - // make a copy before adjusting type to avoid - // messing up the type of an existing initializer - e1 = e1->syntaxCopy(); - e1->type = type; - return e1; - } - /* The first test here is to prevent infinite loops - */ - if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral) - return e1->castTo(NULL, to); - if (e1->op == TOKnull && - (type->ty == Tpointer || type->ty == Tclass)) - { - e1->type = type; - return e1; - } - - if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass) - { - // See if we can remove an unnecessary cast - ClassDeclaration *cdfrom; - ClassDeclaration *cdto; - int offset; - - cdfrom = e1->type->isClassHandle(); - cdto = type->isClassHandle(); - if (cdto->isBaseOf(cdfrom, &offset) && offset == 0) - { - e1->type = type; - return e1; - } - } - - Expression *e; - - if (e1->isConst()) - { - if (e1->op == TOKsymoff) - { - if (type->size() == e1->type->size() && - type->toBasetype()->ty != Tsarray) - { - e1->type = type; - return e1; - } - return this; - } - if (to->toBasetype()->ty == Tvoid) - e = this; - else - e = Cast(type, to, e1); - } - else - e = this; - return e; -} - -Expression *BinExp::optimize(int result) -{ - //printf("BinExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (op == TOKshlass || op == TOKshrass || op == TOKushrass) - { - if (e2->isConst() == 1) - { - dinteger_t i2 = e2->toInteger(); - d_uns64 sz = e1->type->size() * 8; - if (i2 < 0 || i2 >= sz) - { error("shift assign by %jd is outside the range 0..%zu", i2, sz - 1); - e2 = new IntegerExp(0); - } - } - } - return this; -} - -Expression *AddExp::optimize(int result) -{ Expression *e; - - //printf("AddExp::optimize(%s)\n", toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() && e2->isConst()) - { - if (e1->op == TOKsymoff && e2->op == TOKsymoff) - return this; - e = Add(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *MinExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() && e2->isConst()) - { - if (e2->op == TOKsymoff) - return this; - e = Min(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *MulExp::optimize(int result) -{ Expression *e; - - //printf("MulExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Mul(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *DivExp::optimize(int result) -{ Expression *e; - - //printf("DivExp::optimize(%s)\n", toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Div(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *ModExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Mod(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, Expression *, Expression *)) -{ Expression *ex = e; - - e->e1 = e->e1->optimize(result); - e->e2 = e->e2->optimize(result); - if (e->e2->isConst() == 1) - { - dinteger_t i2 = e->e2->toInteger(); - d_uns64 sz = e->e1->type->size() * 8; - if (i2 < 0 || i2 >= sz) - { e->error("shift by %jd is outside the range 0..%zu", i2, sz - 1); - e->e2 = new IntegerExp(0); - } - if (e->e1->isConst() == 1) - ex = (*shift)(e->type, e->e1, e->e2); - } - return ex; -} - -Expression *ShlExp::optimize(int result) -{ - //printf("ShlExp::optimize(result = %d) %s\n", result, toChars()); - return shift_optimize(result, this, Shl); -} - -Expression *ShrExp::optimize(int result) -{ - //printf("ShrExp::optimize(result = %d) %s\n", result, toChars()); - return shift_optimize(result, this, Shr); -} - -Expression *UshrExp::optimize(int result) -{ - //printf("UshrExp::optimize(result = %d) %s\n", result, toChars()); - return shift_optimize(result, this, Ushr); -} - -Expression *AndExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - e = And(type, e1, e2); - else - e = this; - return e; -} - -Expression *OrExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - e = Or(type, e1, e2); - else - e = this; - return e; -} - -Expression *XorExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - e = Xor(type, e1, e2); - else - e = this; - return e; -} - -Expression *CommaExp::optimize(int result) -{ Expression *e; - - //printf("CommaExp::optimize(result = %d) %s\n", result, toChars()); - // Comma needs special treatment, because it may - // contain compiler-generated declarations. We can interpret them, but - // otherwise we must NOT attempt to constant-fold them. - // In particular, if the comma returns a temporary variable, it needs - // to be an lvalue (this is particularly important for struct constructors) - - if (result & WANTinterpret) - { // Interpreting comma needs special treatment, because it may - // contain compiler-generated declarations. - e = interpret(NULL); - return (e == EXP_CANT_INTERPRET) ? this : e; - } - - e1 = e1->optimize(result & WANTinterpret); - e2 = e2->optimize(result); - if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->hasSideEffect()) - { - e = e2; - if (e) - e->type = type; - } - else - e = this; - //printf("-CommaExp::optimize(result = %d) %s\n", result, e->toChars()); - return e; -} - -Expression *ArrayLengthExp::optimize(int result) -{ Expression *e; - - //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | WANTexpand | (result & WANTinterpret)); - e = this; - if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) - { - e = ArrayLength(type, e1); - } - return e; -} - -Expression *EqualExp::optimize(int result) -{ Expression *e; - - //printf("EqualExp::optimize(result = %x) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - e = this; - - Expression *e1 = fromConstInitializer(result, this->e1); - Expression *e2 = fromConstInitializer(result, this->e2); - - e = Equal(op, type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - -Expression *IdentityExp::optimize(int result) -{ - //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - Expression *e = this; - - if ((this->e1->isConst() && this->e2->isConst()) || - (this->e1->op == TOKnull && this->e2->op == TOKnull)) - { - e = Identity(op, type, this->e1, this->e2); - if (e == EXP_CANT_INTERPRET) - e = this; - } - return e; -} - - -/* It is possible for constant folding to change an array expression of - * unknown length, into one where the length is known. - * If the expression 'arr' is a literal, set lengthVar to be its length. - */ -void setLengthVarIfKnown(VarDeclaration *lengthVar, Expression *arr) -{ - if (!lengthVar) - return; - if (lengthVar->init && !lengthVar->init->isVoidInitializer()) - return; // we have previously calculated the length - size_t len; - if (arr->op == TOKstring) - len = ((StringExp *)arr)->len; - else if (arr->op == TOKarrayliteral) - len = ((ArrayLiteralExp *)arr)->elements->dim; - else - return; // we don't know the length yet - - Expression *dollar = new IntegerExp(0, len, Type::tsize_t); - lengthVar->init = new ExpInitializer(0, dollar); - lengthVar->storage_class |= STCstatic | STCconst; -} - - -Expression *IndexExp::optimize(int result) -{ Expression *e; - - //printf("IndexExp::optimize(result = %d) %s\n", result, toChars()); - Expression *e1 = this->e1->optimize(WANTvalue | (result & WANTinterpret)); - if (result & WANTinterpret) - e1 = fromConstInitializer(result, e1); - // We might know $ now - setLengthVarIfKnown(lengthVar, e1); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - e = Index(type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - - -Expression *SliceExp::optimize(int result) -{ Expression *e; - - //printf("SliceExp::optimize(result = %d) %s\n", result, toChars()); - e = this; - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - if (!lwr) - { if (e1->op == TOKstring) - { // Convert slice of string literal into dynamic array - Type *t = e1->type->toBasetype(); - if (t->nextOf()) - e = e1->castTo(NULL, t->nextOf()->arrayOf()); - } - return e; - } - if (result & WANTinterpret) - e1 = fromConstInitializer(result, e1); - // We might know $ now - setLengthVarIfKnown(lengthVar, e1); - lwr = lwr->optimize(WANTvalue | (result & WANTinterpret)); - upr = upr->optimize(WANTvalue | (result & WANTinterpret)); - e = Slice(type, e1, lwr, upr); - if (e == EXP_CANT_INTERPRET) - e = this; - //printf("-SliceExp::optimize() %s\n", e->toChars()); - return e; -} - -Expression *AndAndExp::optimize(int result) -{ Expression *e; - - //printf("AndAndExp::optimize(%d) %s\n", result, toChars()); - e1 = e1->optimize(WANTflags | (result & WANTinterpret)); - e = this; - if (e1->isBool(FALSE)) - { - if (type->toBasetype()->ty == Tvoid) - e = e2; - else - { e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type)); - e->type = type; - } - e = e->optimize(result); - } - else - { - e2 = e2->optimize(WANTflags | (result & WANTinterpret)); - if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) - error("void has no value"); - if (e1->isConst()) - { - if (e2->isConst()) - { int n1 = e1->isBool(1); - int n2 = e2->isBool(1); - - e = new IntegerExp(loc, n1 && n2, type); - } - else if (e1->isBool(TRUE)) - { - if (type->toBasetype()->ty == Tvoid) - e = e2; - else e = new BoolExp(loc, e2, type); - } - } - } - return e; -} - -Expression *OrOrExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(WANTflags | (result & WANTinterpret)); - e = this; - if (e1->isBool(TRUE)) - { // Replace with (e1, 1) - e = new CommaExp(loc, e1, new IntegerExp(loc, 1, type)); - e->type = type; - e = e->optimize(result); - } - else - { - e2 = e2->optimize(WANTflags | (result & WANTinterpret)); - if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) - error("void has no value"); - if (e1->isConst()) - { - if (e2->isConst()) - { int n1 = e1->isBool(1); - int n2 = e2->isBool(1); - - e = new IntegerExp(loc, n1 || n2, type); - } - else if (e1->isBool(FALSE)) - { - if (type->toBasetype()->ty == Tvoid) - e = e2; - else - e = new BoolExp(loc, e2, type); - } - } - } - return e; -} - -Expression *CmpExp::optimize(int result) -{ Expression *e; - - //printf("CmpExp::optimize() %s\n", toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Cmp(op, type, this->e1, this->e2); - } - else - e = this; - return e; -} - -Expression *CatExp::optimize(int result) -{ Expression *e; - - //printf("CatExp::optimize(%d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - e = Cat(type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - - -Expression *CondExp::optimize(int result) -{ Expression *e; - - econd = econd->optimize(WANTflags | (result & WANTinterpret)); - if (econd->isBool(TRUE)) - e = e1->optimize(result); - else if (econd->isBool(FALSE)) - e = e2->optimize(result); - else - { e1 = e1->optimize(result); - e2 = e2->optimize(result); - e = this; - } - return e; -} - - diff --git a/dmd/parse.c b/dmd/parse.c deleted file mode 100644 index a16d0819..00000000 --- a/dmd/parse.c +++ /dev/null @@ -1,5689 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// This is the D parser - -#include -#include -#include // strlen(),memcpy() - -#include "rmem.h" -#include "lexer.h" -#include "parse.h" -#include "init.h" -#include "attrib.h" -#include "cond.h" -#include "mtype.h" -#include "template.h" -#include "staticassert.h" -#include "expression.h" -#include "statement.h" -#include "module.h" -#include "dsymbol.h" -#include "import.h" -#include "declaration.h" -#include "aggregate.h" -#include "enum.h" -#include "id.h" -#include "version.h" -#if DMDV2 -#include "aliasthis.h" -#endif - -// How multiple declarations are parsed. -// If 1, treat as C. -// If 0, treat: -// int *p, i; -// as: -// int* p; -// int* i; -#define CDECLSYNTAX 0 - -// Support C cast syntax: -// (type)(expression) -#define CCASTSYNTAX 1 - -// Support postfix C array declarations, such as -// int a[3][4]; -#define CARRAYDECL 1 - -// Support left-to-right array declarations -#define LTORARRAYDECL 1 - - -Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment) - : Lexer(module, base, 0, length, doDocComment, 0) -{ - //printf("Parser::Parser()\n"); - md = NULL; - linkage = LINKd; - endloc = 0; - inBrackets = 0; - //nextToken(); // start up the scanner -} - -Dsymbols *Parser::parseModule() -{ - Dsymbols *decldefs; - - // ModuleDeclation leads off - if (token.value == TOKmodule) - { - unsigned char *comment = token.blockComment; - - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following module"); - goto Lerr; - } - else - { - Identifiers *a = NULL; - Identifier *id; - - id = token.ident; - while (nextToken() == TOKdot) - { - if (!a) - a = new Identifiers(); - a->push(id); - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following package"); - goto Lerr; - } - id = token.ident; - } - - md = new ModuleDeclaration(a, id); - - check(TOKsemicolon, "module declaration"); - addComment(mod, comment); - } - } - - decldefs = parseDeclDefs(0); - if (token.value != TOKeof) - { error(loc, "unrecognized declaration"); - goto Lerr; - } - return decldefs; - -Lerr: - while (token.value != TOKsemicolon && token.value != TOKeof) - nextToken(); - nextToken(); - return new Dsymbols(); -} - -Dsymbols *Parser::parseDeclDefs(int once) -{ Dsymbol *s; - Dsymbols *decldefs; - Dsymbols *a; - Dsymbols *aelse; - enum PROT prot; - StorageClass stc; - Condition *condition; - unsigned char *comment; - - //printf("Parser::parseDeclDefs()\n"); - decldefs = new Dsymbols(); - do - { - comment = token.blockComment; - switch (token.value) - { - case TOKenum: - s = parseEnum(); - break; - - case TOKstruct: - case TOKunion: - case TOKclass: - case TOKinterface: - s = parseAggregate(); - break; - - case TOKimport: - s = parseImport(decldefs, 0); - break; - - case TOKtemplate: - s = (Dsymbol *)parseTemplateDeclaration(); - break; - - case TOKmixin: - { Loc loc = this->loc; - if (peek(&token)->value == TOKlparen) - { // mixin(string) - nextToken(); - check(TOKlparen, "mixin"); - Expression *e = parseAssignExp(); - check(TOKrparen); - check(TOKsemicolon); - s = new CompileDeclaration(loc, e); - break; - } - s = parseMixin(); - break; - } - - case BASIC_TYPES: - case TOKalias: - case TOKtypedef: - case TOKidentifier: - case TOKtypeof: - case TOKdot: - Ldeclaration: - a = parseDeclarations(); - decldefs->append(a); - continue; - - case TOKthis: - s = parseCtor(); - break; - - case TOKtilde: - s = parseDtor(); - break; - - case TOKinvariant: -#if 1 - s = parseInvariant(); -#else - if (peek(&token)->value == TOKlcurly) - s = parseInvariant(); - else - { - stc = STCimmutable; - goto Lstc; - } -#endif - break; - - case TOKunittest: - s = parseUnitTest(); - break; - - case TOKnew: - s = parseNew(); - break; - - case TOKdelete: - s = parseDelete(); - break; - - case TOKeof: - case TOKrcurly: - return decldefs; - - case TOKstatic: - nextToken(); - if (token.value == TOKthis) - s = parseStaticCtor(); - else if (token.value == TOKtilde) - s = parseStaticDtor(); - else if (token.value == TOKassert) - s = parseStaticAssert(); - else if (token.value == TOKif) - { condition = parseStaticIfCondition(); - a = parseBlock(); - aelse = NULL; - if (token.value == TOKelse) - { nextToken(); - aelse = parseBlock(); - } - s = new StaticIfDeclaration(condition, a, aelse); - break; - } - else if (token.value == TOKimport) - { - s = parseImport(decldefs, 1); - } - else - { stc = STCstatic; - goto Lstc2; - } - break; - - case TOKconst: stc = STCconst; goto Lstc; - case TOKfinal: stc = STCfinal; goto Lstc; - case TOKauto: stc = STCauto; goto Lstc; - case TOKscope: stc = STCscope; goto Lstc; - case TOKoverride: stc = STCoverride; goto Lstc; - case TOKabstract: stc = STCabstract; goto Lstc; - case TOKsynchronized: stc = STCsynchronized; goto Lstc; - case TOKdeprecated: stc = STCdeprecated; goto Lstc; -#if DMDV2 - case TOKnothrow: stc = STCnothrow; goto Lstc; - case TOKpure: stc = STCpure; goto Lstc; - case TOKref: stc = STCref; goto Lstc; - case TOKtls: stc = STCtls; goto Lstc; - case TOKgshared: stc = STCgshared; goto Lstc; - //case TOKmanifest: stc = STCmanifest; goto Lstc; - case TOKat: stc = parseAttribute(); goto Lstc; -#endif - - Lstc: - nextToken(); - Lstc2: - switch (token.value) - { - case TOKconst: stc |= STCconst; goto Lstc; - case TOKfinal: stc |= STCfinal; goto Lstc; - case TOKauto: stc |= STCauto; goto Lstc; - case TOKscope: stc |= STCscope; goto Lstc; - case TOKoverride: stc |= STCoverride; goto Lstc; - case TOKabstract: stc |= STCabstract; goto Lstc; - case TOKsynchronized: stc |= STCsynchronized; goto Lstc; - case TOKdeprecated: stc |= STCdeprecated; goto Lstc; - //case TOKinvariant: stc |= STCimmutable; goto Lstc; - default: - break; - } - - /* Look for auto initializers: - * storage_class identifier = initializer; - */ - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - while (1) - { - Identifier *ident = token.ident; - nextToken(); - nextToken(); - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = stc; - s = v; - if (token.value == TOKsemicolon) - { - nextToken(); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - decldefs->push(s); - addComment(s, comment); - continue; - } - else - error("Identifier expected following comma"); - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - break; - } - } - else - { a = parseBlock(); - s = new StorageClassDeclaration(stc, a); - } - break; - - case TOKextern: - if (peek(&token)->value != TOKlparen) - { stc = STCextern; - goto Lstc; - } - { - enum LINK linksave = linkage; - linkage = parseLinkage(); - a = parseBlock(); - s = new LinkDeclaration(linkage, a); - linkage = linksave; - break; - } - case TOKprivate: prot = PROTprivate; goto Lprot; - case TOKpackage: prot = PROTpackage; goto Lprot; - case TOKprotected: prot = PROTprotected; goto Lprot; - case TOKpublic: prot = PROTpublic; goto Lprot; - case TOKexport: prot = PROTexport; goto Lprot; - - Lprot: - nextToken(); - switch (token.value) - { - case TOKprivate: - case TOKpackage: - case TOKprotected: - case TOKpublic: - case TOKexport: - error("redundant protection attribute"); - break; - } - a = parseBlock(); - s = new ProtDeclaration(prot, a); - break; - - case TOKalign: - { unsigned n; - - // LDC better align code locations - Loc alignloc = loc; - - s = NULL; - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - if (token.value == TOKint32v && token.uns64value > 0) - { - if (token.uns64value & (token.uns64value - 1)) - error("align(%s) must be a power of 2", token.toChars()); - n = (unsigned)token.uns64value; - } - else - { error("positive integer expected, not %s", token.toChars()); - n = 1; - } - nextToken(); - check(TOKrparen); - } - else - n = global.structalign; // default - - a = parseBlock(); - s = new AlignDeclaration(alignloc, n, a); - break; - } - - case TOKpragma: - { Identifier *ident; - Expressions *args = NULL; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("pragma(identifier) expected"); - goto Lerror; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma && peekNext() != TOKrparen) - args = parseArguments(); // pragma(identifier, args...) - else - check(TOKrparen); // pragma(identifier) - - if (token.value == TOKsemicolon) - a = NULL; - else - a = parseBlock(); - s = new PragmaDeclaration(loc, ident, args, a); - break; - } - - case TOKdebug: - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value == TOKidentifier) - s = new DebugSymbol(loc, token.ident); - else if (token.value == TOKint32v || token.value == TOKint64v) - s = new DebugSymbol(loc, (unsigned)token.uns64value); - else - { error("identifier or integer expected, not %s", token.toChars()); - s = NULL; - } - nextToken(); - check(TOKsemicolon, "debug declaration"); - break; - } - - condition = parseDebugCondition(); - goto Lcondition; - - case TOKversion: - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value == TOKidentifier) - s = new VersionSymbol(loc, token.ident); - else if (token.value == TOKint32v || token.value == TOKint64v) - s = new VersionSymbol(loc, (unsigned)token.uns64value); - else - { error("identifier or integer expected, not %s", token.toChars()); - s = NULL; - } - nextToken(); - check(TOKsemicolon, "version declaration"); - break; - } - condition = parseVersionCondition(); - goto Lcondition; - - Lcondition: - a = parseBlock(); - aelse = NULL; - if (token.value == TOKelse) - { nextToken(); - aelse = parseBlock(); - } - s = new ConditionalDeclaration(condition, a, aelse); - break; - - case TOKsemicolon: // empty declaration - nextToken(); - continue; - - default: - error("Declaration expected, not '%s'",token.toChars()); - Lerror: - while (token.value != TOKsemicolon && token.value != TOKeof) - nextToken(); - nextToken(); - s = NULL; - continue; - } - if (s) - { decldefs->push(s); - addComment(s, comment); - } - } while (!once); - return decldefs; -} - -/********************************************* - * Give error on conflicting storage classes. - */ - -#if DMDV2 -void Parser::composeStorageClass(StorageClass stc) -{ - StorageClass u = stc; - u &= STCconst | STCimmutable | STCmanifest; - if (u & (u - 1)) - error("conflicting storage class %s", Token::toChars(token.value)); - u = stc; - u &= STCgshared | STCshared | STCtls; - if (u & (u - 1)) - error("conflicting storage class %s", Token::toChars(token.value)); -} -#endif - -/*********************************************** - * Parse storage class, lexer is on '@' - */ - -#if DMDV2 -StorageClass Parser::parseAttribute() -{ - nextToken(); - StorageClass stc = 0; - if (token.value != TOKidentifier) - { - error("identifier expected after @, not %s", token.toChars()); - } - else if (token.ident == Id::property) - stc = STCproperty; - else if (token.ident == Id::safe) - stc = STCsafe; - else if (token.ident == Id::trusted) - stc = STCtrusted; - else if (token.ident == Id::system) - stc = STCsystem; - else if (token.ident == Id::disable) - stc = STCdisable; - else - error("valid attribute identifiers are @property, @safe, @trusted, @system, @disable not @%s", token.toChars()); - return stc; -} -#endif - - -/******************************************** - * Parse declarations after an align, protection, or extern decl. - */ - -Dsymbols *Parser::parseBlock() -{ - Dsymbols *a = NULL; - - //printf("parseBlock()\n"); - switch (token.value) - { - case TOKsemicolon: - error("declaration expected following attribute, not ';'"); - nextToken(); - break; - - case TOKeof: - error("declaration expected following attribute, not EOF"); - break; - - case TOKlcurly: - nextToken(); - a = parseDeclDefs(0); - if (token.value != TOKrcurly) - { /* { */ - error("matching '}' expected, not %s", token.toChars()); - } - else - nextToken(); - break; - - case TOKcolon: - nextToken(); -#if 0 - a = NULL; -#else - a = parseDeclDefs(0); // grab declarations up to closing curly bracket -#endif - break; - - default: - a = parseDeclDefs(1); - break; - } - return a; -} - -/********************************** - * Parse a static assertion. - */ - -StaticAssert *Parser::parseStaticAssert() -{ - Loc loc = this->loc; - Expression *exp; - Expression *msg = NULL; - - //printf("parseStaticAssert()\n"); - nextToken(); - check(TOKlparen); - exp = parseAssignExp(); - if (token.value == TOKcomma) - { nextToken(); - msg = parseAssignExp(); - } - check(TOKrparen); - check(TOKsemicolon, "static assert"); - return new StaticAssert(loc, exp, msg); -} - -/*********************************** - * Parse typeof(expression). - * Current token is on the 'typeof'. - */ - -#if DMDV2 -TypeQualified *Parser::parseTypeof() -{ TypeQualified *t; - Loc loc = this->loc; - - nextToken(); - check(TOKlparen); - if (token.value == TOKreturn) // typeof(return) - { - nextToken(); - t = new TypeReturn(loc); - } - else - { Expression *exp = parseExpression(); // typeof(expression) - t = new TypeTypeof(loc, exp); - } - check(TOKrparen); - return t; -} -#endif - -/*********************************** - * Parse extern (linkage) - * The parser is on the 'extern' token. - */ - -enum LINK Parser::parseLinkage() -{ - enum LINK link = LINKdefault; - nextToken(); - assert(token.value == TOKlparen); - nextToken(); - if (token.value == TOKidentifier) - { Identifier *id = token.ident; - - nextToken(); - if (id == Id::Windows) - link = LINKwindows; - else if (id == Id::Pascal) - link = LINKpascal; - else if (id == Id::D) - link = LINKd; - else if (id == Id::C) - { - link = LINKc; - if (token.value == TOKplusplus) - { link = LINKcpp; - nextToken(); - } - } - else if (id == Id::System) - { -#if IN_LLVM - if (global.params.targetTriple.isOSWindows()) - link = LINKwindows; - else - link = LINKc; -#else -#if _WIN32 - link = LINKwindows; -#else - link = LINKc; -#endif -#endif - } - else - { - error("valid linkage identifiers are D, C, C++, Pascal, Windows, System"); - link = LINKd; - } - } - else - { - link = LINKd; // default - } - check(TOKrparen); - return link; -} - -/************************************** - * Parse a debug conditional - */ - -Condition *Parser::parseDebugCondition() -{ - Condition *c; - - if (token.value == TOKlparen) - { - nextToken(); - unsigned level = 1; - Identifier *id = NULL; - - if (token.value == TOKidentifier) - id = token.ident; - else if (token.value == TOKint32v || token.value == TOKint64v) - level = (unsigned)token.uns64value; - else - error("identifier or integer expected, not %s", token.toChars()); - nextToken(); - check(TOKrparen); - c = new DebugCondition(mod, level, id); - } - else - c = new DebugCondition(mod, 1, NULL); - return c; - -} - -/************************************** - * Parse a version conditional - */ - -Condition *Parser::parseVersionCondition() -{ - Condition *c; - unsigned level = 1; - Identifier *id = NULL; - - if (token.value == TOKlparen) - { - nextToken(); - if (token.value == TOKidentifier) - id = token.ident; - else if (token.value == TOKint32v || token.value == TOKint64v) - level = (unsigned)token.uns64value; -#if DMDV2 - /* Allow: - * version (unittest) - * even though unittest is a keyword - */ - else if (token.value == TOKunittest) - id = Lexer::idPool(Token::toChars(TOKunittest)); -#endif - else - error("identifier or integer expected, not %s", token.toChars()); - nextToken(); - check(TOKrparen); - - } - else - error("(condition) expected following version"); - c = new VersionCondition(mod, level, id); - return c; - -} - -/*********************************************** - * static if (expression) - * body - * else - * body - */ - -Condition *Parser::parseStaticIfCondition() -{ Expression *exp; - Condition *condition; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - exp = parseAssignExp(); - check(TOKrparen); - } - else - { error("(expression) expected following static if"); - exp = NULL; - } - condition = new StaticIfCondition(loc, exp); - return condition; -} - - -/***************************************** - * Parse a constructor definition: - * this(parameters) { body } - * Current token is 'this'. - */ - -Dsymbol *Parser::parseCtor() -{ - Loc loc = this->loc; - - nextToken(); - int varargs; - Parameters *parameters = parseParameters(&varargs); - CtorDeclaration *f = new CtorDeclaration(loc, 0, parameters, varargs); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a destructor definition: - * ~this() { body } - * Current token is '~'. - */ - -DtorDeclaration *Parser::parseDtor() -{ - DtorDeclaration *f; - Loc loc = this->loc; - - nextToken(); - check(TOKthis, "~"); - check(TOKlparen, "~this"); - check(TOKrparen); - - f = new DtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a static constructor definition: - * static this() { body } - * Current token is 'this'. - */ - -StaticCtorDeclaration *Parser::parseStaticCtor() -{ - Loc loc = this->loc; - - nextToken(); - check(TOKlparen, "static this"); - check(TOKrparen); - - StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a shared static constructor definition: - * shared static this() { body } - * Current token is 'shared'. - */ -#if DMDV2 -SharedStaticCtorDeclaration *Parser::parseSharedStaticCtor() -{ - Loc loc = this->loc; - - nextToken(); - nextToken(); - nextToken(); - check(TOKlparen, "shared static this"); - check(TOKrparen); - - SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, 0); - parseContracts(f); - return f; -} -#endif - -/***************************************** - * Parse a static destructor definition: - * static ~this() { body } - * Current token is '~'. - */ - -StaticDtorDeclaration *Parser::parseStaticDtor() -{ - Loc loc = this->loc; - - nextToken(); - check(TOKthis, "~"); - check(TOKlparen, "~this"); - check(TOKrparen); - - StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a shared static destructor definition: - * shared static ~this() { body } - * Current token is 'shared'. - */ -#if DMDV2 -SharedStaticDtorDeclaration *Parser::parseSharedStaticDtor() -{ - Loc loc = this->loc; - - nextToken(); - nextToken(); - nextToken(); - check(TOKthis, "shared static ~"); - check(TOKlparen, "shared static ~this"); - check(TOKrparen); - - SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, 0); - parseContracts(f); - return f; -} -#endif - -/***************************************** - * Parse an invariant definition: - * invariant() { body } - * Current token is 'invariant'. - */ - -InvariantDeclaration *Parser::parseInvariant() -{ - InvariantDeclaration *f; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) // optional () - { - nextToken(); - check(TOKrparen); - } - - f = new InvariantDeclaration(loc, 0); - f->fbody = parseStatement(PScurly); - return f; -} - -/***************************************** - * Parse a unittest definition: - * unittest { body } - * Current token is 'unittest'. - */ - -UnitTestDeclaration *Parser::parseUnitTest() -{ - UnitTestDeclaration *f; - Statement *body; - Loc loc = this->loc; - - nextToken(); - - body = parseStatement(PScurly); - - f = new UnitTestDeclaration(loc, this->loc); - f->fbody = body; - return f; -} - -/***************************************** - * Parse a new definition: - * new(arguments) { body } - * Current token is 'new'. - */ - -NewDeclaration *Parser::parseNew() -{ - NewDeclaration *f; - Parameters *arguments; - int varargs; - Loc loc = this->loc; - - nextToken(); - arguments = parseParameters(&varargs); - f = new NewDeclaration(loc, 0, arguments, varargs); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a delete definition: - * delete(arguments) { body } - * Current token is 'delete'. - */ - -DeleteDeclaration *Parser::parseDelete() -{ - DeleteDeclaration *f; - Parameters *arguments; - int varargs; - Loc loc = this->loc; - - nextToken(); - arguments = parseParameters(&varargs); - if (varargs) - error("... not allowed in delete function parameter list"); - f = new DeleteDeclaration(loc, 0, arguments); - parseContracts(f); - return f; -} - -/********************************************** - * Parse parameter list. - */ - -Parameters *Parser::parseParameters(int *pvarargs) -{ - Parameters *arguments = new Parameters(); - int varargs = 0; - int hasdefault = 0; - - check(TOKlparen, "start of parameter list"); - while (1) - { Type *tb; - Identifier *ai = NULL; - Type *at; - Parameter *a; - StorageClass storageClass = 0; - Expression *ae; - - storageClass = STCin; // parameter is "in" by default - switch (token.value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - varargs = 1; - nextToken(); - break; - - case TOKin: - storageClass = STCin; - nextToken(); - goto L1; - - case TOKout: - storageClass = STCout; - nextToken(); - goto L1; - - case TOKinout: - case TOKref: - storageClass = STCref; - nextToken(); - goto L1; - - case TOKlazy: - storageClass = STClazy; - nextToken(); - goto L1; - - default: - L1: - tb = parseBasicType(); - at = parseDeclarator(tb, &ai); - ae = NULL; - if (token.value == TOKassign) // = defaultArg - { nextToken(); - ae = parseAssignExp(); - hasdefault = 1; - } - else - { if (hasdefault) - error("default argument expected for %s", - ai ? ai->toChars() : at->toChars()); - } - if (token.value == TOKdotdotdot) - { /* This is: - * at ai ... - */ - - if (storageClass & (STCout | STCref)) - error("variadic argument cannot be out or ref"); - varargs = 2; - a = new Parameter(storageClass, at, ai, ae); - arguments->push(a); - nextToken(); - break; - } - a = new Parameter(storageClass, at, ai, ae); - arguments->push(a); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - break; - } - check(TOKrparen); - *pvarargs = varargs; - return arguments; -} - - -/************************************* - */ - -EnumDeclaration *Parser::parseEnum() -{ EnumDeclaration *e; - Identifier *id; - Type *memtype; - Loc loc = this->loc; - - //printf("Parser::parseEnum()\n"); - nextToken(); - if (token.value == TOKidentifier) - { id = token.ident; - nextToken(); - } - else - id = NULL; - - if (token.value == TOKcolon) - { - nextToken(); - memtype = parseBasicType(); - } - else - memtype = NULL; - - e = new EnumDeclaration(loc, id, memtype); - if (token.value == TOKsemicolon && id) - nextToken(); - else if (token.value == TOKlcurly) - { - //printf("enum definition\n"); - e->members = new Dsymbols(); - nextToken(); - unsigned char *comment = token.blockComment; - while (token.value != TOKrcurly) - { - if (token.value == TOKidentifier) - { - Expression *value; - Identifier *ident; - - loc = this->loc; - ident = token.ident; - value = NULL; - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - value = parseAssignExp(); - } - EnumMember *em = new EnumMember(loc, ident, value); - e->members->push(em); - - if (token.value == TOKrcurly) - ; - else - { addComment(em, comment); - comment = NULL; - check(TOKcomma, "enum member"); - } - addComment(em, comment); - comment = token.blockComment; - } - else - { error("enum member expected"); - nextToken(); - } - } - nextToken(); - } - else - error("enum declaration is invalid"); - - //printf("-parseEnum() %s\n", e->toChars()); - return e; -} - -/******************************** - * Parse struct, union, interface, class. - */ - -Dsymbol *Parser::parseAggregate() -{ AggregateDeclaration *a = NULL; - int anon = 0; - enum TOK tok; - Identifier *id; - TemplateParameters *tpl = NULL; - Expression *constraint = NULL; - - //printf("Parser::parseAggregate()\n"); - tok = token.value; - nextToken(); - if (token.value != TOKidentifier) - { id = NULL; - } - else - { id = token.ident; - nextToken(); - - if (token.value == TOKlparen) - { // Class template declaration. - - // Gather template parameter list - tpl = parseTemplateParameterList(); - } - } - - Loc loc = this->loc; - switch (tok) - { case TOKclass: - case TOKinterface: - { - if (!id) - error("anonymous classes not allowed"); - - // Collect base class(es) - BaseClasses *baseclasses = NULL; - if (token.value == TOKcolon) - { - nextToken(); - baseclasses = parseBaseClasses(); - - if (token.value != TOKlcurly) - error("members expected"); - } - - if (tok == TOKclass) - a = new ClassDeclaration(loc, id, baseclasses); - else - a = new InterfaceDeclaration(loc, id, baseclasses); - break; - } - - case TOKstruct: - if (id) - a = new StructDeclaration(loc, id); - else - anon = 1; - break; - - case TOKunion: - if (id) - a = new UnionDeclaration(loc, id); - else - anon = 2; - break; - - default: - assert(0); - break; - } - if (a && token.value == TOKsemicolon) - { nextToken(); - } - else if (token.value == TOKlcurly) - { - //printf("aggregate definition\n"); - nextToken(); - Dsymbols *decl = parseDeclDefs(0); - if (token.value != TOKrcurly) - error("} expected following member declarations in aggregate"); - nextToken(); - if (anon) - { - /* Anonymous structs/unions are more like attributes. - */ - return new AnonDeclaration(loc, anon - 1, decl); - } - else - a->members = decl; - } - else - { - error("{ } expected following aggregate declaration"); - a = new StructDeclaration(loc, NULL); - } - - if (tpl) - { // Wrap a template around the aggregate declaration - - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(a); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, id, tpl, constraint, decldefs); - return tempdecl; - } - - return a; -} - -/******************************************* - */ - -BaseClasses *Parser::parseBaseClasses() -{ - BaseClasses *baseclasses = new BaseClasses(); - - for (; 1; nextToken()) - { - bool prot = false; - enum PROT protection = PROTpublic; - switch (token.value) - { - case TOKprivate: - prot = true; - protection = PROTprivate; - nextToken(); - break; - case TOKpackage: - prot = true; - protection = PROTpackage; - nextToken(); - break; - case TOKprotected: - prot = true; - protection = PROTprotected; - nextToken(); - break; - case TOKpublic: - prot = true; - protection = PROTpublic; - nextToken(); - break; - } - //if (prot && !global.params.useDeprecated) - //error("use of base class protection is deprecated"); - if (token.value == TOKidentifier) - { - BaseClass *b = new BaseClass(parseBasicType(), protection); - baseclasses->push(b); - if (token.value != TOKcomma) - break; - } - else - { - error("base classes expected instead of %s", token.toChars()); - return NULL; - } - } - return baseclasses; -} - -/************************************** - * Parse constraint. - * Constraint is of the form: - * if ( ConstraintExpression ) - */ - -#if DMDV2 -Expression *Parser::parseConstraint() -{ Expression *e = NULL; - - if (token.value == TOKif) - { - nextToken(); // skip over 'if' - check(TOKlparen, "if"); - e = parseExpression(); - check(TOKrparen); - } - return e; -} -#endif - -/************************************** - * Parse a TemplateDeclaration. - */ - -TemplateDeclaration *Parser::parseTemplateDeclaration() -{ - TemplateDeclaration *tempdecl; - Identifier *id; - TemplateParameters *tpl; - Dsymbols *decldefs; - Loc loc = this->loc; - - nextToken(); - if (token.value != TOKidentifier) - { error("TemplateIdentifier expected following template"); - goto Lerr; - } - id = token.ident; - nextToken(); - tpl = parseTemplateParameterList(); - if (!tpl) - goto Lerr; - - if (token.value != TOKlcurly) - { error("members of template declaration expected"); - goto Lerr; - } - else - { - nextToken(); - decldefs = parseDeclDefs(0); - if (token.value != TOKrcurly) - { error("template member expected"); - goto Lerr; - } - nextToken(); - } - - tempdecl = new TemplateDeclaration(loc, id, tpl, NULL, decldefs); - return tempdecl; - -Lerr: - return NULL; -} - -/****************************************** - * Parse template parameter list. - * Input: - * flag 0: parsing "( list )" - * 1: parsing non-empty "list )" - */ - -TemplateParameters *Parser::parseTemplateParameterList(int flag) -{ - TemplateParameters *tpl = new TemplateParameters(); - - if (token.value != TOKlparen) - { error("parenthesized TemplateParameterList expected following TemplateIdentifier"); - goto Lerr; - } - nextToken(); - - // Get array of TemplateParameters - if (token.value != TOKrparen) - { int isvariadic = 0; - - while (1) - { TemplateParameter *tp; - Identifier *tp_ident = NULL; - Type *tp_spectype = NULL; - Type *tp_valtype = NULL; - Type *tp_defaulttype = NULL; - Expression *tp_specvalue = NULL; - Expression *tp_defaultvalue = NULL; - Token *t; - - // Get TemplateParameter - - // First, look ahead to see if it is a TypeParameter or a ValueParameter - t = peek(&token); - if (token.value == TOKalias) - { // AliasParameter - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected for template parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseBasicType(); - tp_spectype = parseDeclarator(tp_spectype, NULL); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseBasicType(); - tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); - } - tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } - else if (t->value == TOKcolon || t->value == TOKassign || - t->value == TOKcomma || t->value == TOKrparen) - { // TypeParameter - if (token.value != TOKidentifier) - { error("identifier expected for template type parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseBasicType(); - tp_spectype = parseDeclarator(tp_spectype, NULL); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseBasicType(); - tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); - } - tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } - else if (token.value == TOKidentifier && t->value == TOKdotdotdot) - { // ident... - if (isvariadic) - error("variadic template parameter must be last"); - isvariadic = 1; - tp_ident = token.ident; - nextToken(); - nextToken(); - tp = new TemplateTupleParameter(loc, tp_ident); - } -#if DMDV2 - else if (token.value == TOKthis) - { // ThisParameter - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected for template this parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseType(); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseType(); - } - tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } -#endif - else - { // ValueParameter - tp_valtype = parseBasicType(); - tp_valtype = parseDeclarator(tp_valtype, &tp_ident); - if (!tp_ident) - { - error("identifier expected for template value parameter"); - tp_ident = new Identifier("error", TOKidentifier); - } - if (token.value == TOKcolon) // : CondExpression - { - nextToken(); - tp_specvalue = parseCondExp(); - } - if (token.value == TOKassign) // = CondExpression - { - nextToken(); - tp_defaultvalue = parseCondExp(); - } - tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); - } - tpl->push(tp); - if (token.value != TOKcomma) - break; - nextToken(); - } - } - check(TOKrparen); -Lerr: - return tpl; -} - -/****************************************** - * Parse template mixin. - * mixin Foo; - * mixin Foo!(args); - * mixin a.b.c!(args).Foo!(args); - * mixin Foo!(args) identifier; - * mixin typeof(expr).identifier!(args); - */ - -Dsymbol *Parser::parseMixin() -{ - TemplateMixin *tm; - Identifier *id; - Type *tqual; - Objects *tiargs; - Identifiers *idents; - - //printf("parseMixin()\n"); - nextToken(); - tqual = NULL; - if (token.value == TOKdot) - { - id = Id::empty; - } - else - { - if (token.value == TOKtypeof) - { Expression *exp; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - tqual = new TypeTypeof(loc, exp); - check(TOKdot, "typeof (expression)"); - } - if (token.value != TOKidentifier) - { - error("identifier expected, not %s", token.toChars()); - id = Id::empty; - } - else - id = token.ident; - nextToken(); - } - - idents = new Identifiers(); - while (1) - { - tiargs = NULL; - if (token.value == TOKnot) - { - nextToken(); - tiargs = parseTemplateArgumentList(); - } - - if (token.value != TOKdot) - break; - - if (tiargs) - { TemplateInstance *tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = tiargs; - id = (Identifier *)tempinst; - tiargs = NULL; - } - idents->push(id); - - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following '.' instead of '%s'", token.toChars()); - break; - } - id = token.ident; - nextToken(); - } - idents->push(id); - - if (token.value == TOKidentifier) - { - id = token.ident; - nextToken(); - } - else - id = NULL; - - tm = new TemplateMixin(loc, id, tqual, idents, tiargs); - check(TOKsemicolon, "template mixin"); - return tm; -} - -/****************************************** - * Parse template argument list. - * Input: - * current token is opening '(' - * Output: - * current token is one after closing ')' - */ - -Objects *Parser::parseTemplateArgumentList() -{ - //printf("Parser::parseTemplateArgumentList()\n"); - Objects *tiargs = new Objects(); - if (token.value != TOKlparen) - { error("!(TemplateArgumentList) expected following TemplateIdentifier"); - return tiargs; - } - nextToken(); - - // Get TemplateArgumentList - if (token.value != TOKrparen) - { - while (1) - { - // See if it is an Expression or a Type - if (isDeclaration(&token, 0, TOKreserved, NULL)) - { // Type - // Get TemplateArgument - Type *ta = parseBasicType(); - ta = parseDeclarator(ta, NULL); - tiargs->push(ta); - } - else - { // Template argument is an expression - Expression *ea = parseAssignExp(); - tiargs->push(ea); - } - if (token.value != TOKcomma) - break; - nextToken(); - } - } - check(TOKrparen, "template argument list"); - return tiargs; -} - -Import *Parser::parseImport(Array *decldefs, int isstatic) -{ Import *s; - Identifier *id; - Identifier *aliasid = NULL; - Identifiers *a; - Loc loc; - - //printf("Parser::parseImport()\n"); - do - { - L1: - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following import"); - break; - } - - loc = this->loc; - a = NULL; - id = token.ident; - nextToken(); - if (!aliasid && token.value == TOKassign) - { - aliasid = id; - goto L1; - } - while (token.value == TOKdot) - { - if (!a) - a = new Identifiers(); - a->push(id); - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following package"); - break; - } - id = token.ident; - nextToken(); - } - - s = new Import(loc, a, id, aliasid, isstatic); - decldefs->push(s); - - /* Look for - * : alias=name, alias=name; - * syntax. - */ - if (token.value == TOKcolon) - { - do - { Identifier *name; - - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following :"); - break; - } - Identifier *alias = token.ident; - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following %s=", alias->toChars()); - break; - } - name = token.ident; - nextToken(); - } - else - { name = alias; - alias = NULL; - } - s->addAlias(name, alias); - } while (token.value == TOKcomma); - break; // no comma-separated imports of this form - } - - aliasid = NULL; - } while (token.value == TOKcomma); - - if (token.value == TOKsemicolon) - nextToken(); - else - { - check(TOKsemicolon, "import declaration"); - } - - return NULL; -} - -#if DMDV2 -Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl) -{ Type *t; - - /* Take care of the storage class prefixes that - * serve as type attributes: - * const shared, shared const, const, invariant, shared - */ - if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() != TOKlparen || - token.value == TOKshared && peekNext() == TOKconst && peekNext2() != TOKlparen) - { - nextToken(); - nextToken(); - /* shared const type - */ - t = parseType(pident, tpl); - t = t->makeSharedConst(); - return t; - } - else if (token.value == TOKwild && peekNext() == TOKshared && peekNext2() != TOKlparen || - token.value == TOKshared && peekNext() == TOKwild && peekNext2() != TOKlparen) - { - nextToken(); - nextToken(); - /* shared wild type - */ - t = parseType(pident, tpl); - t = t->makeSharedWild(); - return t; - } - else if (token.value == TOKconst && peekNext() != TOKlparen) - { - nextToken(); - /* const type - */ - t = parseType(pident, tpl); - t = t->makeConst(); - return t; - } - else if ((token.value == TOKinvariant || token.value == TOKimmutable) && - peekNext() != TOKlparen) - { - nextToken(); - /* invariant type - */ - t = parseType(pident, tpl); - t = t->makeInvariant(); - return t; - } - else if (token.value == TOKshared && peekNext() != TOKlparen) - { - nextToken(); - /* shared type - */ - t = parseType(pident, tpl); - t = t->makeShared(); - return t; - } - else if (token.value == TOKwild && peekNext() != TOKlparen) - { - nextToken(); - /* wild type - */ - t = parseType(pident, tpl); - t = t->makeWild(); - return t; - } - else - t = parseBasicType(); - t = parseDeclarator(t, pident, tpl); - return t; -} -#endif - -Type *Parser::parseBasicType() -{ Type *t; - Identifier *id; - TypeQualified *tid; - - //printf("parseBasicType()\n"); - switch (token.value) - { - case BASIC_TYPES_X(t): - nextToken(); - break; - - case TOKidentifier: - id = token.ident; - nextToken(); - if (token.value == TOKnot) - { // ident!(template_arguments) - TemplateInstance *tempinst = new TemplateInstance(loc, id); - nextToken(); - tempinst->tiargs = parseTemplateArgumentList(); - tid = new TypeInstance(loc, tempinst); - goto Lident2; - } - Lident: - tid = new TypeIdentifier(loc, id); - Lident2: - while (token.value == TOKdot) - { nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following '.' instead of '%s'", token.toChars()); - break; - } - id = token.ident; - nextToken(); - if (token.value == TOKnot) - { - nextToken(); - TemplateInstance *tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = parseTemplateArgumentList(); - tid->addIdent((Identifier *)tempinst); - } - else - tid->addIdent(id); - } - t = tid; - break; - - case TOKdot: - // Leading . as in .foo - id = Id::empty; - goto Lident; - - case TOKtypeof: - { - nextToken(); - check(TOKlparen); - Expression *exp = parseExpression(); - check(TOKrparen); - tid = new TypeTypeof(loc, exp); - goto Lident2; - } - - default: - error("basic type expected, not %s", token.toChars()); - t = Type::tint32; - break; - } - return t; -} - -/****************************************** - * Parse things that follow the initial type t. - * t * - * t [] - * t [type] - * t [expression] - * t [expression .. expression] - * t function - * t delegate - */ - -Type *Parser::parseBasicType2(Type *t) -{ - Type *ts; - Type *ta; - - //printf("parseBasicType2()\n"); - while (1) - { - switch (token.value) - { - case TOKmul: - t = new TypePointer(t); - nextToken(); - continue; - - case TOKlbracket: -#if LTORARRAYDECL - // Handle []. Make sure things like - // int[3][1] a; - // is (array[1] of array[3] of int) - nextToken(); - if (token.value == TOKrbracket) - { - t = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - - //printf("it's an associative array\n"); - Type *index = parseBasicType(); - index = parseDeclarator(index, NULL); // [ type ] - t = new TypeAArray(t, index); - check(TOKrbracket); - } - else - { - //printf("it's [expression]\n"); - inBrackets++; - Expression *e = parseExpression(); // [ expression ] - if (token.value == TOKslice) - { - nextToken(); - Expression *e2 = parseExpression(); // [ exp .. exp ] - t = new TypeSlice(t, e, e2); - } - else - t = new TypeSArray(t,e); - inBrackets--; - check(TOKrbracket); - } - continue; -#else - // Handle []. Make sure things like - // int[3][1] a; - // is (array[3] of array[1] of int) - ts = t; - while (token.value == TOKlbracket) - { - nextToken(); - if (token.value == TOKrbracket) - { - ta = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - Type *index; - - //printf("it's an associative array\n"); - index = parseBasicType(); - index = parseDeclarator(index, NULL); // [ type ] - check(TOKrbracket); - ta = new TypeAArray(t, index); - } - else - { - //printf("it's [expression]\n"); - Expression *e = parseExpression(); // [ expression ] - ta = new TypeSArray(t,e); - check(TOKrbracket); - } - Type **pt; - for (pt = &ts; *pt != t; pt = &(*pt)->next) - ; - *pt = ta; - } - t = ts; - continue; -#endif - - case TOKdelegate: - case TOKfunction: - { // Handle delegate declaration: - // t delegate(parameter list) - // t function(parameter list) - Parameters *arguments; - int varargs; - enum TOK save = token.value; - - nextToken(); - arguments = parseParameters(&varargs); - t = new TypeFunction(arguments, t, varargs, linkage); - if (save == TOKdelegate) - t = new TypeDelegate(t); - else - t = new TypePointer(t); // pointer to function - continue; - } - - default: - ts = t; - break; - } - break; - } - return ts; -} - -Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl) -{ Type *ts; - Type *ta; - - //printf("parseDeclarator(tpl = %p)\n", tpl); - t = parseBasicType2(t); - - switch (token.value) - { - - case TOKidentifier: - if (pident) - *pident = token.ident; - else - error("unexpected identifer '%s' in declarator", token.ident->toChars()); - ts = t; - nextToken(); - break; - - case TOKlparen: - /* Parse things with parentheses around the identifier, like: - * int (*ident[3])[] - * although the D style would be: - * int[]*[3] ident - */ - nextToken(); - ts = parseDeclarator(t, pident); - check(TOKrparen); - break; - - default: - ts = t; - break; - } - - // parse DeclaratorSuffixes - while (1) - { - switch (token.value) - { -#if CARRAYDECL - /* Support C style array syntax: - * int ident[] - * as opposed to D-style: - * int[] ident - */ - case TOKlbracket: - { // This is the old C-style post [] syntax. - nextToken(); - if (token.value == TOKrbracket) - { // It's a dynamic array - ta = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - - //printf("it's an associative array\n"); - Type *index = parseBasicType(); - index = parseDeclarator(index, NULL); // [ type ] - check(TOKrbracket); - ta = new TypeAArray(t, index); - } - else - { - //printf("it's [expression]\n"); - Expression *e = parseExpression(); // [ expression ] - ta = new TypeSArray(t, e); - check(TOKrbracket); - } - - /* Insert ta into - * ts -> ... -> t - * so that - * ts -> ... -> ta -> t - */ - Type **pt; - for (pt = &ts; *pt != t; pt = &(*pt)->next) - ; - *pt = ta; - continue; - } -#endif - case TOKlparen: - { - if (tpl) - { - /* Look ahead to see if this is (...)(...), - * i.e. a function template declaration - */ - if (peekPastParen(&token)->value == TOKlparen) - { - //printf("function template declaration\n"); - - // Gather template parameter list - *tpl = parseTemplateParameterList(); - } - } - - int varargs; - Parameters *arguments = parseParameters(&varargs); - Type *ta = new TypeFunction(arguments, t, varargs, linkage); - Type **pt; - for (pt = &ts; *pt != t; pt = &(*pt)->next) - ; - *pt = ta; - break; - } - } - break; - } - - return ts; -} - -/********************************** - * Parse Declarations. - * These can be: - * 1. declarations at global/class level - * 2. declarations at statement level - * Return array of Declaration *'s. - */ - -Dsymbols *Parser::parseDeclarations() -{ - StorageClass storage_class; - StorageClass stc; - Type *ts; - Type *t; - Type *tfirst; - Identifier *ident; - Dsymbols *a; - enum TOK tok = TOKreserved; - unsigned char *comment = token.blockComment; - enum LINK link = linkage; - - //printf("parseDeclarations()\n"); - switch (token.value) - { - case TOKtypedef: - case TOKalias: - tok = token.value; - nextToken(); - break; - - default: - tok = TOKreserved; - break; - } - - storage_class = STCundefined; - while (1) - { - switch (token.value) - { - case TOKconst: stc = STCconst; goto L1; - case TOKstatic: stc = STCstatic; goto L1; - case TOKfinal: stc = STCfinal; goto L1; - case TOKauto: stc = STCauto; goto L1; - case TOKscope: stc = STCscope; goto L1; - case TOKoverride: stc = STCoverride; goto L1; - case TOKabstract: stc = STCabstract; goto L1; - case TOKsynchronized: stc = STCsynchronized; goto L1; - case TOKdeprecated: stc = STCdeprecated; goto L1; -#if DMDV2 - case TOKnothrow: stc = STCnothrow; goto L1; - case TOKpure: stc = STCpure; goto L1; - case TOKref: stc = STCref; goto L1; - case TOKtls: stc = STCtls; goto L1; - case TOKenum: stc = STCmanifest; goto L1; -#endif - L1: - if (storage_class & stc) - error("redundant storage class '%s'", token.toChars()); - storage_class = (STC) (storage_class | stc); - nextToken(); - continue; - - case TOKextern: - if (peek(&token)->value != TOKlparen) - { stc = STCextern; - goto L1; - } - - link = parseLinkage(); - continue; - - default: - break; - } - break; - } - - a = new Dsymbols(); - - /* Look for auto initializers: - * storage_class identifier = initializer; - */ - while (storage_class && - token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - ident = token.ident; - nextToken(); - nextToken(); - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = storage_class; - a->push(v); - if (token.value == TOKsemicolon) - { - nextToken(); - addComment(v, comment); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (!(token.value == TOKidentifier && peek(&token)->value == TOKassign)) - { - error("Identifier expected following comma"); - } - else - continue; - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - return a; - } - - if (token.value == TOKclass) - { AggregateDeclaration *s; - - s = (AggregateDeclaration *)parseAggregate(); - s->storage_class |= storage_class; - a->push(s); - addComment(s, comment); - return a; - } - - ts = parseBasicType(); - ts = parseBasicType2(ts); - tfirst = NULL; - - while (1) - { - Loc loc = this->loc; - TemplateParameters *tpl = NULL; - - ident = NULL; - t = parseDeclarator(ts, &ident, &tpl); - assert(t); - if (!tfirst) - tfirst = t; - else if (t != tfirst) - error("multiple declarations must have the same type, not %s and %s", - tfirst->toChars(), t->toChars()); - if (!ident) - error("no identifier for declarator %s", t->toChars()); - - if (tok == TOKtypedef || tok == TOKalias) - { Declaration *v; - Initializer *init = NULL; - - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - if (tok == TOKtypedef) - v = new TypedefDeclaration(loc, ident, t, init); - else - { if (init) - error("alias cannot have initializer"); - v = new AliasDeclaration(loc, ident, t); - } - v->storage_class = storage_class; - if (link == linkage) - a->push(v); - else - { - Dsymbols *ax = new Dsymbols(); - ax->push(v); - Dsymbol *s = new LinkDeclaration(link, ax); - a->push(s); - } - switch (token.value) - { case TOKsemicolon: - nextToken(); - addComment(v, comment); - break; - - case TOKcomma: - nextToken(); - addComment(v, comment); - continue; - - default: - error("semicolon expected to close %s declaration", Token::toChars(tok)); - break; - } - } - else if (t->ty == Tfunction) - { FuncDeclaration *f = - new FuncDeclaration(loc, 0, ident, storage_class, t); - addComment(f, comment); - parseContracts(f); - addComment(f, NULL); - Dsymbol *s; - if (link == linkage) - { - s = f; - } - else - { - Dsymbols *ax = new Dsymbols(); - ax->push(f); - s = new LinkDeclaration(link, ax); - } - if (tpl) // it's a function template - { - // Wrap a template around the aggregate declaration - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(s); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, s->ident, tpl, NULL, decldefs); - s = tempdecl; - } - addComment(s, comment); - a->push(s); - } - else - { - Initializer *init = NULL; - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - - VarDeclaration *v = new VarDeclaration(loc, t, ident, init); - v->storage_class = storage_class; - if (link == linkage) - a->push(v); - else - { - Dsymbols *ax = new Dsymbols(); - ax->push(v); - Dsymbol *s = new LinkDeclaration(link, ax); - a->push(s); - } - switch (token.value) - { case TOKsemicolon: - nextToken(); - addComment(v, comment); - break; - - case TOKcomma: - nextToken(); - addComment(v, comment); - continue; - - default: - error("semicolon expected to close declaration, not '%s'", token.toChars()); - break; - } - } - break; - } - return a; -} - -/***************************************** - * Parse auto declarations of the form: - * storageClass ident = init, ident = init, ... ; - * and return the array of them. - * Starts with token on the first ident. - * Ends with scanner past closing ';' - */ - -#if DMDV2 -Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, unsigned char *comment) -{ - Dsymbols *a = new Dsymbols; - - while (1) - { - Identifier *ident = token.ident; - nextToken(); // skip over ident - assert(token.value == TOKassign); - nextToken(); // skip over '=' - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = storageClass; - a->push(v); - if (token.value == TOKsemicolon) - { - nextToken(); - addComment(v, comment); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - addComment(v, comment); - continue; - } - else - error("Identifier expected following comma"); - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - break; - } - return a; -} -#endif - -/***************************************** - * Parse contracts following function declaration. - */ - -void Parser::parseContracts(FuncDeclaration *f) -{ - enum LINK linksave = linkage; - - // The following is irrelevant, as it is overridden by sc->linkage in - // TypeFunction::semantic - linkage = LINKd; // nested functions have D linkage -L1: - switch (token.value) - { - case TOKlcurly: - if (f->frequire || f->fensure) - error("missing body { ... } after in or out"); - f->fbody = parseStatement(PSsemi); - f->endloc = endloc; - break; - - case TOKbody: - nextToken(); - f->fbody = parseStatement(PScurly); - f->endloc = endloc; - break; - - case TOKsemicolon: - if (f->frequire || f->fensure) - error("missing body { ... } after in or out"); - nextToken(); - break; - -#if 0 // Do we want this for function declarations, so we can do: - // int x, y, foo(), z; - case TOKcomma: - nextToken(); - continue; -#endif - -#if 0 // Dumped feature - case TOKthrow: - if (!f->fthrows) - f->fthrows = new Array(); - nextToken(); - check(TOKlparen); - while (1) - { - Type *tb = parseBasicType(); - f->fthrows->push(tb); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - check(TOKrparen); - goto L1; -#endif - - case TOKin: - nextToken(); - if (f->frequire) - error("redundant 'in' statement"); - f->frequire = parseStatement(PScurly | PSscope); - goto L1; - - case TOKout: - // parse: out (identifier) { statement } - nextToken(); - if (token.value != TOKlcurly) - { - check(TOKlparen, "out"); - if (token.value != TOKidentifier) - error("(identifier) following 'out' expected, not %s", token.toChars()); - f->outId = token.ident; - nextToken(); - check(TOKrparen); - } - if (f->fensure) - error("redundant 'out' statement"); - f->fensure = parseStatement(PScurly | PSscope); - goto L1; - - default: - error("semicolon expected following function declaration"); - break; - } - linkage = linksave; -} - -/***************************************** - * Parse initializer for variable declaration. - */ - -Initializer *Parser::parseInitializer() -{ - StructInitializer *is; - ArrayInitializer *ia; - ExpInitializer *ie; - Expression *e; - Identifier *id; - Initializer *value; - int comma; - Loc loc = this->loc; - Token *t; - int braces; - int brackets; - - switch (token.value) - { - case TOKlcurly: - /* Scan ahead to see if it is a struct initializer or - * a function literal. - * If it contains a ';', it is a function literal. - * Treat { } as a struct initializer. - */ - braces = 1; - for (t = peek(&token); 1; t = peek(t)) - { - switch (t->value) - { - case TOKsemicolon: - case TOKreturn: - goto Lexpression; - - case TOKlcurly: - braces++; - continue; - - case TOKrcurly: - if (--braces == 0) - break; - continue; - - case TOKeof: - break; - - default: - continue; - } - break; - } - - is = new StructInitializer(loc); - nextToken(); - comma = 2; - while (1) - { - switch (token.value) - { - case TOKidentifier: - if (comma == 1) - error("comma expected separating field initializers"); - t = peek(&token); - if (t->value == TOKcolon) - { - id = token.ident; - nextToken(); - nextToken(); // skip over ':' - } - else - { id = NULL; - } - value = parseInitializer(); - is->addInit(id, value); - comma = 1; - continue; - - case TOKcomma: - if (comma == 2) - error("expression expected, not ','"); - nextToken(); - comma = 2; - continue; - - case TOKrcurly: // allow trailing comma's - nextToken(); - break; - - case TOKeof: - error("found EOF instead of initializer"); - break; - - default: - if (comma == 1) - error("comma expected separating field initializers"); - value = parseInitializer(); - is->addInit(NULL, value); - comma = 1; - continue; - //error("found '%s' instead of field initializer", token.toChars()); - //break; - } - break; - } - return is; - - case TOKlbracket: - /* Scan ahead to see if it is an array initializer or - * an expression. - * If it ends with a ';', it is an array initializer. - */ - brackets = 1; - for (t = peek(&token); 1; t = peek(t)) - { - switch (t->value) - { - case TOKlbracket: - brackets++; - continue; - - case TOKrbracket: - if (--brackets == 0) - { t = peek(t); - if (t->value != TOKsemicolon && - t->value != TOKcomma && - t->value != TOKrbracket && - t->value != TOKrcurly) - goto Lexpression; - break; - } - continue; - - case TOKeof: - break; - - default: - continue; - } - break; - } - - ia = new ArrayInitializer(loc); - nextToken(); - comma = 2; - while (1) - { - switch (token.value) - { - default: - if (comma == 1) - { error("comma expected separating array initializers, not %s", token.toChars()); - nextToken(); - break; - } - e = parseAssignExp(); - if (!e) - break; - if (token.value == TOKcolon) - { - nextToken(); - value = parseInitializer(); - } - else - { value = new ExpInitializer(e->loc, e); - e = NULL; - } - ia->addInit(e, value); - comma = 1; - continue; - - case TOKlcurly: - case TOKlbracket: - if (comma == 1) - error("comma expected separating array initializers, not %s", token.toChars()); - value = parseInitializer(); - if (token.value == TOKcolon) - { - nextToken(); - e = value->toExpression(); - value = parseInitializer(); - } - else - e = NULL; - ia->addInit(e, value); - comma = 1; - continue; - - case TOKcomma: - if (comma == 2) - error("expression expected, not ','"); - nextToken(); - comma = 2; - continue; - - case TOKrbracket: // allow trailing comma's - nextToken(); - break; - - case TOKeof: - error("found '%s' instead of array initializer", token.toChars()); - break; - } - break; - } - return ia; - - case TOKvoid: - t = peek(&token); - if (t->value == TOKsemicolon || t->value == TOKcomma) - { - nextToken(); - return new VoidInitializer(loc); - } - goto Lexpression; - - default: - Lexpression: - e = parseAssignExp(); - ie = new ExpInitializer(loc, e); - return ie; - } -} - -/***************************************** - * Parses default argument initializer expression that is an assign expression, - * with special handling for __FILE__ and __LINE__. - */ - -#if DMDV2 -Expression *Parser::parseDefaultInitExp() -{ - if (token.value == TOKfile || - token.value == TOKline) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKrparen) - { Expression *e; - - if (token.value == TOKfile) - e = new FileInitExp(loc); - else - e = new LineInitExp(loc); - nextToken(); - return e; - } - } - - Expression *e = parseAssignExp(); - return e; -} -#endif - -/***************************************** - * Input: - * flags PSxxxx - */ - -Statement *Parser::parseStatement(int flags) -{ Statement *s; - Token *t; - Condition *condition; - Statement *ifbody; - Statement *elsebody; - Loc loc = this->loc; - - //printf("parseStatement()\n"); - - if (flags & PScurly && token.value != TOKlcurly) - error("statement expected to be { }, not %s", token.toChars()); - - switch (token.value) - { - case TOKidentifier: - /* A leading identifier can be a declaration, label, or expression. - * The easiest case to check first is label: - */ - t = peek(&token); - if (t->value == TOKcolon) - { // It's a label - - Identifier *ident = token.ident; - nextToken(); - nextToken(); - s = parseStatement(PSsemi); - s = new LabelStatement(loc, ident, s); - break; - } - // fallthrough to TOKdot - case TOKdot: - case TOKtypeof: - if (isDeclaration(&token, 2, TOKreserved, NULL)) - goto Ldeclaration; - else - goto Lexp; - break; - - case TOKassert: - case TOKthis: - case TOKsuper: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKstring: - case TOKlparen: - case TOKcast: - case TOKmul: - case TOKmin: - case TOKadd: - case TOKplusplus: - case TOKminusminus: - case TOKnew: - case TOKdelete: - case TOKdelegate: - case TOKfunction: - case TOKtypeid: - case TOKis: - case TOKlbracket: -#if DMDV2 - case TOKtilde: - case TOKnot: - case TOKtraits: - case TOKfile: - case TOKline: -#endif - Lexp: - { - Expression *exp = parseExpression(); - check(TOKsemicolon, "statement"); - s = new ExpStatement(loc, exp); - break; - } - - case TOKstatic: - { // Look ahead to see if it's static assert() or static if() - Token *t; - - t = peek(&token); - if (t->value == TOKassert) - { - nextToken(); - s = new StaticAssertStatement(parseStaticAssert()); - break; - } - if (t->value == TOKif) - { - nextToken(); - condition = parseStaticIfCondition(); - goto Lcondition; - } - goto Ldeclaration; - } - - case BASIC_TYPES: - case TOKtypedef: - case TOKalias: - case TOKconst: - case TOKauto: - case TOKextern: - case TOKfinal: - case TOKinvariant: -#if DMDV2 - case TOKimmutable: - case TOKshared: - case TOKwild: - case TOKnothrow: - case TOKpure: - case TOKtls: - case TOKgshared: - case TOKat: -#endif -// case TOKtypeof: - Ldeclaration: - { Array *a; - - a = parseDeclarations(); - if (a->dim > 1) - { - Statements *as = new Statements(); - as->reserve(a->dim); - for (size_t i = 0; i < a->dim; i++) - { - Dsymbol *d = (Dsymbol *)a->data[i]; - s = new ExpStatement(loc, d); - as->push(s); - } - s = new CompoundDeclarationStatement(loc, as); - } - else if (a->dim == 1) - { - Dsymbol *d = (Dsymbol *)a->data[0]; - s = new ExpStatement(loc, d); - } - else - assert(0); - if (flags & PSscope) - s = new ScopeStatement(loc, s); - break; - } - - case TOKstruct: - case TOKunion: - case TOKclass: - case TOKinterface: - { Dsymbol *d; - - d = parseAggregate(); - s = new ExpStatement(loc, d); - break; - } - - case TOKenum: - { Dsymbol *d; - - d = parseEnum(); - s = new ExpStatement(loc, d); - break; - } - - case TOKmixin: - { t = peek(&token); - if (t->value == TOKlparen) - { // mixin(string) - Expression *e = parseAssignExp(); - check(TOKsemicolon); - if (e->op == TOKmixin) - { - CompileExp *cpe = (CompileExp *)e; - s = new CompileStatement(loc, cpe->e1); - } - else - { - s = new ExpStatement(loc, e); - } - break; - } - Dsymbol *d = parseMixin(); - s = new ExpStatement(loc, d); - break; - } - - case TOKlcurly: - { - nextToken(); - Statements *statements = new Statements(); - while (token.value != TOKrcurly && token.value != TOKeof) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - endloc = this->loc; - s = new CompoundStatement(loc, statements); - if (flags & (PSscope | PScurlyscope)) - s = new ScopeStatement(loc, s); - check(TOKrcurly, "compound statement"); - break; - } - - case TOKwhile: - { Expression *condition; - Statement *body; - - nextToken(); - check(TOKlparen, "while"); - condition = parseExpression(); - check(TOKrparen); - body = parseStatement(PSscope); - s = new WhileStatement(loc, condition, body); - break; - } - - case TOKsemicolon: - if (!(flags & PSsemi)) - error("use '{ }' for an empty statement, not a ';'"); - nextToken(); - s = new ExpStatement(loc, (Expression *)NULL); - break; - - case TOKdo: - { Statement *body; - Expression *condition; - - nextToken(); - body = parseStatement(PSscope); - check(TOKwhile, "statement"); - check(TOKlparen, "while"); - condition = parseExpression(); - check(TOKrparen); - s = new DoStatement(loc, body, condition); - break; - } - - case TOKfor: - { - Statement *init; - Expression *condition; - Expression *increment; - Statement *body; - - nextToken(); - check(TOKlparen, "for"); - if (token.value == TOKsemicolon) - { init = NULL; - nextToken(); - } - else - { init = parseStatement(0); - } - if (token.value == TOKsemicolon) - { - condition = NULL; - nextToken(); - } - else - { - condition = parseExpression(); - check(TOKsemicolon, "for condition"); - } - if (token.value == TOKrparen) - { increment = NULL; - nextToken(); - } - else - { increment = parseExpression(); - check(TOKrparen); - } - body = parseStatement(PSscope); - s = new ForStatement(loc, init, condition, increment, body); - if (init) - s = new ScopeStatement(loc, s); - break; - } - - case TOKforeach: - case TOKforeach_reverse: - { - enum TOK op = token.value; - - Statement *d; - Statement *body; - Expression *aggr; - - nextToken(); - check(TOKlparen, "foreach"); - - Parameters *arguments = new Parameters(); - - while (1) - { - Type *tb; - Identifier *ai = NULL; - Type *at; - unsigned storageClass; - - storageClass = STCin; - if (token.value == TOKinout || token.value == TOKref) - { storageClass = STCref; - nextToken(); - } - if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKsemicolon) - { ai = token.ident; - at = NULL; // infer argument type - nextToken(); - goto Larg; - } - } - tb = parseBasicType(); - at = parseDeclarator(tb, &ai); - if (!ai) - error("no identifier for declarator %s", at->toChars()); - Larg: - Parameter *a = new Parameter(storageClass, at, ai, NULL); - arguments->push(a); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - check(TOKsemicolon, "foreach statement"); - - aggr = parseExpression(); - check(TOKrparen); - body = parseStatement(0); - s = new ForeachStatement(loc, op, arguments, aggr, body); - break; - } - - case TOKif: - { Parameter *arg = NULL; - Expression *condition; - Statement *ifbody; - Statement *elsebody; - - nextToken(); - check(TOKlparen, "if"); - - if (token.value == TOKauto) - { - nextToken(); - if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKassign) - { - arg = new Parameter(STCin, NULL, token.ident, NULL); - nextToken(); - nextToken(); - } - else - { error("= expected following auto identifier"); - goto Lerror; - } - } - else - { error("identifier expected following auto"); - goto Lerror; - } - } - else if (isDeclaration(&token, 2, TOKassign, NULL)) - { - Type *tb; - Type *at; - Identifier *ai; - - tb = parseBasicType(); - at = parseDeclarator(tb, &ai); - check(TOKassign); - arg = new Parameter(STCin, at, ai, NULL); - } - - // Check for " ident;" - else if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKsemicolon) - { - arg = new Parameter(STCin, NULL, token.ident, NULL); - nextToken(); - nextToken(); - if (1 || !global.params.useDeprecated) - error("if (v; e) is deprecated, use if (auto v = e)"); - } - } - - condition = parseExpression(); - check(TOKrparen); - ifbody = parseStatement(PSscope); - if (token.value == TOKelse) - { - nextToken(); - elsebody = parseStatement(PSscope); - } - else - elsebody = NULL; - if (condition && ifbody) - s = new IfStatement(loc, arg, condition, ifbody, elsebody); - else - s = NULL; // don't propagate parsing errors - break; - } - - case TOKscope: - if (peek(&token)->value != TOKlparen) - goto Ldeclaration; // scope used as storage class - nextToken(); - check(TOKlparen, "scope"); - if (token.value != TOKidentifier) - { error("scope (identifier) expected"); - goto Lerror; - } - else - { TOK t = TOKon_scope_exit; - Identifier *id = token.ident; - - if (id == Id::exit) - t = TOKon_scope_exit; - else if (id == Id::failure) - t = TOKon_scope_failure; - else if (id == Id::success) - t = TOKon_scope_success; - else - error("valid scope identifiers are exit, failure, or success, not %s", id->toChars()); - nextToken(); - check(TOKrparen); - Statement *st = parseStatement(PScurlyscope); - s = new OnScopeStatement(loc, t, st); - break; - } - - case TOKdebug: - nextToken(); - condition = parseDebugCondition(); - goto Lcondition; - - case TOKversion: - nextToken(); - condition = parseVersionCondition(); - goto Lcondition; - - Lcondition: - ifbody = parseStatement(0 /*PSsemi*/); - elsebody = NULL; - if (token.value == TOKelse) - { - nextToken(); - elsebody = parseStatement(0 /*PSsemi*/); - } - s = new ConditionalStatement(loc, condition, ifbody, elsebody); - break; - - case TOKpragma: - { Identifier *ident; - Expressions *args = NULL; - Statement *body; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("pragma(identifier expected"); - goto Lerror; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma && peekNext() != TOKrparen) - args = parseArguments(); // pragma(identifier, args...); - else - check(TOKrparen); // pragma(identifier); - if (token.value == TOKsemicolon) - { nextToken(); - body = NULL; - } - else - body = parseStatement(PSsemi); - s = new PragmaStatement(loc, ident, args, body); - break; - } - - case TOKswitch: - { - nextToken(); - check(TOKlparen, "switch"); - Expression *condition = parseExpression(); - check(TOKrparen); - Statement *body = parseStatement(PSscope); - s = new SwitchStatement(loc, condition, body); - break; - } - - case TOKcase: - { Expression *exp; - Statements *statements; - Array cases; // array of Expression's - - while (1) - { - nextToken(); - exp = parseAssignExp(); - cases.push(exp); - if (token.value != TOKcomma) - break; - } - check(TOKcolon, "case expression"); - -#if DMDV2 - /* case exp: .. case last: - */ - if (token.value == TOKslice) - { - if (cases.dim > 1) - error("only one case allowed for start of case range"); - nextToken(); - check(TOKcase, ".."); - last = parseAssignExp(); - check(TOKcolon, "case expression"); - } -#endif - - statements = new Statements(); - while (token.value != TOKcase && - token.value != TOKdefault && - token.value != TOKeof && - token.value != TOKrcurly) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - s = new CompoundStatement(loc, statements); - s = new ScopeStatement(loc, s); - - // Keep cases in order by building the case statements backwards - for (size_t i = cases.dim; i; i--) - { - exp = (Expression *)cases.data[i - 1]; - s = new CaseStatement(loc, exp, s); - } - break; - } - - case TOKdefault: - { - Statements *statements; - - nextToken(); - check(TOKcolon, "default"); - - statements = new Statements(); - while (token.value != TOKcase && - token.value != TOKdefault && - token.value != TOKeof && - token.value != TOKrcurly) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - s = new CompoundStatement(loc, statements); - s = new ScopeStatement(loc, s); - s = new DefaultStatement(loc, s); - break; - } - - case TOKreturn: - { Expression *exp; - - nextToken(); - if (token.value == TOKsemicolon) - exp = NULL; - else - exp = parseExpression(); - check(TOKsemicolon, "return expression"); - s = new ReturnStatement(loc, exp); - break; - } - - case TOKbreak: - { Identifier *ident; - - nextToken(); - if (token.value == TOKidentifier) - { ident = token.ident; - nextToken(); - } - else - ident = NULL; - check(TOKsemicolon, "break statement"); - s = new BreakStatement(loc, ident); - break; - } - - case TOKcontinue: - { Identifier *ident; - - nextToken(); - if (token.value == TOKidentifier) - { ident = token.ident; - nextToken(); - } - else - ident = NULL; - check(TOKsemicolon, "continue statement"); - s = new ContinueStatement(loc, ident); - break; - } - - case TOKgoto: - { Identifier *ident; - - nextToken(); - if (token.value == TOKdefault) - { - nextToken(); - s = new GotoDefaultStatement(loc); - } - else if (token.value == TOKcase) - { - Expression *exp = NULL; - - nextToken(); - if (token.value != TOKsemicolon) - exp = parseExpression(); - s = new GotoCaseStatement(loc, exp); - } - else - { - if (token.value != TOKidentifier) - { error("Identifier expected following goto"); - ident = NULL; - } - else - { ident = token.ident; - nextToken(); - } - s = new GotoStatement(loc, ident); - } - check(TOKsemicolon, "goto statement"); - break; - } - - case TOKsynchronized: - { Expression *exp; - Statement *body; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - exp = parseExpression(); - check(TOKrparen); - } - else - exp = NULL; - body = parseStatement(PSscope); - s = new SynchronizedStatement(loc, exp, body); - break; - } - - case TOKwith: - { Expression *exp; - Statement *body; - - nextToken(); - check(TOKlparen, "with"); - exp = parseExpression(); - check(TOKrparen); - body = parseStatement(PSscope); - s = new WithStatement(loc, exp, body); - break; - } - - case TOKtry: - { Statement *body; - Catches *catches = NULL; - Statement *finalbody = NULL; - - nextToken(); - body = parseStatement(PSscope); - while (token.value == TOKcatch) - { - Statement *handler; - Catch *c; - Type *t; - Identifier *id; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlcurly || token.value != TOKlparen) - { - t = NULL; - id = NULL; - } - else - { - check(TOKlparen, "catch"); - t = parseBasicType(); - id = NULL; - t = parseDeclarator(t, &id); - check(TOKrparen); - } - handler = parseStatement(0); - c = new Catch(loc, t, id, handler); - if (!catches) - catches = new Catches(); - catches->push(c); - } - - if (token.value == TOKfinally) - { nextToken(); - finalbody = parseStatement(0); - } - - s = body; - if (!catches && !finalbody) - error("catch or finally expected following try"); - else - { if (catches) - s = new TryCatchStatement(loc, body, catches); - if (finalbody) - s = new TryFinallyStatement(loc, s, finalbody); - } - break; - } - - case TOKthrow: - { Expression *exp; - - nextToken(); - exp = parseExpression(); - check(TOKsemicolon, "throw statement"); - s = new ThrowStatement(loc, exp); - break; - } - - case TOKvolatile: - nextToken(); - s = parseStatement(PSsemi | PScurlyscope); -#if DMDV2 - if (!global.params.useDeprecated) - error("volatile statements deprecated; used synchronized statements instead"); -#endif - s = new VolatileStatement(loc, s); - break; - - case TOKasm: - { Statements *statements; - Identifier *label; - Loc labelloc; - Token *toklist; - Token **ptoklist; - - // Parse the asm block into a sequence of AsmStatements, - // each AsmStatement is one instruction. - // Separate out labels. - // Defer parsing of AsmStatements until semantic processing. - - nextToken(); - check(TOKlcurly, "asm"); - toklist = NULL; - ptoklist = &toklist; - label = NULL; - statements = new Statements(); - while (1) - { - switch (token.value) - { - case TOKidentifier: - if (!toklist) - { - // Look ahead to see if it is a label - t = peek(&token); - if (t->value == TOKcolon) - { // It's a label - label = token.ident; - labelloc = this->loc; - nextToken(); - nextToken(); - continue; - } - } - goto Ldefault; - - case TOKrcurly: - if (toklist || label) - { - error("asm statements must end in ';'"); - } - break; - - case TOKsemicolon: - s = NULL; - if (toklist || label) - { // Create AsmStatement from list of tokens we've saved - s = new AsmStatement(this->loc, toklist); - toklist = NULL; - ptoklist = &toklist; - if (label) - { s = new LabelStatement(labelloc, label, s); - label = NULL; - } - statements->push(s); - } - nextToken(); - continue; - - case TOKeof: - /* { */ - error("matching '}' expected, not end of file"); - break; - - default: - Ldefault: - *ptoklist = new Token(); - memcpy(*ptoklist, &token, sizeof(Token)); - ptoklist = &(*ptoklist)->next; - *ptoklist = NULL; - - nextToken(); - continue; - } - break; - } - s = new AsmBlockStatement(loc, statements); - nextToken(); - break; - } - - default: - error("found '%s' instead of statement", token.toChars()); - goto Lerror; - - Lerror: - while (token.value != TOKrcurly && - token.value != TOKsemicolon && - token.value != TOKeof) - nextToken(); - if (token.value == TOKsemicolon) - nextToken(); - s = NULL; - break; - } - - return s; -} - -void Parser::check(enum TOK value) -{ - check(loc, value); -} - -void Parser::check(Loc loc, enum TOK value) -{ - if (token.value != value) - error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value)); - nextToken(); -} - -void Parser::check(enum TOK value, const char *string) -{ - if (token.value != value) - error("found '%s' when expecting '%s' following %s", - token.toChars(), Token::toChars(value), string); - nextToken(); -} - -/************************************ - * Determine if the scanner is sitting on the start of a declaration. - * Input: - * needId 0 no identifier - * 1 identifier optional - * 2 must have identifier - * Output: - * if *pt is not NULL, it is set to the ending token, which would be endtok - */ - -int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt) -{ - //printf("isDeclaration(needId = %d)\n", needId); - int haveId = 0; - -#if DMDV2 - if ((t->value == TOKconst || - t->value == TOKinvariant || - t->value == TOKimmutable || - t->value == TOKwild || - t->value == TOKshared) && - peek(t)->value != TOKlparen) - { /* const type - * immutable type - * shared type - * wild type - */ - t = peek(t); - } -#endif - - if (!isBasicType(&t)) - { - goto Lisnot; - } - if (!isDeclarator(&t, &haveId, endtok)) - goto Lisnot; - if ( needId == 1 || - (needId == 0 && !haveId) || - (needId == 2 && haveId)) - { if (pt) - *pt = t; - goto Lis; - } - else - goto Lisnot; - -Lis: - //printf("\tis declaration, t = %s\n", t->toChars()); - return TRUE; - -Lisnot: - //printf("\tis not declaration\n"); - return FALSE; -} - -int Parser::isBasicType(Token **pt) -{ - // This code parallels parseBasicType() - Token *t = *pt; - - switch (t->value) - { - case BASIC_TYPES: - t = peek(t); - break; - - case TOKidentifier: - t = peek(t); - if (t->value == TOKnot) - { - goto L4; - } - goto L3; - while (1) - { - L2: - t = peek(t); - L3: - if (t->value == TOKdot) - { - Ldot: - t = peek(t); - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - if (t->value != TOKnot) - goto L3; - L4: - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - if (!skipParens(t, &t)) - goto Lfalse; - } - else - break; - } - break; - - case TOKdot: - goto Ldot; - - case TOKtypeof: - /* typeof(exp).identifier... - */ - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - if (!skipParens(t, &t)) - goto Lfalse; - goto L2; - - default: - goto Lfalse; - } - *pt = t; - //printf("is\n"); - return TRUE; - -Lfalse: - //printf("is not\n"); - return FALSE; -} - -int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok) -{ // This code parallels parseDeclarator() - Token *t = *pt; - int parens; - - //printf("Parser::isDeclarator()\n"); - //t->print(); - if (t->value == TOKassign) - return FALSE; - - while (1) - { - parens = FALSE; - switch (t->value) - { - case TOKmul: - //case TOKand: - t = peek(t); - continue; - - case TOKlbracket: - t = peek(t); - if (t->value == TOKrbracket) - { - t = peek(t); - } - else if (isDeclaration(t, 0, TOKrbracket, &t)) - { // It's an associative array declaration - t = peek(t); - } - else - { - // [ expression ] - // [ expression .. expression ] - if (!isExpression(&t)) - return FALSE; - if (t->value == TOKslice) - { t = peek(t); - if (!isExpression(&t)) - return FALSE; - } - if (t->value != TOKrbracket) - return FALSE; - t = peek(t); - } - continue; - - case TOKidentifier: - if (*haveId) - return FALSE; - *haveId = TRUE; - t = peek(t); - break; - - case TOKlparen: - t = peek(t); - - if (t->value == TOKrparen) - return FALSE; // () is not a declarator - - /* Regard ( identifier ) as not a declarator - * BUG: what about ( *identifier ) in - * f(*p)(x); - * where f is a class instance with overloaded () ? - * Should we just disallow C-style function pointer declarations? - */ - if (t->value == TOKidentifier) - { Token *t2 = peek(t); - if (t2->value == TOKrparen) - return FALSE; - } - - - if (!isDeclarator(&t, haveId, TOKrparen)) - return FALSE; - t = peek(t); - parens = TRUE; - break; - - case TOKdelegate: - case TOKfunction: - t = peek(t); - if (!isParameters(&t)) - return FALSE; - continue; - } - break; - } - - while (1) - { - switch (t->value) - { -#if CARRAYDECL - case TOKlbracket: - parens = FALSE; - t = peek(t); - if (t->value == TOKrbracket) - { - t = peek(t); - } - else if (isDeclaration(t, 0, TOKrbracket, &t)) - { // It's an associative array declaration - t = peek(t); - } - else - { - // [ expression ] - if (!isExpression(&t)) - return FALSE; - if (t->value != TOKrbracket) - return FALSE; - t = peek(t); - } - continue; -#endif - - case TOKlparen: - parens = FALSE; - if (!isParameters(&t)) - return FALSE; -#if DMDV2 - while (1) - { - switch (t->value) - { - case TOKconst: - case TOKinvariant: - case TOKimmutable: - case TOKshared: - case TOKwild: - case TOKpure: - case TOKnothrow: - t = peek(t); - continue; - case TOKat: - t = peek(t); // skip '@' - t = peek(t); // skip identifier - continue; - default: - break; - } - break; - } -#endif - continue; - - // Valid tokens that follow a declaration - case TOKrparen: - case TOKrbracket: - case TOKassign: - case TOKcomma: - case TOKdotdotdot: - case TOKsemicolon: - case TOKlcurly: - case TOKin: - case TOKout: - case TOKbody: - // The !parens is to disallow unnecessary parentheses - if (!parens && (endtok == TOKreserved || endtok == t->value)) - { *pt = t; - return TRUE; - } - return FALSE; - - default: - return FALSE; - } - } -} - - -int Parser::isParameters(Token **pt) -{ // This code parallels parseParameters() - Token *t = *pt; - int tmp; - - //printf("isParameters()\n"); - if (t->value != TOKlparen) - return FALSE; - - t = peek(t); - while (1) - { - switch (t->value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - t = peek(t); - break; - - case TOKin: - case TOKout: - case TOKinout: - case TOKref: - case TOKlazy: - t = peek(t); - default: - if (!isBasicType(&t)) - return FALSE; - tmp = FALSE; - if (t->value != TOKdotdotdot && - !isDeclarator(&t, &tmp, TOKreserved)) - return FALSE; - if (t->value == TOKassign) - { t = peek(t); - if (!isExpression(&t)) - return FALSE; - } - if (t->value == TOKdotdotdot) - { - t = peek(t); - break; - } - if (t->value == TOKcomma) - { t = peek(t); - continue; - } - break; - } - break; - } - if (t->value != TOKrparen) - return FALSE; - t = peek(t); - *pt = t; - return TRUE; -} - -int Parser::isExpression(Token **pt) -{ - // This is supposed to determine if something is an expression. - // What it actually does is scan until a closing right bracket - // is found. - - Token *t = *pt; - int brnest = 0; - int panest = 0; - - for (;; t = peek(t)) - { - switch (t->value) - { - case TOKlbracket: - brnest++; - continue; - - case TOKrbracket: - if (--brnest >= 0) - continue; - break; - - case TOKlparen: - panest++; - continue; - - case TOKcomma: - if (brnest || panest) - continue; - break; - - case TOKrparen: - if (--panest >= 0) - continue; - break; - - case TOKslice: - if (brnest) - continue; - break; - - case TOKeof: - return FALSE; - - default: - continue; - } - break; - } - - *pt = t; - return TRUE; -} - -/********************************************** - * Skip over - * instance foo.bar(parameters...) - * Output: - * if (pt), *pt is set to the token following the closing ) - * Returns: - * 1 it's valid instance syntax - * 0 invalid instance syntax - */ - -int Parser::isTemplateInstance(Token *t, Token **pt) -{ - t = peek(t); - if (t->value != TOKdot) - { - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - } - while (t->value == TOKdot) - { - t = peek(t); - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - } - if (t->value != TOKlparen) - goto Lfalse; - - // Skip over the template arguments - while (1) - { - while (1) - { - t = peek(t); - switch (t->value) - { - case TOKlparen: - if (!skipParens(t, &t)) - goto Lfalse; - continue; - case TOKrparen: - break; - case TOKcomma: - break; - case TOKeof: - case TOKsemicolon: - goto Lfalse; - default: - continue; - } - break; - } - - if (t->value != TOKcomma) - break; - } - if (t->value != TOKrparen) - goto Lfalse; - t = peek(t); - if (pt) - *pt = t; - return 1; - -Lfalse: - return 0; -} - -/******************************************* - * Skip parens, brackets. - * Input: - * t is on opening ( - * Output: - * *pt is set to closing token, which is ')' on success - * Returns: - * !=0 successful - * 0 some parsing error - */ - -int Parser::skipParens(Token *t, Token **pt) -{ - int parens = 0; - - while (1) - { - switch (t->value) - { - case TOKlparen: - parens++; - break; - - case TOKrparen: - parens--; - if (parens < 0) - goto Lfalse; - if (parens == 0) - goto Ldone; - break; - - case TOKeof: - goto Lfalse; - - default: - break; - } - t = peek(t); - } - - Ldone: - if (*pt) - *pt = t; - return 1; - - Lfalse: - return 0; -} - -/********************************* Expression Parser ***************************/ - -Expression *Parser::parsePrimaryExp() -{ Expression *e; - Type *t; - Identifier *id; - enum TOK save; - Loc loc = this->loc; - - //printf("parsePrimaryExp(): loc = %d\n", loc.linnum); - switch (token.value) - { - case TOKidentifier: - id = token.ident; - nextToken(); - if (token.value == TOKnot && peek(&token)->value == TOKlparen) - { // identifier!(template-argument-list) - TemplateInstance *tempinst; - - tempinst = new TemplateInstance(loc, id); - nextToken(); - tempinst->tiargs = parseTemplateArgumentList(); - e = new ScopeExp(loc, tempinst); - } - else - e = new IdentifierExp(loc, id); - break; - - case TOKdollar: - if (!inBrackets) - error("'$' is valid only inside [] of index or slice"); - e = new DollarExp(loc); - nextToken(); - break; - - case TOKdot: - // Signal global scope '.' operator with "" identifier - e = new IdentifierExp(loc, Id::empty); - break; - - case TOKthis: - e = new ThisExp(loc); - nextToken(); - break; - - case TOKsuper: - e = new SuperExp(loc); - nextToken(); - break; - - case TOKint32v: - e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32); - nextToken(); - break; - - case TOKuns32v: - e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32); - nextToken(); - break; - - case TOKint64v: - e = new IntegerExp(loc, token.int64value, Type::tint64); - nextToken(); - break; - - case TOKuns64v: - e = new IntegerExp(loc, token.uns64value, Type::tuns64); - nextToken(); - break; - - case TOKfloat32v: - e = new RealExp(loc, token.float80value, Type::tfloat32); - nextToken(); - break; - - case TOKfloat64v: - e = new RealExp(loc, token.float80value, Type::tfloat64); - nextToken(); - break; - - case TOKfloat80v: - e = new RealExp(loc, token.float80value, Type::tfloat80); - nextToken(); - break; - - case TOKimaginary32v: - e = new RealExp(loc, token.float80value, Type::timaginary32); - nextToken(); - break; - - case TOKimaginary64v: - e = new RealExp(loc, token.float80value, Type::timaginary64); - nextToken(); - break; - - case TOKimaginary80v: - e = new RealExp(loc, token.float80value, Type::timaginary80); - nextToken(); - break; - - case TOKnull: - e = new NullExp(loc); - nextToken(); - break; - -#if DMDV2 - case TOKfile: - { const char *s = loc.filename ? loc.filename : mod->ident->toChars(); - e = new StringExp(loc, (char *)s, strlen(s), 0); - nextToken(); - break; - } - - case TOKline: - e = new IntegerExp(loc, loc.linnum, Type::tint32); - nextToken(); - break; -#endif - - case TOKtrue: - e = new IntegerExp(loc, 1, Type::tbool); - nextToken(); - break; - - case TOKfalse: - e = new IntegerExp(loc, 0, Type::tbool); - nextToken(); - break; - - case TOKcharv: - e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar); - nextToken(); - break; - - case TOKwcharv: - e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar); - nextToken(); - break; - - case TOKdcharv: - e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar); - nextToken(); - break; - - case TOKstring: - { unsigned char *s; - unsigned len; - unsigned char postfix; - - // cat adjacent strings - s = token.ustring; - len = token.len; - postfix = token.postfix; - while (1) - { - nextToken(); - if (token.value == TOKstring) - { unsigned len1; - unsigned len2; - unsigned char *s2; - - if (token.postfix) - { if (token.postfix != postfix) - error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix); - postfix = token.postfix; - } - - len1 = len; - len2 = token.len; - len = len1 + len2; - s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char)); - memcpy(s2, s, len1 * sizeof(unsigned char)); - memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char)); - s = s2; - } - else - break; - } - e = new StringExp(loc, s, len, postfix); - break; - } - - case BASIC_TYPES_X(t): - nextToken(); - check(TOKdot, t->toChars()); - if (token.value != TOKidentifier) - { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars()); - goto Lerr; - } - e = typeDotIdExp(loc, t, token.ident); - nextToken(); - break; - - case TOKtypeof: - { Expression *exp; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - t = new TypeTypeof(loc, exp); - e = new TypeExp(loc, t); - break; - } - - case TOKtypeid: - { Type *t; - - nextToken(); - check(TOKlparen, "typeid"); - t = parseBasicType(); - t = parseDeclarator(t,NULL); // ( type ) - check(TOKrparen); - e = new TypeidExp(loc, t); - break; - } - -#if DMDV2 - case TOKtraits: - { /* __traits(identifier, args...) - */ - Identifier *ident; - Objects *args = NULL; - - nextToken(); - check(TOKlparen, "__traits"); - if (token.value != TOKidentifier) - { error("__traits(identifier, args...) expected"); - goto Lerr; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma) - args = parseTemplateArgumentList2(); // __traits(identifier, args...) - else - check(TOKrparen); // __traits(identifier) - - e = new TraitsExp(loc, ident, args); - break; - } -#endif - - case TOKis: - { Type *targ; - Identifier *ident = NULL; - Type *tspec = NULL; - enum TOK tok = TOKreserved; - enum TOK tok2 = TOKreserved; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - targ = parseBasicType(); - targ = parseDeclarator(targ, &ident); - if (token.value == TOKcolon || token.value == TOKequal) - { - tok = token.value; - nextToken(); - if (tok == TOKequal && - (token.value == TOKtypedef || - token.value == TOKstruct || - token.value == TOKunion || - token.value == TOKclass || - token.value == TOKsuper || - token.value == TOKenum || - token.value == TOKinterface || - token.value == TOKargTypes || -#if DMDV2 - token.value == TOKconst && peek(&token)->value == TOKrparen || - token.value == TOKinvariant && peek(&token)->value == TOKrparen || - token.value == TOKimmutable && peek(&token)->value == TOKrparen || - token.value == TOKshared && peek(&token)->value == TOKrparen || -#endif - token.value == TOKfunction || - token.value == TOKdelegate || - token.value == TOKreturn)) - { - tok2 = token.value; - nextToken(); - } - else - { - tspec = parseBasicType(); - tspec = parseDeclarator(tspec, NULL); - } - } - check(TOKrparen); - } - else - { error("(type identifier : specialization) expected following is"); - goto Lerr; - } - e = new IsExp(loc, targ, ident, tok, tspec, tok2); - break; - } - - case TOKassert: - { Expression *msg = NULL; - - nextToken(); - check(TOKlparen, "assert"); - e = parseAssignExp(); - if (token.value == TOKcomma) - { nextToken(); - msg = parseAssignExp(); - } - check(TOKrparen); - e = new AssertExp(loc, e, msg); - break; - } - - case TOKmixin: - { - nextToken(); - check(TOKlparen, "mixin"); - e = parseAssignExp(); - check(TOKrparen); - e = new CompileExp(loc, e); - break; - } - - case TOKimport: - { - nextToken(); - check(TOKlparen, "import"); - e = parseAssignExp(); - check(TOKrparen); - e = new FileExp(loc, e); - break; - } - - case TOKlparen: - if (peekPastParen(&token)->value == TOKlcurly) - { // (arguments) { statements... } - save = TOKdelegate; - goto case_delegate; - } - // ( expression ) - nextToken(); - e = parseExpression(); - check(loc, TOKrparen); - break; - - case TOKlbracket: - { /* Parse array literals and associative array literals: - * [ value, value, value ... ] - * [ key:value, key:value, key:value ... ] - */ - Expressions *values = new Expressions(); - Expressions *keys = NULL; - - nextToken(); - if (token.value != TOKrbracket) - { - while (token.value != TOKeof) - { - Expression *e = parseAssignExp(); - if (token.value == TOKcolon && (keys || values->dim == 0)) - { nextToken(); - if (!keys) - keys = new Expressions(); - keys->push(e); - e = parseAssignExp(); - } - else if (keys) - { error("'key:value' expected for associative array literal"); - delete keys; - keys = NULL; - } - values->push(e); - if (token.value == TOKrbracket) - break; - check(TOKcomma, "literal element"); - } - } - check(TOKrbracket); - - if (keys) - e = new AssocArrayLiteralExp(loc, keys, values); - else - e = new ArrayLiteralExp(loc, values); - break; - } - - case TOKlcurly: - // { statements... } - save = TOKdelegate; - goto case_delegate; - - case TOKfunction: - case TOKdelegate: - save = token.value; - nextToken(); - case_delegate: - { - /* function type(parameters) { body } - * delegate type(parameters) { body } - */ - Parameters *arguments; - int varargs; - FuncLiteralDeclaration *fd; - Type *t; - - if (token.value == TOKlcurly) - { - t = NULL; - varargs = 0; - arguments = new Parameters(); - } - else - { - if (token.value == TOKlparen) - t = NULL; - else - { - t = parseBasicType(); - t = parseBasicType2(t); // function return type - } - arguments = parseParameters(&varargs); - } - t = new TypeFunction(arguments, t, varargs, linkage); - fd = new FuncLiteralDeclaration(loc, 0, t, save, NULL); - parseContracts(fd); - e = new FuncExp(loc, fd); - break; - } - - default: - error("expression expected, not '%s'", token.toChars()); - Lerr: - // Anything for e, as long as it's not NULL - e = new IntegerExp(loc, 0, Type::tint32); - nextToken(); - break; - } - return parsePostExp(e); -} - -Expression *Parser::parsePostExp(Expression *e) -{ - Loc loc; - - while (1) - { - loc = this->loc; - switch (token.value) - { - case TOKdot: - nextToken(); - if (token.value == TOKidentifier) - { Identifier *id = token.ident; - - nextToken(); - if (token.value == TOKnot && peek(&token)->value == TOKlparen) - { // identifier!(template-argument-list) - TemplateInstance *tempinst; - - tempinst = new TemplateInstance(loc, id); - nextToken(); - tempinst->tiargs = parseTemplateArgumentList(); - e = new DotTemplateInstanceExp(loc, e, tempinst); - } - else - e = new DotIdExp(loc, e, id); - continue; - } - else if (token.value == TOKnew) - { - e = parseNewExp(e); - continue; - } - else - error("identifier expected following '.', not '%s'", token.toChars()); - break; - - case TOKplusplus: - e = new PostExp(TOKplusplus, loc, e); - break; - - case TOKminusminus: - e = new PostExp(TOKminusminus, loc, e); - break; - - case TOKlparen: - e = new CallExp(loc, e, parseArguments()); - continue; - - case TOKlbracket: - { // array dereferences: - // array[index] - // array[] - // array[lwr .. upr] - Expression *index; - Expression *upr; - - inBrackets++; - nextToken(); - if (token.value == TOKrbracket) - { // array[] - inBrackets--; - e = new SliceExp(loc, e, NULL, NULL); - nextToken(); - } - else - { - index = parseAssignExp(); - if (token.value == TOKslice) - { // array[lwr .. upr] - nextToken(); - upr = parseAssignExp(); - e = new SliceExp(loc, e, index, upr); - } - else - { // array[index, i2, i3, i4, ...] - Expressions *arguments = new Expressions(); - arguments->push(index); - if (token.value == TOKcomma) - { - nextToken(); - while (1) - { - Expression *arg = parseAssignExp(); - arguments->push(arg); - if (token.value == TOKrbracket) - break; - check(TOKcomma, "array literal element"); - } - } - e = new ArrayExp(loc, e, arguments); - } - check(TOKrbracket); - inBrackets--; - } - continue; - } - - default: - return e; - } - nextToken(); - } -} - -Expression *Parser::parseUnaryExp() -{ Expression *e; - Loc loc = this->loc; - - switch (token.value) - { - case TOKand: - nextToken(); - e = parseUnaryExp(); - e = new AddrExp(loc, e); - break; - - case TOKplusplus: - nextToken(); - e = parseUnaryExp(); - e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - break; - - case TOKminusminus: - nextToken(); - e = parseUnaryExp(); - e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - break; - - case TOKmul: - nextToken(); - e = parseUnaryExp(); - e = new PtrExp(loc, e); - break; - - case TOKmin: - nextToken(); - e = parseUnaryExp(); - e = new NegExp(loc, e); - break; - - case TOKadd: - nextToken(); - e = parseUnaryExp(); - e = new UAddExp(loc, e); - break; - - case TOKnot: - nextToken(); - e = parseUnaryExp(); - e = new NotExp(loc, e); - break; - - case TOKtilde: - nextToken(); - e = parseUnaryExp(); - e = new ComExp(loc, e); - break; - - case TOKdelete: - nextToken(); - e = parseUnaryExp(); - e = new DeleteExp(loc, e); - break; - - case TOKnew: - e = parseNewExp(NULL); - break; - - case TOKcast: // cast(type) expression - { Type *t; - - nextToken(); - check(TOKlparen); - t = parseBasicType(); - t = parseDeclarator(t,NULL); // ( type ) - check(TOKrparen); - - e = parseUnaryExp(); - e = new CastExp(loc, e, t); - break; - } - - case TOKlparen: - { Token *tk; - - tk = peek(&token); -#if CCASTSYNTAX - // If cast - if (isDeclaration(tk, 0, TOKrparen, &tk)) - { - tk = peek(tk); // skip over right parenthesis - switch (tk->value) - { - case TOKnot: - tk = peek(tk); - if (tk->value == TOKis) // !is - break; - case TOKdot: - case TOKplusplus: - case TOKminusminus: - case TOKdelete: - case TOKnew: - case TOKlparen: - case TOKidentifier: - case TOKthis: - case TOKsuper: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKstring: -#if 0 - case TOKtilde: - case TOKand: - case TOKmul: - case TOKmin: - case TOKadd: -#endif - case TOKfunction: - case TOKdelegate: - case TOKtypeof: -#if DMDV2 - case TOKfile: - case TOKline: -#endif - case BASIC_TYPES: // (type)int.size - { // (type) una_exp - Type *t; - - nextToken(); - t = parseBasicType(); - t = parseDeclarator(t,NULL); - check(TOKrparen); - - // if .identifier - if (token.value == TOKdot) - { - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following (type)."); - return NULL; - } - e = typeDotIdExp(loc, t, token.ident); - nextToken(); - e = parsePostExp(e); - } - else - { - e = parseUnaryExp(); - e = new CastExp(loc, e, t); - error("C style cast illegal, use %s", e->toChars()); - } - return e; - } - } - } -#endif - e = parsePrimaryExp(); - break; - } - default: - e = parsePrimaryExp(); - break; - } - assert(e); - return e; -} - -Expression *Parser::parseMulExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseUnaryExp(); - while (1) - { - switch (token.value) - { - case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue; - case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue; - case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseAddExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseMulExp(); - while (1) - { - switch (token.value) - { - case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue; - case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue; - case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseShiftExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAddExp(); - while (1) - { - switch (token.value) - { - case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue; - case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue; - case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseRelExp() -{ Expression *e; - Expression *e2; - enum TOK op; - Loc loc = this->loc; - - e = parseShiftExp(); - while (1) - { - switch (token.value) - { - case TOKlt: - case TOKle: - case TOKgt: - case TOKge: - case TOKunord: - case TOKlg: - case TOKleg: - case TOKule: - case TOKul: - case TOKuge: - case TOKug: - case TOKue: - op = token.value; - nextToken(); - e2 = parseShiftExp(); - e = new CmpExp(op, loc, e, e2); - continue; - -#if DMDV2 - case TOKnot: // could be !in - if (peekNext() == TOKin) - { - nextToken(); - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - e = new NotExp(loc, e); - continue; - } - break; -#endif - - case TOKin: - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseEqualExp() -{ Expression *e; - Expression *e2; - Token *t; - Loc loc = this->loc; - - e = parseRelExp(); - while (1) - { enum TOK value = token.value; - - switch (value) - { - case TOKequal: - case TOKnotequal: - nextToken(); - e2 = parseRelExp(); - e = new EqualExp(value, loc, e, e2); - continue; - - case TOKidentity: - error("'===' is no longer legal, use 'is' instead"); - goto L1; - - case TOKnotidentity: - error("'!==' is no longer legal, use '!is' instead"); - goto L1; - - case TOKis: - value = TOKidentity; - goto L1; - - case TOKnot: - // Attempt to identify '!is' - t = peek(&token); - if (t->value != TOKis) - break; - nextToken(); - value = TOKnotidentity; - goto L1; - - L1: - nextToken(); - e2 = parseRelExp(); - e = new IdentityExp(value, loc, e, e2); - continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseCmpExp() -{ Expression *e; - Expression *e2; - Token *t; - Loc loc = this->loc; - - e = parseShiftExp(); - enum TOK op = token.value; - - switch (op) - { - case TOKequal: - case TOKnotequal: - nextToken(); - e2 = parseShiftExp(); - e = new EqualExp(op, loc, e, e2); - break; - - case TOKis: - op = TOKidentity; - goto L1; - - case TOKnot: - // Attempt to identify '!is' - t = peek(&token); -#if DMDV2 - if (t->value == TOKin) - { - nextToken(); - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - e = new NotExp(loc, e); - break; - } -#endif - if (t->value != TOKis) - break; - nextToken(); - op = TOKnotidentity; - goto L1; - - L1: - nextToken(); - e2 = parseShiftExp(); - e = new IdentityExp(op, loc, e, e2); - break; - - case TOKlt: - case TOKle: - case TOKgt: - case TOKge: - case TOKunord: - case TOKlg: - case TOKleg: - case TOKule: - case TOKul: - case TOKuge: - case TOKug: - case TOKue: - nextToken(); - e2 = parseShiftExp(); - e = new CmpExp(op, loc, e, e2); - break; - - case TOKin: - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - break; - - default: - break; - } - return e; -} - -Expression *Parser::parseAndExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - if (global.params.Dversion == 1) - { - e = parseEqualExp(); - while (token.value == TOKand) - { - nextToken(); - e2 = parseEqualExp(); - e = new AndExp(loc,e,e2); - loc = this->loc; - } - } - else - { - e = parseCmpExp(); - while (token.value == TOKand) - { - nextToken(); - e2 = parseCmpExp(); - e = new AndExp(loc,e,e2); - loc = this->loc; - } - } - return e; -} - -Expression *Parser::parseXorExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAndExp(); - while (token.value == TOKxor) - { - nextToken(); - e2 = parseAndExp(); - e = new XorExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseOrExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseXorExp(); - while (token.value == TOKor) - { - nextToken(); - e2 = parseXorExp(); - e = new OrExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseAndAndExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseOrExp(); - while (token.value == TOKandand) - { - nextToken(); - e2 = parseOrExp(); - e = new AndAndExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseOrOrExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAndAndExp(); - while (token.value == TOKoror) - { - nextToken(); - e2 = parseAndAndExp(); - e = new OrOrExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseCondExp() -{ Expression *e; - Expression *e1; - Expression *e2; - Loc loc = this->loc; - - e = parseOrOrExp(); - if (token.value == TOKquestion) - { - nextToken(); - e1 = parseExpression(); - check(TOKcolon, "condition ? expression"); - e2 = parseCondExp(); - e = new CondExp(loc, e, e1, e2); - } - return e; -} - -Expression *Parser::parseAssignExp() -{ Expression *e; - Expression *e2; - Loc loc; - - e = parseCondExp(); - while (1) - { - loc = this->loc; - switch (token.value) - { -#define X(tok,ector) \ - case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue; - - X(TOKassign, AssignExp); - X(TOKaddass, AddAssignExp); - X(TOKminass, MinAssignExp); - X(TOKmulass, MulAssignExp); - X(TOKdivass, DivAssignExp); - X(TOKmodass, ModAssignExp); - X(TOKandass, AndAssignExp); - X(TOKorass, OrAssignExp); - X(TOKxorass, XorAssignExp); - X(TOKshlass, ShlAssignExp); - X(TOKshrass, ShrAssignExp); - X(TOKushrass, UshrAssignExp); - X(TOKcatass, CatAssignExp); - -#undef X - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseExpression() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - //printf("Parser::parseExpression() loc = %d\n", loc.linnum); - e = parseAssignExp(); - while (token.value == TOKcomma) - { - nextToken(); - e2 = parseAssignExp(); - e = new CommaExp(loc, e, e2); - loc = this->loc; - } - return e; -} - - -/************************* - * Collect argument list. - * Assume current token is '(' or '['. - */ - -Expressions *Parser::parseArguments() -{ // function call - Expressions *arguments; - Expression *arg; - enum TOK endtok; - - arguments = new Expressions(); - if (token.value == TOKlbracket) - endtok = TOKrbracket; - else - endtok = TOKrparen; - - { - nextToken(); - if (token.value != endtok) - { - while (token.value != TOKeof) - { - arg = parseAssignExp(); - arguments->push(arg); - if (token.value == endtok) - break; - check(TOKcomma, "argument"); - } - } - check(endtok, "argument list"); - } - return arguments; -} - -/******************************************* - */ - -Expression *Parser::parseNewExp(Expression *thisexp) -{ Type *t; - Expressions *newargs; - Expressions *arguments = NULL; - Expression *e; - Loc loc = this->loc; - - nextToken(); - newargs = NULL; - if (token.value == TOKlparen) - { - newargs = parseArguments(); - } - - // An anonymous nested class starts with "class" - if (token.value == TOKclass) - { - nextToken(); - if (token.value == TOKlparen) - arguments = parseArguments(); - - BaseClasses *baseclasses = NULL; - if (token.value != TOKlcurly) - baseclasses = parseBaseClasses(); - - Identifier *id = NULL; - ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses); - - if (token.value != TOKlcurly) - { error("{ members } expected for anonymous class"); - cd->members = NULL; - } - else - { - nextToken(); - Dsymbols *decl = parseDeclDefs(0); - if (token.value != TOKrcurly) - error("class member expected"); - nextToken(); - cd->members = decl; - } - - e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments); - - return e; - } - -#if LTORARRAYDECL - t = parseBasicType(); - t = parseBasicType2(t); - if (t->ty == Taarray) - { - Type *index = ((TypeAArray *)t)->index; - - Expression *e = index->toExpression(); - if (e) - { arguments = new Expressions(); - arguments->push(e); - t = new TypeDArray(t->next); - } - else - { - error("need size of rightmost array, not type %s", index->toChars()); - return new NullExp(loc); - } - } - else if (t->ty == Tsarray) - { - TypeSArray *tsa = (TypeSArray *)t; - Expression *e = tsa->dim; - - arguments = new Expressions(); - arguments->push(e); - t = new TypeDArray(t->next); - } - else if (token.value == TOKlparen) - { - arguments = parseArguments(); - } -#else - t = parseBasicType(); - while (token.value == TOKmul) - { t = new TypePointer(t); - nextToken(); - } - if (token.value == TOKlbracket) - { - Expression *e; - - nextToken(); - e = parseAssignExp(); - arguments = new Array(); - arguments->push(e); - check(TOKrbracket); - t = parseDeclarator(t, NULL); - t = new TypeDArray(t); - } - else if (token.value == TOKlparen) - arguments = parseArguments(); -#endif - e = new NewExp(loc, thisexp, newargs, t, arguments); - return e; -} - -/********************************************** - */ - -void Parser::addComment(Dsymbol *s, unsigned char *blockComment) -{ - s->addComment(combineComments(blockComment, token.lineComment)); - token.lineComment = NULL; -} - -/********************************** - * Set operator precedence for each operator. - */ - -enum PREC precedence[TOKMAX]; - -void initPrecedence() -{ - for (size_t i = 0; i < TOKMAX; i++) - precedence[i] = PREC_zero; - - precedence[TOKtype] = PREC_expr; - precedence[TOKerror] = PREC_expr; - - precedence[TOKtypeof] = PREC_primary; - precedence[TOKmixin] = PREC_primary; - - precedence[TOKdotvar] = PREC_primary; - precedence[TOKimport] = PREC_primary; - precedence[TOKidentifier] = PREC_primary; - precedence[TOKthis] = PREC_primary; - precedence[TOKsuper] = PREC_primary; - precedence[TOKint64] = PREC_primary; - precedence[TOKfloat64] = PREC_primary; - precedence[TOKcomplex80] = PREC_primary; - precedence[TOKnull] = PREC_primary; - precedence[TOKstring] = PREC_primary; - precedence[TOKarrayliteral] = PREC_primary; - precedence[TOKassocarrayliteral] = PREC_primary; -#if DMDV2 - precedence[TOKfile] = PREC_primary; - precedence[TOKline] = PREC_primary; -#endif - precedence[TOKtypeid] = PREC_primary; - precedence[TOKis] = PREC_primary; - precedence[TOKassert] = PREC_primary; - precedence[TOKhalt] = PREC_primary; - precedence[TOKtemplate] = PREC_primary; - precedence[TOKdsymbol] = PREC_primary; - precedence[TOKfunction] = PREC_primary; - precedence[TOKvar] = PREC_primary; - precedence[TOKsymoff] = PREC_primary; - precedence[TOKstructliteral] = PREC_primary; - precedence[TOKarraylength] = PREC_primary; - precedence[TOKremove] = PREC_primary; - precedence[TOKtuple] = PREC_primary; -#if DMDV2 - precedence[TOKtraits] = PREC_primary; - precedence[TOKdefault] = PREC_primary; - precedence[TOKoverloadset] = PREC_primary; - precedence[TOKvoid] = PREC_primary; -#endif - - // post - precedence[TOKdotti] = PREC_primary; - precedence[TOKdot] = PREC_primary; - precedence[TOKdottd] = PREC_primary; - precedence[TOKdotexp] = PREC_primary; - precedence[TOKdottype] = PREC_primary; -// precedence[TOKarrow] = PREC_primary; - precedence[TOKplusplus] = PREC_primary; - precedence[TOKminusminus] = PREC_primary; -#if DMDV2 - precedence[TOKpreplusplus] = PREC_primary; - precedence[TOKpreminusminus] = PREC_primary; -#endif - precedence[TOKcall] = PREC_primary; - precedence[TOKslice] = PREC_primary; - precedence[TOKarray] = PREC_primary; - precedence[TOKindex] = PREC_primary; - - precedence[TOKdelegate] = PREC_unary; - precedence[TOKaddress] = PREC_unary; - precedence[TOKstar] = PREC_unary; - precedence[TOKneg] = PREC_unary; - precedence[TOKuadd] = PREC_unary; - precedence[TOKnot] = PREC_unary; - precedence[TOKtobool] = PREC_add; - precedence[TOKtilde] = PREC_unary; - precedence[TOKdelete] = PREC_unary; - precedence[TOKnew] = PREC_unary; - precedence[TOKnewanonclass] = PREC_unary; - precedence[TOKcast] = PREC_unary; - -#if DMDV2 - precedence[TOKpow] = PREC_pow; -#endif - - precedence[TOKmul] = PREC_mul; - precedence[TOKdiv] = PREC_mul; - precedence[TOKmod] = PREC_mul; - - precedence[TOKadd] = PREC_add; - precedence[TOKmin] = PREC_add; - precedence[TOKcat] = PREC_add; - - precedence[TOKshl] = PREC_shift; - precedence[TOKshr] = PREC_shift; - precedence[TOKushr] = PREC_shift; - - precedence[TOKlt] = PREC_rel; - precedence[TOKle] = PREC_rel; - precedence[TOKgt] = PREC_rel; - precedence[TOKge] = PREC_rel; - precedence[TOKunord] = PREC_rel; - precedence[TOKlg] = PREC_rel; - precedence[TOKleg] = PREC_rel; - precedence[TOKule] = PREC_rel; - precedence[TOKul] = PREC_rel; - precedence[TOKuge] = PREC_rel; - precedence[TOKug] = PREC_rel; - precedence[TOKue] = PREC_rel; - precedence[TOKin] = PREC_rel; - -#if 0 - precedence[TOKequal] = PREC_equal; - precedence[TOKnotequal] = PREC_equal; - precedence[TOKidentity] = PREC_equal; - precedence[TOKnotidentity] = PREC_equal; -#else - /* Note that we changed precedence, so that < and != have the same - * precedence. This change is in the parser, too. - */ - precedence[TOKequal] = PREC_rel; - precedence[TOKnotequal] = PREC_rel; - precedence[TOKidentity] = PREC_rel; - precedence[TOKnotidentity] = PREC_rel; -#endif - - precedence[TOKand] = PREC_and; - - precedence[TOKxor] = PREC_xor; - - precedence[TOKor] = PREC_or; - - precedence[TOKandand] = PREC_andand; - - precedence[TOKoror] = PREC_oror; - - precedence[TOKquestion] = PREC_cond; - - precedence[TOKassign] = PREC_assign; - precedence[TOKconstruct] = PREC_assign; - precedence[TOKblit] = PREC_assign; - precedence[TOKaddass] = PREC_assign; - precedence[TOKminass] = PREC_assign; - precedence[TOKcatass] = PREC_assign; - precedence[TOKmulass] = PREC_assign; - precedence[TOKdivass] = PREC_assign; - precedence[TOKmodass] = PREC_assign; -#if DMDV2 - precedence[TOKpowass] = PREC_assign; -#endif - precedence[TOKshlass] = PREC_assign; - precedence[TOKshrass] = PREC_assign; - precedence[TOKushrass] = PREC_assign; - precedence[TOKandass] = PREC_assign; - precedence[TOKorass] = PREC_assign; - precedence[TOKxorass] = PREC_assign; - - precedence[TOKcomma] = PREC_expr; - precedence[TOKdeclaration] = PREC_expr; - -#if IN_LLVM - // Need to set precedence for TOKgep as well, as expToCBuffer expects it. - precedence[TOKgep] = PREC_primary; -#endif -} - - - diff --git a/dmd/parse.h b/dmd/parse.h deleted file mode 100644 index 4e212e40..00000000 --- a/dmd/parse.h +++ /dev/null @@ -1,172 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_PARSE_H -#define DMD_PARSE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "arraytypes.h" -#include "lexer.h" -#include "enum.h" - -struct Type; -struct TypeQualified; -struct Expression; -struct Declaration; -struct Statement; -struct Import; -struct Initializer; -struct FuncDeclaration; -struct CtorDeclaration; -struct PostBlitDeclaration; -struct DtorDeclaration; -struct StaticCtorDeclaration; -struct StaticDtorDeclaration; -struct ConditionalDeclaration; -struct InvariantDeclaration; -struct UnitTestDeclaration; -struct NewDeclaration; -struct DeleteDeclaration; -struct Condition; -struct Module; -struct ModuleDeclaration; -struct TemplateDeclaration; -struct TemplateInstance; -struct StaticAssert; - -/************************************ - * These control how parseStatement() works. - */ - -enum ParseStatementFlags -{ - PSsemi = 1, // empty ';' statements are allowed - PSscope = 2, // start a new scope - PScurly = 4, // { } statement is required - PScurlyscope = 8, // { } starts a new scope -}; - - -struct Parser : Lexer -{ - ModuleDeclaration *md; - enum LINK linkage; - Loc endloc; // set to location of last right curly - int inBrackets; // inside [] of array index or slice - - Parser(Module *module, unsigned char *base, unsigned length, int doDocComment); - - Dsymbols *parseModule(); - Dsymbols *parseDeclDefs(int once); - Array *parseAutoDeclarations(StorageClass storageClass, unsigned char *comment); - Dsymbols *parseBlock(); - void composeStorageClass(StorageClass stc); - Expression *parseConstraint(); - TemplateDeclaration *parseTemplateDeclaration(); - TemplateParameters *parseTemplateParameterList(int flag = 0); - Dsymbol *parseMixin(); - Objects *parseTemplateArgumentList(); - Objects *parseTemplateArgumentList2(); - Objects *parseTemplateArgument(); - StaticAssert *parseStaticAssert(); - TypeQualified *parseTypeof(); - enum LINK parseLinkage(); - Condition *parseDebugCondition(); - Condition *parseVersionCondition(); - Condition *parseStaticIfCondition(); - Dsymbol *parseCtor(); - PostBlitDeclaration *parsePostBlit(); - DtorDeclaration *parseDtor(); - StaticCtorDeclaration *parseStaticCtor(); - StaticDtorDeclaration *parseStaticDtor(); - InvariantDeclaration *parseInvariant(); - UnitTestDeclaration *parseUnitTest(); - NewDeclaration *parseNew(); - DeleteDeclaration *parseDelete(); - Parameters *parseParameters(int *pvarargs); - EnumDeclaration *parseEnum(); - Dsymbol *parseAggregate(); - BaseClasses *parseBaseClasses(); - Import *parseImport(Array *decldefs, int isstatic); - Type *parseType(Identifier **pident = NULL, TemplateParameters **tpl = NULL); - Type *parseBasicType(); - Type *parseBasicType2(Type *t); - Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL); - Dsymbols *parseDeclarations(); - void parseContracts(FuncDeclaration *f); - Statement *parseStatement(int flags); - Initializer *parseInitializer(); - Expression *parseDefaultInitExp(); - void check(Loc loc, enum TOK value); - void check(enum TOK value); - void check(enum TOK value, const char *string); - int isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt); - int isBasicType(Token **pt); - int isDeclarator(Token **pt, int *haveId, enum TOK endtok); - int isParameters(Token **pt); - int isExpression(Token **pt); - int isTemplateInstance(Token *t, Token **pt); - int skipParens(Token *t, Token **pt); - - Expression *parseExpression(); - Expression *parsePrimaryExp(); - Expression *parseUnaryExp(); - Expression *parsePostExp(Expression *e); - Expression *parseMulExp(); - Expression *parseAddExp(); - Expression *parseShiftExp(); - Expression *parseRelExp(); - Expression *parseEqualExp(); - Expression *parseCmpExp(); - Expression *parseAndExp(); - Expression *parseXorExp(); - Expression *parseOrExp(); - Expression *parseAndAndExp(); - Expression *parseOrOrExp(); - Expression *parseCondExp(); - Expression *parseAssignExp(); - - Expressions *parseArguments(); - - Expression *parseNewExp(Expression *thisexp); - - void addComment(Dsymbol *s, unsigned char *blockComment); -}; - -// Operator precedence - greater values are higher precedence - -enum PREC -{ - PREC_zero, - PREC_expr, - PREC_assign, - PREC_cond, - PREC_oror, - PREC_andand, - PREC_or, - PREC_xor, - PREC_and, - PREC_equal, - PREC_rel, - PREC_shift, - PREC_add, - PREC_mul, - PREC_unary, - PREC_primary, -}; - -extern enum PREC precedence[TOKMAX]; - -void initPrecedence(); - -#endif /* DMD_PARSE_H */ diff --git a/dmd/readme.txt b/dmd/readme.txt deleted file mode 100644 index 42a7a9df..00000000 --- a/dmd/readme.txt +++ /dev/null @@ -1,27 +0,0 @@ - - The D Programming Language - Compiler Front End Source - Copyright (c) 1999-2002, by Digital Mars - www.digitalmars.com - All Rights Reserved - - -This is the source code to the front end Digital Mars D compiler. -It covers the lexical analysis, parsing, and semantic analysis -of the D Programming Language defined in the documents at -www.digitalmars.com/d/ - -The optimizer, code generator, and object file generator are not part -of this source, hence the source does not currently constitute a complete, -compilable program. However, many people have expressed a strong interested -in producing a D compiler with the GNU compiler sources. This release should -enable that. - -These sources are free, they are redistributable and modifiable -under the terms of the GNU General Public License (attached as gpl.txt), -or the Artistic License (attached as artistic.txt). - -It does not apply to anything else distributed by Digital Mars, -including D compiler executables. - --Walter Bright diff --git a/dmd/rmem.h b/dmd/rmem.h deleted file mode 100644 index 5d84828d..00000000 --- a/dmd/rmem.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __RMEM_H__ -#define __RMEM_H__ - -// jam memory stuff here - -#include "mem.h" - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#ifdef __MINGW32__ -#include -#endif - -#endif // __RMEM_H__ diff --git a/dmd/root/aav.c b/dmd/root/aav.c deleted file mode 100644 index ca685d42..00000000 --- a/dmd/root/aav.c +++ /dev/null @@ -1,188 +0,0 @@ -/** - * Implementation of associative arrays. - * - */ - -#include -#include -#include - -#include "aav.h" - -static const size_t prime_list[] = { - 31UL, - 97UL, 389UL, - 1543UL, 6151UL, - 24593UL, 98317UL, - 393241UL, 1572869UL, - 6291469UL, 25165843UL, - 100663319UL, 402653189UL, - 1610612741UL, 4294967291UL, -}; - -struct aaA -{ - aaA *next; - Key key; - Value value; -}; - -struct AA -{ - aaA* *b; - size_t b_length; - size_t nodes; // total number of aaA nodes - aaA* binit[4]; // initial value of b[] -}; - -static const AA bbinit = { NULL, }; - -/**************************************************** - * Determine number of entries in associative array. - */ - -size_t _aaLen(AA* aa) -{ - return aa ? aa->nodes : 0; -} - - -/************************************************* - * Get pointer to value in associative array indexed by key. - * Add entry for key if it is not already there. - */ - -Value* _aaGet(AA** paa, Key key) -{ - //printf("paa = %p\n", paa); - - if (!*paa) - { AA *a = new AA(); - *a = bbinit; - a->b = a->binit; - a->b_length = sizeof(a->binit) / sizeof(a->binit[0]); - *paa = a; - assert((*paa)->b_length == 4); - } - //printf("paa = %p, *paa = %p\n", paa, *paa); - - assert((*paa)->b_length); - size_t i = (size_t)key % (*paa)->b_length; - aaA** pe = &(*paa)->b[i]; - aaA *e; - while ((e = *pe) != NULL) - { - if (key == e->key) - return &e->value; - pe = &e->next; - } - - // Not found, create new elem - //printf("create new one\n"); - e = new aaA(); - e->next = NULL; - e->key = key; - e->value = NULL; - *pe = e; - - size_t nodes = ++(*paa)->nodes; - //printf("length = %d, nodes = %d\n", paa.a.b.length, nodes); - if (nodes > (*paa)->b_length * 4) - { - //printf("rehash\n"); - _aaRehash(paa); - } - - return &e->value; -} - - -/************************************************* - * Get value in associative array indexed by key. - * Returns NULL if it is not already there. - */ - -Value _aaGetRvalue(AA* aa, Key key) -{ - //printf("_aaGetRvalue(key = %p)\n", key); - if (!aa) - return NULL; - - size_t len = aa->b_length; - - if (len) - { - size_t i = (size_t)key % len; - aaA* e = aa->b[i]; - while (e) - { - if (key == e->key) - return e->value; - e = e->next; - } - } - return NULL; // not found -} - - -/******************************************** - * Rehash an array. - */ - -void _aaRehash(AA** paa) -{ - //printf("Rehash\n"); - if (*paa) - { - AA newb = bbinit; - AA *aa = *paa; - size_t len = _aaLen(*paa); - if (len) - { size_t i; - - for (i = 0; i < sizeof(prime_list)/sizeof(prime_list[0]) - 1; i++) - { - if (len <= prime_list[i]) - break; - } - len = prime_list[i]; - newb.b = new aaA*[len]; - memset(newb.b, 0, len * sizeof(aaA*)); - newb.b_length = len; - - for (size_t k = 0; k < aa->b_length; k++) - { aaA *e = aa->b[k]; - while (e) - { aaA* enext = e->next; - size_t j = (size_t)e->key % len; - e->next = newb.b[j]; - newb.b[j] = e; - e = enext; - } - } - if (aa->b != aa->binit) - delete[] aa->b; - - newb.nodes = aa->nodes; - } - - **paa = newb; - } -} - - -#if UNITTEST - -void unittest_aa() -{ - AA* aa = NULL; - Value v = _aaGetRvalue(aa, NULL); - assert(!v); - Value *pv = _aaGet(&aa, NULL); - assert(pv); - *pv = (void *)3; - v = _aaGetRvalue(aa, NULL); - assert(v == (void *)3); -} - -#endif diff --git a/dmd/root/aav.h b/dmd/root/aav.h deleted file mode 100644 index 266b5a83..00000000 --- a/dmd/root/aav.h +++ /dev/null @@ -1,11 +0,0 @@ - -typedef void* Value; -typedef void* Key; - -struct AA; - -size_t _aaLen(AA* aa); -Value* _aaGet(AA** aa, Key key); -Value _aaGetRvalue(AA* aa, Key key); -void _aaRehash(AA** paa); - diff --git a/dmd/root/array.c b/dmd/root/array.c deleted file mode 100644 index 3ef48322..00000000 --- a/dmd/root/array.c +++ /dev/null @@ -1,256 +0,0 @@ - -// Copyright (c) 1999-2010 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#if _MSC_VER || __MINGW32__ -#include -#endif - -#if IN_GCC -#include "gdc_alloca.h" -#endif - -#if _WIN32 -#include -#endif - -#ifndef _WIN32 -#include -#include -#include -#include -#include -#include -#endif - -#include "port.h" -#include "root.h" -#include "rmem.h" - - -/********************************* Array ****************************/ - -Array::Array() -{ - data = SMALLARRAYCAP ? &smallarray[0] : NULL; - dim = 0; - allocdim = SMALLARRAYCAP; -} - -Array::~Array() -{ - if (data != &smallarray[0]) - mem.free(data); -} - -void Array::mark() -{ unsigned u; - - mem.mark(data); - for (u = 0; u < dim; u++) - mem.mark(data[u]); // BUG: what if arrays of Object's? -} - -void Array::reserve(unsigned nentries) -{ - //printf("Array::reserve: dim = %d, allocdim = %d, nentries = %d\n", dim, allocdim, nentries); - if (allocdim - dim < nentries) - { - if (allocdim == 0) - { // Not properly initialized, someone memset it to zero - if (nentries <= SMALLARRAYCAP) - { allocdim = SMALLARRAYCAP; - data = SMALLARRAYCAP ? &smallarray[0] : NULL; - } - else - { allocdim = nentries; - data = (void **)mem.malloc(allocdim * sizeof(*data)); - } - } - else if (allocdim == SMALLARRAYCAP) - { - allocdim = dim + nentries; - data = (void **)mem.malloc(allocdim * sizeof(*data)); - memcpy(data, &smallarray[0], dim * sizeof(*data)); - } - else - { allocdim = dim + nentries; - data = (void **)mem.realloc(data, allocdim * sizeof(*data)); - } - } -} - -void Array::setDim(unsigned newdim) -{ - if (dim < newdim) - { - reserve(newdim - dim); - } - dim = newdim; -} - -void Array::fixDim() -{ - if (dim != allocdim) - { - if (allocdim >= SMALLARRAYCAP) - { - if (dim <= SMALLARRAYCAP) - { - memcpy(&smallarray[0], data, dim * sizeof(*data)); - mem.free(data); - } - else - data = (void **)mem.realloc(data, dim * sizeof(*data)); - } - allocdim = dim; - } -} - -void Array::push(void *ptr) -{ - reserve(1); - data[dim++] = ptr; -} - -void *Array::pop() -{ - return data[--dim]; -} - -void Array::shift(void *ptr) -{ - reserve(1); - memmove(data + 1, data, dim * sizeof(*data)); - data[0] = ptr; - dim++; -} - -void Array::insert(unsigned index, void *ptr) -{ - reserve(1); - memmove(data + index + 1, data + index, (dim - index) * sizeof(*data)); - data[index] = ptr; - dim++; -} - - -void Array::insert(unsigned index, Array *a) -{ - if (a) - { unsigned d; - - d = a->dim; - reserve(d); - if (dim != index) - memmove(data + index + d, data + index, (dim - index) * sizeof(*data)); - memcpy(data + index, a->data, d * sizeof(*data)); - dim += d; - } -} - - -/*********************************** - * Append array a to this array. - */ - -void Array::append(Array *a) -{ - insert(dim, a); -} - -void Array::remove(unsigned i) -{ - if (dim - i - 1) - memmove(data + i, data + i + 1, (dim - i - 1) * sizeof(data[0])); - dim--; -} - -char *Array::toChars() -{ - unsigned len; - unsigned u; - char **buf; - char *str; - char *p; - - buf = (char **)malloc(dim * sizeof(char *)); - assert(buf); - len = 2; - for (u = 0; u < dim; u++) - { - buf[u] = ((Object *)data[u])->toChars(); - len += strlen(buf[u]) + 1; - } - str = (char *)mem.malloc(len); - - str[0] = '['; - p = str + 1; - for (u = 0; u < dim; u++) - { - if (u) - *p++ = ','; - len = strlen(buf[u]); - memcpy(p,buf[u],len); - p += len; - } - *p++ = ']'; - *p = 0; - free(buf); - return str; -} - -void Array::zero() -{ - memset(data,0,dim * sizeof(data[0])); -} - -void *Array::tos() -{ - return dim ? data[dim - 1] : NULL; -} - -int -#if _WIN32 - __cdecl -#endif - Array_sort_compare(const void *x, const void *y) -{ - Object *ox = *(Object **)x; - Object *oy = *(Object **)y; - - return ox->compare(oy); -} - -void Array::sort() -{ - if (dim) - { - qsort(data, dim, sizeof(Object *), Array_sort_compare); - } -} - -Array *Array::copy() -{ - Array *a = new Array(); - - a->setDim(dim); - memcpy(a->data, data, dim * sizeof(void *)); - return a; -} - diff --git a/dmd/root/async.c b/dmd/root/async.c deleted file mode 100644 index 78f17c68..00000000 --- a/dmd/root/async.c +++ /dev/null @@ -1,325 +0,0 @@ - -#define _MT 1 - -#include -#include -#include - -#if _WIN32 - -#include -#include -#include - -#include "root.h" - -static unsigned __stdcall startthread(void *p); - -struct FileData -{ - File *file; - int result; - HANDLE event; -}; - -struct AsyncRead -{ - static AsyncRead *create(size_t nfiles); - void addFile(File *file); - void start(); - int read(size_t i); - static void dispose(AsyncRead *); - - HANDLE hThread; - - size_t filesdim; - size_t filesmax; - FileData files[1]; -}; - - -AsyncRead *AsyncRead::create(size_t nfiles) -{ - AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) + - (nfiles - 1) * sizeof(FileData)); - aw->filesmax = nfiles; - return aw; -} - -void AsyncRead::addFile(File *file) -{ - //printf("addFile(file = %p)\n", file); - //printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax); - assert(filesdim < filesmax); - files[filesdim].file = file; - files[filesdim].event = CreateEvent(NULL, TRUE, FALSE, NULL); - ResetEvent(files[filesdim].event); - filesdim++; -} - -void AsyncRead::start() -{ - //printf("aw->filesdim = %p %d\n", this, filesdim); - if (filesdim) - { - unsigned threadaddr; - hThread = (HANDLE) _beginthreadex(NULL, - 0, - &startthread, - this, - 0, - (unsigned *)&threadaddr); - - if (hThread) - { - SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST); - } - else - { - assert(0); - } - } -} - -int AsyncRead::read(size_t i) -{ - FileData *f = &files[i]; - WaitForSingleObject(f->event, INFINITE); - Sleep(0); // give up time slice - return f->result; -} - -void AsyncRead::dispose(AsyncRead *aw) -{ - free(aw); -} - - - -unsigned __stdcall startthread(void *p) -{ - AsyncRead *aw = (AsyncRead *)p; - - //printf("aw->filesdim = %p %d\n", aw, aw->filesdim); - for (size_t i = 0; i < aw->filesdim; i++) - { FileData *f = &aw->files[i]; - - f->result = f->file->read(); - SetEvent(f->event); - } - _endthreadex(EXIT_SUCCESS); - return EXIT_SUCCESS; // if skidding -} - -#elif linux // Posix - -#include -#include -#include - -#include "root.h" - -void *startthread(void *arg); - -void err_abort(int status, const char *msg) -{ - fprintf(stderr, "fatal error = %d, %s\n", status, msg); - exit(EXIT_FAILURE); -} - -struct FileData -{ - File *file; - int result; - - pthread_mutex_t mutex; - pthread_cond_t cond; - int value; -}; - -struct AsyncRead -{ - static AsyncRead *create(size_t nfiles); - void addFile(File *file); - void start(); - int read(size_t i); - static void dispose(AsyncRead *); - - size_t filesdim; - size_t filesmax; - FileData files[1]; -}; - - -AsyncRead *AsyncRead::create(size_t nfiles) -{ - AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) + - (nfiles - 1) * sizeof(FileData)); - aw->filesmax = nfiles; - return aw; -} - -void AsyncRead::addFile(File *file) -{ - //printf("addFile(file = %p)\n", file); - //printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax); - assert(filesdim < filesmax); - FileData *f = &files[filesdim]; - f->file = file; - - int status = pthread_mutex_init(&f->mutex, NULL); - if (status != 0) - err_abort(status, "init mutex"); - status = pthread_cond_init(&f->cond, NULL); - if (status != 0) - err_abort(status, "init cond"); - - filesdim++; -} - -void AsyncRead::start() -{ - //printf("aw->filesdim = %p %d\n", this, filesdim); - if (filesdim) - { - pthread_t thread_id; - int status = pthread_create(&thread_id, - NULL, - &startthread, - this); - if (status != 0) - err_abort(status, "create thread"); - } -} - -int AsyncRead::read(size_t i) -{ - FileData *f = &files[i]; - - // Wait for the event - int status = pthread_mutex_lock(&f->mutex); - if (status != 0) - err_abort(status, "lock mutex"); - while (f->value == 0) - { - status = pthread_cond_wait(&f->cond, &f->mutex); - if (status != 0) - err_abort(status, "wait on condition"); - } - status = pthread_mutex_unlock(&f->mutex); - if (status != 0) - err_abort(status, "unlock mutex"); - - return f->result; -} - -void AsyncRead::dispose(AsyncRead *aw) -{ - //printf("AsyncRead::dispose()\n"); - for (int i = 0; i < aw->filesdim; i++) - { - FileData *f = &aw->files[i]; - int status = pthread_cond_destroy(&f->cond); - if (status != 0) - err_abort(status, "cond destroy"); - status = pthread_mutex_destroy(&f->mutex); - if (status != 0) - err_abort(status, "mutex destroy"); - } - free(aw); -} - - -void *startthread(void *p) -{ - AsyncRead *aw = (AsyncRead *)p; - - //printf("startthread: aw->filesdim = %p %d\n", aw, aw->filesdim); - size_t dim = aw->filesdim; - for (size_t i = 0; i < dim; i++) - { FileData *f = &aw->files[i]; - - f->result = f->file->read(); - - // Set event - int status = pthread_mutex_lock(&f->mutex); - if (status != 0) - err_abort(status, "lock mutex"); - f->value = 1; - status = pthread_cond_signal(&f->cond); - if (status != 0) - err_abort(status, "signal condition"); - status = pthread_mutex_unlock(&f->mutex); - if (status != 0) - err_abort(status, "unlock mutex"); - } - - return NULL; // end thread -} - -#else - -#include -#include - -#include "root.h" - -struct FileData -{ - File *file; - int result; - //HANDLE event; -}; - -struct AsyncRead -{ - static AsyncRead *create(size_t nfiles); - void addFile(File *file); - void start(); - int read(size_t i); - static void dispose(AsyncRead *); - - //HANDLE hThread; - - size_t filesdim; - size_t filesmax; - FileData files[1]; -}; - - -AsyncRead *AsyncRead::create(size_t nfiles) -{ - AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) + - (nfiles - 1) * sizeof(FileData)); - aw->filesmax = nfiles; - return aw; -} - -void AsyncRead::addFile(File *file) -{ - //printf("addFile(file = %p)\n", file); - //printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax); - assert(filesdim < filesmax); - files[filesdim].file = file; - //files[filesdim].event = CreateEvent(NULL, TRUE, FALSE, NULL); - //ResetEvent(files[filesdim].event); - filesdim++; -} - -void AsyncRead::start() -{ -} - -int AsyncRead::read(size_t i) -{ - FileData *f = &files[i]; - f->result = f->file->read(); - return f->result; -} - -void AsyncRead::dispose(AsyncRead *aw) -{ - free(aw); -} - -#endif diff --git a/dmd/root/async.h b/dmd/root/async.h deleted file mode 100644 index 6f25f367..00000000 --- a/dmd/root/async.h +++ /dev/null @@ -1,33 +0,0 @@ - -// Copyright (c) 2009-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef ASYNC_H -#define ASYNC_H - -#if __DMC__ -#pragma once -#endif - - -/******************* - * Simple interface to read files asynchronously in another - * thread. - */ - -struct AsyncRead -{ - static AsyncRead *create(size_t nfiles); - void addFile(File *file); - void start(); - int read(size_t i); - static void dispose(AsyncRead *); -}; - - -#endif diff --git a/dmd/root/gnuc.c b/dmd/root/gnuc.c deleted file mode 100644 index 8f33d839..00000000 --- a/dmd/root/gnuc.c +++ /dev/null @@ -1,55 +0,0 @@ - -// Put functions in here missing from gnu C - -#include "gnuc.h" - -int memicmp(const char *s1, const char *s2, int n) -{ - int result = 0; - - for (int i = 0; i < n; i++) - { char c1 = s1[i]; - char c2 = s2[i]; - - result = c1 - c2; - if (result) - { - if ('A' <= c1 && c1 <= 'Z') - c1 += 'a' - 'A'; - if ('A' <= c2 && c2 <= 'Z') - c2 += 'a' - 'A'; - result = c1 - c2; - if (result) - break; - } - } - return result; -} - -int stricmp(const char *s1, const char *s2) -{ - int result = 0; - - for (;;) - { char c1 = *s1; - char c2 = *s2; - - result = c1 - c2; - if (result) - { - if ('A' <= c1 && c1 <= 'Z') - c1 += 'a' - 'A'; - if ('A' <= c2 && c2 <= 'Z') - c2 += 'a' - 'A'; - result = c1 - c2; - if (result) - break; - } - if (!c1) - break; - s1++; - s2++; - } - return result; -} - diff --git a/dmd/root/gnuc.h b/dmd/root/gnuc.h deleted file mode 100644 index 00c9851d..00000000 --- a/dmd/root/gnuc.h +++ /dev/null @@ -1,8 +0,0 @@ - -#ifndef _GNUC_H -#define _GNUC_H 1 - -int memicmp(const char *s1, const char *s2, int n); -int stricmp(const char *s1, const char *s2); - -#endif diff --git a/dmd/root/longdouble.c b/dmd/root/longdouble.c deleted file mode 100644 index 8a0f00e7..00000000 --- a/dmd/root/longdouble.c +++ /dev/null @@ -1,636 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Rainer Schuetze -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// 80 bit floating point value implementation for Microsoft compiler - -#if _MSC_VER -#include "longdouble.h" - -#include "assert.h" - -#include -#include -#include - -extern "C" -{ - // implemented in ldfpu.asm for _WIN64 - int ld_initfpu(int bits, int mask); - void ld_expl(longdouble* ld, int exp); - longdouble ld_add(longdouble ld1, longdouble ld2); - longdouble ld_sub(longdouble ld1, longdouble ld2); - longdouble ld_mul(longdouble ld1, longdouble ld2); - longdouble ld_div(longdouble ld1, longdouble ld2); - longdouble ld_mod(longdouble ld1, longdouble ld2); - bool ld_cmpb(longdouble ld1, longdouble ld2); - bool ld_cmpbe(longdouble ld1, longdouble ld2); - bool ld_cmpa(longdouble ld1, longdouble ld2); - bool ld_cmpae(longdouble ld1, longdouble ld2); - bool ld_cmpe(longdouble ld1, longdouble ld2); - bool ld_cmpne(longdouble ld1, longdouble ld2); - longdouble ld_sqrt(longdouble ld1); - longdouble ld_sin(longdouble ld1); - longdouble ld_cos(longdouble ld1); - longdouble ld_tan(longdouble ld1); -} - -bool initFPU() -{ -#ifdef _WIN64 -// int old_cw = ld_initfpu(_RC_NEAR); - int old_cw = ld_initfpu(0x300 /*_PC_64 | _RC_NEAR*/, // #defines NOT identical to CPU FPU control word! - 0xF00 /*_MCW_PC | _MCW_RC*/); -#else - int old_cw = _control87(_MCW_EM | _PC_64 | _RC_NEAR, - _MCW_EM | _MCW_PC | _MCW_RC); -#endif - return true; -} -static bool doInitFPU = initFPU(); - -#ifndef _WIN64 -extern "C" -{ - -double ld_read(const longdouble* pthis) -{ - double res; - __asm - { - mov eax, pthis - fld tbyte ptr [eax] - fstp res - } - return res; -} -long long ld_readll(const longdouble* pthis) -{ -#if 1 - return ld_readull(pthis); -#elif defined _WIN64 - return ld_readll(this); -#else - longdouble* pthis = this; - long long res; - __asm - { - mov eax, pthis - fld tbyte ptr [eax] - fistp qword ptr res - } - return res; -#endif -} - -unsigned long long ld_readull(const longdouble* pthis) -{ -#if 1 - // somehow the FPU does not respect the CHOP mode of the rounding control - // in 64-bit mode - // so we roll our own conversion (it also allows the usual C wrap-around - // instead of the "invalid value" created by the FPU) - int expo = pthis->exponent - 0x3fff; - unsigned long long u; - if(expo < 0 || expo > 127) - return 0; - if(expo < 64) - u = pthis->mantissa >> (63 - expo); - else - u = pthis->mantissa << (expo - 63); - if(pthis->sign) - u = ~u + 1; - return u; -#else - longdouble* pthis = this; - long long res; // cannot use unsigned, VC will not generate "fistp qword" - longdouble twoPow63 = { 1ULL << 63, 0x3fff + 63, 0 }; - __asm - { - mov eax, pthis - fld tbyte ptr [eax] - fld tbyte ptr twoPow63 - fsubp ST(1),ST(0) // move it into signed range - - lea eax, res - fistp qword ptr [eax] - } - res ^= (1LL << 63); - return res; -#endif -} - -void ld_set(longdouble* pthis, double d) -{ - __asm - { - mov eax, pthis - fld d - fstp tbyte ptr [eax] - } -} -void ld_setll(longdouble* pthis, long long d) -{ - __asm - { - fild qword ptr d - mov eax, pthis - fstp tbyte ptr [eax] - } -} -void ld_setull(longdouble* pthis, unsigned long long d) -{ - d ^= (1LL << 63); - longdouble twoPow63 = { 1ULL << 63, 0x3fff + 63, 0 }; - __asm - { - fild qword ptr d - fld tbyte ptr twoPow63 - faddp ST(1),ST(0) - mov eax, pthis - fstp tbyte ptr [eax] - } -} - -} // extern "C" -#endif // !_WIN64 - -longdouble ldexpl(longdouble ld, int exp) -{ -#ifdef _WIN64 - ld_expl(&ld, exp); -#else - __asm - { - fild dword ptr exp - fld tbyte ptr ld - fscale // ST(0) = ST(0) * (2**ST(1)) - fstp ST(1) - fstp tbyte ptr ld - } -#endif - return ld; -} - -/////////////////////////////////////////////////////////////////////// -longdouble operator+(longdouble ld1, longdouble ld2) -{ -#ifdef _WIN64 - return ld_add(ld1, ld2); -#else - longdouble res; - __asm - { - fld tbyte ptr ld1 - fld tbyte ptr ld2 - fadd - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble operator-(longdouble ld1, longdouble ld2) -{ -#ifdef _WIN64 - return ld_sub(ld1, ld2); -#else - longdouble res; - __asm - { - fld tbyte ptr ld1 - fld tbyte ptr ld2 - fsub - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble operator*(longdouble ld1, longdouble ld2) -{ -#ifdef _WIN64 - return ld_mul(ld1, ld2); -#else - longdouble res; - __asm - { - fld tbyte ptr ld1 - fld tbyte ptr ld2 - fmul - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble operator/(longdouble ld1, longdouble ld2) -{ -#ifdef _WIN64 - return ld_div(ld1, ld2); -#else - longdouble res; - __asm - { - fld tbyte ptr ld1 - fld tbyte ptr ld2 - fdiv - fstp tbyte ptr res; - } - return res; -#endif -} - -bool operator< (longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpb(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - setb AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator<=(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpbe(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - setbe AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator> (longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpa(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - seta AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator>=(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpae(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - setae AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator==(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpe(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - sete AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator!=(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpne(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - setne AL - setp AH - or AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} - - -int _isnan(longdouble ld) -{ - return (ld.exponent == 0x7fff && ld.mantissa != 0); -} - -longdouble fabsl(longdouble ld) -{ - ld.sign = 0; - return ld; -} - -longdouble sqrtl(longdouble ld) -{ -#ifdef _WIN64 - return ld_sqrt(ld); -#else - longdouble res; - __asm - { - fld tbyte ptr ld; - fsqrt; - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble sinl (longdouble ld) -{ -#ifdef _WIN64 - return ld_sin(ld); -#else - longdouble res; - __asm - { - fld tbyte ptr ld; - fsin; // exact for |x|<=PI/4 - fstp tbyte ptr res - } - return res; -#endif -} -longdouble cosl (longdouble ld) -{ -#ifdef _WIN64 - return ld_cos(ld); -#else - longdouble res; - __asm - { - fld tbyte ptr ld; - fcos; // exact for |x|<=PI/4 - fstp tbyte ptr res; - } - return res; -#endif -} -longdouble tanl (longdouble ld) -{ -#ifdef _WIN64 - return ld_tan(ld); -#else - longdouble res; - __asm - { - fld tbyte ptr ld; - fptan; - fstp ST(0); // always 1 - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble fmodl(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_mod(x, y); -#else - short sw; - longdouble res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y -FM1: // We don't use fprem1 because for some inexplicable - // reason we get -5 when we do _modulo(15, 10) - fprem // ST = ST % ST1 - fstsw word ptr sw - fwait - mov AH,byte ptr sw+1 // get msb of status word in AH - sahf // transfer to flags - jp FM1 // continue till ST < ST1 - fstp ST(1) // leave remainder on stack - fstp tbyte ptr res; - } - return res; -#endif -} - -////////////////////////////////////////////////////////////// - -longdouble ld_qnan = { 0x8000000000000000ULL, 0x7fff, 0 }; -longdouble ld_snan = { 0x0000000000000001ULL, 0x7fff, 0 }; -longdouble ld_inf = { 0x0000000000000000ULL, 0x7fff, 0 }; - -longdouble ld_zero = { 0, 0, 0 }; -longdouble ld_one = { 0x8000000000000000ULL, 0x3fff, 0 }; -longdouble ld_pi = { 0xc90fdaa22168c235ULL, 0x4000, 0 }; -longdouble ld_log2t = { 0xd49a784bcd1b8afeULL, 0x4000, 0 }; -longdouble ld_log2e = { 0xb8aa3b295c17f0bcULL, 0x3fff, 0 }; -longdouble ld_log2 = { 0x9a209a84fbcff799ULL, 0x3ffd, 0 }; -longdouble ld_ln2 = { 0xb17217f7d1cf79acULL, 0x3ffe, 0 }; - -longdouble ld_pi2 = ld_pi*2; -longdouble ld_piOver2 = ld_pi*0.5; -longdouble ld_piOver4 = ld_pi*0.25; - -////////////////////////////////////////////////////////////// - -#define LD_TYPE_OTHER 0 -#define LD_TYPE_ZERO 1 -#define LD_TYPE_INFINITE 2 -#define LD_TYPE_SNAN 3 -#define LD_TYPE_QNAN 4 - -int ld_type(longdouble x) -{ - if(x.exponent == 0) - return x.mantissa == 0 ? LD_TYPE_ZERO : LD_TYPE_OTHER; // dnormal if not zero - if(x.exponent != 0x7fff) - return LD_TYPE_OTHER; - if(x.mantissa == 0) - return LD_TYPE_INFINITE; - if(x.mantissa & (1LL << 63)) - return LD_TYPE_QNAN; - return LD_TYPE_SNAN; -} - -int ld_sprint(char* str, int fmt, longdouble x) -{ - // fmt is 'a','A','f' or 'g' - if(fmt != 'a' && fmt != 'A') - { - char format[] = { '%', fmt, 0 }; - return sprintf(str, format, ld_read(&x)); - } - - unsigned short exp = x.exponent; - unsigned long long mantissa = x.mantissa; - - switch(ld_type(x)) - { - case LD_TYPE_ZERO: - return sprintf(str, "0x0.0L"); - case LD_TYPE_QNAN: - case LD_TYPE_SNAN: - return sprintf(str, "NAN"); - case LD_TYPE_INFINITE: - return sprintf(str, x.sign ? "-INF" : "INF"); - } - - int len = 0; - if(x.sign) - str[len++] = '-'; - len += sprintf(str + len, mantissa & (1LL << 63) ? "0x1." : "0x0."); - mantissa = mantissa << 1; - while(mantissa) - { - int dig = (mantissa >> 60) & 0xf; - dig += dig < 10 ? '0' : fmt - 10; - str[len++] = dig; - mantissa = mantissa << 4; - } - str[len++] = 'p'; - if(exp < 0x3fff) - { - str[len++] = '-'; - exp = 0x3fff - exp; - } - else - { - str[len++] = '+'; - exp = exp - 0x3fff; - } - int exppos = len; - for(int i = 12; i >= 0; i -= 4) - { - int dig = (exp >> i) & 0xf; - if(dig != 0 || len > exppos || i == 0) - str[len++] = dig + (dig < 10 ? '0' : fmt - 10); - } - str[len] = 0; - return len; -} - -////////////////////////////////////////////////////////////// - -#if UNITTEST -static bool unittest() -{ - char buffer[32]; - ld_sprint(buffer, 'a', ld_pi); - assert(strcmp(buffer, "0x1.921fb54442d1846ap+1") == 0); - - longdouble ldb = ldouble(0.4); - long long b = ldb; - assert(b == 0); - - b = ldouble(0.9); - assert(b == 0); - - long long x = 0x12345678abcdef78LL; - longdouble ldx = ldouble(x); - assert(ldx > 0); - long long y = ldx; - assert(x == y); - - x = -0x12345678abcdef78LL; - ldx = ldouble(x); - assert(ldx < 0); - y = ldx; - assert(x == y); - - unsigned long long u = 0x12345678abcdef78LL; - longdouble ldu = ldouble(u); - assert(ldu > 0); - unsigned long long v = ldu; - assert(u == v); - - u = 0xf234567812345678ULL; - ldu = ldouble(u); - assert(ldu > 0); - v = ldu; - assert(u == v); - - u = 0xf2345678; - ldu = ldouble(u); - ldu = ldu * ldu; - ldu = sqrt(ldu); - v = ldu; - assert(u == v); - - u = 0x123456789A; - ldu = ldouble(u); - ldu = ldu * (1LL << 23); - v = ldu; - u = u * (1LL << 23); - assert(u == v); - - return true; -} - -static bool runUnittest = unittest(); - -#endif // UNITTEST - -#endif // _MSC_VER - diff --git a/dmd/root/longdouble.h b/dmd/root/longdouble.h deleted file mode 100644 index d25223a7..00000000 --- a/dmd/root/longdouble.h +++ /dev/null @@ -1,254 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Rainer Schuetze -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// 80 bit floating point value implementation for Microsoft compiler - -#ifndef __LONG_DOUBLE_H__ -#define __LONG_DOUBLE_H__ - -#if IN_GCC -#include "d-gcc-real.h" -typedef real_t longdouble; - -template longdouble ldouble(T x) { return (longdouble) x; } -inline int ld_sprint(char* str, int fmt, longdouble x) -{ - if(fmt == 'a' || fmt == 'A') - return x.formatHex(buffer, 46); // don't know the size here, but 46 is the max - return x.format(buffer, 46); -} - -#elif !_MSC_VER // has native 10 byte doubles -#include -typedef long double longdouble; -typedef volatile long double volatile_longdouble; - -// also used from within C code, so use a #define rather than a template -// template longdouble ldouble(T x) { return (longdouble) x; } -#define ldouble(x) ((longdouble)(x)) - -inline int ld_sprint(char* str, int fmt, longdouble x) -{ - char sfmt[4] = "%Lg"; - sfmt[2] = fmt; - return sprintf(str, sfmt, x); -} - -#else - -#include -#include - -struct longdouble; - -extern "C" -{ - // implemented in ldfpu.asm for _WIN64 - double ld_read(const longdouble* ld); - long long ld_readll(const longdouble* ld); - unsigned long long ld_readull(const longdouble* ld); - void ld_set(longdouble* ld, double d); - void ld_setll(longdouble* ld, long long d); - void ld_setull(longdouble* ld, unsigned long long d); -} - -struct longdouble -{ - unsigned long long mantissa; - unsigned short exponent:15; // bias 0x3fff - unsigned short sign:1; - unsigned short fill:16; // for 12 byte alignment - - // no constructor to be able to use this class in a union - // use ldouble() to explicitely create a longdouble value - - template longdouble& operator=(T x) { set(x); return *this; } - - void set(longdouble ld) { mantissa = ld.mantissa; exponent = ld.exponent; sign = ld.sign; } - - // we need to list all basic types to avoid ambiguities - void set(float d) { ld_set(this, d); } - void set(double d) { ld_set(this, d); } - void set(long double d) { ld_set(this, d); } - - void set(signed char d) { ld_set(this, d); } - void set(short d) { ld_set(this, d); } - void set(int d) { ld_set(this, d); } - void set(long d) { ld_set(this, d); } - void set(long long d) { ld_setll(this, d); } - - void set(unsigned char d) { ld_set(this, d); } - void set(unsigned short d) { ld_set(this, d); } - void set(unsigned int d) { ld_set(this, d); } - void set(unsigned long d) { ld_set(this, d); } - void set(unsigned long long d) { ld_setull(this, d); } - void set(bool d) { ld_set(this, d); } - - operator float () { return ld_read(this); } - operator double () { return ld_read(this); } - - operator signed char () { return ld_read(this); } - operator short () { return ld_read(this); } - operator int () { return ld_read(this); } - operator long () { return ld_read(this); } - operator long long () { return ld_readll(this); } - - operator unsigned char () { return ld_read(this); } - operator unsigned short () { return ld_read(this); } - operator unsigned int () { return ld_read(this); } - operator unsigned long () { return ld_read(this); } - operator unsigned long long() { return ld_readull(this); } - operator bool () { return mantissa != 0 || exponent != 0; } // correct? -}; - -// some optimizations are avoided by adding volatile to the longdouble -// type, but this introduces bad ambiguities when using the class implementation above -// as we are going through asm these optimizations won't kick in anyway, so "volatile" -// is not required. -typedef longdouble volatile_longdouble; - -inline longdouble ldouble(unsigned long long mantissa, int exp, int sign = 0) -{ - longdouble d; - d.mantissa = mantissa; - d.exponent = exp; - d.sign = sign; - return d; -} -template inline longdouble ldouble(T x) { longdouble d; d.set(x); return d; } -//template inline longdouble ldouble(volatile T x) { longdouble d; d.set(x); return d; } - -longdouble operator+(longdouble ld1, longdouble ld2); -longdouble operator-(longdouble ld1, longdouble ld2); -longdouble operator*(longdouble ld1, longdouble ld2); -longdouble operator/(longdouble ld1, longdouble ld2); - -bool operator< (longdouble ld1, longdouble ld2); -bool operator<=(longdouble ld1, longdouble ld2); -bool operator> (longdouble ld1, longdouble ld2); -bool operator>=(longdouble ld1, longdouble ld2); -bool operator==(longdouble ld1, longdouble ld2); -bool operator!=(longdouble ld1, longdouble ld2); - -inline longdouble operator-(longdouble ld1) { ld1.sign ^= 1; return ld1; } -inline longdouble operator+(longdouble ld1) { return ld1; } - -template inline longdouble operator+(longdouble ld, T x) { return ld + ldouble(x); } -template inline longdouble operator-(longdouble ld, T x) { return ld - ldouble(x); } -template inline longdouble operator*(longdouble ld, T x) { return ld * ldouble(x); } -template inline longdouble operator/(longdouble ld, T x) { return ld / ldouble(x); } - -template inline longdouble operator+(T x, longdouble ld) { return ldouble(x) + ld; } -template inline longdouble operator-(T x, longdouble ld) { return ldouble(x) - ld; } -template inline longdouble operator*(T x, longdouble ld) { return ldouble(x) * ld; } -template inline longdouble operator/(T x, longdouble ld) { return ldouble(x) / ld; } - -template inline longdouble& operator+=(longdouble& ld, T x) { return ld = ld + x; } -template inline longdouble& operator-=(longdouble& ld, T x) { return ld = ld - x; } -template inline longdouble& operator*=(longdouble& ld, T x) { return ld = ld * x; } -template inline longdouble& operator/=(longdouble& ld, T x) { return ld = ld / x; } - -template inline bool operator< (longdouble ld, T x) { return ld < ldouble(x); } -template inline bool operator<=(longdouble ld, T x) { return ld <= ldouble(x); } -template inline bool operator> (longdouble ld, T x) { return ld > ldouble(x); } -template inline bool operator>=(longdouble ld, T x) { return ld >= ldouble(x); } -template inline bool operator==(longdouble ld, T x) { return ld == ldouble(x); } -template inline bool operator!=(longdouble ld, T x) { return ld != ldouble(x); } - -template inline bool operator< (T x, longdouble ld) { return ldouble(x) < ld; } -template inline bool operator<=(T x, longdouble ld) { return ldouble(x) <= ld; } -template inline bool operator> (T x, longdouble ld) { return ldouble(x) > ld; } -template inline bool operator>=(T x, longdouble ld) { return ldouble(x) >= ld; } -template inline bool operator==(T x, longdouble ld) { return ldouble(x) == ld; } -template inline bool operator!=(T x, longdouble ld) { return ldouble(x) != ld; } - -int _isnan(longdouble ld); - -longdouble fabsl(longdouble ld); -longdouble sqrtl(longdouble ld); -longdouble sinl (longdouble ld); -longdouble cosl (longdouble ld); -longdouble tanl (longdouble ld); - -longdouble fmodl(longdouble x, longdouble y); -longdouble ldexpl(longdouble ldval, int exp); // see strtold - -inline longdouble fabs (longdouble ld) { return fabsl(ld); } -inline longdouble sqrt (longdouble ld) { return sqrtl(ld); } - -#undef LDBL_DIG -#undef LDBL_MAX -#undef LDBL_MIN -#undef LDBL_EPSILON -#undef LDBL_MANT_DIG -#undef LDBL_MAX_EXP -#undef LDBL_MIN_EXP -#undef LDBL_MAX_10_EXP -#undef LDBL_MIN_10_EXP - -#define LDBL_DIG 18 -#define LDBL_MAX ldouble(0xffffffffffffffffULL, 0x7ffe) -#define LDBL_MIN ldouble(0x8000000000000000ULL, 1) -#define LDBL_EPSILON ldouble(0x8000000000000000ULL, 0x3fff - 63) // allow denormal? -#define LDBL_MANT_DIG 64 -#define LDBL_MAX_EXP 16384 -#define LDBL_MIN_EXP (-16381) -#define LDBL_MAX_10_EXP 4932 -#define LDBL_MIN_10_EXP (-4932) - -extern longdouble ld_zero; -extern longdouble ld_one; -extern longdouble ld_pi; -extern longdouble ld_log2t; -extern longdouble ld_log2e; -extern longdouble ld_log2; -extern longdouble ld_ln2; - -extern longdouble ld_inf; -extern longdouble ld_qnan; -extern longdouble ld_snan; - -/////////////////////////////////////////////////////////////////////// -// CLASS numeric_limits -template<> class _CRTIMP2_PURE std::numeric_limits -: public _Num_float_base -{ // limits for type long double -public: - typedef longdouble _Ty; - - static _Ty (__CRTDECL min)() _THROW0() { return LDBL_MIN; } - static _Ty (__CRTDECL max)() _THROW0() { return LDBL_MAX; } - static _Ty __CRTDECL epsilon() _THROW0() { return LDBL_EPSILON; } - static _Ty __CRTDECL round_error() _THROW0() { return ldouble(0.5); } - static _Ty __CRTDECL denorm_min() _THROW0() { return ldouble(0x0000000000000001ULL, 1); } - static _Ty __CRTDECL infinity() _THROW0() { return ld_inf; } - static _Ty __CRTDECL quiet_NaN() _THROW0() { return ld_qnan; } - static _Ty __CRTDECL signaling_NaN() _THROW0() { return ld_snan; } - - _STCONS(int, digits, LDBL_MANT_DIG); - _STCONS(int, digits10, LDBL_DIG); - _STCONS(int, max_exponent, (int)LDBL_MAX_EXP); - _STCONS(int, max_exponent10, (int)LDBL_MAX_10_EXP); - _STCONS(int, min_exponent, (int)LDBL_MIN_EXP); - _STCONS(int, min_exponent10, (int)LDBL_MIN_10_EXP); -}; - -//_STCONSDEF(numeric_limits, int, digits) -//_STCONSDEF(numeric_limits, int, digits10) -//_STCONSDEF(numeric_limits, int, max_exponent) -//_STCONSDEF(numeric_limits, int, max_exponent10) -//_STCONSDEF(numeric_limits, int, min_exponent) -//_STCONSDEF(numeric_limits, int, min_exponent10) - -int ld_sprint(char* str, int fmt, longdouble x); - -#endif // !_MSC_VER - -#endif // __LONG_DOUBLE_H__ diff --git a/dmd/root/man.c b/dmd/root/man.c deleted file mode 100644 index 3770aa96..00000000 --- a/dmd/root/man.c +++ /dev/null @@ -1,100 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2008-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include - -#if _WIN32 - -#include - -#pragma comment(lib,"shell32.lib") - -void browse(const char *url) -{ - ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL); -} - -#endif - -#if linux || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 - -#include -#include -#include - -void browse(const char *url) -{ - pid_t childpid; - const char *args[3]; - - const char *browser = getenv("BROWSER"); - if (browser) - browser = strdup(browser); - else - browser = "x-www-browser"; - - args[0] = browser; - args[1] = url; - args[2] = NULL; - - childpid = fork(); - if (childpid == 0) - { - execvp(args[0], (char**)args); - perror(args[0]); // failed to execute - return; - } -} - -#endif - -#if __APPLE__ - -#include -#include -#include - -void browse(const char *url) -{ - pid_t childpid; - const char *args[5]; - - char *browser = getenv("BROWSER"); - if (browser) - { browser = strdup(browser); - args[0] = browser; - args[1] = url; - args[2] = NULL; - } - else - { - //browser = "/Applications/Safari.app/Contents/MacOS/Safari"; - args[0] = "open"; - args[1] = "-a"; - args[2] = "/Applications/Safari.app"; - args[3] = url; - args[4] = NULL; - } - - childpid = fork(); - if (childpid == 0) - { - execvp(args[0], (char**)args); - perror(args[0]); // failed to execute - return; - } -} - -#endif - - diff --git a/dmd/root/port.c b/dmd/root/port.c deleted file mode 100644 index fce3c952..00000000 --- a/dmd/root/port.c +++ /dev/null @@ -1,663 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com - -#include "port.h" -#if __DMC__ -#include -#include -#include -#include -#include -#include - -double Port::nan = NAN; -double Port::infinity = INFINITY; -double Port::dbl_max = DBL_MAX; -double Port::dbl_min = DBL_MIN; -longdouble Port::ldbl_max = LDBL_MAX; - -int Port::isNan(double r) -{ - return ::isnan(r); -} - -int Port::isNan(longdouble r) -{ - return ::isnan(r); -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(longdouble r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 62 of 0..79 for 80 bit reals. - */ - return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); -} - -int Port::isFinite(double r) -{ - return ::isfinite(r); -} - -int Port::isInfinity(double r) -{ - return (::fpclassify(r) == FP_INFINITE); -} - -int Port::Signbit(double r) -{ - return ::signbit(r); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - -longdouble Port::fmodl(longdouble x, longdouble y) -{ - return ::fmodl(x, y); -} - -unsigned long long Port::strtoull(const char *p, char **pend, int base) -{ - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - // LOCALE_SLIST for Windows - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - // LOCALE_SLIST for Windows - return L","; -} - -char *Port::strupr(char *s) -{ - return ::strupr(s); -} - -#endif - -#if _MSC_VER - -// Disable useless warnings about unreferenced functions -#pragma warning (disable : 4514) - -#include -#include -#include -#include -#include -#include -#include -#include // for std::numeric_limits - -static unsigned long nanarray[2]= { 0xFFFFFFFF, 0x7FFFFFFF }; -//static unsigned long nanarray[2] = {0,0x7FF80000 }; -double Port::nan = (*(double *)nanarray); - -//static unsigned long infinityarray[2] = {0,0x7FF00000 }; -static double zero = 0; -double Port::infinity = 1 / zero; - -double Port::dbl_max = DBL_MAX; -double Port::dbl_min = DBL_MIN; -longdouble Port::ldbl_max = LDBL_MAX; - -struct PortInitializer -{ - PortInitializer(); -}; - -static PortInitializer portinitializer; - -PortInitializer::PortInitializer() -{ - Port::infinity = std::numeric_limits::infinity(); -} - -int Port::isNan(double r) -{ - return ::_isnan(r); -} - -int Port::isNan(longdouble r) -{ - return ::_isnan(r); -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(longdouble r) -{ - /* MSVC doesn't have 80 bit long doubles - */ - return isSignallingNan((double) r); -} - -int Port::isFinite(double r) -{ - return ::_finite(r); -} - -int Port::isInfinity(double r) -{ - return (::_fpclass(r) & (_FPCLASS_NINF | _FPCLASS_PINF)); -} - -int Port::Signbit(double r) -{ - return (long)(((long *)&(r))[1] & 0x80000000); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - if (y == 0) - return 1; // even if x is NAN - return ::pow(x, y); -} - -longdouble Port::fmodl(longdouble x, longdouble y) -{ - return ::fmodl(x, y); -} - -unsigned _int64 Port::strtoull(const char *p, char **pend, int base) -{ - unsigned _int64 number = 0; - int c; - int error; -#ifndef ULLONG_MAX - #define ULLONG_MAX ((unsigned _int64)~0I64) -#endif - - while (isspace((unsigned char)*p)) /* skip leading white space */ - p++; - if (*p == '+') - p++; - switch (base) - { case 0: - base = 10; /* assume decimal base */ - if (*p == '0') - { base = 8; /* could be octal */ - p++; - switch (*p) - { case 'x': - case 'X': - base = 16; /* hex */ - p++; - break; -#if BINARY - case 'b': - case 'B': - base = 2; /* binary */ - p++; - break; -#endif - } - } - break; - case 16: /* skip over '0x' and '0X' */ - if (*p == '0' && (p[1] == 'x' || p[1] == 'X')) - p += 2; - break; -#if BINARY - case 2: /* skip over '0b' and '0B' */ - if (*p == '0' && (p[1] == 'b' || p[1] == 'B')) - p += 2; - break; -#endif - } - error = 0; - for (;;) - { c = *p; - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c = (c & ~0x20) - ('A' - 10); - else /* unrecognized character */ - break; - if (c >= base) /* not in number base */ - break; - if ((ULLONG_MAX - c) / base < number) - error = 1; - number = number * base + c; - p++; - } - if (pend) - *pend = (char *)p; - if (error) - { number = ULLONG_MAX; - errno = ERANGE; - } - return number; -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - _ui64toa(ull, buffer, 10); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - _ui64tow(ull, buffer, 10); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ double d; - - if ((__int64) ull < 0) - { - // MSVC doesn't implement the conversion - d = (double) (__int64)(ull - 0x8000000000000000i64); - d += (double)(signed __int64)(0x7FFFFFFFFFFFFFFFi64) + 1.0; - } - else - d = (double)(__int64)ull; - return d; -} - -const char *Port::list_separator() -{ - // LOCALE_SLIST for Windows - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - // LOCALE_SLIST for Windows - return L","; -} - -char *Port::strupr(char *s) -{ - return ::strupr(s); -} - -#endif - -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __MINGW32__ || __HAIKU__ - -#include -#if linux -#include -#include -#endif -#if __FreeBSD__ && __i386__ -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -static double zero = 0; -double Port::nan = copysign(NAN, 1.0); -double Port::infinity = 1 / zero; -double Port::dbl_max = 1.7976931348623157e308; -double Port::dbl_min = 5e-324; -longdouble Port::ldbl_max = LDBL_MAX; - -struct PortInitializer -{ - PortInitializer(); -}; - -static PortInitializer portinitializer; - -PortInitializer::PortInitializer() -{ - assert(!signbit(Port::nan)); - -#if __FreeBSD__ && __i386__ - // LDBL_MAX comes out as infinity. Fix. - static unsigned char x[sizeof(longdouble)] = - { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7F }; - Port::ldbl_max = *(longdouble *)&x[0]; - // FreeBSD defaults to double precision. Switch to extended precision. - fpsetprec(FP_PE); -#endif -} - -int Port::isNan(double r) -{ -#if __APPLE__ -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 - return __inline_isnand(r); -#else - return __inline_isnan(r); -#endif -#elif __OpenBSD__ || __MINGW32__ || __HAIKU__ - return isnan(r); -#else - #undef isnan - return ::isnan(r); -#endif -} - -int Port::isNan(longdouble r) -{ -#if __APPLE__ -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 - return __inline_isnanl(r); -#else - return __inline_isnan(r); -#endif -#elif __OpenBSD__ || __MINGW32__ || __HAIKU__ - return isnan(r); -#else - #undef isnan - return ::isnan(r); -#endif -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(longdouble r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 62 of 0..79 for 80 bit reals. - */ - return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); -} - -#undef isfinite -int Port::isFinite(double r) -{ - return ::finite(r); -} - -int Port::isInfinity(double r) -{ -#if __APPLE__ - return fpclassify(r) == FP_INFINITE; -#elif __OpenBSD__ || __MINGW32__ || __HAIKU__ - return isinf(r); -#else - #undef isinf - return ::isinf(r); -#endif -} - -#undef signbit -int Port::Signbit(double r) -{ - union { double d; long long ll; } u; - u.d = r; - return u.ll < 0; -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - -longdouble Port::fmodl(longdouble x, longdouble y) -{ -#if __FreeBSD__ || __OpenBSD__ - return ::fmod(x, y); // hack for now, fix later -#else - return ::fmodl(x, y); -#endif -} - -unsigned long long Port::strtoull(const char *p, char **pend, int base) -{ - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ -#if __OpenBSD__ - assert(0); -#else -#ifndef __MINGW32__ - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); -#else - _snwprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); -#endif -#endif - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - return L","; -} - -char *Port::strupr(char *s) -{ - char *t = s; - - while (*s) - { - *s = toupper(*s); - s++; - } - - return t; -} - -#endif - -#if __sun&&__SVR4 - -#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static double zero = 0; -double Port::nan = NAN; -double Port::infinity = 1 / zero; -double Port::dbl_max = 1.7976931348623157e308; -double Port::dbl_min = 5e-324; -longdouble Port::ldbl_max = LDBL_MAX; - -struct PortInitializer -{ - PortInitializer(); -}; - -static PortInitializer portinitializer; - -PortInitializer::PortInitializer() -{ - // gcc nan's have the sign bit set by default, so turn it off - // Need the volatile to prevent gcc from doing incorrect - // constant folding. - volatile longdouble foo; - foo = NAN; - if (signbit(foo)) // signbit sometimes, not always, set - foo = -foo; // turn off sign bit - Port::nan = foo; -} - -int Port::isNan(double r) -{ - return isnan(r); -} - -int Port::isNan(longdouble r) -{ - return isnan(r); -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(longdouble r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 62 of 0..79 for 80 bit reals. - */ - return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); -} - -#undef isfinite -int Port::isFinite(double r) -{ - return finite(r); -} - -int Port::isInfinity(double r) -{ - return isinf(r); -} - -#undef signbit -int Port::Signbit(double r) -{ - return (long)(((long *)&r)[1] & 0x80000000); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - -unsigned long long Port::strtoull(const char *p, char **pend, int base) -{ - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - return L","; -} - -char *Port::strupr(char *s) -{ - char *t = s; - - while (*s) - { - *s = toupper(*s); - s++; - } - - return t; -} - -#endif - diff --git a/dmd/root/port.h b/dmd/root/port.h deleted file mode 100644 index bcd3dafc..00000000 --- a/dmd/root/port.h +++ /dev/null @@ -1,83 +0,0 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com - -#ifndef PORT_H -#define PORT_H - -// Portable wrapper around compiler/system specific things. -// The idea is to minimize #ifdef's in the app code. - -#include "longdouble.h" - -#ifndef TYPEDEFS -#define TYPEDEFS - -#include - -#if _MSC_VER -typedef __int64 longlong; -typedef unsigned __int64 ulonglong; - -// According to VC 8.0 docs, long double is the same as double -longdouble strtold(const char *p,char **endp); -#define strtof strtod - -#else -typedef long long longlong; -typedef unsigned long long ulonglong; -#endif - -#endif - -typedef double d_time; - -struct Port -{ - static double nan; - static double infinity; - static double dbl_max; - static double dbl_min; - static longdouble ldbl_max; - -#if __OpenBSD__ -#elif __GNUC__ && !defined __HAIKU__ - // These conflict with macros in math.h, should rename them - #undef isnan - #undef isfinite - #undef isinfinity - #undef signbit -#endif - static int isNan(double); - static int isNan(longdouble); - - static int isSignallingNan(double); - static int isSignallingNan(longdouble); - - static int isFinite(double); - static int isInfinity(double); - static int Signbit(double); - - static double floor(double); - static double pow(double x, double y); - - static longdouble fmodl(longdouble x, longdouble y); - - static ulonglong strtoull(const char *p, char **pend, int base); - - static char *ull_to_string(char *buffer, ulonglong ull); - static wchar_t *ull_to_string(wchar_t *buffer, ulonglong ull); - - // Convert ulonglong to double - static double ull_to_double(ulonglong ull); - - // Get locale-dependent list separator - static const char *list_separator(); - static const wchar_t *wlist_separator(); - - static char *strupr(char *); -}; - -#endif diff --git a/dmd/root/root.c b/dmd/root/root.c deleted file mode 100644 index 71d2bd81..00000000 --- a/dmd/root/root.c +++ /dev/null @@ -1,1992 +0,0 @@ - -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef POSIX -#define POSIX (linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4) -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#if _MSC_VER ||__MINGW32__ -#include -#include -#endif - -#if _WIN32 -#include -#include -#include -#endif - -#ifdef __HAIKU__ -#include -#endif - -#if POSIX -#include -#include -#include -#include -#include -#include -#endif - -#include "port.h" -#include "root.h" -#include "rmem.h" -#include "mars.h" - -#if 0 //__SC__ //def DEBUG -extern "C" void __cdecl _assert(void *e, void *f, unsigned line) -{ - printf("Assert('%s','%s',%d)\n",e,f,line); - fflush(stdout); - *(char *)0 = 0; -} -#endif - - -/************************************* - * Convert wchar string to ascii string. - */ - -char *wchar2ascii(wchar_t *us) -{ - return wchar2ascii(us, wcslen(us)); -} - -char *wchar2ascii(wchar_t *us, unsigned len) -{ - unsigned i; - char *p; - - p = (char *)mem.malloc(len + 1); - for (i = 0; i <= len; i++) - p[i] = (char) us[i]; - return p; -} - -int wcharIsAscii(wchar_t *us) -{ - return wcharIsAscii(us, wcslen(us)); -} - -int wcharIsAscii(wchar_t *us, unsigned len) -{ - unsigned i; - - for (i = 0; i <= len; i++) - { - if (us[i] & ~0xFF) // if high bits set - return 0; // it's not ascii - } - return 1; -} - - -/*********************************** - * Compare length-prefixed strings (bstr). - */ - -int bstrcmp(unsigned char *b1, unsigned char *b2) -{ - return (*b1 == *b2 && memcmp(b1 + 1, b2 + 1, *b2) == 0) ? 0 : 1; -} - -/*************************************** - * Convert bstr into a malloc'd string. - */ - -char *bstr2str(unsigned char *b) -{ - char *s; - unsigned len; - - len = *b; - s = (char *) mem.malloc(len + 1); - s[len] = 0; - return (char *)memcpy(s,b + 1,len); -} - -/************************************** - * Print error message and exit. - */ - -void error(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - printf("Error: "); - vprintf(format, ap); - va_end( ap ); - printf("\n"); - fflush(stdout); - - exit(EXIT_FAILURE); -} - -void error_mem() -{ - error("out of memory"); -} - -/************************************** - * Print warning message. - */ - -void warning(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - printf("Warning: "); - vprintf(format, ap); - va_end( ap ); - printf("\n"); - fflush(stdout); -} - -/****************************** Object ********************************/ - -int Object::equals(Object *o) -{ - return o == this; -} - -hash_t Object::hashCode() -{ - return (hash_t) this; -} - -int Object::compare(Object *obj) -{ - return this - obj; -} - -void Object::print() -{ - printf("%s %p\n", toChars(), this); -} - -char *Object::toChars() -{ - return (char *)"Object"; -} - -int Object::dyncast() -{ - return 0; -} - -void Object::toBuffer(OutBuffer *b) -{ - b->writestring("Object"); -} - -void Object::mark() -{ -} - -/****************************** String ********************************/ - -String::String(char *str, int ref) -{ - this->str = ref ? str : mem.strdup(str); - this->ref = ref; -} - -String::~String() -{ - mem.free(str); -} - -void String::mark() -{ - mem.mark(str); -} - -hash_t String::calcHash(const char *str, size_t len) -{ - hash_t hash = 0; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(uint8_t *)str; - return hash; - - case 2: - hash *= 37; - hash += *(uint16_t *)str; - return hash; - - case 3: - hash *= 37; - hash += (*(uint16_t *)str << 8) + - ((uint8_t *)str)[2]; - return hash; - - default: - hash *= 37; - hash += *(uint32_t *)str; - str += 4; - len -= 4; - break; - } - } -} - -hash_t String::calcHash(const char *str) -{ - return calcHash(str, strlen(str)); -} - -hash_t String::hashCode() -{ - return calcHash(str, strlen(str)); -} - -unsigned String::len() -{ - return strlen(str); -} - -int String::equals(Object *obj) -{ - return strcmp(str,((String *)obj)->str) == 0; -} - -int String::compare(Object *obj) -{ - return strcmp(str,((String *)obj)->str); -} - -char *String::toChars() -{ - return str; -} - -void String::print() -{ - printf("String '%s'\n",str); -} - - -/****************************** FileName ********************************/ - -FileName::FileName(char *str, int ref) - : String(str,ref) -{ -} - -char *FileName::combine(const char *path, const char *name) -{ char *f; - size_t pathlen; - size_t namelen; - - if (!path || !*path) - return (char *)name; - pathlen = strlen(path); - namelen = strlen(name); - f = (char *)mem.malloc(pathlen + 1 + namelen + 1); - memcpy(f, path, pathlen); -#if POSIX - if (path[pathlen - 1] != '/') - { f[pathlen] = '/'; - pathlen++; - } -#elif _WIN32 - if (path[pathlen - 1] != '\\' && - path[pathlen - 1] != '/' && - path[pathlen - 1] != ':') - { f[pathlen] = '\\'; - pathlen++; - } -#else - assert(0); -#endif - memcpy(f + pathlen, name, namelen + 1); - return f; -} - -FileName::FileName(char *path, char *name) - : String(combine(path,name),1) -{ -} - -// Split a path into an Array of paths -Strings *FileName::splitPath(const char *path) -{ - char c = 0; // unnecessary initializer is for VC /W4 - const char *p; - OutBuffer buf; - Strings *array; - - array = new Strings(); - if (path) - { - p = path; - do - { char instring = 0; - - while (isspace((unsigned char)*p)) // skip leading whitespace - p++; - buf.reserve(strlen(p) + 1); // guess size of path - // LDC remember first character - const char* start = p; - for (; ; p++) - { - c = *p; - switch (c) - { - case '"': - instring ^= 1; // toggle inside/outside of string - continue; - -#if MACINTOSH - case ',': -#endif -#if _WIN32 - case ';': -#endif -#if POSIX - case ':': -#endif - p++; - break; // note that ; cannot appear as part - // of a path, quotes won't protect it - - case 0x1A: // ^Z means end of file - case 0: - break; - - case '\r': - continue; // ignore carriage returns - -#if POSIX - case '~': - // LDC don't expand unless first character of path - if (p != start) - goto Ldefault; - buf.writestring(getenv("HOME")); - continue; -#endif - -#if 0 - case ' ': - case '\t': // tabs in filenames? - if (!instring) // if not in string - break; // treat as end of path -#endif - default: - Ldefault: - buf.writeByte(c); - continue; - } - break; - } - if (buf.offset) // if path is not empty - { - buf.writeByte(0); // to asciiz - array->push(buf.extractData()); - } - } while (c); - } - return array; -} - -hash_t FileName::hashCode() -{ -#if _WIN32 - // We need a different hashCode because it must be case-insensitive - size_t len = strlen(str); - hash_t hash = 0; - unsigned char *s = (unsigned char *)str; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(uint8_t *)s | 0x20; - return hash; - - case 2: - hash *= 37; - hash += *(uint16_t *)s | 0x2020; - return hash; - - case 3: - hash *= 37; - hash += ((*(uint16_t *)s << 8) + - ((uint8_t *)s)[2]) | 0x202020; - break; - - default: - hash *= 37; - hash += *(uint32_t *)s | 0x20202020; - s += 4; - len -= 4; - break; - } - } -#else - // darwin HFS is case insensitive, though... - return String::hashCode(); -#endif -} - -int FileName::compare(Object *obj) -{ - return compare(str, ((FileName *)obj)->str); -} - -int FileName::compare(const char *name1, const char *name2) -{ -#if _WIN32 - return stricmp(name1, name2); -#else - return strcmp(name1, name2); -#endif -} - -int FileName::equals(Object *obj) -{ - return compare(obj) == 0; -} - -int FileName::equals(const char *name1, const char *name2) -{ - return compare(name1, name2) == 0; -} - -/************************************ - * Return !=0 if absolute path name. - */ - -int FileName::absolute(const char *name) -{ -#if _WIN32 - return (*name == '\\') || - (*name == '/') || - (*name && name[1] == ':'); -#elif POSIX - return (*name == '/'); -#else - assert(0); -#endif -} - -/******************************** - * Return filename extension (read-only). - * Points past '.' of extension. - * If there isn't one, return NULL. - */ - -char *FileName::ext(const char *str) -{ - char *e; - size_t len = strlen(str); - - e = (char *)str + len; - for (;;) - { - switch (*e) - { case '.': - return e + 1; -#if POSIX - case '/': - break; -#endif -#if _WIN32 - case '\\': - case ':': - case '/': - break; -#endif - default: - if (e == str) - break; - e--; - continue; - } - return NULL; - } -} - -char *FileName::ext() -{ - return ext(str); -} - -/******************************** - * Return mem.malloc'd filename with extension removed. - */ - -char *FileName::removeExt(const char *str) -{ - const char *e = ext(str); - if (e) - { size_t len = (e - str) - 1; - char *n = (char *)mem.malloc(len + 1); - memcpy(n, str, len); - n[len] = 0; - return n; - } - return mem.strdup(str); -} - -/******************************** - * Return filename name excluding path (read-only). - */ - -char *FileName::name(const char *str) -{ - char *e; - size_t len = strlen(str); - - e = (char *)str + len; - for (;;) - { - switch (*e) - { -#if POSIX - case '/': - return e + 1; -#endif -#if _WIN32 - case '/': - case '\\': - return e + 1; - case ':': - /* The ':' is a drive letter only if it is the second - * character or the last character, - * otherwise it is an ADS (Alternate Data Stream) separator. - * Consider ADS separators as part of the file name. - */ - if (e == str + 1 || e == str + len - 1) - return e + 1; -#endif - default: - if (e == str) - break; - e--; - continue; - } - return e; - } -} - -char *FileName::name() -{ - return name(str); -} - -/************************************** - * Return path portion of str. - * Path will does not include trailing path separator. - */ - -char *FileName::path(const char *str) -{ - char *n = name(str); - char *path; - size_t pathlen; - - if (n > str) - { -#if POSIX - if (n[-1] == '/') - n--; -#elif _WIN32 - if (n[-1] == '\\' || n[-1] == '/') - n--; -#else - assert(0); -#endif - } - pathlen = n - str; - path = (char *)mem.malloc(pathlen + 1); - memcpy(path, str, pathlen); - path[pathlen] = 0; - return path; -} - -/************************************** - * Replace filename portion of path. - */ - -const char *FileName::replaceName(const char *path, const char *name) -{ char *f; - char *n; - size_t pathlen; - size_t namelen; - - if (absolute(name)) - return name; - - n = FileName::name(path); - if (n == path) - return name; - pathlen = n - path; - namelen = strlen(name); - f = (char *)mem.malloc(pathlen + 1 + namelen + 1); - memcpy(f, path, pathlen); -#if POSIX - if (path[pathlen - 1] != '/') - { f[pathlen] = '/'; - pathlen++; - } -#elif _WIN32 - if (path[pathlen - 1] != '\\' && - path[pathlen - 1] != '/' && - path[pathlen - 1] != ':') - { f[pathlen] = '\\'; - pathlen++; - } -#else - assert(0); -#endif - memcpy(f + pathlen, name, namelen + 1); - return f; -} - -/*************************** - */ - -FileName *FileName::defaultExt(const char *name, const char *ext) -{ - char *e; - char *s; - size_t len; - size_t extlen; - - e = FileName::ext(name); - if (e) // if already has an extension - return new FileName((char *)name, 0); - - len = strlen(name); - extlen = strlen(ext); - s = (char *)alloca(len + 1 + extlen + 1); - memcpy(s,name,len); - s[len] = '.'; - memcpy(s + len + 1, ext, extlen + 1); - return new FileName(s, 0); -} - -/*************************** - */ - -FileName *FileName::forceExt(const char *name, const char *ext) -{ - char *e; - char *s; - size_t len; - size_t extlen; - - e = FileName::ext(name); - if (e) // if already has an extension - { - len = e - name; - extlen = strlen(ext); - - s = (char *)alloca(len + extlen + 1); - memcpy(s,name,len); - memcpy(s + len, ext, extlen + 1); - return new FileName(s, 0); - } - else - return defaultExt(name, ext); // doesn't have one -} - -/****************************** - * Return !=0 if extensions match. - */ - -int FileName::equalsExt(const char *ext) -{ const char *e; - - e = FileName::ext(); - if (!e && !ext) - return 1; - if (!e || !ext) - return 0; -#if POSIX - return strcmp(e,ext) == 0; -#elif _WIN32 - return stricmp(e,ext) == 0; -#else - assert(0); -#endif -} - -/************************************* - * Copy file from this to to. - */ - -void FileName::CopyTo(FileName *to) -{ - File file(this); - -#if _WIN32 - file.touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); // keep same file time -#elif POSIX - file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time -#else - assert(0); -#endif - file.readv(); - file.name = to; - file.writev(); -} - -/************************************* - * Search Path for file. - * Input: - * cwd if !=0, search current directory before searching path - */ - -char *FileName::searchPath(Strings *path, const char *name, int cwd) -{ - if (absolute(name)) - { - return exists(name) ? (char *)name : NULL; - } - if (cwd) - { - if (exists(name)) - return (char *)name; - } - if (path) - { unsigned i; - - for (i = 0; i < path->dim; i++) - { - char *p = path->tdata()[i]; - char *n = combine(p, name); - - if (exists(n)) - return n; - } - } - return NULL; -} - - -/************************************* - * Search Path for file in a safe manner. - * - * Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory - * ('Path Traversal') attacks. - * http://cwe.mitre.org/data/definitions/22.html - * More info: - * https://www.securecoding.cert.org/confluence/display/seccode/FIO02-C.+Canonicalize+path+names+originating+from+untrusted+sources - * Returns: - * NULL file not found - * !=NULL mem.malloc'd file name - */ - -char *FileName::safeSearchPath(Strings *path, const char *name) -{ -#if _WIN32 - /* Disallow % / \ : and .. in name characters - */ - for (const char *p = name; *p; p++) - { - char c = *p; - if (c == '\\' || c == '/' || c == ':' || c == '%' || - (c == '.' && p[1] == '.')) - { - return NULL; - } - } - - return FileName::searchPath(path, name, 0); -#elif POSIX - /* Even with realpath(), we must check for // and disallow it - */ - for (const char *p = name; *p; p++) - { - char c = *p; - if (c == '/' && p[1] == '/') - { - return NULL; - } - } - - if (path) - { unsigned i; - - /* Each path is converted to a cannonical name and then a check is done to see - * that the searched name is really a child one of the the paths searched. - */ - for (i = 0; i < path->dim; i++) - { - char *cname = NULL; - char *cpath = canonicalName(path->tdata()[i]); - //printf("FileName::safeSearchPath(): name=%s; path=%s; cpath=%s\n", - // name, (char *)path->data[i], cpath); - if (cpath == NULL) - goto cont; - cname = canonicalName(combine(cpath, name)); - //printf("FileName::safeSearchPath(): cname=%s\n", cname); - if (cname == NULL) - goto cont; - //printf("FileName::safeSearchPath(): exists=%i " - // "strncmp(cpath, cname, %i)=%i\n", exists(cname), - // strlen(cpath), strncmp(cpath, cname, strlen(cpath))); - // exists and name is *really* a "child" of path - if (exists(cname) && strncmp(cpath, cname, strlen(cpath)) == 0) - { - free(cpath); - char *p = mem.strdup(cname); - free(cname); - return p; - } -cont: - if (cpath) - free(cpath); - if (cname) - free(cname); - } - } - return NULL; -#else - assert(0); -#endif -} - - -int FileName::exists(const char *name) -{ -#if POSIX - struct stat st; - - if (stat(name, &st) < 0) - return 0; - if (S_ISDIR(st.st_mode)) - return 2; - return 1; -#elif _WIN32 - DWORD dw; - int result; - - dw = GetFileAttributesA(name); - if (dw == -1L) - result = 0; - else if (dw & FILE_ATTRIBUTE_DIRECTORY) - result = 2; - else - result = 1; - return result; -#else - assert(0); -#endif -} - -void FileName::ensurePathExists(const char *path) -{ - //printf("FileName::ensurePathExists(%s)\n", path ? path : ""); - if (path && *path) - { - if (!exists(path)) - { - char *p = FileName::path(path); - if (*p) - { -#if _WIN32 - size_t len = strlen(path); - if (len > 2 && p[-1] == ':' && path + 2 == p) - { mem.free(p); - return; - } -#endif - ensurePathExists(p); - mem.free(p); - } -#if _WIN32 - if (path[strlen(path) - 1] != '\\') -#endif -#if POSIX - if (path[strlen(path) - 1] != '\\') -#endif - { - //printf("mkdir(%s)\n", path); -#if _WIN32 - if (_mkdir(path)) -#endif -#if POSIX - if (mkdir(path, 0777)) -#endif - { - /* Don't error out if another instance of dmd just created - * this directory - */ - if (errno != EEXIST) - error("cannot create directory %s", path); - } - } - } - } -} - - -/****************************************** - * Return canonical version of name in a malloc'd buffer. - * This code is high risk. - */ -char *FileName::canonicalName(const char *name) -{ -#if linux - // Lovely glibc extension to do it for us - return canonicalize_file_name(name); -#elif POSIX - #if _POSIX_VERSION >= 200809L || defined (linux) - // NULL destination buffer is allowed and preferred - return realpath(name, NULL); - #else - char *cname = NULL; - #if PATH_MAX - /* PATH_MAX must be defined as a constant in , - * otherwise using it is unsafe due to TOCTOU - */ - size_t path_max = (size_t)PATH_MAX; - if (path_max > 0) - { - /* Need to add one to PATH_MAX because of realpath() buffer overflow bug: - * http://isec.pl/vulnerabilities/isec-0011-wu-ftpd.txt - */ - cname = (char *)malloc(path_max + 1); - if (cname == NULL) - return NULL; - } - #endif - return realpath(name, cname); - #endif -#elif _WIN32 - /* Apparently, there is no good way to do this on Windows. - * GetFullPathName isn't it. - */ - assert(0); - return NULL; -#else - assert(0); - return NULL; -#endif -} - - -/****************************** File ********************************/ - -File::File(FileName *n) -{ - ref = 0; - buffer = NULL; - len = 0; - touchtime = NULL; - name = n; -} - -File::File(char *n) -{ - ref = 0; - buffer = NULL; - len = 0; - touchtime = NULL; - name = new FileName(n, 0); -} - -File::~File() -{ - if (buffer) - { - if (ref == 0) - mem.free(buffer); -#if _WIN32 - else if (ref == 2) - UnmapViewOfFile(buffer); -#endif - } - if (touchtime) - mem.free(touchtime); -} - -void File::mark() -{ - mem.mark(buffer); - mem.mark(touchtime); - mem.mark(name); -} - -/************************************* - */ - -int File::read() -{ -#if POSIX - off_t size; - ssize_t numread; - int fd; - struct stat buf; - int result = 0; - char *name; - - name = this->name->toChars(); - //printf("File::read('%s')\n",name); - fd = open(name, O_RDONLY); - if (fd == -1) - { - //printf("\topen error, errno = %d\n",errno); - goto err1; - } - - if (!ref) - ::free(buffer); - ref = 0; // we own the buffer now - - //printf("\tfile opened\n"); - if (fstat(fd, &buf)) - { - printf("\tfstat error, errno = %d\n",errno); - goto err2; - } - size = buf.st_size; - buffer = (unsigned char *) ::malloc(size + 2); - if (!buffer) - { - printf("\tmalloc error, errno = %d\n",errno); - goto err2; - } - - numread = ::read(fd, buffer, size); - if (numread != size) - { - printf("\tread error, errno = %d\n",errno); - goto err2; - } - - if (touchtime) - memcpy(touchtime, &buf, sizeof(buf)); - - if (close(fd) == -1) - { - printf("\tclose error, errno = %d\n",errno); - goto err; - } - - len = size; - - // Always store a wchar ^Z past end of buffer so scanner has a sentinel - buffer[size] = 0; // ^Z is obsolete, use 0 - buffer[size + 1] = 0; - return 0; - -err2: - close(fd); -err: - ::free(buffer); - buffer = NULL; - len = 0; - -err1: - result = 1; - return result; -#elif _WIN32 - DWORD size; - DWORD numread; - HANDLE h; - int result = 0; - char *name; - - name = this->name->toChars(); - h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,0); - if (h == INVALID_HANDLE_VALUE) - goto err1; - - if (!ref) - ::free(buffer); - ref = 0; - - size = GetFileSize(h,NULL); - buffer = (unsigned char *) ::malloc(size + 2); - if (!buffer) - goto err2; - - if (ReadFile(h,buffer,size,&numread,NULL) != TRUE) - goto err2; - - if (numread != size) - goto err2; - - if (touchtime) - { - if (!GetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime)) - goto err2; - } - - if (!CloseHandle(h)) - goto err; - - len = size; - - // Always store a wchar ^Z past end of buffer so scanner has a sentinel - buffer[size] = 0; // ^Z is obsolete, use 0 - buffer[size + 1] = 0; - return 0; - -err2: - CloseHandle(h); -err: - ::free(buffer); - buffer = NULL; - len = 0; - -err1: - result = 1; - return result; -#else - assert(0); -#endif -} - -/***************************** - * Read a file with memory mapped file I/O. - */ - -int File::mmread() -{ -#if POSIX - return read(); -#elif _WIN32 - HANDLE hFile; - HANDLE hFileMap; - DWORD size; - char *name; - - name = this->name->toChars(); - hFile = CreateFile(name, GENERIC_READ, - FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) - goto Lerr; - size = GetFileSize(hFile, NULL); - //printf(" file created, size %d\n", size); - - hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,size,NULL); - if (CloseHandle(hFile) != TRUE) - goto Lerr; - - if (hFileMap == NULL) - goto Lerr; - - //printf(" mapping created\n"); - - if (!ref) - mem.free(buffer); - ref = 2; - buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL); - if (CloseHandle(hFileMap) != TRUE) - goto Lerr; - if (buffer == NULL) // mapping view failed - goto Lerr; - - len = size; - //printf(" buffer = %p\n", buffer); - - return 0; - -Lerr: - return GetLastError(); // failure -#else - assert(0); -#endif -} - -/********************************************* - * Write a file. - * Returns: - * 0 success - */ - -int File::write() -{ -#if POSIX - int fd; - ssize_t numwritten; - char *name; - - name = this->name->toChars(); - fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644); - if (fd == -1) - goto err; - - numwritten = ::write(fd, buffer, len); - if (len != numwritten) - goto err2; - - if (close(fd) == -1) - goto err; - - if (touchtime) - { struct utimbuf ubuf; - - ubuf.actime = ((struct stat *)touchtime)->st_atime; - ubuf.modtime = ((struct stat *)touchtime)->st_mtime; - if (utime(name, &ubuf)) - goto err; - } - return 0; - -err2: - close(fd); - ::remove(name); -err: - return 1; -#elif _WIN32 - HANDLE h; - DWORD numwritten; - char *name; - - name = this->name->toChars(); - h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); - if (h == INVALID_HANDLE_VALUE) - goto err; - - if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) - goto err2; - - if (len != numwritten) - goto err2; - - if (touchtime) { - SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); - } - if (!CloseHandle(h)) - goto err; - return 0; - -err2: - CloseHandle(h); - DeleteFileA(name); -err: - return 1; -#else - assert(0); -#endif -} - -/********************************************* - * Append to a file. - * Returns: - * 0 success - */ - -int File::append() -{ -#if POSIX - return 1; -#elif _WIN32 - HANDLE h; - DWORD numwritten; - char *name; - - name = this->name->toChars(); - h = CreateFileA(name,GENERIC_WRITE,0,NULL,OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); - if (h == INVALID_HANDLE_VALUE) - goto err; - -#if 1 - SetFilePointer(h, 0, NULL, FILE_END); -#else // INVALID_SET_FILE_POINTER doesn't seem to have a definition - if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) - goto err; -#endif - - if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) - goto err2; - - if (len != numwritten) - goto err2; - - if (touchtime) { - SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); - } - if (!CloseHandle(h)) - goto err; - return 0; - -err2: - CloseHandle(h); -err: - return 1; -#else - assert(0); -#endif -} - -/************************************** - */ - -void File::readv() -{ - if (read()) - error("Error reading file '%s'\n",name->toChars()); -} - -/************************************** - */ - -void File::mmreadv() -{ - if (mmread()) - readv(); -} - -void File::writev() -{ - if (write()) - error("Error writing file '%s'\n",name->toChars()); -} - -void File::appendv() -{ - if (write()) - error("Error appending to file '%s'\n",name->toChars()); -} - -/******************************************* - * Return !=0 if file exists. - * 0: file doesn't exist - * 1: normal file - * 2: directory - */ - -int File::exists() -{ -#if POSIX - return 0; -#elif _WIN32 - DWORD dw; - int result; - char *name; - - name = this->name->toChars(); - if (touchtime) - dw = ((WIN32_FIND_DATAA *)touchtime)->dwFileAttributes; - else - dw = GetFileAttributesA(name); - if (dw == -1L) - result = 0; - else if (dw & FILE_ATTRIBUTE_DIRECTORY) - result = 2; - else - result = 1; - return result; -#else - assert(0); -#endif -} - -void File::remove() -{ -#if POSIX - ::remove(this->name->toChars()); -#elif _WIN32 - DeleteFileA(this->name->toChars()); -#else - assert(0); -#endif -} - -Files *File::match(char *n) -{ - return match(new FileName(n, 0)); -} - -Files *File::match(FileName *n) -{ -#if POSIX - return NULL; -#elif _WIN32 - HANDLE h; - WIN32_FIND_DATAA fileinfo; - Files *a; - char *c; - char *name; - - a = new Files(); - c = n->toChars(); - name = n->name(); - h = FindFirstFileA(c,&fileinfo); - if (h != INVALID_HANDLE_VALUE) - { - do - { - // Glue path together with name - char *fn; - File *f; - - fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1); - memcpy(fn, c, name - c); - strcpy(fn + (name - c), fileinfo.cFileName); - f = new File(fn); - f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); - memcpy(f->touchtime, &fileinfo, sizeof(fileinfo)); - a->push(f); - } while (FindNextFileA(h,&fileinfo) != FALSE); - FindClose(h); - } - return a; -#else - assert(0); -#endif -} - -int File::compareTime(File *f) -{ -#if POSIX - return 0; -#elif _WIN32 - if (!touchtime) - stat(); - if (!f->touchtime) - f->stat(); - return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime); -#else - assert(0); -#endif -} - -void File::stat() -{ -#if POSIX - if (!touchtime) - { - touchtime = mem.calloc(1, sizeof(struct stat)); - } -#elif _WIN32 - HANDLE h; - - if (!touchtime) - { - touchtime = mem.calloc(1, sizeof(WIN32_FIND_DATAA)); - } - h = FindFirstFileA(name->toChars(),(WIN32_FIND_DATAA *)touchtime); - if (h != INVALID_HANDLE_VALUE) - { - FindClose(h); - } -#else - assert(0); -#endif -} - -void File::checkoffset(size_t offset, size_t nbytes) -{ - if (offset > len || offset + nbytes > len) - error("Corrupt file '%s': offset x%llx off end of file",toChars(),(ulonglong)offset); -} - -char *File::toChars() -{ - return name->toChars(); -} - - -/************************* OutBuffer *************************/ - -OutBuffer::OutBuffer() -{ - data = NULL; - offset = 0; - size = 0; -} - -OutBuffer::~OutBuffer() -{ - mem.free(data); -} - -char *OutBuffer::extractData() -{ - char *p; - - p = (char *)data; - data = NULL; - offset = 0; - size = 0; - return p; -} - -void OutBuffer::mark() -{ - mem.mark(data); -} - -void OutBuffer::reserve(unsigned nbytes) -{ - //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); - if (size - offset < nbytes) - { -#if defined (__x86_64__) - size = (offset + nbytes) * 2 + 2; -#else - size = (offset + nbytes) * 2; -#endif - data = (unsigned char *)mem.realloc(data, size); - } -} - -void OutBuffer::reset() -{ - offset = 0; -} - -void OutBuffer::setsize(unsigned size) -{ - offset = size; -} - -void OutBuffer::write(const void *data, unsigned nbytes) -{ - reserve(nbytes); - memcpy(this->data + offset, data, nbytes); - offset += nbytes; -} - -void OutBuffer::writebstring(unsigned char *string) -{ - write(string,*string + 1); -} - -void OutBuffer::writestring(const char *string) -{ - write(string,strlen(string)); -} - -void OutBuffer::prependstring(const char *string) -{ unsigned len; - - len = strlen(string); - reserve(len); - memmove(data + len, data, offset); - memcpy(data, string, len); - offset += len; -} - -void OutBuffer::writenl() -{ -#if _WIN32 - writeword(0x0A0D); // newline is CR,LF on Microsoft OS's -#else - writeByte('\n'); -#endif -} - -void OutBuffer::writeByte(unsigned b) -{ - reserve(1); - this->data[offset] = (unsigned char)b; - offset++; -} - -void OutBuffer::writeUTF8(unsigned b) -{ - reserve(6); - if (b <= 0x7F) - { - this->data[offset] = (unsigned char)b; - offset++; - } - else if (b <= 0x7FF) - { - this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0); - this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80); - offset += 2; - } - else if (b <= 0xFFFF) - { - this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0); - this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); - this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80); - offset += 3; - } - else if (b <= 0x1FFFFF) - { - this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0); - this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); - this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); - this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80); - offset += 4; - } - else if (b <= 0x3FFFFFF) - { - this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8); - this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); - this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); - this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); - this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80); - offset += 5; - } - else if (b <= 0x7FFFFFFF) - { - this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC); - this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80); - this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); - this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); - this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); - this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80); - offset += 6; - } - else - assert(0); -} - -void OutBuffer::prependbyte(unsigned b) -{ - reserve(1); - memmove(data + 1, data, offset); - data[0] = (unsigned char)b; - offset++; -} - -void OutBuffer::writeword(unsigned w) -{ - reserve(2); - *(unsigned short *)(this->data + offset) = (unsigned short)w; - offset += 2; -} - -void OutBuffer::writeUTF16(unsigned w) -{ - reserve(4); - if (w <= 0xFFFF) - { - *(unsigned short *)(this->data + offset) = (unsigned short)w; - offset += 2; - } - else if (w <= 0x10FFFF) - { - *(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0); - *(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00); - offset += 4; - } - else - assert(0); -} - -void OutBuffer::write4(unsigned w) -{ - reserve(4); - *(unsigned *)(this->data + offset) = w; - offset += 4; -} - -void OutBuffer::write(OutBuffer *buf) -{ - if (buf) - { reserve(buf->offset); - memcpy(data + offset, buf->data, buf->offset); - offset += buf->offset; - } -} - -void OutBuffer::write(Object *obj) -{ - if (obj) - { - writestring(obj->toChars()); - } -} - -void OutBuffer::fill0(unsigned nbytes) -{ - reserve(nbytes); - memset(data + offset,0,nbytes); - offset += nbytes; -} - -void OutBuffer::align(unsigned size) -{ unsigned nbytes; - - nbytes = ((offset + size - 1) & ~(size - 1)) - offset; - fill0(nbytes); -} - - -//////////////////////////////////////////////////////////////// -// The compiler shipped with Visual Studio 2005 (and possible -// other versions) does not support C99 printf format specfiers -// such as %z and %j -#if 0 && _MSC_VER -using std::string; -using std::wstring; - -template -inline void -search_and_replace(S& str, const S& what, const S& replacement) -{ - assert(!what.empty()); - size_t pos = str.find(what); - while (pos != S::npos) - { - str.replace(pos, what.size(), replacement); - pos = str.find(what, pos + replacement.size()); - } -} -#define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) \ - S tmp = f; \ - search_and_replace(fmt, S("%z"), S("%l")); \ - search_and_replace(fmt, S("%j"), S("%l")); \ - f = tmp.c_str(); -#else -#define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) -#endif - -void OutBuffer::vprintf(const char *format, va_list args) -{ - char buffer[128]; - char *p; - unsigned psize; - int count; - - WORKAROUND_C99_SPECIFIERS_BUG(string, fmt, format); - - p = buffer; - psize = sizeof(buffer); - for (;;) - { -#if _WIN32 - count = _vsnprintf(p,psize,format,args); - if (count != -1) - break; - psize *= 2; -#elif POSIX - va_list va; - va_copy(va, args); -/* - The functions vprintf(), vfprintf(), vsprintf(), vsnprintf() - are equivalent to the functions printf(), fprintf(), sprintf(), - snprintf(), respectively, except that they are called with a - va_list instead of a variable number of arguments. These - functions do not call the va_end macro. Consequently, the value - of ap is undefined after the call. The application should call - va_end(ap) itself afterwards. - */ - count = vsnprintf(p,psize,format,va); - va_end(va); - if (count == -1) - psize *= 2; - else if (count >= psize) - psize = count + 1; - else - break; -#else - assert(0); -#endif - p = (char *) alloca(psize); // buffer too small, try again with larger size - } - write(p,count); -} - -void OutBuffer::printf(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - vprintf(format,ap); - va_end(ap); -} - -void OutBuffer::bracket(char left, char right) -{ - reserve(2); - memmove(data + 1, data, offset); - data[0] = left; - data[offset + 1] = right; - offset += 2; -} - -/****************** - * Insert left at i, and right at j. - * Return index just past right. - */ - -unsigned OutBuffer::bracket(unsigned i, const char *left, unsigned j, const char *right) -{ - size_t leftlen = strlen(left); - size_t rightlen = strlen(right); - reserve(leftlen + rightlen); - insert(i, left, leftlen); - insert(j + leftlen, right, rightlen); - return j + leftlen + rightlen; -} - -void OutBuffer::spread(unsigned offset, unsigned nbytes) -{ - reserve(nbytes); - memmove(data + offset + nbytes, data + offset, - this->offset - offset); - this->offset += nbytes; -} - -/**************************************** - * Returns: offset + nbytes - */ - -unsigned OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes) -{ - spread(offset, nbytes); - memmove(data + offset, p, nbytes); - return offset + nbytes; -} - -void OutBuffer::remove(unsigned offset, unsigned nbytes) -{ - memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes)); - this->offset -= nbytes; -} - -char *OutBuffer::toChars() -{ - writeByte(0); - return (char *)data; -} - -/********************************* Bits ****************************/ - -Bits::Bits() -{ - data = NULL; - bitdim = 0; - allocdim = 0; -} - -Bits::~Bits() -{ - mem.free(data); -} - -void Bits::mark() -{ - mem.mark(data); -} - -void Bits::resize(unsigned bitdim) -{ - unsigned allocdim; - unsigned mask; - - allocdim = (bitdim + 31) / 32; - data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0])); - if (this->allocdim < allocdim) - memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0])); - - // Clear other bits in last word - mask = (1 << (bitdim & 31)) - 1; - if (mask) - data[allocdim - 1] &= ~mask; - - this->bitdim = bitdim; - this->allocdim = allocdim; -} - -void Bits::set(unsigned bitnum) -{ - data[bitnum / 32] |= 1 << (bitnum & 31); -} - -void Bits::clear(unsigned bitnum) -{ - data[bitnum / 32] &= ~(1 << (bitnum & 31)); -} - -int Bits::test(unsigned bitnum) -{ - return data[bitnum / 32] & (1 << (bitnum & 31)); -} - -void Bits::set() -{ unsigned mask; - - memset(data, ~0, allocdim * sizeof(data[0])); - - // Clear other bits in last word - mask = (1 << (bitdim & 31)) - 1; - if (mask) - data[allocdim - 1] &= mask; -} - -void Bits::clear() -{ - memset(data, 0, allocdim * sizeof(data[0])); -} - -void Bits::copy(Bits *from) -{ - assert(bitdim == from->bitdim); - memcpy(data, from->data, allocdim * sizeof(data[0])); -} - -Bits *Bits::clone() -{ - Bits *b; - - b = new Bits(); - b->resize(bitdim); - b->copy(this); - return b; -} - -void Bits::sub(Bits *b) -{ - unsigned u; - - for (u = 0; u < allocdim; u++) - data[u] &= ~b->data[u]; -} - - - - - - - - - - - - - - - diff --git a/dmd/root/root.h b/dmd/root/root.h deleted file mode 100644 index 387218b3..00000000 --- a/dmd/root/root.h +++ /dev/null @@ -1,422 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef ROOT_H -#define ROOT_H - -#include -#include -#ifdef DEBUG -#include -#endif - -#if __DMC__ -#pragma once -#endif - -#ifndef IS_PRINTF -# ifdef __GNUC__ -# define IS_PRINTF(FMTARG) __attribute((__format__ (__printf__, (FMTARG), (FMTARG)+1) )) -# else -# define IS_PRINTF(FMTARG) -# endif -#endif - -typedef size_t hash_t; - -#include "longdouble.h" - -char *wchar2ascii(wchar_t *); -int wcharIsAscii(wchar_t *); -char *wchar2ascii(wchar_t *, unsigned len); -int wcharIsAscii(wchar_t *, unsigned len); - -int bstrcmp(unsigned char *s1, unsigned char *s2); -char *bstr2str(unsigned char *b); -void error(const char *format, ...) IS_PRINTF(1); -#if M_UNICODE -void error(const dchar *format, ...); -#endif -void warning(const char *format, ...) IS_PRINTF(1); - -#ifndef TYPEDEFS -#define TYPEDEFS - -#if _MSC_VER -#include // for _isnan -#include // for alloca -// According to VC 8.0 docs, long double is the same as double -longdouble strtold(const char *p,char **endp); -#define strtof strtod -#define isnan _isnan - -typedef __int64 longlong; -typedef unsigned __int64 ulonglong; -#else -typedef long long longlong; -typedef unsigned long long ulonglong; -#endif - -#endif - -longlong randomx(); - -/* - * Root of our class library. - */ - -struct OutBuffer; - -// Can't include arraytypes.h here, need to declare these directly. -template struct ArrayBase; -typedef ArrayBase Files; -typedef ArrayBase Strings; - - -struct Object -{ - Object() { } - virtual ~Object() { } - - virtual int equals(Object *o); - - /** - * Returns a hash code, useful for things like building hash tables of Objects. - */ - virtual hash_t hashCode(); - - /** - * Return <0, ==0, or >0 if this is less than, equal to, or greater than obj. - * Useful for sorting Objects. - */ - virtual int compare(Object *obj); - - /** - * Pretty-print an Object. Useful for debugging the old-fashioned way. - */ - virtual void print(); - - virtual char *toChars(); - virtual void toBuffer(OutBuffer *buf); - - /** - * Used as a replacement for dynamic_cast. Returns a unique number - * defined by the library user. For Object, the return value is 0. - */ - virtual int dyncast(); - - /** - * Marks pointers for garbage collector by calling mem.mark() for all pointers into heap. - */ - /*virtual*/ // not used, disable for now - void mark(); -}; - -struct String : Object -{ - int ref; // != 0 if this is a reference to someone else's string - char *str; // the string itself - - String(char *str, int ref = 1); - - ~String(); - - static hash_t calcHash(const char *str, size_t len); - static hash_t calcHash(const char *str); - hash_t hashCode(); - unsigned len(); - int equals(Object *obj); - int compare(Object *obj); - char *toChars(); - void print(); - void mark(); -}; - -struct FileName : String -{ - FileName(char *str, int ref); - FileName(char *path, char *name); - hash_t hashCode(); - int equals(Object *obj); - static int equals(const char *name1, const char *name2); - int compare(Object *obj); - static int compare(const char *name1, const char *name2); - static int absolute(const char *name); - static char *ext(const char *); - char *ext(); - static char *removeExt(const char *str); - static char *name(const char *); - char *name(); - static char *path(const char *); - static const char *replaceName(const char *path, const char *name); - - static char *combine(const char *path, const char *name); - static Strings *splitPath(const char *path); - static FileName *defaultExt(const char *name, const char *ext); - static FileName *forceExt(const char *name, const char *ext); - int equalsExt(const char *ext); - - void CopyTo(FileName *to); - static char *searchPath(Strings *path, const char *name, int cwd); - static char *safeSearchPath(Strings *path, const char *name); - static int exists(const char *name); - static void ensurePathExists(const char *path); - static char *canonicalName(const char *name); -}; - -struct File : Object -{ - int ref; // != 0 if this is a reference to someone else's buffer - unsigned char *buffer; // data for our file - unsigned len; // amount of data in buffer[] - void *touchtime; // system time to use for file - - FileName *name; // name of our file - - File(char *); - File(FileName *); - ~File(); - - void mark(); - - char *toChars(); - - /* Read file, return !=0 if error - */ - - int read(); - - /* Write file, either succeed or fail - * with error message & exit. - */ - - void readv(); - - /* Read file, return !=0 if error - */ - - int mmread(); - - /* Write file, either succeed or fail - * with error message & exit. - */ - - void mmreadv(); - - /* Write file, return !=0 if error - */ - - int write(); - - /* Write file, either succeed or fail - * with error message & exit. - */ - - void writev(); - - /* Return !=0 if file exists. - * 0: file doesn't exist - * 1: normal file - * 2: directory - */ - - /* Append to file, return !=0 if error - */ - - int append(); - - /* Append to file, either succeed or fail - * with error message & exit. - */ - - void appendv(); - - /* Return !=0 if file exists. - * 0: file doesn't exist - * 1: normal file - * 2: directory - */ - - int exists(); - - /* Given wildcard filespec, return an array of - * matching File's. - */ - - static Files *match(char *); - static Files *match(FileName *); - - // Compare file times. - // Return <0 this < f - // =0 this == f - // >0 this > f - int compareTime(File *f); - - // Read system file statistics - void stat(); - - /* Set buffer - */ - - void setbuffer(void *buffer, unsigned len) - { - this->buffer = (unsigned char *)buffer; - this->len = len; - } - - void checkoffset(size_t offset, size_t nbytes); - - void remove(); // delete file -}; - -struct OutBuffer : Object -{ - unsigned char *data; - unsigned offset; - unsigned size; - - OutBuffer(); - ~OutBuffer(); - char *extractData(); - void mark(); - - void reserve(unsigned nbytes); - void setsize(unsigned size); - void reset(); - void write(const void *data, unsigned nbytes); - void writebstring(unsigned char *string); - void writestring(const char *string); - void prependstring(const char *string); - void writenl(); // write newline - void writeByte(unsigned b); - void writebyte(unsigned b) { writeByte(b); } - void writeUTF8(unsigned b); - void prependbyte(unsigned b); - void writeword(unsigned w); - void writeUTF16(unsigned w); - void write4(unsigned w); - void write(OutBuffer *buf); - void write(Object *obj); - void fill0(unsigned nbytes); - void align(unsigned size); - void vprintf(const char *format, va_list args); - void printf(const char *format, ...) IS_PRINTF(2); -#if M_UNICODE - void vprintf(const unsigned short *format, va_list args); - void printf(const unsigned short *format, ...); -#endif - void bracket(char left, char right); - unsigned bracket(unsigned i, const char *left, unsigned j, const char *right); - void spread(unsigned offset, unsigned nbytes); - unsigned insert(unsigned offset, const void *data, unsigned nbytes); - void remove(unsigned offset, unsigned nbytes); - char *toChars(); - char *extractString(); -}; - -struct Array : Object -{ - unsigned dim; - void **data; - - private: - unsigned allocdim; - #define SMALLARRAYCAP 1 - void *smallarray[SMALLARRAYCAP]; // inline storage for small arrays - - public: - Array(); - ~Array(); - //Array(const Array&); - void mark(); - char *toChars(); - - void reserve(unsigned nentries); - void setDim(unsigned newdim); - void fixDim(); - void push(void *ptr); - void *pop(); - void shift(void *ptr); - void insert(unsigned index, void *ptr); - void insert(unsigned index, Array *a); - void append(Array *a); - void remove(unsigned i); - void zero(); - void *tos(); - void sort(); - Array *copy(); -}; - -template -struct ArrayBase : Array -{ - TYPE **tdata() - { - return (TYPE **)data; - } - - TYPE*& operator[] (size_t index) - { -#ifdef DEBUG - assert(index < dim); -#endif - return ((TYPE **)data)[index]; - } - - void insert(size_t index, TYPE *v) - { - Array::insert(index, (void *)v); - } - - void insert(size_t index, ArrayBase *a) - { - Array::insert(index, (Array *)a); - } - - void append(ArrayBase *a) - { - Array::append((Array *)a); - } - - void push(TYPE *a) - { - Array::push((void *)a); - } - - ArrayBase *copy() - { - return (ArrayBase *)Array::copy(); - } -}; - -struct Bits : Object -{ - unsigned bitdim; - unsigned allocdim; - unsigned *data; - - Bits(); - ~Bits(); - void mark(); - - void resize(unsigned bitdim); - - void set(unsigned bitnum); - void clear(unsigned bitnum); - int test(unsigned bitnum); - - void set(); - void clear(); - void copy(Bits *from); - Bits *clone(); - - void sub(Bits *b); -}; - -#endif diff --git a/dmd/root/stringtable.c b/dmd/root/stringtable.c deleted file mode 100644 index 58dcd0b6..00000000 --- a/dmd/root/stringtable.c +++ /dev/null @@ -1,189 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#include -#include // uint{8|16|32}_t -#include // memcpy() -#include - -#include "root.h" -#include "rmem.h" // mem -#include "stringtable.h" - -hash_t calcHash(const char *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint16_t *)str; -#else - hash += str[0] * 256 + str[1]; -#endif - return hash; - - case 3: - hash *= 37; -#if LITTLE_ENDIAN - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; -#else - hash += (str[0] * 256 + str[1]) * 256 + str[2]; -#endif - return hash; - - default: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint32_t *)str; -#else - hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; -#endif - str += 4; - len -= 4; - break; - } - } -} - -void StringValue::ctor(const char *p, unsigned length) -{ - this->length = length; - this->lstring[length] = 0; - memcpy(this->lstring, p, length * sizeof(char)); -} - -void StringTable::init(unsigned size) -{ - table = (void **)mem.calloc(size, sizeof(void *)); - tabledim = size; - count = 0; -} - -StringTable::~StringTable() -{ - unsigned i; - - // Zero out dangling pointers to help garbage collector. - // Should zero out StringEntry's too. - for (i = 0; i < count; i++) - table[i] = NULL; - - mem.free(table); - table = NULL; -} - -struct StringEntry -{ - StringEntry *left; - StringEntry *right; - hash_t hash; - - StringValue value; - - static StringEntry *alloc(const char *s, unsigned len); -}; - -StringEntry *StringEntry::alloc(const char *s, unsigned len) -{ - StringEntry *se; - - se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) + len + 1); - se->value.ctor(s, len); - se->hash = calcHash(s,len); - return se; -} - -void **StringTable::search(const char *s, unsigned len) -{ - hash_t hash; - unsigned u; - int cmp; - StringEntry **se; - - //printf("StringTable::search(%p,%d)\n",s,len); - hash = calcHash(s,len); - u = hash % tabledim; - se = (StringEntry **)&table[u]; - //printf("\thash = %d, u = %d\n",hash,u); - while (*se) - { - cmp = (*se)->hash - hash; - if (cmp == 0) - { - cmp = (*se)->value.len() - len; - if (cmp == 0) - { - cmp = ::memcmp(s,(*se)->value.toDchars(),len); - if (cmp == 0) - break; - } - } - if (cmp < 0) - se = &(*se)->left; - else - se = &(*se)->right; - } - //printf("\treturn %p, %p\n",se, (*se)); - return (void **)se; -} - -StringValue *StringTable::lookup(const char *s, unsigned len) -{ StringEntry *se; - - se = *(StringEntry **)search(s,len); - if (se) - return &se->value; - else - return NULL; -} - -StringValue *StringTable::update(const char *s, unsigned len) -{ StringEntry **pse; - StringEntry *se; - - pse = (StringEntry **)search(s,len); - se = *pse; - if (!se) // not in table: so create new entry - { - se = StringEntry::alloc(s, len); - *pse = se; - } - return &se->value; -} - -StringValue *StringTable::insert(const char *s, unsigned len) -{ StringEntry **pse; - StringEntry *se; - - pse = (StringEntry **)search(s,len); - se = *pse; - if (se) - return NULL; // error: already in table - else - { - se = StringEntry::alloc(s, len); - *pse = se; - } - return &se->value; -} diff --git a/dmd/root/stringtable.h b/dmd/root/stringtable.h deleted file mode 100644 index 170894e6..00000000 --- a/dmd/root/stringtable.h +++ /dev/null @@ -1,71 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#ifndef STRINGTABLE_H -#define STRINGTABLE_H - -#if __SC__ -#pragma once -#endif - -#include "root.h" - -struct StringEntry; - -// StringValue is a variable-length structure as indicated by the last array -// member with unspecified size. It has neither proper c'tors nor a factory -// method because the only thing which should be creating these is StringTable. -struct StringValue -{ - union - { - void *ptrvalue; - char *string; - }; -private: - unsigned length; - -#ifndef IN_GCC - // Disable warning about nonstandard extension - #pragma warning (disable : 4200) -#endif - char lstring[]; - -public: - unsigned len() const { return length; } - const char *toDchars() const { return lstring; } - -private: - friend struct StringEntry; - StringValue(); // not constructible - // This is more like a placement new c'tor - void ctor(const char *p, unsigned length); -}; - -struct StringTable -{ -private: - void **table; - unsigned count; - unsigned tabledim; - -public: - void init(unsigned size = 37); - ~StringTable(); - - StringValue *lookup(const char *s, unsigned len); - StringValue *insert(const char *s, unsigned len); - StringValue *update(const char *s, unsigned len); - -private: - void **search(const char *s, unsigned len); -}; - -#endif diff --git a/dmd/scope.c b/dmd/scope.c deleted file mode 100644 index 0e2592f4..00000000 --- a/dmd/scope.c +++ /dev/null @@ -1,400 +0,0 @@ - -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include // strlen() - -#include "root.h" -#include "speller.h" - -#include "mars.h" -#include "init.h" -#include "identifier.h" -#include "scope.h" -#include "attrib.h" -#include "dsymbol.h" -#include "declaration.h" -#include "aggregate.h" -#include "module.h" -#include "id.h" -#include "lexer.h" - -Scope *Scope::freelist = NULL; - -void *Scope::operator new(size_t size) -{ - if (freelist) - { - Scope *s = freelist; - freelist = s->enclosing; - //printf("freelist %p\n", s); - assert(s->flags & SCOPEfree); - s->flags &= ~SCOPEfree; - return s; - } - - void *p = ::operator new(size); - //printf("new %p\n", p); - return p; -} - -Scope::Scope() -{ // Create root scope - - //printf("Scope::Scope() %p\n", this); - this->module = NULL; - this->scopesym = NULL; - this->sd = NULL; - this->enclosing = NULL; - this->parent = NULL; - this->sw = NULL; - this->enclosingFinally = NULL; - this->enclosingScopeExit = NULL; - this->tinst = NULL; - this->sbreak = NULL; - this->scontinue = NULL; - this->fes = NULL; - this->structalign = global.structalign; - this->func = NULL; - this->slabel = NULL; - this->linkage = LINKd; - this->protection = PROTpublic; - this->explicitProtection = 0; - this->stc = 0; - this->offset = 0; - this->inunion = 0; - this->incontract = 0; - this->nofree = 0; - this->noctor = 0; - this->noaccesscheck = 0; - this->mustsemantic = 0; - this->intypeof = 0; - this->parameterSpecialization = 0; - this->callSuper = 0; - this->flags = 0; - this->lastdc = NULL; - this->lastoffset = 0; - this->docbuf = NULL; -} - -Scope::Scope(Scope *enclosing) -{ - //printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this); - assert(!(enclosing->flags & SCOPEfree)); - this->module = enclosing->module; - this->func = enclosing->func; - this->parent = enclosing->parent; - this->scopesym = NULL; - this->sd = NULL; - this->sw = enclosing->sw; - this->enclosingFinally = enclosing->enclosingFinally; - this->enclosingScopeExit = enclosing->enclosingScopeExit; - this->tinst = enclosing->tinst; - this->sbreak = enclosing->sbreak; - this->scontinue = enclosing->scontinue; - this->fes = enclosing->fes; - this->structalign = enclosing->structalign; - this->enclosing = enclosing; -#ifdef DEBUG - if (enclosing->enclosing) - assert(!(enclosing->enclosing->flags & SCOPEfree)); - if (this == enclosing->enclosing) - { - printf("this = %p, enclosing = %p, enclosing->enclosing = %p\n", this, enclosing, enclosing->enclosing); - } - assert(this != enclosing->enclosing); -#endif - this->slabel = NULL; - this->linkage = enclosing->linkage; - this->protection = enclosing->protection; - this->explicitProtection = enclosing->explicitProtection; - this->stc = enclosing->stc; - this->offset = 0; - this->inunion = enclosing->inunion; - this->incontract = enclosing->incontract; - this->nofree = 0; - this->noctor = enclosing->noctor; - this->noaccesscheck = enclosing->noaccesscheck; - this->mustsemantic = enclosing->mustsemantic; - this->intypeof = enclosing->intypeof; - this->parameterSpecialization = enclosing->parameterSpecialization; - this->callSuper = enclosing->callSuper; - this->flags = 0; - this->lastdc = NULL; - this->lastoffset = 0; - this->docbuf = enclosing->docbuf; - assert(this != enclosing); -} - -Scope *Scope::createGlobal(Module *module) -{ - Scope *sc; - - sc = new Scope(); - sc->module = module; - sc->scopesym = new ScopeDsymbol(); - sc->scopesym->symtab = new DsymbolTable(); - - // Add top level package as member of this global scope - Dsymbol *m = module; - while (m->parent) - m = m->parent; - m->addMember(NULL, sc->scopesym, 1); - m->parent = NULL; // got changed by addMember() - - // Create the module scope underneath the global scope - sc = sc->push(module); - sc->parent = module; - return sc; -} - -Scope *Scope::push() -{ - //printf("Scope::push()\n"); - Scope *s = new Scope(this); - assert(this != s); - return s; -} - -Scope *Scope::push(ScopeDsymbol *ss) -{ - //printf("Scope::push(%s)\n", ss->toChars()); - Scope *s = push(); - s->scopesym = ss; - return s; -} - -Scope *Scope::pop() -{ - //printf("Scope::pop() %p nofree = %d\n", this, nofree); - Scope *enc = enclosing; - - if (enclosing) - enclosing->callSuper |= callSuper; - - if (!nofree) - { enclosing = freelist; - freelist = this; - flags |= SCOPEfree; - } - - return enc; -} - -void Scope::mergeCallSuper(Loc loc, unsigned cs) -{ - // This does a primitive flow analysis to support the restrictions - // regarding when and how constructors can appear. - // It merges the results of two paths. - // The two paths are callSuper and cs; the result is merged into callSuper. - - if (cs != callSuper) - { int a; - int b; - - callSuper |= cs & (CSXany_ctor | CSXlabel); - if (cs & CSXreturn) - { - } - else if (callSuper & CSXreturn) - { - callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel)); - } - else - { - a = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0; - b = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0; - if (a != b) - error(loc, "one path skips constructor"); - callSuper |= cs; - } - } -} - -Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) -{ Dsymbol *s; - Scope *sc; - - //printf("Scope::search(%p, '%s')\n", this, ident->toChars()); - if (ident == Id::empty) - { - // Look for module scope - for (sc = this; sc; sc = sc->enclosing) - { - assert(sc != sc->enclosing); - if (sc->scopesym) - { - s = sc->scopesym->isModule(); - if (s) - { - //printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars()); - if (pscopesym) - *pscopesym = sc->scopesym; - return s; - } - } - } - return NULL; - } - - for (sc = this; sc; sc = sc->enclosing) - { - assert(sc != sc->enclosing); - if (sc->scopesym) - { - //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind()); - s = sc->scopesym->search(loc, ident, 0); - if (s) - { - if ((global.params.warnings || - global.params.Dversion > 1) && - ident == Id::length && - sc->scopesym->isArrayScopeSymbol() && - sc->enclosing && - sc->enclosing->search(loc, ident, NULL)) - { - warning(s->loc, "array 'length' hides other 'length' name in outer scope"); - } - - //printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind()); - if (pscopesym) - *pscopesym = sc->scopesym; - return s; - } - } - } - - return NULL; -} - -Dsymbol *Scope::insert(Dsymbol *s) -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) - { - //printf("\tsc = %p\n", sc); - if (sc->scopesym) - { - //printf("\t\tsc->scopesym = %p\n", sc->scopesym); - if (!sc->scopesym->symtab) - sc->scopesym->symtab = new DsymbolTable(); - return sc->scopesym->symtabInsert(s); - } - } - assert(0); - return NULL; -} - -/******************************************** - * Search enclosing scopes for ClassDeclaration. - */ - -ClassDeclaration *Scope::getClassScope() -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) - { - ClassDeclaration *cd; - - if (sc->scopesym) - { - cd = sc->scopesym->isClassDeclaration(); - if (cd) - return cd; - } - } - return NULL; -} - -/******************************************** - * Search enclosing scopes for ClassDeclaration. - */ - -AggregateDeclaration *Scope::getStructClassScope() -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) - { - AggregateDeclaration *ad; - - if (sc->scopesym) - { - ad = sc->scopesym->isClassDeclaration(); - if (ad) - return ad; - else - { ad = sc->scopesym->isStructDeclaration(); - if (ad) - return ad; - } - } - } - return NULL; -} - -/******************************************* - * For TemplateDeclarations, we need to remember the Scope - * where it was declared. So mark the Scope as not - * to be free'd. - */ - -void Scope::setNoFree() -{ Scope *sc; - //int i = 0; - - //printf("Scope::setNoFree(this = %p)\n", this); - for (sc = this; sc; sc = sc->enclosing) - { - //printf("\tsc = %p\n", sc); - sc->nofree = 1; - - assert(!(flags & SCOPEfree)); - //assert(sc != sc->enclosing); - //assert(!sc->enclosing || sc != sc->enclosing->enclosing); - //if (++i == 10) - //assert(0); - } -} - - -/************************************************ - * Given the failed search attempt, try to find - * one with a close spelling. - */ - -void *scope_search_fp(void *arg, const char *seed) -{ - //printf("scope_search_fp('%s')\n", seed); - - /* If not in the lexer's string table, it certainly isn't in the symbol table. - * Doing this first is a lot faster. - */ - size_t len = strlen(seed); - if (!len) - return NULL; - StringValue *sv = Lexer::stringtable.lookup(seed, len); - if (!sv) - return NULL; - Identifier *id = (Identifier *)sv->ptrvalue; - assert(id); - - Scope *sc = (Scope *)arg; - Module::clearCache(); - Dsymbol *s = sc->search(0, id, NULL); - return s; -} - -Dsymbol *Scope::search_correct(Identifier *ident) -{ - if (global.gag) - return NULL; // don't do it for speculative compiles; too time consuming - - return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars); -} diff --git a/dmd/scope.h b/dmd/scope.h deleted file mode 100644 index 2fc23af6..00000000 --- a/dmd/scope.h +++ /dev/null @@ -1,130 +0,0 @@ - -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_SCOPE_H -#define DMD_SCOPE_H - -#ifdef __DMC__ -#pragma once -#endif - -struct Dsymbol; -struct ScopeDsymbol; -struct Array; -struct Identifier; -struct Module; -struct Statement; -struct SwitchStatement; -struct TryFinallyStatement; -struct LabelStatement; -struct ForeachStatement; -struct ClassDeclaration; -struct AggregateDeclaration; -struct AnonymousAggregateDeclaration; -struct FuncDeclaration; -struct DocComment; -struct TemplateInstance; - -#if IN_LLVM -struct EnclosingHandler; -struct AnonDeclaration; -#endif - -#if __GNUC__ -// Requires a full definition for PROT and LINK -#include "dsymbol.h" // PROT -#include "mars.h" // LINK -#else -enum LINK; -enum PROT; -#endif - -struct Scope -{ - Scope *enclosing; // enclosing Scope - - Module *module; // Root module - ScopeDsymbol *scopesym; // current symbol - ScopeDsymbol *sd; // if in static if, and declaring new symbols, - // sd gets the addMember() - FuncDeclaration *func; // function we are in - Dsymbol *parent; // parent to use - LabelStatement *slabel; // enclosing labelled statement - SwitchStatement *sw; // enclosing switch statement - TryFinallyStatement *enclosingFinally; // enclosing try finally statement; set inside its finally block - TemplateInstance *tinst; // enclosing template instance - Statement *enclosingScopeExit; // enclosing statement that wants to do something on scope exit - Statement *sbreak; // enclosing statement that supports "break" - Statement *scontinue; // enclosing statement that supports "continue" - ForeachStatement *fes; // if nested function for ForeachStatement, this is it - unsigned offset; // next offset to use in aggregate - // This really shouldn't be a part of Scope, because it requires - // semantic() to be done in the lexical field order. It should be - // set in a pass after semantic() on all fields so they can be - // semantic'd in any order. - int inunion; // we're processing members of a union - int incontract; // we're inside contract code - int nofree; // set if shouldn't free it - int noctor; // set if constructor calls aren't allowed - int intypeof; // in typeof(exp) - int parameterSpecialization; // if in template parameter specialization - int noaccesscheck; // don't do access checks - int mustsemantic; // cannot defer semantic() - - unsigned callSuper; // primitive flow analysis for constructors -#define CSXthis_ctor 1 // called this() -#define CSXsuper_ctor 2 // called super() -#define CSXthis 4 // referenced this -#define CSXsuper 8 // referenced super -#define CSXlabel 0x10 // seen a label -#define CSXreturn 0x20 // seen a return statement -#define CSXany_ctor 0x40 // either this() or super() was called - - structalign_t structalign; // alignment for struct members - enum LINK linkage; // linkage for external functions - - enum PROT protection; // protection for class members - int explicitProtection; // set if in an explicit protection attribute - - StorageClass stc; // storage class - - unsigned flags; -#define SCOPEctor 1 // constructor type -#define SCOPEstaticif 2 // inside static if -#define SCOPEfree 4 // is on free list - - - DocComment *lastdc; // documentation comment for last symbol at this scope - unsigned lastoffset; // offset in docbuf of where to insert next dec - OutBuffer *docbuf; // buffer for documentation output - - static Scope *freelist; - static void *operator new(size_t sz); - static Scope *createGlobal(Module *module); - - Scope(); - Scope(Module *module); - Scope(Scope *enclosing); - - Scope *push(); - Scope *push(ScopeDsymbol *ss); - Scope *pop(); - - void mergeCallSuper(Loc loc, unsigned cs); - - Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym); - Dsymbol *search_correct(Identifier *ident); - Dsymbol *insert(Dsymbol *s); - - ClassDeclaration *getClassScope(); - AggregateDeclaration *getStructClassScope(); - void setNoFree(); -}; - -#endif /* DMD_SCOPE_H */ diff --git a/dmd/sideeffect.c b/dmd/sideeffect.c deleted file mode 100644 index 9cc43b70..00000000 --- a/dmd/sideeffect.c +++ /dev/null @@ -1,34 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "init.h" -#include "expression.h" -#include "template.h" -#include "statement.h" -#include "mtype.h" -#include "utf.h" -#include "declaration.h" -#include "aggregate.h" -#include "scope.h" -#include "attrib.h" - -/******************************************** - * Determine if Expression has any side effects. - */ - -bool Expression::hasSideEffect() -{ - return checkSideEffect(2); -} - diff --git a/dmd/speller.c b/dmd/speller.c deleted file mode 100644 index 0a93b0e9..00000000 --- a/dmd/speller.c +++ /dev/null @@ -1,262 +0,0 @@ - -#include -#include -#include -#include - -#if __sun&&__SVR4 || _MSC_VER -#include -#endif -#if _MSC_VER -#include -#endif - - - -#include "speller.h" - -const char idchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; - -/************************************************** - * Looks for correct spelling. - * Currently only looks a 'distance' of one from the seed[]. - * This does an exhaustive search, so can potentially be very slow. - * Input: - * seed wrongly spelled word - * fp search function - * fparg argument to search function - * charset character set - * Returns: - * NULL no correct spellings found - * void* value returned by fp() for first possible correct spelling - */ - -void *spellerY(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, - const char *charset, size_t index) -{ - if (!seedlen) - return NULL; - assert(seed[seedlen] == 0); - - char tmp[30]; - char *buf; - if (seedlen <= sizeof(tmp) - 2) - buf = tmp; - else - { - buf = (char *)alloca(seedlen + 2); // leave space for extra char - if (!buf) - return NULL; // no matches - } - - memcpy(buf, seed, index); - - /* Delete at seed[index] */ - if (index < seedlen) - { - memcpy(buf + index, seed + index + 1, seedlen - index); - assert(buf[seedlen - 1] == 0); - void *p = (*fp)(fparg, buf); - if (p) - return p; - } - - if (charset && *charset) - { - /* Substitutions */ - if (index < seedlen) - { - memcpy(buf, seed, seedlen + 1); - for (const char *s = charset; *s; s++) - { - buf[index] = *s; - - //printf("sub buf = '%s'\n", buf); - void *p = (*fp)(fparg, buf); - if (p) - return p; - } - assert(buf[seedlen] == 0); - } - - /* Insertions */ - memcpy (buf + index + 1, seed + index, seedlen + 1 - index); - - for (const char *s = charset; *s; s++) - { - buf[index] = *s; - - //printf("ins buf = '%s'\n", buf); - void *p = (*fp)(fparg, buf); - if (p) - return p; - } - assert(buf[seedlen + 1] == 0); - } - - return NULL; // didn't find any corrections -} - -void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, - const char *charset, int flag) -{ - if (!seedlen) - return NULL; - - char tmp[30]; - char *buf; - if (seedlen <= sizeof(tmp) - 2) - buf = tmp; - else - { - buf = (char *)alloca(seedlen + 2); // leave space for extra char - if (!buf) - return NULL; // no matches - } - - /* Deletions */ - memcpy(buf, seed + 1, seedlen); - for (size_t i = 0; i < seedlen; i++) - { - //printf("del buf = '%s'\n", buf); - void *p; - if (flag) - p = spellerY(buf, seedlen - 1, fp, fparg, charset, i); - else - p = (*fp)(fparg, buf); - if (p) - return p; - - buf[i] = seed[i]; - } - - /* Transpositions */ - if (!flag) - { - memcpy(buf, seed, seedlen + 1); - for (size_t i = 0; i + 1 < seedlen; i++) - { - // swap [i] and [i + 1] - buf[i] = seed[i + 1]; - buf[i + 1] = seed[i]; - - //printf("tra buf = '%s'\n", buf); - void *p = (*fp)(fparg, buf); - if (p) - return p; - - buf[i] = seed[i]; - } - } - - if (charset && *charset) - { - /* Substitutions */ - memcpy(buf, seed, seedlen + 1); - for (size_t i = 0; i < seedlen; i++) - { - for (const char *s = charset; *s; s++) - { - buf[i] = *s; - - //printf("sub buf = '%s'\n", buf); - void *p; - if (flag) - p = spellerY(buf, seedlen, fp, fparg, charset, i + 1); - else - p = (*fp)(fparg, buf); - if (p) - return p; - } - buf[i] = seed[i]; - } - - /* Insertions */ - memcpy(buf + 1, seed, seedlen + 1); - for (size_t i = 0; i <= seedlen; i++) // yes, do seedlen+1 iterations - { - for (const char *s = charset; *s; s++) - { - buf[i] = *s; - - //printf("ins buf = '%s'\n", buf); - void *p; - if (flag) - p = spellerY(buf, seedlen + 1, fp, fparg, charset, i + 1); - else - p = (*fp)(fparg, buf); - if (p) - return p; - } - buf[i] = seed[i]; // going past end of seed[] is ok, as we hit the 0 - } - } - - return NULL; // didn't find any corrections -} - -void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset) -{ - size_t seedlen = strlen(seed); - for (int distance = 0; distance < 2; distance++) - { void *p = spellerX(seed, seedlen, fp, fparg, charset, distance); - if (p) - return p; -// if (seedlen > 10) -// break; - } - return NULL; // didn't find it -} - - -#if UNITTEST - -#include -#include -#include - -void *speller_test(void *fparg, const char *s) -{ - //printf("speller_test(%s, %s)\n", fparg, s); - if (strcmp((char *)fparg, s) == 0) - return fparg; - return NULL; -} - -void unittest_speller() -{ - static const char *cases[][3] = - { - { "hello", "hell", "y" }, - { "hello", "hel", "y" }, - { "hello", "ello", "y" }, - { "hello", "llo", "y" }, - { "hello", "hellox", "y" }, - { "hello", "helloxy", "y" }, - { "hello", "xhello", "y" }, - { "hello", "xyhello", "y" }, - { "hello", "ehllo", "y" }, - { "hello", "helol", "y" }, - { "hello", "abcd", "n" }, - //{ "ehllo", "helol", "y" }, - { "hello", "helxxlo", "y" }, - { "hello", "ehlxxlo", "n" }, - { "hello", "heaao", "y" }, - { "_123456789_123456789_123456789_123456789", "_123456789_123456789_123456789_12345678", "y" }, - }; - //printf("unittest_speller()\n"); - const void *p = speller("hello", &speller_test, (void *)"hell", idchars); - assert(p != NULL); - for (int i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) - { - //printf("case [%d]\n", i); - void *p = speller(cases[i][0], &speller_test, (void *)cases[i][1], idchars); - if (p) - assert(cases[i][2][0] == 'y'); - else - assert(cases[i][2][0] == 'n'); - } - //printf("unittest_speller() success\n"); -} - -#endif diff --git a/dmd/speller.h b/dmd/speller.h deleted file mode 100644 index bfffb739..00000000 --- a/dmd/speller.h +++ /dev/null @@ -1,7 +0,0 @@ - -typedef void *(fp_speller_t)(void *, const char *); - -extern const char idchars[]; - -void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset); - diff --git a/dmd/statement.c b/dmd/statement.c deleted file mode 100644 index 7d412d45..00000000 --- a/dmd/statement.c +++ /dev/null @@ -1,4665 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "rmem.h" - -#include "statement.h" -#include "expression.h" -#include "cond.h" -#include "init.h" -#include "staticassert.h" -#include "mtype.h" -#include "scope.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" -#include "hdrgen.h" -#include "parse.h" -#include "template.h" -#include "attrib.h" - -/*********************************** - * Return size of OS critical section. - */ -#if IN_LLVM - -#if linux || __APPLE__ || __FreeBSD__ || __HAIKU__ || __sun&&__SVR4 -#include // Needs pthread_mutex_t for os_critsecsize -#elif _WIN32 -#include -#endif - -// sizes based on those from tollvm.cpp:DtoMutexType() -int os_critsecsize() -{ -#if defined(_MSC_VER) - // Return sizeof(RTL_CRITICAL_SECTION) - return global.params.is64bit ? 40 : 24; -#else - if (global.params.targetTriple.isOSWindows()) - return global.params.is64bit ? 40 : 24; - else if (global.params.targetTriple.getOS() == llvm::Triple::FreeBSD) - return sizeof(size_t); - else - return sizeof(pthread_mutex_t); -#endif -} -#elif IN_DMD - -extern int os_critsecsize32(); -extern int os_critsecsize64(); - -#endif - -/******************************** Statement ***************************/ - -Statement::Statement(Loc loc) - : loc(loc) -{ - // If this is an in{} contract scope statement (skip for determining - // inlineStatus of a function body for header content) - incontract = 0; -} - -Statement *Statement::syntaxCopy() -{ - assert(0); - return NULL; -} - -void Statement::print() -{ - fprintf(stdmsg, "%s\n", toChars()); - fflush(stdmsg); -} - -char *Statement::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); -} - -void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("Statement::toCBuffer()"); - buf->writenl(); -} - -Statement *Statement::semantic(Scope *sc) -{ - return this; -} - -Statement *Statement::semanticNoScope(Scope *sc) -{ - //printf("Statement::semanticNoScope() %s\n", toChars()); - Statement *s = this; - if (!s->isCompoundStatement() && !s->isScopeStatement()) - { - s = new CompoundStatement(loc, this); // so scopeCode() gets called - } - s = s->semantic(sc); - return s; -} - -// Same as semanticNoScope(), but do create a new scope - -Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue) -{ - Scope *scd = sc->push(); - if (sbreak) - scd->sbreak = sbreak; - if (scontinue) - scd->scontinue = scontinue; - Statement *s = semanticNoScope(scd); - scd->pop(); - return s; -} - -void Statement::error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); -} - -void Statement::warning(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::vwarning(loc, format, ap); - va_end( ap ); -} - -int Statement::hasBreak() -{ - //printf("Statement::hasBreak()\n"); - return FALSE; -} - -int Statement::hasContinue() -{ - return FALSE; -} - -// TRUE if statement uses exception handling - -int Statement::usesEH() -{ - return FALSE; -} - -/* Only valid after semantic analysis - */ -int Statement::blockExit(bool mustNotThrow) -{ - printf("Statement::blockExit(%p)\n", this); - printf("%s\n", toChars()); - assert(0); - return BEany; -} - -// TRUE if statement 'comes from' somewhere else, like a goto - -int Statement::comeFrom() -{ - //printf("Statement::comeFrom()\n"); - return FALSE; -} - -// Return TRUE if statement has no code in it -int Statement::isEmpty() -{ - //printf("Statement::isEmpty()\n"); - return FALSE; -} - -/**************************************** - * If this statement has code that needs to run in a finally clause - * at the end of the current scope, return that code in the form of - * a Statement. - * Output: - * *sentry code executed upon entry to the scope - * *sexception code executed upon exit from the scope via exception - * *sfinally code executed in finally block - */ - -void Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("Statement::scopeCode()\n"); - //print(); - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; -} - -/********************************* - * Flatten out the scope by presenting the statement - * as an array of statements. - * Returns NULL if no flattening necessary. - */ - -Statements *Statement::flatten(Scope *sc) -{ - return NULL; -} - - -/******************************** PeelStatement ***************************/ - -PeelStatement::PeelStatement(Statement *s) - : Statement(s->loc) -{ - this->s = s; -} - -Statement *PeelStatement::semantic(Scope *sc) -{ - /* "peel" off this wrapper, and don't run semantic() - * on the result. - */ - return s; -} - -/******************************** ExpStatement ***************************/ - -ExpStatement::ExpStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -ExpStatement::ExpStatement(Loc loc, Dsymbol *declaration) - : Statement(loc) -{ - this->exp = new DeclarationExp(loc, declaration); -} - -Statement *ExpStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - ExpStatement *es = new ExpStatement(loc, e); - return es; -} - -void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (exp) - { exp->toCBuffer(buf, hgs); - if (exp->op != TOKdeclaration) - { buf->writeByte(';'); - if (!hgs->FLinit.init) - buf->writenl(); - } - } - else - { - buf->writeByte(';'); - if (!hgs->FLinit.init) - buf->writenl(); - } -} - -Statement *ExpStatement::semantic(Scope *sc) -{ - if (exp) - { - //printf("ExpStatement::semantic() %s\n", exp->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp->checkSideEffect(0); - exp = exp->optimize(0); - } - return this; -} - -int ExpStatement::blockExit(bool mustNotThrow) -{ int result = BEfallthru; - - if (exp) - { - if (exp->op == TOKhalt) - return BEhalt; - if (exp->op == TOKassert) - { AssertExp *a = (AssertExp *)exp; - - if (a->e1->isBool(FALSE)) // if it's an assert(0) - return BEhalt; - } - if (exp->canThrow()) - result |= BEthrow; - } - return result; -} - -int ExpStatement::isEmpty() -{ - return exp == NULL; -} - -void ExpStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("ExpStatement::scopeCode()\n"); - //print(); - - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - - if (exp) - { - if (exp->op == TOKdeclaration) - { - DeclarationExp *de = (DeclarationExp *)(exp); - VarDeclaration *v = de->declaration->isVarDeclaration(); - if (v) - { - Expression *e = v->callScopeDtor(sc); - if (e) - { - //printf("dtor is: "); e->print(); -#if 0 - if (v->type->toBasetype()->ty == Tstruct) - { /* Need a 'gate' to turn on/off destruction, - * in case v gets moved elsewhere. - */ - Identifier *id = Lexer::uniqueId("__runDtor"); - ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(1)); - VarDeclaration *rd = new VarDeclaration(loc, Type::tint32, id, ie); - *sentry = new ExpStatement(loc, rd); - v->rundtor = rd; - - /* Rewrite e as: - * rundtor && e - */ - Expression *ve = new VarExp(loc, v->rundtor); - e = new AndAndExp(loc, ve, e); - e->type = Type::tbool; - } -#endif - *sfinally = new ExpStatement(loc, e); - } - } - } - } -} - -/******************************** CompileStatement ***************************/ - -CompileStatement::CompileStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *CompileStatement::syntaxCopy() -{ - Expression *e = exp->syntaxCopy(); - CompileStatement *es = new CompileStatement(loc, e); - return es; -} - -void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - exp->toCBuffer(buf, hgs); - buf->writestring(");"); - if (!hgs->FLinit.init) - buf->writenl(); -} - -Statements *CompileStatement::flatten(Scope *sc) -{ - //printf("CompileStatement::flatten() %s\n", exp->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->ctfeInterpret(); - if (exp->op == TOKerror) - return NULL; - StringExp *se = exp->toString(); - if (!se) - { error("argument to mixin must be a string, not (%s)", exp->toChars()); - return NULL; - } - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - - Statements *a = new Statements(); - while (p.token.value != TOKeof) - { - Statement *s = p.parseStatement(PSsemi | PScurlyscope); - if (s) // if no parsing errors - a->push(s); - } - return a; -} - -Statement *CompileStatement::semantic(Scope *sc) -{ - //printf("CompileStatement::semantic() %s\n", exp->toChars()); - Statements *a = flatten(sc); - if (!a) - return NULL; - Statement *s = new CompoundStatement(loc, a); - return s->semantic(sc); -} - - -/******************************** CompoundStatement ***************************/ - -CompoundStatement::CompoundStatement(Loc loc, Statements *s) - : Statement(loc) -{ - statements = s; -} - -CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2) - : Statement(loc) -{ - statements = new Statements(); - statements->reserve(2); - statements->push(s1); - statements->push(s2); -} - -CompoundStatement::CompoundStatement(Loc loc, Statement *s1) - : Statement(loc) -{ - statements = new Statements(); - statements->push(s1); -} - -Statement *CompoundStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - s = s->syntaxCopy(); - a->data[i] = s; - } - CompoundStatement *cs = new CompoundStatement(loc, a); - return cs; -} - - -Statement *CompoundStatement::semantic(Scope *sc) -{ Statement *s; - - //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc); - - for (size_t i = 0; i < statements->dim; ) - { - s = (*statements)[i]; - if (s) - { Statements *a = s->flatten(sc); - - if (a) - { - statements->remove(i); - statements->insert(i, a); - continue; - } - s = s->semantic(sc); - (*statements)[i] = s; - if (s) - { - Statement *sentry; - Statement *sexception; - Statement *sfinally; - - s->scopeCode(sc, &sentry, &sexception, &sfinally); - if (sentry) - { - sentry = sentry->semantic(sc); - statements->data[i] = sentry; - } - if (sexception) - sexception = sexception->semantic(sc); - if (sexception) - { - if (i + 1 == statements->dim && !sfinally) - { - } - else - { - /* Rewrite: - * s; s1; s2; - * As: - * s; - * try { s1; s2; } - * catch (Object __o) - * { sexception; throw __o; } - */ - Statements *a = new Statements(); - for (size_t j = i + 1; j < statements->dim; j++) - { - a->push((*statements)[j]); - } - Statement *body = new CompoundStatement(0, a); - body = new ScopeStatement(0, body); - - Identifier *id = Lexer::uniqueId("__o"); - - Statement *handler = sexception; - if (sexception->blockExit(FALSE) & BEfallthru) - { handler = new ThrowStatement(0, new IdentifierExp(0, id)); - handler = new CompoundStatement(0, sexception, handler); - } - - Catches *catches = new Catches(); - Catch *ctch = new Catch(0, NULL, id, handler); - catches->push(ctch); - s = new TryCatchStatement(0, body, catches); - - if (sfinally) - s = new TryFinallyStatement(0, s, sfinally); - s = s->semantic(sc); - statements->setDim(i + 1); - statements->push(s); - break; - } - } - else if (sfinally) - { - if (0 && i + 1 == statements->dim) - { - statements->push(sfinally); - } - else - { - /* Rewrite: - * s; s1; s2; - * As: - * s; try { s1; s2; } finally { sfinally; } - */ - Statements *a = new Statements(); - for (size_t j = i + 1; j < statements->dim; j++) - { - a->push((*statements)[j]); - } - Statement *body = new CompoundStatement(0, a); - s = new TryFinallyStatement(0, body, sfinally); - s = s->semantic(sc); - statements->setDim(i + 1); - statements->push(s); - break; - } - } - } - } - i++; - } - if (statements->dim == 1 && !isAsmBlockStatement()) - { - return (*statements)[0]; - } - return this; -} - -Statements *CompoundStatement::flatten(Scope *sc) -{ - return statements; -} - -ReturnStatement *CompoundStatement::isReturnStatement() -{ - ReturnStatement *rs = NULL; - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - rs = s->isReturnStatement(); - if (rs) - break; - } - } - return rs; -} - -void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - s->toCBuffer(buf, hgs); - } -} - -int CompoundStatement::usesEH() -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s && s->usesEH()) - return TRUE; - } - return FALSE; -} - -int CompoundStatement::blockExit(bool mustNotThrow) -{ - //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim); - int result = BEfallthru; - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { -//printf("result = x%x\n", result); -//printf("%s\n", s->toChars()); - if (!(result & BEfallthru) && !s->comeFrom()) - { - if (s->blockExit(mustNotThrow) != BEhalt && !s->isEmpty()) - s->warning("statement is not reachable"); - } - else - { - result &= ~BEfallthru; - result |= s->blockExit(mustNotThrow); - } - } - } - return result; -} - -int CompoundStatement::comeFrom() -{ int comefrom = FALSE; - - //printf("CompoundStatement::comeFrom()\n"); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - - if (!s) - continue; - - comefrom |= s->comeFrom(); - } - return comefrom; -} - -int CompoundStatement::isEmpty() -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s && !s->isEmpty()) - return FALSE; - } - return TRUE; -} - - -/******************************** CompoundDeclarationStatement ***************************/ - -CompoundDeclarationStatement::CompoundDeclarationStatement(Loc loc, Statements *s) - : CompoundStatement(loc, s) -{ - statements = s; -} - -Statement *CompoundDeclarationStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - s = s->syntaxCopy(); - a->data[i] = s; - } - CompoundDeclarationStatement *cs = new CompoundDeclarationStatement(loc, a); - return cs; -} - -void CompoundDeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - int nwritten = 0; - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - ExpStatement *ds; - if (s && - (ds = s->isExpStatement()) != NULL && - ds->exp->op == TOKdeclaration) - { - DeclarationExp *de = (DeclarationExp *)ds->exp; - assert(de->op == TOKdeclaration); - Declaration *d = de->declaration->isDeclaration(); - assert(d); - VarDeclaration *v = d->isVarDeclaration(); - if (v) - { - /* This essentially copies the part of VarDeclaration::toCBuffer() - * that does not print the type. - * Should refactor this. - */ - if (nwritten) - { - buf->writeByte(','); - buf->writestring(v->ident->toChars()); - } - else - { - StorageClassDeclaration::stcToCBuffer(buf, v->storage_class); - if (v->type) - v->type->toCBuffer(buf, v->ident, hgs); - else - buf->writestring(v->ident->toChars()); - } - - if (v->init) - { buf->writestring(" = "); -#if DMDV2 - ExpInitializer *ie = v->init->isExpInitializer(); - if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) - ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); - else -#endif - v->init->toCBuffer(buf, hgs); - } - } - else - d->toCBuffer(buf, hgs); - nwritten++; - } - } - buf->writeByte(';'); - if (!hgs->FLinit.init) - buf->writenl(); -} - -/**************************** UnrolledLoopStatement ***************************/ - -UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s) - : Statement(loc) -{ - statements = s; -} - -Statement *UnrolledLoopStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - s = s->syntaxCopy(); - a->data[i] = s; - } - UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); - return cs; -} - - -Statement *UnrolledLoopStatement::semantic(Scope *sc) -{ - //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); - - sc->noctor++; - Scope *scd = sc->push(); - scd->sbreak = this; - scd->scontinue = this; - - for (size_t i = 0; i < statements->dim; i++) - { - Statement *s = (*statements)[i]; - if (s) - { - //printf("[%d]: %s\n", i, s->toChars()); - s = s->semantic(scd); - statements->data[i] = s; - } - } - - scd->pop(); - sc->noctor--; - return this; -} - -void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("unrolled {"); - buf->writenl(); - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s; - - s = (*statements)[i]; - if (s) - s->toCBuffer(buf, hgs); - } - - buf->writeByte('}'); - buf->writenl(); -} - -int UnrolledLoopStatement::hasBreak() -{ - return TRUE; -} - -int UnrolledLoopStatement::hasContinue() -{ - return TRUE; -} - -int UnrolledLoopStatement::usesEH() -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s && s->usesEH()) - return TRUE; - } - return FALSE; -} - -int UnrolledLoopStatement::blockExit(bool mustNotThrow) -{ - int result = BEfallthru; - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - int r = s->blockExit(mustNotThrow); - result |= r & ~(BEbreak | BEcontinue); - } - } - return result; -} - - -int UnrolledLoopStatement::comeFrom() -{ int comefrom = FALSE; - - //printf("UnrolledLoopStatement::comeFrom()\n"); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - - if (!s) - continue; - - comefrom |= s->comeFrom(); - } - return comefrom; -} - - -/******************************** ScopeStatement ***************************/ - -ScopeStatement::ScopeStatement(Loc loc, Statement *s) - : Statement(loc) -{ - this->statement = s; -} - -Statement *ScopeStatement::syntaxCopy() -{ - Statement *s; - - s = statement ? statement->syntaxCopy() : NULL; - s = new ScopeStatement(loc, s); - return s; -} - - -Statement *ScopeStatement::semantic(Scope *sc) -{ ScopeDsymbol *sym; - - //printf("ScopeStatement::semantic(sc = %p)\n", sc); - if (statement) - { Statements *a; - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - a = statement->flatten(sc); - if (a) - { - statement = new CompoundStatement(loc, a); - } - - statement = statement->semantic(sc); - if (statement) - { - Statement *sentry; - Statement *sexception; - Statement *sfinally; - - statement->scopeCode(sc, &sentry, &sexception, &sfinally); - if (sfinally) - { - //printf("adding sfinally\n"); - sfinally = sfinally->semantic(sc); - statement = new CompoundStatement(loc, statement, sfinally); - } - } - - sc->pop(); - } - return this; -} - -int ScopeStatement::hasBreak() -{ - //printf("ScopeStatement::hasBreak() %s\n", toChars()); - return statement ? statement->hasBreak() : FALSE; -} - -int ScopeStatement::hasContinue() -{ - return statement ? statement->hasContinue() : FALSE; -} - -int ScopeStatement::usesEH() -{ - return statement ? statement->usesEH() : FALSE; -} - -int ScopeStatement::blockExit(bool mustNotThrow) -{ - //printf("ScopeStatement::blockExit(%p)\n", statement); - return statement ? statement->blockExit(mustNotThrow) : BEfallthru; -} - - -int ScopeStatement::comeFrom() -{ - //printf("ScopeStatement::comeFrom()\n"); - return statement ? statement->comeFrom() : FALSE; -} - -int ScopeStatement::isEmpty() -{ - //printf("ScopeStatement::isEmpty() %d\n", statement ? statement->isEmpty() : TRUE); - return statement ? statement->isEmpty() : TRUE; -} - -void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('{'); - buf->writenl(); - - if (statement) - statement->toCBuffer(buf, hgs); - - buf->writeByte('}'); - buf->writenl(); -} - -/******************************** WhileStatement ***************************/ - -WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b) - : Statement(loc) -{ - condition = c; - body = b; -} - -Statement *WhileStatement::syntaxCopy() -{ - WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; -} - - -Statement *WhileStatement::semantic(Scope *sc) -{ - /* Rewrite as a for(;condition;) loop - */ - - Statement *s = new ForStatement(loc, NULL, condition, NULL, body); - s = s->semantic(sc); - return s; -} - -int WhileStatement::hasBreak() -{ - return TRUE; -} - -int WhileStatement::hasContinue() -{ - return TRUE; -} - -int WhileStatement::usesEH() -{ - assert(0); - return body ? body->usesEH() : 0; -} - -int WhileStatement::blockExit(bool mustNotThrow) -{ - assert(0); - //printf("WhileStatement::blockExit(%p)\n", this); - - int result = BEnone; - if (condition->canThrow()) - result |= BEthrow; - if (condition->isBool(TRUE)) - { - if (body) - { result |= body->blockExit(mustNotThrow); - if (result & BEbreak) - result |= BEfallthru; - } - } - else if (condition->isBool(FALSE)) - { - result |= BEfallthru; - } - else - { - if (body) - result |= body->blockExit(mustNotThrow); - result |= BEfallthru; - } - result &= ~(BEbreak | BEcontinue); - return result; -} - - -int WhileStatement::comeFrom() -{ - assert(0); - if (body) - return body->comeFrom(); - return FALSE; -} - -void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("while ("); - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); -} - -/******************************** DoStatement ***************************/ - -DoStatement::DoStatement(Loc loc, Statement *b, Expression *c) - : Statement(loc) -{ - body = b; - condition = c; -} - -Statement *DoStatement::syntaxCopy() -{ - DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy()); - return s; -} - - -Statement *DoStatement::semantic(Scope *sc) -{ - sc->noctor++; - if (body) - body = body->semanticScope(sc, this, this); - sc->noctor--; - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - - condition = condition->checkToBoolean(); - - return this; -} - -int DoStatement::hasBreak() -{ - return TRUE; -} - -int DoStatement::hasContinue() -{ - return TRUE; -} - -int DoStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int DoStatement::blockExit(bool mustNotThrow) -{ int result; - - if (body) - { result = body->blockExit(mustNotThrow); - if (result == BEbreak) - return BEfallthru; - if (result & BEcontinue) - result |= BEfallthru; - } - else - result = BEfallthru; - if (result & BEfallthru) - { - if (condition->canThrow()) - result |= BEthrow; - if (!(result & BEbreak) && condition->isBool(TRUE)) - result &= ~BEfallthru; - } - result &= ~(BEbreak | BEcontinue); - return result; -} - - -int DoStatement::comeFrom() -{ - if (body) - return body->comeFrom(); - return FALSE; -} - -void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("do"); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writestring("while ("); - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); -} - -/******************************** ForStatement ***************************/ - -ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body) - : Statement(loc) -{ - this->init = init; - this->condition = condition; - this->increment = increment; - this->body = body; -} - -Statement *ForStatement::syntaxCopy() -{ - Statement *i = NULL; - if (init) - i = init->syntaxCopy(); - Expression *c = NULL; - if (condition) - c = condition->syntaxCopy(); - Expression *inc = NULL; - if (increment) - inc = increment->syntaxCopy(); - ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy()); - return s; -} - -Statement *ForStatement::semantic(Scope *sc) -{ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - if (init) - init = init->semantic(sc); -#if 0 - if (!condition) - // Use a default value - condition = new IntegerExp(loc, 1, Type::tboolean); -#endif - sc->noctor++; - if (condition) - { - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - condition = condition->checkToBoolean(); - } - if (increment) - { increment = increment->semantic(sc); - increment = resolveProperties(sc, increment); - increment = increment->optimize(0); - } - - sc->sbreak = this; - sc->scontinue = this; - if (body) - body = body->semanticNoScope(sc); - sc->noctor--; - - sc->pop(); - return this; -} - -void ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("ForStatement::scopeCode()\n"); - //print(); - if (init) - init->scopeCode(sc, sentry, sexception, sfinally); - else - Statement::scopeCode(sc, sentry, sexception, sfinally); -} - -int ForStatement::hasBreak() -{ - //printf("ForStatement::hasBreak()\n"); - return TRUE; -} - -int ForStatement::hasContinue() -{ - return TRUE; -} - -int ForStatement::usesEH() -{ - return (init && init->usesEH()) || body->usesEH(); -} - -int ForStatement::blockExit(bool mustNotThrow) -{ int result = BEfallthru; - - if (init) - { result = init->blockExit(mustNotThrow); - if (!(result & BEfallthru)) - return result; - } - if (condition) - { if (condition->canThrow()) - result |= BEthrow; - if (condition->isBool(TRUE)) - result &= ~BEfallthru; - else if (condition->isBool(FALSE)) - return result; - } - else - result &= ~BEfallthru; // the body must do the exiting - if (body) - { int r = body->blockExit(mustNotThrow); - if (r & (BEbreak | BEgoto)) - result |= BEfallthru; - result |= r & ~(BEfallthru | BEbreak | BEcontinue); - } - if (increment && increment->canThrow()) - result |= BEthrow; - return result; -} - - -int ForStatement::comeFrom() -{ - //printf("ForStatement::comeFrom()\n"); - if (body) - { int result = body->comeFrom(); - //printf("result = %d\n", result); - return result; - } - return FALSE; -} - -void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("for ("); - if (init) - { - hgs->FLinit.init++; - init->toCBuffer(buf, hgs); - hgs->FLinit.init--; - } - else - buf->writebyte(';'); - if (condition) - { buf->writebyte(' '); - condition->toCBuffer(buf, hgs); - } - buf->writebyte(';'); - if (increment) - { buf->writebyte(' '); - increment->toCBuffer(buf, hgs); - } - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/******************************** ForeachStatement ***************************/ - -ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Parameters *arguments, - Expression *aggr, Statement *body) - : Statement(loc) -{ - this->op = op; - this->arguments = arguments; - this->aggr = aggr; - this->body = body; - - this->key = NULL; - this->value = NULL; - - this->func = NULL; - - this->cases = NULL; - this->gotos = NULL; -} - -Statement *ForeachStatement::syntaxCopy() -{ - //printf("ForeachStatement::syntaxCopy()\n"); - Parameters *args = Parameter::arraySyntaxCopy(arguments); - Expression *exp = aggr->syntaxCopy(); - ForeachStatement *s = new ForeachStatement(loc, op, args, exp, - body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *ForeachStatement::semantic(Scope *sc) -{ - //printf("ForeachStatement::semantic() %p\n", this); - ScopeDsymbol *sym; - Statement *s = this; - size_t dim = arguments->dim; - TypeAArray *taa = NULL; - - Type *tn = NULL; - Type *tnv = NULL; - - func = sc->func; - if (func->fes) - func = func->fes->func; - - aggr = aggr->semantic(sc); - aggr = resolveProperties(sc, aggr); - aggr = aggr->optimize(WANTvalue); - if (!aggr->type) - { - error("invalid foreach aggregate %s", aggr->toChars()); - return this; - } - if (aggr->type->toBasetype()->ty == Terror) - return NULL; - - inferApplyArgTypes(op, arguments, aggr, sc->module); - - /* Check for inference errors - */ - if (dim != arguments->dim) - { - //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim); - error("cannot uniquely infer foreach argument types"); - return this; - } - - Type *tab = aggr->type->toBasetype(); - - if (tab->ty == Ttuple) // don't generate new scope for tuple loops - { - if (dim < 1 || dim > 2) - { - error("only one (value) or two (key,value) arguments for tuple foreach"); - return s; - } - - TypeTuple *tuple = (TypeTuple *)tab; - Statements *statements = new Statements(); - //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); - size_t n; - TupleExp *te = NULL; - if (aggr->op == TOKtuple) // expression tuple - { te = (TupleExp *)aggr; - n = te->exps->dim; - } - else if (aggr->op == TOKtype) // type tuple - { - n = Parameter::dim(tuple->arguments); - } - else - assert(0); - for (size_t j = 0; j < n; j++) - { size_t k = (op == TOKforeach) ? j : n - 1 - j; - Expression *e; - Type *t; - if (te) - e = (*te->exps)[k]; - else - t = Parameter::getNth(tuple->arguments, k)->type; - Parameter *arg = (*arguments)[0]; - Statements *st = new Statements(); - - if (dim == 2) - { // Declare key - if (arg->storageClass & (STCout | STCref | STClazy)) - error("no storage class for key %s", arg->ident->toChars()); - arg->type = arg->type->semantic(loc, sc); - TY keyty = arg->type->ty; - if (keyty != Tint32 && keyty != Tuns32) - { - if (global.params.is64bit) - { - if (keyty != Tint64 && keyty != Tuns64) - error("foreach: key type must be int or uint, long or ulong, not %s", arg->type->toChars()); - } - else - error("foreach: key type must be int or uint, not %s", arg->type->toChars()); - } - Initializer *ie = new ExpInitializer(0, new IntegerExp(k)); - VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie); - var->storage_class |= STCconst; - DeclarationExp *de = new DeclarationExp(loc, var); - st->push(new ExpStatement(loc, de)); - arg = (*arguments)[1]; // value - } - // Declare value - if (arg->storageClass & (STCout | STCref | STClazy)) - error("no storage class for value %s", arg->ident->toChars()); - Dsymbol *var; - if (te) - { Type *tb = e->type->toBasetype(); - Dsymbol *s = NULL; - if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar) - s = ((VarExp *)e)->var; - else if (e->op == TOKtemplate) - s =((TemplateExp *)e)->td; - else if (e->op == TOKimport) - s =((ScopeExp *)e)->sds; - - if (s) - { - var = new AliasDeclaration(loc, arg->ident, s); - } - else if (e->op == TOKtype) - { - var = new AliasDeclaration(loc, arg->ident, e->type); - } - else - { - arg->type = e->type; - Initializer *ie = new ExpInitializer(0, e); - VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); - if (e->isConst() || e->op == TOKstring) - v->storage_class |= STCconst; - var = v; - } - } - else - { - var = new AliasDeclaration(loc, arg->ident, t); - } - DeclarationExp *de = new DeclarationExp(loc, var); - st->push(new ExpStatement(loc, de)); - - st->push(body->syntaxCopy()); - s = new CompoundStatement(loc, st); - s = new ScopeStatement(loc, s); - statements->push(s); - } - - s = new UnrolledLoopStatement(loc, statements); - s = s->semantic(sc); - return s; - } - - for (size_t i = 0; i < dim; i++) - { Parameter *arg = (Parameter *)arguments->data[i]; - if (!arg->type) - { - error("cannot infer type for %s", arg->ident->toChars()); - return this; - } - } - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - sc->noctor++; - - switch (tab->ty) - { - case Tarray: - case Tsarray: - if (dim < 1 || dim > 2) - { - error("only one or two arguments for array foreach"); - break; - } - - /* Look for special case of parsing char types out of char type - * array. - */ - tn = tab->nextOf()->toBasetype(); - if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) - { Parameter *arg; - - int i = (dim == 1) ? 0 : 1; // index of value - arg = (*arguments)[i]; - arg->type = arg->type->semantic(loc, sc); - tnv = arg->type->toBasetype(); - if (tnv->ty != tn->ty && - (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar)) - { - if (arg->storageClass & STCref) - error("foreach: value of UTF conversion cannot be ref"); - if (dim == 2) - { arg = (*arguments)[0]; - if (arg->storageClass & STCref) - error("foreach: key cannot be ref"); - } - goto Lapply; - } - } - - for (size_t i = 0; i < dim; i++) - { // Declare args - Parameter *arg = (*arguments)[i]; - Type *argtype = arg->type->semantic(loc, sc); - VarDeclaration *var; - - var = new VarDeclaration(loc, argtype, arg->ident, NULL); - var->storage_class |= STCforeach; - var->storage_class |= arg->storageClass & (STCin | STCout | STCref); - - if (dim == 2 && i == 0) - key = var; - else - value = var; -#if 0 - DeclarationExp *de = new DeclarationExp(loc, var); - de->semantic(sc); -#endif - } - -#if 1 - { - /* Convert to a ForStatement - * foreach (key, value; a) body => - * for (T[] tmp = a[], size_t key; key < tmp.length; ++key) - * { T value = tmp[k]; body } - * - * foreach_reverse (key, value; a) body => - * for (T[] tmp = a[], size_t key = tmp.length; key--; ) - * { T value = tmp[k]; body } - */ - Identifier *id = Lexer::uniqueId("__aggr"); - ExpInitializer *ie = new ExpInitializer(loc, new SliceExp(loc, aggr, NULL, NULL)); - VarDeclaration *tmp = new VarDeclaration(loc, aggr->type->nextOf()->arrayOf(), id, ie); - - Expression *tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id::length); - - if (!key) - { - Identifier *idkey = Lexer::uniqueId("__key"); - key = new VarDeclaration(loc, Type::tsize_t, idkey, NULL); - } - if (op == TOKforeach_reverse) - key->init = new ExpInitializer(loc, tmp_length); - else - key->init = new ExpInitializer(loc, new IntegerExp(0)); - - Statements *cs = new Statements(); - cs->push(new ExpStatement(loc, tmp)); - cs->push(new ExpStatement(loc, key)); - Statement *forinit = new CompoundDeclarationStatement(loc, cs); - - Expression *cond; - if (op == TOKforeach_reverse) - // key-- - cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key)); - else - // key < tmp.length - cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), tmp_length); - - Expression *increment = NULL; - if (op == TOKforeach) - // key += 1 - increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); - - // T value = tmp[key]; - value->init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, key))); - Statement *ds = new ExpStatement(loc, value); - - body = new CompoundStatement(loc, ds, body); - - ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); - s = fs->semantic(sc); - break; - } -#else - if (!value->type->equals(tab->next)) - { - if (aggr->op == TOKstring) - aggr = aggr->implicitCastTo(sc, value->type->arrayOf()); - else - error("foreach: %s is not an array of %s", - tab->toChars(), value->type->toChars()); - } - - if (key) - { - if (key->type->ty != Tint32 && key->type->ty != Tuns32) - { - if (global.params.is64bit) - { - if (key->type->ty != Tint64 && key->type->ty != Tuns64) - error("foreach: key type must be int or uint, long or ulong, not %s", key->type->toChars()); - } - else - error("foreach: key type must be int or uint, not %s", key->type->toChars()); - } - - if (key->storage_class & (STCout | STCref)) - error("foreach: key cannot be out or ref"); - } - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - break; -#endif - - case Taarray: - taa = (TypeAArray *)tab; - if (dim < 1 || dim > 2) - { - error("only one or two arguments for associative array foreach"); - break; - } - if (op == TOKforeach_reverse) - { - error("no reverse iteration on associative arrays"); - } - goto Lapply; - - case Tclass: - case Tstruct: -#if DMDV2 - { /* Look for range iteration, i.e. the properties - * .empty, .next, .retreat, .head and .rear - * foreach (e; aggr) { ... } - * translates to: - * for (auto __r = aggr[]; !__r.empty; __r.next) - * { auto e = __r.head; - * ... - * } - */ - if (dim != 1) // only one argument allowed with ranges - goto Lapply; - AggregateDeclaration *ad = (tab->ty == Tclass) - ? (AggregateDeclaration *)((TypeClass *)tab)->sym - : (AggregateDeclaration *)((TypeStruct *)tab)->sym; - Identifier *idhead; - Identifier *idnext; - if (op == TOKforeach) - { idhead = Id::Fhead; - idnext = Id::Fnext; - } - else - { idhead = Id::Ftoe; - idnext = Id::Fretreat; - } - Dsymbol *shead = search_function(ad, idhead); - if (!shead) - goto Lapply; - - /* Generate a temporary __r and initialize it with the aggregate. - */ - Identifier *id = Identifier::generateId("__r"); - Expression *rinit = new SliceExp(loc, aggr, NULL, NULL); - rinit = rinit->trySemantic(sc); - if (!rinit) // if application of [] failed - rinit = aggr; - VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, rinit)); -// r->semantic(sc); -//printf("r: %s, init: %s\n", r->toChars(), r->init->toChars()); - Statement *init = new ExpStatement(loc, r); -//printf("init: %s\n", init->toChars()); - - // !__r.empty - Expression *e = new VarExp(loc, r); - e = new DotIdExp(loc, e, Id::Fempty); - Expression *condition = new NotExp(loc, e); - - // __r.next - e = new VarExp(loc, r); - Expression *increment = new DotIdExp(loc, e, idnext); - - /* Declaration statement for e: - * auto e = __r.idhead; - */ - e = new VarExp(loc, r); - Expression *einit = new DotIdExp(loc, e, idhead); -// einit = einit->semantic(sc); - Parameter *arg = (*arguments)[0]; - VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit)); - ve->storage_class |= STCforeach; - ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); - - DeclarationExp *de = new DeclarationExp(loc, ve); - - Statement *body = new CompoundStatement(loc, - new ExpStatement(loc, de), this->body); - - s = new ForStatement(loc, init, condition, increment, body); -#if 0 - printf("init: %s\n", init->toChars()); - printf("condition: %s\n", condition->toChars()); - printf("increment: %s\n", increment->toChars()); - printf("body: %s\n", body->toChars()); -#endif - s = s->semantic(sc); - break; - } -#endif - case Tdelegate: - Lapply: - { - Expression *ec; - Expression *e; - Parameter *a; - TypeDelegate* dgty; - TypeDelegate* dgty2; - TypeDelegate* fldeTy; - - Type *tret = func->type->nextOf(); - - /* Turn body into the function literal: - * int delegate(ref T arg) { body } - */ - Parameters *args = new Parameters(); - for (size_t i = 0; i < dim; i++) - { Parameter *arg = (*arguments)[i]; - StorageClass stc = STCref; - Identifier *id; - - arg->type = arg->type->semantic(loc, sc); - if (arg->storageClass & STCref) - id = arg->ident; - else - { // Make a copy of the ref argument so it isn't - // a reference. - - id = Lexer::uniqueId("__applyArg", i); - Initializer *ie = new ExpInitializer(0, new IdentifierExp(0, id)); - VarDeclaration *v = new VarDeclaration(0, arg->type, arg->ident, ie); - s = new ExpStatement(0, v); - body = new CompoundStatement(loc, s, body); - } - a = new Parameter(STCref, arg->type, id, NULL); - args->push(a); - } - Type *t = new TypeFunction(args, Type::tint32, 0, LINKd); - cases = new Statements(); - gotos = new CompoundStatements(); - FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this); - fld->fbody = body; - Expression *flde = new FuncExp(loc, fld); - flde = flde->semantic(sc); - - // Resolve any forward referenced goto's - for (size_t i = 0; i < gotos->dim; i++) - { CompoundStatement *cs = (*gotos)[i]; - GotoStatement *gs = (GotoStatement *)(*cs->statements)[0]; - - if (!gs->label->statement) - { // 'Promote' it to this scope, and replace with a return - cases->push(gs); - s = new ReturnStatement(0, new IntegerExp(cases->dim + 1)); - (*cs->statements)[0] = s; - } - } - - if (taa) - { - // Check types - Parameter *arg = (*arguments)[0]; - if (dim == 2) - { - if (arg->storageClass & STCref) - error("foreach: index cannot be ref"); - if (!arg->type->equals(taa->index)) - error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars()); - arg = (*arguments)[1]; - } - if (!arg->type->equals(taa->nextOf())) - error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars()); - - /* Call: - * _aaApply(aggr, keysize, flde) - */ - //LDC: Build arguments. - static FuncDeclaration *aaApply2_fd = NULL; - static TypeDelegate* aaApply2_dg; - if(!aaApply2_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->pointerTo(), NULL, NULL)); - args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); - Parameters* dgargs = new Parameters; - dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - aaApply2_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tint32, 0, LINKd)); - args->push(new Parameter(STCin, aaApply2_dg, NULL, NULL)); - aaApply2_fd = FuncDeclaration::genCfunc(args, Type::tint32, "_aaApply2"); - } - static FuncDeclaration *aaApply_fd = NULL; - static TypeDelegate* aaApply_dg; - if(!aaApply_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->pointerTo(), NULL, NULL)); // FIXME: Real parameter type is AA. - args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); - Parameters* dgargs = new Parameters; - dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - aaApply_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tint32, 0, LINKd)); - args->push(new Parameter(STCin, aaApply_dg, NULL, NULL)); - aaApply_fd = FuncDeclaration::genCfunc(args, Type::tint32, "_aaApply"); - } - FuncDeclaration *fdapply; - if (dim == 2) { - fdapply = aaApply2_fd; - fldeTy = aaApply2_dg; - } else { - fdapply = aaApply_fd; - fldeTy = aaApply_dg; - } - ec = new VarExp(0, fdapply); - Expressions *exps = new Expressions(); - exps->push(aggr); - size_t keysize = taa->key->size(); - if (global.params.is64bit) - keysize = (keysize + 15) & ~15; - else - keysize = (keysize + PTRSIZE - 1) & ~(PTRSIZE - 1); - exps->push(new IntegerExp(0, keysize, Type::tsize_t)); - - // LDC paint delegate argument to the type runtime expects - if (!fldeTy->equals(flde->type)) - { - flde = new CastExp(loc, flde, flde->type); - flde->type = fldeTy; - } - exps->push(flde); - e = new CallExp(loc, ec, exps); - e->type = Type::tint32; // don't run semantic() on e - } - else if (tab->ty == Tarray || tab->ty == Tsarray) - { - /* Call: - * _aApply(aggr, flde) - */ - static char fntab[9][3] = - { "cc","cw","cd", - "wc","cc","wd", - "dc","dw","dd" - }; - char fdname[7+1+2+ sizeof(dim)*3 + 1]; - int flag; - - switch (tn->ty) - { - case Tchar: flag = 0; break; - case Twchar: flag = 3; break; - case Tdchar: flag = 6; break; - default: assert(0); - } - switch (tnv->ty) - { - case Tchar: flag += 0; break; - case Twchar: flag += 1; break; - case Tdchar: flag += 2; break; - default: assert(0); - } - const char *r = (op == TOKforeach_reverse) ? "R" : ""; -#ifdef __MINGW32__ - int j = sprintf(fdname, "_aApply%s%.*s%lu", r, 2, fntab[flag], dim); -#else - int j = sprintf(fdname, "_aApply%s%.*s%zu", r, 2, fntab[flag], dim); -#endif - assert(j < sizeof(fdname)); - //LDC: Build arguments. - FuncDeclaration *fdapply; - Parameters* args = new Parameters; - args->push(new Parameter(STCin, tn->arrayOf(), NULL, NULL)); - if (dim == 2) { - Parameters* dgargs = new Parameters; - dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tint32, 0, LINKd)); - args->push(new Parameter(STCin, dgty, NULL, NULL)); - fdapply = FuncDeclaration::genCfunc(args, Type::tint32, fdname); - } else { - Parameters* dgargs = new Parameters; - dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tint32, 0, LINKd)); - args->push(new Parameter(STCin, dgty, NULL, NULL)); - fdapply = FuncDeclaration::genCfunc(args, Type::tint32, fdname); - } - - ec = new VarExp(0, fdapply); - Expressions *exps = new Expressions(); - if (tab->ty == Tsarray) - aggr = aggr->castTo(sc, tn->arrayOf()); - exps->push(aggr); - - // LDC paint delegate argument to the type runtime expects - if (!dgty->equals(flde->type)) - { - flde = new CastExp(loc, flde, flde->type); - flde->type = dgty; - } - exps->push(flde); - e = new CallExp(loc, ec, exps); - e->type = Type::tint32; // don't run semantic() on e - } - else if (tab->ty == Tdelegate) - { - /* Call: - * aggr(flde) - */ - Expressions *exps = new Expressions(); - exps->push(flde); - if (aggr->op == TOKdelegate && - ((DelegateExp *)aggr)->func->isNested()) - // See Bugzilla 3560 - e = new CallExp(loc, ((DelegateExp *)aggr)->e1, exps); - else - e = new CallExp(loc, aggr, exps); - e = e->semantic(sc); - if (e->type != Type::tint32) - error("opApply() function for %s must return an int", tab->toChars()); - } - else - { - /* Call: - * aggr.apply(flde) - */ - ec = new DotIdExp(loc, aggr, - (op == TOKforeach_reverse) ? Id::applyReverse - : Id::apply); - Expressions *exps = new Expressions(); - exps->push(flde); - e = new CallExp(loc, ec, exps); - e = e->semantic(sc); - if (e->type != Type::tint32) - error("opApply() function for %s must return an int", tab->toChars()); - } - - if (!cases->dim) - // Easy case, a clean exit from the loop - s = new ExpStatement(loc, e); - else - { // Construct a switch statement around the return value - // of the apply function. - Statements *a = new Statements(); - - // default: break; takes care of cases 0 and 1 - s = new BreakStatement(0, NULL); - s = new DefaultStatement(0, s); - a->push(s); - - // cases 2... - for (size_t i = 0; i < cases->dim; i++) - { - s = (*cases)[i]; - s = new CaseStatement(0, new IntegerExp(i + 2), s); - a->push(s); - } - - s = new CompoundStatement(loc, a); - s = new SwitchStatement(loc, e, s); - s = s->semantic(sc); - } - break; - } - case Terror: - s = NULL; - break; - - default: - error("foreach: %s is not an aggregate type", aggr->type->toChars()); - s = NULL; // error recovery - break; - } - sc->noctor--; - sc->pop(); - return s; -} - -int ForeachStatement::hasBreak() -{ - return TRUE; -} - -int ForeachStatement::hasContinue() -{ - return TRUE; -} - -int ForeachStatement::usesEH() -{ - return body->usesEH(); -} - -int ForeachStatement::blockExit(bool mustNotThrow) -{ int result = BEfallthru; - - if (aggr->canThrow()) - result |= BEthrow; - - if (body) - { - result |= body->blockExit(mustNotThrow) & ~(BEbreak | BEcontinue); - } - return result; -} - - -int ForeachStatement::comeFrom() -{ - if (body) - return body->comeFrom(); - return FALSE; -} - -void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - buf->writestring(" ("); - for (size_t i = 0; i < arguments->dim; i++) - { - Parameter *a = (*arguments)[i]; - if (i) - buf->writestring(", "); - if (a->storageClass & STCref) - buf->writestring((global.params.Dversion == 1) - ? (char*)"inout " : (char*)"ref "); - if (a->type) - a->type->toCBuffer(buf, a->ident, hgs); - else - buf->writestring(a->ident->toChars()); - } - buf->writestring("; "); - aggr->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/**************************** ForeachRangeStatement ***************************/ - -#if DMDV2 - -ForeachRangeStatement::ForeachRangeStatement(Loc loc, enum TOK op, Parameter *arg, - Expression *lwr, Expression *upr, Statement *body) - : Statement(loc) -{ - this->op = op; - this->arg = arg; - this->lwr = lwr; - this->upr = upr; - this->body = body; - - this->key = NULL; -} - -Statement *ForeachRangeStatement::syntaxCopy() -{ - ForeachRangeStatement *s = new ForeachRangeStatement(loc, op, - arg->syntaxCopy(), - lwr->syntaxCopy(), - upr->syntaxCopy(), - body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *ForeachRangeStatement::semantic(Scope *sc) -{ - //printf("ForeachRangeStatement::semantic() %p\n", this); - Statement *s = this; - - lwr = lwr->semantic(sc); - lwr = resolveProperties(sc, lwr); - lwr = lwr->optimize(WANTvalue); - if (!lwr->type) - { - error("invalid range lower bound %s", lwr->toChars()); - return this; - } - - upr = upr->semantic(sc); - upr = resolveProperties(sc, upr); - upr = upr->optimize(WANTvalue); - if (!upr->type) - { - error("invalid range upper bound %s", upr->toChars()); - return this; - } - - if (arg->type) - { - arg->type = arg->type->semantic(loc, sc); - lwr = lwr->implicitCastTo(sc, arg->type); - upr = upr->implicitCastTo(sc, arg->type); - } - else - { - /* Must infer types from lwr and upr - */ - AddExp ea(loc, lwr, upr); - Expression *e = ea.typeCombine(sc); - if (e->op == TOKerror) - return this; - arg->type = ea.type->mutableOf(); - lwr = ea.e1; - upr = ea.e2; - } -#if 1 - /* Convert to a for loop: - * foreach (key; lwr .. upr) => - * for (auto key = lwr, auto tmp = upr; key < tmp; ++key) - * - * foreach_reverse (key; lwr .. upr) => - * for (auto tmp = lwr, auto key = upr; key-- > tmp;) - */ - - ExpInitializer *ie = new ExpInitializer(loc, (op == TOKforeach) ? lwr : upr); - key = new VarDeclaration(loc, arg->type, arg->ident, ie); - - Identifier *id = Lexer::uniqueId("__limit"); - ie = new ExpInitializer(loc, (op == TOKforeach) ? upr : lwr); - VarDeclaration *tmp = new VarDeclaration(loc, arg->type, id, ie); - - Statements *cs = new Statements(); - // Keep order of evaluation as lwr, then upr - if (op == TOKforeach) - { - cs->push(new ExpStatement(loc, key)); - cs->push(new ExpStatement(loc, tmp)); - } - else - { - cs->push(new ExpStatement(loc, tmp)); - cs->push(new ExpStatement(loc, key)); - } - Statement *forinit = new CompoundDeclarationStatement(loc, cs); - - Expression *cond; - if (op == TOKforeach_reverse) - { // key-- > tmp - cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key)); - cond = new CmpExp(TOKgt, loc, cond, new VarExp(loc, tmp)); - } - else - // key < tmp - cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), new VarExp(loc, tmp)); - - Expression *increment = NULL; - if (op == TOKforeach) - // key += 1 - increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); - - ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); - s = fs->semantic(sc); - return s; -#else - if (!arg->type->isscalar()) - error("%s is not a scalar type", arg->type->toChars()); - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - sc->noctor++; - - key = new VarDeclaration(loc, arg->type, arg->ident, NULL); - DeclarationExp *de = new DeclarationExp(loc, key); - de->semantic(sc); - - if (key->storage_class) - error("foreach range: key cannot have storage class"); - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - - sc->noctor--; - sc->pop(); - return s; -#endif -} - -int ForeachRangeStatement::hasBreak() -{ - return TRUE; -} - -int ForeachRangeStatement::hasContinue() -{ - return TRUE; -} - -int ForeachRangeStatement::usesEH() -{ - assert(0); - return body->usesEH(); -} - -int ForeachRangeStatement::blockExit(bool mustNotThrow) -{ - assert(0); - int result = BEfallthru; - - if (lwr && lwr->canThrow()) - result |= BEthrow; - else if (upr && upr->canThrow()) - result |= BEthrow; - - if (body) - { - result |= body->blockExit(mustNotThrow) & ~(BEbreak | BEcontinue); - } - return result; -} - - -int ForeachRangeStatement::comeFrom() -{ - assert(0); - if (body) - return body->comeFrom(); - return FALSE; -} - -void ForeachRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - buf->writestring(" ("); - - if (arg->type) - arg->type->toCBuffer(buf, arg->ident, hgs); - else - buf->writestring(arg->ident->toChars()); - - buf->writestring("; "); - lwr->toCBuffer(buf, hgs); - buf->writestring(" .. "); - upr->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -#endif - -/******************************** IfStatement ***************************/ - -IfStatement::IfStatement(Loc loc, Parameter *arg, Expression *condition, Statement *ifbody, Statement *elsebody) - : Statement(loc) -{ - this->arg = arg; - this->condition = condition; - this->ifbody = ifbody; - this->elsebody = elsebody; - this->match = NULL; -} - -Statement *IfStatement::syntaxCopy() -{ - Statement *i = NULL; - if (ifbody) - i = ifbody->syntaxCopy(); - - Statement *e = NULL; - if (elsebody) - e = elsebody->syntaxCopy(); - - Parameter *a = arg ? arg->syntaxCopy() : NULL; - IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e); - return s; -} - -Statement *IfStatement::semantic(Scope *sc) -{ - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->checkToBoolean(); - - // If we can short-circuit evaluate the if statement, don't do the - // semantic analysis of the skipped code. - // This feature allows a limited form of conditional compilation. - condition = condition->optimize(WANTflags); - - // Evaluate at runtime - unsigned cs0 = sc->callSuper; - unsigned cs1; - - Scope *scd; - if (arg) - { /* Declare arg, which we will set to be the - * result of condition. - */ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - scd = sc->push(sym); - - Type *t = arg->type ? arg->type : condition->type; - match = new VarDeclaration(loc, t, arg->ident, NULL); - match->noscope = 1; - match->semantic(scd); - if (!scd->insert(match)) - assert(0); - match->parent = sc->func; - - /* Generate: - * (arg = condition) - */ - VarExp *v = new VarExp(0, match); - condition = new AssignExp(loc, v, condition); - condition = condition->semantic(scd); - } - else - scd = sc->push(); - ifbody = ifbody->semanticNoScope(scd); - scd->pop(); - - cs1 = sc->callSuper; - sc->callSuper = cs0; - if (elsebody) - elsebody = elsebody->semanticScope(sc, NULL, NULL); - sc->mergeCallSuper(loc, cs1); - - return this; -} - -int IfStatement::usesEH() -{ - return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); -} - -int IfStatement::blockExit(bool mustNotThrow) -{ - //printf("IfStatement::blockExit(%p)\n", this); - - int result = BEnone; - if (condition->canThrow()) - result |= BEthrow; - if (condition->isBool(TRUE)) - { - if (ifbody) - result |= ifbody->blockExit(mustNotThrow); - else - result |= BEfallthru; - } - else if (condition->isBool(FALSE)) - { - if (elsebody) - result |= elsebody->blockExit(mustNotThrow); - else - result |= BEfallthru; - } - else - { - if (ifbody) - result |= ifbody->blockExit(mustNotThrow); - else - result |= BEfallthru; - if (elsebody) - result |= elsebody->blockExit(mustNotThrow); - else - result |= BEfallthru; - } - //printf("IfStatement::blockExit(%p) = x%x\n", this, result); - return result; -} - - -void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("if ("); - if (arg) - { - if (arg->type) - arg->type->toCBuffer(buf, arg->ident, hgs); - else - { buf->writestring("auto "); - buf->writestring(arg->ident->toChars()); - } - buf->writestring(" = "); - } - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - ifbody->toCBuffer(buf, hgs); - if (elsebody) - { buf->writestring("else"); - buf->writenl(); - elsebody->toCBuffer(buf, hgs); - } -} - -/******************************** ConditionalStatement ***************************/ - -ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody) - : Statement(loc) -{ - this->condition = condition; - this->ifbody = ifbody; - this->elsebody = elsebody; -} - -Statement *ConditionalStatement::syntaxCopy() -{ - Statement *e = NULL; - if (elsebody) - e = elsebody->syntaxCopy(); - ConditionalStatement *s = new ConditionalStatement(loc, - condition->syntaxCopy(), ifbody->syntaxCopy(), e); - return s; -} - -Statement *ConditionalStatement::semantic(Scope *sc) -{ - //printf("ConditionalStatement::semantic()\n"); - - // If we can short-circuit evaluate the if statement, don't do the - // semantic analysis of the skipped code. - // This feature allows a limited form of conditional compilation. - if (condition->include(sc, NULL)) - { - ifbody = ifbody->semantic(sc); - return ifbody; - } - else - { - if (elsebody) - elsebody = elsebody->semantic(sc); - return elsebody; - } -} - -Statements *ConditionalStatement::flatten(Scope *sc) -{ - Statement *s; - - if (condition->include(sc, NULL)) - s = ifbody; - else - s = elsebody; - - Statements *a = new Statements(); - a->push(s); - return a; -} - -int ConditionalStatement::usesEH() -{ - return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); -} - -int ConditionalStatement::blockExit(bool mustNotThrow) -{ - int result = ifbody->blockExit(mustNotThrow); - if (elsebody) - result |= elsebody->blockExit(mustNotThrow); - return result; -} - -void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - condition->toCBuffer(buf, hgs); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - if (ifbody) - ifbody->toCBuffer(buf, hgs); - buf->writeByte('}'); - buf->writenl(); - if (elsebody) - { - buf->writestring("else"); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - elsebody->toCBuffer(buf, hgs); - buf->writeByte('}'); - buf->writenl(); - } - buf->writenl(); -} - - -/******************************** PragmaStatement ***************************/ - -PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body) - : Statement(loc) -{ - this->ident = ident; - this->args = args; - this->body = body; -} - -Statement *PragmaStatement::syntaxCopy() -{ - Statement *b = NULL; - if (body) - b = body->syntaxCopy(); - PragmaStatement *s = new PragmaStatement(loc, - ident, Expression::arraySyntaxCopy(args), b); - return s; -} - -Statement *PragmaStatement::semantic(Scope *sc) -{ // Should be merged with PragmaDeclaration - //printf("PragmaStatement::semantic() %s\n", toChars()); - //printf("body = %p\n", body); - if (ident == Id::msg) - { - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (*args)[i]; - - e = e->semantic(sc); - if (e->op != TOKerror && e->op != TOKtype) - e = e->ctfeInterpret(); - StringExp *se = e->toString(); - if (se) - { - fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); - } - else - fprintf(stdmsg, "%s", e->toChars()); - } - fprintf(stdmsg, "\n"); - } - } - else if (ident == Id::lib) - { -#if 1 - /* Should this be allowed? - */ - error("pragma(lib) not allowed as statement"); -#else - if (!args || args->dim != 1) - error("string expected for library name"); - else - { - Expression *e = (*args)[0]; - - e = e->semantic(sc); - e = e->ctfeInterpret(); - (*args)[0] = e; - StringExp *se = e->toString(); - if (!se) - error("string expected for library name, not '%s'", e->toChars()); - else if (global.params.verbose) - { - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - printf("library %s\n", name); - mem.free(name); - } - } -#endif - } - - // LDC - else if (ident == Id::allow_inline) - { - sc->func->allowInlining = true; - } -#if DMDV2 - else if (ident == Id::startaddress) - { - if (!args || args->dim != 1) - error("function name expected for start address"); - else - { - Expression *e = (*args)[0]; - e = e->semantic(sc); - e = e->ctfeInterpret(); - (*args)[0] = e; - Dsymbol *sa = getDsymbol(e); - if (!sa || !sa->isFuncDeclaration()) - error("function name expected for start address, not '%s'", e->toChars()); - if (body) - { - body = body->semantic(sc); - } - return this; - } - } -#endif - else - error("unrecognized pragma(%s)", ident->toChars()); - - if (body) - { - body = body->semantic(sc); - } - return body; -} - -int PragmaStatement::usesEH() -{ - return body && body->usesEH(); -} - -int PragmaStatement::blockExit(bool mustNotThrow) -{ - int result = BEfallthru; -#if 0 // currently, no code is generated for Pragma's, so it's just fallthru - if (arrayExpressionCanThrow(args)) - result |= BEthrow; - if (body) - result |= body->blockExit(mustNotThrow); -#endif - return result; -} - - -void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("pragma ("); - buf->writestring(ident->toChars()); - if (args && args->dim) - { - buf->writestring(", "); - argsToCBuffer(buf, args, hgs); - } - buf->writeByte(')'); - if (body) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - - body->toCBuffer(buf, hgs); - - buf->writeByte('}'); - buf->writenl(); - } - else - { - buf->writeByte(';'); - buf->writenl(); - } -} - - -/******************************** StaticAssertStatement ***************************/ - -StaticAssertStatement::StaticAssertStatement(StaticAssert *sa) - : Statement(sa->loc) -{ - this->sa = sa; -} - -Statement *StaticAssertStatement::syntaxCopy() -{ - StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL)); - return s; -} - -Statement *StaticAssertStatement::semantic(Scope *sc) -{ - sa->semantic2(sc); - return NULL; -} - -int StaticAssertStatement::blockExit(bool mustNotThrow) -{ - return BEfallthru; -} - -void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - sa->toCBuffer(buf, hgs); -} - - -/******************************** SwitchStatement ***************************/ - -SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b) - : Statement(loc) -{ - condition = c; - body = b; - sdefault = NULL; - cases = NULL; - hasNoDefault = 0; - // LDC - enclosingScopeExit = NULL; -} - -Statement *SwitchStatement::syntaxCopy() -{ - SwitchStatement *s = new SwitchStatement(loc, - condition->syntaxCopy(), body->syntaxCopy()); - return s; -} - -Statement *SwitchStatement::semantic(Scope *sc) -{ - //printf("SwitchStatement::semantic(%p)\n", this); - assert(!cases); // ensure semantic() is only run once - - // LDC - enclosingScopeExit = sc->enclosingScopeExit; - - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - if (condition->type->isString()) - { - // If it's not an array, cast it to one - if (condition->type->ty != Tarray) - { - condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf()); - } - } - else - { condition = condition->integralPromotions(sc); - condition->checkIntegral(); - } - condition = condition->optimize(WANTvalue); - - sc = sc->push(); - sc->sbreak = this; - sc->sw = this; - - cases = new CaseStatements(); - sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead - body = body->semantic(sc); - sc->noctor--; - - // Resolve any goto case's with exp - for (size_t i = 0; i < gotoCases.dim; i++) - { - GotoCaseStatement *gcs = gotoCases[i]; - - if (!gcs->exp) - { - gcs->error("no case statement following goto case;"); - break; - } - - for (Scope *scx = sc; scx; scx = scx->enclosing) - { - if (!scx->sw) - continue; - for (size_t j = 0; j < scx->sw->cases->dim; j++) - { - CaseStatement *cs = (*scx->sw->cases)[j]; - - if (cs->exp->equals(gcs->exp)) - { - gcs->cs = cs; - goto Lfoundcase; - } - } - } - gcs->error("case %s not found", gcs->exp->toChars()); - - Lfoundcase: - ; - } - - if (!sc->sw->sdefault) - { hasNoDefault = 1; - - warning("switch statement has no default"); - - // Generate runtime error if the default is hit - Statements *a = new Statements(); - CompoundStatement *cs; - Statement *s; - - if (global.params.useSwitchError) - s = new SwitchErrorStatement(loc); - else - { Expression *e = new HaltExp(loc); - s = new ExpStatement(loc, e); - } - - a->reserve(4); - a->push(body); - - // LDC needs semantic to be run on break - Statement *breakstmt = new BreakStatement(loc, NULL); - breakstmt->semantic(sc); - a->push(breakstmt); - - sc->sw->sdefault = new DefaultStatement(loc, s); - a->push(sc->sw->sdefault); - cs = new CompoundStatement(loc, a); - body = cs; - } - -#if DMDV2 - if (isFinal) - { Type *t = condition->type; - while (t->ty == Ttypedef) - { // Don't use toBasetype() because that will skip past enums - t = ((TypeTypedef *)t)->sym->basetype; - } - if (condition->type->ty == Tenum) - { TypeEnum *te = (TypeEnum *)condition->type; - EnumDeclaration *ed = te->toDsymbol(sc)->isEnumDeclaration(); - assert(ed); - size_t dim = ed->members->dim; - for (size_t i = 0; i < dim; i++) - { - EnumMember *em = (*ed->members)[i]->isEnumMember(); - if (em) - { - for (size_t j = 0; j < cases->dim; j++) - { CaseStatement *cs = (*cases)[j]; - if (cs->exp->equals(em->value)) - goto L1; - } - error("enum member %s not represented in final switch", em->toChars()); - } - L1: - ; - } - } - } -#endif - - sc->pop(); - return this; -} - -int SwitchStatement::hasBreak() -{ - return TRUE; -} - -int SwitchStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int SwitchStatement::blockExit(bool mustNotThrow) -{ int result = BEnone; - if (condition->canThrow()) - result |= BEthrow; - - if (body) - { result |= body->blockExit(mustNotThrow); - if (result & BEbreak) - { result |= BEfallthru; - result &= ~BEbreak; - } - } - else - result |= BEfallthru; - - return result; -} - - -void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("switch ("); - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - if (body) - { - if (!body->isScopeStatement()) - { buf->writebyte('{'); - buf->writenl(); - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); - } - else - { - body->toCBuffer(buf, hgs); - } - } -} - -/******************************** CaseStatement ***************************/ - -CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s) - : Statement(loc) -{ - this->exp = exp; - this->statement = s; - cblock = NULL; - bodyBB = NULL; - llvmIdx = NULL; - // LDC - enclosingScopeExit = NULL; -} - -Statement *CaseStatement::syntaxCopy() -{ - CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy()); - return s; -} - -Statement *CaseStatement::semantic(Scope *sc) -{ SwitchStatement *sw = sc->sw; - - //printf("CaseStatement::semantic() %s\n", toChars()); - exp = exp->semantic(sc); - if (sw) - { - // LDC - enclosingScopeExit = sc->enclosingScopeExit; - if (enclosingScopeExit != sw->enclosingScopeExit) - { - error("case must be inside the same try, synchronized or volatile level as switch"); - } - - exp = exp->implicitCastTo(sc, sw->condition->type); - exp = exp->ctfeInterpret(); - if (exp->op != TOKstring && exp->op != TOKint64 && exp->op != TOKerror) - { - error("case must be a string or an integral constant, not %s", exp->toChars()); - exp = new IntegerExp(0); - } - - for (size_t i = 0; i < sw->cases->dim; i++) - { - CaseStatement *cs = (*sw->cases)[i]; - - //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars()); - if (cs->exp->equals(exp)) - { error("duplicate case %s in switch statement", exp->toChars()); - break; - } - } - - sw->cases->push(this); - - // Resolve any goto case's with no exp to this case statement - for (size_t i = 0; i < sw->gotoCases.dim; i++) - { - GotoCaseStatement *gcs = sw->gotoCases[i]; - - if (!gcs->exp) - { - gcs->cs = this; - sw->gotoCases.remove(i); // remove from array - } - } - } - else - error("case not in switch statement"); - statement = statement->semantic(sc); - return this; -} - -int CaseStatement::compare(Object *obj) -{ - // Sort cases so we can do an efficient lookup - CaseStatement *cs2 = (CaseStatement *)(obj); - - return exp->compare(cs2->exp); -} - -int CaseStatement::usesEH() -{ - return statement->usesEH(); -} - -int CaseStatement::blockExit(bool mustNotThrow) -{ - return statement->blockExit(mustNotThrow); -} - - -int CaseStatement::comeFrom() -{ - return TRUE; -} - -void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("case "); - exp->toCBuffer(buf, hgs); - buf->writebyte(':'); - buf->writenl(); - statement->toCBuffer(buf, hgs); -} - -/******************************** CaseRangeStatement ***************************/ - -#if DMDV2 - -CaseRangeStatement::CaseRangeStatement(Loc loc, Expression *first, - Expression *last, Statement *s) - : Statement(loc) -{ - this->first = first; - this->last = last; - this->statement = s; -} - -Statement *CaseRangeStatement::syntaxCopy() -{ - CaseRangeStatement *s = new CaseRangeStatement(loc, - first->syntaxCopy(), last->syntaxCopy(), statement->syntaxCopy()); - return s; -} - -Statement *CaseRangeStatement::semantic(Scope *sc) -{ SwitchStatement *sw = sc->sw; - - //printf("CaseRangeStatement::semantic() %s\n", toChars()); - if (sw->isFinal) - error("case ranges not allowed in final switch"); - - first = first->semantic(sc); - first = first->implicitCastTo(sc, sw->condition->type); - first = first->ctfeInterpret(); - - last = last->semantic(sc); - last = last->implicitCastTo(sc, sw->condition->type); - last = last->ctfeInterpret(); - - if (first->op == TOKerror || last->op == TOKerror) - return statement ? statement->semantic(sc) : NULL; - - dinteger_t fval = first->toInteger(); - dinteger_t lval = last->toInteger(); - - if (lval - fval > 256) - { error("more than 256 cases in case range"); - lval = fval + 256; - } - - /* This works by replacing the CaseRange with an array of Case's. - * - * case a: .. case b: s; - * => - * case a: - * [...] - * case b: - * s; - */ - - Statements *statements = new Statements(); - for (dinteger_t i = fval; i <= lval; i++) - { - Statement *s = statement; - if (i != lval) - s = new ExpStatement(loc, NULL); - Expression *e = new IntegerExp(loc, i, first->type); - Statement *cs = new CaseStatement(loc, e, s); - statements->push(cs); - } - Statement *s = new CompoundStatement(loc, statements); - s = s->semantic(sc); - return s; -} - -void CaseRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("case "); - first->toCBuffer(buf, hgs); - buf->writestring(": .. case "); - last->toCBuffer(buf, hgs); - buf->writenl(); - statement->toCBuffer(buf, hgs); -} - -#endif - -/******************************** DefaultStatement ***************************/ - -DefaultStatement::DefaultStatement(Loc loc, Statement *s) - : Statement(loc) -{ - this->statement = s; -#if IN_GCC -+ cblock = NULL; -#endif - bodyBB = NULL; - // LDC - enclosingScopeExit = NULL; -} - -Statement *DefaultStatement::syntaxCopy() -{ - DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy()); - return s; -} - -Statement *DefaultStatement::semantic(Scope *sc) -{ - //printf("DefaultStatement::semantic()\n"); - if (sc->sw) - { - if (sc->sw->sdefault) - { - error("switch statement already has a default"); - } - sc->sw->sdefault = this; - - // LDC - enclosingScopeExit = sc->enclosingScopeExit; - if (enclosingScopeExit != sc->sw->enclosingScopeExit) - { - error("default must be inside the same try, synchronized or volatile level as switch"); - } - } - else - error("default not in switch statement"); - statement = statement->semantic(sc); - return this; -} - -int DefaultStatement::usesEH() -{ - return statement->usesEH(); -} - -int DefaultStatement::blockExit(bool mustNotThrow) -{ - return statement->blockExit(mustNotThrow); -} - - -int DefaultStatement::comeFrom() -{ - return TRUE; -} - -void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("default:\n"); - statement->toCBuffer(buf, hgs); -} - -/******************************** GotoDefaultStatement ***************************/ - -GotoDefaultStatement::GotoDefaultStatement(Loc loc) - : Statement(loc) -{ - sw = NULL; -} - -Statement *GotoDefaultStatement::syntaxCopy() -{ - GotoDefaultStatement *s = new GotoDefaultStatement(loc); - return s; -} - -Statement *GotoDefaultStatement::semantic(Scope *sc) -{ - sw = sc->sw; - if (!sw) - error("goto default not in switch statement"); - return this; -} - -int GotoDefaultStatement::blockExit(bool mustNotThrow) -{ - return BEgoto; -} - - -void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("goto default;\n"); -} - -/******************************** GotoCaseStatement ***************************/ - -GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - cs = NULL; - this->exp = exp; - sw = NULL; -} - -Statement *GotoCaseStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - GotoCaseStatement *s = new GotoCaseStatement(loc, e); - return s; -} - -Statement *GotoCaseStatement::semantic(Scope *sc) -{ - if (exp) - exp = exp->semantic(sc); - - if (!sc->sw) - error("goto case not in switch statement"); - else - { - sw = sc->sw; - sc->sw->gotoCases.push(this); - if (exp) - { - exp = exp->implicitCastTo(sc, sc->sw->condition->type); - exp = exp->optimize(WANTvalue); - } - } - return this; -} - -int GotoCaseStatement::blockExit(bool mustNotThrow) -{ - return BEgoto; -} - - -void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("goto case"); - if (exp) - { buf->writebyte(' '); - exp->toCBuffer(buf, hgs); - } - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** SwitchErrorStatement ***************************/ - -SwitchErrorStatement::SwitchErrorStatement(Loc loc) - : Statement(loc) -{ -} - -int SwitchErrorStatement::blockExit(bool mustNotThrow) -{ - return BEthrow; -} - - -void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("SwitchErrorStatement::toCBuffer()"); - buf->writenl(); -} - -/******************************** ReturnStatement ***************************/ - -ReturnStatement::ReturnStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; - this->implicit0 = 0; -} - -Statement *ReturnStatement::syntaxCopy() -{ - Expression *e = NULL; - if (exp) - e = exp->syntaxCopy(); - ReturnStatement *s = new ReturnStatement(loc, e); - return s; -} - -Statement *ReturnStatement::semantic(Scope *sc) -{ - //printf("ReturnStatement::semantic() %s\n", toChars()); - - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - Scope *scx = sc; - Expression *eorg = NULL; - - if (fd->fes) - fd = fd->fes->func; // fd is now function enclosing foreach - - Type *tret = fd->type->nextOf(); - if (fd->tintro) - /* We'll be implicitly casting the return expression to tintro - */ - tret = fd->tintro->nextOf(); - Type *tbret = NULL; - - if (tret) - tbret = tret->toBasetype(); - - // main() returns 0, even if it returns void - if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain()) - { implicit0 = 1; - exp = new IntegerExp(0); - } - - if (sc->incontract || scx->incontract) - error("return statements cannot be in contracts"); - if (sc->enclosingFinally || scx->enclosingFinally) - error("return statements cannot be in finally, scope(exit) or scope(success) bodies"); - - if (fd->isCtorDeclaration()) - { - // Constructors implicitly do: - // return this; - if (exp && exp->op != TOKthis) - error("cannot return expression from constructor"); - exp = new ThisExp(0); - } - - if (!exp) - fd->nrvo_can = 0; - - if (exp) - { - fd->hasReturnExp |= 1; - - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue); - - if (fd->nrvo_can && exp->op == TOKvar) - { VarExp *ve = (VarExp *)exp; - VarDeclaration *v = ve->var->isVarDeclaration(); - - if (!v || v->isOut() || v->isRef()) - fd->nrvo_can = 0; - else if (fd->nrvo_var == NULL) - { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd) - { //printf("Setting nrvo to %s\n", v->toChars()); - fd->nrvo_var = v; - } - else - fd->nrvo_can = 0; - } - else if (fd->nrvo_var != v) - fd->nrvo_can = 0; - } - else - fd->nrvo_can = 0; - -#if 0 - if (fd->returnLabel && tbret && tbret->ty != Tvoid) - { - } - else -#endif - if (fd->inferRetType) - { - Type *tfret = fd->type->nextOf(); - if (tfret) - { - if (tfret != Type::terror && !exp->type->equals(tfret)) - error("mismatched function return type inference of %s and %s", - exp->type->toChars(), tfret->toChars()); - } - else - { - fd->type->next = exp->type; - fd->type = fd->type->semantic(loc, sc); - if (!fd->tintro) - { tret = fd->type->nextOf(); - tbret = tret->toBasetype(); - } - } - if (fd->returnLabel) - eorg = exp; - } - else if (tbret->ty != Tvoid) - { - if (fd->tintro) - exp = exp->implicitCastTo(sc, fd->type->nextOf()); - - // eorg isn't casted to tret (== fd->tintro->nextOf()) - if (fd->returnLabel) - eorg = exp->copy(); - exp = exp->implicitCastTo(sc, tret); - } - } - else if (fd->inferRetType) - { - if (fd->type->nextOf()) - { - if (fd->type->nextOf()->ty != Tvoid) - error("mismatched function return type inference of void and %s", - fd->type->nextOf()->toChars()); - } - else - { - fd->type->next = Type::tvoid; - //fd->type = fd->type->semantic(loc, sc); - if (!fd->tintro) - { tret = Type::tvoid; - tbret = tret; - } - } - } - else if (tbret->ty != Tvoid) // if non-void return - error("return expression expected"); - - if (sc->fes) - { - Statement *s; - - if (exp && !implicit0) - { - exp = exp->implicitCastTo(sc, tret); - } - if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 || - exp->op == TOKimaginary80 || exp->op == TOKcomplex80 || - exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull || - exp->op == TOKstring) - { - sc->fes->cases->push(this); - // Construct: return cases->dim+1; - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - } - else if (fd->type->nextOf()->toBasetype() == Type::tvoid) - { - s = new ReturnStatement(0, NULL); - sc->fes->cases->push(s); - - // Construct: { exp; return cases->dim + 1; } - Statement *s1 = new ExpStatement(loc, exp); - Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - else - { - // Construct: return vresult; - if (!fd->vresult) - { // Declare vresult - Scope *sco = fd->scout ? fd->scout : scx; - VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noscope = 1; - v->semantic(sco); - if (!sco->insert(v)) - assert(0); - v->parent = fd; - fd->vresult = v; - } - - s = new ReturnStatement(0, new VarExp(0, fd->vresult)); - sc->fes->cases->push(s); - - // Construct: { vresult = exp; return cases->dim + 1; } - exp = new ConstructExp(loc, new VarExp(0, fd->vresult), exp); - exp = exp->semantic(sc); - Statement *s1 = new ExpStatement(loc, exp); - Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - return s; - } - - if (exp) - { - if (fd->returnLabel && tbret->ty != Tvoid) - { - fd->buildResultVar(); - VarExp *v = new VarExp(0, fd->vresult); - - assert(eorg); - exp = new AssignExp(loc, v, eorg); - exp->op = TOKconstruct; - exp = exp->semantic(sc); - } - //exp->dump(0); - //exp->print(); - exp->checkEscape(); - } - - /* BUG: need to issue an error on: - * this - * { if (x) return; - * super(); - * } - */ - - if (sc->callSuper & CSXany_ctor && - !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor))) - error("return without calling constructor"); - - sc->callSuper |= CSXreturn; - - // See if all returns are instead to be replaced with a goto returnLabel; - if (fd->returnLabel) - { - GotoStatement *gs = new GotoStatement(loc, Id::returnLabel); - - gs->label = fd->returnLabel; - if (exp) - { /* Replace: return exp; - * with: exp; goto returnLabel; - */ - Statement *s = new ExpStatement(0, exp); - return new CompoundStatement(loc, s, gs); - } - return gs; - } - - if (exp && tbret->ty == Tvoid && !implicit0) - { - /* Replace: - * return exp; - * with: - * exp; return; - */ - Statement *s = new ExpStatement(loc, exp); - exp = NULL; - s = s->semantic(sc); - return new CompoundStatement(loc, s, this); - } - - return this; -} - -int ReturnStatement::blockExit(bool mustNotThrow) -{ int result = BEreturn; - - if (exp && exp->canThrow()) - result |= BEthrow; - return result; -} - - -void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("return "); - if (exp) - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - buf->writenl(); -} - -/******************************** BreakStatement ***************************/ - -BreakStatement::BreakStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; -} - -Statement *BreakStatement::syntaxCopy() -{ - BreakStatement *s = new BreakStatement(loc, ident); - return s; -} - -Statement *BreakStatement::semantic(Scope *sc) -{ - //printf("BreakStatement::semantic()\n"); - // If: - // break Identifier; - if (ident) - { - Scope *scx; - FuncDeclaration *thisfunc = sc->func; - - for (scx = sc; scx; scx = scx->enclosing) - { - LabelStatement *ls; - - if (scx->func != thisfunc) // if in enclosing function - { - if (sc->fes) // if this is the body of a foreach - { - /* Post this statement to the fes, and replace - * it with a return value that caller will put into - * a switch. Caller will figure out where the break - * label actually is. - * Case numbers start with 2, not 0, as 0 is continue - * and 1 is break. - */ - Statement *s; - sc->fes->cases->push(this); - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - return s; - } - break; // can't break to it - } - - ls = scx->slabel; - if (ls && ls->ident == ident) - { - Statement *s = ls->statement; - - if (!s->hasBreak()) - error("label '%s' has no break", ident->toChars()); - if (ls->enclosingFinally != sc->enclosingFinally) - error("cannot break out of finally block"); - - this->target = ls; - return this; - } - } - error("enclosing label '%s' for break not found", ident->toChars()); - } - else if (!sc->sbreak) - { - if (sc->fes) - { Statement *s; - - // Replace break; with return 1; - s = new ReturnStatement(0, new IntegerExp(1)); - return s; - } - error("break is not inside a loop or switch"); - } - return this; -} - -int BreakStatement::blockExit(bool mustNotThrow) -{ - //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak); - return ident ? BEgoto : BEbreak; -} - - -void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("break"); - if (ident) - { buf->writebyte(' '); - buf->writestring(ident->toChars()); - } - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** ContinueStatement ***************************/ - -ContinueStatement::ContinueStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; -} - -Statement *ContinueStatement::syntaxCopy() -{ - ContinueStatement *s = new ContinueStatement(loc, ident); - return s; -} - -Statement *ContinueStatement::semantic(Scope *sc) -{ - //printf("ContinueStatement::semantic() %p\n", this); - if (ident) - { - Scope *scx; - FuncDeclaration *thisfunc = sc->func; - - for (scx = sc; scx; scx = scx->enclosing) - { - LabelStatement *ls; - - if (scx->func != thisfunc) // if in enclosing function - { - if (sc->fes) // if this is the body of a foreach - { - for (; scx; scx = scx->enclosing) - { - ls = scx->slabel; - if (ls && ls->ident == ident && ls->statement == sc->fes) - { - // Replace continue ident; with return 0; - return new ReturnStatement(0, new IntegerExp(0)); - } - } - - /* Post this statement to the fes, and replace - * it with a return value that caller will put into - * a switch. Caller will figure out where the break - * label actually is. - * Case numbers start with 2, not 0, as 0 is continue - * and 1 is break. - */ - Statement *s; - sc->fes->cases->push(this); - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - return s; - } - break; // can't continue to it - } - - ls = scx->slabel; - if (ls && ls->ident == ident) - { - Statement *s = ls->statement; - - if (!s->hasContinue()) - error("label '%s' has no continue", ident->toChars()); - if (ls->enclosingFinally != sc->enclosingFinally) - error("cannot continue out of finally block"); - - this->target = ls; - return this; - } - } - error("enclosing label '%s' for continue not found", ident->toChars()); - } - else if (!sc->scontinue) - { - if (sc->fes) - { Statement *s; - - // Replace continue; with return 0; - s = new ReturnStatement(0, new IntegerExp(0)); - return s; - } - error("continue is not inside a loop"); - } - return this; -} - -int ContinueStatement::blockExit(bool mustNotThrow) -{ - return ident ? BEgoto : BEcontinue; -} - - -void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("continue"); - if (ident) - { buf->writebyte(' '); - buf->writestring(ident->toChars()); - } - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** SynchronizedStatement ***************************/ - -SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body) - : Statement(loc) -{ - this->exp = exp; - this->body = body; - this->esync = NULL; - // LDC - this->llsync = NULL; -} - -SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body) - : Statement(loc) -{ - this->exp = NULL; - this->body = body; - this->esync = esync; - // LDC - this->llsync = NULL; -} - -Statement *SynchronizedStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *SynchronizedStatement::semantic(Scope *sc) -{ - if (exp) - { - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (exp->op == TOKerror) - goto Lbody; - ClassDeclaration *cd = exp->type->isClassHandle(); - if (!cd) - error("can only synchronize on class objects, not '%s'", exp->type->toChars()); - else if (cd->isInterfaceDeclaration()) - { /* Cast the interface to an object, as the object has the monitor, - * not the interface. - */ - if (!ClassDeclaration::object) - { - error("missing or corrupt object.d"); - fatal(); - } - - Type *t = ClassDeclaration::object->type; - t = t->semantic(0, sc)->toBasetype(); - assert(t->ty == Tclass); - - exp = new CastExp(loc, exp, t); - exp = exp->semantic(sc); - } - -#if 1 - /* Rewrite as: - * auto tmp = exp; - * _d_monitorenter(tmp); - * try { body } finally { _d_monitorexit(tmp); } - */ - Identifier *id = Lexer::uniqueId("__sync"); - ExpInitializer *ie = new ExpInitializer(loc, exp); - VarDeclaration *tmp = new VarDeclaration(loc, exp->type, id, ie); - - Statements *cs = new Statements(); - cs->push(new ExpStatement(loc, tmp)); - - Parameters* enterargs = new Parameters; - enterargs->push(new Parameter(STCin, ClassDeclaration::object->type, NULL, NULL)); - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(enterargs, Type::tvoid, Id::monitorenter); - Expression *e = new CallExp(loc, new VarExp(loc, fdenter), new VarExp(loc, tmp)); - e->type = Type::tvoid; // do not run semantic on e - cs->push(new ExpStatement(loc, e)); - - Parameters* exitargs = new Parameters; - exitargs->push(new Parameter(STCin, ClassDeclaration::object->type, NULL, NULL)); - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(exitargs, Type::tvoid, Id::monitorexit); - e = new CallExp(loc, new VarExp(loc, fdexit), new VarExp(loc, tmp)); - e->type = Type::tvoid; // do not run semantic on e - Statement *s = new ExpStatement(loc, e); - s = new TryFinallyStatement(loc, body, s); - cs->push(s); - - s = new CompoundStatement(loc, cs); - return s->semantic(sc); -#endif - } -#if 1 - else - { /* Generate our own critical section, then rewrite as: - * __gshared byte[CriticalSection.sizeof] critsec; - * _d_criticalenter(critsec.ptr); - * try { body } finally { _d_criticalexit(critsec.ptr); } - */ - Identifier *id = Lexer::uniqueId("__critsec"); -#if IN_DMD - Type *t = new TypeSArray(Type::tint8, new IntegerExp(PTRSIZE + (global.params.is64bit ? os_critsecsize64() : os_critsecsize32()))); -#elif IN_LLVM - Type *t = new TypeSArray(Type::tint8, new IntegerExp(PTRSIZE + os_critsecsize())); -#endif - VarDeclaration *tmp = new VarDeclaration(loc, t, id, NULL); - tmp->storage_class |= STCgshared | STCstatic; - - Statements *cs = new Statements(); - cs->push(new ExpStatement(loc, tmp)); - - Parameters* enterargs = new Parameters; - enterargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(enterargs, Type::tvoid, Id::criticalenter); - Expression *e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); - e = e->semantic(sc); - e = new CallExp(loc, new VarExp(loc, fdenter), e); - e->type = Type::tvoid; // do not run semantic on e - cs->push(new ExpStatement(loc, e)); - - Parameters* exitargs = new Parameters; - exitargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(exitargs, Type::tvoid, Id::criticalexit); - e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); - e = e->semantic(sc); - e = new CallExp(loc, new VarExp(loc, fdexit), e); - e->type = Type::tvoid; // do not run semantic on e - Statement *s = new ExpStatement(loc, e); - s = new TryFinallyStatement(loc, body, s); - cs->push(s); - - s = new CompoundStatement(loc, cs); - return s->semantic(sc); - } -#endif -Lbody: - if (body) - body = body->semantic(sc); - return this; -} - -int SynchronizedStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int SynchronizedStatement::hasContinue() -{ - return FALSE; //TRUE; -} - -int SynchronizedStatement::usesEH() -{ - return TRUE; -} - -int SynchronizedStatement::blockExit(bool mustNotThrow) -{ - return body ? body->blockExit(mustNotThrow) : BEfallthru; -} - - -void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("synchronized"); - if (exp) - { buf->writebyte('('); - exp->toCBuffer(buf, hgs); - buf->writebyte(')'); - } - if (body) - { - buf->writebyte(' '); - body->toCBuffer(buf, hgs); - } -} - -/******************************** WithStatement ***************************/ - -WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body) - : Statement(loc) -{ - this->exp = exp; - this->body = body; - wthis = NULL; -} - -Statement *WithStatement::syntaxCopy() -{ - WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *WithStatement::semantic(Scope *sc) -{ ScopeDsymbol *sym; - Initializer *init; - - //printf("WithStatement::semantic()\n"); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (exp->op == TOKerror) - return NULL; - if (exp->op == TOKimport) - { ScopeExp *es = (ScopeExp *)exp; - - sym = es->sds; - } - else if (exp->op == TOKtype) - { TypeExp *es = (TypeExp *)exp; - - Dsymbol *s = es->type->toDsymbol(sc); - sym = s ? s->isScopeDsymbol() : NULL; - if (!sym) - { error("with type %s has no members", es->toChars()); - if (body) - body = body->semantic(sc); - return this; - } - } - else - { Type *t = exp->type; - - assert(t); - t = t->toBasetype(); - if (t->isClassHandle()) - { - init = new ExpInitializer(loc, exp); - wthis = new VarDeclaration(loc, exp->type, Id::withSym, init); - wthis->semantic(sc); - - sym = new WithScopeSymbol(this); - sym->parent = sc->scopesym; - } - else if (t->ty == Tstruct) - { - Expression *e = exp->addressOf(sc); - init = new ExpInitializer(loc, e); - wthis = new VarDeclaration(loc, e->type, Id::withSym, init); - wthis->semantic(sc); - sym = new WithScopeSymbol(this); - sym->parent = sc->scopesym; - } - else - { error("with expressions must be class objects, not '%s'", exp->type->toChars()); - return NULL; - } - } - sc = sc->push(sym); - - if (body) - body = body->semantic(sc); - - sc->pop(); - - return this; -} - -void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("with ("); - exp->toCBuffer(buf, hgs); - buf->writestring(")\n"); - if (body) - body->toCBuffer(buf, hgs); -} - -int WithStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int WithStatement::blockExit(bool mustNotThrow) -{ - int result = BEnone; - if (exp->canThrow()) - result = BEthrow; - if (body) - result |= body->blockExit(mustNotThrow); - else - result |= BEfallthru; - return result; -} - - -/******************************** TryCatchStatement ***************************/ - -TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Catches *catches) - : Statement(loc) -{ - this->body = body; - this->catches = catches; -} - -Statement *TryCatchStatement::syntaxCopy() -{ - Catches *a = new Catches(); - a->setDim(catches->dim); - for (size_t i = 0; i < a->dim; i++) - { Catch *c; - - c = (*catches)[i]; - c = c->syntaxCopy(); - (*a)[i] = c; - } - TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); - return s; -} - -Statement *TryCatchStatement::semantic(Scope *sc) -{ - body = body->semanticScope(sc, NULL /*this*/, NULL); - - /* Even if body is NULL, still do semantic analysis on catches - */ - for (size_t i = 0; i < catches->dim; i++) - { Catch *c = (*catches)[i]; - c->semantic(sc); - - // Determine if current catch 'hides' any previous catches - for (size_t j = 0; j < i; j++) - { Catch *cj = (*catches)[j]; - char *si = c->loc.toChars(); - char *sj = cj->loc.toChars(); - - if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype())) - error("catch at %s hides catch at %s", sj, si); - } - } - - if (!body || body->isEmpty()) - { - return NULL; - } - return this; -} - -int TryCatchStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int TryCatchStatement::usesEH() -{ - return TRUE; -} - -int TryCatchStatement::blockExit(bool mustNotThrow) -{ - assert(body); - int result = body->blockExit(false); - - int catchresult = 0; - for (size_t i = 0; i < catches->dim; i++) - { - Catch *c =(* catches)[i]; - if (c->type == Type::terror) - continue; - - catchresult |= c->blockExit(mustNotThrow); - - /* If we're catching Object, then there is no throwing - */ - Identifier *id = c->type->toBasetype()->isClassHandle()->ident; - if (id == Id::Object) - { - result &= ~BEthrow; - } - } - if (mustNotThrow && (result & BEthrow)) - { - body->blockExit(mustNotThrow); // now explain why this is nothrow - } - return result | catchresult; -} - - -void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("try"); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - for (size_t i = 0; i < catches->dim; i++) - { - Catch *c = (*catches)[i]; - c->toCBuffer(buf, hgs); - } -} - -/******************************** Catch ***************************/ - -Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler) -{ - //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars()); - this->loc = loc; - this->type = t; - this->ident = id; - this->handler = handler; - var = NULL; -} - -Catch *Catch::syntaxCopy() -{ - Catch *c = new Catch(loc, - (type ? type->syntaxCopy() : NULL), - ident, - (handler ? handler->syntaxCopy() : NULL)); - return c; -} - -void Catch::semantic(Scope *sc) -{ - if (type && type->deco) - return; - - //printf("Catch::semantic(%s)\n", ident->toChars()); - -#ifndef IN_GCC - if (sc->enclosingFinally) - { - /* This is because the _d_local_unwind() gets the stack munged - * up on this. The workaround is to place any try-catches into - * a separate function, and call that. - * To fix, have the compiler automatically convert the finally - * body into a nested function. - */ - error(loc, "cannot put catch statement inside finally block"); - } -#endif - - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - if (!type) - type = new TypeIdentifier(0, Id::Object); - type = type->semantic(loc, sc); - if (!type->toBasetype()->isClassHandle()) - { - if (type != Type::terror) - { error(loc, "can only catch class objects, not '%s'", type->toChars()); - type = Type::terror; - } - } - else if (ident) - { - var = new VarDeclaration(loc, type, ident, NULL); - var->parent = sc->parent; - sc->insert(var); - } - handler = handler->semantic(sc); - - sc->pop(); -} - -int Catch::blockExit(bool mustNotThrow) -{ - return handler ? handler->blockExit(mustNotThrow) : BEfallthru; -} - -void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("catch"); - if (type) - { buf->writebyte('('); - type->toCBuffer(buf, ident, hgs); - buf->writebyte(')'); - } - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (handler) - handler->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/****************************** TryFinallyStatement ***************************/ - -TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody) - : Statement(loc) -{ - this->body = body; - this->finalbody = finalbody; -} - -Statement *TryFinallyStatement::syntaxCopy() -{ - TryFinallyStatement *s = new TryFinallyStatement(loc, - body->syntaxCopy(), finalbody->syntaxCopy()); - return s; -} - -Statement *TryFinallyStatement::semantic(Scope *sc) -{ - //printf("TryFinallyStatement::semantic()\n"); - // This code is different in LDC because LDC needs to know the - // enclosingScopeExit for its labels - Statement* oldScopeExit = sc->enclosingScopeExit; - sc->enclosingScopeExit = this; - body = body->semantic(sc); - sc->enclosingScopeExit = oldScopeExit; - sc = sc->push(); - sc->enclosingFinally = this; - sc->sbreak = NULL; - sc->scontinue = NULL; // no break or continue out of finally block - finalbody = finalbody->semanticNoScope(sc); - sc->pop(); - return this; -} - -void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("try\n{\n"); - body->toCBuffer(buf, hgs); - buf->printf("}\nfinally\n{\n"); - finalbody->toCBuffer(buf, hgs); - buf->writeByte('}'); - buf->writenl(); -} - -int TryFinallyStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int TryFinallyStatement::hasContinue() -{ - return FALSE; //TRUE; -} - -int TryFinallyStatement::usesEH() -{ - return TRUE; -} - -int TryFinallyStatement::blockExit(bool mustNotThrow) -{ - if (body) - return body->blockExit(mustNotThrow); - return BEfallthru; -} - - -/****************************** OnScopeStatement ***************************/ - -OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement) - : Statement(loc) -{ - this->tok = tok; - this->statement = statement; -} - -Statement *OnScopeStatement::syntaxCopy() -{ - OnScopeStatement *s = new OnScopeStatement(loc, - tok, statement->syntaxCopy()); - return s; -} - -Statement *OnScopeStatement::semantic(Scope *sc) -{ - /* semantic is called on results of scopeCode() */ - return this; -} - -int OnScopeStatement::blockExit(bool mustNotThrow) -{ // At this point, this statement is just an empty placeholder - return BEfallthru; -} - -void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(tok)); - buf->writebyte(' '); - statement->toCBuffer(buf, hgs); -} - -int OnScopeStatement::usesEH() -{ - return (tok != TOKon_scope_success); -} - -void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("OnScopeStatement::scopeCode()\n"); - //print(); - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - switch (tok) - { - case TOKon_scope_exit: - *sfinally = statement; - break; - - case TOKon_scope_failure: - *sexception = statement; - break; - - case TOKon_scope_success: - { - /* Create: - * sentry: int x = 0; - * sexception: x = 1; - * sfinally: if (!x) statement; - */ - Identifier *id = Lexer::uniqueId("__os"); - - ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0)); - VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie); - *sentry = new ExpStatement(loc, v); - - Expression *e = new IntegerExp(1); - e = new AssignExp(0, new VarExp(0, v), e); - *sexception = new ExpStatement(0, e); - - e = new VarExp(0, v); - e = new NotExp(0, e); - *sfinally = new IfStatement(0, NULL, e, statement, NULL); - - break; - } - - default: - assert(0); - } -} - -/******************************** ThrowStatement ***************************/ - -ThrowStatement::ThrowStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *ThrowStatement::syntaxCopy() -{ - ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy()); - return s; -} - -Statement *ThrowStatement::semantic(Scope *sc) -{ - //printf("ThrowStatement::semantic()\n"); - - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - fd->hasReturnExp |= 2; - - if (sc->incontract) - error("Throw statements cannot be in contracts"); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (exp->op == TOKerror) - return this; - if (!exp->type->toBasetype()->isClassHandle()) - error("can only throw class objects, not type %s", exp->type->toChars()); - return this; -} - -int ThrowStatement::blockExit(bool mustNotThrow) -{ - return BEthrow; // obviously -} - - -void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("throw "); - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - buf->writenl(); -} - -/******************************** VolatileStatement **************************/ - -VolatileStatement::VolatileStatement(Loc loc, Statement *statement) - : Statement(loc) -{ - this->statement = statement; -} - -Statement *VolatileStatement::syntaxCopy() -{ - VolatileStatement *s = new VolatileStatement(loc, - statement ? statement->syntaxCopy() : NULL); - return s; -} - -Statement *VolatileStatement::semantic(Scope *sc) -{ - if (statement) - { - Statement* oldScopeExit = sc->enclosingScopeExit; - sc->enclosingScopeExit = this; - statement = statement->semantic(sc); - sc->enclosingScopeExit = oldScopeExit; - } - return this; -} - -Statements *VolatileStatement::flatten(Scope *sc) -{ - Statements *a; - - a = statement ? statement->flatten(sc) : NULL; - if (a) - { for (size_t i = 0; i < a->dim; i++) - { Statement *s = (*a)[i]; - - s = new VolatileStatement(loc, s); - (*a)[i] = s; - } - } - - return a; -} - -int VolatileStatement::blockExit(bool mustNotThrow) -{ - return statement ? statement->blockExit(mustNotThrow) : BEfallthru; -} - - -void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("volatile"); - if (statement) - { if (statement->isScopeStatement()) - buf->writenl(); - else - buf->writebyte(' '); - statement->toCBuffer(buf, hgs); - } -} - - -/******************************** GotoStatement ***************************/ - -GotoStatement::GotoStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; - this->label = NULL; - this->enclosingFinally = NULL; - this->enclosingScopeExit = NULL; -} - -Statement *GotoStatement::syntaxCopy() -{ - GotoStatement *s = new GotoStatement(loc, ident); - return s; -} - -Statement *GotoStatement::semantic(Scope *sc) -{ FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - - //printf("GotoStatement::semantic()\n"); - enclosingFinally = sc->enclosingFinally; - enclosingScopeExit = sc->enclosingScopeExit; - - label = fd->searchLabel(ident); - if (!label->statement && sc->fes) - { - /* Either the goto label is forward referenced or it - * is in the function that the enclosing foreach is in. - * Can't know yet, so wrap the goto in a compound statement - * so we can patch it later, and add it to a 'look at this later' - * list. - */ - Statements *a = new Statements(); - CompoundStatement *s; - - a->push(this); - s = new CompoundStatement(loc, a); - sc->fes->gotos->push(s); // 'look at this later' list - return s; - } - if (label->statement && label->statement->enclosingFinally != sc->enclosingFinally) - error("cannot goto in or out of finally block"); - return this; -} - -int GotoStatement::blockExit(bool mustNotThrow) -{ - //printf("GotoStatement::blockExit(%p)\n", this); - return BEgoto; -} - - -void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("goto "); - buf->writestring(ident->toChars()); - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** LabelStatement ***************************/ - -LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement) - : Statement(loc) -{ - this->ident = ident; - this->statement = statement; - this->enclosingFinally = NULL; - this->enclosingScopeExit = NULL; - this->lblock = NULL; - this->asmLabel = false; - this->fwdrefs = NULL; -} - -Statement *LabelStatement::syntaxCopy() -{ - LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy()); - return s; -} - -Statement *LabelStatement::semantic(Scope *sc) -{ LabelDsymbol *ls; - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - - //printf("LabelStatement::semantic()\n"); - ls = fd->searchLabel(ident); - if (ls->statement) - error("Label '%s' already defined", ls->toChars()); - else - ls->statement = this; - - enclosingFinally = sc->enclosingFinally; - enclosingScopeExit = sc->enclosingScopeExit; - - sc = sc->push(); - sc->scopesym = sc->enclosing->scopesym; - sc->callSuper |= CSXlabel; - sc->slabel = this; - if (statement) - statement = statement->semanticNoScope(sc); - sc->pop(); - - // LDC put in labmap - fd->labmap[ident->toChars()] = this; - - return this; -} - -Statements *LabelStatement::flatten(Scope *sc) -{ - Statements *a = NULL; - - if (statement) - { - a = statement->flatten(sc); - if (a) - { - if (!a->dim) - { - a->push(new ExpStatement(loc, (Expression *)NULL)); - } - Statement *s = (*a)[0]; - - s = new LabelStatement(loc, ident, s); - (*a)[0] = s; - } - } - - return a; -} - - -int LabelStatement::usesEH() -{ - return statement ? statement->usesEH() : FALSE; -} - -int LabelStatement::blockExit(bool mustNotThrow) -{ - //printf("LabelStatement::blockExit(%p)\n", this); - return statement ? statement->blockExit(mustNotThrow) : BEfallthru; -} - - -int LabelStatement::comeFrom() -{ - //printf("LabelStatement::comeFrom()\n"); - return TRUE; -} - -void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - buf->writebyte(':'); - buf->writenl(); - if (statement) - statement->toCBuffer(buf, hgs); -} - - -/******************************** LabelDsymbol ***************************/ - -LabelDsymbol::LabelDsymbol(Identifier *ident) - : Dsymbol(ident) -{ - statement = NULL; -#if IN_GCC - asmLabelNum = 0; -#endif -} - -LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()? -{ - return this; -} diff --git a/dmd/statement.h b/dmd/statement.h deleted file mode 100644 index c78816b1..00000000 --- a/dmd/statement.h +++ /dev/null @@ -1,943 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_STATEMENT_H -#define DMD_STATEMENT_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" - -#include "arraytypes.h" -#include "dsymbol.h" -#include "lexer.h" - -struct OutBuffer; -struct Scope; -struct Expression; -struct LabelDsymbol; -struct Identifier; -struct IfStatement; -struct ExpStatement; -struct DefaultStatement; -struct VarDeclaration; -struct Condition; -struct Module; -struct Token; -struct InlineCostState; -struct InlineDoState; -struct InlineScanState; -struct ReturnStatement; -struct CompoundStatement; -struct Parameter; -struct StaticAssert; -struct AsmStatement; -struct AsmBlockStatement; -struct GotoStatement; -struct ScopeStatement; -struct TryCatchStatement; -struct TryFinallyStatement; -struct CaseStatement; -struct DefaultStatement; -struct LabelStatement; -struct HdrGenState; -struct InterState; -struct CaseStatement; -struct LabelStatement; -struct VolatileStatement; -struct SynchronizedStatement; - -enum TOK; -#if IN_LLVM -namespace llvm -{ - class Value; - class BasicBlock; - class ConstantInt; -} -#endif - -// Back end -struct IRState; -struct Blockx; -#if IN_LLVM -struct DValue; -typedef DValue elem; -#endif - -#if IN_GCC -union tree_node; typedef union tree_node block; -//union tree_node; typedef union tree_node elem; -#else -struct block; -//struct elem; -#endif -struct code; - -/* How a statement exits; this is returned by blockExit() - */ -enum BE -{ - BEnone = 0, - BEfallthru = 1, - BEthrow = 2, - BEreturn = 4, - BEgoto = 8, - BEhalt = 0x10, - BEbreak = 0x20, - BEcontinue = 0x40, - BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), -}; - -struct Statement : Object -{ - Loc loc; - - Statement(Loc loc); - virtual Statement *syntaxCopy(); - - void print(); - char *toChars(); - - void error(const char *format, ...) IS_PRINTF(2); - void warning(const char *format, ...) IS_PRINTF(2); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual TryCatchStatement *isTryCatchStatement() { return NULL; } - virtual GotoStatement *isGotoStatement() { return NULL; } - virtual AsmStatement *isAsmStatement() { return NULL; } - virtual AsmBlockStatement *isAsmBlockStatement() { return NULL; } - int incontract; - virtual ScopeStatement *isScopeStatement() { return NULL; } - virtual Statement *semantic(Scope *sc); - Statement *semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue); - Statement *semanticNoScope(Scope *sc); - virtual int hasBreak(); - virtual int hasContinue(); - virtual int usesEH(); - virtual int blockExit(bool mustNotThrow); - virtual int comeFrom(); - virtual int isEmpty(); - virtual void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - virtual Statements *flatten(Scope *sc); - virtual Expression *interpret(InterState *istate); - - virtual int inlineCost(InlineCostState *ics); - virtual Expression *doInline(InlineDoState *ids); - virtual Statement *doInlineStatement(InlineDoState *ids); - virtual Statement *inlineScan(InlineScanState *iss); - - // Back end - virtual void toIR(IRState *irs); - - // Avoid dynamic_cast - virtual ExpStatement *isExpStatement() { return NULL; } - virtual CompoundStatement *isCompoundStatement() { return NULL; } - virtual ReturnStatement *isReturnStatement() { return NULL; } - virtual IfStatement *isIfStatement() { return NULL; } - virtual CaseStatement *isCaseStatement() { return NULL; } - virtual DefaultStatement *isDefaultStatement() { return NULL; } - virtual LabelStatement* isLabelStatement() { return NULL; } - -#if IN_LLVM - virtual void toNakedIR(IRState *irs); - virtual AsmBlockStatement* endsWithAsm(); -#endif -}; - -struct PeelStatement : Statement -{ - Statement *s; - - PeelStatement(Statement *s); - Statement *semantic(Scope *sc); -}; - -struct ExpStatement : Statement -{ - Expression *exp; - - ExpStatement(Loc loc, Expression *exp); - ExpStatement(Loc loc, Dsymbol *s); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(bool mustNotThrow); - int isEmpty(); - void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - -#if IN_LLVM - void toNakedIR(IRState *irs); -#endif - - ExpStatement *isExpStatement() { return this; } -}; - -struct CompileStatement : Statement -{ - Expression *exp; - - CompileStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statements *flatten(Scope *sc); - Statement *semantic(Scope *sc); -}; - -struct CompoundStatement : Statement -{ - Statements *statements; - - CompoundStatement(Loc loc, Statements *s); - CompoundStatement(Loc loc, Statement *s1); - CompoundStatement(Loc loc, Statement *s1, Statement *s2); - virtual Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual Statement *semantic(Scope *sc); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - int isEmpty(); - virtual Statements *flatten(Scope *sc); - ReturnStatement *isReturnStatement(); - Expression *interpret(InterState *istate); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - virtual void toIR(IRState *irs); - - // LDC - virtual void toNakedIR(IRState *irs); - virtual AsmBlockStatement* endsWithAsm(); - - virtual CompoundStatement *isCompoundStatement() { return this; } -}; - -struct CompoundDeclarationStatement : CompoundStatement -{ - CompoundDeclarationStatement(Loc loc, Statements *s); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -/* The purpose of this is so that continue will go to the next - * of the statements, and break will go to the end of the statements. - */ -struct UnrolledLoopStatement : Statement -{ - Statements *statements; - - UnrolledLoopStatement(Loc loc, Statements *statements); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ScopeStatement : Statement -{ - Statement *statement; - - ScopeStatement(Loc loc, Statement *s); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - ScopeStatement *isScopeStatement() { return this; } - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - int isEmpty(); - Expression *interpret(InterState *istate); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct WhileStatement : Statement -{ - Expression *condition; - Statement *body; - - WhileStatement(Loc loc, Expression *c, Statement *b); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct DoStatement : Statement -{ - Statement *body; - Expression *condition; - - DoStatement(Loc loc, Statement *b, Expression *c); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ForStatement : Statement -{ - Statement *init; - Expression *condition; - Expression *increment; - Statement *body; - - ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - int inlineCost(InlineCostState *ics); - Statement *inlineScan(InlineScanState *iss); - Statement *doInlineStatement(InlineDoState *ids); - - void toIR(IRState *irs); -}; - -struct ForeachStatement : Statement -{ - enum TOK op; // TOKforeach or TOKforeach_reverse - Parameters *arguments; // array of Parameter*'s - Expression *aggr; - Statement *body; - - VarDeclaration *key; - VarDeclaration *value; - - FuncDeclaration *func; // function we're lexically in - - Statements *cases; // put breaks, continues, gotos and returns here - CompoundStatements *gotos; // forward referenced goto's go here - - ForeachStatement(Loc loc, enum TOK op, Parameters *arguments, Expression *aggr, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - bool checkForArgTypes(); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -#if DMDV2 -struct ForeachRangeStatement : Statement -{ - enum TOK op; // TOKforeach or TOKforeach_reverse - Parameter *arg; // loop index variable - Expression *lwr; - Expression *upr; - Statement *body; - - VarDeclaration *key; - - ForeachRangeStatement(Loc loc, enum TOK op, Parameter *arg, - Expression *lwr, Expression *upr, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; -#endif - -struct IfStatement : Statement -{ - Parameter *arg; - Expression *condition; - Statement *ifbody; - Statement *elsebody; - - VarDeclaration *match; // for MatchExpression results - - IfStatement(Loc loc, Parameter *arg, Expression *condition, Statement *ifbody, Statement *elsebody); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int usesEH(); - int blockExit(bool mustNotThrow); - IfStatement *isIfStatement() { return this; } - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ConditionalStatement : Statement -{ - Condition *condition; - Statement *ifbody; - Statement *elsebody; - - ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int usesEH(); - int blockExit(bool mustNotThrow); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct PragmaStatement : Statement -{ - Identifier *ident; - Expressions *args; // array of Expression's - Statement *body; - - PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int usesEH(); - int blockExit(bool mustNotThrow); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct StaticAssertStatement : Statement -{ - StaticAssert *sa; - - StaticAssertStatement(StaticAssert *sa); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int blockExit(bool mustNotThrow); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct SwitchStatement : Statement -{ - Expression *condition; - Statement *body; - - DefaultStatement *sdefault; - - GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's - CaseStatements *cases; // array of CaseStatement's - int hasNoDefault; // !=0 if no default statement - - // LDC - Statement *enclosingScopeExit; - - SwitchStatement(Loc loc, Expression *c, Statement *b); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int usesEH(); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct CaseStatement : Statement -{ - Expression *exp; - Statement *statement; - - int index; // which case it is (since we sort this) - block *cblock; // back end: label for the block - - // LDC - Statement *enclosingScopeExit; - - CaseStatement(Loc loc, Expression *exp, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int compare(Object *obj); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - CaseStatement *isCaseStatement() { return this; } - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - -#if IN_LLVM - llvm::BasicBlock* bodyBB; - llvm::Value* llvmIdx; -#endif -}; - -#if DMDV2 - -struct CaseRangeStatement : Statement -{ - Expression *first; - Expression *last; - Statement *statement; - - CaseRangeStatement(Loc loc, Expression *first, Expression *last, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#endif - -struct DefaultStatement : Statement -{ - Statement *statement; -#if IN_GCC - block *cblock; // back end: label for the block -#endif - - // LDC - Statement *enclosingScopeExit; - - DefaultStatement(Loc loc, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - DefaultStatement *isDefaultStatement() { return this; } - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - // LDC - llvm::BasicBlock* bodyBB; -}; - -struct GotoDefaultStatement : Statement -{ - SwitchStatement *sw; - - GotoDefaultStatement(Loc loc); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct GotoCaseStatement : Statement -{ - Expression *exp; // NULL, or which case to goto - CaseStatement *cs; // case statement it resolves to - SwitchStatement *sw; - - GotoCaseStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct SwitchErrorStatement : Statement -{ - SwitchErrorStatement(Loc loc); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct ReturnStatement : Statement -{ - Expression *exp; - int implicit0; - - ReturnStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - ReturnStatement *isReturnStatement() { return this; } -}; - -struct BreakStatement : Statement -{ - Identifier *ident; - - BreakStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); - - // LDC: only set if ident is set: label statement to jump to - LabelStatement *target; -}; - -struct ContinueStatement : Statement -{ - Identifier *ident; - - ContinueStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); - - // LDC: only set if ident is set: label statement to jump to - LabelStatement *target; -}; - -struct SynchronizedStatement : Statement -{ - Expression *exp; - Statement *body; - - SynchronizedStatement(Loc loc, Expression *exp, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - -// Back end - elem *esync; - SynchronizedStatement(Loc loc, elem *esync, Statement *body); - void toIR(IRState *irs); - llvm::Value* llsync; -}; - -struct WithStatement : Statement -{ - Expression *exp; - Statement *body; - VarDeclaration *wthis; - - WithStatement(Loc loc, Expression *exp, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int usesEH(); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct TryCatchStatement : Statement -{ - Statement *body; - Catches *catches; - - TryCatchStatement(Loc loc, Statement *body, Catches *catches); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int usesEH(); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - TryCatchStatement *isTryCatchStatement() { return this; } -}; - -struct Catch : Object -{ - Loc loc; - Type *type; - Identifier *ident; - VarDeclaration *var; - Statement *handler; - - Catch(Loc loc, Type *t, Identifier *id, Statement *handler); - Catch *syntaxCopy(); - void semantic(Scope *sc); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct TryFinallyStatement : Statement -{ - Statement *body; - Statement *finalbody; - - TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct OnScopeStatement : Statement -{ - TOK tok; - Statement *statement; - - OnScopeStatement(Loc loc, TOK tok, Statement *statement); - Statement *syntaxCopy(); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int usesEH(); - void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - Expression *interpret(InterState *istate); - - void toIR(IRState *irs); -}; - -struct ThrowStatement : Statement -{ - Expression *exp; - - ThrowStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct VolatileStatement : Statement -{ - Statement *statement; - - VolatileStatement(Loc loc, Statement *statement); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct GotoStatement : Statement -{ - Identifier *ident; - LabelDsymbol *label; - TryFinallyStatement *enclosingFinally; - Statement* enclosingScopeExit; - - GotoStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - - void toIR(IRState *irs); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - GotoStatement *isGotoStatement() { return this; } -}; - -struct LabelStatement : Statement -{ - Identifier *ident; - Statement *statement; - TryFinallyStatement *enclosingFinally; - Statement* enclosingScopeExit; - block *lblock; // back end - - Blocks *fwdrefs; // forward references to this LabelStatement - - LabelStatement(Loc loc, Identifier *ident, Statement *statement); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - LabelStatement *isLabelStatement() { return this; } - - void toIR(IRState *irs); - - // LDC - bool asmLabel; // for labels inside inline assembler - void toNakedIR(IRState *irs); -}; - -struct LabelDsymbol : Dsymbol -{ - LabelStatement *statement; -#if IN_GCC - unsigned asmLabelNum; // GCC-specific -#endif - - LabelDsymbol(Identifier *ident); - LabelDsymbol *isLabel(); -}; - -struct AsmStatement : Statement -{ - Token *tokens; - code *asmcode; - unsigned asmalign; // alignment of this statement - unsigned regs; // mask of registers modified (must match regm_t in back end) - unsigned char refparam; // !=0 if function parameter is referenced - unsigned char naked; // !=0 if function is to be naked - - AsmStatement(Loc loc, Token *tokens); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual AsmStatement *isAsmStatement() { return this; } - - void toIR(IRState *irs); - - // LDC - // non-zero if this is a branch, contains the target labels identifier - Identifier* isBranchToLabel; - - void toNakedIR(IRState *irs); -}; - -struct AsmBlockStatement : CompoundStatement -{ - TryFinallyStatement* enclosingFinally; - Statement* enclosingScopeExit; - - AsmBlockStatement(Loc loc, Statements *s); - Statements *flatten(Scope *sc); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - - CompoundStatement *isCompoundStatement() { return NULL; } - AsmBlockStatement *isAsmBlockStatement() { return this; } - - void toIR(IRState *irs); - void toNakedIR(IRState *irs); - AsmBlockStatement* endsWithAsm(); - - llvm::Value* abiret; -}; - -#endif /* DMD_STATEMENT_H */ diff --git a/dmd/staticassert.c b/dmd/staticassert.c deleted file mode 100644 index 062219c2..00000000 --- a/dmd/staticassert.c +++ /dev/null @@ -1,126 +0,0 @@ - -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// http://www.dsource.org/projects/dmd/browser/branches/dmd-1.x/src/staticassert.c -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "dsymbol.h" -#include "staticassert.h" -#include "expression.h" -#include "id.h" -#include "hdrgen.h" -#include "scope.h" -#include "template.h" -#include "declaration.h" - - -/********************************* AttribDeclaration ****************************/ - -StaticAssert::StaticAssert(Loc loc, Expression *exp, Expression *msg) - : Dsymbol(Id::empty) -{ - this->loc = loc; - this->exp = exp; - this->msg = msg; -} - -Dsymbol *StaticAssert::syntaxCopy(Dsymbol *s) -{ - StaticAssert *sa; - - assert(!s); - sa = new StaticAssert(loc, exp->syntaxCopy(), msg ? msg->syntaxCopy() : NULL); - return sa; -} - -int StaticAssert::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - return 0; // we didn't add anything -} - -void StaticAssert::semantic(Scope *sc) -{ -} - -void StaticAssert::semantic2(Scope *sc) -{ - //printf("StaticAssert::semantic2() %s\n", toChars()); - Expression *e = exp->semantic(sc); - if (!e->type->checkBoolean()) - { - if (e->type->toBasetype() != Type::terror) - exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars()); - return; - } - unsigned olderrs = global.errors; - e = e->ctfeInterpret(); - if (global.errors != olderrs) - { - errorSupplemental(loc, "while evaluating: static assert(%s)", exp->toChars()); - } - else if (e->isBool(FALSE)) - { - if (msg) - { HdrGenState hgs; - OutBuffer buf; - - msg = msg->semantic(sc); - msg = msg->ctfeInterpret(); - hgs.console = 1; - msg->toCBuffer(&buf, &hgs); - error("%s", buf.toChars()); - } - else - error("(%s) is false", exp->toChars()); - if (sc->tinst) - sc->tinst->printInstantiationTrace(); - if (!global.gag) - fatal(); - } - else if (!e->isBool(TRUE)) - { - error("(%s) is not evaluatable at compile time", exp->toChars()); - } -} - -int StaticAssert::oneMember(Dsymbol **ps) -{ - //printf("StaticAssert::oneMember())\n"); - *ps = NULL; - return TRUE; -} - -void StaticAssert::inlineScan() -{ -} - -void StaticAssert::toObjFile(int multiobj) -{ -} - -const char *StaticAssert::kind() -{ - return "static assert"; -} - -void StaticAssert::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(kind()); - buf->writeByte('('); - exp->toCBuffer(buf, hgs); - if (msg) - { - buf->writeByte(','); - msg->toCBuffer(buf, hgs); - } - buf->writestring(");"); - buf->writenl(); -} diff --git a/dmd/staticassert.h b/dmd/staticassert.h deleted file mode 100644 index 2f7e0906..00000000 --- a/dmd/staticassert.h +++ /dev/null @@ -1,41 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_STATICASSERT_H -#define DMD_STATICASSERT_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - -struct Expression; -struct HdrGenState; - -struct StaticAssert : Dsymbol -{ - Expression *exp; - Expression *msg; - - StaticAssert(Loc loc, Expression *exp, Expression *msg); - - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *sd, int memnum); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void inlineScan(); - int oneMember(Dsymbol **ps); - void toObjFile(int multiobj); - const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#endif diff --git a/dmd/struct.c b/dmd/struct.c deleted file mode 100644 index ad1f5975..00000000 --- a/dmd/struct.c +++ /dev/null @@ -1,683 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" -#include "aggregate.h" -#include "scope.h" -#include "mtype.h" -#include "declaration.h" -#include "module.h" -#include "id.h" -#include "statement.h" -#include "template.h" - -/********************************* AggregateDeclaration ****************************/ - -AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) - : ScopeDsymbol(id) -{ - this->loc = loc; - - storage_class = 0; - protection = PROTpublic; - type = NULL; - handle = NULL; - structsize = 0; // size of struct - alignsize = 0; // size of struct for alignment purposes - structalign = 0; // struct member alignment in effect - hasUnions = 0; - sizeok = SIZEOKnone; // size not determined yet - isdeprecated = 0; - inv = NULL; - aggNew = NULL; - aggDelete = NULL; - -#if IN_DMD - stag = NULL; - sinit = NULL; -#endif -#if DMDV2 - dtor = NULL; - - ctor = NULL; - defaultCtor = NULL; - aliasthis = NULL; - noDefaultCtor = FALSE; -#endif - dtor = NULL; - -#if IN_LLVM - availableExternally = true; // assume this unless proven otherwise -#endif -} - -enum PROT AggregateDeclaration::prot() -{ - return protection; -} - -void AggregateDeclaration::semantic2(Scope *sc) -{ - //printf("AggregateDeclaration::semantic2(%s)\n", toChars()); - if (scope && members) - { error("has forward references"); - return; - } - if (members) - { - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->semantic2(sc); - } - sc->pop(); - } -} - -void AggregateDeclaration::semantic3(Scope *sc) -{ - // LDC - if (!global.params.useAvailableExternally) - availableExternally = false; - - //printf("AggregateDeclaration::semantic3(%s)\n", toChars()); - if (members) - { - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->semantic3(sc); - } - sc->pop(); - } -} - -void AggregateDeclaration::inlineScan() -{ - //printf("AggregateDeclaration::inlineScan(%s)\n", toChars()); - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - //printf("inline scan aggregate symbol '%s'\n", s->toChars()); - s->inlineScan(); - } - } -} - -unsigned AggregateDeclaration::size(Loc loc) -{ - //printf("AggregateDeclaration::size() %s, scope = %p\n", toChars(), scope); - if (loc.linnum == 0) - loc = this->loc; - if (!members) - error(loc, "unknown size"); - if (sizeok != SIZEOKdone && scope) - semantic(NULL); - if (sizeok != SIZEOKdone) - { error(loc, "no size yet for forward reference"); - //*(char*)0=0; - } - return structsize; -} - -Type *AggregateDeclaration::getType() -{ - return type; -} - -int AggregateDeclaration::isDeprecated() -{ - return isdeprecated; -} - -int AggregateDeclaration::isExport() -{ - return protection == PROTexport; -} - -/**************************** - * Do byte or word alignment as necessary. - * Align sizes of 0, as we may not know array sizes yet. - */ - -void AggregateDeclaration::alignmember( - structalign_t salign, // struct alignment that is in effect - unsigned size, // alignment requirement of field - unsigned *poffset) -{ - //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); - if (salign == STRUCTALIGN_DEFAULT) - salign = 8; - if (salign > 1) - { - assert(size != 3); - unsigned sa = size; - if (sa == 0 || salign < sa) - sa = salign; - *poffset = (*poffset + sa - 1) & ~(sa - 1); - } - //printf("result = %d\n", *poffset); -} - -/**************************************** - * Place a member (mem) into an aggregate (agg), which can be a struct, union or class - * Returns: - * offset to place field at - */ -unsigned AggregateDeclaration::placeField( - unsigned *nextoffset, // next location in aggregate - unsigned memsize, // size of member - unsigned memalignsize, // size of member for alignment purposes - structalign_t memalign, // alignment in effect for this member - unsigned *paggsize, // size of aggregate (updated) - unsigned *paggalignsize, // size of aggregate for alignment purposes (updated) - bool isunion // the aggregate is a union - ) -{ - unsigned ofs = *nextoffset; - alignmember(memalign, memalignsize, &ofs); - unsigned memoffset = ofs; - ofs += memsize; - if (ofs > *paggsize) - *paggsize = ofs; - if (!isunion) - *nextoffset = ofs; - if (global.params.is64bit && memalign == 8 && memalignsize == 16) - /* Not sure how to handle this */ - ; - else if (memalign == STRUCTALIGN_DEFAULT && 8 < memalignsize) - memalignsize = 8; - else if (memalign < memalignsize) - memalignsize = memalign; - if (*paggalignsize < memalignsize) - *paggalignsize = memalignsize; - - return memoffset; -} - - -/**************************************** - * If field[indx] is not part of a union, return indx. - * Otherwise, return the lowest field index of the union. - */ -int AggregateDeclaration::firstFieldInUnion(int indx) -{ - if (isUnionDeclaration()) - return 0; - VarDeclaration * vd = fields[indx]; - int firstNonZero = indx; // first index in the union with non-zero size - for (; ;) - { - if (indx == 0) - return firstNonZero; - VarDeclaration * v = fields[indx - 1]; - if (v->offset != vd->offset) - return firstNonZero; - --indx; - /* If it is a zero-length field, it's ambiguous: we don't know if it is - * in the union unless we find an earlier non-zero sized field with the - * same offset. - */ - if (v->size(loc) != 0) - firstNonZero = indx; - } -} - -/**************************************** - * Count the number of fields starting at firstIndex which are part of the - * same union as field[firstIndex]. If not a union, return 1. - */ -int AggregateDeclaration::numFieldsInUnion(int firstIndex) -{ - VarDeclaration * vd = fields[firstIndex]; - /* If it is a zero-length field, AND we can't find an earlier non-zero - * sized field with the same offset, we assume it's not part of a union. - */ - if (vd->size(loc) == 0 && !isUnionDeclaration() && - firstFieldInUnion(firstIndex) == firstIndex) - return 1; - int count = 1; - for (size_t i = firstIndex+1; i < fields.dim; ++i) - { - VarDeclaration * v = fields[i]; - // If offsets are different, they are not in the same union - if (v->offset != vd->offset) - break; - ++count; - } - return count; -} - -/********************************* StructDeclaration ****************************/ - -StructDeclaration::StructDeclaration(Loc loc, Identifier *id) - : AggregateDeclaration(loc, id) -{ - zeroInit = 0; // assume false until we do semantic processing -#if DMDV2 - hasIdentityAssign = 0; - cpctor = NULL; - postblit = NULL; - eq = NULL; -#endif - arg1type = NULL; - arg2type = NULL; - - // For forward references - type = new TypeStruct(this); -} - -Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s) -{ - StructDeclaration *sd; - - if (s) - sd = (StructDeclaration *)s; - else - sd = new StructDeclaration(loc, ident); - ScopeDsymbol::syntaxCopy(sd); - return sd; -} - -void StructDeclaration::semantic(Scope *sc) -{ - Scope *sc2; - - //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok); - - //static int count; if (++count == 20) halt(); - - assert(type); - if (!members) // if forward reference - return; - - if (symtab) - { if (sizeok == SIZEOKdone || !scope) - { //printf("already completed\n"); - scope = NULL; - return; // semantic() already completed - } - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - unsigned dprogress_save = Module::dprogress; - - parent = sc->parent; - type = type->semantic(loc, sc); -#if STRUCTTHISREF - handle = type; -#else - handle = type->pointerTo(); -#endif - structalign = sc->structalign; - protection = sc->protection; - if (sc->stc & STCdeprecated) - isdeprecated = 1; - assert(!isAnonymous()); - if (sc->stc & STCabstract) - error("structs, unions cannot be abstract"); - - if (sizeok == SIZEOKnone) // if not already done the addMember step - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); - s->addMember(sc, this, 1); - } - } - - sizeok = SIZEOKnone; - sc2 = sc->push(this); - sc2->stc = 0; - sc2->parent = this; - if (isUnionDeclaration()) - sc2->inunion = 1; - sc2->protection = PROTpublic; - sc2->explicitProtection = 0; - - size_t members_dim = members->dim; - - /* Set scope so if there are forward references, we still might be able to - * resolve individual members like enums. - */ - for (size_t i = 0; i < members_dim; i++) - { Dsymbol *s = (*members)[i]; - /* There are problems doing this in the general case because - * Scope keeps track of things like 'offset' - */ - if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) - { - //printf("setScope %s %s\n", s->kind(), s->toChars()); - s->setScope(sc2); - } - } - - for (size_t i = 0; i < members_dim; i++) - { - Dsymbol *s = (*members)[i]; - // Ungag errors when not speculative - unsigned oldgag = global.gag; - if (global.isSpeculativeGagging() && !isSpeculative()) - { - global.gag = 0; - } - s->semantic(sc2); - global.gag = oldgag; -#if 0 - if (sizeok == 2) - { //printf("forward reference\n"); - break; - } -#endif - } - finalizeSize(sc2); - -#if DMDV1 - /* This doesn't work for DMDV2 because (ref S) and (S) parameter - * lists will overload the same. - */ - /* The TypeInfo_Struct is expecting an opEquals and opCmp with - * a parameter that is a pointer to the struct. But if there - * isn't one, but is an opEquals or opCmp with a value, write - * another that is a shell around the value: - * int opCmp(struct *p) { return opCmp(*p); } - */ - - TypeFunction *tfeqptr; - { - Parameters *arguments = new Parameters; - Parameter *arg = new Parameter(STCin, handle, Id::p, NULL); - - arguments->push(arg); - tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); - tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc); - } - - TypeFunction *tfeq; - { - Parameters *arguments = new Parameters; - Parameter *arg = new Parameter(STCin, type, NULL, NULL); - - arguments->push(arg); - tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); - tfeq = (TypeFunction *)tfeq->semantic(0, sc); - } - - Identifier *id = Id::eq; - for (int i = 0; i < 2; i++) - { - Dsymbol *s = search_function(this, id); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - if (fdx) - { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr, getModule()); - if (!fd) - { fd = fdx->overloadExactMatch(tfeq, getModule()); - if (fd) - { // Create the thunk, fdptr - FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr); - Expression *e = new IdentifierExp(loc, Id::p); - e = new PtrExp(loc, e); - Expressions *args = new Expressions(); - args->push(e); - e = new IdentifierExp(loc, id); - e = new CallExp(loc, e, args); - fdptr->fbody = new ReturnStatement(loc, e); - ScopeDsymbol *s = fdx->parent->isScopeDsymbol(); - assert(s); - s->members->push(fdptr); - fdptr->addMember(sc, s, 1); - fdptr->semantic(sc2); - } - } - } - - id = Id::cmp; - } -#endif -#if DMDV2 - dtor = buildDtor(sc2); - postblit = buildPostBlit(sc2); - cpctor = buildCpCtor(sc2); - - buildOpAssign(sc2); - hasIdentityEquals = (buildOpEquals(sc2) != NULL); - - xeq = buildXopEquals(sc2); -#endif - - sc2->pop(); - - if (sizeok == 2) - { // semantic() failed because of forward references. - // Unwind what we did, and defer it for later - for (size_t i = 0; i < fields.dim; i++) - { Dsymbol *s = fields[i]; - VarDeclaration *vd = s->isVarDeclaration(); - if (vd) - vd->offset = 0; - } - fields.setDim(0); - structsize = 0; - alignsize = 0; - structalign = 0; - - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - - Module::dprogress = dprogress_save; - //printf("\tdeferring %s\n", toChars()); - return; - } - - // 0 sized struct's are set to 1 byte - if (structsize == 0) - { - structsize = 1; - alignsize = 1; - } - - // Round struct size up to next alignsize boundary. - // This will ensure that arrays of structs will get their internals - // aligned properly. - structsize = (structsize + alignsize - 1) & ~(alignsize - 1); - - sizeok = SIZEOKdone; - Module::dprogress++; - - //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); - - // Determine if struct is all zeros or not - zeroInit = 1; - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *vd = s->isVarDeclaration(); - if (vd && !vd->isDataseg()) - { - if (vd->init) - { - // Should examine init to see if it is really all 0's - zeroInit = 0; - break; - } - else - { - if (!vd->type->isZeroInit(loc)) - { - zeroInit = 0; - break; - } - } - } - } - - /* Look for special member functions. - */ -#if DMDV2 - ctor = (CtorDeclaration *)search(0, Id::ctor, 0); -#endif - inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0); - aggNew = (NewDeclaration *)search(0, Id::classNew, 0); - aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); - - TypeTuple *tup = type->toArgTypes(); - size_t dim = tup->arguments->dim; - if (dim >= 1) - { assert(dim <= 2); - arg1type = (*tup->arguments)[0]->type; - if (dim == 2) - arg2type = (*tup->arguments)[1]->type; - } - - if (sc->func) - { - semantic2(sc); - semantic3(sc); - } -} - -Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s.StructDeclaration::search('%s')\n", toChars(), ident->toChars()); - - if (scope && !symtab) - semantic(scope); - - if (!members || !symtab) - { - error("is forward referenced when looking for '%s'", ident->toChars()); - return NULL; - } - - return ScopeDsymbol::search(loc, ident, flags); -} - -void StructDeclaration::finalizeSize(Scope *sc) -{ - //printf("StructDeclaration::finalizeSize() %s\n", toChars()); - if (sizeok != SIZEOKnone) - return; - - // Set the offsets of the fields and determine the size of the struct - unsigned offset = 0; - bool isunion = isUnionDeclaration() != NULL; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->setFieldOffset(this, &offset, isunion); - } - if (sizeok == SIZEOKfwd) - return; - - // 0 sized struct's are set to 1 byte - if (structsize == 0) - { - structsize = 1; - alignsize = 1; - } - - // Round struct size up to next alignsize boundary. - // This will ensure that arrays of structs will get their internals - // aligned properly. - structsize = (structsize + alignsize - 1) & ~(alignsize - 1); - - sizeok = SIZEOKdone; -} - -/*************************************** - * Return true if struct is POD (Plain Old Data). - * This is defined as: - * not nested - * no postblits, constructors, destructors, or assignment operators - * no fields with with any of those - * The idea being these are compatible with C structs. - * - * Note that D struct constructors can mean POD, since there is always default - * construction with no ctor, but that interferes with OPstrpar which wants it - * on the stack in memory, not in registers. - */ -bool StructDeclaration::isPOD() -{ - return true; -} - -void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("%s ", kind()); - if (!isAnonymous()) - buf->writestring(toChars()); - if (!members) - { - buf->writeByte(';'); - buf->writenl(); - return; - } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - buf->writenl(); -} - - -const char *StructDeclaration::kind() -{ - return "struct"; -} - -/********************************* UnionDeclaration ****************************/ - -UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id) - : StructDeclaration(loc, id) -{ -} - -Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s) -{ - UnionDeclaration *ud; - - if (s) - ud = (UnionDeclaration *)s; - else - ud = new UnionDeclaration(loc, ident); - StructDeclaration::syntaxCopy(ud); - return ud; -} - - -const char *UnionDeclaration::kind() -{ - return "union"; -} - - diff --git a/dmd/template.c b/dmd/template.c deleted file mode 100644 index a0b3943f..00000000 --- a/dmd/template.c +++ /dev/null @@ -1,5601 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Handle template implementation - -#include -#include - -#include "root.h" -#include "aav.h" -#include "rmem.h" -#include "stringtable.h" - -#include "mtype.h" -#include "template.h" -#include "init.h" -#include "expression.h" -#include "scope.h" -#include "module.h" -#include "aggregate.h" -#include "declaration.h" -#include "dsymbol.h" -#include "mars.h" -#include "dsymbol.h" -#include "identifier.h" -#include "hdrgen.h" - -#if WINDOWS_SEH -#include -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); -#endif - -#define LOG 0 - -/******************************************** - * These functions substitute for dynamic_cast. dynamic_cast does not work - * on earlier versions of gcc. - */ - -Expression *isExpression(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_EXPRESSION) - return NULL; - return (Expression *)o; -} - -Dsymbol *isDsymbol(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_DSYMBOL) - return NULL; - return (Dsymbol *)o; -} - -Type *isType(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_TYPE) - return NULL; - return (Type *)o; -} - -Tuple *isTuple(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_TUPLE) - return NULL; - return (Tuple *)o; -} - -/************************************** - * Is this Object an error? - */ -int isError(Object *o) -{ - Type *t = isType(o); - if (t) - return (t->ty == Terror); - Expression *e = isExpression(o); - if (e) - return (e->op == TOKerror || !e->type || e->type->ty== Terror); - Tuple *v = isTuple(o); - if (v) - return arrayObjectIsError(&v->objects); - return 0; -} - -/************************************** - * Are any of the Objects an error? - */ -int arrayObjectIsError(Objects *args) -{ - for (size_t i = 0; i < args->dim; i++) - { - Object *o = (*args)[i]; - if (isError(o)) - return 1; - } - return 0; -} - -/*********************** - * Try to get arg as a type. - */ - -Type *getType(Object *o) -{ - Type *t = isType(o); - if (!t) - { Expression *e = isExpression(o); - if (e) - t = e->type; - } - return t; -} - -Dsymbol *getDsymbol(Object *oarg) -{ - Dsymbol *sa; - Expression *ea = isExpression(oarg); - if (ea) - { // Try to convert Expression to symbol - if (ea->op == TOKvar) - sa = ((VarExp *)ea)->var; - else if (ea->op == TOKfunction) - sa = ((FuncExp *)ea)->fd; - else - sa = NULL; - } - else - { // Try to convert Type to symbol - Type *ta = isType(oarg); - if (ta) - sa = ta->toDsymbol(NULL); - else - sa = isDsymbol(oarg); // if already a symbol - } - return sa; -} - -/****************************** - * If o1 matches o2, return 1. - * Else, return 0. - */ - -int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) -{ - Type *t1 = isType(o1); - Type *t2 = isType(o2); - Expression *e1 = isExpression(o1); - Expression *e2 = isExpression(o2); - Dsymbol *s1 = isDsymbol(o1); - Dsymbol *s2 = isDsymbol(o2); - Tuple *u1 = isTuple(o1); - Tuple *u2 = isTuple(o2); - - //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, u1 %p u2 %p\n", t1,t2,e1,e2,s1,s2,u1,u2); - - /* A proper implementation of the various equals() overrides - * should make it possible to just do o1->equals(o2), but - * we'll do that another day. - */ - - if (s1) - { - VarDeclaration *v1 = s1->isVarDeclaration(); - if (v1 && v1->storage_class & STCmanifest) - { ExpInitializer *ei1 = v1->init->isExpInitializer(); - if (ei1) - e1 = ei1->exp, s1 = NULL; - } - } - if (s2) - { - VarDeclaration *v2 = s2->isVarDeclaration(); - if (v2 && v2->storage_class & STCmanifest) - { ExpInitializer *ei2 = v2->init->isExpInitializer(); - if (ei2) - e2 = ei2->exp, s2 = NULL; - } - } - - if (t1) - { - /* if t1 is an instance of ti, then give error - * about recursive expansions. - */ - Dsymbol *s = t1->toDsymbol(sc); - if (s && s->parent) - { TemplateInstance *ti1 = s->parent->isTemplateInstance(); - if (ti1 && ti1->tempdecl == tempdecl) - { - for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing) - { - if (sc1->scopesym == ti1) - { - tempdecl->error("recursive template expansion for template argument %s", t1->toChars()); - return 1; // fake a match - } - } - } - } - - //printf("t1 = %s\n", t1->toChars()); - //printf("t2 = %s\n", t2->toChars()); - if (!t2 || !t1->equals(t2)) - goto Lnomatch; - } - else if (e1) - { -#if 0 - if (e1 && e2) - { - printf("match %d\n", e1->equals(e2)); - e1->print(); - e2->print(); - e1->type->print(); - e2->type->print(); - } -#endif - if (!e2) - goto Lnomatch; - if (!e1->equals(e2)) - goto Lnomatch; - } - else if (s1) - { - if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) - goto Lnomatch; - } - else if (u1) - { - if (!u2) - goto Lnomatch; - if (u1->objects.dim != u2->objects.dim) - goto Lnomatch; - for (size_t i = 0; i < u1->objects.dim; i++) - { - if (!match(u1->objects[i], - u2->objects[i], - tempdecl, sc)) - goto Lnomatch; - } - } - //printf("match\n"); - return 1; // match - -Lnomatch: - //printf("nomatch\n"); - return 0; // nomatch; -} - - -/************************************ - * Match an array of them. - * This should match what genIdent() does. - */ -int arrayObjectMatch(Objects *oa1, Objects *oa2, TemplateDeclaration *tempdecl, Scope *sc) -{ - if (oa1 == oa2) - return 1; - if (oa1->dim != oa2->dim) - return 0; - for (size_t j = 0; j < oa1->dim; j++) - { Object *o1 = (*oa1)[j]; - Object *o2 = (*oa2)[j]; - if (!match(o1, o2, tempdecl, sc)) - { - return 0; - } - } - return 1; -} - -/**************************************** - * This makes a 'pretty' version of the template arguments. - * It's analogous to genIdent() which makes a mangled version. - */ - -void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) -{ - //printf("ObjectToCBuffer()\n"); - Type *t = isType(oarg); - Expression *e = isExpression(oarg); - Dsymbol *s = isDsymbol(oarg); - Tuple *v = isTuple(oarg); - /* The logic of this should match what genIdent() does. The _dynamic_cast() - * function relies on all the pretty strings to be unique for different classes - * (see Bugzilla 7375). - * Perhaps it would be better to demangle what genIdent() does. - */ - if (t) - { //printf("\tt: %s ty = %d\n", t->toChars(), t->ty); - t->toCBuffer(buf, NULL, hgs); - } - else if (e) - { - if (e->op == TOKvar) - e = e->optimize(WANTvalue); // added to fix Bugzilla 7375 - e->toCBuffer(buf, hgs); - } - else if (s) - { - char *p = s->ident ? s->ident->toChars() : s->toChars(); - buf->writestring(p); - } - else if (v) - { - Objects *args = &v->objects; - for (size_t i = 0; i < args->dim; i++) - { - if (i) - buf->writeByte(','); - Object *o = (*args)[i]; - ObjectToCBuffer(buf, hgs, o); - } - } - else if (!oarg) - { - buf->writestring("NULL"); - } - else - { -#ifdef DEBUG - printf("bad Object = %p\n", oarg); -#endif - assert(0); - } -} - -#if DMDV2 -Object *objectSyntaxCopy(Object *o) -{ - if (!o) - return NULL; - Type *t = isType(o); - if (t) - return t->syntaxCopy(); - Expression *e = isExpression(o); - if (e) - return e->syntaxCopy(); - return o; -} -#endif - - -/* ======================== TemplateDeclaration ============================= */ - -TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, - TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs) - : ScopeDsymbol(id) -{ -#if LOG - printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars()); -#endif -#if 0 - if (parameters) - for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = (*parameters)[i]; - //printf("\tparameter[%d] = %p\n", i, tp); - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - - if (ttp) - { - printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); - } - } -#endif - this->loc = loc; - this->parameters = parameters; - this->origParameters = parameters; - this->constraint = constraint; - this->members = decldefs; - this->overnext = NULL; - this->overroot = NULL; - this->semanticRun = PASSinit; - this->onemember = NULL; - - // Compute in advance for Ddoc's use - if (members) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s)) - { - if (s && s->ident && s->ident->equals(ident)) - { - onemember = s; - s->parent = this; - } - } - } -} - -Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) -{ - //printf("TemplateDeclaration::syntaxCopy()\n"); - TemplateDeclaration *td; - TemplateParameters *p; - - p = NULL; - if (parameters) - { - p = new TemplateParameters(); - p->setDim(parameters->dim); - for (size_t i = 0; i < p->dim; i++) - { TemplateParameter *tp = (*parameters)[i]; - (*p)[i] = tp->syntaxCopy(); - } - } - Expression *e = NULL; - if (constraint) - e = constraint->syntaxCopy(); - Dsymbols *d = Dsymbol::arraySyntaxCopy(members); - td = new TemplateDeclaration(loc, ident, p, e, d); - -#if IN_LLVM - // LDC - td->intrinsicName = intrinsicName; -#endif - - return td; -} - -void TemplateDeclaration::semantic(Scope *sc) -{ -#if LOG - printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars()); - printf("sc->stc = %llx\n", sc->stc); - printf("sc->module = %s\n", sc->module->toChars()); -#endif - if (semanticRun) - return; // semantic() already run - semanticRun = PASSsemantic; - - if (sc->func) - { -#if DMDV1 - error("cannot declare template at function scope %s", sc->func->toChars()); -#endif - } - - if (/*global.params.useArrayBounds &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - - // FIXME: LDC - //sc->module->toModuleArray(); - } - - if (/*global.params.useAssert &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - - // FIXME: LDC - //sc->module->toModuleAssert(); - } - -#if DMDV2 - if (/*global.params.useUnitTests &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - sc->module->toModuleUnittest(); - } -#endif - - /* Remember Scope for later instantiations, but make - * a copy since attributes can change. - */ - if (!this->scope) - { this->scope = new Scope(*sc); - this->scope->setNoFree(); - } - - // Set up scope for parameters - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = sc->parent; - Scope *paramscope = sc->push(paramsym); - paramscope->parameterSpecialization = 1; - paramscope->stc = 0; - - if (global.params.doDocComments) - { - origParameters = new TemplateParameters(); - origParameters->setDim(parameters->dim); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - origParameters->data[i] = (void *)tp->syntaxCopy(); - } - } - - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - - tp->declareParameter(paramscope); - } - - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - - tp->semantic(paramscope); - if (i + 1 != parameters->dim && tp->isTemplateTupleParameter()) - error("template tuple parameter must be last one"); - } - - paramscope->pop(); - - // Compute again - onemember = NULL; - if (members) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s)) - { - if (s && s->ident && s->ident->equals(ident)) - { - onemember = s; - s->parent = this; - } - } - } - - /* BUG: should check: - * o no virtual functions or non-static data members of classes - */ -} - -const char *TemplateDeclaration::kind() -{ - return (onemember && onemember->isAggregateDeclaration()) - ? onemember->kind() - : (char *)"template"; -} - -/********************************** - * Overload existing TemplateDeclaration 'this' with the new one 's'. - * Return !=0 if successful; i.e. no conflict. - */ - -int TemplateDeclaration::overloadInsert(Dsymbol *s) -{ - TemplateDeclaration **pf; - TemplateDeclaration *f; - -#if LOG - printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars()); -#endif - f = s->isTemplateDeclaration(); - if (!f) - return FALSE; - TemplateDeclaration *pthis = this; - for (pf = &pthis; *pf; pf = &(*pf)->overnext) - { -#if 0 - // Conflict if TemplateParameter's match - // Will get caught anyway later with TemplateInstance, but - // should check it now. - TemplateDeclaration *f2 = *pf; - - if (f->parameters->dim != f2->parameters->dim) - goto Lcontinue; - - for (size_t i = 0; i < f->parameters->dim; i++) - { TemplateParameter *p1 = (TemplateParameter *)f->parameters->data[i]; - TemplateParameter *p2 = (TemplateParameter *)f2->parameters->data[i]; - - if (!p1->overloadMatch(p2)) - goto Lcontinue; - } - -#if LOG - printf("\tfalse: conflict\n"); -#endif - return FALSE; - - Lcontinue: - ; -#endif - } - - f->overroot = this; - *pf = f; -#if LOG - printf("\ttrue: no conflict\n"); -#endif - return TRUE; -} - -/*************************************** - * Given that ti is an instance of this TemplateDeclaration, - * deduce the types of the parameters to this, and store - * those deduced types in dedtypes[]. - * Input: - * flag 1: don't do semantic() because of dummy types - * 2: don't change types in matchArg() - * Output: - * dedtypes deduced arguments - * Return match level. - */ - -MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, - Objects *dedtypes, int flag) -{ MATCH m; - size_t dedtypes_dim = dedtypes->dim; - -#define LOGM 0 -#if LOGM - printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag); -#endif - -#if 0 - printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim); - if (ti->tiargs->dim) - printf("ti->tiargs->dim = %d, [0] = %p\n", - ti->tiargs->dim, - ti->tiargs->data[0]); -#endif - dedtypes->zero(); - - size_t parameters_dim = parameters->dim; - int variadic = isVariadic() != NULL; - - // If more arguments than parameters, no match - if (ti->tiargs->dim > parameters_dim && !variadic) - { -#if LOGM - printf(" no match: more arguments than parameters\n"); -#endif - return MATCHnomatch; - } - - assert(dedtypes_dim == parameters_dim); - assert(dedtypes_dim >= ti->tiargs->dim || variadic); - - // Set up scope for parameters - assert((size_t)scope > 0x10000); - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = scope->parent; - Scope *paramscope = scope->push(paramsym); - paramscope->stc = 0; - - // Attempt type deduction - m = MATCHexact; - for (size_t i = 0; i < dedtypes_dim; i++) - { MATCH m2; - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - Declaration *sparam; - - //printf("\targument [%d]\n", i); -#if LOGM - //printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null"); - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - if (ttp) - printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); -#endif - -#if DMDV1 - m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); -#else - m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam, (flag & 2) ? 1 : 0); - -#endif - //printf("\tm2 = %d\n", m2); - - if (m2 == MATCHnomatch) - { -#if 0 - printf("\tmatchArg() for parameter %i failed\n", i); -#endif - goto Lnomatch; - } - - if (m2 < m) - m = m2; - - if (!flag) - sparam->semantic(paramscope); - if (!paramscope->insert(sparam)) - goto Lnomatch; - } - - if (!flag) - { - /* Any parameter left without a type gets the type of - * its corresponding arg - */ - for (size_t i = 0; i < dedtypes_dim; i++) - { - if (!(*dedtypes)[i]) - { assert(i < ti->tiargs->dim); - (*dedtypes)[i] = (Type *)(*ti->tiargs)[i]; - } - } - } - -#if DMDV2 - if (m && constraint && !flag) - { /* Check to see if constraint is satisfied. - */ - makeParamNamesVisibleInConstraint(paramscope, fargs); - Expression *e = constraint->syntaxCopy(); - Scope *sc = paramscope->push(); - - /* There's a chicken-and-egg problem here. We don't know yet if this template - * instantiation will be a local one (isnested is set), and we won't know until - * after selecting the correct template. Thus, function we're nesting inside - * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel(). - * Workaround the problem by setting a flag to relax the checking on frame errors. - */ - sc->flags |= SCOPEstaticif; - - FuncDeclaration *fd = onemember && onemember->toAlias() ? - onemember->toAlias()->isFuncDeclaration() : NULL; - Dsymbol *s = parent; - while (s->isTemplateInstance() || s->isTemplateMixin()) - s = s->parent; - AggregateDeclaration *ad = s->isAggregateDeclaration(); - VarDeclaration *vthissave; - if (fd && ad) - { - vthissave = fd->vthis; - fd->vthis = fd->declareThis(paramscope, ad); - } - - e = e->semantic(sc); - if (e->op == TOKerror) - goto Lnomatch; - - if (fd && fd->vthis) - fd->vthis = vthissave; - - sc->pop(); - e = e->ctfeInterpret(); - if (e->isBool(TRUE)) - ; - else if (e->isBool(FALSE)) - goto Lnomatch; - else - { - e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); - } - } -#endif - -#if LOGM - // Print out the results - printf("--------------------------\n"); - printf("template %s\n", toChars()); - printf("instance %s\n", ti->toChars()); - if (m) - { - for (size_t i = 0; i < dedtypes_dim; i++) - { - TemplateParameter *tp = (*parameters)[i]; - Object *oarg; - - printf(" [%d]", i); - - if (i < ti->tiargs->dim) - oarg = (*ti->tiargs)[i]; - else - oarg = NULL; - tp->print(oarg, (*dedtypes)[i]); - } - } - else - goto Lnomatch; -#endif - -#if LOGM - printf(" match = %d\n", m); -#endif - goto Lret; - -Lnomatch: -#if LOGM - printf(" no match\n"); -#endif - m = MATCHnomatch; - -Lret: - paramscope->pop(); -#if LOGM - printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); -#endif - return m; -} - -/******************************************** - * Determine partial specialization order of 'this' vs td2. - * Returns: - * match this is at least as specialized as td2 - * 0 td2 is more specialized than this - */ - -MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2) -{ - /* This works by taking the template parameters to this template - * declaration and feeding them to td2 as if it were a template - * instance. - * If it works, then this template is at least as specialized - * as td2. - */ - - TemplateInstance ti(0, ident); // create dummy template instance - Objects dedtypes; - -#define LOG_LEASTAS 0 - -#if LOG_LEASTAS - printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars()); -#endif - - // Set type arguments to dummy template instance to be types - // generated from the parameters to this template declaration - ti.tiargs = new Objects(); - ti.tiargs->setDim(parameters->dim); - for (size_t i = 0; i < ti.tiargs->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - - void *p = tp->dummyArg(); - if (p) - ti.tiargs->data[i] = p; - else - ti.tiargs->setDim(i); - } - - // Temporary Array to hold deduced types - //dedtypes.setDim(parameters->dim); - dedtypes.setDim(td2->parameters->dim); - - // Attempt a type deduction - MATCH m = td2->matchWithInstance(&ti, &dedtypes, 1); - if (m) - { - /* A non-variadic template is more specialized than a - * variadic one. - */ - if (isVariadic() && !td2->isVariadic()) - goto L1; - -#if LOG_LEASTAS - printf(" matches %d, so is least as specialized\n", m); -#endif - return m; - } - L1: -#if LOG_LEASTAS - printf(" doesn't match, so is not as specialized\n"); -#endif - return MATCHnomatch; -} - - -/************************************************* - * Match function arguments against a specific template function. - * Input: - * loc instantiation location - * targsi Expression/Type initial list of template arguments - * ethis 'this' argument if !NULL - * fargs arguments to function - * Output: - * dedargs Expression/Type deduced template arguments - * Returns: - * match level - */ - -MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Objects *targsi, - Expression *ethis, Expressions *fargs, - Objects *dedargs) -{ - size_t nfparams; - size_t nfargs; - size_t nargsi; // array size of targsi - int fptupindex = -1; - int tuple_dim = 0; - MATCH match = MATCHexact; - FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); - Parameters *fparameters; // function parameter list - int fvarargs; // function varargs - Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T - -#if 0 - printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars()); - for (size_t i = 0; i < fargs->dim; i++) - { Expression *e = (Expression *)fargs->data[i]; - printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); - } - printf("fd = %s\n", fd->toChars()); - printf("fd->type = %p\n", fd->type); -#endif - - assert((size_t)scope > 0x10000); - - dedargs->setDim(parameters->dim); - dedargs->zero(); - - dedtypes.setDim(parameters->dim); - dedtypes.zero(); - - // Set up scope for parameters - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = scope->parent; - Scope *paramscope = scope->push(paramsym); - paramscope->stc = 0; - - TemplateTupleParameter *tp = isVariadic(); - -#if 0 - for (size_t i = 0; i < dedargs->dim; i++) - { - printf("\tdedarg[%d] = ", i); - Object *oarg = (Object *)dedargs->data[i]; - if (oarg) printf("%s", oarg->toChars()); - printf("\n"); - } -#endif - - - nargsi = 0; - if (targsi) - { // Set initial template arguments - - nargsi = targsi->dim; - size_t n = parameters->dim; - if (nargsi > n) - { if (!tp) - goto Lnomatch; - dedargs->setDim(nargsi); - dedargs->zero(); - } - else - n = nargsi; - - /* Test case for nargsi instead of n: - * string foo(T...)() { return ""; } - * void main() { foo!(int, char)(); } - */ - //memcpy(dedargs->data, targsi->data, n * sizeof(*dedargs->data)); - memcpy(dedargs->data, targsi->data, nargsi * sizeof(*dedargs->data)); - - for (size_t i = 0; i < n; i++) - { assert(i < parameters->dim); - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - MATCH m; - Declaration *sparam = NULL; - - m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); - //printf("\tdeduceType m = %d\n", m); - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - - sparam->semantic(paramscope); - if (!paramscope->insert(sparam)) - goto Lnomatch; - } - } -#if 0 - for (size_t i = 0; i < dedargs->dim; i++) - { - printf("\tdedarg[%d] = ", i); - Object *oarg = (Object *)dedargs->data[i]; - if (oarg) printf("%s", oarg->toChars()); - printf("\n"); - } -#endif - - fparameters = fd->getParameters(&fvarargs); - nfparams = Parameter::dim(fparameters); // number of function parameters - nfargs = fargs ? fargs->dim : 0; // number of function arguments - - /* Check for match of function arguments with variadic template - * parameter, such as: - * - * template Foo(T, A...) { void Foo(T t, A a); } - * void main() { Foo(1,2,3); } - */ - if (tp) // if variadic - { - if (nfparams == 0 && nfargs != 0) // if no function parameters - { - Tuple *t = new Tuple(); - //printf("t = %p\n", t); - dedargs->data[parameters->dim - 1] = (void *)t; - declareParameter(paramscope, tp, t); - goto L2; - } - else if (nfargs < nfparams - 1) - goto L1; - else - { - /* Figure out which of the function parameters matches - * the tuple template parameter. Do this by matching - * type identifiers. - * Set the index of this function parameter to fptupindex. - */ - for (fptupindex = 0; fptupindex < nfparams; fptupindex++) - { - Parameter *fparam = (Parameter *)fparameters->data[fptupindex]; - if (fparam->type->ty != Tident) - continue; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (!tp->ident->equals(tid->ident) || tid->idents.dim) - continue; - - if (fvarargs) // variadic function doesn't - goto Lnomatch; // go with variadic template - - /* The types of the function arguments - * now form the tuple argument. - */ - Tuple *t = new Tuple(); - dedargs->tdata()[parameters->dim - 1] = t; - - tuple_dim = nfargs - (nfparams - 1); - t->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { Expression *farg = fargs->tdata()[fptupindex + i]; - - // Check invalid arguments to detect errors early. - if (farg->op == TOKerror || farg->type->ty == Terror) - goto Lnomatch; - - t->objects.data[i] = (void *)farg->type; - } - declareParameter(paramscope, tp, t); - goto L2; - } - fptupindex = -1; - } - } - -L1: - if (nfparams == nfargs) - ; - else if (nfargs > nfparams) - { - if (fvarargs == 0) - goto Lnomatch; // too many args, no match - match = MATCHconvert; // match ... with a conversion - } - -L2: -#if DMDV2 - if (ethis) - { - // Match 'ethis' to any TemplateThisParameter's - for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; - TemplateThisParameter *ttp = tp->isTemplateThisParameter(); - if (ttp) - { MATCH m; - - Type *t = new TypeIdentifier(0, ttp->ident); - m = ethis->type->deduceType(paramscope, t, parameters, &dedtypes); - if (!m) - goto Lnomatch; - if (m < match) - match = m; // pick worst match - } - } - - // Match attributes of ethis against attributes of fd - if (fd->type) - { - Type *tthis = ethis->type; - unsigned mod = fd->type->mod; - StorageClass stc = scope->stc; - if (stc & (STCshared | STCsynchronized)) - mod |= MODshared; - if (stc & STCimmutable) - mod |= MODimmutable; - if (stc & STCconst) - mod |= MODconst; - if (stc & STCwild) - mod |= MODwild; - // Fix mod - if (mod & MODimmutable) - mod = MODimmutable; - if (mod & MODconst) - mod &= ~STCwild; - if (tthis->mod != mod) - { - if (!MODimplicitConv(tthis->mod, mod)) - goto Lnomatch; - if (MATCHconst < match) - match = MATCHconst; - } - } - } -#endif - - // Loop through the function parameters - for (size_t parami = 0; parami < nfparams; parami++) - { - /* Skip over function parameters which wound up - * as part of a template tuple parameter. - */ - if (parami == fptupindex) - continue; - /* Set i = index into function arguments - * Function parameters correspond to function arguments as follows. - * Note that tuple_dim may be zero, and there may be default or - * variadic arguments at the end. - * arg [0..fptupindex] == param[0..fptupindex] - * arg [fptupindex..fptupindex+tuple_dim] == param[fptupindex] - * arg[fputupindex+dim.. ] == param[fptupindex+1.. ] - */ - size_t i = parami; - if (fptupindex >= 0 && parami > fptupindex) - i += tuple_dim - 1; - - Parameter *fparam = Parameter::getNth(fparameters, parami); - - if (i >= nfargs) // if not enough arguments - { - if (fparam->defaultArg) - { /* Default arguments do not participate in template argument - * deduction. - */ - goto Lmatch; - } - } - else - { - Expression *farg = fargs->tdata()[i]; - - // Check invalid arguments to detect errors early. - if (farg->op == TOKerror || farg->type->ty == Terror) - goto Lnomatch; - -#if 0 - printf("\tfarg->type = %s\n", farg->type->toChars()); - printf("\tfparam->type = %s\n", fparam->type->toChars()); -#endif - Type *argtype = farg->type; - -#if DMDV2 - /* Allow string literals which are type [] to match with [dim] - */ - if (farg->op == TOKstring) - { StringExp *se = (StringExp *)farg; - if (!se->committed && argtype->ty == Tarray && - fparam->type->toBasetype()->ty == Tsarray) - { - argtype = new TypeSArray(argtype->nextOf(), new IntegerExp(se->loc, se->len, Type::tindex)); - argtype = argtype->semantic(se->loc, NULL); - argtype = argtype->invariantOf(); - } - } - - /* Allow implicit function literals to delegate conversion - */ - if (farg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)farg; - Type *tp = fparam->type; - Expression *e = fe->inferType(tp, 1, parameters); - if (!e) - goto Lvarargs; - farg = e; - argtype = farg->type; - } - - if (!(fparam->storageClass & STClazy) && argtype->ty == Tvoid) - goto Lnomatch; - - /* Remove top const for dynamic array types and pointer types - */ - if ((argtype->ty == Tarray || argtype->ty == Tpointer) && - !argtype->isMutable() && - (!(fparam->storageClass & STCref) || - (fparam->storageClass & STCauto) && !farg->isLvalue())) - { - argtype = argtype->mutableOf(); - } -#endif - - MATCH m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes); - //printf("\tdeduceType m = %d\n", m); - - /* If no match, see if there's a conversion to a delegate - */ - if (!m && fparam->type->toBasetype()->ty == Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype(); - TypeFunction *tf = (TypeFunction *)td->next; - - if (!tf->varargs && Parameter::dim(tf->parameters) == 0) - { - m = farg->type->deduceType(paramscope, tf->next, parameters, &dedtypes); - if (!m && tf->next->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - //printf("\tm2 = %d\n", m); - } - - if (m) - { if (m < match) - match = m; // pick worst match - continue; - } - } - - /* The following code for variadic arguments closely - * matches TypeFunction::callMatch() - */ - if (!(fvarargs == 2 && i + 1 == nfparams)) - goto Lnomatch; - - /* Check for match with function parameter T... - */ - Type *tb = fparam->type->toBasetype(); - switch (tb->ty) - { - // Perhaps we can do better with this, see TypeFunction::callMatch() - case Tsarray: - { TypeSArray *tsa = (TypeSArray *)tb; - dinteger_t sz = tsa->dim->toInteger(); - if (sz != nfargs - i) - goto Lnomatch; - } - case Tarray: - { TypeArray *ta = (TypeArray *)tb; - for (; i < nfargs; i++) - { - Expression *arg = (Expression *)fargs->data[i]; - assert(arg); - MATCH m; - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type *tret = fparam->isLazyArray(); - if (tret) - { - if (ta->next->equals(arg->type)) - { m = MATCHexact; - } - else - { - m = arg->implicitConvTo(tret); - if (m == MATCHnomatch) - { - if (tret->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - } - } - else - { - m = arg->type->deduceType(paramscope, ta->next, parameters, &dedtypes); - //m = arg->implicitConvTo(ta->next); - } - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - } - goto Lmatch; - } - case Tclass: - case Tident: - goto Lmatch; - - default: - goto Lnomatch; - } - } - -Lmatch: - - /* Fill in any missing arguments with their defaults. - */ - for (size_t i = nargsi; i < dedargs->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - //printf("tp[%d] = %s\n", i, tp->ident->toChars()); - /* For T:T*, the dedargs is the T*, dedtypes is the T - * But for function templates, we really need them to match - */ - Object *oarg = (Object *)dedargs->data[i]; - Object *oded = (Object *)dedtypes.data[i]; - //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); - //if (oarg) printf("oarg: %s\n", oarg->toChars()); - //if (oded) printf("oded: %s\n", oded->toChars()); - if (!oarg) - { - if (oded) - { - if (tp->specialization()) - { /* The specialization can work as long as afterwards - * the oded == oarg - */ - Declaration *sparam; - dedargs->data[i] = (void *)oded; - MATCH m2 = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam, 0); - //printf("m2 = %d\n", m2); - if (!m2) - goto Lnomatch; - if (m2 < match) - match = m2; // pick worst match - if (dedtypes.data[i] != oded) - error("specialization not allowed for deduced parameter %s", tp->ident->toChars()); - } - } - else - { oded = tp->defaultArg(loc, paramscope); - if (!oded) - goto Lnomatch; - } - declareParameter(paramscope, tp, oded); - dedargs->data[i] = (void *)oded; - } - } - -#if DMDV2 - if (constraint) - { /* Check to see if constraint is satisfied. - * Most of this code appears twice; this is a good candidate for refactoring. - */ - makeParamNamesVisibleInConstraint(paramscope, fargs); - Expression *e = constraint->syntaxCopy(); - paramscope->flags |= SCOPEstaticif; - - /* Detect recursive attempts to instantiate this template declaration, - * Bugzilla 4072 - * void foo(T)(T x) if (is(typeof(foo(x)))) { } - * static assert(!is(typeof(foo(7)))); - * Recursive attempts are regarded as a constraint failure. - */ - int nmatches = 0; - for (Previous *p = previous; p; p = p->prev) - { - if (arrayObjectMatch(p->dedargs, dedargs, this, sc)) - { - //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars()); - /* It must be a subscope of p->sc, other scope chains are not recursive - * instantiations. - */ - for (Scope *scx = sc; scx; scx = scx->enclosing) - { - if (scx == p->sc) - goto Lnomatch; - } - } - /* BUG: should also check for ref param differences - */ - } - - Previous pr; - pr.prev = previous; - pr.sc = paramscope; - pr.dedargs = dedargs; - previous = ≺ // add this to threaded list - - int nerrors = global.errors; - - FuncDeclaration *fd = onemember && onemember->toAlias() ? - onemember->toAlias()->isFuncDeclaration() : NULL; - Dsymbol *s = parent; - while (s->isTemplateInstance() || s->isTemplateMixin()) - s = s->parent; - AggregateDeclaration *ad = s->isAggregateDeclaration(); - VarDeclaration *vthissave; - if (fd && ad) - { - vthissave = fd->vthis; - fd->vthis = fd->declareThis(paramscope, ad); - } - - e = e->semantic(paramscope); - - if (fd && fd->vthis) - fd->vthis = vthissave; - - previous = pr.prev; // unlink from threaded list - - if (nerrors != global.errors) // if any errors from evaluating the constraint, no match - goto Lnomatch; - if (e->op == TOKerror) - goto Lnomatch; - - e = e->ctfeInterpret(); - if (e->isBool(TRUE)) - ; - else if (e->isBool(FALSE)) - goto Lnomatch; - else - { - e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); - } - } -#endif - -#if 0 - for (i = 0; i < dedargs->dim; i++) - { Type *t = (*dedargs)[i]; - printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); - } -#endif - - paramscope->pop(); - //printf("\tmatch %d\n", match); - return match; - -Lnomatch: - paramscope->pop(); - //printf("\tnomatch\n"); - return MATCHnomatch; -} - -/************************************************** - * Declare template parameter tp with value o, and install it in the scope sc. - */ - -void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o) -{ - //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o); - - Type *targ = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - - Dsymbol *s; - - // See if tp->ident already exists with a matching definition - Dsymbol *scopesym; - s = sc->search(loc, tp->ident, &scopesym); - if (s && scopesym == sc->scopesym) - { - TupleDeclaration *td = s->isTupleDeclaration(); - if (va && td) - { Tuple tup; - tup.objects = *td->objects; - if (match(va, &tup, this, sc)) - { - return; - } - } - } - if (ea && ea->op == TOKtype) - targ = ea->type; - else if (ea && ea->op == TOKimport) - sa = ((ScopeExp *)ea)->sds; - else if (ea && (ea->op == TOKthis || ea->op == TOKsuper)) - sa = ((ThisExp *)ea)->var; - - if (targ) - { - //printf("type %s\n", targ->toChars()); - s = new AliasDeclaration(0, tp->ident, targ); - } - else if (sa) - { - //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars()); - s = new AliasDeclaration(0, tp->ident, sa); - } - else if (ea) - { - // tdtypes.data[i] always matches ea here - Initializer *init = new ExpInitializer(loc, ea); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - assert(tvp); - - VarDeclaration *v = new VarDeclaration(loc, tvp->valType, tp->ident, init); - v->storage_class = STCconst; - s = v; - } - else if (va) - { - //printf("\ttuple\n"); - s = new TupleDeclaration(loc, tp->ident, &va->objects); - } - else - { -#ifdef DEBUG - o->print(); -#endif - assert(0); - } - if (!sc->insert(s)) - error("declaration %s is already defined", tp->ident->toChars()); - s->semantic(sc); -} - -/************************************** - * Determine if TemplateDeclaration is variadic. - */ - -TemplateTupleParameter *isVariadic(TemplateParameters *parameters) -{ size_t dim = parameters->dim; - TemplateTupleParameter *tp = NULL; - - if (dim) - tp = ((TemplateParameter *)parameters->data[dim - 1])->isTemplateTupleParameter(); - return tp; -} - -TemplateTupleParameter *TemplateDeclaration::isVariadic() -{ - return ::isVariadic(parameters); -} - -/*********************************** - * We can overload templates. - */ - -int TemplateDeclaration::isOverloadable() -{ - return 1; -} - -/************************************************* - * Given function arguments, figure out which template function - * to expand, and return that function. - * If no match, give error message and return NULL. - * Input: - * sc instantiation scope - * loc instantiation location - * targsi initial list of template arguments - * ethis if !NULL, the 'this' pointer argument - * fargs arguments to function - * flags 1: do not issue error message on no match, just return NULL - */ - -FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, - Objects *targsi, Expression *ethis, Expressions *fargs, int flags) -{ - MATCH m_best = MATCHnomatch; - TemplateDeclaration *td_ambig = NULL; - TemplateDeclaration *td_best = NULL; - Objects *tdargs = new Objects(); - TemplateInstance *ti; - FuncDeclaration *fd; - -#if 0 - printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars()); - printf(" targsi:\n"); - if (targsi) - { for (size_t i = 0; i < targsi->dim; i++) - { Object *arg = (*targsi)[i]; - printf("\t%s\n", arg->toChars()); - } - } - printf(" fargs:\n"); - for (size_t i = 0; i < fargs->dim; i++) - { Expression *arg = (*fargs)[i]; - printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); - //printf("\tty = %d\n", arg->type->ty); - } - printf("stc = %llx\n", scope->stc); -#endif - - for (TemplateDeclaration *td = this; td; td = td->overnext) - { - if (!td->semanticRun) - { - error("forward reference to template %s", td->toChars()); - goto Lerror; - } - if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) - { - error("is not a function template"); - goto Lerror; - } - - Objects dedargs; - - MATCH m = td->deduceFunctionTemplateMatch(loc, targsi, ethis, fargs, &dedargs); - //printf("deduceFunctionTemplateMatch = %d\n", m); - if (!m) // if no match - continue; - - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; - - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best); - MATCH c2 = td_best->leastAsSpecialized(td); - //printf("c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - else - goto Lambig; - } - - Lambig: // td_best and td are ambiguous - td_ambig = td; - continue; - - Ltd_best: // td_best is the best match so far - td_ambig = NULL; - continue; - - Ltd: // td is the new best match - td_ambig = NULL; - assert((size_t)td->scope > 0x10000); - td_best = td; - m_best = m; - tdargs->setDim(dedargs.dim); - memcpy(tdargs->tdata(), dedargs.tdata(), tdargs->dim * sizeof(void *)); - continue; - } - if (!td_best) - { - error(loc, "does not match any function template declaration"); - goto Lerror; - } - if (td_ambig) - { - ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - kind(), parent->toPrettyChars(), ident->toChars(), - td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), - td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); - } - - /* The best match is td_best with arguments tdargs. - * Now instantiate the template. - */ - assert((size_t)td_best->scope > 0x10000); - ti = new TemplateInstance(loc, td_best, tdargs); - ti->semantic(sc); - fd = ti->toAlias()->isFuncDeclaration(); - if (!fd) - goto Lerror; - - /* As Bugzilla 3682 shows, a template instance can be matched while instantiating - * that same template. Thus, the function type can be incomplete. Complete it. - */ - { TypeFunction *tf = (TypeFunction *)fd->type; - assert(tf->ty == Tfunction); - if (tf->next) - fd->type = tf->semantic(loc, sc); - } - - return fd; - - Lerror: -#if DMDV2 - if (!(flags & 1)) -#endif - { - HdrGenState hgs; - - OutBuffer bufa; - Objects *args = targsi; - if (args) - { for (size_t i = 0; i < args->dim; i++) - { - if (i) - bufa.writeByte(','); - Object *oarg = (*args)[i]; - ObjectToCBuffer(&bufa, &hgs, oarg); - } - } - - OutBuffer buf; - argExpTypesToCBuffer(&buf, fargs, &hgs); - if (this->overnext) - ::error(this->loc, "%s %s.%s cannot deduce template function from argument types !(%s)(%s)", - kind(), parent->toPrettyChars(), ident->toChars(), - bufa.toChars(), buf.toChars()); - else - error("cannot deduce template function from argument types !(%s)(%s)", - bufa.toChars(), buf.toChars()); - } - return NULL; -} - -bool TemplateDeclaration::hasStaticCtorOrDtor() -{ - return FALSE; // don't scan uninstantiated templates -} - -void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ -#if 0 // Should handle template functions for doc generation - if (onemember && onemember->isFuncDeclaration()) - buf->writestring("foo "); -#endif - if (hgs->ddoc) - buf->writestring(kind()); - else - buf->writestring("template"); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - buf->writeByte('('); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - if (hgs->ddoc) - tp = (TemplateParameter *)origParameters->data[i]; - if (i) - buf->writeByte(','); - tp->toCBuffer(buf, hgs); - } - buf->writeByte(')'); -#if DMDV2 - if (constraint) - { buf->writestring(" if ("); - constraint->toCBuffer(buf, hgs); - buf->writeByte(')'); - } -#endif - - if (hgs->hdrgen) - { - hgs->tpltMember++; - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->toCBuffer(buf, hgs); - } - buf->writebyte('}'); - buf->writenl(); - hgs->tpltMember--; - } -} - - -char *TemplateDeclaration::toChars() -{ OutBuffer buf; - HdrGenState hgs; - - memset(&hgs, 0, sizeof(hgs)); - buf.writestring(ident->toChars()); - buf.writeByte('('); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - if (i) - buf.writeByte(','); - tp->toCBuffer(&buf, &hgs); - } - buf.writeByte(')'); -#if DMDV2 - if (constraint) - { buf.writestring(" if ("); - constraint->toCBuffer(&buf, &hgs); - buf.writeByte(')'); - } -#endif - buf.writeByte(0); - return (char *)buf.extractData(); -} - -/* ======================== Type ============================================ */ - -/**** - * Given an identifier, figure out which TemplateParameter it is. - * Return -1 if not found. - */ - -int templateIdentifierLookup(Identifier *id, TemplateParameters *parameters) -{ - for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; - - if (tp->ident->equals(id)) - return i; - } - return -1; -} - -int templateParameterLookup(Type *tparam, TemplateParameters *parameters) -{ - assert(tparam->ty == Tident); - TypeIdentifier *tident = (TypeIdentifier *)tparam; - //printf("\ttident = '%s'\n", tident->toChars()); - if (tident->idents.dim == 0) - { - return templateIdentifierLookup(tident->ident, parameters); - } - return -1; -} - -/* These form the heart of template argument deduction. - * Given 'this' being the type argument to the template instance, - * it is matched against the template declaration parameter specialization - * 'tparam' to determine the type to be used for the parameter. - * Example: - * template Foo(T:T*) // template declaration - * Foo!(int*) // template instantiation - * Input: - * this = int* - * tparam = T* - * parameters = [ T:T* ] // Array of TemplateParameter's - * Output: - * dedtypes = [ int ] // Array of Expression/Type's - */ - -MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes) -{ -#if 0 - printf("Type::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - if (!tparam) - goto Lnomatch; - - if (this == tparam) - goto Lexact; - - if (tparam->ty == Tident) - { - // Determine which parameter tparam is - int i = templateParameterLookup(tparam, parameters); - if (i == -1) - { - if (!sc) - goto Lnomatch; - - /* Need a loc to go with the semantic routine. - */ - Loc loc; - if (parameters->dim) - { - TemplateParameter *tp = parameters->tdata()[0]; - loc = tp->loc; - } - - /* BUG: what if tparam is a template instance, that - * has as an argument another Tident? - */ - tparam = tparam->semantic(loc, sc); - assert(tparam->ty != Tident); - return deduceType(sc, tparam, parameters, dedtypes); - } - - TemplateParameter *tp = parameters->tdata()[i]; - - // Found the corresponding parameter tp - if (!tp->isTemplateTypeParameter()) - goto Lnomatch; - Type *at = (Type *)dedtypes->data[i]; - if (!at) - { - dedtypes->data[i] = (void *)this; - goto Lexact; - } - if (equals(at)) - goto Lexact; - else if (ty == Tclass && at->ty == Tclass) - { - return (MATCH) implicitConvTo(at); - } - else if (ty == Tsarray && at->ty == Tarray && - nextOf()->equals(at->nextOf())) - { - goto Lexact; - } - else - goto Lnomatch; - } - else if (tparam->ty == Ttypeof) - { - /* Need a loc to go with the semantic routine. - */ - Loc loc; - if (parameters->dim) - { - TemplateParameter *tp = parameters->tdata()[0]; - loc = tp->loc; - } - - tparam = tparam->semantic(loc, sc); - } - - if (ty != tparam->ty) - { -#if DMDV2 - // Can't instantiate AssociativeArray!() without a scope - if (tparam->ty == Taarray && !((TypeAArray*)tparam)->sc) - ((TypeAArray*)tparam)->sc = sc; - - MATCH m = implicitConvTo(tparam); - if (m == MATCHnomatch) - { - Type *at = aliasthisOf(); - if (at) - m = at->deduceType(sc, tparam, parameters, dedtypes, wildmatch); - } - return m; -#else - return implicitConvTo(tparam); -#endif - } - - if (nextOf()) - return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes); - -Lexact: - return MATCHexact; - -Lnomatch: - return MATCHnomatch; - -#if DMDV2 -Lconst: - return MATCHconst; -#endif -} - -#if DMDV2 -MATCH TypeDArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeDArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} -#endif - -MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes) -{ -#if 0 - printf("TypeSArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // Extra check that array dimensions must match - if (tparam) - { - if (tparam->ty == Tarray) - { MATCH m; - - m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes); - if (m == MATCHexact) - m = MATCHconvert; - return m; - } - - Identifier *id = NULL; - if (tparam->ty == Tsarray) - { - TypeSArray *tp = (TypeSArray *)tparam; - if (tp->dim->op == TOKvar && - ((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter) - { - id = ((VarExp *)tp->dim)->var->ident; - } - else if (dim->toInteger() != tp->dim->toInteger()) - return MATCHnomatch; - } - else if (tparam->ty == Taarray) - { - TypeAArray *tp = (TypeAArray *)tparam; - if (tp->index->ty == Tident && - ((TypeIdentifier *)tp->index)->idents.dim == 0) - { - id = ((TypeIdentifier *)tp->index)->ident; - } - } - if (id) - { - // This code matches code in TypeInstance::deduceType() - int i = templateIdentifierLookup(id, parameters); - if (i == -1) - goto Lnomatch; - TemplateParameter *tprm = parameters->tdata()[i]; - TemplateValueParameter *tvp = tprm->isTemplateValueParameter(); - if (!tvp) - goto Lnomatch; - Expression *e = (Expression *)dedtypes->tdata()[i]; - if (e) - { - if (!dim->equals(e)) - goto Lnomatch; - } - else - { - Type *vt = tvp->valType->semantic(0, sc); - MATCH m = (MATCH)dim->implicitConvTo(vt); - if (!m) - goto Lnomatch; - dedtypes->tdata()[i] = dim; - } - return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes); - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); - - Lnomatch: - return MATCHnomatch; -} - -MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ -#if 0 - printf("TypeAArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // Extra check that index type must match - if (tparam && tparam->ty == Taarray) - { - TypeAArray *tp = (TypeAArray *)tparam; - if (!index->deduceType(sc, tp->index, parameters, dedtypes)) - { - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - //printf("TypeFunction::deduceType()\n"); - //printf("\tthis = %d, ", ty); print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - - // Extra check that function characteristics must match - if (tparam && tparam->ty == Tfunction) - { - TypeFunction *tp = (TypeFunction *)tparam; - if (varargs != tp->varargs || - linkage != tp->linkage) - return MATCHnomatch; - - size_t nfargs = Parameter::dim(this->parameters); - size_t nfparams = Parameter::dim(tp->parameters); - - /* See if tuple match - */ - if (nfparams > 0 && nfargs >= nfparams - 1) - { - /* See if 'A' of the template parameter matches 'A' - * of the type of the last function parameter. - */ - Parameter *fparam = Parameter::getNth(tp->parameters, nfparams - 1); - assert(fparam); - assert(fparam->type); - if (fparam->type->ty != Tident) - goto L1; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (tid->idents.dim) - goto L1; - - /* Look through parameters to find tuple matching tid->ident - */ - size_t tupi = 0; - for (; 1; tupi++) - { if (tupi == parameters->dim) - goto L1; - TemplateParameter *t = (*parameters)[tupi]; - TemplateTupleParameter *tup = t->isTemplateTupleParameter(); - if (tup && tup->ident->equals(tid->ident)) - break; - } - - /* The types of the function arguments [nfparams - 1 .. nfargs] - * now form the tuple argument. - */ - size_t tuple_dim = nfargs - (nfparams - 1); - - /* See if existing tuple, and whether it matches or not - */ - Object *o = (*dedtypes)[tupi]; - if (o) - { // Existing deduced argument must be a tuple, and must match - Tuple *t = isTuple(o); - if (!t || t->objects.dim != tuple_dim) - return MATCHnomatch; - for (size_t i = 0; i < tuple_dim; i++) - { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); - if (!arg->type->equals(t->objects[i])) - return MATCHnomatch; - } - } - else - { // Create new tuple - Tuple *t = new Tuple(); - t->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); - t->objects[i] = arg->type; - } - (*dedtypes)[tupi] = t; - } - nfparams--; // don't consider the last parameter for type deduction - goto L2; - } - - L1: - if (nfargs != nfparams) - return MATCHnomatch; - L2: - for (size_t i = 0; i < nfparams; i++) - { - Parameter *a = Parameter::getNth(this->parameters, i); - Parameter *ap = Parameter::getNth(tp->parameters, i); - if (a->storageClass != ap->storageClass || - !a->type->deduceType(sc, ap->type, parameters, dedtypes)) - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - // Extra check - if (tparam && tparam->ty == Tident) - { - TypeIdentifier *tp = (TypeIdentifier *)tparam; - - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id1 = idents[i]; - Identifier *id2 = tp->idents[i]; - - if (!id1->equals(id2)) - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeInstance::deduceType(Scope *sc, - Type *tparam, TemplateParameters *parameters, - Objects *dedtypes) -{ -#if 0 - printf("TypeInstance::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // Extra check - if (tparam && tparam->ty == Tinstance) - { - TypeInstance *tp = (TypeInstance *)tparam; - - //printf("tempinst->tempdecl = %p\n", tempinst->tempdecl); - //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl); - if (!tp->tempinst->tempdecl) - { //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars()); - if (!tp->tempinst->name->equals(tempinst->name)) - { - /* Handle case of: - * template Foo(T : sa!(T), alias sa) - */ - int i = templateIdentifierLookup(tp->tempinst->name, parameters); - if (i == -1) - { /* Didn't find it as a parameter identifier. Try looking - * it up and seeing if is an alias. See Bugzilla 1454 - */ - TypeIdentifier *tid = new TypeIdentifier(0, tp->tempinst->name); - Type *t; - Expression *e; - Dsymbol *s; - tid->resolve(0, sc, &e, &t, &s); - if (t) - { - s = t->toDsymbol(sc); - if (s) - { TemplateInstance *ti = s->parent->isTemplateInstance(); - s = ti ? ti->tempdecl : NULL; - } - } - if (s) - { - s = s->toAlias(); - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td && td == tempinst->tempdecl) - goto L2; - } - goto Lnomatch; - } - TemplateParameter *tpx = (*parameters)[i]; - // This logic duplicates tpx->matchArg() - TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); - if (!ta) - goto Lnomatch; - Object *sa = tempinst->tempdecl; - if (!sa) - goto Lnomatch; - if (ta->specAlias && sa != ta->specAlias) - goto Lnomatch; - if ((*dedtypes)[i]) - { // Must match already deduced symbol - Object *s = (*dedtypes)[i]; - - if (s != sa) - goto Lnomatch; - } - (*dedtypes)[i] = sa; - } - } - else if (tempinst->tempdecl != tp->tempinst->tempdecl) - goto Lnomatch; - - L2: - - for (size_t i = 0; 1; i++) - { - //printf("\ttest: tempinst->tiargs[%d]\n", i); - Object *o1 = NULL; - if (i < tempinst->tiargs->dim) - o1 = (*tempinst->tiargs)[i]; - else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) - // Pick up default arg - o1 = tempinst->tdtypes[i]; - else if (i >= tp->tempinst->tiargs->dim) - break; - - if (i >= tp->tempinst->tiargs->dim) - goto Lnomatch; - - Object *o2 = (*tp->tempinst->tiargs)[i]; - Type *t2 = isType(o2); - - int j; - if (t2 && - t2->ty == Tident && - i == tp->tempinst->tiargs->dim - 1 && - (j = templateParameterLookup(t2, parameters), j != -1) && - j == parameters->dim - 1 && - (*parameters)[j]->isTemplateTupleParameter()) - { - /* Given: - * struct A(B...) {} - * alias A!(int, float) X; - * static if (is(X Y == A!(Z), Z...)) {} - * deduce that Z is a tuple(int, float) - */ - - /* Create tuple from remaining args - */ - Tuple *vt = new Tuple(); - size_t vtdim = (tempinst->tempdecl->isVariadic() - ? tempinst->tiargs->dim : tempinst->tdtypes.dim) - i; - vt->objects.setDim(vtdim); - for (size_t k = 0; k < vtdim; k++) - { - Object *o; - if (k < tempinst->tiargs->dim) - o = (*tempinst->tiargs)[i + k]; - else // Pick up default arg - o = tempinst->tdtypes[i + k]; - vt->objects[k] = o; - } - - Tuple *v = (Tuple *)(*dedtypes)[j]; - if (v) - { - if (!match(v, vt, tempinst->tempdecl, sc)) - goto Lnomatch; - } - else - (*dedtypes)[j] = vt; - break; //return MATCHexact; - } - else if (!o1) - break; - - Type *t1 = isType(o1); - - Expression *e1 = isExpression(o1); - Expression *e2 = isExpression(o2); - - Dsymbol *s1 = isDsymbol(o1); - Dsymbol *s2 = isDsymbol(o2); - - Tuple *v1 = isTuple(o1); - Tuple *v2 = isTuple(o2); -#if 0 - if (t1) printf("t1 = %s\n", t1->toChars()); - if (t2) printf("t2 = %s\n", t2->toChars()); - if (e1) printf("e1 = %s\n", e1->toChars()); - if (e2) printf("e2 = %s\n", e2->toChars()); - if (s1) printf("s1 = %s\n", s1->toChars()); - if (s2) printf("s2 = %s\n", s2->toChars()); - if (v1) printf("v1 = %s\n", v1->toChars()); - if (v2) printf("v2 = %s\n", v2->toChars()); -#endif - - if (t1 && t2) - { - if (!t1->deduceType(sc, t2, parameters, dedtypes)) - goto Lnomatch; - } - else if (e1 && e2) - { - Le: - e1 = e1->ctfeInterpret(); - e2 = e2->ctfeInterpret(); - - //printf("e1 = %s, type = %s %d\n", e1->toChars(), e1->type->toChars(), e1->type->ty); - //printf("e2 = %s, type = %s %d\n", e2->toChars(), e2->type->toChars(), e2->type->ty); - if (!e1->equals(e2)) - { if (e2->op == TOKvar) - { - /* - * (T:Number!(e2), int e2) - */ - j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); - goto L1; - } - if (!e2->implicitConvTo(e1->type)) - goto Lnomatch; - - e2 = e2->implicitCastTo(sc, e1->type); - e2 = e2->ctfeInterpret(); - if (!e1->equals(e2)) - goto Lnomatch; - } - } - else if (e1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - L1: - if (j == -1) - { - t2->resolve(loc, sc, &e2, &t2, &s2); - if (e2) - goto Le; - goto Lnomatch; - } - TemplateParameter *tp = (*parameters)[j]; - // BUG: use tp->matchArg() instead of the following - TemplateValueParameter *tv = tp->isTemplateValueParameter(); - if (!tv) - goto Lnomatch; - Expression *e = (Expression *)(*dedtypes)[j]; - if (e) - { - if (!e1->equals(e)) - goto Lnomatch; - } - else - { Type *vt = tv->valType->semantic(0, sc); - MATCH m = (MATCH)e1->implicitConvTo(vt); - if (!m) - goto Lnomatch; - (*dedtypes)[j] = e1; - } - } - else if (s1 && s2) - { - Ls: - if (!s1->equals(s2)) - goto Lnomatch; - } - else if (s1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - if (j == -1) - { - t2->resolve(loc, sc, &e2, &t2, &s2); - if (s2) - goto Ls; - goto Lnomatch; - } - TemplateParameter *tp = (*parameters)[j]; - // BUG: use tp->matchArg() instead of the following - TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); - if (!ta) - goto Lnomatch; - Dsymbol *s = (Dsymbol *)(*dedtypes)[j]; - if (s) - { - if (!s1->equals(s)) - goto Lnomatch; - } - else - { - (*dedtypes)[j] = s1; - } - } - else - goto Lnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); - -Lnomatch: - //printf("no match\n"); - return MATCHnomatch; -} - -MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - //printf("TypeStruct::deduceType()\n"); - //printf("\tthis->parent = %s, ", sym->parent->toChars()); print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - - /* If this struct is a template struct, and we're matching - * it against a template instance, convert the struct type - * to a template instance, too, and try again. - */ - TemplateInstance *ti = sym->parent->isTemplateInstance(); - - if (tparam && tparam->ty == Tinstance) - { - if (ti && ti->toAlias() == sym) - { - TypeInstance *t = new TypeInstance(0, ti); - return t->deduceType(sc, tparam, parameters, dedtypes); - } - - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.dim) - { Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1]; - if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) - { - Type *tparent = sym->parent->getType(); - if (tparent) - { - /* Slice off the .foo in S!(T).foo - */ - tpi->idents.dim--; - MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes); - tpi->idents.dim++; - return m; - } - } - } - } - - // Extra check - if (tparam && tparam->ty == Tstruct) - { - TypeStruct *tp = (TypeStruct *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - // Extra check - if (tparam && tparam->ty == Tenum) - { - TypeEnum *tp = (TypeEnum *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - // Extra check - if (tparam && tparam->ty == Ttypedef) - { - TypeTypedef *tp = (TypeTypedef *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -/* Helper for TypeClass::deduceType(). - * Classes can match with implicit conversion to a base class or interface. - * This is complicated, because there may be more than one base class which - * matches. In such cases, one or more parameters remain ambiguous. - * For example, - * - * interface I(X, Y) {} - * class C : I(uint, double), I(char, double) {} - * C x; - * foo(T, U)( I!(T, U) x) - * - * deduces that U is double, but T remains ambiguous (could be char or uint). - * - * Given a baseclass b, and initial deduced types 'dedtypes', this function - * tries to match tparam with b, and also tries all base interfaces of b. - * If a match occurs, numBaseClassMatches is incremented, and the new deduced - * types are ANDed with the current 'best' estimate for dedtypes. - */ -void deduceBaseClassParameters(BaseClass *b, - Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, - Objects *best, int &numBaseClassMatches) -{ - TemplateInstance *parti = b->base ? b->base->parent->isTemplateInstance() : NULL; - if (parti) - { - // Make a temporary copy of dedtypes so we don't destroy it - Objects *tmpdedtypes = new Objects(); - tmpdedtypes->setDim(dedtypes->dim); - memcpy(tmpdedtypes->data, dedtypes->data, dedtypes->dim * sizeof(void *)); - - TypeInstance *t = new TypeInstance(0, parti); - MATCH m = t->deduceType(sc, tparam, parameters, tmpdedtypes); - if (m != MATCHnomatch) - { - // If this is the first ever match, it becomes our best estimate - if (numBaseClassMatches==0) - memcpy(best->data, tmpdedtypes->data, tmpdedtypes->dim * sizeof(void *)); - else for (size_t k = 0; k < tmpdedtypes->dim; ++k) - { - // If we've found more than one possible type for a parameter, - // mark it as unknown. - if (tmpdedtypes->data[k] != best->data[k]) - best->data[k] = dedtypes->data[k]; - } - ++numBaseClassMatches; - } - } - // Now recursively test the inherited interfaces - for (size_t j = 0; j < b->baseInterfaces_dim; ++j) - { - deduceBaseClassParameters( &(b->baseInterfaces)[j], - sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - } - -} - -MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - //printf("TypeClass::deduceType(this = %s)\n", toChars()); - - /* If this class is a template class, and we're matching - * it against a template instance, convert the class type - * to a template instance, too, and try again. - */ - TemplateInstance *ti = sym->parent->isTemplateInstance(); - - if (tparam && tparam->ty == Tinstance) - { - if (ti && ti->toAlias() == sym) - { - TypeInstance *t = new TypeInstance(0, ti); - MATCH m = t->deduceType(sc, tparam, parameters, dedtypes); - // Even if the match fails, there is still a chance it could match - // a base class. - if (m != MATCHnomatch) - return m; - } - - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.dim) - { Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1]; - if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) - { - Type *tparent = sym->parent->getType(); - if (tparent) - { - /* Slice off the .foo in S!(T).foo - */ - tpi->idents.dim--; - MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes); - tpi->idents.dim++; - return m; - } - } - } - - // If it matches exactly or via implicit conversion, we're done - MATCH m = Type::deduceType(sc, tparam, parameters, dedtypes); - if (m != MATCHnomatch) - return m; - - /* There is still a chance to match via implicit conversion to - * a base class or interface. Because there could be more than one such - * match, we need to check them all. - */ - - int numBaseClassMatches = 0; // Have we found an interface match? - - // Our best guess at dedtypes - Objects *best = new Objects(); - best->setDim(dedtypes->dim); - - ClassDeclaration *s = sym; - while(s && s->baseclasses->dim > 0) - { - // Test the base class - deduceBaseClassParameters((BaseClass *)(s->baseclasses->data[0]), - sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - - // Test the interfaces inherited by the base class - for (size_t i = 0; i < s->interfaces_dim; ++i) - { - BaseClass *b = s->interfaces[i]; - deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - } - s = ((BaseClass *)(s->baseclasses->data[0]))->base; - } - - if (numBaseClassMatches == 0) - return MATCHnomatch; - - // If we got at least one match, copy the known types into dedtypes - memcpy(dedtypes->data, best->data, best->dim * sizeof(void *)); - return MATCHconvert; - } - - // Extra check - if (tparam && tparam->ty == Tclass) - { - TypeClass *tp = (TypeClass *)tparam; - - //printf("\t%d\n", (MATCH) implicitConvTo(tp)); - return implicitConvTo(tp); - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -/* ======================== TemplateParameter =============================== */ - -TemplateParameter::TemplateParameter(Loc loc, Identifier *ident) -{ - this->loc = loc; - this->ident = ident; - this->sparam = NULL; -} - -TemplateTypeParameter *TemplateParameter::isTemplateTypeParameter() -{ - return NULL; -} - -TemplateValueParameter *TemplateParameter::isTemplateValueParameter() -{ - return NULL; -} - -TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter() -{ - return NULL; -} - -TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter() -{ - return NULL; -} - -#if DMDV2 -TemplateThisParameter *TemplateParameter::isTemplateThisParameter() -{ - return NULL; -} -#endif - -/* ======================== TemplateTypeParameter =========================== */ - -// type-parameter - -TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, - Type *defaultType) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specType = specType; - this->defaultType = defaultType; -} - -TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter() -{ - return this; -} - -TemplateParameter *TemplateTypeParameter::syntaxCopy() -{ - TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - if (defaultType) - tp->defaultType = defaultType->syntaxCopy(); - return tp; -} - -void TemplateTypeParameter::declareParameter(Scope *sc) -{ - //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars()); - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - sparam = new AliasDeclaration(loc, ident, ti); - if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); -} - -void TemplateTypeParameter::semantic(Scope *sc) -{ - //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars()); - if (specType) - { - specType = specType->semantic(loc, sc); - } -#if 0 // Don't do semantic() until instantiation - if (defaultType) - { - defaultType = defaultType->semantic(loc, sc); - } -#endif -} - -/**************************************** - * Determine if two TemplateParameters are the same - * as far as TemplateDeclaration overloading goes. - * Returns: - * 1 match - * 0 no match - */ - -int TemplateTypeParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - - if (ttp) - { - if (specType != ttp->specType) - goto Lnomatch; - - if (specType && !specType->equals(ttp->specType)) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - -/******************************************* - * Match to a particular TemplateParameter. - * Input: - * i i'th argument - * tiargs[] actual arguments to template instance - * parameters[] template parameters - * dedtypes[] deduced arguments to template instance - * *psparam set to symbol declared and initialized to dedtypes[i] - * flags 1: don't do 'toHeadMutable()' - */ - -MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam, int flags) -{ - //printf("TemplateTypeParameter::matchArg()\n"); - Type *t; - Object *oarg; - MATCH m = MATCHexact; - Type *ta; - - if (i < tiargs->dim) - oarg = (Object *)tiargs->data[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = (Object *)dedtypes->data[i]; - if (!oarg) - goto Lnomatch; - } - } - - ta = isType(oarg); - if (!ta) - goto Lnomatch; - //printf("ta is %s\n", ta->toChars()); - - t = (Type *)dedtypes->data[i]; - - if (specType) - { - //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars()); - MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes); - if (m2 == MATCHnomatch) - { //printf("\tfailed deduceType\n"); - goto Lnomatch; - } - - if (m2 < m) - m = m2; - t = (Type *)dedtypes->data[i]; - } - else - { - // So that matches with specializations are better - m = MATCHconvert; - if (t) - { // Must match already deduced type - - m = MATCHexact; - if (!t->equals(ta)) - { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); - goto Lnomatch; - } - } - } - - if (!t) - { - dedtypes->data[i] = ta; - t = ta; - } - *psparam = new AliasDeclaration(loc, ident, t); - //printf("\tm = %d\n", m); - return m; - -Lnomatch: - *psparam = NULL; - //printf("\tm = %d\n", MATCHnomatch); - return MATCHnomatch; -} - - -void TemplateTypeParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Type *t = isType(oarg); - Type *ta = isType(oded); - - assert(ta); - - if (specType) - printf("\tSpecialization: %s\n", specType->toChars()); - if (defaultType) - printf("\tDefault: %s\n", defaultType->toChars()); - printf("\tParameter: %s\n", t ? t->toChars() : "NULL"); - printf("\tDeduced Type: %s\n", ta->toChars()); -} - - -void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - if (specType) - { - buf->writestring(" : "); - specType->toCBuffer(buf, NULL, hgs); - } - if (defaultType) - { - buf->writestring(" = "); - defaultType->toCBuffer(buf, NULL, hgs); - } -} - - -void *TemplateTypeParameter::dummyArg() -{ Type *t; - - if (specType) - t = specType; - else - { // Use this for alias-parameter's too (?) - t = new TypeIdentifier(loc, ident); - } - return (void *)t; -} - - -Object *TemplateTypeParameter::specialization() -{ - return specType; -} - - -Object *TemplateTypeParameter::defaultArg(Loc loc, Scope *sc) -{ - Type *t; - - t = defaultType; - if (t) - { - t = t->syntaxCopy(); - t = t->semantic(loc, sc); - } - return t; -} - -/* ======================== TemplateThisParameter =========================== */ - -#if DMDV2 -// this-parameter - -TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident, - Type *specType, - Type *defaultType) - : TemplateTypeParameter(loc, ident, specType, defaultType) -{ -} - -TemplateThisParameter *TemplateThisParameter::isTemplateThisParameter() -{ - return this; -} - -TemplateParameter *TemplateThisParameter::syntaxCopy() -{ - TemplateThisParameter *tp = new TemplateThisParameter(loc, ident, specType, defaultType); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - if (defaultType) - tp->defaultType = defaultType->syntaxCopy(); - return tp; -} - -void TemplateThisParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this "); - TemplateTypeParameter::toCBuffer(buf, hgs); -} -#endif - -/* ======================== TemplateAliasParameter ========================== */ - -// alias-parameter - -Dsymbol *TemplateAliasParameter::sdummy = NULL; - -TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, Type *specAliasT, Type *defaultAlias) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specAliasT = specAliasT; - this->defaultAlias = defaultAlias; - - this->specAlias = NULL; -} - -TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() -{ - return this; -} - -TemplateParameter *TemplateAliasParameter::syntaxCopy() -{ - TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specAliasT, defaultAlias); - if (tp->specAliasT) - tp->specAliasT = specAliasT->syntaxCopy(); - if (defaultAlias) - tp->defaultAlias = defaultAlias->syntaxCopy(); - return tp; -} - -void TemplateAliasParameter::declareParameter(Scope *sc) -{ - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - sparam = new AliasDeclaration(loc, ident, ti); - if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); -} - -void TemplateAliasParameter::semantic(Scope *sc) -{ - if (specAliasT) - { - specAlias = specAliasT->toDsymbol(sc); - if (!specAlias) - error(loc, "%s is not a symbol", specAliasT->toChars()); - } -#if 0 // Don't do semantic() until instantiation - if (defaultAlias) - defaultAlias = defaultAlias->semantic(loc, sc); -#endif -} - -int TemplateAliasParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); - - if (tap) - { - if (specAlias != tap->specAlias) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - -MATCH TemplateAliasParameter::matchArg(Scope *sc, - Objects *tiargs, size_t i, TemplateParameters *parameters, - Objects *dedtypes, - Declaration **psparam, int flags) -{ - Dsymbol *sa; - Object *oarg; - Expression *ea; - - //printf("TemplateAliasParameter::matchArg()\n"); - - if (i < tiargs->dim) - oarg = (*tiargs)[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = (*dedtypes)[i]; - if (!oarg) - goto Lnomatch; - } - } - - sa = getDsymbol(oarg); - if (!sa) - goto Lnomatch; - - if (specAlias) - { - if (!sa || sa == sdummy) - goto Lnomatch; - if (sa != specAlias && isDsymbol(sa)) - { - TemplateInstance *ti = isDsymbol(sa)->isTemplateInstance(); - Type *ta = isType(specAlias); - if (!ti || !ta) - goto Lnomatch; - Type *t = new TypeInstance(0, ti); - MATCH m = t->deduceType(sc, ta, parameters, dedtypes); - if (m == MATCHnomatch) - goto Lnomatch; - } - } - else if ((*dedtypes)[i]) - { // Must match already deduced symbol - Object *si = (*dedtypes)[i]; - - if (!sa || si != sa) - goto Lnomatch; - } - (*dedtypes)[i] = sa; - - *psparam = new AliasDeclaration(loc, ident, sa); - return MATCHexact; - -Lnomatch: - *psparam = NULL; - //printf("\tm = %d\n", MATCHnomatch); - return MATCHnomatch; -} - - -void TemplateAliasParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Dsymbol *sa = isDsymbol(oded); - assert(sa); - - printf("\tParameter alias: %s\n", sa->toChars()); -} - -void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); - buf->writestring(ident->toChars()); - if (specAliasT) - { - buf->writestring(" : "); - specAliasT->toCBuffer(buf, NULL, hgs); - } - if (defaultAlias) - { - buf->writestring(" = "); - defaultAlias->toCBuffer(buf, NULL, hgs); - } -} - - -void *TemplateAliasParameter::dummyArg() -{ Dsymbol *s; - - s = specAlias; - if (!s) - { - if (!sdummy) - sdummy = new Dsymbol(); - s = sdummy; - } - return (void*)s; -} - - -Object *TemplateAliasParameter::specialization() -{ - return specAliasT; -} - - -Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) -{ - Dsymbol *s = NULL; - - if (defaultAlias) - { - s = defaultAlias->toDsymbol(sc); - if (!s) - error(Loc(0), "%s is not a symbol", defaultAlias->toChars()); - } - return s; -} - -/* ======================== TemplateValueParameter ========================== */ - -// value-parameter - -AA *TemplateValueParameter::edummies = NULL; - -TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, - Expression *specValue, Expression *defaultValue) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->valType = valType; - this->specValue = specValue; - this->defaultValue = defaultValue; -} - -TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter() -{ - return this; -} - -TemplateParameter *TemplateValueParameter::syntaxCopy() -{ - TemplateValueParameter *tp = - new TemplateValueParameter(loc, ident, valType, specValue, defaultValue); - tp->valType = valType->syntaxCopy(); - if (specValue) - tp->specValue = specValue->syntaxCopy(); - if (defaultValue) - tp->defaultValue = defaultValue->syntaxCopy(); - return tp; -} - -void TemplateValueParameter::declareParameter(Scope *sc) -{ - VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL); - v->storage_class = STCtemplateparameter; - if (!sc->insert(v)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); - sparam = v; -} - -void TemplateValueParameter::semantic(Scope *sc) -{ - bool wasSame = (sparam->type == valType); - sparam->semantic(sc); - if (sparam->type == Type::terror && wasSame) - { // If sparam has a type error, avoid duplicate errors - valType = Type::terror; - return; - } - valType = valType->semantic(loc, sc); - if (!(valType->isintegral() || valType->isfloating() || valType->isString()) && - valType->ty != Tident) - { - if (valType != Type::terror) - error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars()); - } - - if (specValue) - { Expression *e = specValue; - - e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); - e = e->ctfeInterpret(); - if (e->op == TOKint64 || e->op == TOKfloat64 || - e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring) - specValue = e; - //e->toInteger(); - } - -#if 0 // defer semantic analysis to arg match - if (defaultValue) - { Expression *e = defaultValue; - - e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); - e = e->ctfeInterpret(); - if (e->op == TOKint64) - defaultValue = e; - //e->toInteger(); - } -#endif -} - -int TemplateValueParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - - if (tvp) - { - if (valType != tvp->valType) - goto Lnomatch; - - if (valType && !valType->equals(tvp->valType)) - goto Lnomatch; - - if (specValue != tvp->specValue) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - - -MATCH TemplateValueParameter::matchArg(Scope *sc, - Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam, int flags) -{ - //printf("TemplateValueParameter::matchArg()\n"); - - Initializer *init; - Declaration *sparam; - MATCH m = MATCHexact; - Expression *ei; - Object *oarg; - - if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = dedtypes->tdata()[i]; - if (!oarg) - goto Lnomatch; - } - } - - ei = isExpression(oarg); - Type *vt; - - if (!ei && oarg) - goto Lnomatch; - - if (specValue) - { - if (!ei || _aaGetRvalue(edummies, ei->type) == ei) - goto Lnomatch; - - Expression *e = specValue; - - e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); - e = e->ctfeInterpret(); - - ei = ei->syntaxCopy(); - ei = ei->semantic(sc); - ei = ei->ctfeInterpret(); - //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars()); - //printf("e : %s, %s\n", e->toChars(), e->type->toChars()); - if (!ei->equals(e)) - goto Lnomatch; - } - else if (dedtypes->data[i]) - { // Must match already deduced value - Expression *e = (Expression *)dedtypes->data[i]; - - if (!ei || !ei->equals(e)) - goto Lnomatch; - } -Lmatch: - //printf("valType: %s, ty = %d\n", valType->toChars(), valType->ty); - vt = valType->semantic(0, sc); - //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars()); - if (ei->type) - { - m = (MATCH)ei->implicitConvTo(vt); - //printf("m: %d\n", m); - if (!m) - goto Lnomatch; - } - dedtypes->data[i] = ei; - - init = new ExpInitializer(loc, ei); - sparam = new VarDeclaration(loc, vt, ident, init); - sparam->storage_class = STCconst; - *psparam = sparam; - return m; - -Lnomatch: - //printf("\tno match\n"); - *psparam = NULL; - return MATCHnomatch; -} - - -void TemplateValueParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Expression *ea = isExpression(oded); - - if (specValue) - printf("\tSpecialization: %s\n", specValue->toChars()); - printf("\tParameter Value: %s\n", ea ? ea->toChars() : "NULL"); -} - - -void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - valType->toCBuffer(buf, ident, hgs); - if (specValue) - { - buf->writestring(" : "); - specValue->toCBuffer(buf, hgs); - } - if (defaultValue) - { - buf->writestring(" = "); - defaultValue->toCBuffer(buf, hgs); - } -} - - -void *TemplateValueParameter::dummyArg() -{ Expression *e; - - e = specValue; - if (!e) - { - // Create a dummy value - Expression **pe = (Expression **)_aaGet(&edummies, valType); - if (!*pe) - *pe = valType->defaultInit(); - e = *pe; - } - return (void *)e; -} - - -Object *TemplateValueParameter::specialization() -{ - return specValue; -} - - -Object *TemplateValueParameter::defaultArg(Loc loc, Scope *sc) -{ - Expression *e = defaultValue; - if (e) - { - e = e->syntaxCopy(); - e = e->semantic(sc); -#if DMDV2 - e = e->resolveLoc(loc, sc); -#endif - } - return e; -} - -/* ======================== TemplateTupleParameter ========================== */ - -// variadic-parameter - -TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident) - : TemplateParameter(loc, ident) -{ - this->ident = ident; -} - -TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter() -{ - return this; -} - -TemplateParameter *TemplateTupleParameter::syntaxCopy() -{ - TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident); - return tp; -} - -void TemplateTupleParameter::declareParameter(Scope *sc) -{ - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - sparam = new AliasDeclaration(loc, ident, ti); - if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); -} - -void TemplateTupleParameter::semantic(Scope *sc) -{ -} - -int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateTupleParameter *tvp = tp->isTemplateTupleParameter(); - - if (tvp) - { - return 1; // match - } - - return 0; -} - -MATCH TemplateTupleParameter::matchArg(Scope *sc, - Objects *tiargs, size_t i, TemplateParameters *parameters, - Objects *dedtypes, - Declaration **psparam, int flags) -{ - //printf("TemplateTupleParameter::matchArg()\n"); - - /* The rest of the actual arguments (tiargs[]) form the match - * for the variadic parameter. - */ - assert(i + 1 == dedtypes->dim); // must be the last one - Tuple *ovar; - if (dedtypes->data[i] && isTuple((Object *)dedtypes->data[i])) - // It was already been deduced - ovar = isTuple((Object *)dedtypes->data[i]); - else if (i + 1 == tiargs->dim && isTuple((Object *)tiargs->data[i])) - ovar = isTuple((Object *)tiargs->data[i]); - else - { - ovar = new Tuple(); - //printf("ovar = %p\n", ovar); - if (i < tiargs->dim) - { - //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim); - ovar->objects.setDim(tiargs->dim - i); - for (size_t j = 0; j < ovar->objects.dim; j++) - ovar->objects.data[j] = tiargs->data[i + j]; - } - } - *psparam = new TupleDeclaration(loc, ident, &ovar->objects); - dedtypes->data[i] = (void *)ovar; - return MATCHexact; -} - - -void TemplateTupleParameter::print(Object *oarg, Object *oded) -{ - printf(" %s... [", ident->toChars()); - Tuple *v = isTuple(oded); - assert(v); - - //printf("|%d| ", v->objects.dim); - for (size_t i = 0; i < v->objects.dim; i++) - { - if (i) - printf(", "); - - Object *o = (Object *)v->objects.data[i]; - - Dsymbol *sa = isDsymbol(o); - if (sa) - printf("alias: %s", sa->toChars()); - - Type *ta = isType(o); - if (ta) - printf("type: %s", ta->toChars()); - - Expression *ea = isExpression(o); - if (ea) - printf("exp: %s", ea->toChars()); - - assert(!isTuple(o)); // no nested Tuple arguments - } - - printf("]\n"); -} - -void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - buf->writestring("..."); -} - - -void *TemplateTupleParameter::dummyArg() -{ - return NULL; -} - - -Object *TemplateTupleParameter::specialization() -{ - return NULL; -} - - -Object *TemplateTupleParameter::defaultArg(Loc loc, Scope *sc) -{ - return NULL; -} - -/* ======================== TemplateInstance ================================ */ - -TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) - : ScopeDsymbol(NULL) -{ -#if LOG - printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident->toChars() : "null"); -#endif - this->loc = loc; - this->name = ident; - this->tiargs = NULL; - this->tempdecl = NULL; - this->inst = NULL; - this->tinst = NULL; - this->argsym = NULL; - this->aliasdecl = NULL; - this->semanticRun = PASSinit; - this->semantictiargsdone = 0; - this->withsym = NULL; - this->nest = 0; - this->havetempdecl = 0; - this->isnested = NULL; - this->speculative = 0; - -#if IN_LLVM - // LDC - this->emittedInModule = NULL; - this->tmodule = NULL; -#endif -} - -/***************** - * This constructor is only called when we figured out which function - * template to instantiate. - */ - -TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs) - : ScopeDsymbol(NULL) -{ -#if LOG - printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars()); -#endif - this->loc = loc; - this->name = td->ident; - this->tiargs = tiargs; - this->tempdecl = td; - this->inst = NULL; - this->tinst = NULL; - this->argsym = NULL; - this->aliasdecl = NULL; - this->semanticRun = PASSinit; - this->semantictiargsdone = 1; - this->withsym = NULL; - this->nest = 0; - this->havetempdecl = 1; - this->isnested = NULL; - this->speculative = 0; - -#if IN_LLVM - // LDC - this->emittedInModule = NULL; - this->tmodule = NULL; -#endif - - assert((size_t)tempdecl->scope > 0x10000); -} - - -Objects *TemplateInstance::arraySyntaxCopy(Objects *objs) -{ - Objects *a = NULL; - if (objs) - { a = new Objects(); - a->setDim(objs->dim); - for (size_t i = 0; i < objs->dim; i++) - { - Type *ta = isType((Object *)objs->data[i]); - if (ta) - a->data[i] = ta->syntaxCopy(); - else - { - Expression *ea = isExpression((Object *)objs->data[i]); - assert(ea); - a->data[i] = ea->syntaxCopy(); - } - } - } - return a; -} - -Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) -{ - TemplateInstance *ti; - - if (s) - ti = (TemplateInstance *)s; - else - ti = new TemplateInstance(loc, name); - - ti->tiargs = arraySyntaxCopy(tiargs); - - ScopeDsymbol::syntaxCopy(ti); - return ti; -} - - -void TemplateInstance::semantic(Scope *sc) -{ - if (global.errors) - { - if (!global.gag) - { - /* Trying to soldier on rarely generates useful messages - * at this point. - */ - fatal(); - } - //return; - } -#if LOG - printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); -#endif - if (inst) // if semantic() was already run - { -#if LOG - printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst); -#endif - return; - } - - // get the enclosing template instance from the scope tinst - tinst = sc->tinst; - - if (semanticRun != PASSinit) - { -#if LOG - printf("Recursive template expansion\n"); -#endif - error(loc, "recursive template expansion"); -// inst = this; - return; - } - semanticRun = PASSsemantic; - - // get the enclosing template instance from the scope tinst - tinst = sc->tinst; - - // get the module of the outermost enclosing instantiation - if (tinst) - tmodule = tinst->tmodule; - else - tmodule = sc->module; - //printf("%s in %s\n", toChars(), tmodule->toChars()); - -#if LOG - printf("\tdo semantic\n"); -#endif - if (havetempdecl) - { - assert((size_t)tempdecl->scope > 0x10000); - // Deduce tdtypes - tdtypes.setDim(tempdecl->parameters->dim); - if (!tempdecl->matchWithInstance(this, &tdtypes, 0)) - { - error("incompatible arguments for template instantiation"); - inst = this; - return; - } - } - else - { - /* Find template declaration first. - */ - tempdecl = findTemplateDeclaration(sc); - if (!tempdecl) - { if (!sc->parameterSpecialization) - inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } - - /* Run semantic on each argument, place results in tiargs[] - * (if we have tempdecl, then tiargs is already evaluated) - */ - semanticTiargs(sc); - if (arrayObjectIsError(tiargs)) - { if (!sc->parameterSpecialization) - inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } - - tempdecl = findBestMatch(sc); - if (!tempdecl || global.errors) - { if (!sc->parameterSpecialization) - inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } - } - - hasNestedArgs(tiargs); - - /* See if there is an existing TemplateInstantiation that already - * implements the typeargs. If so, just refer to that one instead. - */ - - for (size_t i = 0; i < tempdecl->instances.dim; i++) - { - TemplateInstance *ti = tempdecl->instances[i]; -#if LOG - printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars()); -#endif - assert(tdtypes.dim == ti->tdtypes.dim); - - // Nesting must match - if (isnested != ti->isnested) - { - //printf("test2 isnested %s ti->isnested %s\n", isnested ? isnested->toChars() : "", ti->isnested ? ti->isnested->toChars() : ""); - continue; - } -#if 0 - if (isnested && sc->parent != ti->parent) - continue; -#endif - for (size_t j = 0; j < tdtypes.dim; j++) - { Object *o1 = (Object *)tdtypes.data[j]; - Object *o2 = (Object *)ti->tdtypes.data[j]; - if (!match(o1, o2, tempdecl, sc)) - { - goto L1; - } - } - - // It's a match - inst = ti; - parent = ti->parent; - - // If both this and the previous instantiation were speculative, - // use the number of errors that happened last time. - if (inst->speculative && global.gag) - { - global.errors += inst->errors; - global.gaggedErrors += inst->errors; - } - - // If the first instantiation was speculative, but this is not: - if (inst->speculative && !global.gag) - { - // If the first instantiation had failed, re-run semantic, - // so that error messages are shown. - if (inst->errors) - goto L1; - // It had succeeded, mark it is a non-speculative instantiation, - // and reuse it. - inst->speculative = 0; - } - -#if LOG - printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun); -#endif - return; - - L1: - ; - } - - /* So, we need to implement 'this' instance. - */ -#if LOG - printf("\timplement template instance %s '%s'\n", tempdecl->parent->toChars(), toChars()); - printf("\ttempdecl %s\n", tempdecl->toChars()); -#endif - unsigned errorsave = global.errors; - inst = this; - // Mark as speculative if we are instantiated from inside is(typeof()) - if (global.gag && sc->intypeof) - speculative = 1; - - int tempdecl_instance_idx = tempdecl->instances.dim; - tempdecl->instances.push(this); - parent = tempdecl->parent; - //printf("parent = '%s'\n", parent->kind()); - - ident = genIdent(); // need an identifier for name mangling purposes. - -#if 1 - if (isnested) - parent = isnested; -#endif - //printf("parent = '%s'\n", parent->kind()); - - // Add 'this' to the enclosing scope's members[] so the semantic routines - // will get called on the instance members. Store the place we added it to - // in target_symbol_list(_idx) so we can remove it later if we encounter - // an error. -#if 1 - int dosemantic3 = 0; - Dsymbols *target_symbol_list = NULL; - int target_symbol_list_idx; - - if (!sc->parameterSpecialization) - { Dsymbols *a; - - Scope *scx = sc; -#if 0 - for (scx = sc; scx; scx = scx->enclosing) - if (scx->scopesym) - break; -#endif - - //if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - if (scx && scx->scopesym && - scx->scopesym->members && !scx->scopesym->isTemplateMixin() -#if 1 // removed because it bloated compile times - /* The problem is if A imports B, and B imports A, and both A - * and B instantiate the same template, does the compilation of A - * or the compilation of B do the actual instantiation? - * - * see bugzilla 2500. - */ - && !scx->module->selfImports() -#endif - ) - { - //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - a = scx->scopesym->members; - } - else - { Module *m = sc->module->importedFrom; - //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); - a = m->members; - if (m->semanticRun >= 3) - { - dosemantic3 = 1; - } - } - for (size_t i = 0; 1; i++) - { - if (i == a->dim) - { - target_symbol_list = a; - target_symbol_list_idx = i; - a->push(this); - break; - } - if (this == (*a)[i]) // if already in Array - break; - } - } -#endif - - // Copy the syntax trees from the TemplateDeclaration - members = Dsymbol::arraySyntaxCopy(tempdecl->members); - - // Create our own scope for the template parameters - Scope *scope = tempdecl->scope; - if (!tempdecl->semanticRun) - { - error("template instantiation %s forward references template declaration %s\n", toChars(), tempdecl->toChars()); - return; - } - -#if LOG - printf("\tcreate scope for template parameters '%s'\n", toChars()); -#endif - argsym = new ScopeDsymbol(); - argsym->parent = scope->parent; - scope = scope->push(argsym); - - // Declare each template parameter as an alias for the argument type - Scope *paramscope = scope->push(); - paramscope->stc = 0; - declareParameters(paramscope); - paramscope->pop(); - - // Add members of template instance to template instance symbol table -// parent = scope->scopesym; - symtab = new DsymbolTable(); - int memnum = 0; - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; -#if LOG - printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum); -#endif - memnum |= s->addMember(scope, this, memnum); - } -#if LOG - printf("adding members done\n"); -#endif - - /* See if there is only one member of template instance, and that - * member has the same name as the template instance. - * If so, this template instance becomes an alias for that member. - */ - //printf("members->dim = %d\n", members->dim); - if (members->dim) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s) && s) - { - //printf("s->kind = '%s'\n", s->kind()); - //s->print(); - //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); - if (s->ident && s->ident->equals(tempdecl->ident)) - { - //printf("setting aliasdecl\n"); - aliasdecl = new AliasDeclaration(loc, s->ident, s); - -#if IN_LLVM - // LDC propagate internal information - if (tempdecl->llvmInternal) { - s->llvmInternal = tempdecl->llvmInternal; - if (FuncDeclaration* fd = s->isFuncDeclaration()) { - fd->intrinsicName = tempdecl->intrinsicName; - } - } -#endif - } - } - } - - // Do semantic() analysis on template instance members -#if LOG - printf("\tdo semantic() on template instance members '%s'\n", toChars()); -#endif - Scope *sc2; - sc2 = scope->push(this); - //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars()); - sc2->parent = /*isnested ? sc->parent :*/ this; - sc2->tinst = this; - -#if WINDOWS_SEH - __try - { -#endif - static int nest; - //printf("%d\n", nest); - if (++nest > 500) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); - //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); -// if (isnested) -// s->parent = sc->parent; - //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); - s->semantic(sc2); - //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); - sc2->module->runDeferredSemantic(); - } - --nest; -#if WINDOWS_SEH - } - __except (__ehfilter(GetExceptionInformation())) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } -#endif - - /* If any of the instantiation members didn't get semantic() run - * on them due to forward references, we cannot run semantic2() - * or semantic3() yet. - */ - for (size_t i = 0; i < Module::deferred.dim; i++) - { Dsymbol *sd = Module::deferred[i]; - - if (sd->parent == this) - goto Laftersemantic; - } - - /* The problem is when to parse the initializer for a variable. - * Perhaps VarDeclaration::semantic() should do it like it does - * for initializers inside a function. - */ -// if (sc->parent->isFuncDeclaration()) - - /* BUG 782: this has problems if the classes this depends on - * are forward referenced. Find a way to defer semantic() - * on this template. - */ - semantic2(sc2); - - if (sc->func || dosemantic3) - { -#if WINDOWS_SEH - __try - { -#endif - static int nest; - if (++nest > 300) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - semantic3(sc2); - --nest; -#if WINDOWS_SEH - } - __except (__ehfilter(GetExceptionInformation())) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } -#endif - } - - Laftersemantic: - sc2->pop(); - - scope->pop(); - - // Give additional context info if error occurred during instantiation - if (global.errors != errorsave) - { - error(loc, "error instantiating"); - if (tinst) - { tinst->printInstantiationTrace(); - if (!global.gag) - fatal(); - } - errors = 1; - if (global.gag) - { - // Errors are gagged, so remove the template instance from the - // instance/symbol lists we added it to and reset our state to - // finish clean and so we can try to instantiate it again later - // (see bugzilla 4302 and 6602). - tempdecl->instances.remove(tempdecl_instance_idx); - if (target_symbol_list) - { - // Because we added 'this' in the last position above, we - // should be able to remove it without messing other indices up. - assert((*target_symbol_list)[target_symbol_list_idx] == this); - target_symbol_list->remove(target_symbol_list_idx); - } - semanticRun = PASSinit; - inst = NULL; - } - } - -#if LOG - printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); -#endif -} - - -void TemplateInstance::semanticTiargs(Scope *sc) -{ - //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); - if (semantictiargsdone) - return; - semantictiargsdone = 1; - semanticTiargs(loc, sc, tiargs, 0); -} - -/********************************** - * Input: - * flags 1: replace const variables with their initializers - */ - -void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags) -{ - // Run semantic on each argument, place results in tiargs[] - //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); - if (!tiargs) - return; - for (size_t j = 0; j < tiargs->dim; j++) - { - Object *o = (*tiargs)[j]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - - //printf("1: (*tiargs)[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); - if (ta) - { - //printf("type %s\n", ta->toChars()); - // It might really be an Expression or an Alias - ta->resolve(loc, sc, &ea, &ta, &sa); - if (ea) - { - ea = ea->semantic(sc); - ea = ea->ctfeInterpret(); - (*tiargs)[j] = ea; - } - else if (sa) - { - Ldsym: - (*tiargs)[j] = sa; - TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); - if (d) - { - size_t dim = d->objects->dim; - tiargs->remove(j); - tiargs->insert(j, d->objects); - j--; - } - } - else if (ta) - { - Ltype: - if (ta->ty == Ttuple) - { // Expand tuple - TypeTuple *tt = (TypeTuple *)ta; - size_t dim = tt->arguments->dim; - tiargs->remove(j); - if (dim) - { tiargs->reserve(dim); - for (size_t i = 0; i < dim; i++) - { Parameter *arg = (*tt->arguments)[i]; - tiargs->insert(j + i, arg->type); - } - } - j--; - } - else - (*tiargs)[j] = ta; - } - else - { - assert(global.errors); - (*tiargs)[j] = Type::terror; - } - } - else if (ea) - { - if (!ea) - { assert(global.errors); - ea = new ErrorExp(); - } - assert(ea); - ea = ea->semantic(sc); - ea = ea->ctfeInterpret(); - (*tiargs)[j] = ea; - if (ea->op == TOKtype) - { ta = ea->type; - goto Ltype; - } - if (ea->op == TOKimport) - { sa = ((ScopeExp *)ea)->sds; - goto Ldsym; - } - if (ea->op == TOKtuple) - { // Expand tuple - TupleExp *te = (TupleExp *)ea; - size_t dim = te->exps->dim; - tiargs->remove(j); - if (dim) - { tiargs->reserve(dim); - for (size_t i = 0; i < dim; i++) - tiargs->insert(j + i, (*te->exps)[i]); - } - j--; - } - } - else if (sa) - { - } - else - { - assert(0); - } - //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); - } -#if 0 - printf("-TemplateInstance::semanticTiargs('%s', this=%p)\n", toChars(), this); - for (size_t j = 0; j < tiargs->dim; j++) - { - Object *o = (*tiargs)[j]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - - printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); - } -#endif -} - -/********************************************** - * Find template declaration corresponding to template instance. - */ - -TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc) -{ - //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars()); - if (!tempdecl) - { - /* Given: - * foo!( ... ) - * figure out which TemplateDeclaration foo refers to. - */ - Dsymbol *s; - Dsymbol *scopesym; - Identifier *id; - - id = name; - s = sc->search(loc, id, &scopesym); - if (!s) - { - s = sc->search_correct(id); - if (s) - error("template '%s' is not defined, did you mean %s?", id->toChars(), s->toChars()); - else - error("template '%s' is not defined", id->toChars()); - return NULL; - } -#if LOG - printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind()); - if (s->parent) - printf("s->parent = '%s'\n", s->parent->toChars()); -#endif - withsym = scopesym->isWithScopeSymbol(); - - /* We might have found an alias within a template when - * we really want the template. - */ - TemplateInstance *ti; - if (s->parent && - (ti = s->parent->isTemplateInstance()) != NULL) - { - if (ti->tempdecl && ti->tempdecl->ident == id) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - s = tempdecl; - } - } - - s = s->toAlias(); - - /* It should be a TemplateDeclaration, not some other symbol - */ - tempdecl = s->isTemplateDeclaration(); - if (!tempdecl) - { - if (!s->parent && global.errors) - return NULL; - if (!s->parent && s->getType()) - { Dsymbol *s2 = s->getType()->toDsymbol(sc); - if (!s2) - { - error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); - return NULL; - } - s = s2; - } -#ifdef DEBUG - //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars()); -#endif - //assert(s->parent); - TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL; - if (ti && - (ti->name == id || - ti->toAlias()->ident == id) - && - ti->tempdecl) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - } - else - { - error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); - return NULL; - } - } - } - else - assert(tempdecl->isTemplateDeclaration()); - return tempdecl; -} - -TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc) -{ - /* Since there can be multiple TemplateDeclaration's with the same - * name, look for the best match. - */ - TemplateDeclaration *td_ambig = NULL; - TemplateDeclaration *td_best = NULL; - MATCH m_best = MATCHnomatch; - Objects dedtypes; - -#if LOG - printf("TemplateInstance::findBestMatch()\n"); -#endif - // First look for forward references - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - if (!td->semanticRun) - { - if (td->scope) - { // Try to fix forward reference - td->semantic(td->scope); - } - if (!td->semanticRun) - { - error("%s forward references template declaration %s\n", toChars(), td->toChars()); - return NULL; - } - } - } - - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - MATCH m; - -//if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, tiargs->data[0]); - - // If more arguments than parameters, - // then this is no match. - if (td->parameters->dim < tiargs->dim) - { - if (!td->isVariadic()) - continue; - } - - dedtypes.setDim(td->parameters->dim); - dedtypes.zero(); - assert(td->semanticRun); - m = td->matchWithInstance(this, &dedtypes, 0); - //printf("matchWithInstance = %d\n", m); - if (!m) // no match at all - continue; - - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; - - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best); - MATCH c2 = td_best->leastAsSpecialized(td); - //printf("c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - else - goto Lambig; - } - - Lambig: // td_best and td are ambiguous - td_ambig = td; - continue; - - Ltd_best: // td_best is the best match so far - td_ambig = NULL; - continue; - - Ltd: // td is the new best match - td_ambig = NULL; - td_best = td; - m_best = m; - tdtypes.setDim(dedtypes.dim); - memcpy(tdtypes.data, dedtypes.data, tdtypes.dim * sizeof(void *)); - continue; - } - - if (!td_best) - { - if (tempdecl && !tempdecl->overnext) - // Only one template, so we can give better error message - error("%s does not match template declaration %s", toChars(), tempdecl->toChars()); - else - ::error(loc, "%s %s.%s does not match any template declaration", - tempdecl->kind(), tempdecl->parent->toPrettyChars(), tempdecl->ident->toChars()); - return NULL; - } - if (td_ambig) - { - ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - td_best->kind(), td_best->parent->toPrettyChars(), td_best->ident->toChars(), - td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), - td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); - } - - /* The best match is td_best - */ - tempdecl = td_best; - -#if 0 - /* Cast any value arguments to be same type as value parameter - */ - for (size_t i = 0; i < tiargs->dim; i++) - { Object *o = (Object *)tiargs->data[i]; - Expression *ea = isExpression(o); // value argument - TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - if (tvp) - { - assert(ea); - ea = ea->castTo(tvp->valType); - ea = ea->ctfeInterpret(); - tiargs->data[i] = (Object *)ea; - } - } -#endif - -#if LOG - printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars()); -#endif - return tempdecl; -} - - -/***************************************** - * Determines if a TemplateInstance will need a nested - * generation of the TemplateDeclaration. - */ - -int TemplateInstance::hasNestedArgs(Objects *args) -{ int nested = 0; - //printf("TemplateInstance::hasNestedArgs('%s')\n", tempdecl->ident->toChars()); - - /* A nested instance happens when an argument references a local - * symbol that is on the stack. - */ - for (size_t i = 0; i < args->dim; i++) - { Object *o = (*args)[i]; - Expression *ea = isExpression(o); - Type *ta = isType(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - //printf("o %p ea %p ta %p sa %p va %p\n", o, ea, ta, sa, va); - if (ea) - { - if (ea->op == TOKvar) - { - sa = ((VarExp *)ea)->var; - goto Lsa; - } - if (ea->op == TOKthis) - { - sa = ((ThisExp *)ea)->var; - goto Lsa; - } - if (ea->op == TOKfunction) - { - sa = ((FuncExp *)ea)->fd; - goto Lsa; - } - } - else if (ta) - { - if (ta->ty == Tstruct || ta->ty == Tclass) - { sa = ta->toDsymbol(NULL); - TemplateInstance *ti = sa->parent->isTemplateInstance(); - if (ti && ti->isnested) - { sa = ti; - goto Lsa; - } - } - } - else if (sa) - { - Lsa: - //printf("sa = %s %s\n", sa->kind(), sa->toChars()); - Declaration *d = sa->isDeclaration(); - TemplateInstance *ad = sa->isTemplateInstance(); - if ( - (ad && ad->isnested) || - (d && !d->isDataseg() && -#if DMDV2 - !(d->storage_class & STCmanifest) && -#endif - (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && - !isTemplateMixin() - )) - { - // if module level template - if (tempdecl->toParent()->isModule()) - { Dsymbol *dparent = sa->toParent(); - if (!isnested) - isnested = dparent; - else if (isnested != dparent) - { - /* Select the more deeply nested of the two. - * Error if one is not nested inside the other. - */ - for (Dsymbol *p = isnested; p; p = p->parent) - { - if (p == dparent) - goto L1; // isnested is most nested - } - for (Dsymbol *p = dparent; p; p = p->parent) - { - if (p == isnested) - { isnested = dparent; - goto L1; // dparent is most nested - } - } - error("%s is nested in both %s and %s", - toChars(), isnested->toPrettyChars(), dparent->toPrettyChars()); - } - L1: - //printf("\tnested inside %s\n", isnested->toChars()); - nested |= 1; - } - else - error("cannot use local '%s' as parameter to non-global template %s", sa->toChars(), tempdecl->toChars()); - } - } - else if (va) - { - nested |= hasNestedArgs(&va->objects); - } - } - return nested; -} - -/**************************************** - * This instance needs an identifier for name mangling purposes. - * Create one by taking the template declaration name and adding - * the type signature for it. - */ - -Identifier *TemplateInstance::genIdent() -{ OutBuffer buf; - - //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); - char *id = tempdecl->ident->toChars(); - buf.printf("__T%zu%s", strlen(id), id); - Objects *args = tiargs; - for (size_t i = 0; i < args->dim; i++) - { Object *o = (Object *)args->data[i]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); - if (ta) - { - buf.writeByte('T'); - if (ta->deco) - buf.writestring(ta->deco); - else - { -#ifdef DEBUG - printf("ta = %d, %s\n", ta->ty, ta->toChars()); -#endif - assert(global.errors); - } - } - else if (ea) - { - ea = ea->ctfeInterpret(); - if (ea->op == TOKvar) - { - sa = ((VarExp *)ea)->var; - ea = NULL; - goto Lsa; - } - if (ea->op == TOKthis) - { - sa = ((ThisExp *)ea)->var; - ea = NULL; - goto Lsa; - } - if (ea->op == TOKfunction) - { - sa = ((FuncExp *)ea)->fd; - ea = NULL; - goto Lsa; - } - buf.writeByte('V'); - if (ea->op == TOKtuple) - { ea->error("tuple is not a valid template value argument"); - continue; - } - if (ea->op == TOKerror) - continue; -#if 1 - /* Use deco that matches what it would be for a function parameter - */ - buf.writestring(ea->type->deco); -#else - // Use type of parameter, not type of argument - TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - assert(tvp); - buf.writestring(tvp->valType->deco); -#endif - ea->toMangleBuffer(&buf); - } - else if (sa) - { - Lsa: - buf.writeByte('S'); - Declaration *d = sa->isDeclaration(); - if (d && (!d->type || !d->type->deco)) - error("forward reference of %s", d->toChars()); - else - { - const char *p = sa->mangle(); - - /* Bugzilla 3043: if the first character of p is a digit this - * causes ambiguity issues because the digits of the two numbers are adjacent. - * Current demanglers resolve this by trying various places to separate the - * numbers until one gets a successful demangle. - * Unfortunately, fixing this ambiguity will break existing binary - * compatibility and the demanglers, so we'll leave it as is. - */ - buf.printf("%zu%s", strlen(p), p); - } - } - else if (va) - { - assert(i + 1 == args->dim); // must be last one - args = &va->objects; - i = -1; - } - else - assert(0); - } - buf.writeByte('Z'); - id = buf.toChars(); - buf.data = NULL; - //printf("\tgenIdent = %s\n", id); - return new Identifier(id, TOKidentifier); -} - - -/**************************************************** - * Declare parameters of template instance, initialize them with the - * template instance arguments. - */ - -void TemplateInstance::declareParameters(Scope *sc) -{ - //printf("TemplateInstance::declareParameters()\n"); - for (size_t i = 0; i < tdtypes.dim; i++) - { - TemplateParameter *tp = tempdecl->parameters->tdata()[i]; - //Object *o = tiargs->tdata()[i]; - Object *o = tdtypes.tdata()[i]; // initializer for tp - - //printf("\ttdtypes[%d] = %p\n", i, o); - tempdecl->declareParameter(sc, tp, o); - } -} - -/***************************************************** - * Determine if template instance is really a template function, - * and that template function needs to infer types from the function - * arguments. - */ - -int TemplateInstance::needsTypeInference(Scope *sc) -{ - //printf("TemplateInstance::needsTypeInference() %s\n", toChars()); - if (!tempdecl) - tempdecl = findTemplateDeclaration(sc); - int multipleMatches = FALSE; - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - /* If any of the overloaded template declarations need inference, - * then return TRUE - */ - FuncDeclaration *fd; - if (!td->onemember || - (fd = td->onemember->toAlias()->isFuncDeclaration()) == NULL || - fd->type->ty != Tfunction) - { - /* Not a template function, therefore type inference is not possible. - */ - //printf("false\n"); - return FALSE; - } - -#if DMDV2 - for (size_t i = 0; i < td->parameters->dim; i++) - if (td->parameters->tdata()[i]->isTemplateThisParameter()) - return TRUE; -#endif - - /* Determine if the instance arguments, tiargs, are all that is necessary - * to instantiate the template. - */ - //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, tiargs->dim); - TypeFunction *fdtype = (TypeFunction *)fd->type; - if (Parameter::dim(fdtype->parameters)) - { - TemplateParameter *tp = td->isVariadic(); - if (tp && td->parameters->dim > 1) - return TRUE; - - if (tiargs->dim < td->parameters->dim) - { // Can remain tiargs be filled by default arguments? - for (size_t i = tiargs->dim; i < td->parameters->dim; i++) - { tp = (*td->parameters)[i]; - if (TemplateTypeParameter *ttp = tp->isTemplateTypeParameter()) - { if (!ttp->defaultType) - return TRUE; - } - else if (TemplateAliasParameter *tap = tp->isTemplateAliasParameter()) - { if (!tap->defaultAlias) - return TRUE; - } - else if (TemplateValueParameter *tvp = tp->isTemplateValueParameter()) - { if (!tvp->defaultValue) - return TRUE; - } - } - } - } - } - //printf("false\n"); - return multipleMatches; -} - -void TemplateInstance::semantic2(Scope *sc) -{ int i; - - if (semanticRun >= PASSsemantic2) - return; - semanticRun = PASSsemantic2; -#if LOG - printf("+TemplateInstance::semantic2('%s')\n", toChars()); -#endif - if (!errors && members) - { - sc = tempdecl->scope; - assert(sc); - sc = sc->push(argsym); - sc = sc->push(this); - sc->tinst = this; - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; -#if LOG -printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); -#endif - s->semantic2(sc); - } - sc = sc->pop(); - sc->pop(); - } -#if LOG - printf("-TemplateInstance::semantic2('%s')\n", toChars()); -#endif -} - -void TemplateInstance::semantic3(Scope *sc) -{ -#if LOG - printf("TemplateInstance::semantic3('%s'), semanticRun = %d\n", toChars(), semanticRun); -#endif -//if (toChars()[0] == 'D') *(char*)0=0; - if (semanticRun >= PASSsemantic3) - return; - semanticRun = PASSsemantic3; - if (!errors && members) - { - sc = tempdecl->scope; - sc = sc->push(argsym); - sc = sc->push(this); - sc->tinst = this; - int oldgag = global.gag; - int olderrors = global.errors; - /* If this is a speculative instantiation, gag errors. - * Future optimisation: If the results are actually needed, errors - * would already be gagged, so we don't really need to run semantic - * on the members. - */ - if (speculative && !oldgag) - olderrors = global.startGagging(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->semantic3(sc); - if (speculative && global.errors != olderrors) - break; - } - if (speculative && !oldgag) - { // If errors occurred, this instantiation failed - errors += global.errors - olderrors; - global.endGagging(olderrors); - } - sc = sc->pop(); - sc->pop(); - } -} - -#if IN_DMD - -/************************************** - * Given an error instantiating the TemplateInstance, - * give the nested TemplateInstance instantiations that got - * us here. Those are a list threaded into the nested scopes. - */ -void TemplateInstance::printInstantiationTrace() -{ - if (global.gag) - return; - - const unsigned max_shown = 6; - const char format[] = "instantiated from here: %s"; - - // determine instantiation depth and number of recursive instantiations - int n_instantiations = 1; - int n_totalrecursions = 0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - ++n_instantiations; - // If two instantiations use the same declaration, they are recursive. - // (this works even if they are instantiated from different places in the - // same template). - // In principle, we could also check for multiple-template recursion, but it's - // probably not worthwhile. - if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl - && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) - ++n_totalrecursions; - } - - // show full trace only if it's short or verbose is on - if (n_instantiations <= max_shown || global.params.verbose) - { - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - errorSupplemental(cur->loc, format, cur->toChars()); - } - } - else if (n_instantiations - n_totalrecursions <= max_shown) - { - // By collapsing recursive instantiations into a single line, - // we can stay under the limit. - int recursionDepth=0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl - && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) - { - ++recursionDepth; - } - else - { - if (recursionDepth) - errorSupplemental(cur->loc, "%d recursive instantiations from here: %s", recursionDepth+2, cur->toChars()); - else - errorSupplemental(cur->loc, format, cur->toChars()); - recursionDepth = 0; - } - } - } - else - { - // Even after collapsing the recursions, the depth is too deep. - // Just display the first few and last few instantiations. - unsigned i = 0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - if (i == max_shown / 2) - errorSupplemental(cur->loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown); - - if (i < max_shown / 2 || - i >= n_instantiations - max_shown + max_shown / 2) - errorSupplemental(cur->loc, format, cur->toChars()); - ++i; - } - } -} - -void TemplateInstance::toObjFile(int multiobj) -{ -#if LOG - printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this); -#endif - if (!errors && members) - { - if (multiobj) - // Append to list of object files to be written later - //obj_append(this); - assert(0 && "multiobj"); - else - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->toObjFile(multiobj); - } - } - } -} - -#endif - -void TemplateInstance::inlineScan() -{ -#if LOG - printf("TemplateInstance::inlineScan('%s')\n", toChars()); -#endif - if (!errors && members) - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->inlineScan(); - } - } -} - -void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - int i; - - Identifier *id = name; - buf->writestring(id->toChars()); - buf->writestring("!("); - if (nest) - buf->writestring("..."); - else - { - nest++; - Objects *args = tiargs; - for (i = 0; i < args->dim; i++) - { - if (i) - buf->writeByte(','); - Object *oarg = (*args)[i]; - ObjectToCBuffer(buf, hgs, oarg); - } - nest--; - } - buf->writeByte(')'); -} - - -Dsymbol *TemplateInstance::toAlias() -{ -#if LOG - printf("TemplateInstance::toAlias()\n"); -#endif - if (!inst) - { - // Maybe we can resolve it - if (scope) - { - /* Anything that affects scope->offset must be - * done in lexical order. Fwd ref error if it is affected, otherwise allow. - */ - unsigned offset = scope->offset; - Scope *sc = scope; - semantic(scope); -// if (offset != sc->offset) -// inst = NULL; // trigger fwd ref error - } - if (!inst) - { error("cannot resolve forward reference"); - errors = 1; - return this; - } - } - - if (inst != this) - return inst->toAlias(); - - if (aliasdecl) - { - return aliasdecl->toAlias(); - } - - return inst; -} - -AliasDeclaration *TemplateInstance::isAliasDeclaration() -{ - return aliasdecl; -} - -const char *TemplateInstance::kind() -{ - return "template instance"; -} - -int TemplateInstance::oneMember(Dsymbol **ps) -{ - *ps = NULL; - return TRUE; -} - -char *TemplateInstance::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *s; - - toCBuffer(&buf, &hgs); - s = buf.toChars(); - buf.data = NULL; - return s; -} - -#if IN_LLVM - -void TemplateInstance::printInstantiationTrace() -{ - if(global.gag) - return; - - const int max_shown = 6; - - // determine instantiation depth - int n_instantiations = 1; - TemplateInstance* cur = this; - while(cur = cur->tinst) - ++n_instantiations; - - // show full trace only if it's short or verbose is on - if(n_instantiations <= max_shown || global.params.verbose) - { - cur = this; - while(cur) - { - fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); - cur = cur->tinst; - } - } - else - { - cur = this; - size_t i = 0; - for(; i < max_shown/2; ++i, cur = cur->tinst) - fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); - fprintf(stdmsg," ... (%d instantiations, -v to show) ...\n", n_instantiations - max_shown); - for(; i < n_instantiations - max_shown + max_shown/2; ++i, cur = cur->tinst) - {} - for(; i < n_instantiations; ++i, cur = cur->tinst) - fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); - } -} - -#endif - -/* ======================== TemplateMixin ================================ */ - -TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, - Identifiers *idents, Objects *tiargs) - : TemplateInstance(loc, idents->tdata()[idents->dim - 1]) -{ - //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); - this->ident = ident; - this->tqual = tqual; - this->idents = idents; - this->tiargs = tiargs ? tiargs : new Objects(); -} - -Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) -{ TemplateMixin *tm; - - Identifiers *ids = new Identifiers(); - ids->setDim(idents->dim); - for (size_t i = 0; i < idents->dim; i++) - { // Matches TypeQualified::syntaxCopyHelper() - Identifier *id = idents->tdata()[i]; - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; - - ti = (TemplateInstance *)ti->syntaxCopy(NULL); - id = (Identifier *)ti; - } - ids->tdata()[i] = id; - } - - tm = new TemplateMixin(loc, ident, - (Type *)(tqual ? tqual->syntaxCopy() : NULL), - ids, tiargs); - TemplateInstance::syntaxCopy(tm); - return tm; -} - -void TemplateMixin::semantic(Scope *sc) -{ -#if LOG - printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); - fflush(stdout); -#endif - if (semanticRun) - { - // This for when a class/struct contains mixin members, and - // is done over because of forward references - if (parent && toParent()->isAggregateDeclaration()) - semanticRun = PASSsemantic; // do over - else - { -#if LOG - printf("\tsemantic done\n"); -#endif - return; - } - } - if (!semanticRun) - semanticRun = PASSsemantic; -#if LOG - printf("\tdo semantic\n"); -#endif - -#if !IN_LLVM - // dont know what this is - util_progress(); -#endif - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - // Follow qualifications to find the TemplateDeclaration - if (!tempdecl) - { Dsymbol *s; - size_t i; - Identifier *id; - - if (tqual) - { s = tqual->toDsymbol(sc); - i = 0; - } - else - { - i = 1; - id = idents->tdata()[0]; - switch (id->dyncast()) - { - case DYNCAST_IDENTIFIER: - s = sc->search(loc, id, NULL); - break; - - case DYNCAST_DSYMBOL: - { - TemplateInstance *ti = (TemplateInstance *)id; - ti->semantic(sc); - s = ti; - break; - } - default: - assert(0); - } - } - - for (; i < idents->dim; i++) - { - if (!s) - break; - id = idents->tdata()[i]; - s = s->searchX(loc, sc, id); - } - if (!s) - { - error("is not defined"); - inst = this; - return; - } - tempdecl = s->toAlias()->isTemplateDeclaration(); - if (!tempdecl) - { - error("%s isn't a template", s->toChars()); - inst = this; - return; - } - } - - // Look for forward reference - assert(tempdecl); - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - if (!td->semanticRun) - { - /* Cannot handle forward references if mixin is a struct member, - * because addField must happen during struct's semantic, not - * during the mixin semantic. - * runDeferred will re-run mixin's semantic outside of the struct's - * semantic. - */ - semanticRun = PASSinit; - AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); - if (ad) - ad->sizeok = SIZEOKfwd; - else - { - // Forward reference - //printf("forward reference - deferring\n"); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - return; - } - } - - // Run semantic on each argument, place results in tiargs[] - semanticTiargs(sc); - if (errors || arrayObjectIsError(tiargs)) - return; - - tempdecl = findBestMatch(sc); - if (!tempdecl) - { inst = this; - return; // error recovery - } - - if (!ident) - ident = genIdent(); - - inst = this; - parent = sc->parent; - - /* Detect recursive mixin instantiations. - */ - for (Dsymbol *s = parent; s; s = s->parent) - { - //printf("\ts = '%s'\n", s->toChars()); - TemplateMixin *tm = s->isTemplateMixin(); - if (!tm || tempdecl != tm->tempdecl) - continue; - - /* Different argument list lengths happen with variadic args - */ - if (tiargs->dim != tm->tiargs->dim) - continue; - - for (size_t i = 0; i < tiargs->dim; i++) - { Object *o = (*tiargs)[i]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Object *tmo = (*tm->tiargs)[i]; - if (ta) - { - Type *tmta = isType(tmo); - if (!tmta) - goto Lcontinue; - if (!ta->equals(tmta)) - goto Lcontinue; - } - else if (ea) - { Expression *tme = isExpression(tmo); - if (!tme || !ea->equals(tme)) - goto Lcontinue; - } - else if (sa) - { - Dsymbol *tmsa = isDsymbol(tmo); - if (sa != tmsa) - goto Lcontinue; - } - else - assert(0); - } - error("recursive mixin instantiation"); - return; - - Lcontinue: - continue; - } - - // Copy the syntax trees from the TemplateDeclaration - members = Dsymbol::arraySyntaxCopy(tempdecl->members); - if (!members) - return; - - symtab = new DsymbolTable(); - - for (Scope *sce = sc; 1; sce = sce->enclosing) - { - ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; - if (sds) - { - sds->importScope(this, PROTpublic); - break; - } - } - -#if LOG - printf("\tcreate scope for template parameters '%s'\n", toChars()); -#endif - Scope *scy = sc; - scy = sc->push(this); - scy->parent = this; - - argsym = new ScopeDsymbol(); - argsym->parent = scy->parent; - Scope *argscope = scy->push(argsym); - - unsigned errorsave = global.errors; - - // Declare each template parameter as an alias for the argument type - declareParameters(argscope); - - // Add members to enclosing scope, as well as this scope - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->addMember(argscope, this, i); - //sc->insert(s); - //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); - //printf("s->parent = %s\n", s->parent->toChars()); - } - - // Do semantic() analysis on template instance members -#if LOG - printf("\tdo semantic() on template instance members '%s'\n", toChars()); -#endif - Scope *sc2; - sc2 = argscope->push(this); - sc2->offset = sc->offset; - - static int nest; - //printf("%d\n", nest); - if (++nest > 500) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->semantic(sc2); - } - - nest--; - - sc->offset = sc2->offset; - - /* The problem is when to parse the initializer for a variable. - * Perhaps VarDeclaration::semantic() should do it like it does - * for initializers inside a function. - */ -// if (sc->parent->isFuncDeclaration()) - - semantic2(sc2); - - if (sc->func) - { - semantic3(sc2); - } - - // Give additional context info if error occurred during instantiation - if (global.errors != errorsave) - { - error("error instantiating"); - } - - sc2->pop(); - - argscope->pop(); - -// if (!isAnonymous()) - { - scy->pop(); - } -#if LOG - printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); -#endif -} - -void TemplateMixin::semantic2(Scope *sc) -{ - if (semanticRun >= PASSsemantic2) - return; - semanticRun = PASSsemantic2; -#if LOG - printf("+TemplateMixin::semantic2('%s')\n", toChars()); -#endif - if (members) - { - assert(sc); - sc = sc->push(argsym); - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; -#if LOG - printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); -#endif - s->semantic2(sc); - } - sc = sc->pop(); - sc->pop(); - } -#if LOG - printf("-TemplateMixin::semantic2('%s')\n", toChars()); -#endif -} - -void TemplateMixin::semantic3(Scope *sc) -{ - if (semanticRun >= PASSsemantic3) - return; - semanticRun = PASSsemantic3; -#if LOG - printf("TemplateMixin::semantic3('%s')\n", toChars()); -#endif - if (members) - { - sc = sc->push(argsym); - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->semantic3(sc); - } - sc = sc->pop(); - sc->pop(); - } -} - -void TemplateMixin::inlineScan() -{ - TemplateInstance::inlineScan(); -} - -const char *TemplateMixin::kind() -{ - return "mixin"; -} - -int TemplateMixin::oneMember(Dsymbol **ps) -{ - return Dsymbol::oneMember(ps); -} - -int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param) -{ - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - if (s) - { - if (s->apply(fp, param)) - return 1; - } - } - } - return 0; -} - -int TemplateMixin::hasPointers() -{ - //printf("TemplateMixin::hasPointers() %s\n", toChars()); - - if (members) - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - //printf(" s = %s %s\n", s->kind(), s->toChars()); - if (s->hasPointers()) - { - return 1; - } - } - return 0; -} - -void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - //printf("TemplateMixin::setFieldOffset() %s\n", toChars()); - if (scope) // if fwd reference - semantic(NULL); // try to resolve it - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - //printf("\t%s\n", s->toChars()); - s->setFieldOffset(ad, poffset, isunion); - } - } -} - -char *TemplateMixin::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *s; - - TemplateInstance::toCBuffer(&buf, &hgs); - s = buf.toChars(); - buf.data = NULL; - return s; -} - -void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin "); - - for (size_t i = 0; i < idents->dim; i++) - { Identifier *id = idents->tdata()[i]; - - if (i) - buf->writeByte('.'); - buf->writestring(id->toChars()); - } - buf->writestring("!("); - if (tiargs) - { - for (size_t i = 0; i < tiargs->dim; i++) - { if (i) - buf->writebyte(','); - Object *oarg = (Object *)tiargs->data[i]; - Type *t = isType(oarg); - Expression *e = isExpression(oarg); - Dsymbol *s = isDsymbol(oarg); - if (t) - t->toCBuffer(buf, NULL, hgs); - else if (e) - e->toCBuffer(buf, hgs); - else if (s) - { - char *p = s->ident ? s->ident->toChars() : s->toChars(); - buf->writestring(p); - } - else if (!oarg) - { - buf->writestring("NULL"); - } - else - { - assert(0); - } - } - } - buf->writebyte(')'); - if (ident) - { - buf->writebyte(' '); - buf->writestring(ident->toChars()); - } - buf->writebyte(';'); - buf->writenl(); -} - - -#if IN_DMD -void TemplateMixin::toObjFile(int multiobj) -{ - //printf("TemplateMixin::toObjFile('%s')\n", toChars()); - TemplateInstance::toObjFile(multiobj); -} -#endif - diff --git a/dmd/template.h b/dmd/template.h deleted file mode 100644 index 352b5bcd..00000000 --- a/dmd/template.h +++ /dev/null @@ -1,388 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_TEMPLATE_H -#define DMD_TEMPLATE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include - -#include "root.h" -#include "arraytypes.h" -#include "dsymbol.h" -#include "mtype.h" - - -struct OutBuffer; -struct Identifier; -struct TemplateInstance; -struct TemplateParameter; -struct TemplateTypeParameter; -struct TemplateThisParameter; -struct TemplateValueParameter; -struct TemplateAliasParameter; -struct TemplateTupleParameter; -struct Type; -struct TypeTypeof; -struct Scope; -struct Expression; -struct AliasDeclaration; -struct FuncDeclaration; -struct HdrGenState; -enum MATCH; -enum PASS; - -struct Tuple : Object -{ - Objects objects; - - int dyncast() { return DYNCAST_TUPLE; } // kludge for template.isType() -}; - - -struct TemplateDeclaration : ScopeDsymbol -{ - TemplateParameters *parameters; // array of TemplateParameter's - - TemplateParameters *origParameters; // originals for Ddoc - Expression *constraint; - TemplateInstances instances; // array of TemplateInstance's - - TemplateDeclaration *overnext; // next overloaded TemplateDeclaration - TemplateDeclaration *overroot; // first in overnext list - - enum PASS semanticRun; // 1 semantic() run - - Dsymbol *onemember; // if !=NULL then one member of this template - - TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, - Expression *constraint, Dsymbols *decldefs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int overloadInsert(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - bool hasStaticCtorOrDtor(); - const char *kind(); - char *toChars(); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); -// void toDocBuffer(OutBuffer *buf); - - MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, int flag); - MATCH leastAsSpecialized(TemplateDeclaration *td2); - - MATCH deduceFunctionTemplateMatch(Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, Objects *dedargs); - FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, int flags = 0); - void declareParameter(Scope *sc, TemplateParameter *tp, Object *o); - - TemplateDeclaration *isTemplateDeclaration() { return this; } - - TemplateTupleParameter *isVariadic(); - int isOverloadable(); - - void makeParamNamesVisibleInConstraint(Scope *paramscope); - -#if IN_LLVM - // LDC - std::string intrinsicName; -#endif -}; - -struct TemplateParameter -{ - /* For type-parameter: - * template Foo(ident) // specType is set to NULL - * template Foo(ident : specType) - * For value-parameter: - * template Foo(valType ident) // specValue is set to NULL - * template Foo(valType ident : specValue) - * For alias-parameter: - * template Foo(alias ident) - * For this-parameter: - * template Foo(this ident) - */ - - Loc loc; - Identifier *ident; - - Declaration *sparam; - - TemplateParameter(Loc loc, Identifier *ident); - - virtual TemplateTypeParameter *isTemplateTypeParameter(); - virtual TemplateValueParameter *isTemplateValueParameter(); - virtual TemplateAliasParameter *isTemplateAliasParameter(); -#if DMDV2 - virtual TemplateThisParameter *isTemplateThisParameter(); -#endif - virtual TemplateTupleParameter *isTemplateTupleParameter(); - - virtual TemplateParameter *syntaxCopy() = 0; - virtual void declareParameter(Scope *sc) = 0; - virtual void semantic(Scope *) = 0; - virtual void print(Object *oarg, Object *oded) = 0; - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; - virtual Object *specialization() = 0; - virtual Object *defaultArg(Loc loc, Scope *sc) = 0; - - /* If TemplateParameter's match as far as overloading goes. - */ - virtual int overloadMatch(TemplateParameter *) = 0; - - /* Match actual argument against parameter. - */ - virtual MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags = 0) = 0; - - /* Create dummy argument based on parameter. - */ - virtual void *dummyArg() = 0; -}; - -struct TemplateTypeParameter : TemplateParameter -{ - /* Syntax: - * ident : specType = defaultType - */ - Type *specType; // type parameter: if !=NULL, this is the type specialization - Type *defaultType; - - TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); - - TemplateTypeParameter *isTemplateTypeParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); - void *dummyArg(); -}; - -#if DMDV2 -struct TemplateThisParameter : TemplateTypeParameter -{ - /* Syntax: - * this ident : specType = defaultType - */ - Type *specType; // type parameter: if !=NULL, this is the type specialization - Type *defaultType; - - TemplateThisParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); - - TemplateThisParameter *isTemplateThisParameter(); - TemplateParameter *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; -#endif - -struct TemplateValueParameter : TemplateParameter -{ - /* Syntax: - * valType ident : specValue = defaultValue - */ - - Type *valType; - Expression *specValue; - Expression *defaultValue; - - static AA *edummies; - - TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue); - - TemplateValueParameter *isTemplateValueParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); - void *dummyArg(); -}; - -struct TemplateAliasParameter : TemplateParameter -{ - /* Syntax: - * specType ident : specAlias = defaultAlias - */ - - Type *specAliasT; - Dsymbol *specAlias; - - Type *defaultAlias; - - static Dsymbol *sdummy; - - TemplateAliasParameter(Loc loc, Identifier *ident, Type *specAliasT, Type *defaultAlias); - - TemplateAliasParameter *isTemplateAliasParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); - void *dummyArg(); -}; - -struct TemplateTupleParameter : TemplateParameter -{ - /* Syntax: - * ident ... - */ - - TemplateTupleParameter(Loc loc, Identifier *ident); - - TemplateTupleParameter *isTemplateTupleParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); - void *dummyArg(); -}; - -struct TemplateInstance : ScopeDsymbol -{ - /* Given: - * foo!(args) => - * name = foo - * tiargs = args - */ - Identifier *name; - //Identifiers idents; - Objects *tiargs; // Array of Types/Expressions of template - // instance arguments [int*, char, 10*10] - - Objects tdtypes; // Array of Types/Expressions corresponding - // to TemplateDeclaration.parameters - // [int, char, 100] - - TemplateDeclaration *tempdecl; // referenced by foo.bar.abc - TemplateInstance *inst; // refer to existing instance - TemplateInstance *tinst; // enclosing template instance - ScopeDsymbol *argsym; // argument symbol table - AliasDeclaration *aliasdecl; // !=NULL if instance is an alias for its - // sole member - WithScopeSymbol *withsym; // if a member of a with statement - enum PASS semanticRun; // has semantic() been done? - int semantictiargsdone; // has semanticTiargs() been done? - int nest; // for recursion detection - int havetempdecl; // 1 if used second constructor - Dsymbol *isnested; // if referencing local symbols, this is the context - int speculative; // 1 if only instantiated with errors gagged -#ifdef IN_GCC - /* On some targets, it is necessary to know whether a symbol - will be emitted in the output or not before the symbol - is used. This can be different from getModule(). */ - Module * objFileModule; -#endif - - TemplateInstance(Loc loc, Identifier *temp_id); - TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs); - static Objects *arraySyntaxCopy(Objects *objs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Dsymbol *toAlias(); // resolve real symbol - const char *kind(); - int oneMember(Dsymbol **ps); - int needsTypeInference(Scope *sc); - char *toChars(); - char *mangle(); - void printInstantiationTrace(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - - // Internal - static void semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags); - void semanticTiargs(Scope *sc); - TemplateDeclaration *findTemplateDeclaration(Scope *sc); - TemplateDeclaration *findBestMatch(Scope *sc); - void declareParameters(Scope *sc); - int hasNestedArgs(Objects *tiargs); - Identifier *genIdent(); - - TemplateInstance *isTemplateInstance() { return this; } - AliasDeclaration *isAliasDeclaration(); - -#if IN_LLVM - // LDC - Module* tmodule; // module from outermost enclosing template instantiation - Module* emittedInModule; // which module this template instance has been emitted in - - void codegen(Ir*); -#endif -}; - -struct TemplateMixin : TemplateInstance -{ - Identifiers *idents; - Type *tqual; - - TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Identifiers *idents, Objects *tiargs); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - const char *kind(); - int oneMember(Dsymbol **ps); - int apply(Dsymbol_apply_ft_t fp, void *param); - int hasPointers(); - void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - char *toChars(); - char *mangle(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - - TemplateMixin *isTemplateMixin() { return this; } - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -Expression *isExpression(Object *o); -Dsymbol *isDsymbol(Object *o); -Type *isType(Object *o); -Tuple *isTuple(Object *o); -int arrayObjectIsError(Objects *args); -int isError(Object *o); -Type *getType(Object *o); -Dsymbol *getDsymbol(Object *o); - -void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg); - -#endif /* DMD_TEMPLATE_H */ diff --git a/dmd/unialpha.c b/dmd/unialpha.c deleted file mode 100644 index 5c407180..00000000 --- a/dmd/unialpha.c +++ /dev/null @@ -1,323 +0,0 @@ - -// Copyright (c) 2003 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include - -/******************************* - * Return !=0 if unicode alpha. - * Use table from C99 Appendix D. - */ - -int isUniAlpha(unsigned u) -{ - static unsigned short table[][2] = - { - { 0x00AA, 0x00AA }, - { 0x00B5, 0x00B5 }, - { 0x00B7, 0x00B7 }, - { 0x00BA, 0x00BA }, - { 0x00C0, 0x00D6 }, - { 0x00D8, 0x00F6 }, - { 0x00F8, 0x01F5 }, - { 0x01FA, 0x0217 }, - { 0x0250, 0x02A8 }, - { 0x02B0, 0x02B8 }, - { 0x02BB, 0x02BB }, - { 0x02BD, 0x02C1 }, - { 0x02D0, 0x02D1 }, - { 0x02E0, 0x02E4 }, - { 0x037A, 0x037A }, - { 0x0386, 0x0386 }, - { 0x0388, 0x038A }, - { 0x038C, 0x038C }, - { 0x038E, 0x03A1 }, - { 0x03A3, 0x03CE }, - { 0x03D0, 0x03D6 }, - { 0x03DA, 0x03DA }, - { 0x03DC, 0x03DC }, - { 0x03DE, 0x03DE }, - { 0x03E0, 0x03E0 }, - { 0x03E2, 0x03F3 }, - { 0x0401, 0x040C }, - { 0x040E, 0x044F }, - { 0x0451, 0x045C }, - { 0x045E, 0x0481 }, - { 0x0490, 0x04C4 }, - { 0x04C7, 0x04C8 }, - { 0x04CB, 0x04CC }, - { 0x04D0, 0x04EB }, - { 0x04EE, 0x04F5 }, - { 0x04F8, 0x04F9 }, - { 0x0531, 0x0556 }, - { 0x0559, 0x0559 }, - { 0x0561, 0x0587 }, - { 0x05B0, 0x05B9 }, - { 0x05BB, 0x05BD }, - { 0x05BF, 0x05BF }, - { 0x05C1, 0x05C2 }, - { 0x05D0, 0x05EA }, - { 0x05F0, 0x05F2 }, - { 0x0621, 0x063A }, - { 0x0640, 0x0652 }, - { 0x0660, 0x0669 }, - { 0x0670, 0x06B7 }, - { 0x06BA, 0x06BE }, - { 0x06C0, 0x06CE }, - { 0x06D0, 0x06DC }, - { 0x06E5, 0x06E8 }, - { 0x06EA, 0x06ED }, - { 0x06F0, 0x06F9 }, - { 0x0901, 0x0903 }, - { 0x0905, 0x0939 }, - { 0x093D, 0x093D }, - { 0x093E, 0x094D }, - { 0x0950, 0x0952 }, - { 0x0958, 0x0963 }, - { 0x0966, 0x096F }, - { 0x0981, 0x0983 }, - { 0x0985, 0x098C }, - { 0x098F, 0x0990 }, - { 0x0993, 0x09A8 }, - { 0x09AA, 0x09B0 }, - { 0x09B2, 0x09B2 }, - { 0x09B6, 0x09B9 }, - { 0x09BE, 0x09C4 }, - { 0x09C7, 0x09C8 }, - { 0x09CB, 0x09CD }, - { 0x09DC, 0x09DD }, - { 0x09DF, 0x09E3 }, - { 0x09E6, 0x09EF }, - { 0x09F0, 0x09F1 }, - { 0x0A02, 0x0A02 }, - { 0x0A05, 0x0A0A }, - { 0x0A0F, 0x0A10 }, - { 0x0A13, 0x0A28 }, - { 0x0A2A, 0x0A30 }, - { 0x0A32, 0x0A33 }, - { 0x0A35, 0x0A36 }, - { 0x0A38, 0x0A39 }, - { 0x0A3E, 0x0A42 }, - { 0x0A47, 0x0A48 }, - { 0x0A4B, 0x0A4D }, - { 0x0A59, 0x0A5C }, - { 0x0A5E, 0x0A5E }, - { 0x0A66, 0x0A6F }, - { 0x0A74, 0x0A74 }, - { 0x0A81, 0x0A83 }, - { 0x0A85, 0x0A8B }, - { 0x0A8D, 0x0A8D }, - { 0x0A8F, 0x0A91 }, - { 0x0A93, 0x0AA8 }, - { 0x0AAA, 0x0AB0 }, - { 0x0AB2, 0x0AB3 }, - { 0x0AB5, 0x0AB9 }, - { 0x0ABD, 0x0AC5 }, - { 0x0AC7, 0x0AC9 }, - { 0x0ACB, 0x0ACD }, - { 0x0AD0, 0x0AD0 }, - { 0x0AE0, 0x0AE0 }, - { 0x0AE6, 0x0AEF }, - { 0x0B01, 0x0B03 }, - { 0x0B05, 0x0B0C }, - { 0x0B0F, 0x0B10 }, - { 0x0B13, 0x0B28 }, - { 0x0B2A, 0x0B30 }, - { 0x0B32, 0x0B33 }, - { 0x0B36, 0x0B39 }, - { 0x0B3D, 0x0B3D }, - { 0x0B3E, 0x0B43 }, - { 0x0B47, 0x0B48 }, - { 0x0B4B, 0x0B4D }, - { 0x0B5C, 0x0B5D }, - { 0x0B5F, 0x0B61 }, - { 0x0B66, 0x0B6F }, - { 0x0B82, 0x0B83 }, - { 0x0B85, 0x0B8A }, - { 0x0B8E, 0x0B90 }, - { 0x0B92, 0x0B95 }, - { 0x0B99, 0x0B9A }, - { 0x0B9C, 0x0B9C }, - { 0x0B9E, 0x0B9F }, - { 0x0BA3, 0x0BA4 }, - { 0x0BA8, 0x0BAA }, - { 0x0BAE, 0x0BB5 }, - { 0x0BB7, 0x0BB9 }, - { 0x0BBE, 0x0BC2 }, - { 0x0BC6, 0x0BC8 }, - { 0x0BCA, 0x0BCD }, - { 0x0BE7, 0x0BEF }, - { 0x0C01, 0x0C03 }, - { 0x0C05, 0x0C0C }, - { 0x0C0E, 0x0C10 }, - { 0x0C12, 0x0C28 }, - { 0x0C2A, 0x0C33 }, - { 0x0C35, 0x0C39 }, - { 0x0C3E, 0x0C44 }, - { 0x0C46, 0x0C48 }, - { 0x0C4A, 0x0C4D }, - { 0x0C60, 0x0C61 }, - { 0x0C66, 0x0C6F }, - { 0x0C82, 0x0C83 }, - { 0x0C85, 0x0C8C }, - { 0x0C8E, 0x0C90 }, - { 0x0C92, 0x0CA8 }, - { 0x0CAA, 0x0CB3 }, - { 0x0CB5, 0x0CB9 }, - { 0x0CBE, 0x0CC4 }, - { 0x0CC6, 0x0CC8 }, - { 0x0CCA, 0x0CCD }, - { 0x0CDE, 0x0CDE }, - { 0x0CE0, 0x0CE1 }, - { 0x0CE6, 0x0CEF }, - { 0x0D02, 0x0D03 }, - { 0x0D05, 0x0D0C }, - { 0x0D0E, 0x0D10 }, - { 0x0D12, 0x0D28 }, - { 0x0D2A, 0x0D39 }, - { 0x0D3E, 0x0D43 }, - { 0x0D46, 0x0D48 }, - { 0x0D4A, 0x0D4D }, - { 0x0D60, 0x0D61 }, - { 0x0D66, 0x0D6F }, - { 0x0E01, 0x0E3A }, - { 0x0E40, 0x0E5B }, -// { 0x0E50, 0x0E59 }, - { 0x0E81, 0x0E82 }, - { 0x0E84, 0x0E84 }, - { 0x0E87, 0x0E88 }, - { 0x0E8A, 0x0E8A }, - { 0x0E8D, 0x0E8D }, - { 0x0E94, 0x0E97 }, - { 0x0E99, 0x0E9F }, - { 0x0EA1, 0x0EA3 }, - { 0x0EA5, 0x0EA5 }, - { 0x0EA7, 0x0EA7 }, - { 0x0EAA, 0x0EAB }, - { 0x0EAD, 0x0EAE }, - { 0x0EB0, 0x0EB9 }, - { 0x0EBB, 0x0EBD }, - { 0x0EC0, 0x0EC4 }, - { 0x0EC6, 0x0EC6 }, - { 0x0EC8, 0x0ECD }, - { 0x0ED0, 0x0ED9 }, - { 0x0EDC, 0x0EDD }, - { 0x0F00, 0x0F00 }, - { 0x0F18, 0x0F19 }, - { 0x0F20, 0x0F33 }, - { 0x0F35, 0x0F35 }, - { 0x0F37, 0x0F37 }, - { 0x0F39, 0x0F39 }, - { 0x0F3E, 0x0F47 }, - { 0x0F49, 0x0F69 }, - { 0x0F71, 0x0F84 }, - { 0x0F86, 0x0F8B }, - { 0x0F90, 0x0F95 }, - { 0x0F97, 0x0F97 }, - { 0x0F99, 0x0FAD }, - { 0x0FB1, 0x0FB7 }, - { 0x0FB9, 0x0FB9 }, - { 0x10A0, 0x10C5 }, - { 0x10D0, 0x10F6 }, - { 0x1E00, 0x1E9B }, - { 0x1EA0, 0x1EF9 }, - { 0x1F00, 0x1F15 }, - { 0x1F18, 0x1F1D }, - { 0x1F20, 0x1F45 }, - { 0x1F48, 0x1F4D }, - { 0x1F50, 0x1F57 }, - { 0x1F59, 0x1F59 }, - { 0x1F5B, 0x1F5B }, - { 0x1F5D, 0x1F5D }, - { 0x1F5F, 0x1F7D }, - { 0x1F80, 0x1FB4 }, - { 0x1FB6, 0x1FBC }, - { 0x1FBE, 0x1FBE }, - { 0x1FC2, 0x1FC4 }, - { 0x1FC6, 0x1FCC }, - { 0x1FD0, 0x1FD3 }, - { 0x1FD6, 0x1FDB }, - { 0x1FE0, 0x1FEC }, - { 0x1FF2, 0x1FF4 }, - { 0x1FF6, 0x1FFC }, - { 0x203F, 0x2040 }, - { 0x207F, 0x207F }, - { 0x2102, 0x2102 }, - { 0x2107, 0x2107 }, - { 0x210A, 0x2113 }, - { 0x2115, 0x2115 }, - { 0x2118, 0x211D }, - { 0x2124, 0x2124 }, - { 0x2126, 0x2126 }, - { 0x2128, 0x2128 }, - { 0x212A, 0x2131 }, - { 0x2133, 0x2138 }, - { 0x2160, 0x2182 }, - { 0x3005, 0x3007 }, - { 0x3021, 0x3029 }, - { 0x3041, 0x3093 }, - { 0x309B, 0x309C }, - { 0x30A1, 0x30F6 }, - { 0x30FB, 0x30FC }, - { 0x3105, 0x312C }, - { 0x4E00, 0x9FA5 }, - { 0xAC00, 0xD7A3 }, - }; - -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - //printf("%x\n", table[i][0]); - assert(table[i][0] <= table[i][1]); - if (i < sizeof(table) / sizeof(table[0]) - 1) - assert(table[i][1] < table[i + 1][0]); - } -#endif - - if (u > 0xD7A3) - goto Lisnot; - - // Binary search - int mid; - int low; - int high; - - low = 0; - high = sizeof(table) / sizeof(table[0]) - 1; - while (low <= high) - { - mid = (low + high) >> 1; - if (u < table[mid][0]) - high = mid - 1; - else if (u > table[mid][1]) - low = mid + 1; - else - goto Lis; - } - -Lisnot: -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - assert(u < table[i][0] || u > table[i][1]); - } -#endif - return 0; - -Lis: -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (u >= table[i][0] && u <= table[i][1]) - return 1; - } - assert(0); // should have been in table -#endif - return 1; -} - diff --git a/dmd/utf.c b/dmd/utf.c deleted file mode 100644 index 78f8cd4a..00000000 --- a/dmd/utf.c +++ /dev/null @@ -1,320 +0,0 @@ -// utf.c -// Copyright (c) 2003-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Description of UTF-8 at: -// http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - -#include -#include -#include - -#include "utf.h" - -int utf_isValidDchar(dchar_t c) -{ - return c < 0xD800 || - (c > 0xDFFF && c <= 0x10FFFF && c != 0xFFFE && c != 0xFFFF); -} - -static const unsigned char UTF8stride[256] = -{ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF, -}; - -/** - * stride() returns the length of a UTF-8 sequence starting at index i - * in string s. - * Returns: - * The number of bytes in the UTF-8 sequence or - * 0xFF meaning s[i] is not the start of of UTF-8 sequence. - */ - -unsigned stride(unsigned char* s, size_t i) -{ - unsigned result = UTF8stride[s[i]]; - return result; -} - -/******************************************** - * Decode a single UTF-8 character sequence. - * Returns: - * NULL success - * !=NULL error message string - */ - -const char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t *presult) -{ - dchar_t V; - size_t i = *pidx; - unsigned char u = s[i]; - - //printf("utf_decodeChar(s = %02x, %02x, %02x len = %d)\n", u, s[1], s[2], len); - - assert(i >= 0 && i < len); - - if (u & 0x80) - { unsigned n; - unsigned char u2; - - /* The following encodings are valid, except for the 5 and 6 byte - * combinations: - * 0xxxxxxx - * 110xxxxx 10xxxxxx - * 1110xxxx 10xxxxxx 10xxxxxx - * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - for (n = 1; ; n++) - { - if (n > 4) - goto Lerr; // only do the first 4 of 6 encodings - if (((u << n) & 0x80) == 0) - { - if (n == 1) - goto Lerr; - break; - } - } - - // Pick off (7 - n) significant bits of B from first byte of octet - V = (dchar_t)(u & ((1 << (7 - n)) - 1)); - - if (i + (n - 1) >= len) - goto Lerr; // off end of string - - /* The following combinations are overlong, and illegal: - * 1100000x (10xxxxxx) - * 11100000 100xxxxx (10xxxxxx) - * 11110000 1000xxxx (10xxxxxx 10xxxxxx) - * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) - * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) - */ - u2 = s[i + 1]; - if ((u & 0xFE) == 0xC0 || - (u == 0xE0 && (u2 & 0xE0) == 0x80) || - (u == 0xF0 && (u2 & 0xF0) == 0x80) || - (u == 0xF8 && (u2 & 0xF8) == 0x80) || - (u == 0xFC && (u2 & 0xFC) == 0x80)) - goto Lerr; // overlong combination - - for (unsigned j = 1; j != n; j++) - { - u = s[i + j]; - if ((u & 0xC0) != 0x80) - goto Lerr; // trailing bytes are 10xxxxxx - V = (V << 6) | (u & 0x3F); - } - if (!utf_isValidDchar(V)) - goto Lerr; - i += n; - } - else - { - V = (dchar_t) u; - i++; - } - - assert(utf_isValidDchar(V)); - *pidx = i; - *presult = V; - return NULL; - - Lerr: - *presult = (dchar_t) s[i]; - *pidx = i + 1; - return "invalid UTF-8 sequence"; -} - -/*************************************************** - * Validate a UTF-8 string. - * Returns: - * NULL success - * !=NULL error message string - */ - -const char *utf_validateString(unsigned char *s, size_t len) -{ - size_t idx; - const char *err = NULL; - dchar_t dc; - - for (idx = 0; idx < len; ) - { - err = utf_decodeChar(s, len, &idx, &dc); - if (err) - break; - } - return err; -} - - -/******************************************** - * Decode a single UTF-16 character sequence. - * Returns: - * NULL success - * !=NULL error message string - */ - - -const char *utf_decodeWchar(unsigned short *s, size_t len, size_t *pidx, dchar_t *presult) -{ - const char *msg; - size_t i = *pidx; - unsigned u = s[i]; - - assert(i >= 0 && i < len); - if (u & ~0x7F) - { if (u >= 0xD800 && u <= 0xDBFF) - { unsigned u2; - - if (i + 1 == len) - { msg = "surrogate UTF-16 high value past end of string"; - goto Lerr; - } - u2 = s[i + 1]; - if (u2 < 0xDC00 || u2 > 0xDFFF) - { msg = "surrogate UTF-16 low value out of range"; - goto Lerr; - } - u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); - i += 2; - } - else if (u >= 0xDC00 && u <= 0xDFFF) - { msg = "unpaired surrogate UTF-16 value"; - goto Lerr; - } - else if (u == 0xFFFE || u == 0xFFFF) - { msg = "illegal UTF-16 value"; - goto Lerr; - } - else - i++; - } - else - { - i++; - } - - assert(utf_isValidDchar(u)); - *pidx = i; - *presult = (dchar_t)u; - return NULL; - - Lerr: - *presult = (dchar_t)s[i]; - *pidx = i + 1; - return msg; -} - -void utf_encodeChar(unsigned char *s, dchar_t c) -{ - if (c <= 0x7F) - { - s[0] = (char) c; - } - else if (c <= 0x7FF) - { - s[0] = (char)(0xC0 | (c >> 6)); - s[1] = (char)(0x80 | (c & 0x3F)); - } - else if (c <= 0xFFFF) - { - s[0] = (char)(0xE0 | (c >> 12)); - s[1] = (char)(0x80 | ((c >> 6) & 0x3F)); - s[2] = (char)(0x80 | (c & 0x3F)); - } - else if (c <= 0x10FFFF) - { - s[0] = (char)(0xF0 | (c >> 18)); - s[1] = (char)(0x80 | ((c >> 12) & 0x3F)); - s[2] = (char)(0x80 | ((c >> 6) & 0x3F)); - s[3] = (char)(0x80 | (c & 0x3F)); - } - else - assert(0); -} - -void utf_encodeWchar(unsigned short *s, dchar_t c) -{ - if (c <= 0xFFFF) - { - s[0] = (wchar_t) c; - } - else - { - s[0] = (wchar_t) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); - s[1] = (wchar_t) (((c - 0x10000) & 0x3FF) + 0xDC00); - } -} - - -/** - * Returns the code length of c in the encoding. - * The code is returned in character count, not in bytes. - */ - -int utf_codeLengthChar(dchar_t c) -{ - return - c <= 0x7F ? 1 - : c <= 0x7FF ? 2 - : c <= 0xFFFF ? 3 - : c <= 0x10FFFF ? 4 - : (assert(false), 6); -} - -int utf_codeLengthWchar(dchar_t c) -{ - return c <= 0xFFFF ? 1 : 2; -} - -/** - * Returns the code length of c in the encoding. - * sz is the encoding: 1 = utf8, 2 = utf16, 4 = utf32. - * The code is returned in character count, not in bytes. - */ -int utf_codeLength(int sz, dchar_t c) -{ - if (sz == 1) - return utf_codeLengthChar(c); - if (sz == 2) - return utf_codeLengthWchar(c); - assert(sz == 4); - return 1; -} - -void utf_encode(int sz, void *s, dchar_t c) -{ - if (sz == 1) - utf_encodeChar((unsigned char *)s, c); - else if (sz == 2) - utf_encodeWchar((unsigned short *)s, c); - else - { - assert(sz == 4); - memcpy((unsigned char *)s, &c, sz); - } -} - diff --git a/dmd/utf.h b/dmd/utf.h deleted file mode 100644 index 22d8d3eb..00000000 --- a/dmd/utf.h +++ /dev/null @@ -1,35 +0,0 @@ -// Compiler implementation of the D programming language -// utf.h -// Copyright (c) 2003-2010 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_UTF_H -#define DMD_UTF_H - - -typedef unsigned dchar_t; - -int utf_isValidDchar(dchar_t c); - -const char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t *presult); -const char *utf_decodeWchar(unsigned short *s, size_t len, size_t *pidx, dchar_t *presult); - -const char *utf_validateString(unsigned char *s, size_t len); - -extern int isUniAlpha(dchar_t); - -void utf_encodeChar(unsigned char *s, dchar_t c); -void utf_encodeWchar(unsigned short *s, dchar_t c); - -int utf_codeLengthChar(dchar_t c); -int utf_codeLengthWchar(dchar_t c); - -int utf_codeLength(int sz, dchar_t c); -void utf_encode(int sz, void *s, dchar_t c); - -#endif diff --git a/dmd/version.c b/dmd/version.c deleted file mode 100644 index 37f33c06..00000000 --- a/dmd/version.c +++ /dev/null @@ -1,181 +0,0 @@ - -// Copyright (c) 1999-2005 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" - -#include "identifier.h" -#include "dsymbol.h" -#include "cond.h" -#include "version.h" -#include "module.h" - -/* ================================================== */ - -/* DebugSymbol's happen for statements like: - * debug = identifier; - * debug = integer; - */ - -DebugSymbol::DebugSymbol(Loc loc, Identifier *ident) - : Dsymbol(ident) -{ - this->loc = loc; -} - -DebugSymbol::DebugSymbol(Loc loc, unsigned level) - : Dsymbol() -{ - this->level = level; - this->loc = loc; -} - -Dsymbol *DebugSymbol::syntaxCopy(Dsymbol *s) -{ - assert(!s); - DebugSymbol *ds = new DebugSymbol(loc, ident); - ds->level = level; - return ds; -} - -int DebugSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("DebugSymbol::addMember('%s') %s\n", sd->toChars(), toChars()); - Module *m; - - // Do not add the member to the symbol table, - // just make sure subsequent debug declarations work. - m = sd->isModule(); - if (ident) - { - if (!m) - error("declaration must be at module level"); - else - { - if (findCondition(m->debugidsNot, ident)) - error("defined after use"); - if (!m->debugids) - m->debugids = new Strings(); - m->debugids->push(ident->toChars()); - } - } - else - { - if (!m) - error("level declaration must be at module level"); - else - m->debuglevel = level; - } - return 0; -} - -void DebugSymbol::semantic(Scope *sc) -{ - //printf("DebugSymbol::semantic() %s\n", toChars()); -} - -void DebugSymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("debug = "); - if (ident) - buf->writestring(ident->toChars()); - else - buf->printf("%u", level); - buf->writestring(";"); - buf->writenl(); -} - -const char *DebugSymbol::kind() -{ - return "debug"; -} - -/* ================================================== */ - -/* VersionSymbol's happen for statements like: - * version = identifier; - * version = integer; - */ - -VersionSymbol::VersionSymbol(Loc loc, Identifier *ident) - : Dsymbol(ident) -{ - this->loc = loc; -} - -VersionSymbol::VersionSymbol(Loc loc, unsigned level) - : Dsymbol() -{ - this->level = level; - this->loc = loc; -} - -Dsymbol *VersionSymbol::syntaxCopy(Dsymbol *s) -{ - assert(!s); - VersionSymbol *ds = new VersionSymbol(loc, ident); - ds->level = level; - return ds; -} - -int VersionSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("VersionSymbol::addMember('%s') %s\n", sd->toChars(), toChars()); - Module *m; - - // Do not add the member to the symbol table, - // just make sure subsequent debug declarations work. - m = sd->isModule(); - if (ident) - { - VersionCondition::checkPredefined(loc, ident->toChars()); - if (!m) - error("declaration must be at module level"); - else - { - if (findCondition(m->versionidsNot, ident)) - error("defined after use"); - if (!m->versionids) - m->versionids = new Strings(); - m->versionids->push(ident->toChars()); - } - } - else - { - if (!m) - error("level declaration must be at module level"); - else - m->versionlevel = level; - } - return 0; -} - -void VersionSymbol::semantic(Scope *sc) -{ -} - -void VersionSymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("version = "); - if (ident) - buf->writestring(ident->toChars()); - else - buf->printf("%u", level); - buf->writestring(";"); - buf->writenl(); -} - -const char *VersionSymbol::kind() -{ - return "version"; -} - - diff --git a/dmd/version.h b/dmd/version.h deleted file mode 100644 index b5ae51d2..00000000 --- a/dmd/version.h +++ /dev/null @@ -1,51 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_VERSION_H -#define DMD_VERSION_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - -struct OutBuffer; -struct HdrGenState; - -struct DebugSymbol : Dsymbol -{ - unsigned level; - - DebugSymbol(Loc loc, Identifier *ident); - DebugSymbol(Loc loc, unsigned level); - Dsymbol *syntaxCopy(Dsymbol *); - - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); -}; - -struct VersionSymbol : Dsymbol -{ - unsigned level; - - VersionSymbol(Loc loc, Identifier *ident); - VersionSymbol(Loc loc, unsigned level); - Dsymbol *syntaxCopy(Dsymbol *); - - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); -}; - -#endif /* DMD_VERSION_H */ diff --git a/ldc-posix-tango b/ldc-posix-tango deleted file mode 100644 index d5c67c40..00000000 --- a/ldc-posix-tango +++ /dev/null @@ -1,78 +0,0 @@ -ignore=object - -compiler=ldc -inifile=ldc.rebuild.conf - -exeext= -objext=o - - -version=LLVM -version=LDC -noversion=DigitalMars -noversion=GNU -testversion=linux -testversion=darwin -testversion=freebsd -testversion=Unix -testversion=Posix -testversion=Windows -testversion=Win32 -testversion=Win64 -testversion=mingw32 -testversion=X86 -testversion=PPC -testversion=X86_64 -testversion=PPC64 -testversion=D_InlineAsm -testversion=D_InlineAsm_X86 -testversion=D_InlineAsm_PPC -testversion=D_InlineAsm_X86_64 -testversion=D_InlineAsm_PPC64 -testversion=LLVM_InlineAsm_X86 -testversion=LittleEndian -testversion=BigEndian -testversion=LLVM64 -testversion=PIC -testversion=Tango - - -[compile] -oneatatime=yes -cmd=ldmd -c $i - -flag=$i -incdir=-I$i -libdir=-L-L$i -optimize=-O3 -version=-version=$i - - -[link] -oneatatime=yes -cmd=ldc $i -of$o - -libdir=-L-L$i -lib=-L-l$i -flag=-L$i - - -[liblink] -safe=yes -oneatatime=yes -cmd=ar rc $o $i - -libdir= -lib= -flag= - - -[postliblink] -cmd=ranlib $i - - -[shliblink] -shlibs=no - -[dyliblink] -dylibs=no From 1e4a8fffc2e0dc913e0e947ae3eeccb338c0a4b0 Mon Sep 17 00:00:00 2001 From: kai Date: Tue, 5 Mar 2013 18:37:09 +0100 Subject: [PATCH 2/6] Remove DMDV1 and DMDV2. --- driver/cl_options.cpp | 9 - driver/cl_options.h | 2 - driver/ldmd.cpp | 12 -- driver/main.cpp | 17 -- gen/aa.cpp | 54 ------ gen/abi-ppc64.cpp | 3 +- gen/abi-win64.cpp | 4 - gen/abi-x86-64.cpp | 3 +- gen/abi-x86.cpp | 3 +- gen/abi.cpp | 3 +- gen/arrays.cpp | 272 ---------------------------- gen/arrays.h | 5 - gen/asmstmt.cpp | 7 - gen/binops.cpp | 9 - gen/classes.cpp | 5 - gen/declarations.cpp | 12 +- gen/functions.cpp | 39 ---- gen/irstate.h | 6 - gen/llvmhelpers.cpp | 61 ------- gen/llvmhelpers.h | 2 - gen/module.cpp | 27 --- gen/nested.cpp | 50 +---- gen/nested.h | 4 - gen/passes/GarbageCollect2Stack.cpp | 5 - gen/pragma.cpp | 6 - gen/runtime.cpp | 139 -------------- gen/runtime.h | 6 - gen/statements.cpp | 33 +--- gen/structs.cpp | 2 - gen/tocall.cpp | 16 -- gen/todebug.cpp | 4 - gen/toir.cpp | 80 -------- gen/tollvm.cpp | 6 - gen/typinf.cpp | 59 ------ ir/irclass.cpp | 2 - ir/irlandingpad.cpp | 8 - ir/irstruct.cpp | 2 - ir/irtype.cpp | 4 - ir/irtype.h | 6 - ir/irtypeclass.cpp | 2 - 40 files changed, 8 insertions(+), 981 deletions(-) diff --git a/driver/cl_options.cpp b/driver/cl_options.cpp index dda40e86..76878d02 100644 --- a/driver/cl_options.cpp +++ b/driver/cl_options.cpp @@ -31,12 +31,6 @@ cl::list runargs("run", cl::Positional, cl::PositionalEatsArgs); -#if DMDV1 -static cl::opt useDeprecated("d", - cl::desc("Allow deprecated language features"), - cl::ZeroOrMore, - cl::location(global.params.useDeprecated)); -#else static cl::opt useDeprecated( cl::desc("Allow deprecated code/language features:"), cl::ZeroOrMore, @@ -47,14 +41,11 @@ static cl::opt useDeprecated( clEnumValEnd), cl::location(global.params.useDeprecated), cl::init(2)); -#endif -#if DMDV2 cl::opt enforcePropertySyntax("property", cl::desc("Enforce property syntax"), cl::ZeroOrMore, cl::location(global.params.enforcePropertySyntax)); -#endif static cl::opt useDv1( cl::desc("Force language version:"), diff --git a/driver/cl_options.h b/driver/cl_options.h index 605b21e3..d1320894 100644 --- a/driver/cl_options.h +++ b/driver/cl_options.h @@ -31,9 +31,7 @@ namespace opts { extern cl::list fileList; extern cl::list runargs; extern cl::opt compileOnly; -#if DMDV2 extern cl::opt enforcePropertySyntax; -#endif extern cl::opt createStaticLib; extern cl::opt createSharedLib; extern cl::opt noAsm; diff --git a/driver/ldmd.cpp b/driver/ldmd.cpp index 498d1032..d6de17b0 100644 --- a/driver/ldmd.cpp +++ b/driver/ldmd.cpp @@ -185,9 +185,7 @@ Usage:\n\ #if 0 " -map generate linker .map file\n" #endif -#if DMDV2 " -noboundscheck turns off array bounds checking for all functions\n" -#endif " -nofloat do not emit reference to floating point\n\ -O optimize\n\ -o- do not write object file\n\ @@ -450,18 +448,12 @@ Params parseArgs(size_t originalArgc, char** originalArgv, ls::Path ldcPath) result.verbose = true; else if (strcmp(p + 1, "vdmd") == 0) result.vdmd = true; -#if DMDV2 else if (strcmp(p + 1, "vtls") == 0) result.logTlsUse = true; -#endif else if (strcmp(p + 1, "v1") == 0) { -#if DMDV1 - // Just ignore, for backwards compatibility. -#else error("use DMD 1.0 series compilers for -v1 switch"); break; -#endif } else if (strcmp(p + 1, "w") == 0) result.warnings = Warnings::asErrors; @@ -582,10 +574,8 @@ Params parseArgs(size_t originalArgc, char** originalArgv, ls::Path ldcPath) result.quiet = 1; else if (strcmp(p + 1, "release") == 0) result.release = 1; -#if DMDV2 else if (strcmp(p + 1, "noboundscheck") == 0) result.noBoundsChecks = 1; -#endif else if (strcmp(p + 1, "unittest") == 0) result.emitUnitTests = 1; else if (p[1] == 'I') @@ -752,12 +742,10 @@ void buildCommandLine(std::vector& r, const Params& p) if (p.emitSharedLib) r.push_back("-shared"); if (p.pic) r.push_back("-relocation-model=pic"); if (p.emitMap) warning("Map file generation not yet supported by LDC."); -#ifndef DMDV1 // LDMD historically did not enable singleobj mode, so in order not to // break build systems as a D1 parting gift, don't change this right now. // This might change based on user feedback, though. if (!p.multiObj) r.push_back("-singleobj"); -#endif if (p.debugInfo == Debug::normal) r.push_back("-g"); else if (p.debugInfo == Debug::pretendC) r.push_back("-gc"); if (p.alwaysStackFrame) r.push_back("-disable-fp-elim"); diff --git a/driver/main.cpp b/driver/main.cpp index 608fbb17..4dd31edc 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -192,9 +192,7 @@ int main(int argc, char** argv) VersionCondition::addPredefinedGlobalIdent("LLVM"); // For backwards compatibility. VersionCondition::addPredefinedGlobalIdent("LDC"); VersionCondition::addPredefinedGlobalIdent("all"); -#if DMDV2 VersionCondition::addPredefinedGlobalIdent("D_Version2"); -#endif // build complete fixed up list of command line arguments std::vector final_args; @@ -210,11 +208,7 @@ int main(int argc, char** argv) ConfigFile cfg_file; // just ignore errors for now, they are still printed -#if DMDV2 #define CFG_FILENAME "ldc2.conf" -#else -#define CFG_FILENAME "ldc.conf" -#endif cfg_file.read(global.params.argv0, (void*)main, CFG_FILENAME); #undef CFG_FILENAME @@ -374,16 +368,7 @@ int main(int argc, char** argv) } else { -#if DMDV2 global.params.linkswitches->push(mem.strdup("-ldruntime-ldc")); -#else - global.params.linkswitches->push(mem.strdup("-lldc-runtime")); - global.params.linkswitches->push(mem.strdup("-ltango-cc-tango")); - global.params.linkswitches->push(mem.strdup("-ltango-gc-basic")); - // pass the runtime again to resolve issues - // with linking order - global.params.linkswitches->push(mem.strdup("-lldc-runtime")); -#endif } } @@ -748,7 +733,6 @@ int main(int argc, char** argv) if (global.params.doDocComments) VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); -#if DMDV2 // unittests? if (global.params.useUnitTests) VersionCondition::addPredefinedGlobalIdent("unittest"); @@ -758,7 +742,6 @@ int main(int argc, char** argv) if (!global.params.useArrayBounds) VersionCondition::addPredefinedGlobalIdent("D_NoBoundsChecks"); -#endif // Initialization Type::init(&ir); diff --git a/gen/aa.cpp b/gen/aa.cpp index a88b108e..1f370611 100644 --- a/gen/aa.cpp +++ b/gen/aa.cpp @@ -21,7 +21,6 @@ #include "gen/tollvm.h" #include "ir/irmodule.h" -#if DMDV2 // returns the keytype typeinfo static LLValue* to_keyti(DValue* aa) { @@ -30,15 +29,6 @@ static LLValue* to_keyti(DValue* aa) TypeAArray * aatype = static_cast(aa->type->toBasetype()); return DtoTypeInfoOf(aatype->index, false); } -#else -// returns the keytype typeinfo -static LLValue* to_keyti(DValue* key) -{ - // keyti param - Type* keytype = key->getType(); - return DtoTypeInfoOf(keytype, false); -} -#endif ///////////////////////////////////////////////////////////////////////////////////// @@ -57,11 +47,7 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue) // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey) // first get the runtime function -#if DMDV2 llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, lvalue?"_aaGetX":"_aaInX"); -#else - llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, lvalue?"_aaGet":"_aaIn"); -#endif LLFunctionType* funcTy = func->getFunctionType(); // aa param @@ -69,11 +55,7 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue) aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // keyti param -#if DMDV2 LLValue* keyti = to_keyti(aa); -#else - LLValue* keyti = to_keyti(key); -#endif keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // pkey param @@ -113,16 +95,10 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue) std::vector args; -#if DMDV2 // module param LLValue *moduleInfoSymbol = gIR->func()->decl->getModule()->moduleInfoSymbol(); LLType *moduleInfoType = DtoType(Module::moduleinfo->type); args.push_back(DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType))); -#else - // file param - IrModule* irmod = getIrModule(NULL); - args.push_back(DtoLoad(irmod->fileName)); -#endif // line param LLConstant* c = DtoConstUint(loc.linnum); @@ -154,11 +130,7 @@ DValue* DtoAAIn(Loc& loc, Type* type, DValue* aa, DValue* key) // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey) // first get the runtime function -#if DMDV2 llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaInX"); -#else - llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaIn"); -#endif LLFunctionType* funcTy = func->getFunctionType(); if (Logger::enabled()) @@ -174,11 +146,7 @@ DValue* DtoAAIn(Loc& loc, Type* type, DValue* aa, DValue* key) aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // keyti param -#if DMDV2 LLValue* keyti = to_keyti(aa); -#else - LLValue* keyti = to_keyti(key); -#endif keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // pkey param @@ -209,11 +177,7 @@ DValue *DtoAARemove(Loc& loc, DValue* aa, DValue* key) // extern(C) bool _aaDelX(AA aa, TypeInfo keyti, void* pkey) // first get the runtime function -#if DMDV2 llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaDelX"); -#else - llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaDel"); -#endif LLFunctionType* funcTy = func->getFunctionType(); if (Logger::enabled()) @@ -229,11 +193,7 @@ DValue *DtoAARemove(Loc& loc, DValue* aa, DValue* key) aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // keyti param -#if DMDV2 LLValue* keyti = to_keyti(aa); -#else - LLValue* keyti = to_keyti(key); -#endif keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // pkey param @@ -249,11 +209,7 @@ DValue *DtoAARemove(Loc& loc, DValue* aa, DValue* key) // call runtime LLCallSite call = gIR->CreateCallOrInvoke(func, args); -#if DMDV2 return new DImValue(Type::tbool, call.getInstruction()); -#else - return NULL; -#endif } ///////////////////////////////////////////////////////////////////////////////////// @@ -262,7 +218,6 @@ LLValue* DtoAAEquals(Loc& loc, TOK op, DValue* l, DValue* r) { Type* t = l->getType()->toBasetype(); assert(t == r->getType()->toBasetype() && "aa equality is only defined for aas of same type"); -#if DMDV2 llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaEqual"); LLFunctionType* funcTy = func->getFunctionType(); @@ -270,15 +225,6 @@ LLValue* DtoAAEquals(Loc& loc, TOK op, DValue* l, DValue* r) LLValue* abval = DtoBitCast(r->getRVal(), funcTy->getParamType(2)); LLValue* aaTypeInfo = DtoTypeInfoOf(t); LLValue* res = gIR->CreateCallOrInvoke3(func, aaTypeInfo, aaval, abval, "aaEqRes").getInstruction(); -#else - llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaEq"); - LLFunctionType* funcTy = func->getFunctionType(); - - LLValue* aaval = DtoBitCast(l->getRVal(), funcTy->getParamType(0)); - LLValue* abval = DtoBitCast(r->getRVal(), funcTy->getParamType(1)); - LLValue* aaTypeInfo = DtoTypeInfoOf(t); - LLValue* res = gIR->CreateCallOrInvoke3(func, aaval, abval, aaTypeInfo, "aaEqRes").getInstruction(); -#endif res = gIR->ir->CreateICmpNE(res, DtoConstInt(0), "tmp"); if (op == TOKnotequal) res = gIR->ir->CreateNot(res, "tmp"); diff --git a/gen/abi-ppc64.cpp b/gen/abi-ppc64.cpp index bb77d295..d707193c 100644 --- a/gen/abi-ppc64.cpp +++ b/gen/abi-ppc64.cpp @@ -44,10 +44,9 @@ struct PPC64TargetABI : TargetABI { bool returnInArg(TypeFunction* tf) { -#if DMDV2 if (tf->isref) return false; -#endif + // Return structs and static arrays on the stack. The latter is needed // because otherwise LLVM tries to actually return the array in a number // of physical registers, which leads, depending on the target, to diff --git a/gen/abi-win64.cpp b/gen/abi-win64.cpp index 12330644..bd76d5cb 100644 --- a/gen/abi-win64.cpp +++ b/gen/abi-win64.cpp @@ -127,10 +127,8 @@ llvm::CallingConv::ID Win64TargetABI::callingConv(LINK l) bool Win64TargetABI::returnInArg(TypeFunction* tf) { -#if DMDV2 if (tf->isref) return false; -#endif Type* rt = tf->next->toBasetype(); @@ -164,9 +162,7 @@ void Win64TargetABI::rewriteFunctionType(TypeFunction* tf) // RETURN VALUE -#if DMDV2 if (!tf->isref) -#endif { if (rt->ty == Tcomplex80) { diff --git a/gen/abi-x86-64.cpp b/gen/abi-x86-64.cpp index 7ac2ae89..69771f1f 100644 --- a/gen/abi-x86-64.cpp +++ b/gen/abi-x86-64.cpp @@ -439,10 +439,9 @@ bool X86_64TargetABI::returnInArg(TypeFunction* tf) { Type* rt = tf->next->toBasetype(); if (tf->linkage == LINKd) { -#if DMDV2 if (tf->isref) return false; -#endif + // All non-structs can be returned in registers. return rt->ty == Tstruct #if SARRAYVALUE diff --git a/gen/abi-x86.cpp b/gen/abi-x86.cpp index f7734604..9dd4ef92 100644 --- a/gen/abi-x86.cpp +++ b/gen/abi-x86.cpp @@ -70,10 +70,9 @@ struct X86TargetABI : TargetABI bool returnInArg(TypeFunction* tf) { -#if DMDV2 if (tf->isref) return false; -#endif + Type* rt = tf->next->toBasetype(); // D only returns structs on the stack if (tf->linkage == LINKd) diff --git a/gen/abi.cpp b/gen/abi.cpp index e2f9f3c1..b76e3d7e 100644 --- a/gen/abi.cpp +++ b/gen/abi.cpp @@ -58,10 +58,9 @@ struct UnknownTargetABI : TargetABI bool returnInArg(TypeFunction* tf) { -#if DMDV2 if (tf->isref) return false; -#endif + // Return structs and static arrays on the stack. The latter is needed // because otherwise LLVM tries to actually return the array in a number // of physical registers, which leads, depending on the target, to diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 609b5683..bbebb884 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -114,13 +114,11 @@ void DtoArrayInit(Loc& loc, DValue* array, DValue* value, int op) Logger::println("DtoArrayInit"); LOG_SCOPE; -#if DMDV2 if (op != -1 && op != TOKblit && arrayNeedsPostblit(array->type)) { DtoArraySetAssign(loc, array, value, op); return; } -#endif LLValue* dim = DtoArrayLen(array); LLValue* ptr = DtoArrayPtr(array); @@ -183,8 +181,6 @@ void DtoArrayInit(Loc& loc, DValue* array, DValue* value, int op) ////////////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - Type *DtoArrayElementType(Type *arrayType) { assert(arrayType->toBasetype()->nextOf()); @@ -252,8 +248,6 @@ void DtoArraySetAssign(Loc &loc, DValue *array, DValue *value, int op) call.setCallingConv(llvm::CallingConv::C); } -#endif - ////////////////////////////////////////////////////////////////////////////////////////// void DtoSetArray(DValue* array, LLValue* dim, LLValue* ptr) @@ -451,11 +445,9 @@ LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit) // be used as an initializer for a static T[] - where modifying contents is allowed. LLGlobalVariable* gvar = new LLGlobalVariable(*gIR->module, constarr->getType(), false, LLGlobalValue::InternalLinkage, constarr, ".constarray"); -#if DMDV2 if (arrty->ty == Tpointer) // we need to return pointer to the static array. return DtoBitCast(gvar, DtoType(arrty)); -#endif LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) }; @@ -589,8 +581,6 @@ DSliceValue* DtoNewDynArray(Loc& loc, Type* arrayType, DValue* dim, bool default defaultInit = false; bool zeroInit = eltType->isZeroInit(); -#if DMDV2 - const char* fnname = zeroInit ? "_d_newarrayT" : "_d_newarrayiT"; LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, fnname); @@ -598,27 +588,6 @@ DSliceValue* DtoNewDynArray(Loc& loc, Type* arrayType, DValue* dim, bool default LLValue* newArray = gIR->CreateCallOrInvoke2(fn, arrayTypeInfo, arrayLen, ".gc_mem").getInstruction(); return getSlice(arrayType, newArray); - -#else - - const char* fnname = defaultInit ? (zeroInit ? "_d_newarrayT" : "_d_newarrayiT") : "_d_newarrayvT"; - LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, fnname); - - // call allocator - LLValue* newptr = gIR->CreateCallOrInvoke2(fn, arrayTypeInfo, arrayLen, ".gc_mem").getInstruction(); - - // cast to wanted type - LLType* dstType = DtoType(arrayType)->getContainedType(1); - if (newptr->getType() != dstType) - newptr = DtoBitCast(newptr, dstType, ".gc_mem"); - - if (Logger::enabled()) - Logger::cout() << "final ptr = " << *newptr << '\n'; - - return new DSliceValue(arrayType, arrayLen, newptr); - - -#endif } ////////////////////////////////////////////////////////////////////////////////////////// @@ -640,7 +609,6 @@ DSliceValue* DtoNewMulDimDynArray(Loc& loc, Type* arrayType, DValue** dims, size if (defaultInit && !isInitialized(vtype)) defaultInit = false; -#if DMDV2 const char* fnname = zeroInit ? "_d_newarraymT" : "_d_newarraymiT"; LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, fnname); @@ -660,35 +628,6 @@ DSliceValue* DtoNewMulDimDynArray(Loc& loc, Type* arrayType, DValue** dims, size Logger::cout() << "final ptr = " << *newptr << '\n'; return getSlice(arrayType, newptr); -#else - - const char* fnname = defaultInit ? (zeroInit ? "_d_newarraymT" : "_d_newarraymiT") : "_d_newarraymvT"; - LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, fnname); - - // build dims - LLValue* dimsArg = DtoArrayAlloca(Type::tsize_t, ndims, ".newdims"); - LLValue* firstDim = NULL; - for (size_t i=0; igetRVal(); - if (!firstDim) firstDim = dim; - DtoStore(dim, DtoGEPi1(dimsArg, i)); - } - - // call allocator - LLValue* newptr = gIR->CreateCallOrInvoke3(fn, arrayTypeInfo, DtoConstSize_t(ndims), dimsArg, ".gc_mem").getInstruction(); - - // cast to wanted type - LLType* dstType = DtoType(arrayType)->getContainedType(1); - if (newptr->getType() != dstType) - newptr = DtoBitCast(newptr, dstType, ".gc_mem"); - - if (Logger::enabled()) - Logger::cout() << "final ptr = " << *newptr << '\n'; - - assert(firstDim); - return new DSliceValue(arrayType, firstDim, newptr); -#endif } ////////////////////////////////////////////////////////////////////////////////////////// @@ -712,33 +651,13 @@ DSliceValue* DtoResizeDynArray(Type* arrayType, DValue* array, LLValue* newdim) args.push_back(DtoTypeInfoOf(arrayType)); args.push_back(newdim); -#if DMDV2 - args.push_back(DtoBitCast(array->getLVal(), fn->getFunctionType()->getParamType(2))); LLValue* newArray = gIR->CreateCallOrInvoke(fn, args, ".gc_mem").getInstruction(); return getSlice(arrayType, newArray); - -#else - - args.push_back(DtoArrayLen(array)); - - LLValue* arrPtr = DtoArrayPtr(array); - if (Logger::enabled()) - Logger::cout() << "arrPtr = " << *arrPtr << '\n'; - args.push_back(DtoBitCast(arrPtr, fn->getFunctionType()->getParamType(3), "tmp")); - - LLValue* newptr = gIR->CreateCallOrInvoke(fn, args, ".gc_mem").getInstruction(); - if (newptr->getType() != arrPtr->getType()) - newptr = DtoBitCast(newptr, arrPtr->getType(), ".gc_mem"); - - return new DSliceValue(arrayType, newdim, newptr); - -#endif } ////////////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 void DtoCatAssignElement(Loc& loc, Type* arrayType, DValue* array, Expression* exp) { @@ -768,32 +687,8 @@ void DtoCatAssignElement(Loc& loc, Type* arrayType, DValue* array, Expression* e callPostblit(loc, exp, val); } -#else - -void DtoCatAssignElement(Loc& loc, Type* arrayType, DValue* array, Expression* exp) -{ - Logger::println("DtoCatAssignElement"); - LOG_SCOPE; - - assert(array); - - LLValue *valueToAppend = makeLValue(loc, exp->toElem(gIR)); - - LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_arrayappendcT"); - LLSmallVector args; - args.push_back(DtoTypeInfoOf(arrayType)); - args.push_back(DtoBitCast(array->getLVal(), fn->getFunctionType()->getParamType(1))); - args.push_back(DtoBitCast(valueToAppend, getVoidPtrType())); - - gIR->CreateCallOrInvoke(fn, args, ".appendedArray"); -} - -#endif - ////////////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - DSliceValue* DtoCatAssignArray(DValue* arr, Expression* exp) { Logger::println("DtoCatAssignArray"); @@ -818,44 +713,8 @@ DSliceValue* DtoCatAssignArray(DValue* arr, Expression* exp) return getSlice(arrayType, newArray); } -#else - -DSliceValue* DtoCatAssignArray(DValue* arr, Expression* exp) -{ - Logger::println("DtoCatAssignArray"); - LOG_SCOPE; - - DValue* e = exp->toElem(gIR); - - llvm::Value *len1, *len2, *src1, *src2, *res; - - len1 = DtoArrayLen(arr); - len2 = DtoArrayLen(e); - res = gIR->ir->CreateAdd(len1,len2,"tmp"); - - DValue* newdim = new DImValue(Type::tsize_t, res); - DSliceValue* slice = DtoResizeDynArray(arr->getType(), arr, newdim->getRVal()); - - src1 = slice->ptr; - src2 = DtoArrayPtr(e); - - // advance ptr - src1 = gIR->ir->CreateGEP(src1,len1,"tmp"); - - // memcpy - LLValue* elemSize = DtoConstSize_t(getTypePaddedSize(src2->getType()->getContainedType(0))); - LLValue* bytelen = gIR->ir->CreateMul(len2, elemSize, "tmp"); - DtoMemCpy(src1,src2,bytelen); - - return slice; -} - -#endif - ////////////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - DSliceValue* DtoCatArrays(Type* arrayType, Expression* exp1, Expression* exp2) { Logger::println("DtoCatAssignArray"); @@ -904,117 +763,6 @@ DSliceValue* DtoCatArrays(Type* arrayType, Expression* exp1, Expression* exp2) return getSlice(arrayType, newArray); } -#else - -DSliceValue* DtoCatArrays(Type* type, Expression* exp1, Expression* exp2) -{ - Logger::println("DtoCatArrays"); - LOG_SCOPE; - - Type* t1 = exp1->type->toBasetype(); - Type* t2 = exp2->type->toBasetype(); - - assert(t1->ty == Tarray || t1->ty == Tsarray); - assert(t2->ty == Tarray || t2->ty == Tsarray); - - DValue* e1 = exp1->toElem(gIR); - DValue* e2 = exp2->toElem(gIR); - - llvm::Value *len1, *len2, *src1, *src2, *res; - - len1 = DtoArrayLen(e1); - len2 = DtoArrayLen(e2); - res = gIR->ir->CreateAdd(len1,len2,"tmp"); - - DValue* lenval = new DImValue(Type::tsize_t, res); - DSliceValue* slice = DtoNewDynArray(exp1->loc, type, lenval, false); - LLValue* mem = slice->ptr; - - src1 = DtoArrayPtr(e1); - src2 = DtoArrayPtr(e2); - - // first memcpy - LLValue* elemSize = DtoConstSize_t(getTypePaddedSize(src1->getType()->getContainedType(0))); - LLValue* bytelen = gIR->ir->CreateMul(len1, elemSize, "tmp"); - DtoMemCpy(mem,src1,bytelen); - - // second memcpy - mem = gIR->ir->CreateGEP(mem,len1,"tmp"); - bytelen = gIR->ir->CreateMul(len2, elemSize, "tmp"); - DtoMemCpy(mem,src2,bytelen); - - return slice; -} - -#endif - -////////////////////////////////////////////////////////////////////////////////////////// - -#if DMDV1 - -DSliceValue* DtoCatArrayElement(Type* type, Expression* exp1, Expression* exp2) -{ - Logger::println("DtoCatArrayElement"); - LOG_SCOPE; - - Type* t1 = exp1->type->toBasetype(); - Type* t2 = exp2->type->toBasetype(); - - DValue* e1 = exp1->toElem(gIR); - DValue* e2 = exp2->toElem(gIR); - - llvm::Value *len1, *src1, *res; - - // handle prefix case, eg. int~int[] - if (t2->nextOf() && t1 == t2->nextOf()->toBasetype()) - { - len1 = DtoArrayLen(e2); - res = gIR->ir->CreateAdd(len1,DtoConstSize_t(1),"tmp"); - - DValue* lenval = new DImValue(Type::tsize_t, res); - DSliceValue* slice = DtoNewDynArray(exp1->loc, type, lenval, false); - LLValue* mem = slice->ptr; - - DVarValue* memval = new DVarValue(e1->getType(), mem); - DtoAssign(exp1->loc, memval, e1); - - src1 = DtoArrayPtr(e2); - - mem = gIR->ir->CreateGEP(mem,DtoConstSize_t(1),"tmp"); - - LLValue* elemSize = DtoConstSize_t(getTypePaddedSize(src1->getType()->getContainedType(0))); - LLValue* bytelen = gIR->ir->CreateMul(len1, elemSize, "tmp"); - DtoMemCpy(mem,src1,bytelen); - - - return slice; - } - // handle suffix case, eg. int[]~int - else - { - len1 = DtoArrayLen(e1); - res = gIR->ir->CreateAdd(len1,DtoConstSize_t(1),"tmp"); - - DValue* lenval = new DImValue(Type::tsize_t, res); - DSliceValue* slice = DtoNewDynArray(exp1->loc, type, lenval, false); - LLValue* mem = slice->ptr; - - src1 = DtoArrayPtr(e1); - - LLValue* elemSize = DtoConstSize_t(getTypePaddedSize(src1->getType()->getContainedType(0))); - LLValue* bytelen = gIR->ir->CreateMul(len1, elemSize, "tmp"); - DtoMemCpy(mem,src1,bytelen); - - mem = gIR->ir->CreateGEP(mem,len1,"tmp"); - DVarValue* memval = new DVarValue(e2->getType(), mem); - DtoAssign(exp1->loc, memval, e2); - - return slice; - } -} - -#endif - ////////////////////////////////////////////////////////////////////////////////////////// DSliceValue* DtoAppendDChar(DValue* arr, Expression* exp, const char *func) @@ -1357,13 +1105,8 @@ DValue* DtoCastArray(Loc& loc, DValue* u, Type* to) void DtoArrayBoundsCheck(Loc& loc, DValue* arr, DValue* index, DValue* lowerBound) { Type* arrty = arr->getType()->toBasetype(); -#if DMDV2 assert((arrty->ty == Tsarray || arrty->ty == Tarray || arrty->ty == Tpointer) && "Can only array bounds check for static or dynamic arrays"); -#else - assert((arrty->ty == Tsarray || arrty->ty == Tarray) && - "Can only array bounds check for static or dynamic arrays"); -#endif // static arrays could get static checks for static indices // but shouldn't since it might be generic code that's never executed @@ -1405,25 +1148,10 @@ void DtoArrayBoundsCheck(Loc& loc, DValue* arr, DValue* index, DValue* lowerBoun std::vector args; Module* funcmodule = gIR->func()->decl->getModule(); -#if DMDV2 // module param LLValue *moduleInfoSymbol = funcmodule->moduleInfoSymbol(); LLType *moduleInfoType = DtoType(Module::moduleinfo->type); args.push_back(DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType))); -#else - // file param - // we might be generating for an imported template function - const char* cur_file = funcmodule->srcfile->name->toChars(); - if (loc.filename && strcmp(loc.filename, cur_file) != 0) - { - args.push_back(DtoConstString(loc.filename)); - } - else - { - IrModule* irmod = getIrModule(funcmodule); - args.push_back(DtoLoad(irmod->fileName)); - } -#endif // line param LLConstant* c = DtoConstUint(loc.linnum); diff --git a/gen/arrays.h b/gen/arrays.h index d32ac898..391eda32 100644 --- a/gen/arrays.h +++ b/gen/arrays.h @@ -36,12 +36,10 @@ void DtoArrayCopySlices(DSliceValue* dst, DSliceValue* src); void DtoArrayCopyToSlice(DSliceValue* dst, DValue* src); void DtoArrayInit(Loc& loc, DValue* array, DValue* value, int op); -#if DMDV2 Type *DtoArrayElementType(Type *arrayType); bool arrayNeedsPostblit(Type *t); void DtoArrayAssign(DValue *from, DValue *to, int op); void DtoArraySetAssign(Loc &loc, DValue *array, DValue *value, int op); -#endif void DtoSetArray(DValue* array, LLValue* dim, LLValue* ptr); void DtoSetArrayToNull(LLValue* v); @@ -52,9 +50,6 @@ DSliceValue* DtoResizeDynArray(Type* arrayType, DValue* array, llvm::Value* newd void DtoCatAssignElement(Loc& loc, Type* type, DValue* arr, Expression* exp); DSliceValue* DtoCatAssignArray(DValue* arr, Expression* exp); DSliceValue* DtoCatArrays(Type* type, Expression* e1, Expression* e2); -#if DMDV1 -DSliceValue* DtoCatArrayElement(Type* type, Expression* exp1, Expression* exp2); -#endif DSliceValue* DtoAppendDCharToString(DValue* arr, Expression* exp); DSliceValue* DtoAppendDCharToUnicodeString(DValue* arr, Expression* exp); diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp index b8aff97b..621a0665 100644 --- a/gen/asmstmt.cpp +++ b/gen/asmstmt.cpp @@ -153,10 +153,8 @@ bool d_have_inline_asm() { return true; } Statement *AsmStatement::semantic(Scope *sc) { -#if DMDV2 if (sc->func && sc->func->isSafe()) error("inline assembler not allowed in @safe function %s", sc->func->toChars()); -#endif bool err = false; llvm::Triple const t = global.params.targetTriple; @@ -176,9 +174,6 @@ Statement *AsmStatement::semantic(Scope *sc) //puts(toChars()); -#if DMDV1 - sc->func->inlineAsm = true; -#endif sc->func->hasReturnExp |= 8; // empty statement -- still do the above things because they might be expected? @@ -201,10 +196,8 @@ Statement *AsmStatement::semantic(Scope *sc) int AsmStatement::blockExit(bool mustNotThrow) { //printf("AsmStatement::blockExit(%p)\n", this); -#if DMDV2 if (mustNotThrow) error("asm statements are assumed to throw"); -#endif // Assume the worst return BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt; } diff --git a/gen/binops.cpp b/gen/binops.cpp index bcf32c76..fb65e59b 100644 --- a/gen/binops.cpp +++ b/gen/binops.cpp @@ -137,7 +137,6 @@ LLValue* DtoBinNumericEquals(Loc loc, DValue* lhs, DValue* rhs, TOK op) LLValue* DtoBinFloatsEquals(Loc loc, DValue* lhs, DValue* rhs, TOK op) { LLValue* res = 0; -#if DMDV2 if (op == TOKequal) { res = gIR->ir->CreateFCmpOEQ(lhs->getRVal(), rhs->getRVal(), "tmp"); } else if (op == TOKnotequal) { @@ -153,14 +152,6 @@ LLValue* DtoBinFloatsEquals(Loc loc, DValue* lhs, DValue* rhs, TOK op) LLValue* val = DtoMemCmp(makeLValue(loc, lhs), makeLValue(loc, rhs), sz); res = gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false), "tmp"); } -#else - LLValue* lv = lhs->getRVal(); - LLValue* rv = rhs->getRVal(); - res = (op == TOKidentity || op == TOKequal) ? - gIR->ir->CreateFCmpOEQ(lv, rv, "tmp") : - gIR->ir->CreateFCmpUNE(lv, rv, "tmp"); - -#endif assert(res); return res; } diff --git a/gen/classes.cpp b/gen/classes.cpp index cf3535d9..5a268b48 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -796,7 +796,6 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) VarDeclaration* defConstructorVar = static_cast(cinfo->fields.data[10]); b.push_funcptr(cd->defaultCtor, defConstructorVar->type); -#if DMDV2 // immutable(void)* m_RTInfo; // The cases where getRTInfo is null are not quite here, but the code is // modelled after what DMD does. @@ -806,10 +805,6 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) b.push_size_as_vp(0); // no pointers else b.push_size_as_vp(1); // has pointers -#else - // typeinfo - since 1.045 - b.push_typeinfo(cd->type); -#endif /*size_t n = inits.size(); for (size_t i=0; icodegen(p); // global variable -#if DMDV2 // taken from dmd2/structs if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init)) -#else - if (isDataseg()) -#endif { Logger::println("data segment"); - #if DMDV2 && 0 // TODO: + #if 0 // TODO: assert(!(storage_class & STCmanifest) && "manifest constant being codegen'd!"); #endif @@ -147,12 +143,8 @@ void VarDeclaration::codegen(Ir* p) Logger::println("parent: %s (%s)", parent->toChars(), parent->kind()); - #if DMDV2 // not sure why this is only needed for d2 bool _isconst = isConst() && init; - #else - bool _isconst = isConst(); - #endif Logger::println("Creating global variable"); @@ -260,10 +252,8 @@ void TemplateInstance::codegen(Ir* p) #if LOG printf("TemplateInstance::codegen('%s', this = %p)\n", toChars(), this); #endif -#if DMDV2 if (ignore) return; -#endif if (!errors && members) { diff --git a/gen/functions.cpp b/gen/functions.cpp index dc1b604a..a48b6d77 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -121,10 +121,8 @@ llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, else { Type *t = rt; -#if DMDV2 if (f->isref) t = t->pointerTo(); -#endif #if LDC_LLVM_VER >= 303 if (llvm::Attribute::AttrKind a = DtoShouldExtend(t)) attrBuilder.addAttribute(a); @@ -140,11 +138,7 @@ llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, #elif LDC_LLVM_VER == 302 llvm::Attributes a = llvm::Attributes::get(gIR->context(), attrBuilder); #endif -#if DMDV2 fty.ret = new IrFuncTyArg(rt, f->isref, a); -#else - fty.ret = new IrFuncTyArg(rt, false, a); -#endif } lidx++; @@ -426,7 +420,6 @@ llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl) Type *dthis=0, *dnest=0; -#if DMDV2 if (fdecl->ident == Id::ensure || fdecl->ident == Id::require) { FuncDeclaration *p = fdecl->parent->isFuncDeclaration(); assert(p); @@ -434,7 +427,6 @@ llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl) assert(ad); dnest = Type::tvoid->pointerTo(); } else -#endif if (fdecl->needThis()) { if (AggregateDeclaration* ad = fdecl->isMember2()) { Logger::println("isMember = this is: %s", ad->type->toChars()); @@ -752,12 +744,10 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) // calling convention LINK link = f->linkage; if (vafunc || fdecl->llvmInternal == LLVMintrinsic -#if DMDV2 // DMD treats _Dmain as having C calling convention and this has been // hardcoded into druntime, even if the frontend type has D linkage. // See Bugzilla issue 9028. || fdecl->isMain() -#endif ) { link = LINKc; @@ -815,7 +805,6 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) gIR->mainFunc = func; } -#if DMDV2 // shared static ctor if (fdecl->isSharedStaticCtorDeclaration()) { if (mustDefineSymbol(fdecl)) { @@ -830,7 +819,6 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) gIR->sharedGates.push_front(dtorDecl->vgate); } } else -#endif // static ctor if (fdecl->isStaticCtorDeclaration()) { if (mustDefineSymbol(fdecl)) { @@ -841,10 +829,8 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) else if (StaticDtorDeclaration *dtorDecl = fdecl->isStaticDtorDeclaration()) { if (mustDefineSymbol(fdecl)) { gIR->dtors.push_front(fdecl); -#if DMDV2 if (dtorDecl->vgate) gIR->gates.push_front(dtorDecl->vgate); -#endif } } @@ -1063,13 +1049,6 @@ void DtoDefineFunction(FuncDeclaration* fd) IrParameter* irparam = vd->ir.irParam; assert(irparam); - #if DMDV1 - if (vd->nestedref) - { - fd->nestedVars.insert(vd); - } - #endif - bool refout = vd->storage_class & (STCref | STCout); bool lazy = vd->storage_class & STClazy; if (!refout && (!irparam->arg->byref || lazy)) @@ -1095,31 +1074,13 @@ void DtoDefineFunction(FuncDeclaration* fd) } } - -#if DMDV1 - // need result variable? (nested) - if (fd->vresult && fd->vresult->nestedref) { - Logger::println("nested vresult value: %s", fd->vresult->toChars()); - fd->nestedVars.insert(fd->vresult); - } - - if (fd->vthis && fd->vthis->nestedref && !fd->nestedVars.empty()) { - Logger::println("nested vthis value: %s", fd->vthis->toChars()); - fd->nestedVars.insert(fd->vthis); - } -#endif - FuncGen fg; irfunction->gen = &fg; DtoCreateNestedContext(fd); if (fd->vresult && ! -#if DMDV2 fd->vresult->nestedrefs.dim // FIXME: not sure here :/ -#else - fd->vresult->nestedref -#endif ) { DtoVarDeclaration(fd->vresult); diff --git a/gen/irstate.h b/gen/irstate.h index 9aa17124..80f263ba 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -73,10 +73,8 @@ struct IRScope const IRScope& operator=(const IRScope& rhs); -#if DMDV2 // list of variables needing destruction std::vector varsInScope; -#endif }; struct IRBuilderHelper @@ -159,9 +157,7 @@ struct IRState // basic block scopes std::vector scopes; IRScope& scope(); -#if DMDV2 std::vector &varsInScope() { return scope().varsInScope; } -#endif llvm::BasicBlock* scopebb(); llvm::BasicBlock* scopeend(); bool scopereturned(); @@ -193,12 +189,10 @@ struct IRState typedef std::list GatesList; FuncDeclList ctors; FuncDeclList dtors; -#if DMDV2 FuncDeclList sharedCtors; FuncDeclList sharedDtors; GatesList gates; GatesList sharedGates; -#endif FuncDeclList unitTests; // all template instances that had members emitted diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 713d2482..e11f0dfa 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -71,12 +71,10 @@ void DtoDeleteClass(LLValue* inst) llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delclass"); // build args LLSmallVector arg; -#if DMDV2 // druntime wants a pointer to object LLValue *ptr = DtoRawAlloca(inst->getType(), 0, "objectPtr"); DtoStore(inst, ptr); inst = ptr; -#endif arg.push_back(DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp")); // call gIR->CreateCallOrInvoke(fn, arg); @@ -93,8 +91,6 @@ void DtoDeleteInterface(LLValue* inst) gIR->CreateCallOrInvoke(fn, arg); } -#if DMDV2 - void DtoDeleteArray(DValue* arr) { // get runtime function @@ -109,24 +105,6 @@ void DtoDeleteArray(DValue* arr) gIR->CreateCallOrInvoke(fn, arg); } -#else - -void DtoDeleteArray(DValue* arr) -{ - // get runtime function - llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delarray"); - - // build args - LLSmallVector arg; - arg.push_back(DtoArrayLen(arr)); - arg.push_back(DtoBitCast(DtoArrayPtr(arr), getVoidPtrType(), ".tmp")); - - // call - gIR->CreateCallOrInvoke(fn, arg); -} - -#endif - /****************************************************************************************/ /*//////////////////////////////////////////////////////////////////////////////////////// // ALLOCA HELPERS @@ -416,7 +394,6 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPostblit) if (t->nextOf()->toBasetype()->equals(t2)) { DtoArrayInit(loc, lhs, rhs, op); } -#if DMDV2 else if (DtoArrayElementType(t)->equals(stripModifiers(t2))) { DtoArrayInit(loc, s, rhs, op); } @@ -425,7 +402,6 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPostblit) ) { DtoArrayAssign(s, rhs, op); } -#endif else if (DSliceValue *s2 = rhs->isSlice()) { DtoArrayCopySlices(s, s2); } @@ -456,7 +432,6 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPostblit) if (t->nextOf()->toBasetype()->equals(t2)) { DtoArrayInit(loc, lhs, rhs, op); } -#if DMDV2 else if (DtoArrayElementType(t)->equals(stripModifiers(t2))) { DtoArrayInit(loc, lhs, rhs, op); } @@ -465,7 +440,6 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPostblit) ) { DtoArrayAssign(lhs, rhs, op); } -#endif // T[n] = T[n] else if (DtoType(lhs->getType()) == DtoType(rhs->getType())) { DtoStaticArrayCopy(lhs->getLVal(), rhs->getRVal()); @@ -772,7 +746,6 @@ DValue* DtoCastNull(Loc& loc, DValue* val, Type* to) } } -#if DMDV2 DValue* DtoCastVector(Loc& loc, DValue* val, Type* to) { assert(val->getType()->toBasetype()->ty == Tvector); @@ -828,19 +801,16 @@ DValue* DtoCastVector(Loc& loc, DValue* val, Type* to) fatal(); } } -#endif DValue* DtoCast(Loc& loc, DValue* val, Type* to) { Type* fromtype = val->getType()->toBasetype(); Type* totype = to->toBasetype(); -#if DMDV2 if (fromtype->ty == Taarray) fromtype = static_cast(fromtype)->getImpl()->type; if (totype->ty == Taarray) totype = static_cast(totype)->getImpl()->type; -#endif if (fromtype->equals(totype)) return val; @@ -848,12 +818,10 @@ DValue* DtoCast(Loc& loc, DValue* val, Type* to) Logger::println("Casting from '%s' to '%s'", fromtype->toChars(), to->toChars()); LOG_SCOPE; -#if DMDV2 if (fromtype->ty == Tvector) { return DtoCastVector(loc, val, to); } else -#endif if (fromtype->isintegral()) { return DtoCastInt(loc, val, to); } @@ -967,13 +935,11 @@ TemplateInstance* DtoIsTemplateInstance(Dsymbol* s, bool checkLiteralOwner) if (!s) return NULL; if (s->isTemplateInstance() && !s->isTemplateMixin()) return s->isTemplateInstance(); -#if DMDV2 if (FuncLiteralDeclaration* fld = s->isFuncLiteralDeclaration()) { if (checkLiteralOwner && fld->owningTemplate) return fld->owningTemplate; } -#endif if (s->parent) return DtoIsTemplateInstance(s->parent, checkLiteralOwner); return NULL; @@ -1061,11 +1027,7 @@ void DtoVarDeclaration(VarDeclaration* vd) Logger::println("vdtype = %s", vd->type->toChars()); -#if DMDV2 if (vd->nestedrefs.dim) -#else - if (vd->nestedref) -#endif { Logger::println("has nestedref set (referenced by nested function/delegate)"); assert(vd->ir.irLocal && "irLocal is expected to be already set by DtoCreateNestedContext"); @@ -1075,7 +1037,6 @@ void DtoVarDeclaration(VarDeclaration* vd) { // Nothing to do if it has already been allocated. } -#if DMDV2 /* Named Return Value Optimization (NRVO): T f(){ T ret; // &ret == hidden pointer @@ -1088,12 +1049,10 @@ void DtoVarDeclaration(VarDeclaration* vd) vd->ir.irLocal = new IrLocal(vd); vd->ir.irLocal->value = gIR->func()->retArg; } -#endif // normal stack variable, allocate storage on the stack if it has not already been done else { vd->ir.irLocal = new IrLocal(vd); -#if DMDV2 /* NRVO again: T t = f(); // t's memory address is taken hidden pointer */ @@ -1123,7 +1082,6 @@ void DtoVarDeclaration(VarDeclaration* vd) } } } -#endif Type* type = isSpecialRefVar(vd) ? vd->type->pointerTo() : vd->type; LLType* lltype = DtoType(type); @@ -1144,7 +1102,6 @@ void DtoVarDeclaration(VarDeclaration* vd) DtoInitializer(vd->ir.irLocal->value, vd->init); // TODO: Remove altogether? -#if DMDV2 Lexit: /* Mark the point of construction of a variable that needs to be destructed. */ @@ -1153,7 +1110,6 @@ Lexit: // Put vd on list of things needing destruction gIR->varsInScope().push_back(vd); } -#endif } DValue* DtoDeclarationExp(Dsymbol* declaration) @@ -1285,11 +1241,7 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr) } // referenced by nested function? -#if DMDV2 if (var->nestedrefs.dim) -#else - if (var->nestedref) -#endif { assert(var->ir.irLocal); if(!var->ir.irLocal->value) @@ -1508,13 +1460,8 @@ static LLConstant* expand_to_sarray(Type *base, Expression* exp) LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) { -#if DMDV2 Type* expbase = stripModifiers(exp->type->toBasetype())->merge(); Type* base = stripModifiers(type->toBasetype())->merge(); -#else - Type* expbase = exp->type->toBasetype(); - Type* base = type->toBasetype(); -#endif // if not the same basetypes, we won't get the same llvm types either if (!expbase->equals(base)) @@ -1529,7 +1476,6 @@ LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) return expand_to_sarray(base, exp); } -#if DMDV2 if (base->ty == Tvector) { LLConstant* val = exp->toConstElem(gIR); @@ -1541,7 +1487,6 @@ LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) return llvm::ConstantVector::getSplat(tv->size(loc), val); #endif } -#endif error(loc, "LDC internal error: cannot yet convert default initializer %s of type %s to %s", exp->toChars(), exp->type->toChars(), type->toChars()); @@ -1793,13 +1738,9 @@ size_t realignOffset(size_t offset, Type* type) Type * stripModifiers( Type * type ) { -#if DMDV2 if (type->ty == Tfunction) return type; return type->castMod(0); -#else - return type; -#endif } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1839,7 +1780,6 @@ LLValue* makeLValue(Loc& loc, DValue* value) ////////////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 void callPostblit(Loc &loc, Expression *exp, LLValue *val) { @@ -1859,7 +1799,6 @@ void callPostblit(Loc &loc, Expression *exp, LLValue *val) } } } -#endif ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index e099dcd8..4a9ec3f8 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -166,9 +166,7 @@ size_t realignOffset(size_t offset, Type* type); /// functions without problems. LLValue* makeLValue(Loc& loc, DValue* value); -#if DMDV2 void callPostblit(Loc &loc, Expression *exp, LLValue *val); -#endif /// Returns whether the given variable is a DMD-internal "ref variable". /// diff --git a/gen/module.cpp b/gen/module.cpp index 9d153db8..6788b448 100644 --- a/gen/module.cpp +++ b/gen/module.cpp @@ -56,10 +56,7 @@ #endif #endif -#if DMDV2 #define NEW_MODULEINFO_LAYOUT 1 -#endif - static llvm::Function* build_module_function(const std::string &name, const std::list &funcs, const std::list &gates = std::list()) @@ -116,11 +113,7 @@ llvm::Function* build_module_ctor() std::string name("_D"); name.append(gIR->dmodule->mangle()); name.append("6__ctorZ"); -#if DMDV2 return build_module_function(name, gIR->ctors, gIR->gates); -#else - return build_module_function(name, gIR->ctors); -#endif } // build module dtor @@ -143,8 +136,6 @@ static llvm::Function* build_module_unittest() return build_module_function(name, gIR->unitTests); } -#if DMDV2 - // build module shared ctor llvm::Function* build_module_shared_ctor() @@ -165,8 +156,6 @@ static llvm::Function* build_module_shared_dtor() return build_module_function(name, gIR->sharedDtors); } -#endif - // build ModuleReference and register function, to register the module info in the global linked list static LLFunction* build_module_reference_and_ctor(LLConstant* moduleinfo) { @@ -372,11 +361,7 @@ void Module::genmoduleinfo() // check for patch else { -#if DMDV2 unsigned sizeof_ModuleInfo = 16 * PTRSIZE; -#else - unsigned sizeof_ModuleInfo = 14 * PTRSIZE; -#endif if (sizeof_ModuleInfo != moduleinfo->structsize) { error("object.d ModuleInfo class is incorrect"); @@ -606,20 +591,12 @@ void Module::genmoduleinfo() LLType* fnptrTy = getPtrToType(LLFunctionType::get(LLType::getVoidTy(gIR->context()), std::vector(), false)); // ctor -#if DMDV2 llvm::Function* fctor = build_module_shared_ctor(); -#else - llvm::Function* fctor = build_module_ctor(); -#endif c = fctor ? fctor : getNullValue(fnptrTy); b.push(c); // dtor -#if DMDV2 llvm::Function* fdtor = build_module_shared_dtor(); -#else - llvm::Function* fdtor = build_module_dtor(); -#endif c = fdtor ? fdtor : getNullValue(fnptrTy); b.push(c); @@ -636,8 +613,6 @@ void Module::genmoduleinfo() c = getNullValue(fnptrTy); b.push(c); -#if DMDV2 - // tls ctor fctor = build_module_ctor(); c = fctor ? fctor : getNullValue(fnptrTy); @@ -653,8 +628,6 @@ void Module::genmoduleinfo() c = getNullValue(AT); b.push(c); -#endif - #endif // create and set initializer diff --git a/gen/nested.cpp b/gen/nested.cpp index e32e6447..eaee88d3 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -44,7 +44,6 @@ static FuncDeclaration* getParentFunc(Dsymbol* sym, bool stopOnStatic) { static void storeVariable(VarDeclaration *vd, LLValue *dst) { LLValue *value = vd->ir.irLocal->value; -#if DMDV2 int ty = vd->type->ty; FuncDeclaration *fd = getParentFunc(vd, true); assert(fd && "No parent function for nested variable?"); @@ -54,7 +53,6 @@ static void storeVariable(VarDeclaration *vd, LLValue *dst) DtoAggrCopy(mem, value); DtoAlignedStore(mem, dst); } else -#endif // Store the address into the frame DtoAlignedStore(value, dst); } @@ -99,27 +97,11 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) LLValue* ctx = 0; if (irfunc->decl->isMember2()) { - #if DMDV2 AggregateDeclaration* cd = irfunc->decl->isMember2(); LLValue* val = irfunc->thisArg; if (cd->isClassDeclaration()) val = DtoLoad(val); ctx = DtoLoad(DtoGEPi(val, 0, cd->vthis->ir.irField->index, ".vthis")); - #else - ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration(); - LLValue* val = DtoLoad(irfunc->thisArg); - ctx = DtoGEPi(val, 0, cd->vthis->ir.irField->index, ".vthis"); - - if (!irfunc->frameType && vd->isThisDeclaration()) - { - // If the only "nested" variable is the outer this pointer, we don't - // emit a normal context, but just store the this pointer - see - // GitHub #127. - return new DVarValue(astype, vd, ctx); - } - - ctx = DtoLoad(ctx); - #endif } else if (irfunc->nestedVar) { ctx = irfunc->nestedVar; @@ -189,11 +171,7 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) return new DVarValue(astype, vd, val); } -#if DMDV2 void DtoResolveNestedContext(Loc loc, AggregateDeclaration *decl, LLValue *value) -#else -void DtoResolveNestedContext(Loc loc, ClassDeclaration *decl, LLValue *value) -#endif { Logger::println("Resolving nested context"); LOG_SCOPE; @@ -238,7 +216,6 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) // or just have a this argument else if (irfunc->thisArg) { -#if DMDV2 AggregateDeclaration* ad = irfunc->decl->isMember2(); val = ad->isClassDeclaration() ? DtoLoad(irfunc->thisArg) : irfunc->thisArg; if (!ad->vthis) @@ -247,12 +224,6 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) // function (but without any variables in the nested context). return val; } -#else - ClassDeclaration* ad = irfunc->decl->isMember2()->isClassDeclaration(); - val = DtoLoad(irfunc->thisArg); - if (!ad || !ad->vthis) - return val; -#endif val = DtoLoad(DtoGEPi(val, 0, ad->vthis->ir.irField->index, ".vthis")); } else @@ -264,20 +235,14 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) } struct FuncDeclaration* fd = 0; -#if DMDV2 if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) // If sym is a nested struct or a nested class, pass the frame // of the function where sym is declared. fd = ad->toParent()->isFuncDeclaration(); else -#endif if (FuncDeclaration* symfd = sym->isFuncDeclaration()) { // Make sure we've had a chance to analyze nested context usage -#if DMDV2 DtoCreateNestedContextType(symfd); -#else - DtoDefineFunction(symfd); -#endif // if this is for a function that doesn't access variables from // enclosing scopes, it doesn't matter what we pass. @@ -331,7 +296,6 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) { return; fd->ir.irFunc->nestedContextCreated = true; -#if DMDV2 if (fd->nestedVars.empty()) { // fill nestedVars size_t nnest = fd->closureVars.dim; @@ -341,7 +305,6 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) { fd->nestedVars.insert(vd); } } -#endif // construct nested variables array if (!fd->nestedVars.empty()) @@ -455,13 +418,10 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { // Create frame for current function and append to frames list // FIXME: alignment ? LLValue* frame = 0; -#if DMDV2 if (fd->needsClosure()) frame = DtoGcMalloc(frameType, ".frame"); else -#endif - frame = DtoRawAlloca(frameType, 0, ".frame"); - + frame = DtoRawAlloca(frameType, 0, ".frame"); // copy parent frames into beginning if (depth != 0) { @@ -470,20 +430,14 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { assert(irfunction->thisArg); assert(fd->isMember2()); LLValue* thisval = DtoLoad(irfunction->thisArg); -#if DMDV2 AggregateDeclaration* cd = fd->isMember2(); -#else - ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); -#endif assert(cd); assert(cd->vthis); Logger::println("Indexing to 'this'"); -#if DMDV2 if (cd->isStructDeclaration()) src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis"); else -#endif - src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); + src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); } else { src = DtoLoad(src); } diff --git a/gen/nested.h b/gen/nested.h index 3eaa6fa9..397236f6 100644 --- a/gen/nested.h +++ b/gen/nested.h @@ -28,11 +28,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd); /// Resolves the nested context for classes and structs with arbitrary nesting. -#if DMDV2 void DtoResolveNestedContext(Loc loc, AggregateDeclaration *decl, LLValue *value); -#else -void DtoResolveNestedContext(Loc loc, ClassDeclaration *decl, LLValue *value); -#endif /// Gets the context value for a call to a nested function or creating a nested /// class or struct with arbitrary nesting. diff --git a/gen/passes/GarbageCollect2Stack.cpp b/gen/passes/GarbageCollect2Stack.cpp index 65f3bd3c..a14c5679 100644 --- a/gen/passes/GarbageCollect2Stack.cpp +++ b/gen/passes/GarbageCollect2Stack.cpp @@ -359,12 +359,7 @@ GarbageCollect2Stack::GarbageCollect2Stack() : FunctionPass(ID), AllocMemoryT(0, true, false), NewArrayVT(0, true, false, false, 1), -#ifdef DMDV1 - // _d_newarrayT returns just the void* ptr in the LDC D1 runtime. - NewArrayT(0, true, false, true, 1) -#else NewArrayT(0, true, true, true, 1) -#endif { KnownFunctions["_d_allocmemoryT"] = &AllocMemoryT; KnownFunctions["_d_newarrayvT"] = &NewArrayVT; diff --git a/gen/pragma.cpp b/gen/pragma.cpp index be2d62b6..806f9df9 100644 --- a/gen/pragma.cpp +++ b/gen/pragma.cpp @@ -46,7 +46,6 @@ static bool parseIntExp(Expression* e, dinteger_t& res) static void pragmaDeprecated(Identifier* oldIdent, Identifier* newIdent) { -#if !DMDV1 // Do not print a deprecation warning for D1 – we do not want to // introduce needless breakage at this stage. if (global.params.useDeprecated == 0) @@ -59,7 +58,6 @@ static void pragmaDeprecated(Identifier* oldIdent, Identifier* newIdent) warning("non-vendor-prefixed pragma '%s' is deprecated; use '%s' instead", oldIdent->toChars(), newIdent->toChars()); } -#endif } bool matchPragma(Identifier* needle, Identifier* ident, Identifier* oldIdent) @@ -388,11 +386,7 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s, TypeFunction* type = static_cast(fd->type); Type* retType = type->next; if (retType->ty != Tvoid || type->parameters->dim > 0 || ( -#if DMDV2 fd->isAggregateMember() -#else - fd->isThis() -#endif && !fd->isStatic())) { error(s->loc, "the '%s' pragma is only allowed on void functions which take no arguments", ident->toChars()); diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 3c63aa16..ddee7b7e 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -218,10 +218,6 @@ static void LLVM_D_BuildRuntimeModule() = NoAttrs.addAttribute(gIR->context(), 1, llvm::Attribute::NoCapture), Attr_NoAlias_1_NoCapture = Attr_1_NoCapture.addAttribute(gIR->context(), 0, llvm::Attribute::NoAlias), -#if DMDV1 - Attr_NoAlias_3_NoCapture - = Attr_NoAlias.addAttribute(gIR->context(), 3, llvm::Attribute::NoCapture), -#endif Attr_1_2_NoCapture = Attr_1_NoCapture.addAttribute(gIR->context(), 2, llvm::Attribute::NoCapture), Attr_1_3_NoCapture @@ -251,10 +247,6 @@ static void LLVM_D_BuildRuntimeModule() = NoAttrs.addAttr(gIR->context(), 1, llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::NoCapture))), Attr_NoAlias_1_NoCapture = Attr_1_NoCapture.addAttr(gIR->context(), 0, llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::NoAlias))), -#if DMDV1 - Attr_NoAlias_3_NoCapture - = Attr_NoAlias.addAttr(gIR->context(), 3, llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::NoCapture))), -#endif Attr_1_2_NoCapture = Attr_1_NoCapture.addAttr(gIR->context(), 2, llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::NoCapture))), Attr_1_3_NoCapture @@ -284,10 +276,6 @@ static void LLVM_D_BuildRuntimeModule() = NoAttrs.addAttr(1, NoCapture), Attr_NoAlias_1_NoCapture = Attr_1_NoCapture.addAttr(0, NoAlias), -#if DMDV1 - Attr_NoAlias_3_NoCapture - = Attr_NoAlias.addAttr(3, NoCapture), -#endif Attr_1_2_NoCapture = Attr_1_NoCapture.addAttr(2, NoCapture), Attr_1_3_NoCapture @@ -308,21 +296,13 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } - // D1: - // void _d_array_bounds( char[] file, uint line ) - // void _d_switch_error( char[] file, uint line ) - // D2: // void _d_array_bounds(ModuleInfo* m, uint line) // void _d_switch_error(ModuleInfo* m, uint line) { llvm::StringRef fname("_d_array_bounds"); llvm::StringRef fname2("_d_switch_error"); LLType *types[] = { -#if DMDV2 getPtrToType(DtoType(Module::moduleinfo->type)), -#else - stringTy, -#endif intTy }; LLFunctionType* fty = llvm::FunctionType::get(voidTy, types, false); @@ -360,40 +340,6 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) ->setAttributes(Attr_NoAlias); } -#if DMDV1 - // void* _d_newarrayT(TypeInfo ti, size_t length) - // void* _d_newarrayiT(TypeInfo ti, size_t length) - // void* _d_newarrayvT(TypeInfo ti, size_t length) - { - llvm::StringRef fname("_d_newarrayT"); - llvm::StringRef fname2("_d_newarrayiT"); - llvm::StringRef fname3("_d_newarrayvT"); - LLType *types[] = { typeInfoTy, sizeTy }; - LLFunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) - ->setAttributes(Attr_NoAlias); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M) - ->setAttributes(Attr_NoAlias); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname3, M) - ->setAttributes(Attr_NoAlias); - } - // void* _d_newarraymT(TypeInfo ti, size_t length, size_t* dims) - // void* _d_newarraymiT(TypeInfo ti, size_t length, size_t* dims) - // void* _d_newarraymvT(TypeInfo ti, size_t length, size_t* dims) - { - llvm::StringRef fname("_d_newarraymT"); - llvm::StringRef fname2("_d_newarraymiT"); - llvm::StringRef fname3("_d_newarraymvT"); - LLType *types[] = { typeInfoTy, sizeTy, rt_ptr(sizeTy) }; - LLFunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) - ->setAttributes(Attr_NoAlias_3_NoCapture); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M) - ->setAttributes(Attr_NoAlias_3_NoCapture); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname3, M) - ->setAttributes(Attr_NoAlias_3_NoCapture); - } -#else // void[] _d_newarrayT(TypeInfo ti, size_t length) // void[] _d_newarrayiT(TypeInfo ti, size_t length) { @@ -414,12 +360,7 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); } -#endif - // D1: - // void* _d_arraysetlengthT(TypeInfo ti, size_t newlength, size_t plength, void* pdata) - // void* _d_arraysetlengthiT(TypeInfo ti, size_t newlength, size_t plength, void* pdata) - // D2: // void[] _d_arraysetlengthT(TypeInfo ti, size_t newlength, void[] *array) // void[] _d_arraysetlengthiT(TypeInfo ti, size_t newlength, void[] *array) { @@ -428,21 +369,13 @@ static void LLVM_D_BuildRuntimeModule() LLType *types[] = { typeInfoTy, sizeTy, -#if DMDV2 voidArrayPtrTy }; LLFunctionType* fty = llvm::FunctionType::get(voidArrayTy, types, false); -#else - sizeTy, - voidPtrTy - }; - LLFunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); -#endif llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); } -#if DMDV2 // byte[] _d_arrayappendcTX(TypeInfo ti, ref byte[] px, size_t n) { llvm::StringRef fname("_d_arrayappendcTX"); @@ -485,15 +418,6 @@ static void LLVM_D_BuildRuntimeModule() LLFunctionType* fty = llvm::FunctionType::get(voidArrayTy, types, true); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } -#else // DMDV1 - // byte[] _d_arrayappendcT(TypeInfo ti, void* array, void* element) - { - llvm::StringRef fname("_d_arrayappendcT"); - LLType *types[] = { typeInfoTy, voidPtrTy, voidPtrTy }; - LLFunctionType* fty = llvm::FunctionType::get(voidArrayTy, types, false); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); - } -#endif // Object _d_allocclass(ClassInfo ci) { @@ -504,8 +428,6 @@ static void LLVM_D_BuildRuntimeModule() ->setAttributes(Attr_NoAlias); } -#if DMDV2 - // void _d_delarray_t(Array *p, TypeInfo ti) { llvm::StringRef fname("_d_delarray_t"); @@ -514,23 +436,6 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } -#else - - // void _d_delarray(size_t plength, void* pdata) - { - llvm::StringRef fname("_d_delarray"); - LLType *types[] = { sizeTy, voidPtrTy }; - LLFunctionType* fty = llvm::FunctionType::get(voidTy, types, false); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); - } - -#endif - - // D1: - // void _d_delmemory(void* p) - // void _d_delinterface(void* p) - // void _d_callfinalizer(void* p) - // D2: // void _d_delmemory(void **p) // void _d_delinterface(void **p) // void _d_callfinalizer(void *p) @@ -545,16 +450,11 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname3, M); } - // D1: void _d_delclass(Object p) // D2: void _d_delclass(Object* p) { llvm::StringRef fname("_d_delclass"); LLType *types[] = { -#if DMDV2 rt_ptr(objectTy) -#else - objectTy -#endif }; LLFunctionType* fty = llvm::FunctionType::get(voidTy, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); @@ -654,8 +554,6 @@ static void LLVM_D_BuildRuntimeModule() ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - // void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to) // void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to) { @@ -680,8 +578,6 @@ static void LLVM_D_BuildRuntimeModule() ->setAttributes(Attr_NoAlias); } -#endif - ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// @@ -802,50 +698,28 @@ static void LLVM_D_BuildRuntimeModule() ->setAttributes(Attr_ReadOnly_NoUnwind_1_NoCapture); } - // D1: - // void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey) - // D2: // void* _aaGetX(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey) { -#if DMDV2 llvm::StringRef fname("_aaGetX"); -#else - llvm::StringRef fname("_aaGet"); -#endif LLType *types[] = { aaTy, typeInfoTy, sizeTy, voidPtrTy }; LLFunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) ->setAttributes(Attr_1_4_NoCapture); } - // D1: - // void* _aaIn(AA aa, TypeInfo keyti, void* pkey) - // D2: // void* _aaInX(AA aa, TypeInfo keyti, void* pkey) { -#if DMDV2 llvm::StringRef fname("_aaInX"); -#else - llvm::StringRef fname("_aaIn"); -#endif LLType *types[] = { aaTy, typeInfoTy, voidPtrTy }; LLFunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) ->setAttributes(Attr_ReadOnly_1_3_NoCapture); } - // D1: - // void _aaDel(AA aa, TypeInfo keyti, void* pkey) - // D2: // bool _aaDelX(AA aa, TypeInfo keyti, void* pkey) { -#if DMDV2 llvm::StringRef fname("_aaDelX"); LLType *retType = boolTy; -#else - llvm::StringRef fname("_aaDel"); - LLType *retType = voidTy; -#endif LLType *types[] = { aaTy, typeInfoTy, voidPtrTy }; LLFunctionType* fty = llvm::FunctionType::get(retType, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) @@ -896,7 +770,6 @@ static void LLVM_D_BuildRuntimeModule() ->setAttributes(Attr_1_NoCapture); } -#if DMDV2 // int _aaEqual(TypeInfo_AssociativeArray ti, AA e1, AA e2) { llvm::StringRef fname("_aaEqual"); @@ -912,16 +785,6 @@ static void LLVM_D_BuildRuntimeModule() LLFunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } -#else - // int _aaEq(AA aa, AA ab, TypeInfo_AssociativeArray ti) - { - llvm::StringRef fname("_aaEq"); - LLType *types[] = { aaTy, aaTy, typeInfoTy }; - LLFunctionType* fty = llvm::FunctionType::get(intTy, types, false); - llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) - ->setAttributes(Attr_1_2_NoCapture); - } -#endif ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// @@ -1040,12 +903,10 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } -#if DMDV2 // void _d_hidden_func() { llvm::StringRef fname("_d_hidden_func"); LLFunctionType* fty = llvm::FunctionType::get(voidTy, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } -#endif } diff --git a/gen/runtime.h b/gen/runtime.h index 05e62c09..f64e3ae4 100644 --- a/gen/runtime.h +++ b/gen/runtime.h @@ -30,14 +30,8 @@ llvm::Function* LLVM_D_GetRuntimeFunction(llvm::Module* target, const char* name llvm::GlobalVariable* LLVM_D_GetRuntimeGlobal(llvm::Module* target, const char* name); -#if DMDV1 -#define _d_allocclass "_d_allocclass" -#define _adEq "_adEq" -#define _adCmp "_adCmp" -#else #define _d_allocclass "_d_newclass" #define _adEq "_adEq2" #define _adCmp "_adCmp2" -#endif #endif // LDC_GEN_RUNTIME_H diff --git a/gen/statements.cpp b/gen/statements.cpp index 09fcefc3..f6f61355 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -83,11 +83,10 @@ void ReturnStatement::toIR(IRState* p) DValue* e = exp->toElemDtor(p); // store return value DtoAssign(loc, rvar, e); -#if DMDV2 + // call postblit if necessary if (!p->func()->type->isref && !(f->decl->nrvo_can && f->decl->nrvo_var)) callPostblit(loc, exp, rvar->getLVal()); -#endif // emit scopes DtoEnclosingHandlers(loc, NULL); @@ -108,7 +107,6 @@ void ReturnStatement::toIR(IRState* p) } else { if (exp->op == TOKnull) exp->type = p->func()->type->next; -#if DMDV2 DValue* dval = 0; // call postblit if necessary if (!p->func()->type->isref) { @@ -120,10 +118,6 @@ void ReturnStatement::toIR(IRState* p) } // do abi specific transformations on the return value v = p->func()->type->fty.putRet(exp->type, dval); -#else - DValue* dval = exp->toElemDtor(p); - v = p->func()->type->fty.putRet(exp->type, dval); -#endif } if (Logger::enabled()) @@ -137,9 +131,7 @@ void ReturnStatement::toIR(IRState* p) int ty = f->type->next->toBasetype()->ty; if (v->getType() != p->topfunc()->getReturnType() && (ty == Tstruct -#if DMDV2 || ty == Tsarray -#endif ) && isaPointer(v->getType())) { Logger::println("Loading value for return"); @@ -214,8 +206,6 @@ void ExpStatement::toIR(IRState* p) ////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - void DtorExpStatement::toIR(IRState *irs) { assert(irs->func()); @@ -233,8 +223,6 @@ void DtorExpStatement::toIR(IRState *irs) } } -#endif - ////////////////////////////////////////////////////////////////////////////// void IfStatement::toIR(IRState* p) @@ -1290,8 +1278,6 @@ void ForeachStatement::toIR(IRState* p) ////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - void ForeachRangeStatement::toIR(IRState* p) { Logger::println("ForeachRangeStatement::toIR(): %s", loc.toChars()); @@ -1394,8 +1380,6 @@ void ForeachRangeStatement::toIR(IRState* p) p->scope() = IRScope(endbb,oldend); } -#endif // D2 - ////////////////////////////////////////////////////////////////////////////// void LabelStatement::toIR(IRState* p) @@ -1627,16 +1611,10 @@ void SwitchErrorStatement::toIR(IRState* p) std::vector args; -#if DMDV2 // module param LLValue *moduleInfoSymbol = gIR->func()->decl->getModule()->moduleInfoSymbol(); LLType *moduleInfoType = DtoType(Module::moduleinfo->type); args.push_back(DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType))); -#else - // file param - IrModule* irmod = getIrModule(NULL); - args.push_back(DtoLoad(irmod->fileName)); -#endif // line param LLConstant* c = DtoConstUint(loc.linnum); @@ -1645,19 +1623,13 @@ void SwitchErrorStatement::toIR(IRState* p) // call LLCallSite call = gIR->CreateCallOrInvoke(fn, args); call.setDoesNotReturn(); - -#if DMDV1 - gIR->ir->CreateUnreachable(); -#endif } ////////////////////////////////////////////////////////////////////////////// -#if DMDV2 void ImportStatement::toIR(IRState *irs) { } -#endif ////////////////////////////////////////////////////////////////////////////// @@ -1693,10 +1665,7 @@ STUBST(Statement); //STUBST(GotoStatement); //STUBST(UnrolledLoopStatement); //STUBST(OnScopeStatement); - -#if DMDV2 STUBST(PragmaStatement); -#endif ////////////////////////////////////////////////////////////////////////////// diff --git a/gen/structs.cpp b/gen/structs.cpp index 43a4e5bb..efa17310 100644 --- a/gen/structs.cpp +++ b/gen/structs.cpp @@ -253,12 +253,10 @@ std::vector DtoStructLiteralValues(const StructDeclaration* sd, // update offsets lastoffset = os; -#if DMDV2 // sometimes size of the initializer is less than size of the variable, // so make sure that lastsize is correct if (inits[i]->getType()->isSized()) sz = ceil(gDataLayout->getTypeSizeInBits(init->getType()) / 8.0); -#endif lastsize = sz; // go to next explicit init diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 2b44b69d..c6e2ea82 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -135,11 +135,7 @@ static LLValue *fixArgument(DValue *argval, TypeFunction* tf, LLType *callableAr // pointer to a struct, load from it before passing it in. int ty = argval->getType()->toBasetype()->ty; if (isaPointer(arg) && !isaPointer(callableArgType) && -#if DMDV2 (ty == Tstruct || ty == Tsarray)) -#else - ty == Tstruct) -#endif { Logger::println("Loading struct type for function argument"); arg = DtoLoad(arg); @@ -408,7 +404,6 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // then comes a context argument... if(thiscall || delegatecall || nestedcall) { -#if DMDV2 if (dfnval && (dfnval->func->ident == Id::ensure || dfnval->func->ident == Id::require)) { // ... which can be the this "context" argument for a contract // invocation (in D2, we do not generate a full nested contexts @@ -420,7 +415,6 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* args.push_back(thisarg); } else -#endif if (thiscall && dfnval && dfnval->vthis) { // ... or a normal 'this' argument @@ -630,9 +624,7 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // a stack slot before continuing. int ty = tf->next->toBasetype()->ty; if ((ty == Tstruct && !isaPointer(retllval)) -#if DMDV2 || (ty == Tsarray && isaArray(retllval)) -#endif ) { Logger::println("Storing return value to stack slot"); @@ -652,11 +644,9 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* switch(rbase->ty) { case Tarray: - #if DMDV2 if (tf->isref) retllval = DtoBitCast(retllval, DtoType(rbase->pointerTo())); else - #endif retllval = DtoAggrPaint(retllval, DtoType(rbase)); break; @@ -667,15 +657,12 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* case Tclass: case Taarray: case Tpointer: - #if DMDV2 if (tf->isref) retllval = DtoBitCast(retllval, DtoType(rbase->pointerTo())); else - #endif retllval = DtoBitCast(retllval, DtoType(rbase)); break; -#if DMDV2 case Tstruct: if (nextbase->ty == Taarray && !tf->isref) { @@ -694,7 +681,6 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* break; } // Fall through. -#endif default: // Unfortunately, DMD has quirks resp. bugs with regard to name @@ -766,9 +752,7 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // or if we are returning a reference // make sure we provide a lvalue back! if (retinptr -#if DMDV2 || tf->isref -#endif ) return new DVarValue(resulttype, retllval); diff --git a/gen/todebug.cpp b/gen/todebug.cpp index eb6791b0..6792c7b2 100644 --- a/gen/todebug.cpp +++ b/gen/todebug.cpp @@ -298,11 +298,7 @@ static llvm::DIType dwarfCompositeType(Type* type) static llvm::DIGlobalVariable dwarfGlobalVariable(LLGlobalVariable* ll, VarDeclaration* vd) { -#if DMDV2 assert(vd->isDataseg() || (vd->storage_class & (STCconst | STCimmutable) && vd->init)); -#else - assert(vd->isDataseg()); -#endif return gIR->dibuilder.createGlobalVariable( vd->toChars(), // name TODO: mangle() or toPrettyChars() instead? diff --git a/gen/toir.cpp b/gen/toir.cpp index cec9a779..c12d3366 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -60,7 +60,6 @@ void Expression::cacheLvalue(IRState* irs) DValue *Expression::toElemDtor(IRState *irs) { -#if DMDV2 Logger::println("Expression::toElemDtor(): %s", toChars()); LOG_SCOPE @@ -76,9 +75,6 @@ DValue *Expression::toElemDtor(IRState *irs) vd->edtor->toElem(gIR); } return val; -#else - return toElem(irs); -#endif } ////////////////////////////////////////////////////////////////////////////////////////// @@ -117,13 +113,11 @@ DValue* VarExp::toElem(IRState* p) { Logger::println("VarDeclaration ' %s ' of type ' %s '", vd->toChars(), vd->type->toChars()); -#if DMDV2 /* The magic variable __ctfe is always false at runtime */ if (vd->ident == Id::ctfe) { return new DConstValue(type, DtoConstBool(false)); } -#endif // this is an error! must be accessed with DotVarExp if (var->needThis()) @@ -179,11 +173,7 @@ DValue* VarExp::toElem(IRState* p) return new DImValue(type, m); } // nested variable - #if DMDV2 else if (vd->nestedrefs.dim) { - #else - else if (vd->nestedref) { - #endif Logger::println("nested variable"); return DtoNestedVariable(loc, type, vd); } @@ -238,9 +228,7 @@ DValue* VarExp::toElem(IRState* p) { Logger::println("FuncDeclaration"); LLValue* func = 0; -#if DMDV2 fdecl = fdecl->toAliasFunc(); -#endif if (fdecl->llvmInternal == LLVMinline_asm) { error("special ldc inline asm is not a normal function"); fatal(); @@ -608,11 +596,9 @@ DValue* AssignExp::toElem(IRState* p) Logger::println("performing aggregate zero initialization"); assert(e2->toInteger() == 0); DtoAggrZeroInit(l->getLVal()); -#if DMDV2 TypeStruct *ts = static_cast(e1->type); if (ts->sym->isNested() && ts->sym->vthis) DtoResolveNestedContext(loc, ts->sym, l->getLVal()); -#endif // Return value should be irrelevant. return r; } @@ -933,7 +919,6 @@ DValue* CallExp::toElem(IRState* p) // llvm doesn't need the second param hence the override Expression* exp = static_cast(arguments->data[0]); LLValue* arg = exp->toElem(p)->getLVal(); -#if DMDV2 if (LLValue *argptr = gIR->func()->_argptr) { DtoStore(DtoLoad(argptr), DtoBitCast(arg, getPtrToType(getVoidPtrType()))); return new DImValue(type, arg); @@ -943,13 +928,11 @@ DValue* CallExp::toElem(IRState* p) va_list = DtoBitCast(va_list, getVoidPtrType()); return new DImValue(type, gIR->ir->CreateCall(GET_INTRINSIC_DECL(vastart), va_list, "")); } else -#endif { arg = DtoBitCast(arg, getVoidPtrType()); return new DImValue(type, gIR->ir->CreateCall(GET_INTRINSIC_DECL(vastart), arg, "")); } } -#if DMDV2 else if (fndecl->llvmInternal == LLVMva_copy && global.params.targetTriple.getArch() == llvm::Triple::x86_64) { if (arguments->dim != 2) { @@ -967,7 +950,6 @@ DValue* CallExp::toElem(IRState* p) DtoStore(DtoLoad(DtoLoad(arg2)), DtoLoad(arg1)); return new DVarValue(type, arg1); } -#endif // va_arg instruction else if (fndecl->llvmInternal == LLVMva_arg) { if (arguments->dim != 1) { @@ -1523,7 +1505,6 @@ DValue* ThisExp::toElem(IRState* p) LLValue* v; Dsymbol* vdparent = vd->toParent2(); Identifier *ident = p->func()->decl->ident; -#if DMDV2 // In D1, contracts are treated as normal nested methods, 'this' is // just passed in the context struct along with any used parameters. if (ident == Id::ensure || ident == Id::require) { @@ -1531,7 +1512,6 @@ DValue* ThisExp::toElem(IRState* p) v = p->func()->nestArg; v = DtoBitCast(v, DtoType(type)->getPointerTo()); } else -#endif if (vdparent != p->func()->decl) { Logger::println("nested this exp"); #if STRUCTTHISREF @@ -1648,11 +1628,7 @@ DValue* SliceExp::toElem(IRState* p) LLValue* vlo = lo->getRVal(); LLValue* vup = up->getRVal(); -#if DMDV2 if(global.params.useArrayBounds) -#else - if(global.params.useArrayBounds && (etype->ty == Tsarray || etype->ty == Tarray)) -#endif DtoArrayBoundsCheck(loc, e, up, lo); // offset by lower @@ -1993,7 +1969,6 @@ DValue* NewExp::toElem(IRState* p) Logger::println("new struct on heap: %s\n", newtype->toChars()); // allocate LLValue* mem = 0; -#if DMDV2 if (allocator) { // custom allocator @@ -2002,7 +1977,6 @@ DValue* NewExp::toElem(IRState* p) DValue* res = DtoCallFunction(loc, NULL, &dfn, newargs); mem = DtoBitCast(res->getRVal(), DtoType(ntype->pointerTo()), ".newstruct_custom"); } else -#endif { // default allocator mem = DtoNew(newtype); @@ -2017,7 +1991,6 @@ DValue* NewExp::toElem(IRState* p) ts->sym->codegen(Type::sir); DtoAggrCopy(mem, ts->sym->ir.irStruct->getInitSymbol()); } -#if DMDV2 if (ts->sym->isNested() && ts->sym->vthis) DtoResolveNestedContext(loc, ts->sym, mem); @@ -2030,7 +2003,6 @@ DValue* NewExp::toElem(IRState* p) DFuncValue dfn(member, member->ir.irFunc->func, mem); DtoCallFunction(loc, ts, &dfn, arguments); } -#endif return new DImValue(type, mem); } // new basic type @@ -2066,14 +2038,7 @@ DValue* DeleteExp::toElem(IRState* p) // simple pointer if (et->ty == Tpointer) { -#if DMDV2 DtoDeleteMemory(dval->isLVal() ? dval->getLVal() : makeLValue(loc, dval)); -#else - LLValue* rval = dval->getRVal(); - DtoDeleteMemory(rval); - if (dval->isVar()) - DtoStore(LLConstant::getNullValue(rval->getType()), dval->getLVal()); -#endif } // class else if (et->ty == Tclass) @@ -2082,11 +2047,7 @@ DValue* DeleteExp::toElem(IRState* p) TypeClass* tc = static_cast(et); if (tc->sym->isInterfaceDeclaration()) { -#if DMDV2 LLValue *val = dval->getLVal(); -#else - LLValue *val = dval->getRVal(); -#endif DtoDeleteInterface(val); onstack = true; } @@ -2618,23 +2579,7 @@ DValue* CatExp::toElem(IRState* p) Logger::print("CatExp::toElem: %s @ %s\n", toChars(), type->toChars()); LOG_SCOPE; -#if DMDV2 return DtoCatArrays(type, e1, e2); -#else - - bool arrNarr = e1->type->toBasetype() == e2->type->toBasetype(); - // array ~ array - if (arrNarr) - { - return DtoCatArrays(type, e1, e2); - } - // array ~ element - // element ~ array - else - { - return DtoCatArrayElement(type, e1, e2); - } -#endif } ////////////////////////////////////////////////////////////////////////////////////////// @@ -2704,17 +2649,14 @@ DValue* FuncExp::toElem(IRState* p) LLValue* cval; IrFunction* irfn = p->func(); if (irfn->nestedVar -#if DMDV2 // We cannot use a frame allocated in one function // for a delegate created in another function // (that happens with anonymous functions) && fd->toParent2() == irfn->decl -#endif ) cval = irfn->nestedVar; else if (irfn->nestArg) cval = DtoLoad(irfn->nestArg); -#if DMDV2 // TODO: should we enable that for D1 as well? else if (irfn->thisArg) { @@ -2726,7 +2668,6 @@ DValue* FuncExp::toElem(IRState* p) cval = DtoLoad(DtoGEPi(cval, 0,ad->vthis->ir.irField->index, ".vthis")); } } -#endif else cval = getNullPtr(getVoidPtrType()); cval = DtoBitCast(cval, dgty->getContainedType(0)); @@ -2882,11 +2823,9 @@ LLConstant* ArrayLiteralExp::toConstElem(IRState* p) LLConstant* globalstore = new LLGlobalVariable(*gIR->module, t, false, LLGlobalValue::InternalLinkage, initval, ".dynarrayStorage"); globalstore = DtoBitCast(globalstore, getPtrToType(arrtype)); -#if DMDV2 if (bt->ty == Tpointer) // we need to return pointer to the static array. return globalstore; -#endif // build a constant dynamic array reference with the .ptr field pointing into globalstore LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) }; @@ -2911,8 +2850,6 @@ DValue* StructLiteralExp::toElem(IRState* p) Logger::print("StructLiteralExp::toElem: %s @ %s\n", toChars(), type->toChars()); LOG_SCOPE; - -#if DMDV2 if (sinit) { // Copied from VarExp::toElem, need to clean this mess up. @@ -2927,7 +2864,6 @@ DValue* StructLiteralExp::toElem(IRState* p) initsym = DtoBitCast(initsym, DtoType(ts->pointerTo())); return new DVarValue(type, initsym); } -#endif // make sure the struct is fully resolved sd->codegen(Type::sir); @@ -2974,13 +2910,11 @@ DValue* StructLiteralExp::toElem(IRState* p) IF_LOG Logger::println("expr %zu = %s", it.index, expr->toChars()); val = expr->toElem(gIR); } -#if DMDV2 else if (vd == sd->vthis) { IF_LOG Logger::println("initializing vthis"); LOG_SCOPE val = new DImValue(vd->type, DtoBitCast(DtoNestedContext(loc, sd), DtoType(vd->type))); } -#endif else { if (vd->init && vd->init->isVoidInitializer()) @@ -2997,10 +2931,8 @@ DValue* StructLiteralExp::toElem(IRState* p) // store the initializer there DtoAssign(loc, &field, val, TOKconstruct); -#if DMDV2 if (expr) callPostblit(loc, expr, field.getLVal()); -#endif // Also zero out padding bytes counted as being part of the type in DMD // but not in LLVM; e.g. real/x86_fp80. @@ -3028,7 +2960,6 @@ LLConstant* StructLiteralExp::toConstElem(IRState* p) Logger::print("StructLiteralExp::toConstElem: %s @ %s\n", toChars(), type->toChars()); LOG_SCOPE; -#if DMDV2 if (sinit) { // Copied from VarExp::toConstElem, need to clean this mess up. @@ -3040,7 +2971,6 @@ LLConstant* StructLiteralExp::toConstElem(IRState* p) return ts->sym->ir.irStruct->getDefaultInit(); } -#endif // make sure the struct is resolved sd->codegen(Type::sir); @@ -3118,7 +3048,6 @@ DValue* AssocArrayLiteralExp::toElem(IRState* p) Type* aatype = basetype; Type* vtype = aatype->nextOf(); -#if DMDV2 if (!keys->dim) goto LruntimeInit; @@ -3183,7 +3112,6 @@ DValue* AssocArrayLiteralExp::toElem(IRState* p) } LruntimeInit: -#endif // it should be possible to avoid the temporary in some cases LLValue* tmp = DtoAlloca(type, "aaliteral"); @@ -3276,8 +3204,6 @@ DValue* TupleExp::toElem(IRState *p) ////////////////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - DValue* VectorExp::toElem(IRState* p) { Logger::print("VectorExp::toElem() %s\n", toChars()); @@ -3312,20 +3238,14 @@ DValue* VectorExp::toElem(IRState* p) return new DVarValue(to, vector); } -#endif - - ////////////////////////////////////////////////////////////////////////////////////////// #define STUB(x) DValue *x::toElem(IRState * p) {error("Exp type "#x" not implemented: %s", toChars()); fatal(); return 0; } STUB(Expression); STUB(ScopeExp); - -#if DMDV2 STUB(SymbolExp); STUB(PowExp); STUB(PowAssignExp); -#endif #define CONSTSTUB(x) LLConstant* x::toConstElem(IRState * p) { \ error("expression '%s' is not a constant", toChars()); \ diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 85347fb9..38c5b9ae 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -202,12 +202,10 @@ LLType* DtoType(Type* t) case Taarray: return getVoidPtrType(); -#if DMDV2 case Tvector: { return IrTypeVector::get(t)->getLLType(); } -#endif /* Not needed atm as VarDecls for tuples are rewritten as a string of @@ -1036,11 +1034,7 @@ LLStructType* DtoModuleReferenceType() // add members LLType *types[] = { getPtrToType(st), -#if DMDV1 - DtoType(Module::moduleinfo->type) -#else DtoType(Module::moduleinfo->type->pointerTo()) -#endif }; // resolve type diff --git a/gen/typinf.cpp b/gen/typinf.cpp index 404c450d..cb531eb1 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -82,10 +82,8 @@ Expression *Type::getInternalTypeInfo(Scope *sc) goto Linternal; case Tarray: - #if DMDV2 // convert to corresponding dynamic array type t = t->nextOf()->mutableOf()->arrayOf(); - #endif if (t->nextOf()->ty != Tclass) break; goto Linternal; @@ -129,7 +127,6 @@ Expression *Type::getTypeInfo(Scope *sc) if (!t->vtinfo) { -#if DMDV2 if (t->isShared()) t->vtinfo = new TypeInfoSharedDeclaration(t); else if (t->isConst()) @@ -139,7 +136,6 @@ Expression *Type::getTypeInfo(Scope *sc) else if (t->isWild()) t->vtinfo = new TypeInfoWildDeclaration(t); else -#endif t->vtinfo = t->getTypeInfoDeclaration(); assert(t->vtinfo); @@ -218,12 +214,10 @@ TypeInfoDeclaration *TypeClass::getTypeInfoDeclaration() return new TypeInfoClassDeclaration(this); } -#if DMDV2 TypeInfoDeclaration *TypeVector::getTypeInfoDeclaration() { return new TypeInfoVectorDeclaration(this); } -#endif TypeInfoDeclaration *TypeEnum::getTypeInfoDeclaration() { @@ -258,22 +252,14 @@ int Type::builtinTypeInfo() int TypeBasic::builtinTypeInfo() { -#if DMDV2 return mod ? 0 : 1; -#else - return 1; -#endif } int TypeDArray::builtinTypeInfo() { -#if DMDV2 return !mod && ((next->isTypeBasic() != NULL && !next->mod) || // strings are so common, make them builtin (next->ty == Tchar && next->mod == MODimmutable)); -#else - return next->isTypeBasic() != NULL; -#endif } int TypeClass::builtinTypeInfo() @@ -466,11 +452,7 @@ void TypeInfoEnumDeclaration::llvmDefine() else { LLType* memty = DtoType(sd->memtype); -#if DMDV2 LLConstant* C = LLConstantInt::get(memty, sd->defaultval->toInteger(), !isLLVMUnsigned(sd->memtype)); -#else - LLConstant* C = LLConstantInt::get(memty, sd->defaultval, !isLLVMUnsigned(sd->memtype)); -#endif b.push_void_array(C, sd->memtype, sd); } @@ -546,10 +528,8 @@ void TypeInfoAssociativeArrayDeclaration::llvmDefine() // key typeinfo b.push_typeinfo(tc->index); -#if DMDV2 // impl typeinfo b.push_typeinfo(tc->getImpl()->type); -#endif // finish b.finalize(ir.irGlobal); @@ -646,16 +626,10 @@ void TypeInfoStructDeclaration::llvmDefine() { Scope sc; tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); -#if DMDV2 tftohash ->mod = MODconst; -#endif tftohash = static_cast(tftohash->semantic(0, &sc)); -#if DMDV2 Type *retType = Type::tchar->invariantOf()->arrayOf(); -#else - Type *retType = Type::tchar->arrayOf(); -#endif tftostring = new TypeFunction(NULL, retType, 0, LINKd); tftostring = static_cast(tftostring->semantic(0, &sc)); } @@ -675,9 +649,7 @@ void TypeInfoStructDeclaration::llvmDefine() #endif arguments->push(arg); tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); -#if DMDV2 tfcmpptr->mod = MODconst; -#endif tfcmpptr = static_cast(tfcmpptr->semantic(0, &sc)); } @@ -689,11 +661,7 @@ void TypeInfoStructDeclaration::llvmDefine() b.push_funcptr(fd); // opEquals -#if DMDV2 fd = sd->xeq; -#else - fd = find_method_overload(sd, Id::eq, tfcmpptr, gm); -#endif b.push_funcptr(fd); // opCmp @@ -708,8 +676,6 @@ void TypeInfoStructDeclaration::llvmDefine() unsigned hasptrs = tc->hasPointers() ? 1 : 0; b.push_uint(hasptrs); -#if DMDV2 - ClassDeclaration* tscd = Type::typeinfostruct; // On x86_64, class TypeInfo_Struct contains 2 additional fields @@ -759,15 +725,12 @@ void TypeInfoStructDeclaration::llvmDefine() else b.push_size_as_vp(1); // has pointers -#endif - // finish b.finalize(ir.irGlobal); } /* ========================================================================= */ -#if DMDV2 void TypeInfoClassDeclaration::codegen(Ir*i) { @@ -778,28 +741,10 @@ void TypeInfoClassDeclaration::codegen(Ir*i) tc->sym->codegen(Type::sir); // make sure class is resolved irg->value = tc->sym->ir.irStruct->getClassInfoSymbol(); } -#endif void TypeInfoClassDeclaration::llvmDefine() { -#if DMDV2 llvm_unreachable("TypeInfoClassDeclaration should not be called for D2"); -#endif - Logger::println("TypeInfoClassDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // make sure class is resolved - assert(tinfo->ty == Tclass); - TypeClass *tc = static_cast(tinfo); - tc->sym->codegen(Type::sir); - - RTTIBuilder b(Type::typeinfoclass); - - // TypeInfo base - b.push_classinfo(tc->sym); - - // finish - b.finalize(ir.irGlobal); } /* ========================================================================= */ @@ -861,8 +806,6 @@ void TypeInfoTupleDeclaration::llvmDefine() /* ========================================================================= */ -#if DMDV2 - void TypeInfoConstDeclaration::llvmDefine() { Logger::println("TypeInfoConstDeclaration::llvmDefine() %s", toChars()); @@ -933,5 +876,3 @@ void TypeInfoVectorDeclaration::llvmDefine() // finish b.finalize(ir.irGlobal); } - -#endif diff --git a/ir/irclass.cpp b/ir/irclass.cpp index 219f92f5..21c4b057 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -185,7 +185,6 @@ LLConstant * IrStruct::getVtblInit() fd->codegen(Type::sir); assert(fd->ir.irFunc && "invalid vtbl function"); c = fd->ir.irFunc->func; -#if DMDV2 if (cd->isFuncHidden(fd)) { /* fd is hidden from the view of this class. * If fd overlaps with any function in the vtbl[], then @@ -218,7 +217,6 @@ LLConstant * IrStruct::getVtblInit() } } } -#endif } constants.push_back(c); } diff --git a/ir/irlandingpad.cpp b/ir/irlandingpad.cpp index 8f4c25ca..55b0e54d 100644 --- a/ir/irlandingpad.cpp +++ b/ir/irlandingpad.cpp @@ -28,11 +28,7 @@ IRLandingPadInfo::IRLandingPadInfo(Catch* catchstmt_, llvm::BasicBlock* end_) : catchType->codegen(Type::sir); if(catchstmt->var) { - #if DMDV2 if(!catchstmt->var->nestedrefs.dim) { - #else - if(!catchstmt->var->nestedref) { - #endif gIR->func()->gen->landingPadInfo.getExceptionStorage(); } } @@ -56,11 +52,7 @@ void IRLandingPadInfo::toIR() if(catchstmt->var) { // use the same storage for all exceptions that are not accessed in // nested functions - #if DMDV2 if(!catchstmt->var->nestedrefs.dim) { - #else - if(!catchstmt->var->nestedref) { - #endif assert(!catchstmt->var->ir.irLocal); catchstmt->var->ir.irLocal = new IrLocal(catchstmt->var); LLValue* catch_var = gIR->func()->gen->landingPadInfo.getExceptionStorage(); diff --git a/ir/irstruct.cpp b/ir/irstruct.cpp index db7410e3..0873f403 100644 --- a/ir/irstruct.cpp +++ b/ir/irstruct.cpp @@ -67,11 +67,9 @@ LLGlobalVariable * IrStruct::getInitSymbol() // set alignment init->setAlignment(type->alignsize()); -#if DMDV2 StructDeclaration *sd = aggrdecl->isStructDeclaration(); if (sd && sd->alignment != STRUCTALIGN_DEFAULT) init->setAlignment(sd->alignment); -#endif return init; } diff --git a/ir/irtype.cpp b/ir/irtype.cpp index c25f206e..f73c71f6 100644 --- a/ir/irtype.cpp +++ b/ir/irtype.cpp @@ -266,8 +266,6 @@ IrTypeArray* IrTypeArray::get(Type* dt) ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -#if DMDV2 - IrTypeVector::IrTypeVector(Type* dt) : IrType(dt, vector2llvm(dt)) { @@ -297,6 +295,4 @@ llvm::Type* IrTypeVector::vector2llvm(Type* dt) return llvm::VectorType::get(elemType, dim); } -#endif - ////////////////////////////////////////////////////////////////////////////// diff --git a/ir/irtype.h b/ir/irtype.h index 14e5c6a7..c3205350 100644 --- a/ir/irtype.h +++ b/ir/irtype.h @@ -37,9 +37,7 @@ class IrTypeFunction; class IrTypePointer; class IrTypeSArray; class IrTypeStruct; -#if DMDV2 class IrTypeVector; -#endif ////////////////////////////////////////////////////////////////////////////// @@ -72,10 +70,8 @@ public: virtual IrTypeSArray* isSArray() { return NULL; } /// virtual IrTypeStruct* isStruct() { return NULL; } -#if DMDV2 /// IrTypeVector* isVector() { return NULL; } -#endif /// Type* getDType() { return dtype; } @@ -170,7 +166,6 @@ protected: ////////////////////////////////////////////////////////////////////////////// -#if DMDV2 /// IrType for vectors class IrTypeVector : public IrType { @@ -187,6 +182,5 @@ protected: static llvm::Type* vector2llvm(Type* dt); }; -#endif #endif diff --git a/ir/irtypeclass.cpp b/ir/irtypeclass.cpp index 49635811..e29aa7d4 100644 --- a/ir/irtypeclass.cpp +++ b/ir/irtypeclass.cpp @@ -323,7 +323,6 @@ std::vector IrTypeClass::buildVtblType(Type* first, Array* vtbl_arr IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); -#if DMDV2 // If inferring return type and semantic3 has not been run, do it now. // This pops up in some other places in the frontend as well, however // it is probably a bug that it still occurs that late. @@ -336,7 +335,6 @@ std::vector IrTypeClass::buildVtblType(Type* first, Array* vtbl_arr if (spec && global.errors != olderrs) spec->errors = global.errors - olderrs; } -#endif if (!fd->type->nextOf()) { // Return type of the function has not been inferred. This seems to From c3801d65f55f92c0cf3ebe8a8106fc74e356ab82 Mon Sep 17 00:00:00 2001 From: kai Date: Tue, 5 Mar 2013 18:44:32 +0100 Subject: [PATCH 3/6] Remove STRUCTTHISREF --- gen/functions.cpp | 18 ------------------ gen/toir.cpp | 4 ---- gen/typinf.cpp | 6 +----- 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/gen/functions.cpp b/gen/functions.cpp index a48b6d77..9fc74e2d 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -90,28 +90,12 @@ llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, llvm::AttrBuilder().addAttribute(llvm::Attributes::StructRet) .addAttribute(llvm::Attributes::NoAlias) #endif - #if !STRUCTTHISREF - // In D2 where 'this' in structs is a reference, nocapture - // might not actually be applicable, even if it probably still - // is for all sane code from a high-level semantic standpoint. - // Specifying nocapture on a parameter but then passing it as a - // non-nocapture argument in a function call can lead to - // _silent_ miscompilations (especially in the GVN pass). -#if LDC_LLVM_VER >= 303 - .addAttribute(llvm::Attribute::NoCapture) -#else - .addAttribute(llvm::Attributes::NoCapture) -#endif - #endif #if LDC_LLVM_VER == 302 ) #endif ); #else fty.arg_sret = new IrFuncTyArg(rt, true, StructRet | NoAlias - #if !STRUCTTHISREF - | NoCapture - #endif ); #endif rt = Type::tvoid; @@ -1010,9 +994,7 @@ void DtoDefineFunction(FuncDeclaration* fd) assert(thisvar); LLValue* thismem = thisvar; - #if STRUCTTHISREF if (!f->fty.arg_this->byref) - #endif { thismem = DtoRawAlloca(thisvar->getType(), 0, "this"); // FIXME: align? DtoStore(thisvar, thismem); diff --git a/gen/toir.cpp b/gen/toir.cpp index c12d3366..0fcad2a7 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1514,11 +1514,7 @@ DValue* ThisExp::toElem(IRState* p) } else if (vdparent != p->func()->decl) { Logger::println("nested this exp"); -#if STRUCTTHISREF return DtoNestedVariable(loc, type, vd, type->ty == Tstruct); -#else - return DtoNestedVariable(loc, type, vd); -#endif } else { Logger::println("normal this exp"); diff --git a/gen/typinf.cpp b/gen/typinf.cpp index cb531eb1..f9df4a57 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -640,13 +640,9 @@ void TypeInfoStructDeclaration::llvmDefine() { Scope sc; Parameters *arguments = new Parameters; -#if STRUCTTHISREF + // arg type is ref const T Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); -#else - // arg type is const T* - Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); -#endif arguments->push(arg); tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfcmpptr->mod = MODconst; From 37558273c264d0d44d64d1414f5d64e79bac998b Mon Sep 17 00:00:00 2001 From: kai Date: Tue, 5 Mar 2013 18:49:30 +0100 Subject: [PATCH 4/6] Remove SARRAYVALUE --- gen/abi-win64.cpp | 2 -- gen/abi-x86-64.cpp | 2 -- gen/abi-x86.cpp | 2 -- gen/functions.cpp | 3 --- 4 files changed, 9 deletions(-) diff --git a/gen/abi-win64.cpp b/gen/abi-win64.cpp index bd76d5cb..5bd00aa5 100644 --- a/gen/abi-win64.cpp +++ b/gen/abi-win64.cpp @@ -140,9 +140,7 @@ bool Win64TargetABI::returnInArg(TypeFunction* tf) // or ST(1) & ST(0) (creal) // all other structs and static arrays are returned by struct-return (sret) return (rt->ty == Tstruct -#if SARRAYVALUE || rt->ty == Tsarray -#endif ) && !canRewriteAsInt(rt); } diff --git a/gen/abi-x86-64.cpp b/gen/abi-x86-64.cpp index 69771f1f..0563315c 100644 --- a/gen/abi-x86-64.cpp +++ b/gen/abi-x86-64.cpp @@ -444,9 +444,7 @@ bool X86_64TargetABI::returnInArg(TypeFunction* tf) { // All non-structs can be returned in registers. return rt->ty == Tstruct -#if SARRAYVALUE || rt->ty == Tsarray -#endif ; } else { if (rt == Type::tvoid || keepUnchanged(rt)) diff --git a/gen/abi-x86.cpp b/gen/abi-x86.cpp index 9dd4ef92..c2e2e1e3 100644 --- a/gen/abi-x86.cpp +++ b/gen/abi-x86.cpp @@ -78,9 +78,7 @@ struct X86TargetABI : TargetABI if (tf->linkage == LINKd) { return rt->ty == Tstruct -#if SARRAYVALUE || rt->ty == Tsarray -#endif ; } // other ABI's follow C, which is cdouble and creal returned on the stack diff --git a/gen/functions.cpp b/gen/functions.cpp index 9fc74e2d..51a0f48f 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -192,9 +192,6 @@ llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, // reference semantics? ref, out and d1 static arrays are bool byref = arg->storageClass & (STCref|STCout); -#if !SARRAYVALUE - byref = byref || (arg->type->toBasetype()->ty == Tsarray); -#endif Type* argtype = arg->type; #if LDC_LLVM_VER >= 302 From 0b5e04580c9a36ca36ff8053e6e6a2af1cfbd3a4 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 6 Mar 2013 16:45:27 +0100 Subject: [PATCH 5/6] Removed a few D1 leftovers. --- ldc.rebuild.conf.in | 2 - ldc_install.conf.in | 18 - runtime/CMakeLists.txt | 9 - tests/d1/.gitignore | 6 - tests/d1/README | 15 - tests/d1/findregressions.d | 367 ------------ tests/d1/makewebstatistics.d | 705 ------------------------ tests/d1/minicomplex/arrays1.d | 78 --- tests/d1/minicomplex/constructors.d | 31 -- tests/d1/minicomplex/files1.d | 12 - tests/d1/minicomplex/gc2.d | 9 - tests/d1/minicomplex/ina1.d | 11 - tests/d1/minicomplex/l.d | 6 - tests/d1/minicomplex/mem1.d | 63 --- tests/d1/minicomplex/mem4.d | 29 - tests/d1/minicomplex/stdout1.d | 7 - tests/d1/minicomplex/stdout2.d | 8 - tests/d1/minicomplex/templ1.d | 13 - tests/d1/minicomplex/u.d | 9 - tests/d1/minicomplex/vararg1.d | 13 - tests/d1/minicomplex/vararg2.d | 42 -- tests/d1/minicomplex/volatile1.d | 13 - tests/d1/runminitest.d | 128 ----- tests/d1/runtest | 62 --- tests/d1/testincludes/Makefile | 51 -- tests/d1/testincludes/object.di | 320 ----------- tests/d1/testincludes/std/IEEE.d | 136 ----- tests/d1/testincludes/std/compat.d | 10 - tests/d1/testincludes/std/gc.d | 250 --------- tests/d1/testincludes/std/outofmemory.d | 11 - tests/d1/testincludes/std/stdarg.d | 30 - 31 files changed, 2464 deletions(-) delete mode 100644 ldc.rebuild.conf.in delete mode 100644 ldc_install.conf.in delete mode 100644 tests/d1/.gitignore delete mode 100644 tests/d1/README delete mode 100644 tests/d1/findregressions.d delete mode 100644 tests/d1/makewebstatistics.d delete mode 100644 tests/d1/minicomplex/arrays1.d delete mode 100644 tests/d1/minicomplex/constructors.d delete mode 100644 tests/d1/minicomplex/files1.d delete mode 100644 tests/d1/minicomplex/gc2.d delete mode 100644 tests/d1/minicomplex/ina1.d delete mode 100644 tests/d1/minicomplex/l.d delete mode 100644 tests/d1/minicomplex/mem1.d delete mode 100644 tests/d1/minicomplex/mem4.d delete mode 100644 tests/d1/minicomplex/stdout1.d delete mode 100644 tests/d1/minicomplex/stdout2.d delete mode 100644 tests/d1/minicomplex/templ1.d delete mode 100644 tests/d1/minicomplex/u.d delete mode 100644 tests/d1/minicomplex/vararg1.d delete mode 100644 tests/d1/minicomplex/vararg2.d delete mode 100644 tests/d1/minicomplex/volatile1.d delete mode 100644 tests/d1/runminitest.d delete mode 100755 tests/d1/runtest delete mode 100644 tests/d1/testincludes/Makefile delete mode 100644 tests/d1/testincludes/object.di delete mode 100644 tests/d1/testincludes/std/IEEE.d delete mode 100644 tests/d1/testincludes/std/compat.d delete mode 100644 tests/d1/testincludes/std/gc.d delete mode 100644 tests/d1/testincludes/std/outofmemory.d delete mode 100644 tests/d1/testincludes/std/stdarg.d diff --git a/ldc.rebuild.conf.in b/ldc.rebuild.conf.in deleted file mode 100644 index 6b5031b5..00000000 --- a/ldc.rebuild.conf.in +++ /dev/null @@ -1,2 +0,0 @@ -[Environment] -DFLAGS=-I@RUNTIME_DIR@ -I@RUNTIME_DIR@/lib/common -L-L@CMAKE_INSTALL_LIBDIR@ -d-version=Tango -defaultlib=@RUNTIME_AIO@ -debuglib=@RUNTIME_AIO@ diff --git a/ldc_install.conf.in b/ldc_install.conf.in deleted file mode 100644 index b919273f..00000000 --- a/ldc_install.conf.in +++ /dev/null @@ -1,18 +0,0 @@ -// This configuration file uses libconfig. -// See http://www.hyperrealm.com/libconfig/ for syntax details. - -// The default group is required -default: -{ - // 'switches' holds array of string that are appends to the command line - // arguments before they are parsed. - switches = [ - "-I@INCLUDE_INSTALL_DIR@/@RUNTIME_AIO@", - "-I@INCLUDE_INSTALL_DIR@/@RUNTIME_AIO@/core/vendor", - "-I@INCLUDE_INSTALL_DIR@", - "-L-L@CMAKE_INSTALL_LIBDIR@", - "-d-version=Tango", - "-defaultlib=@RUNTIME_AIO@", - "-debuglib=@RUNTIME_AIO@" - ]; -}; diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 04d5bd95..f7a146c0 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -57,15 +57,6 @@ endif() get_directory_property(PROJECT_PARENT_DIR DIRECTORY ${PROJECT_SOURCE_DIR} PARENT_DIRECTORY) set(RUNTIME_DIR ${PROJECT_SOURCE_DIR}/druntime CACHE PATH "runtime source dir") -if(D_VERSION EQUAL 1) - set(RUNTIME_AIO tango) - configure_file(${PROJECT_PARENT_DIR}/${LDC_EXE}_install.conf.in ${PROJECT_BINARY_DIR}/../bin/${LDC_EXE}_install.conf) - configure_file(${PROJECT_PARENT_DIR}/${LDC_EXE}.rebuild.conf.in ${PROJECT_BINARY_DIR}/../bin/${LDC_EXE}_install.rebuild.conf) - - message(STATUS "Note: Tango is no longer included in D1 builds, please compile and install it separately using its own build infrastructure (bob).") - return() -endif() - # # Gather source files. # diff --git a/tests/d1/.gitignore b/tests/d1/.gitignore deleted file mode 100644 index de7fc2b0..00000000 --- a/tests/d1/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/dstress -/findregressions -/makewebstatistics -/*.o -/testincludes/*.a -/testincludes/*.o diff --git a/tests/d1/README b/tests/d1/README deleted file mode 100644 index d05d86df..00000000 --- a/tests/d1/README +++ /dev/null @@ -1,15 +0,0 @@ -We have two different test sets. For the test drivers -you need do compile the .d files in this folder with -a Phobos D compiler. - -To run the 'mini' test suite run -./runminitests - -To run the DStress based tests execute -./runtest tmp-sensible-name -and then use -./findregressions old-results new-results -to display a list of regressions. You can -download old result files from -http://www.incasoftware.de/~kamm/ldc/reference - diff --git a/tests/d1/findregressions.d b/tests/d1/findregressions.d deleted file mode 100644 index 04a81b99..00000000 --- a/tests/d1/findregressions.d +++ /dev/null @@ -1,367 +0,0 @@ -// Based on DSTRESS code by Thomas Kühne - -module findregressions; - -private import std.string; -private import std.conv; -private import std.stdio; -private import std.stream; -private import std.file; -private import std.c.stdlib; -private import std.date; - - -enum Result{ - UNTESTED = 0, - PASS = 1 << 2, - XFAIL = 2 << 2, - XPASS = 3 << 2, - FAIL = 4 << 2, - ERROR = 5 << 2, - BASE_MASK = 7 << 2, - - EXT_MASK = 3, - BAD_MSG = 1, - BAD_GDB = 2, - - MAX = BAD_GDB + BASE_MASK -} - -char[] toString(Result r){ - switch(r & Result.BASE_MASK){ - case Result.PASS: return "PASS"; - case Result.XPASS: return "XPASS"; - case Result.FAIL: return "FAIL"; - case Result.XFAIL: return "XFAIL"; - case Result.ERROR: return "ERROR"; - case Result.UNTESTED: return "UNTESTED"; - default: - break; - } - throw new Exception(format("unhandled Result value %s", cast(int)r)); -} - -char[] dateString(){ - static char[] date; - if(date is null){ - auto time = getUTCtime(); - auto year = YearFromTime(time); - auto month = MonthFromTime(time); - auto day = DateFromTime(time); - date = format("%d-%02d-%02d", year, month+1, day); - } - return date; -} - -char[][] unique(char[][] a){ - char[][] b = a.sort; - char[][] back; - - back ~= b[0]; - - size_t ii=0; - for(size_t i=0; i= start){ - end--; - } - - back = back[start .. end+1]; - - return back; -} - -class Test{ - char[] name; - char[] file; - Result r; - - this(char[] file){ - this.file = file; - - int start = rfind(file, "/"); - if(start<0){ - start = 0; - }else{ - start += 1; - } - - int end = rfind(file, "."); - if(end < start){ - end = file.length; - } - - name = file[start .. end]; - } -} - - -class Log{ - Test[char[]] tests; - - char[] id; - - this(char[] id){ - this.id = id; - } - - - void dropBogusResults(FStime recordTime, char[] testRoot){ - uint totalCount = tests.length; - - char[][] sourcesTests = tests.keys; - foreach(char[] source; sourcesTests){ - if(find(source, "complex/") < 0){ - try{ - FStime caseTime = getFStime(testRoot~std.path.sep~source); - if(caseTime > recordTime){ - debug(drop) fwritefln(stderr, "dropped: %s", source); - tests.remove(source); - } - }catch(Exception e){ - debug(drop) fwritefln(stderr, "dropped: %s", source); - tests.remove(source); - } - } - // asm-filter - int i = find(source, "asm_p"); - if(i >= 0){ - tests.remove(source); - } - } - tests.rehash; - - writefln("dropped %s outdated tests (%s remaining)", totalCount - tests.length, tests.length); - } - - - bool add(char[] line){ - const char[] SUB = "Torture-Sub-"; - const char[] TORTURE = "Torture:"; - - line = strip(line); - int id = -1; - Result r = Result.UNTESTED; - - if(line.length > SUB.length && line[0 .. SUB.length] == SUB){ - line = line[SUB.length .. $]; - id = 0; - while(line[id] >= '0' && line[id] <= '9'){ - id++; - } - int start = id; - id = std.conv.toUint(line[0 .. id]); - - while(line[start] != '-'){ - start++; - } - line = line[start+1 .. $]; - } - - char[][] token = split(line); - if(token.length < 2){ - return false; - } - char[] file = strip(token[1]); - - switch(token[0]){ - case "PASS:": - r = Result.PASS; break; - case "FAIL:": - r = Result.FAIL; break; - case "XPASS:": - r = Result.XPASS; break; - case "XFAIL:": - r = Result.XFAIL; break; - case "ERROR:": - r = Result.ERROR; break; - default:{ - if(token[0] == TORTURE){ - throw new Exception("not yet handled: "~line); - }else if(id > -1){ - throw new Exception(format("bug in SUB line: (%s) %s", id, line)); - } - } - } - - if(r != Result.UNTESTED){ - if(std.string.find(line, "bad error message") > -1){ - r |= Result.BAD_MSG; - } - if(std.string.find(line, "bad debugger message") > -1){ - r |= Result.BAD_MSG; - } - - file = cleanFileName(file); - - if(id >= 0){ - // update sub - id--; - - Test* test = file in tests; - - if(test is null){ - Test t = new Test(file); - tests[file] = t; - t.r = r; - }else{ - if(test.r != Result.UNTESTED){ - test.r = Result.UNTESTED; - } - test.r = r; - } - } - return true; - } - return false; - } -} - - -int main(char[][] args){ - - if(args.length < 2){ - fwritefln(stderr, "%s ", args[0]); - return 1; - } - - - Log[] logs; - - foreach(size_t id, char[] file; args[1 .. $]){ - writefln("parsing: %s", file); - FStime logTime = getFStime(file); - debug fwritefln(stderr, "sourceTime: %s", logTime); - - Log l= new Log(file); - Stream source = new BufferedFile(file, FileMode.In); - while(!source.eof()){ - l.add(source.readLine()); - } - - l.dropBogusResults(logTime, "dstress"); - - logs ~= l; - } - - Log oldLog = logs[0]; - Log newLog = logs[1]; - - foreach(Test t; newLog.tests.values){ - Test* oldT = t.file in oldLog.tests; - - if(oldT !is null){ - if(oldT.r == t.r) - continue; - else if(t.r >= Result.XPASS && oldT.r && oldT.r <= Result.XFAIL){ - writef("Regression "); - } - else if(t.r && t.r <= Result.XFAIL && oldT.r >= Result.XPASS){ - writef("Improvement "); - } - else { - writef("Change "); - } - writefln(toString(oldT.r), " -> ", toString(t.r), " : ", t.name, " in ", t.file); - } - } - - - return 0; -} - diff --git a/tests/d1/makewebstatistics.d b/tests/d1/makewebstatistics.d deleted file mode 100644 index 6c018760..00000000 --- a/tests/d1/makewebstatistics.d +++ /dev/null @@ -1,705 +0,0 @@ -// Based on DSTRESS code by Thomas Kühne - -module findregressions; - -private import std.string; -private import std.conv; -private import std.stdio; -private import std.stream; -private import std.file; -private import std.c.stdlib; -private import std.date; -private import std.path; - - -enum Result{ - UNTESTED = 0, - PASS = 1 << 2, - XFAIL = 2 << 2, - XPASS = 3 << 2, - FAIL = 4 << 2, - ERROR = 5 << 2, - BASE_MASK = 7 << 2, - - EXT_MASK = 3, - BAD_MSG = 1, - BAD_GDB = 2, - - MAX = BAD_GDB + BASE_MASK -} - -char[] toString(Result r){ - switch(r & Result.BASE_MASK){ - case Result.PASS: return "PASS"; - case Result.XPASS: return "XPASS"; - case Result.FAIL: return "FAIL"; - case Result.XFAIL: return "XFAIL"; - case Result.ERROR: return "ERROR"; - case Result.UNTESTED: return "UNTESTED"; - default: - break; - } - throw new Exception(format("unhandled Result value %s", cast(int)r)); -} - -char[] dateString(){ - static char[] date; - if(date is null){ - auto time = getUTCtime(); - auto year = YearFromTime(time); - auto month = MonthFromTime(time); - auto day = DateFromTime(time); - date = format("%d-%02d-%02d", year, month+1, day); - } - return date; -} - -char[][] unique(char[][] a){ - char[][] b = a.sort; - char[][] back; - - back ~= b[0]; - - size_t ii=0; - for(size_t i=0; i= start){ - end--; - } - - back = back[start .. end+1]; - - return back; -} - -class Test{ - char[] name; - char[] file; - Result r; - - this(char[] file){ - this.file = file; - - int start = rfind(file, "/"); - if(start<0){ - start = 0; - }else{ - start += 1; - } - - int end = rfind(file, "."); - if(end < start){ - end = file.length; - } - - name = file[start .. end]; - } -} - - -class Log{ - Test[char[]] tests; - - char[] id; - - int[Result] counts; - - this(char[] id, char[] file){ - this.id = id; - counts = [ - Result.PASS: 0, - Result.FAIL: 0, - Result.XPASS: 0, - Result.XFAIL: 0, - Result.ERROR: 0 ]; - - writefln("parsing: %s", file); - FStime logTime = getFStime(file); - Stream source = new BufferedFile(file, FileMode.In); - while(!source.eof()){ - add(source.readLine()); - } - dropBogusResults(logTime, "dstress"); - } - - - void dropBogusResults(FStime recordTime, char[] testRoot){ - uint totalCount = tests.length; - - char[][] sourcesTests = tests.keys; - foreach(char[] source; sourcesTests){ - if(find(source, "complex/") < 0){ - try{ - FStime caseTime = getFStime(testRoot~std.path.sep~source); - if(caseTime > recordTime){ - debug(drop) fwritefln(stderr, "dropped: %s", source); - counts[tests[source].r & Result.BASE_MASK]--; - tests.remove(source); - continue; - } - }catch(Exception e){ - debug(drop) fwritefln(stderr, "dropped: %s", source); - counts[tests[source].r & Result.BASE_MASK]--; - tests.remove(source); - continue; - } - } - // asm-filter - int i = find(source, "asm_p"); - if(i >= 0){ - counts[tests[source].r & Result.BASE_MASK]--; - tests.remove(source); - continue; - } - } - tests.rehash; - - writefln("dropped %s outdated tests (%s remaining)", totalCount - tests.length, tests.length); - } - - - bool add(char[] line){ - const char[] SUB = "Torture-Sub-"; - const char[] TORTURE = "Torture:"; - - line = strip(line); - int id = -1; - Result r = Result.UNTESTED; - - if(line.length > SUB.length && line[0 .. SUB.length] == SUB){ - line = line[SUB.length .. $]; - id = 0; - while(line[id] >= '0' && line[id] <= '9'){ - id++; - } - int start = id; - id = std.conv.toUint(line[0 .. id]); - - while(line[start] != '-'){ - start++; - } - line = line[start+1 .. $]; - } - - char[][] token = split(line); - if(token.length < 2){ - return false; - } - char[] file = strip(token[1]); - - switch(token[0]){ - case "PASS:": - r = Result.PASS; break; - case "FAIL:": - r = Result.FAIL; break; - case "XPASS:": - r = Result.XPASS; break; - case "XFAIL:": - r = Result.XFAIL; break; - case "ERROR:": - r = Result.ERROR; break; - default:{ - if(token[0] == TORTURE){ - throw new Exception("not yet handled: "~line); - }else if(id > -1){ - throw new Exception(format("bug in SUB line: (%s) %s", id, line)); - } - } - } - - if(r != Result.UNTESTED){ - if(std.string.find(line, "bad error message") > -1){ - r |= Result.BAD_MSG; - } - if(std.string.find(line, "bad debugger message") > -1){ - r |= Result.BAD_MSG; - } - - file = cleanFileName(file); - - if(id >= 0){ - // update sub - id--; - - Test* test = file in tests; - - if(test is null){ - Test t = new Test(file); - tests[file] = t; - t.r = r; - counts[r & Result.BASE_MASK]++; - }else{ - if(test.r != Result.UNTESTED){ - test.r = Result.UNTESTED; - } - test.r = r; - } - } - return true; - } - return false; - } -} - - -char[] basedir = "web"; -bool regenerate = false; - -int main(char[][] args){ - - if(args.length < 3 || (args[1] == "--regenerate" && args.length < 4)){ - fwritefln(stderr, "%s [--regenerate] ...", args[0]); - fwritefln(stderr, "bash example: %s reference/dmd-something $(ls reference/ldc*)", args[0]); - return 1; - } - - char[] reference; - char[][] files; - if(args[1] == "--regenerate") { - regenerate = true; - reference = args[2]; - files = args[3..$] ~ reference; - } else { - reference = args[1]; - files = args[2..$] ~ reference; - } - - // make sure base path exists - if(std.file.exists(basedir) && !std.file.isdir(basedir)) - throw new Exception(basedir ~ " is not a directory!"); - else if(!std.file.exists(basedir)) - std.file.mkdir(basedir); - - - Log[char[]] logs; - - // emit per-log data - foreach(char[] file; files) - generateLogStatistics(file, logs); - - // differences between logs - foreach(int i, char[] file; files[1 .. $]) - generateChangeStatistics(files[1+i], files[1+i-1], logs); - - // differences between reference and logs - foreach(char[] file; files[0..$-1]) - generateChangeStatistics(file, reference, logs); - - // collect all the stats.base files into a large table - BufferedFile index = new BufferedFile(std.path.join(basedir, "index.html"), FileMode.OutNew); - scope(exit) index.close(); - index.writefln(` - - - - DStress results for x86-32 Linux - - - - -

    DStress results for x86-32 Linux

    - -

    Legend

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ColorDescription
    PASSTest passed and was expected to pass
    XFAILTest failed and expected to fail
    FAILTest failed but was expected to pass
    XPASSTest passed but was expected to fail
    ERRORThe compiler, linker or the test segfaulted
    +Changes from FAIL, XPASS or ERROR to PASS or XFAIL
    -Changes from PASS or XFAIL to FAIL, XPASS or ERROR
    chgChanged within the good or bad group without crossing over
    - -

    Results

    - - - - - - - - - - - - - - - - - - - - - - `); - - for(int i = files.length - 1; i >= 0; --i) { - auto file = files[i]; - index.writefln(``); - char[] id = std.path.getBaseName(file); - char[] statsname = std.path.join(std.path.join(basedir, id), "stats.base"); - index.writef(cast(char[])std.file.read(statsname)); - - if(i != 0) { - char[] newid = std.path.getBaseName(files[i-1]); - statsname = std.path.join(std.path.join(basedir, newid ~ "-to-" ~ id), "stats.base"); - index.writef(cast(char[])std.file.read(statsname)); - } else { - index.writefln(``); - } - - if(i != files.length - 1) { - char[] refid = std.path.getBaseName(reference); - statsname = std.path.join(std.path.join(basedir, refid ~ "-to-" ~ id), "stats.base"); - index.writef(cast(char[])std.file.read(statsname)); - } else { - index.writefln(``); - } - - index.writefln(``); - } - - index.writefln(`
    Test resultsDiff to previousDiff to ` ~ std.path.getBaseName(reference) ~ `
    NamePASSXFAILFAILXPASSERROR+-chg+-chg
    `); - - return 0; -} - -void generateLogStatistics(char[] file, ref Log[char[]] logs) -{ - char[] id = std.path.getBaseName(file); - char[] dirname = std.path.join(basedir, id); - - if(std.file.exists(dirname)) { - if(std.file.isdir(dirname)) { - if(!regenerate) { - writefln("Directory ", dirname, " already exists, skipping..."); - return; - } - } - else - throw new Exception(dirname ~ " is not a directory!"); - } - else - std.file.mkdir(dirname); - - // parse etc. - Log log = new Log(id, file); - logs[id] = log; - - // write status - { - BufferedFile makeFile(char[] name) { - return new BufferedFile(std.path.join(dirname, name), FileMode.OutNew); - } - BufferedFile[Result] resultsfile = [ - Result.PASS: makeFile("pass.html"), - Result.FAIL: makeFile("fail.html"), - Result.XPASS: makeFile("xpass.html"), - Result.XFAIL: makeFile("xfail.html"), - Result.ERROR: makeFile("error.html") ]; - - scope(exit) { - foreach(file; resultsfile) - file.close(); - } - - foreach(file; resultsfile) - file.writefln(``); - - foreach(tkey; log.tests.keys.sort) { - auto test = log.tests[tkey]; - auto result = test.r & Result.BASE_MASK; - resultsfile[result].writefln(test.name, " in ", test.file, "
    "); - } - - foreach(file; resultsfile) - file.writefln(``); - } - - BufferedFile stats = new BufferedFile(std.path.join(dirname, "stats.base"), FileMode.OutNew); - scope(exit) stats.close(); - stats.writefln(``, id, ``); - stats.writefln(``, log.counts[Result.PASS], ``); - stats.writefln(``, log.counts[Result.XFAIL], ``); - stats.writefln(``, log.counts[Result.FAIL], ``); - stats.writefln(``, log.counts[Result.XPASS], ``); - stats.writefln(``, log.counts[Result.ERROR], ``); -} - -void generateChangeStatistics(char[] file1, char[] file2, ref Log[char[]] logs) -{ - char[] newid = std.path.getBaseName(file1); - char[] oldid = std.path.getBaseName(file2); - - char[] dirname = std.path.join(basedir, oldid ~ "-to-" ~ newid); - - if(std.file.exists(dirname)) { - if(std.file.isdir(dirname)) { - if(!regenerate) { - writefln("Directory ", dirname, " already exists, skipping..."); - return; - } - } - else - throw new Exception(dirname ~ " is not a directory!"); - } - else - std.file.mkdir(dirname); - - // parse etc. - Log newLog, oldLog; - Log getOrParse(char[] id, char[] file) { - if(id in logs) - return logs[id]; - else { - Log tmp = new Log(id, file); - logs[id] = tmp; - return tmp; - } - } - newLog = getOrParse(newid, file1); - oldLog = getOrParse(oldid, file2); - - int nRegressions, nImprovements, nChanges; - - { - auto regressionsFile = new BufferedFile(std.path.join(dirname, "regressions.html"), FileMode.OutNew); - scope(exit) regressionsFile.close(); - regressionsFile.writefln(``); - - auto improvementsFile = new BufferedFile(std.path.join(dirname, "improvements.html"), FileMode.OutNew); - scope(exit) improvementsFile.close(); - improvementsFile.writefln(``); - - auto changesFile = new BufferedFile(std.path.join(dirname, "changes.html"), FileMode.OutNew); - scope(exit) changesFile.close(); - changesFile.writefln(``); - - BufferedFile targetFile; - - foreach(file; newLog.tests.keys.sort){ - Test* t = file in newLog.tests; - Test* oldT = file in oldLog.tests; - - if(oldT !is null){ - if(oldT.r == t.r) - continue; - else if(t.r >= Result.XPASS && oldT.r && oldT.r <= Result.XFAIL){ - targetFile = regressionsFile; - nRegressions++; - } - else if(t.r && t.r <= Result.XFAIL && oldT.r >= Result.XPASS){ - targetFile = improvementsFile; - nImprovements++; - } - else { - targetFile = changesFile; - nChanges++; - } - targetFile.writefln(toString(oldT.r), " -> ", toString(t.r), " : ", t.name, " in ", t.file, "
    "); - } - } - - regressionsFile.writefln(``); - improvementsFile.writefln(``); - changesFile.writefln(``); - } - - BufferedFile stats = new BufferedFile(std.path.join(dirname, "stats.base"), FileMode.OutNew); - scope(exit) stats.close(); - auto dir = oldid ~ "-to-" ~ newid; - stats.writefln(``, nImprovements, ``); - stats.writefln(``, nRegressions, ``); - stats.writefln(``, nChanges, ``); -} diff --git a/tests/d1/minicomplex/arrays1.d b/tests/d1/minicomplex/arrays1.d deleted file mode 100644 index 82e97b2c..00000000 --- a/tests/d1/minicomplex/arrays1.d +++ /dev/null @@ -1,78 +0,0 @@ -module tangotests.arrays1; - -import tango.stdc.stdio; - -void main() -{ - real[] arr; - print(arr); - main2(); -} - -void main2() -{ - real[] arr = void; - fill(arr); - print(arr); - main3(); -} - -void main3() -{ -} - -void print(real[] arr) -{ - printf("len=%u ; ptr=%p\n", arr.length, arr.ptr); -} - -void fill(ref real[] arr) -{ - auto ptr = cast(void**)&arr; - *ptr++ = cast(void*)0xbeefc0de; - *ptr = cast(void*)0xbeefc0de; -} - -void dg1(void delegate(int[]) dg) -{ - dg2(dg); -} - -void dg2(void delegate(int[]) dg) -{ - dg(null); -} - -void sarr1(int[16] sa) -{ - sarr1(sa); -} - -struct Str -{ - size_t length; - char* ptr; -} - -void str1(Str str) -{ - str1(str); -} - -void str2(ref Str str) -{ - str2(str); -} - -void str3(out Str str) -{ - str3(str); -} - -void str4(Str* str) -{ - str4(str); -} - -void str5(Str); - diff --git a/tests/d1/minicomplex/constructors.d b/tests/d1/minicomplex/constructors.d deleted file mode 100644 index 4a55d6c7..00000000 --- a/tests/d1/minicomplex/constructors.d +++ /dev/null @@ -1,31 +0,0 @@ -module constructors; - -import tango.io.Console; - -class C -{ - this() - { - Cout("C()").newline; - } - this(char[] str) - { - Cout("C(")(str)(")").newline; - } -} - -class D : C -{ - this() - { - super("D"); - Cout("D()").newline; - } -} - -void main() -{ - auto c1 = new C(); - auto c2 = new C("C"); - auto d = new D(); -} diff --git a/tests/d1/minicomplex/files1.d b/tests/d1/minicomplex/files1.d deleted file mode 100644 index 3bc88df0..00000000 --- a/tests/d1/minicomplex/files1.d +++ /dev/null @@ -1,12 +0,0 @@ -module tangotests.files1; - -//import tango.io.Stdout; -import tango.io.File; - -void main() -{ - auto file = new File("files1.output"); - char[] str = "hello world from files1 test\n"; - void[] data = cast(void[])str; - file.write(str); -} diff --git a/tests/d1/minicomplex/gc2.d b/tests/d1/minicomplex/gc2.d deleted file mode 100644 index 057408b5..00000000 --- a/tests/d1/minicomplex/gc2.d +++ /dev/null @@ -1,9 +0,0 @@ -module tangotests.gc2; - -import tango.core.Memory; - -void main() -{ - char[] tmp = new char[2500]; - GC.collect(); -} diff --git a/tests/d1/minicomplex/ina1.d b/tests/d1/minicomplex/ina1.d deleted file mode 100644 index 483e882c..00000000 --- a/tests/d1/minicomplex/ina1.d +++ /dev/null @@ -1,11 +0,0 @@ -module tangotests.ina1; - -import tango.stdc.stdio; - -void main() -{ - int alder; - printf("Hvor gammel er du?\n"); - scanf("%d", &alder); - printf("om 10 år er du %d\n", alder + 10); -} diff --git a/tests/d1/minicomplex/l.d b/tests/d1/minicomplex/l.d deleted file mode 100644 index 5a54fddd..00000000 --- a/tests/d1/minicomplex/l.d +++ /dev/null @@ -1,6 +0,0 @@ -import tango.io.Console; - -void main() -{ - Cout("Hi, says LDC + Tango").newline; -} diff --git a/tests/d1/minicomplex/mem1.d b/tests/d1/minicomplex/mem1.d deleted file mode 100644 index c8b31d0a..00000000 --- a/tests/d1/minicomplex/mem1.d +++ /dev/null @@ -1,63 +0,0 @@ -module tangotests.mem1; - -import tango.stdc.stdio; - -void main() -{ - printf("new int;\n"); - int* i = new int; - assert(*i == 0); - - printf("new int[3];\n"); - int[] ar = new int[3]; - ar[0] = 1; - ar[1] = 56; - assert(ar.length == 3); - assert(ar[0] == 1); - assert(ar[1] == 56); - assert(ar[2] == 0); - - printf("array ~= elem;\n"); - int[] ar2; - ar2 ~= 22; - assert(ar2.length == 1); - assert(ar2[0] == 22); - - printf("array ~= array;\n"); - ar2 ~= ar; - assert(ar2.length == 4); - assert(ar2[0] == 22); - assert(ar2[1] == 1); - printf("%d %d %d %d\n", ar2[0], ar2[1], ar2[2], ar2[3]); - assert(ar2[2] == 56); - assert(ar2[3] == 0); - - printf("array ~ array;\n"); - int[] ar5 = ar ~ ar2; - assert(ar5.length == 7); - assert(ar5[0] == 1); - assert(ar5[1] == 56); - assert(ar5[2] == 0); - assert(ar5[3] == 22); - assert(ar5[4] == 1); - assert(ar5[5] == 56); - assert(ar5[6] == 0); - - printf("array ~ elem;\n"); - int[] ar4 = ar2 ~ 123; - assert(ar4.length == 5); - assert(ar4[0] == 22); - assert(ar4[1] == 1); - assert(ar4[2] == 56); - assert(ar4[3] == 0); - assert(ar4[4] == 123); - - printf("elem ~ array;\n"); - int[] ar3 = 123 ~ ar2; - assert(ar3.length == 5); - assert(ar3[0] == 123); - assert(ar3[1] == 22); - assert(ar3[2] == 1); - assert(ar3[3] == 56); - assert(ar3[4] == 0); -} diff --git a/tests/d1/minicomplex/mem4.d b/tests/d1/minicomplex/mem4.d deleted file mode 100644 index 1e395ab4..00000000 --- a/tests/d1/minicomplex/mem4.d +++ /dev/null @@ -1,29 +0,0 @@ -module tangotests.mem4; - -import tango.stdc.stdio; - -class C { - int* ptr; - this() { - printf("this()\n"); - ptr = new int; - } - ~this() { - printf("~this()\n"); - delete ptr; - assert(ptr is null); - } - final void check() - { - printf("check()\n"); - assert(ptr !is null); - } -} - -void main() -{ - C c = new C(); - c.check(); - delete c; - assert(c is null); -} \ No newline at end of file diff --git a/tests/d1/minicomplex/stdout1.d b/tests/d1/minicomplex/stdout1.d deleted file mode 100644 index a5bab25e..00000000 --- a/tests/d1/minicomplex/stdout1.d +++ /dev/null @@ -1,7 +0,0 @@ -import tango.io.Stdout; - -void main() -{ - Stdout("Hello World").newline; - Stdout.formatln("{} {}", "Hello", "World"); -} diff --git a/tests/d1/minicomplex/stdout2.d b/tests/d1/minicomplex/stdout2.d deleted file mode 100644 index 8c32e578..00000000 --- a/tests/d1/minicomplex/stdout2.d +++ /dev/null @@ -1,8 +0,0 @@ -module tangotests.stdout2; - -import tango.io.Stdout; - -void main() -{ - Stdout.formatln("{} {} {}", "a", "b", 1.0); -} diff --git a/tests/d1/minicomplex/templ1.d b/tests/d1/minicomplex/templ1.d deleted file mode 100644 index d394d99d..00000000 --- a/tests/d1/minicomplex/templ1.d +++ /dev/null @@ -1,13 +0,0 @@ -module tangotests.templ1; - -import Util = tango.text.Util; - -extern(C) int printf(char*, ...); - -void main() -{ - foreach (line; Util.lines("a\nb\nc")) - { - printf("%.*s\n", line.length, line.ptr); - } -} diff --git a/tests/d1/minicomplex/u.d b/tests/d1/minicomplex/u.d deleted file mode 100644 index 2068f362..00000000 --- a/tests/d1/minicomplex/u.d +++ /dev/null @@ -1,9 +0,0 @@ -import tango.io.Console; -void main() -{ - Cout("getting name std").newline; - Cerr("getting name err").newline; - auto s = Cin.get(); - Cout("putting name").newline; - Cout (s).newline; -} diff --git a/tests/d1/minicomplex/vararg1.d b/tests/d1/minicomplex/vararg1.d deleted file mode 100644 index 401020ce..00000000 --- a/tests/d1/minicomplex/vararg1.d +++ /dev/null @@ -1,13 +0,0 @@ -module tangotests.vararg1; - -import tango.stdc.stdio; - -void func(int[] arr...) -{ - printf("1,2,4,5,6 == %d,%d,%d,%d,%d\n", arr[0],arr[1],arr[2],arr[3],arr[4]); -} - -void main() -{ - func(1,2,4,5,6); -} diff --git a/tests/d1/minicomplex/vararg2.d b/tests/d1/minicomplex/vararg2.d deleted file mode 100644 index edfccc41..00000000 --- a/tests/d1/minicomplex/vararg2.d +++ /dev/null @@ -1,42 +0,0 @@ -module tangotests.vararg2; - -extern(C) int printf(char*, ...); - -import tango.core.Vararg; - -void main() -{ - func(0xf00, 1, " ", 2, " ", 3, "\n", 0.3, "\n"); -} - -void func(int foo, ...) -{ - foreach(t; _arguments) - { - if (t == typeid(char[])) - { - char[] str = va_arg!(char[])(_argptr); - printf("%.*s", str.length, str.ptr); - } - else if (t == typeid(int)) - { - printf("%d", va_arg!(int)(_argptr)); - } - else if (t == typeid(float)) - { - printf("%f", va_arg!(float)(_argptr)); - } - else if (t == typeid(double)) - { - printf("%f", va_arg!(double)(_argptr)); - } - else if (t == typeid(real)) - { - printf("%f", va_arg!(real)(_argptr)); - } - else - { - assert(0, "not int"); - } - } -} diff --git a/tests/d1/minicomplex/volatile1.d b/tests/d1/minicomplex/volatile1.d deleted file mode 100644 index 6eeaa94c..00000000 --- a/tests/d1/minicomplex/volatile1.d +++ /dev/null @@ -1,13 +0,0 @@ -module tangotests.volatile1; - -import tango.stdc.stdlib; - -void main() -{ - int var = rand(); - { - int i = var; - volatile; - int j = i; - } -} diff --git a/tests/d1/runminitest.d b/tests/d1/runminitest.d deleted file mode 100644 index d5ef2dcd..00000000 --- a/tests/d1/runminitest.d +++ /dev/null @@ -1,128 +0,0 @@ -module runminitest; - -import tango.sys.Environment, - tango.io.Stdout, - tango.io.vfs.FileFolder; -import Path = tango.io.Path; -import Util = tango.text.Util; -import tango.text.convert.Format; -import tango.stdc.stdlib, - tango.stdc.stringz; - -int main(char[][] args) -{ - enum : int - { - COMPILE, - NOCOMPILE, - RUN, - NORUN - } - - char[][] compilefailed; - char[][] nocompilefailed; - char[][] runfailed; - char[][] norunfailed; - - Environment.cwd("mini"); - - if (!Path.exists("obj")) - Path.createFolder("obj"); - - foreach(f; Path.children("./obj")) - { - Path.remove(f.path ~ f.name); - } - - static int classify(char[] name) - { - char[] tail; - char[] desc = Util.head(name, "_", tail); - if ("compile" == desc) - return COMPILE; - else if ("nocompile" == desc) - return NOCOMPILE; - else if ("run" == desc) - return RUN; - else if ("norun" == desc) - return NORUN; - return RUN; - } - - auto scan = new FileFolder ("."); - auto contents = scan.tree.catalog("*.d"); - foreach(c; contents) { - auto testname = Path.parse(c.name).name; - Stdout.formatln("TEST NAME: {}", testname); - - char[] cmd = Format.convert("ldc {} -quiet -L-s -ofobj/{}", c, testname); - foreach(v; args[1..$]) { - cmd ~= ' '; - cmd ~= v; - } - int cl = classify(testname); - if (cl == COMPILE || cl == NOCOMPILE) - cmd ~= " -c"; - Stdout(cmd).newline; - if (system(toStringz(cmd)) != 0) { - if (cl != NOCOMPILE) - compilefailed ~= c.toString; - } - else if (cl == RUN || cl == NORUN) { - if (system(toStringz(Path.native("obj/" ~ testname))) != 0) { - if (cl == RUN) - runfailed ~= c.toString; - } - else { - if (cl == NORUN) - norunfailed ~= c.toString; - } - } - else { - if (cl == NOCOMPILE) - nocompilefailed ~= c.toString; - } - } - - size_t nerrors = 0; - - if (compilefailed.length > 0) - { - Stdout.formatln("{}{}{}{}", compilefailed.length, '/', contents.files, " of the tests failed to compile:"); - foreach(b; compilefailed) { - Stdout.formatln(" {}",b); - } - nerrors += compilefailed.length; - } - - if (nocompilefailed.length > 0) - { - Stdout.formatln("{}{}{}{}", nocompilefailed.length, '/', contents.files, " of the tests failed to NOT compile:"); - foreach(b; nocompilefailed) { - Stdout.formatln(" {}",b); - } - nerrors += nocompilefailed.length; - } - - if (runfailed.length > 0) - { - Stdout.formatln("{}{}{}{}", runfailed.length, '/', contents.files, " of the tests failed to run:"); - foreach(b; runfailed) { - Stdout.formatln(" {}",b); - } - nerrors += runfailed.length; - } - - if (norunfailed.length > 0) - { - Stdout.formatln("{}{}{}{}", norunfailed.length, '/', contents.files, " of the tests failed to NOT run:"); - foreach(b; norunfailed) { - Stdout.formatln(" {}",b); - } - nerrors += norunfailed.length; - } - - Stdout.formatln("{}{}{}{}", contents.files - nerrors, '/', contents.files, " of the tests passed"); - - return nerrors ? 1 : 0; -} diff --git a/tests/d1/runtest b/tests/d1/runtest deleted file mode 100755 index dc4699ee..00000000 --- a/tests/d1/runtest +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/sh - -# check for command line arguments -if [ -z "$1" ] ; then - echo "Usage: `basename $0` " - exit -fi -TARGETFILE=$1 - -# build libtangobos-partial -echo "Building libtangobos-partial.a" -cd testincludes -make -cd .. - -# check for dstress -if ! [ -d dstress ] ; then - echo "Testing requires DStress to be checked out into dstress/" - exit -fi - -BASEPATH=`pwd` -cd dstress - -# remove excessive tests -sed -i -e 's/torture-//g' Makefile - -# make sure only .d files in 'run' tests are run -sed -i -e 's/find run -type f |/find run -type f -name "*\\\\.d" |/' Makefile -sed -i -e 's/find norun -type f |/find norun -type f -name "*\\\\.d" |/' Makefile - -# impose more conservative constraints (10s and 256 MB) -sed -i -e 's/crashRun 30 1000/crashRun 10 256/' dstress.c - -echo -echo "Running new test and storing result in $TARGETFILE ..." -echo -echo "Remember to make sure you have an up to date runtime!" -echo - -if [ -z "$DMD" ] ; then - echo "Testing with LDC. Set DMD environment variable to select compiler." - DMD="ldmd -I$BASEPATH/testincludes -L$BASEPATH/testincludes/libtangobos-partial.a" - echo "Default is $DMD" -else - echo "Using compiler given by DMD environment variable: $DMD" -fi - -echo -echo "This will take a while, try 'tail -f $TARGETFILE' to follow progress." -echo "Note that aborting is tricky. Try killing the processes by the name of" -echo "run.sh, compile.sh, nocompile.sh and norun.sh as well as this one." -echo - -DMD=$DMD make compile nocompile run norun > ../$TARGETFILE -cd .. - -echo -echo "Cleanup... (removing all .o and .exe files)" -echo - -find dstress -name "*\.o" -o -name "*\.exe" -delete diff --git a/tests/d1/testincludes/Makefile b/tests/d1/testincludes/Makefile deleted file mode 100644 index acb74df3..00000000 --- a/tests/d1/testincludes/Makefile +++ /dev/null @@ -1,51 +0,0 @@ -# Copied from tango runtime makefile. -# Designed to work with GNU make -# Targets: -# make -# Same as make all -# make lib -# Build the common library -# make doc -# Generate documentation -# make clean -# Delete unneeded files created by build process - -LIB_TARGET=libtangobos-partial.a -LIB_MASK=libtangobos-partial.* - -CP=cp -f -RM=rm -f -MD=mkdir -p - -ADD_CFLAGS= -ADD_DFLAGS= - -#CFLAGS=-O3 $(ADD_CFLAGS) -CFLAGS=-g $(ADD_CFLAGS) - -#DFLAGS=-release -O3 -inline -w $(ADD_DFLAGS) -DFLAGS=-g -w -noasm $(ADD_DFLAGS) - -DC=ldc - -targets : lib -all : lib -lib : tangobos.lib - -SOURCE= \ - std/gc.d \ - std/outofmemory.d \ - std/IEEE.d \ - std/stdarg.d \ -# std/asserterror.d \ -# std/format.d \ - -tangobos.lib : $(LIB_TARGET) - -$(LIB_TARGET) : $(ALL_OBJS) - $(DC) -lib -of$(LIB_TARGET) $(DFLAGS) $(SOURCE) - -clean : - $(RM) $(ALL_OBJS) - find . -name "$(LIB_MASK)" | xargs $(RM) - diff --git a/tests/d1/testincludes/object.di b/tests/d1/testincludes/object.di deleted file mode 100644 index 9b88ca1f..00000000 --- a/tests/d1/testincludes/object.di +++ /dev/null @@ -1,320 +0,0 @@ -// A copy of the object.di from Tango, with std.compat publically included to -// to make sure the Phobos compatibilty aliases are always available (DStress -// depends on Phobos). -module object; - -public import std.compat; - -/// unsigned integer type of the size of a pointer -alias typeof(int.sizeof) size_t; -/// signed integer type of the size of a pointer -alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t; - -/// type of hashes used in associative arrays -alias size_t hash_t; -/// type returned by equality comparisons -alias int equals_t; - -/// root class for all objects in D -class Object -{ - void dispose(); - /// returns a string representation of the object (for debugging purposes) - char[] toString(); - /// returns a hash - hash_t toHash(); - /// compares two objects, returns a number ret, such (a op b) is rewritten as (a.opCmp(b) op 0) - /// thus if a>b a.opCmp(b)>0 - int opCmp(Object o); - /// returns 0 if this==o - equals_t opEquals(Object o); - - interface Monitor - { - void lock(); - void unlock(); - } -} - -/// interface, if COM objects (IUnknown) they might not be casted to Object -struct Interface -{ - /// class info of the interface - ClassInfo classinfo; - void*[] vtbl; - /// offset to Interface 'this' from Object 'this' - ptrdiff_t offset; -} - -struct PointerMap -{ - // Conservative pointer mask (one word, scan it, we don't know if it's - // really a pointer) - size_t[] bits = [1, 1, 0]; - - size_t size(); - bool mustScanWordAt(size_t offset); - bool isPointerAt(size_t offset); - bool canUpdatePointers(); -} - -struct PointerMapBuilder -{ - private size_t[] m_bits = null; - private size_t m_size = 0; - - void size(size_t bytes); - void mustScanWordAt(size_t offset); - void inlineAt(size_t offset, PointerMap pm); - PointerMap convertToPointerMap(); -} - -/// class information -class ClassInfo : Object -{ - byte[] init; // class static initializer - char[] name; /// class name - void*[] vtbl; // virtual function pointer table - Interface[] interfaces; /// implemented interfaces - ClassInfo base; /// base class - void* destructor; /// compiler dependent storage of destructor function pointer - void* classInvariant; /// compiler dependent storage of classInvariant function pointer - /// flags - /// 1: IUnknown - /// 2: has no possible pointers into GC memory - /// 4: has offTi[] member - /// 8: has constructors - // 32: has typeinfo - uint flags; - void* deallocator; - OffsetTypeInfo[] offTi; /// offsets of its members (not supported by all compilers) - void* defaultConstructor; /// compiler dependent storage of constructor function pointer - /// TypeInfo information about this class - TypeInfo typeinfo; - version (D_HavePointerMap) { - PointerMap pointermap; - } - /// finds the classinfo of the class with the given name - static ClassInfo find(char[] classname); - /// creates an instance of this class (works only if there is a constructor without arguments) - Object create(); -} - -/// offset of the different fields (at the moment works only with ldc) -struct OffsetTypeInfo -{ - size_t offset; - TypeInfo ti; -} - -/// information on a type -class TypeInfo -{ - /// returns the hash of the type of this TypeInfo at p - hash_t getHash(void *p); - /// returns 0 if the types of this TypeInfo stored at p1 and p2 are different - equals_t equals(void *p1, void *p2); - /// compares the types of this TypeInfo stored at p1 and p2 - int compare(void *p1, void *p2); - /// Return alignment of type - size_t talign() { return tsize(); } - /// returns the size of a type with the current TypeInfo - size_t tsize(); - /// swaps the two types stored at p1 and p2 - void swap(void *p1, void *p2); - /// "next" TypeInfo (for an array its elements, for a pointer what it is pointed to,...) - TypeInfo next(); - void[] init(); - /// flags, 1: has possible pointers into GC memory - uint flags(); - PointerMap pointermap(); - /// offsets of the various elements - OffsetTypeInfo[] offTi(); - - /** Return internal info on arguments fitting into 8byte. - * See X86-64 ABI 3.2.3 - */ - version (X86_64) int argTypes(out TypeInfo arg1, out TypeInfo arg2); -} - -class TypeInfo_Typedef : TypeInfo -{ - TypeInfo base; - char[] name; - void[] m_init; -} - -class TypeInfo_Enum : TypeInfo_Typedef -{ -} - -class TypeInfo_Pointer : TypeInfo -{ - TypeInfo m_next; -} - -class TypeInfo_Array : TypeInfo -{ - /// typeinfo of the elements, might be null for basic arrays, it is safer to use next() - TypeInfo value; - - //ensure derived array TypeInfos use correct method - //if this declaration is forgotten, e.g. TypeInfo_Ai will have a wrong vtbl entry - PointerMap pointermap(); -} - -class TypeInfo_StaticArray : TypeInfo -{ - TypeInfo value; - size_t len; -} - -class TypeInfo_AssociativeArray : TypeInfo -{ - TypeInfo value; - TypeInfo key; -} - -class TypeInfo_Function : TypeInfo -{ - TypeInfo next; -} - -class TypeInfo_Delegate : TypeInfo -{ - TypeInfo next; -} - -class TypeInfo_Class : TypeInfo -{ - ClassInfo info; -} - -class TypeInfo_Interface : TypeInfo -{ - ClassInfo info; -} - -class TypeInfo_Struct : TypeInfo -{ - char[] name; - void[] m_init; - - hash_t function() xtoHash; - int function(void*) xopEquals; - int function(void*) xopCmp; - char[] function() xtoString; - - uint m_flags; - - version (D_HavePointerMap) { - PointerMap m_pointermap; - } -} - -class TypeInfo_Tuple : TypeInfo -{ - TypeInfo[] elements; -} - -/// information about a module (can be used for example to get its unittests) -class ModuleInfo -{ - /// name of the module - char[] name; - /// - ModuleInfo[] importedModules; - /// - ClassInfo[] localClasses; - uint flags; - - void function() ctor; - void function() dtor; - /// unit tests of the module - void function() unitTest; - - version(GNU){} - else{ - void* xgetMembers; - void function() ictor; - } - - /// loops on all the modules loaded - static int opApply( int delegate( ref ModuleInfo ) ); -} - -/// base class for all exceptions/errors -/// it is a good practice to pass line and file to the exception, which can be obtained with -/// __FILE__ and __LINE__, and then passed to the exception constructor -class Exception : Object -{ - /// Information about a frame in the stack - struct FrameInfo{ - /// line number in the source of the most likely start adress (0 if not available) - long line; - /// number of the stack frame (starting at 0 for the top frame) - ptrdiff_t iframe; - /// offset from baseSymb: within the function, or from the closest symbol - ptrdiff_t offsetSymb; - /// adress of the symbol in this execution - size_t baseSymb; - /// offset within the image (from this you can use better methods to get line number - /// a posteriory) - ptrdiff_t offsetImg; - /// base adress of the image (will be dependent on randomization schemes) - size_t baseImg; - /// adress of the function, or at which the ipc will return - /// (which most likely is the one after the adress where it started) - /// this is the raw adress returned by the backtracing function - size_t address; - /// file (image) of the current adress - char[] file; - /// name of the function, if possible demangled - char[] func; - /// extra information (for example calling arguments) - char[] extra; - /// if the address is exact or it is the return address - bool exactAddress; - /// if this function is an internal functions (for example the backtracing function itself) - /// if true by default the frame is not printed - bool internalFunction; - alias void function(FrameInfo*,void delegate(char[])) FramePrintHandler; - /// the default printing function - static FramePrintHandler defaultFramePrintingFunction; - /// writes out the current frame info - void writeOut(void delegate(char[])sink); - /// clears the frame information stored - void clear(); - } - /// trace information has the following interface - interface TraceInfo - { - int opApply( int delegate( ref FrameInfo fInfo) ); - void writeOut(void delegate(char[])sink); - } - /// message of the exception - char[] msg; - /// file name - char[] file; - /// line number - size_t line; // long would be better to be consistent - /// trace of where the exception was raised - TraceInfo info; - /// next exception (if an exception made an other exception raise) - Exception next; - - /// designated constructor (breakpoint this if you want to catch all explict Exception creations, - /// special exception just allocate and init the structure directly) - this(char[] msg, char[] file, long line, Exception next, TraceInfo info ); - this(char[] msg, Exception next=null); - this(char[] msg, char[] file, long line, Exception next = null); - /// returns the message of the exception, should not be used (because it should not allocate, - /// and thus only a small message is returned) - char[] toString(); - /// writes out the message of the exception, by default writes toString - /// override this is you have a better message for the exception - void writeOutMsg(void delegate(char[]) sink); - /// writes out the exception message, file, line number, stacktrace (if available) and any - /// subexceptions - void writeOut(void delegate(char[]) sink); -} diff --git a/tests/d1/testincludes/std/IEEE.d b/tests/d1/testincludes/std/IEEE.d deleted file mode 100644 index 96fb0c62..00000000 --- a/tests/d1/testincludes/std/IEEE.d +++ /dev/null @@ -1,136 +0,0 @@ -// Written in the D programming language -/* - * Authors: - * Walter Bright, Don Clugston - * Copyright: - * Copyright (c) 2001-2005 by Digital Mars, - * All Rights Reserved, - * www.digitalmars.com - * License: - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - *
      - *
    • The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - *
    • - *
    • Altered source versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - *
    • - *
    • This notice may not be removed or altered from any source - * distribution. - *
    • - *
    - */ -/* Cut down version for libtangobos-partial/dstress */ - -module tango.math.IEEE; - - -private: -/* - * The following IEEE 'real' formats are currently supported: - * 64 bit Big-endian 'double' (eg PowerPC) - * 128 bit Big-endian 'quadruple' (eg SPARC) - * 64 bit Little-endian 'double' (eg x86-SSE2) - * 80 bit Little-endian, with implied bit 'real80' (eg x87, Itanium). - * 128 bit Little-endian 'quadruple' (not implemented on any known processor!) - * - * Non-IEEE 128 bit Big-endian 'doubledouble' (eg PowerPC) has partial support - */ -version(LittleEndian) { - static assert(real.mant_dig == 53 || real.mant_dig==64 - || real.mant_dig == 113, - "Only 64-bit, 80-bit, and 128-bit reals" - " are supported for LittleEndian CPUs"); -} else { - static assert(real.mant_dig == 53 || real.mant_dig==106 - || real.mant_dig == 113, - "Only 64-bit and 128-bit reals are supported for BigEndian CPUs." - " double-double reals have partial support"); -} - -// Constants used for extracting the components of the representation. -// They supplement the built-in floating point properties. -template floatTraits(T) { - // EXPMASK is a ushort mask to select the exponent portion (without sign) - // POW2MANTDIG = pow(2, real.mant_dig) is the value such that - // (smallest_denormal)*POW2MANTDIG == real.min - // EXPPOS_SHORT is the index of the exponent when represented as a ushort array. - // SIGNPOS_BYTE is the index of the sign when represented as a ubyte array. - static if (T.mant_dig == 24) { // float - const ushort EXPMASK = 0x7F80; - const ushort EXPBIAS = 0x3F00; - const uint EXPMASK_INT = 0x7F80_0000; - const uint MANTISSAMASK_INT = 0x007F_FFFF; - const real POW2MANTDIG = 0x1p+24; - version(LittleEndian) { - const EXPPOS_SHORT = 1; - } else { - const EXPPOS_SHORT = 0; - } - } else static if (T.mant_dig == 53) { // double, or real==double - const ushort EXPMASK = 0x7FF0; - const ushort EXPBIAS = 0x3FE0; - const uint EXPMASK_INT = 0x7FF0_0000; - const uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only - const real POW2MANTDIG = 0x1p+53; - version(LittleEndian) { - const EXPPOS_SHORT = 3; - const SIGNPOS_BYTE = 7; - } else { - const EXPPOS_SHORT = 0; - const SIGNPOS_BYTE = 0; - } - } else static if (T.mant_dig == 64) { // real80 - const ushort EXPMASK = 0x7FFF; - const ushort EXPBIAS = 0x3FFE; - const real POW2MANTDIG = 0x1p+63; - version(LittleEndian) { - const EXPPOS_SHORT = 4; - const SIGNPOS_BYTE = 9; - } else { - const EXPPOS_SHORT = 0; - const SIGNPOS_BYTE = 0; - } - } else static if (real.mant_dig == 113){ // quadruple - const ushort EXPMASK = 0x7FFF; - const real POW2MANTDIG = 0x1p+113; - version(LittleEndian) { - const EXPPOS_SHORT = 7; - const SIGNPOS_BYTE = 15; - } else { - const EXPPOS_SHORT = 0; - const SIGNPOS_BYTE = 0; - } - } else static if (real.mant_dig == 106) { // doubledouble - const ushort EXPMASK = 0x7FF0; - const real POW2MANTDIG = 0x1p+53; // doubledouble denormals are strange - // and the exponent byte is not unique - version(LittleEndian) { - const EXPPOS_SHORT = 7; // [3] is also an exp short - const SIGNPOS_BYTE = 15; - } else { - const EXPPOS_SHORT = 0; // [4] is also an exp short - const SIGNPOS_BYTE = 0; - } - } -} - - -public: -/********************************* - * Return 1 if sign bit of e is set, 0 if not. - */ - -int signbit(real x) -{ - return ((cast(ubyte *)&x)[floatTraits!(real).SIGNPOS_BYTE] & 0x80) != 0; -} diff --git a/tests/d1/testincludes/std/compat.d b/tests/d1/testincludes/std/compat.d deleted file mode 100644 index d977473d..00000000 --- a/tests/d1/testincludes/std/compat.d +++ /dev/null @@ -1,10 +0,0 @@ -module std.compat; - -extern (C) int printf(char *, ...); - -alias char[] string; -alias wchar[] wstring; -alias dchar[] dstring; - -alias Exception Error; -alias bool bit; diff --git a/tests/d1/testincludes/std/gc.d b/tests/d1/testincludes/std/gc.d deleted file mode 100644 index fe690c43..00000000 --- a/tests/d1/testincludes/std/gc.d +++ /dev/null @@ -1,250 +0,0 @@ - -/* - * Copyright (C) 1999-2006 by Digital Mars, www.digitalmars.com - * Written by Walter Bright - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * o The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * o Altered source versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - * o This notice may not be removed or altered from any source - * distribution. - */ - - -/** - * The garbage collector normally works behind the scenes without needing any - * specific interaction. These functions are for advanced applications that - * benefit from tuning the operation of the collector. - * Macros: - * WIKI=Phobos/StdGc - */ - -module std.gc; - -import tango.core.Memory; - -/** - * Add p to list of roots. Roots are references to memory allocated by the - collector that are maintained in memory outside the collector pool. The garbage - collector will by default look for roots in the stacks of each thread, the - registers, and the default static data segment. If roots are held elsewhere, - use addRoot() or addRange() to tell the collector not to free the memory it - points to. - */ -void addRoot(void *p) // add p to list of roots -{ - GC.addRoot(p); -} - -/** - * Remove p from list of roots. - */ -void removeRoot(void *p) // remove p from list of roots -{ - GC.removeRoot(p); -} - -/** - * Add range to scan for roots. - */ -void addRange(void *pbot, void *ptop) // add range to scan for roots -{ - GC.addRange(pbot, ptop-pbot); -} - -/** - * Remove range. - */ -void removeRange(void *pbot) // remove range -{ - GC.removeRange(pbot); -} - -/** - * Mark a gc allocated block of memory as possibly containing pointers. - */ -void hasPointers(void* p) -{ - GC.clrAttr(p, GC.BlkAttr.NO_SCAN); -} - -/** - * Mark a gc allocated block of memory as definitely NOT containing pointers. - */ -void hasNoPointers(void* p) -{ - GC.setAttr(p, GC.BlkAttr.NO_SCAN); -} - -/** - * Mark a gc allocated block of memory pointed to by p as being populated with - * an array of TypeInfo ti (as many as will fit). - */ -//void setTypeInfo(TypeInfo ti, void* p); - -/** - * Allocate nbytes of uninitialized data. - * The allocated memory will be scanned for pointers during - * a gc collection cycle, unless - * it is followed by a call to hasNoPointers(). - */ -void[] malloc(size_t nbytes) -{ - void* p = GC.malloc(nbytes); - if (p is null) - return null; - else - return p[0..nbytes]; -} - -/** - * Resize allocated memory block pointed to by p to be at least nbytes long. - * It will try to resize the memory block in place. - * If nbytes is 0, the memory block is free'd. - * If p is null, the memory block is allocated using malloc. - * The returned array may not be at the same location as the original - * memory block. - * The allocated memory will be scanned for pointers during - * a gc collection cycle, unless - * it is followed by a call to hasNoPointers(). - */ -void[] realloc(void* p, size_t nbytes) -{ - p = GC.realloc(p, nbytes); - if (p is null) - return null; - else - return p[0..nbytes]; -} - -/** - * Attempt to enlarge the memory block pointed to by p - * by at least minbytes beyond its current capacity, - * up to a maximum of maxbytes. - * Returns: - * 0 if could not extend p, - * total size of entire memory block if successful. - */ -size_t extend(void* p, size_t minbytes, size_t maxbytes) -{ - return GC.extend(p, maxbytes, minbytes); -} - -/** - * Returns capacity (size of the memory block) that p - * points to the beginning of. - * If p does not point into the gc memory pool, or does - * not point to the beginning of an allocated memory block, - * 0 is returned. - */ -size_t capacity(void* p) -{ - return GC.sizeOf(p); -} - -/** - * Set gc behavior to match that of 1.0. - */ -void setV1_0() -{ -} - -/*********************************** - * Run a full garbage collection cycle. - * - * The collector normally runs synchronously with a storage allocation request - (i.e. it never happens when in code that does not allocate memory). In some - circumstances, for example when a particular task is finished, it is convenient - to explicitly run the collector and free up all memory used by that task. It - can also be helpful to run a collection before starting a new task that would - be annoying if it ran a collection in the middle of that task. Explicitly - running a collection can also be done in a separate very low priority thread, - so that if the program is idly waiting for input, memory can be cleaned up. - */ - -void fullCollect() -{ - GC.collect(); -} - -/*********************************** - * Run a generational garbage collection cycle. - * Takes less time than a fullcollect(), but isn't - * as effective. - */ - -void genCollect() -{ - GC.collect(); -} - -//void genCollectNoStack(); - -/** - * Minimizes physical memory usage - */ -void minimize() -{ - GC.collect(); -} - -/*************************************** - * disable() temporarily disables garbage collection cycle, enable() - * then reenables them. - * - * This is used for brief time critical sections of code, so the amount of time - * it will take is predictable. - * If the collector runs out of memory while it is disabled, it will throw an - * std.outofmemory.OutOfMemoryException. - * The disable() function calls can be nested, but must be - * matched with corresponding enable() calls. - * By default collections are enabled. - */ - -void disable() -{ - GC.disable(); -} - -/** - * ditto - */ -void enable() -{ - GC.enable(); -} - -//void getStats(out GCStats stats); - -/*************************************** - * Get handle to the collector. - */ - -//void* getGCHandle(); - -/*************************************** - * Set handle to the collector. - */ - -//void setGCHandle(void* p); - -//void endGCHandle(); - -/* -extern (C) -{ - void gc_init(); - void gc_term(); -} -*/ diff --git a/tests/d1/testincludes/std/outofmemory.d b/tests/d1/testincludes/std/outofmemory.d deleted file mode 100644 index c8339736..00000000 --- a/tests/d1/testincludes/std/outofmemory.d +++ /dev/null @@ -1,11 +0,0 @@ -module std.outofmemory; -import std.compat; - -public import tango.core.Exception; - -extern (C) void _d_OutOfMemory() -{ - throw cast(OutOfMemoryException) - cast(void *) - OutOfMemoryException.classinfo.init; -} diff --git a/tests/d1/testincludes/std/stdarg.d b/tests/d1/testincludes/std/stdarg.d deleted file mode 100644 index 2d2274dc..00000000 --- a/tests/d1/testincludes/std/stdarg.d +++ /dev/null @@ -1,30 +0,0 @@ - -/* - * Placed in public domain. - * Written by Hauke Duden and Walter Bright - */ - -/* This is for use with variable argument lists with extern(D) linkage. */ - -module std.stdarg; - -version(LDC) -{ - public import ldc.vararg; -} -else -{ - -alias void* va_list; - -template va_arg(T) -{ - T va_arg(inout va_list _argptr) - { - T arg = *cast(T*)_argptr; - _argptr = _argptr + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1)); - return arg; - } -} - -} From a3036220746fd92159bd46fe6bc77e099f8283df Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 7 Mar 2013 23:18:08 +0100 Subject: [PATCH 6/6] Allow casting AAs to void*. GitHub: Fixes #302. --- gen/llvmhelpers.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index e11f0dfa..8ad26c94 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -808,7 +808,20 @@ DValue* DtoCast(Loc& loc, DValue* val, Type* to) Type* totype = to->toBasetype(); if (fromtype->ty == Taarray) + { + // DMD allows casting AAs to void*, even if they are internally + // implemented as structs. + if (totype->ty == Tpointer) + { + IF_LOG Logger::println("Casting AA to pointer."); + LLValue *rval = DtoBitCast(val->getRVal(), DtoType(to)); + return new DImValue(to, rval); + } + + // Else try dealing with the rewritten (struct) type. fromtype = static_cast(fromtype)->getImpl()->type; + } + if (totype->ty == Taarray) totype = static_cast(totype)->getImpl()->type; @@ -821,8 +834,7 @@ DValue* DtoCast(Loc& loc, DValue* val, Type* to) if (fromtype->ty == Tvector) { return DtoCastVector(loc, val, to); } - else - if (fromtype->isintegral()) { + else if (fromtype->isintegral()) { return DtoCastInt(loc, val, to); } else if (fromtype->iscomplex()) {