Mercurial > projects > ldc
diff dmd2/dsymbol.c @ 758:f04dde6e882c
Added initial D2 support, D2 frontend and changes to codegen to make things compile.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 11 Nov 2008 01:38:48 +0100 |
parents | |
children | 356e65836fb5 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd2/dsymbol.c Tue Nov 11 01:38:48 2008 +0100 @@ -0,0 +1,1172 @@ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "mem.h" + +#include "mars.h" +#include "dsymbol.h" +#include "aggregate.h" +#include "identifier.h" +#include "module.h" +#include "mtype.h" +#include "expression.h" +#include "statement.h" +#include "declaration.h" +#include "id.h" +#include "scope.h" +#include "init.h" +#include "import.h" +#include "template.h" +#include "attrib.h" + +#include "../gen/enums.h" + +/****************************** Dsymbol ******************************/ + +Dsymbol::Dsymbol() +{ + //printf("Dsymbol::Dsymbol(%p)\n", this); + this->ident = NULL; + this->c_ident = NULL; + this->parent = NULL; + this->csym = NULL; + this->isym = NULL; + this->loc = 0; + this->comment = NULL; + + this->llvmInternal = LLVMnone; +} + +Dsymbol::Dsymbol(Identifier *ident) +{ + //printf("Dsymbol::Dsymbol(%p, ident)\n", this); + this->ident = ident; + this->c_ident = NULL; + this->parent = NULL; + this->csym = NULL; + this->isym = NULL; + this->loc = 0; + this->comment = NULL; + + this->llvmInternal = LLVMnone; +} + +int Dsymbol::equals(Object *o) +{ Dsymbol *s; + + if (this == o) + return TRUE; + s = (Dsymbol *)(o); + if (s && ident->equals(s->ident)) + return TRUE; + return FALSE; +} + +/************************************** + * Copy the syntax. + * Used for template instantiations. + * If s is NULL, allocate the new object, otherwise fill it in. + */ + +Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s) +{ + print(); + printf("%s %s\n", kind(), toChars()); + assert(0); + return NULL; +} + +/************************************** + * Determine if this symbol is only one. + * Returns: + * FALSE, *ps = NULL: There are 2 or more symbols + * TRUE, *ps = NULL: There are zero symbols + * TRUE, *ps = symbol: The one and only one symbol + */ + +int Dsymbol::oneMember(Dsymbol **ps) +{ + //printf("Dsymbol::oneMember()\n"); + *ps = this; + return TRUE; +} + +/***************************************** + * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. + */ + +int Dsymbol::oneMembers(Array *members, Dsymbol **ps) +{ + //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); + Dsymbol *s = NULL; + + if (members) + { + for (int i = 0; i < members->dim; i++) + { Dsymbol *sx = (Dsymbol *)members->data[i]; + + int x = sx->oneMember(ps); + //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); + if (!x) + { + //printf("\tfalse 1\n"); + assert(*ps == NULL); + return FALSE; + } + if (*ps) + { + if (s) // more than one symbol + { *ps = NULL; + //printf("\tfalse 2\n"); + return FALSE; + } + s = *ps; + } + } + } + *ps = s; // s is the one symbol, NULL if none + //printf("\ttrue\n"); + return TRUE; +} + +/***************************************** + * Is Dsymbol a variable that contains pointers? + */ + +int Dsymbol::hasPointers() +{ + //printf("Dsymbol::hasPointers() %s\n", toChars()); + return 0; +} + +char *Dsymbol::toChars() +{ + return ident ? ident->toChars() : (char *)"__anonymous"; +} + +char *Dsymbol::toPrettyChars() +{ Dsymbol *p; + char *s; + char *q; + size_t len; + + //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); + if (!parent) + return toChars(); + + len = 0; + for (p = this; p; p = p->parent) + len += strlen(p->toChars()) + 1; + + s = (char *)mem.malloc(len); + q = s + len - 1; + *q = 0; + for (p = this; p; p = p->parent) + { + char *t = p->toChars(); + len = strlen(t); + q -= len; + memcpy(q, t, len); + if (q == s) + break; + q--; + *q = '.'; + } + return s; +} + +char *Dsymbol::locToChars() +{ + OutBuffer buf; + char *p; + + Module *m = getModule(); + + if (m && m->srcfile) + loc.filename = m->srcfile->toChars(); + return loc.toChars(); +} + +const char *Dsymbol::kind() +{ + return "symbol"; +} + +/********************************* + * If this symbol is really an alias for another, + * return that other. + */ + +Dsymbol *Dsymbol::toAlias() +{ + return this; +} + +Dsymbol *Dsymbol::toParent() +{ + return parent ? parent->pastMixin() : NULL; +} + +Dsymbol *Dsymbol::pastMixin() +{ + Dsymbol *s = this; + + //printf("Dsymbol::pastMixin() %s\n", toChars()); + while (s && s->isTemplateMixin()) + s = s->parent; + return s; +} + +/********************************** + * Use this instead of toParent() when looking for the + * 'this' pointer of the enclosing function/class. + */ + +Dsymbol *Dsymbol::toParent2() +{ + Dsymbol *s = parent; + while (s && s->isTemplateInstance()) + s = s->parent; + return s; +} + +TemplateInstance *Dsymbol::inTemplateInstance() +{ + for (Dsymbol *parent = this->parent; parent; parent = parent->parent) + { + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + return ti; + } + return NULL; +} + +int Dsymbol::isAnonymous() +{ + return ident ? 0 : 1; +} + +void Dsymbol::semantic(Scope *sc) +{ + error("%p has no semantic routine", this); +} + +void Dsymbol::semantic2(Scope *sc) +{ + // Most Dsymbols have no further semantic analysis needed +} + +void Dsymbol::semantic3(Scope *sc) +{ + // Most Dsymbols have no further semantic analysis needed +} + +void Dsymbol::inlineScan() +{ + // Most Dsymbols have no further semantic analysis needed +} + +/********************************************* + * 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 identifier id as a member of 'this'. + * id may be a template instance. + * Returns: + * symbol found, NULL if not + */ + +Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) +{ + //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); + Dsymbol *s = toAlias(); + Dsymbol *sm; + + switch (id->dyncast()) + { + case DYNCAST_IDENTIFIER: + sm = s->search(loc, id, 0); + break; + + case DYNCAST_DSYMBOL: + { // It's a template instance + //printf("\ttemplate instance id\n"); + Dsymbol *st = (Dsymbol *)id; + TemplateInstance *ti = st->isTemplateInstance(); + id = ti->name; + sm = s->search(loc, id, 0); + if (!sm) + { error("template identifier %s is not a member of %s %s", + id->toChars(), s->kind(), s->toChars()); + return NULL; + } + sm = sm->toAlias(); + TemplateDeclaration *td = sm->isTemplateDeclaration(); + if (!td) + { + error("%s is not a template, it is a %s", id->toChars(), sm->kind()); + return NULL; + } + ti->tempdecl = td; + if (!ti->semanticdone) + ti->semantic(sc); + sm = ti->toAlias(); + break; + } + + default: + assert(0); + } + return sm; +} + +int Dsymbol::overloadInsert(Dsymbol *s) +{ + //printf("Dsymbol::overloadInsert('%s')\n", s->toChars()); + return FALSE; +} + +void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(toChars()); +} + +unsigned Dsymbol::size(Loc loc) +{ + error("Dsymbol '%s' has no size\n", toChars()); + return 0; +} + +int Dsymbol::isforwardRef() +{ + return FALSE; +} + +AggregateDeclaration *Dsymbol::isThis() +{ + return NULL; +} + +ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class? +{ + Dsymbol *parent = toParent(); + if (parent && parent->isClassDeclaration()) + return (ClassDeclaration *)parent; + return NULL; +} + +void Dsymbol::defineRef(Dsymbol *s) +{ + assert(0); +} + +int Dsymbol::isExport() +{ + return FALSE; +} + +int Dsymbol::isImportedSymbol() +{ + return FALSE; +} + +int Dsymbol::isDeprecated() +{ + return FALSE; +} + +int Dsymbol::isOverloadable() +{ + 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::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("Dsymbol::addMember('%s')\n", toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab); + parent = sd; + if (!isAnonymous()) // no name, so can't add it to symbol table + { + if (!sd->symtab->insert(this)) // if name is already defined + { + Dsymbol *s2; + + s2 = sd->symtab->lookup(ident); + if (!s2->overloadInsert(this)) + { + sd->multiplyDefined(0, this, s2); + } + } + if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) + { + if (ident == Id::__sizeof || ident == Id::alignof || ident == Id::mangleof) + error(".%s property cannot be redefined", ident->toChars()); + } + return 1; + } + return 0; +} + +void Dsymbol::error(const char *format, ...) +{ + //printf("Dsymbol::error()\n"); + if (!global.gag) + { + char *p = locToChars(); + + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + fprintf(stdmsg, "Error: "); + if (isAnonymous()) + fprintf(stdmsg, "%s ", kind()); + else + fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); + + va_list ap; + va_start(ap, format); + vfprintf(stdmsg, format, ap); + va_end(ap); + + fprintf(stdmsg, "\n"); + fflush(stdmsg); + } + global.errors++; + + //fatal(); +} + +void Dsymbol::error(Loc loc, const char *format, ...) +{ + if (!global.gag) + { + char *p = loc.toChars(); + if (!*p) + p = locToChars(); + + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + fprintf(stdmsg, "Error: "); + fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); + + va_list ap; + va_start(ap, format); + vfprintf(stdmsg, format, ap); + va_end(ap); + + fprintf(stdmsg, "\n"); + fflush(stdmsg); + } + + global.errors++; + + //fatal(); +} + +void Dsymbol::checkDeprecated(Loc loc, Scope *sc) +{ + if (!global.params.useDeprecated && isDeprecated()) + { + // Don't complain if we're inside a deprecated symbol's scope + for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) + { if (sp->isDeprecated()) + return; + } + + for (; sc; sc = sc->enclosing) + { + if (sc->scopesym && sc->scopesym->isDeprecated()) + return; + + // If inside a StorageClassDeclaration that is deprecated + if (sc->stc & STCdeprecated) + return; + } + + error(loc, "is deprecated"); + } +} + +/********************************** + * Determine which Module a Dsymbol is in. + */ + +Module *Dsymbol::getModule() +{ + Module *m; + Dsymbol *s; + + //printf("Dsymbol::getModule()\n"); + s = this; + while (s) + { + //printf("\ts = '%s'\n", s->toChars()); + m = s->isModule(); + if (m) + return m; + s = s->parent; + } + return NULL; +} + +/************************************* + */ + +enum PROT Dsymbol::prot() +{ + return PROTpublic; +} + +/************************************* + * Do syntax copy of an array of Dsymbol's. + */ + + +Array *Dsymbol::arraySyntaxCopy(Array *a) +{ + + Array *b = NULL; + if (a) + { + b = a->copy(); + for (int i = 0; i < b->dim; i++) + { + Dsymbol *s = (Dsymbol *)b->data[i]; + + s = s->syntaxCopy(NULL); + b->data[i] = (void *)s; + } + } + return b; +} + + +/**************************************** + * Add documentation comment to Dsymbol. + * Ignore NULL comments. + */ + +void Dsymbol::addComment(unsigned char *comment) +{ + //if (comment) + //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); + + if (!this->comment) + this->comment = comment; +#if 1 + else if (comment && strcmp((char *)comment, (char *)this->comment)) + { // Concatenate the two + this->comment = Lexer::combineComments(this->comment, comment); + } +#endif +} + +/********************************* OverloadSet ****************************/ + +OverloadSet::OverloadSet() + : Dsymbol() +{ +} + +void OverloadSet::push(Dsymbol *s) +{ + a.push(s); +} + +const char *OverloadSet::kind() +{ + return "overloadset"; +} + + +/********************************* 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); + + // Look in symbols declared in this module + Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; + + // hide private nonlocal symbols + if (flags & 1 && s && s->prot() == PROTprivate) + s = NULL; + + if (s) + { + //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); + } + else if (imports) + { + OverloadSet *a = NULL; + + // Look in imported modules + for (int i = 0; i < imports->dim; i++) + { ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i]; + Dsymbol *s2; + + // If private import, don't search it + if (flags & 1 && prots[i] == PROTprivate) + continue; + + //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); + /* Don't find private members if ss is a module + */ + s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); + if (!s) + s = s2; + else if (s2 && s != s2) + { + if (s->toAlias() == s2->toAlias()) + { + /* After following aliases, we found the same symbol, + * so it's not an ambiguity. + * But if one alias is deprecated, 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)) + ) + ) + ) + { + /* If both s2 and s are overloadable (though we only + * need to check s once) + */ + if (s2->isOverloadable() && (a || s->isOverloadable())) + { if (!a) + a = new OverloadSet(); + /* Don't add to a[] if s2 is alias of previous sym + */ + for (int j = 0; j < a->a.dim; j++) + { Dsymbol *s3 = (Dsymbol *)a->a.data[j]; + if (s2->toAlias() == s3->toAlias()) + { + if (s3->isDeprecated()) + a->a.data[j] = (void *)s2; + goto Lcontinue; + } + } + a->push(s2); + Lcontinue: + continue; + } + if (flags & 4) // if return NULL on ambiguity + return NULL; + if (!(flags & 2)) + ss->multiplyDefined(loc, s, s2); + break; + } + } + } + } + + /* Build special symbol if we had multiple finds + */ + if (a) + { assert(s); + a->push(s); + s = a; + } + + if (s) + { + Declaration *d = s->isDeclaration(); + if (d && d->protection == PROTprivate && + !d->parent->isTemplateMixin() && + !(flags & 2)) + error("%s is private", d->toPrettyChars()); + } + } + return s; +} + +void ScopeDsymbol::importScope(ScopeDsymbol *s, enum PROT protection) +{ + //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); + + // No circular or redundant import's + if (s != this) + { + if (!imports) + imports = new Array(); + else + { + for (int i = 0; i < imports->dim; i++) + { ScopeDsymbol *ss; + + ss = (ScopeDsymbol *) imports->data[i]; + if (ss == s) + { + if (protection > prots[i]) + prots[i] = protection; // upgrade access + return; + } + } + } + imports->push(s); + prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0])); + prots[imports->dim - 1] = protection; + } +} + +int ScopeDsymbol::isforwardRef() +{ + return (members == NULL); +} + +void ScopeDsymbol::defineRef(Dsymbol *s) +{ + ScopeDsymbol *ss; + + ss = s->isScopeDsymbol(); + members = ss->members; + ss->members = NULL; +} + +void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2) +{ +#if 0 + printf("ScopeDsymbol::multiplyDefined()\n"); + printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1->toChars(), s1->kind(), s1->parent ? s1->parent->toChars() : ""); + printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : ""); +#endif + if (loc.filename) + { ::error(loc, "%s at %s conflicts with %s at %s", + s1->toPrettyChars(), + s1->locToChars(), + s2->toPrettyChars(), + s2->locToChars()); + } + else + { + s1->error(loc, "conflicts with %s %s at %s", + s2->kind(), + s2->toPrettyChars(), + s2->locToChars()); + } +halt(); +} + +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"; +} + + +/*************************************** + * Determine number of Dsymbols, folding in AttribDeclaration members. + */ + +size_t ScopeDsymbol::dim(Array *members) +{ + size_t n = 0; + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + AttribDeclaration *a = s->isAttribDeclaration(); + + if (a) + { + n += dim(a->decl); + } + else + n++; + } + } + return n; +} + +/*************************************** + * Get nth Dsymbol, folding in AttribDeclaration members. + * Returns: + * Dsymbol* nth Dsymbol + * NULL not found, *pn gets incremented by the number + * of Dsymbols + */ + +Dsymbol *ScopeDsymbol::getNth(Array *members, size_t nth, size_t *pn) +{ + if (!members) + return NULL; + + size_t n = 0; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + AttribDeclaration *a = s->isAttribDeclaration(); + + if (a) + { + s = getNth(a->decl, nth - n, &n); + if (s) + return s; + } + else if (n == nth) + return s; + else + n++; + } + + if (pn) + *pn += n; + return NULL; +} + +/******************************************* + * 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; + Arguments *arguments = new Arguments; + Arguments *arg = new Argument(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL); + arguments->push(arg); + + Type *tret = NULL; + tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd); + tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc); + } + if (fdx) + fdx = fdx->overloadExactMatch(tfgetmembers); +#endif + if (fdx && fdx->isVirtual()) + fdx = NULL; + + return fdx; +} +#endif + + +/****************************** WithScopeSymbol ******************************/ + +WithScopeSymbol::WithScopeSymbol(WithStatement *withstate) + : ScopeDsymbol() +{ + this->withstate = withstate; +} + +Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags) +{ + // Acts as proxy to the with class declaration + return withstate->exp->type->toDsymbol(NULL)->search(loc, ident, 0); +} + +/****************************** ArrayScopeSymbol ******************************/ + +ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e) + : ScopeDsymbol() +{ + assert(e->op == TOKindex || e->op == TOKslice); + exp = e; + type = NULL; + td = NULL; + this->sc = sc; +} + +ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t) + : ScopeDsymbol() +{ + exp = NULL; + type = t; + td = NULL; + this->sc = sc; +} + +ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s) + : ScopeDsymbol() +{ + exp = NULL; + type = NULL; + td = s; + this->sc = sc; +} + +Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) +{ + //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); + if (ident == Id::length || ident == Id::dollar) + { VarDeclaration **pvar; + Expression *ce; + + L1: + + if (td) + { + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + v->semantic(sc); + return v; + } + + if (type) + { + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + v->semantic(sc); + return v; + } + + if (exp->op == TOKindex) + { + IndexExp *ie = (IndexExp *)exp; + + pvar = &ie->lengthVar; + ce = ie->e1; + } + else if (exp->op == TOKslice) + { + SliceExp *se = (SliceExp *)exp; + + pvar = &se->lengthVar; + ce = se->e1; + } + else + return NULL; + + if (ce->op == TOKtype) + { + Type *t = ((TypeExp *)ce)->type; + if (t->ty == Ttuple) + { type = (TypeTuple *)t; + goto L1; + } + } + + if (!*pvar) + { + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + + if (ce->op == TOKvar) + { // if ce is const, get its initializer + ce = fromConstInitializer(WANTvalue | WANTinterpret, ce); + } + + if (ce->op == TOKstring) + { /* It is for a string literal, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((StringExp *)ce)->len, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + } + else if (ce->op == TOKarrayliteral) + { /* It is for an array literal, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((ArrayLiteralExp *)ce)->elements->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + } + else if (ce->op == TOKtuple) + { /* It is for an expression tuple, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + } + *pvar = v; + } + (*pvar)->semantic(sc); + return (*pvar); + } + return NULL; +} + + +/****************************** DsymbolTable ******************************/ + +DsymbolTable::DsymbolTable() +{ + tab = new StringTable; +} + +DsymbolTable::~DsymbolTable() +{ + delete tab; +} + +Dsymbol *DsymbolTable::lookup(Identifier *ident) +{ StringValue *sv; + +#ifdef DEBUG + assert(ident); + assert(tab); +#endif + sv = tab->lookup((char*)ident->string, ident->len); + return (Dsymbol *)(sv ? sv->ptrvalue : NULL); +} + +Dsymbol *DsymbolTable::insert(Dsymbol *s) +{ StringValue *sv; + Identifier *ident; + + //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); + ident = s->ident; +#ifdef DEBUG + assert(ident); + assert(tab); +#endif + sv = tab->insert(ident->toChars(), ident->len); + if (!sv) + return NULL; // already in table + sv->ptrvalue = s; + return s; +} + +Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) +{ StringValue *sv; + + //printf("DsymbolTable::insert()\n"); + sv = tab->insert(ident->toChars(), ident->len); + if (!sv) + return NULL; // already in table + sv->ptrvalue = s; + return s; +} + +Dsymbol *DsymbolTable::update(Dsymbol *s) +{ StringValue *sv; + Identifier *ident; + + ident = s->ident; + sv = tab->update(ident->toChars(), ident->len); + sv->ptrvalue = s; + return s; +} + + + +