view dmd/Dsymbol.d @ 56:51605de93870

TupleExp.optimize UnrolledLoopStatement.ctor UnrolledLoopStatement.semantic UnrolledLoopStatement.blockExit OrOrExp.checkSideEffect FuncExp.syntaxCopy FuncLiteralDeclaration.syntaxCopy WhileStatement.hasBreak StructInitializer.toExpression StructLiteralExp.ctor StructLiteralExp.optimize BinExp.commonSemanticAssign ModAssignExp.opId Argument.isLazyArray CommaExp.implicitConvTo CommaExp.castTo TypeClass.isBaseOf createTypeInfoArray TypeTuple.getTypeInfoDeclaration TypeInfoTupleDeclaration.ctor TypeNext.constConv XorExp.implicitConvTo TemplateParameter.isTemplateValueParameter
author korDen
date Sat, 21 Aug 2010 14:16:53 +0400
parents adf6f7f216ea
children ecf732dfe11e
line wrap: on
line source

module dmd.Dsymbol;

import dmd.Loc;
import dmd.STC;
import dmd.Scope;
import dmd.Lexer;
import dmd.Module;
import dmd.Array;
import dmd.ScopeDsymbol;
import dmd.OutBuffer;
import dmd.Id;
import dmd.Identifier;
import dmd.TemplateInstance;
import dmd.HdrGenState;
import dmd.AggregateDeclaration;
import dmd.ClassDeclaration;
import dmd.LabelDsymbol;
import dmd.Type;
import dmd.PROT;
import dmd.ArrayTypes;
import dmd.Package;
import dmd.EnumMember;
import dmd.TemplateDeclaration;
import dmd.TemplateMixin;
import dmd.Declaration;
import dmd.ThisDeclaration;
import dmd.TupleDeclaration;
import dmd.TypedefDeclaration;
import dmd.AliasDeclaration;
import dmd.FuncDeclaration;
import dmd.FuncAliasDeclaration;
import dmd.FuncLiteralDeclaration;
import dmd.CtorDeclaration;
import dmd.PostBlitDeclaration;
import dmd.DtorDeclaration;
import dmd.StaticCtorDeclaration;
import dmd.StaticDtorDeclaration;
import dmd.InvariantDeclaration;
import dmd.UnitTestDeclaration;
import dmd.NewDeclaration;
import dmd.VarDeclaration;
import dmd.StructDeclaration;
import dmd.UnionDeclaration;
import dmd.InterfaceDeclaration;
import dmd.WithScopeSymbol;
import dmd.ArrayScopeSymbol;
import dmd.Import;
import dmd.EnumDeclaration;
import dmd.DeleteDeclaration;
import dmd.SymbolDeclaration;
import dmd.AttribDeclaration;
import dmd.OverloadSet;
import dmd.DYNCAST;
import dmd.Global;
import dmd.Expression;
import dmd.TOK;
import dmd.VarExp;
import dmd.FuncExp;

import dmd.backend.Symbol;
import dmd.backend.TYPE;
import dmd.backend.Util;
import dmd.backend.mTYman;
import dmd.backend.TYFL;
import dmd.backend.TYM;
import dmd.backend.mTY;
import dmd.backend.SC;
import dmd.backend.FL;
import dmd.backend.LIST;

import core.stdc.string : strcmp, memcpy, strlen;
version (Bug4054) import core.memory;
else import core.stdc.stdlib : alloca;

import std.stdio;

// TODO: remove dependencies on these
Expression isExpression(Object o)
{
    return cast(Expression)o;
}

Dsymbol isDsymbol(Object o)
{
    return cast(Dsymbol)o;
}

Type isType(Object o)
{
    return cast(Type)o;
}

/***********************
 * 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 == TOK.TOKvar)
			sa = (cast(VarExp)ea).var;
		else if (ea.op == TOK.TOKfunction)
			sa = (cast(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;
}

class Dsymbol
{
    Identifier ident;
    Identifier c_ident;
    Dsymbol parent;
    Symbol* csym;		// symbol for code generator
    Symbol* isym;		// import version of csym
    ubyte* comment;	// documentation comment for this Dsymbol
    Loc loc;			// where defined
    Scope scope_;		// !=null means context to use for semantic()

    this()
	{
		// do nothing
	}
	
    this(Identifier ident)
	{
		this.ident = ident;
	}

    string toChars()
	{
		return ident ? ident.toChars() : "__anonymous";
	}

    string locToChars()
	{
		scope OutBuffer buf = new OutBuffer();
		Module m = getModule();

		if (m && m.srcfile)
			loc.filename = m.srcfile.toChars();

		return loc.toChars();
	}

    bool equals(Object o)
	{
		assert(false);
	}

    bool isAnonymous()
	{
		return ident ? 0 : 1;
	}

    void error(T...)(Loc loc, string format, T t)
	{
		if (!global.gag)
		{
			string p = loc.toChars();
			if (p.length == 0)
				p = locToChars();

			if (p.length != 0) {
				writef("%s: ", p);
			}

			write("Error: ");
			writef("%s %s ", kind(), toPrettyChars());

			writefln(format, t);
		}

		global.errors++;
		
		//fatal();
	}

    void error(T...)(string format, T t)
	{
		//printf("Dsymbol.error()\n");
		if (!global.gag)
		{
			string p = loc.toChars();

			if (p.length != 0) {
				writef("%s: ", p);
			}

			write("Error: ");
			if (isAnonymous()) {
				writef("%s ", kind());
			} else {
				writef("%s %s ", kind(), toPrettyChars());
			}

			writefln(format, t);
		}
		global.errors++;

		//fatal();
	}

    void 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 & STC.STCdeprecated)
					return;
			}

			error(loc, "is deprecated");
		}
	}
	
    Module getModule()
	{
		//printf("Dsymbol.getModule()\n");
		Dsymbol s = this;
		while (s)
		{
			//printf("\ts = '%s'\n", s.toChars());
			Module m = s.isModule();
			if (m)
				return m;
			s = s.parent;
		}

		return null;
	}
	
    Dsymbol pastMixin()
	{
		 Dsymbol s = this;
		//printf("Dsymbol::pastMixin() %s\n", toChars());
		while (s && s.isTemplateMixin())
			s = s.parent;
		return s;
	}
	
    Dsymbol toParent()
	{
		return parent ? parent.pastMixin() : null;
	}

	/**********************************
	 * Use this instead of toParent() when looking for the
	 * 'this' pointer of the enclosing function/class.
	 */
    Dsymbol toParent2()
	{
		Dsymbol s = parent;
		while (s && s.isTemplateInstance())
			s = s.parent;
		return s;
	}
	
    TemplateInstance inTemplateInstance()
	{
		for (Dsymbol parent = this.parent; parent; parent = parent.parent)
		{
			TemplateInstance ti = parent.isTemplateInstance();
			if (ti)
				return ti;
		}

		return null;
	}

    DYNCAST dyncast() { return DYNCAST.DYNCAST_DSYMBOL; }	// kludge for template.isSymbol()

	/*************************************
	 * Do syntax copy of an array of Dsymbol's.
	 */
    static Array arraySyntaxCopy(Array a)
	{
		Array b = null;
		if (a)
		{
			b = a.copy();
			for (int i = 0; i < b.dim; i++)
			{
				Dsymbol s = cast(Dsymbol)b.data[i];

				s = s.syntaxCopy(null);
				b.data[i] = cast(void*)s;
			}
		}
		return b;
	}

    string toPrettyChars()
	{
		//printf("Dsymbol.toPrettyChars() '%s'\n", toChars());
		if (!parent) {
			return toChars();
		}

		size_t len = 0;
		for (Dsymbol p = this; p; p = p.parent) {
			len += p.toChars().length + 1;
		}
		--len;

version (Bug4054)
		char* s = cast(char*)GC.malloc(len);
else
		char* s = cast(char*)alloca(len);
		char* q = s + len;

		for (Dsymbol p = this; p; p = p.parent)
		{
			string t = p.toChars();
			size_t length = t.length;
			q -= length;

			memcpy(q, t.ptr, length);
			if (q is s)
				break;
			
			q--;
	version (TARGET_NET) {
			if (AggregateDeclaration ad = p.isAggregateDeclaration())
			{
				if (ad.isNested() && p.parent && p.parent.isAggregateDeclaration())
				{
					*q = '/';
					continue;
				}
			}
	}
			*q = '.';
		}

		return s[0..len].idup;
	}
	
    string kind()
	{
		assert(false);
	}
	
	/*********************************
	 * If this symbol is really an alias for another,
	 * return that other.
	 */
    Dsymbol toAlias()			// resolve real symbol
	{
		return this;
	}
	
    bool addMember(Scope sc, ScopeDsymbol sd, bool memnum)
	{
		//printf("Dsymbol.addMember('%s')\n", toChars());
		//printf("Dsymbol.addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd.toChars());
		assert(sd !is null);
		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 = sd.symtab.lookup(ident);
				if (!s2.overloadInsert(this))
				{
					sd.multiplyDefined(Loc(0), this, s2);
				}
			}
			if (sd.isAggregateDeclaration() || sd.isEnumDeclaration())
			{
				if (ident is Id.__sizeof || ident is Id.alignof_ || ident is Id.mangleof_)
					error(".%s property cannot be redefined", ident.toChars());
			}
			return true;
		}

		return false;
	}
	
    void 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 semantic(Scope sc)
	{
		assert(false);
	}
	
	/*************************************
	 * Does semantic analysis on initializers and members of aggregates.
	 */
    void semantic2(Scope sc)
	{
		// Most Dsymbols have no further semantic analysis needed
	}

	/*************************************
	 * Does semantic analysis on function bodies.
	 */	
    void semantic3(Scope sc)
	{
		// Most Dsymbols have no further semantic analysis needed
	}
	
	/*************************************
	 * Look for function inlining possibilities.
	 */
    void 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 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 searchX(Loc loc, Scope sc, Object o)
	{
		//printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
		Dsymbol s = toAlias();
		Dsymbol sm;

		if (auto ident = cast(Identifier)o)
		{
			sm = s.search(loc, ident, 0);
		}
		else if (auto st = cast(Dsymbol)o)
		{
			// It's a template instance
			//printf("\ttemplate instance id\n");
			TemplateInstance ti = st.isTemplateInstance();
			Identifier id = ti.name;
			sm = s.search(loc, cast(Identifier)id, 0);
			if (!sm)
			{   
				error("template identifier %s is not a member of %s %s", id.toChars(), s.kind(), s.toChars());
				return null;
			}
			sm = sm.toAlias();
			TemplateDeclaration td = sm.isTemplateDeclaration();
			if (!td)
			{
				error("%s is not a template, it is a %s", id.toChars(), sm.kind());
				return null;
			}

			ti.tempdecl = td;
			if (!ti.semanticRun)
				ti.semantic(sc);

			sm = ti.toAlias();
		}
		else
		{
			assert(0);
		}
		return sm;
	}
	
    bool overloadInsert(Dsymbol s)
	{
		assert(false);
	}
	
version (_DH) {
    char* toHChars()
	{
		assert(false);
	}
	
    void toHBuffer(OutBuffer buf, HdrGenState* hgs)
	{
		assert(false);
	}
}
    void toCBuffer(OutBuffer buf, HdrGenState* hgs)
	{
		assert(false);
	}
	
    void toDocBuffer(OutBuffer buf)
	{
		assert(false);
	}
	
    uint size(Loc loc)
	{
		assert(false);
	}

    int isforwardRef()
	{
		assert(false);
	}
	
    void defineRef(Dsymbol s)
	{
		assert(false);
	}
	
    AggregateDeclaration isThis()	// is a 'this' required to access the member
	{
		assert(false);
	}
	
    ClassDeclaration isClassMember()	// are we a member of a class?
	{
		Dsymbol parent = toParent();
		if (parent && parent.isClassDeclaration())
			return cast(ClassDeclaration)parent;
		return null;
	}
	
    bool isExport()			// is Dsymbol exported?
	{
		return false;
	}
	
    bool isImportedSymbol()		// is Dsymbol imported?
	{
		return false;
	}
	
    bool isDeprecated()			// is Dsymbol deprecated?
	{
		return false;
	}

version (DMDV2) {
    bool isOverloadable()
	{
		return false;
	}
}

    LabelDsymbol isLabel()		// is this a LabelDsymbol?
	{
		return null;
	}
	
    AggregateDeclaration isMember()	// is this symbol 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 getType()			// is this a type?
	{
		return null;
	}
	
    string mangle()
	{
		OutBuffer buf = new OutBuffer();
		string id;

static if (false) {
		printf("Dsymbol::mangle() '%s'", toChars());
		if (parent)
			printf("  parent = %s %s", parent.kind(), parent.toChars());
		printf("\n");
}
		id = ident ? ident.toChars() : toChars();
		if (parent)
		{
			string p = parent.mangle();
			if (p[0] == '_' && p[1] == 'D')
				p =  p[2..$];
			buf.writestring(p);
		}
		///buf.printf("%zu%s", id.length, id);
		buf.printf("%d%s", id.length, id);
		id = buf.toChars();
		buf.data = null;
		//printf("Dsymbol::mangle() %s = %s\n", toChars(), id);
		return id;
	}

    bool needThis()			// need a 'this' pointer?
	{
		return false;
	}

    PROT prot()
	{
		assert(false);
	}

    Dsymbol syntaxCopy(Dsymbol s)	// copy only syntax trees
	{
		assert(false);
	}

	/**************************************
	 * 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
	 */
    bool oneMember(Dsymbol* ps)
	{
		//printf("Dsymbol::oneMember()\n");
		*ps = this;
		return true;
	}

	/*****************************************
	 * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
	 */
    static bool 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 = cast(Dsymbol)members.data[i];

				bool 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 is 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?
	 */
    bool hasPointers()
	{
		//printf("Dsymbol::hasPointers() %s\n", toChars());
		return 0;
	}

    void addLocalClass(ClassDeclarations) { }
    void checkCtorConstInit() { }

    void addComment(ubyte* comment)
	{
		//if (comment)
			//printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());

		if (this.comment is null) {
			this.comment = comment;
		} else {
static if (true) {
			if (comment !is null && strcmp(cast(char*)comment, cast(char*)this.comment) != 0)
			{	// Concatenate the two
				this.comment = Lexer.combineComments(this.comment, comment);
			}
}
		}
	}
	
    void emitComment(Scope sc)
	{
		assert(false);
	}
	
    void emitDitto(Scope sc)
	{
		assert(false);
	}

    // Backend

    Symbol* toSymbol()			// to backend symbol
	{
		assert(false);
	}
	
    void toObjFile(int multiobj)			// compile to .obj file
	{
		//printf("Dsymbol::toObjFile('%s')\n", toChars());
		// ignore
	}
	
    int cvMember(ubyte* p)	// emit cv debug info for member
	{
		assert(false);
	}

	/*********************************
	 * Generate import symbol from symbol.
	 */
    Symbol* toImport()				// to backend import symbol
	{
		if (!isym)
		{
			if (!csym)
				csym = toSymbol();
			isym = toImport(csym);
		}

		return isym;
	}
	
    static Symbol* toImport(Symbol* sym)		// to backend import symbol
	{
		char* id;
		char* n;
		Symbol* s;
		type* t;

		//printf("Dsymbol::toImport('%s')\n", sym->Sident);
		n = sym.Sident.ptr;
version (Bug4054)
		id = cast(char*) GC.malloc(6 + strlen(n) + 1 + (type_paramsize_i(sym.Stype)).sizeof*3 + 1);
else
		id = cast(char*) alloca(6 + strlen(n) + 1 + (type_paramsize_i(sym.Stype)).sizeof*3 + 1);
		if (sym.Stype.Tmangle == mTYman_std && tyfunc(sym.Stype.Tty))
		{
			sprintf(id, "_imp__%s@%lu", n, type_paramsize_i(sym.Stype));
		}
		else if (sym.Stype.Tmangle == mTYman_d)
			sprintf(id,"_imp_%s",n);
		else
			sprintf(id,"_imp__%s",n);
		t = type_alloc(TYnptr | mTYconst);
		t.Tnext = sym.Stype;
		t.Tnext.Tcount++;
		t.Tmangle = mTYman_c;
		t.Tcount++;
		s = symbol_calloc(id);
		s.Stype = t;
		s.Sclass = SCextern;
		s.Sfl = FLextern;
		slist_add(s);

		return s;
	}

    Symbol* toSymbolX(string prefix, int sclass, TYPE* t, string suffix)	// helper
	{
		Symbol* s;
		char* id;
		string n;
		size_t nlen;

		//writef("Dsymbol::toSymbolX('%s', '%s')\n", prefix, this.classinfo.name);
		n = mangle();
		assert(n.length != 0);

		nlen = n.length;
static if (false) {
		if (nlen > 2 && n[0] == '_' && n[1] == 'D')
		{
			nlen -= 2;
			n += 2;
		}
}
		version (Bug4054)
		id = cast(char*) GC.malloc(2 + nlen + size_t.sizeof * 3 + prefix.length + suffix.length + 1);
		else
		id = cast(char*) alloca(2 + nlen + size_t.sizeof * 3 + prefix.length + suffix.length + 1);
		sprintf(id, "_D%.*s%lu%.*s%.*s", n, prefix.length, prefix, suffix);
		
	static if (false) {
		if (global.params.isWindows && (type_mangle(t) == mTYman.mTYman_c || type_mangle(t) == mTYman.mTYman_std))
			id++;			// Windows C mangling will put the '_' back in
	}
		s = symbol_name(id, sclass, t);
		
		//printf("-Dsymbol::toSymbolX() %s\n", id);
		return s;
	}

    // Eliminate need for dynamic_cast
    Package isPackage() { return null; }
    Module isModule() { return null; }
    EnumMember isEnumMember() { return null; }
    TemplateDeclaration isTemplateDeclaration() { return null; }
    TemplateInstance isTemplateInstance() { return null; }
    TemplateMixin isTemplateMixin() { return null; }
    Declaration isDeclaration() { return null; }
    ThisDeclaration isThisDeclaration() { return null; }
    TupleDeclaration isTupleDeclaration() { return null; }
    TypedefDeclaration isTypedefDeclaration() { return null; }
    AliasDeclaration isAliasDeclaration() { return null; }
    AggregateDeclaration isAggregateDeclaration() { return null; }
    FuncDeclaration isFuncDeclaration() { return null; }
    FuncAliasDeclaration isFuncAliasDeclaration() { return null; }
    FuncLiteralDeclaration isFuncLiteralDeclaration() { return null; }
    CtorDeclaration isCtorDeclaration() { return null; }
    PostBlitDeclaration isPostBlitDeclaration() { return null; }
    DtorDeclaration isDtorDeclaration() { return null; }
    StaticCtorDeclaration isStaticCtorDeclaration() { return null; }
    StaticDtorDeclaration isStaticDtorDeclaration() { return null; }
    InvariantDeclaration isInvariantDeclaration() { return null; }
    UnitTestDeclaration isUnitTestDeclaration() { return null; }
    NewDeclaration isNewDeclaration() { return null; }
    VarDeclaration isVarDeclaration() { return null; }
    ClassDeclaration isClassDeclaration() { return null; }
    StructDeclaration isStructDeclaration() { return null; }
    UnionDeclaration isUnionDeclaration() { return null; }
    InterfaceDeclaration isInterfaceDeclaration() { return null; }
    ScopeDsymbol isScopeDsymbol() { return null; }
    WithScopeSymbol isWithScopeSymbol() { return null; }
    ArrayScopeSymbol isArrayScopeSymbol() { return null; }
    Import isImport() { return null; }
    EnumDeclaration isEnumDeclaration() { return null; }
version (_DH) {
    DeleteDeclaration isDeleteDeclaration() { return null; }
}
    SymbolDeclaration isSymbolDeclaration() { return null; }
    AttribDeclaration isAttribDeclaration() { return null; }
    OverloadSet isOverloadSet() { return null; }
version (TARGET_NET) {
    PragmaScope isPragmaScope() { return null; }
}
}