Mercurial > projects > ddmd
diff dmd/TraitsExp.d @ 17:ddae60498573
Implemented mixin statements, DefaultInitExps, FileInitExps, LineInitExps and __traits.
author | Robert Clipsham <robert@octarineparrot.com> |
---|---|
date | Mon, 05 Apr 2010 03:24:08 +0100 |
parents | 10317f0c89a5 |
children | 460959608115 |
line wrap: on
line diff
--- a/dmd/TraitsExp.d Sun Apr 04 22:41:11 2010 +0100 +++ b/dmd/TraitsExp.d Mon Apr 05 03:24:08 2010 +0100 @@ -8,32 +8,448 @@ import dmd.Scope; import dmd.HdrGenState; import dmd.TOK; +import dmd.TY; +import dmd.STC; +import dmd.WANT; +import dmd.Id; +import dmd.Global; +import dmd.Lexer; +import dmd.ArrayLiteralExp; +import dmd.VarExp; +import dmd.StringExp; +import dmd.DotIdExp; +import dmd.DotVarExp; +import dmd.IntegerExp; +import dmd.TupleExp; +import dmd.Type; +import dmd.Dsymbol; +import dmd.DsymbolExp; +import dmd.ScopeDsymbol; +import dmd.FuncDeclaration; +import dmd.ClassDeclaration; +import dmd.TemplateDeclaration; +import dmd.TemplateInstance; +import dmd.TypeClass; +import dmd.Util; +import dmd.expression.Util; -class TraitsExp : Expression -{ - Identifier ident; - - Objects args; - - this(Loc loc, Identifier ident, Objects args) - { - assert(false); - super(loc, TOK.init, 0); - } - - Expression syntaxCopy() - { - assert(false); - } - - Expression semantic(Scope sc) - { - assert(false); - } - - void toCBuffer(OutBuffer buf, HdrGenState* hgs) - { - assert(false); - } -} - +import core.stdc.string : strcmp; + +/************************************************ + * Delegate to be passed to overloadApply() that looks + * for virtual functions. + */ + +struct Pvirtuals +{ + Expression e1; + Expressions exps; + int fpvirtuals(void* param, FuncDeclaration f) + { Pvirtuals p = *cast(Pvirtuals*)param; + + if (f.isVirtual()) + { Expression e; + + if (p.e1.op == TOK.TOKdotvar) + { DotVarExp dve = cast(DotVarExp)p.e1; + e = new DotVarExp(Loc(0), dve.e1, f); + } + else + e = new DsymbolExp(Loc(0), f); + p.exps.push(cast(void*)e); + } + return 0; + } +} + + + +class TraitsExp : Expression +{ + Identifier ident; + + Objects args; + + this(Loc loc, Identifier ident, Objects args) + { + super(loc, TOK.TOKtraits, this.sizeof); + this.ident = ident; + this.args = args; + } + + Expression syntaxCopy() + { + return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args)); + } + + Expression semantic(Scope sc) + { + version (LOGSEMANTIC) { + printf("TraitsExp.semantic() %s\n", toChars()); + } + if (ident != Id.compiles && ident != Id.isSame) + TemplateInstance.semanticTiargs(loc, sc, args, 1); + size_t dim = args ? args.dim : 0; + Object o; + FuncDeclaration f; + + string ISTYPE(string cond) + { + return ` + for (size_t i = 0; i < dim; i++) + { Type t = getType(cast(Object)args.data[i]); + if (!t) + goto Lfalse; + if (!(`~cond~`)) + goto Lfalse; + } + if (!dim) + goto Lfalse; + goto Ltrue; + `; + } + + string ISDSYMBOL(string cond) + { + return `for (size_t i = 0; i < dim; i++) + { Dsymbol s = getDsymbol(cast(Object)args.data[i]); + if (!s) + goto Lfalse; + if (!(`~cond~`)) + goto Lfalse; + } + if (!dim) + goto Lfalse; + goto Ltrue;`; + } + + if (ident == Id.isArithmetic) + { + mixin(ISTYPE(`t.isintegral() || t.isfloating()`)); + } + else if (ident == Id.isFloating) + { + mixin(ISTYPE(q{t.isfloating()})); + } + else if (ident == Id.isIntegral) + { + mixin(ISTYPE(q{t.isintegral()})); + } + else if (ident == Id.isScalar) + { + mixin(ISTYPE(q{t.isscalar()})); + } + else if (ident == Id.isUnsigned) + { + mixin(ISTYPE(q{t.isunsigned()})); + } + else if (ident == Id.isAssociativeArray) + { + mixin(ISTYPE(q{t.toBasetype().ty == TY.Taarray})); + } + else if (ident == Id.isStaticArray) + { + mixin(ISTYPE(q{t.toBasetype().ty == TY.Tsarray})); + } + else if (ident == Id.isAbstractClass) + { + mixin(ISTYPE(q{t.toBasetype().ty == TY.Tclass && (cast(TypeClass)t.toBasetype()).sym.isAbstract()})); + } + else if (ident == Id.isFinalClass) + { + mixin(ISTYPE(q{t.toBasetype().ty == TY.Tclass && (cast(TypeClass)t.toBasetype()).sym.storage_class & STC.STCfinal})); + } + else if (ident == Id.isAbstractFunction) + { + mixin(ISDSYMBOL(q{(f = s.isFuncDeclaration()) !is null && f.isAbstract()})); + } + else if (ident == Id.isVirtualFunction) + { + mixin(ISDSYMBOL(q{(f = s.isFuncDeclaration()) !is null && f.isVirtual()})); + } + else if (ident == Id.isFinalFunction) + { + mixin(ISDSYMBOL(q{(f = s.isFuncDeclaration()) !is null && f.isFinal()})); + } + else if (ident == Id.hasMember || + ident == Id.getMember || + ident == Id.getVirtualFunctions) + { + if (dim != 2) + goto Ldimerror; + Object o_ = cast(Object)args.data[0]; + Expression e = isExpression(cast(Object)args.data[1]); + if (!e) + { error("expression expected as second argument of __traits %s", ident.toChars()); + goto Lfalse; + } + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (e.op != TOKstring) + { error("string expected as second argument of __traits %s instead of %s", ident.toChars(), e.toChars()); + goto Lfalse; + } + StringExp se = cast(StringExp)e; + se = se.toUTF8(sc); + if (se.sz != 1) + { error("string must be chars"); + goto Lfalse; + } + Identifier id = Lexer.idPool(fromStringz(cast(char*)se.string_)); + + Type t = isType(o_); + e = isExpression(o_); + Dsymbol s = isDsymbol(o_); + if (t) + e = typeDotIdExp(loc, t, id); + else if (e) + e = new DotIdExp(loc, e, id); + else if (s) + { e = new DsymbolExp(loc, s); + e = new DotIdExp(loc, e, id); + } + else + { error("invalid first argument"); + goto Lfalse; + } + + if (ident == Id.hasMember) + { /* Take any errors as meaning it wasn't found + */ + e = e.trySemantic(sc); + if (!e) + { if (global.gag) + global.errors++; + goto Lfalse; + } + else + goto Ltrue; + } + else if (ident == Id.getMember) + { + e = e.semantic(sc); + return e; + } + else if (ident == Id.getVirtualFunctions) + { + uint errors = global.errors; + Expression ex = e; + e = e.semantic(sc); + if (errors < global.errors) + error("%s cannot be resolved", ex.toChars()); + + /* Create tuple of virtual function overloads of e + */ + //e.dump(0); + Expressions exps = new Expressions(); + FuncDeclaration f_; + if (e.op == TOKvar) + { VarExp ve = cast(VarExp)e; + f_ = ve.var.isFuncDeclaration(); + } + else if (e.op == TOKdotvar) + { DotVarExp dve = cast(DotVarExp)e; + f_ = dve.var.isFuncDeclaration(); + } + else + f_ = null; + Pvirtuals p; + p.exps = exps; + p.e1 = e; + overloadApply(f_, &p.fpvirtuals, &p); + + TupleExp tup = new TupleExp(loc, exps); + return tup.semantic(sc); + } + else + assert(0); + } + else if (ident == Id.classInstanceSize) + { + if (dim != 1) + goto Ldimerror; + Object o_ = cast(Object)args.data[0]; + Dsymbol s = getDsymbol(o_); + ClassDeclaration cd; + if (!s || (cd = s.isClassDeclaration()) is null) + { + error("first argument is not a class"); + goto Lfalse; + } + return new IntegerExp(loc, cd.structsize, Type.tsize_t); + } + else if (ident == Id.allMembers || ident == Id.derivedMembers) + { + if (dim != 1) + goto Ldimerror; + Object o_ = cast(Object)args.data[0]; + Dsymbol s = getDsymbol(o_); + ScopeDsymbol sd; + if (!s) + { + error("argument has no members"); + goto Lfalse; + } + if ((sd = s.isScopeDsymbol()) is null) + { + error("%s %s has no members", s.kind(), s.toChars()); + goto Lfalse; + } + Expressions exps = new Expressions; + while (1) + { size_t dim_ = ScopeDsymbol.dim(sd.members); + for (size_t i = 0; i < dim_; i++) + { + Dsymbol sm = ScopeDsymbol.getNth(sd.members, i); + //printf("\t[%i] %s %s\n", i, sm.kind(), sm.toChars()); + if (sm.ident) + { + //printf("\t%s\n", sm.ident.toChars()); + auto str = sm.ident.toChars(); + + /* Skip if already present in exps[] + */ + for (size_t j = 0; j < exps.dim; j++) + { StringExp se2 = cast(StringExp)exps.data[j]; + if (strcmp(toStringz(str), cast(char*)se2.string_) == 0) + goto Lnext; + } + + StringExp se = new StringExp(loc, str); + exps.push(cast(void*)se); + } +Lnext: + ; + } + ClassDeclaration cd = sd.isClassDeclaration(); + if (cd && cd.baseClass && ident == Id.allMembers) + sd = cd.baseClass; // do again with base class + else + break; + } + Expression e = new ArrayLiteralExp(loc, exps); + e = e.semantic(sc); + return e; + } + else if (ident == Id.compiles) + { + /* Determine if all the objects - types, expressions, or symbols - + * compile without error + */ + if (!dim) + goto Lfalse; + + for (size_t i = 0; i < dim; i++) + { Object o_ = cast(Object)args.data[i]; + Expression e; + + uint errors = global.errors; + global.gag++; + + Type t = isType(o_); + if (t) + { Dsymbol s; + t.resolve(loc, sc, &e, &t, &s); + if (t) + t.semantic(loc, sc); + else if (e) + e.semantic(sc); + } + else + { e = isExpression(o); + if (e) + e.semantic(sc); + } + + global.gag--; + if (errors != global.errors) + { if (global.gag == 0) + global.errors = errors; + goto Lfalse; + } + } + goto Ltrue; + } + else if (ident == Id.isSame) + { /* Determine if two symbols are the same + */ + if (dim != 2) + goto Ldimerror; + TemplateInstance.semanticTiargs(loc, sc, args, 0); + Object o1 = cast(Object)args.data[0]; + Object o2 = cast(Object)args.data[1]; + Dsymbol s1 = getDsymbol(o1); + Dsymbol s2 = getDsymbol(o2); + + static if (0) { + printf("o1: %p\n", o1); + printf("o2: %p\n", o2); + if (!s1) + { Expression ea = isExpression(o1); + if (ea) + printf("%s\n", ea.toChars()); + Type ta = isType(o1); + if (ta) + printf("%s\n", ta.toChars()); + goto Lfalse; + } + else + printf("%s %s\n", s1.kind(), s1.toChars()); + } + if (!s1 && !s2) + { Expression ea1 = isExpression(o1); + Expression ea2 = isExpression(o2); + if (ea1 && ea2 && ea1.equals(ea2)) + goto Ltrue; + } + + if (!s1 || !s2) + goto Lfalse; + + s1 = s1.toAlias(); + s2 = s2.toAlias(); + + if (s1 == s2) + goto Ltrue; + else + goto Lfalse; + } + else + { error("unrecognized trait %s", ident.toChars()); + goto Lfalse; + } + + return null; + +Lnottype: + error("%s is not a type", o/*.toChars()*/); // BUG: o is Object, no member toChars() + goto Lfalse; + +Ldimerror: + error("wrong number of arguments %d", dim); + goto Lfalse; + + +Lfalse: + return new IntegerExp(loc, 0, Type.tbool); + +Ltrue: + return new IntegerExp(loc, 1, Type.tbool); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring("__traits("); + buf.writestring(ident.toChars()); + if (args) + { + for (int i = 0; i < args.dim; i++) + { + buf.writeByte(','); + Object oarg = cast(Object)args.data[i]; + ObjectToCBuffer(buf, hgs, oarg); + } + } + buf.writeByte(')'); + } +} +