Beispiel #1
0
        protected override void GenerateMethods(GenContext context)
        {
            HashSet <MethodInfo> implemented = new HashSet <MethodInfo>();

            for (ISeq s = RT.seq(Methods); s != null; s = s.next())
            {
                NewInstanceMethod method = (NewInstanceMethod)s.first();
                method.GenerateCode(this, context);
                implemented.UnionWith(method.MethodInfos);
            }

            foreach (List <MethodInfo> ms in _methodMap.Values)
            {
                foreach (MethodInfo mi in ms)
                {
                    if (NeedsDummy(mi, implemented))
                    {
                        GenerateDummyMethod(context, mi);
                    }
                }
            }

            GenerateHasArityMethod(TypeBuilder, null, false, 0);
        }
        protected override void EmitMethods(TypeBuilder tb)
        {
            HashSet <MethodInfo> implemented = new HashSet <MethodInfo>();

            for (ISeq s = RT.seq(Methods); s != null; s = s.next())
            {
                NewInstanceMethod method = (NewInstanceMethod)s.first();
                method.Emit(this, tb);
                implemented.UnionWith(method.MethodInfos);
            }

            foreach (List <MethodInfo> ms in _methodMap.Values)
            {
                foreach (MethodInfo mi in ms)
                {
                    if (NeedsDummy(mi, implemented))
                    {
                        EmitDummyMethod(tb, mi, true);
                    }
                }
            }

            EmitHasArityMethod(TypeBuilder, null, false, 0);
        }
Beispiel #3
0
        internal static ObjExpr Build(
            IPersistentVector interfaceSyms,
            IPersistentVector fieldSyms,
            Symbol thisSym,
            string tagName,
            Symbol className,
            Symbol typeTag,
            ISeq methodForms,
            Object frm)
        {
            NewInstanceExpr ret = new NewInstanceExpr(null);

            ret._src         = frm;
            ret._name        = className.ToString();
            ret._classMeta   = GenInterface.ExtractAttributes(RT.meta(className));
            ret.InternalName = ret.Name;  // ret.Name.Replace('.', '/');
            // Java: ret.objtype = Type.getObjectType(ret.internalName);

            if (thisSym != null)
            {
                ret._thisName = thisSym.Name;
            }

            if (fieldSyms != null)
            {
                IPersistentMap fmap      = PersistentHashMap.EMPTY;
                object[]       closesvec = new object[2 * fieldSyms.count()];
                for (int i = 0; i < fieldSyms.count(); i++)
                {
                    Symbol       sym = (Symbol)fieldSyms.nth(i);
                    LocalBinding lb  = new LocalBinding(-1, sym, null, new MethodParamExpr(Compiler.TagType(Compiler.TagOf(sym))), false, false);
                    fmap                 = fmap.assoc(sym, lb);
                    closesvec[i * 2]     = lb;
                    closesvec[i * 2 + 1] = lb;
                }
                // Java TODO: inject __meta et al into closes - when?
                // use array map to preserve ctor order
                ret._closes = new PersistentArrayMap(closesvec);
                ret._fields = fmap;
                for (int i = fieldSyms.count() - 1; i >= 0 && ((Symbol)fieldSyms.nth(i)).Name.StartsWith("__"); --i)
                {
                    ret._altCtorDrops++;
                }
            }

            // Java TODO: set up volatiles
            //ret._volatiles = PersistentHashSet.create(RT.seq(RT.get(ret._optionsMap, volatileKey)));

            IPersistentVector interfaces = PersistentVector.EMPTY;

            for (ISeq s = RT.seq(interfaceSyms); s != null; s = s.next())
            {
                Type t = (Type)Compiler.Resolve((Symbol)s.first());
                if (!t.IsInterface)
                {
                    throw new ParseException("only interfaces are supported, had: " + t.Name);
                }
                interfaces = interfaces.cons(t);
            }
            Type superClass = typeof(Object);

            Dictionary <IPersistentVector, List <MethodInfo> > overrideables;

            GatherMethods(superClass, RT.seq(interfaces), out overrideables);

            ret._methodMap = overrideables;

            //string[] inames = InterfaceNames(interfaces);

            Type   stub    = CompileStub(superClass, ret, SeqToTypeArray(interfaces), frm);
            Symbol thisTag = Symbol.intern(null, stub.FullName);
            //Symbol stubTag = Symbol.intern(null,stub.FullName);
            //Symbol thisTag = Symbol.intern(null, tagName);

            // Needs its own GenContext so it has its own DynInitHelper
            // Can't reuse Compiler.EvalContext if it is a DefType because we have to use the given name and will get a conflict on redefinition
            GenContext context = Compiler.CompilerContextVar.get() as GenContext ?? (ret.IsDefType ? GenContext.CreateWithExternalAssembly("deftype" + RT.nextID().ToString(), ".dll", true) : Compiler.EvalContext);
            GenContext genC    = context.WithNewDynInitHelper(ret.InternalName + "__dynInitHelper_" + RT.nextID().ToString());

            //genC.FnCompileMode = FnMode.Full;

            try
            {
                Var.pushThreadBindings(
                    RT.map(
                        Compiler.ConstantsVar, PersistentVector.EMPTY,
                        Compiler.ConstantIdsVar, new IdentityHashMap(),
                        Compiler.KeywordsVar, PersistentHashMap.EMPTY,
                        Compiler.VarsVar, PersistentHashMap.EMPTY,
                        Compiler.KeywordCallsitesVar, PersistentVector.EMPTY,
                        Compiler.ProtocolCallsitesVar, PersistentVector.EMPTY,
                        Compiler.VarCallsitesVar, Compiler.EmptyVarCallSites(),
                        Compiler.NoRecurVar, null,
                        Compiler.CompilerContextVar, genC
                        ));

                if (ret.IsDefType)
                {
                    Var.pushThreadBindings(
                        RT.map(
                            Compiler.MethodVar, null,
                            Compiler.LocalEnvVar, ret._fields,
                            Compiler.CompileStubSymVar, Symbol.intern(null, tagName),
                            Compiler.CompileStubClassVar, stub
                            ));
                    ret._hintedFields = RT.subvec(fieldSyms, 0, fieldSyms.count() - ret._altCtorDrops);
                }
                // now (methodname [args] body)*
                // TODO: SourceLocation?
                //ret.line = (Integer)LINE.deref();
                IPersistentCollection methods = null;
                for (ISeq s = methodForms; s != null; s = RT.next(s))
                {
                    NewInstanceMethod m = NewInstanceMethod.Parse(ret, (ISeq)RT.first(s), thisTag, overrideables);
                    methods = RT.conj(methods, m);
                }

                ret.Methods           = methods;
                ret.Keywords          = (IPersistentMap)Compiler.KeywordsVar.deref();
                ret.Vars              = (IPersistentMap)Compiler.VarsVar.deref();
                ret.Constants         = (PersistentVector)Compiler.ConstantsVar.deref();
                ret._constantsID      = RT.nextID();
                ret.KeywordCallsites  = (IPersistentVector)Compiler.KeywordCallsitesVar.deref();
                ret.ProtocolCallsites = (IPersistentVector)Compiler.ProtocolCallsitesVar.deref();
                ret.VarCallsites      = (IPersistentSet)Compiler.VarCallsitesVar.deref();
            }
            finally
            {
                if (ret.IsDefType)
                {
                    Var.popThreadBindings();
                }
                Var.popThreadBindings();
            }

            // TOD:  Really, the first stub here should be 'superclass' but can't handle hostexprs nested in method bodies -- reify method compilation takes place before this sucker is compiled, so can't replace the call.
            // Might be able to flag stub classes and not try to convert, leading to a dynsite.
            ret.Compile(stub, stub, interfaces, false, genC);
            Compiler.RegisterDuplicateType(ret.CompiledType);

            return(ret);
        }
Beispiel #4
0
        public static NewInstanceMethod Parse(ObjExpr objx, ISeq form, Symbol thisTag, Dictionary<IPersistentVector, List<MethodInfo>> overrideables)
        {
            // (methodname [this-name args*] body...)
            // this-name might be nil

            NewInstanceMethod method = new NewInstanceMethod(objx, (ObjMethod)Compiler.MethodVar.deref());

            Symbol dotName = (Symbol)RT.first(form);
            Symbol name;
            string methodName;

            int idx = dotName.Name.LastIndexOf(".");
            if (idx >= 0)
            {
                // we have an explicit interface implementation
                string dotNameStr = dotName.Name;
                string interfaceName = dotNameStr.Substring(0, idx);

                method._explicitInterface = RT.classForName(interfaceName);
                if (method._explicitInterface == null)
                    throw new ParseException(String.Format("Unable to find interface {0} for explicit method implemntation: {1}", interfaceName, dotNameStr));

                methodName = dotNameStr.Substring(idx + 1);
                name = (Symbol)Symbol.intern(null, Compiler.munge(dotName.Name)).withMeta(RT.meta(dotName));
            }
            else
            {
                name = (Symbol)Symbol.intern(null, Compiler.munge(dotName.Name)).withMeta(RT.meta(dotName));
                methodName = name.Name;
            }

            IPersistentVector parms = (IPersistentVector)RT.second(form);
            if (parms.count() == 0 || !(parms.nth(0) is Symbol))
                throw new ParseException("Must supply at least one argument for 'this' in: " + dotName);

            Symbol thisName = (Symbol)parms.nth(0);
            parms = RT.subvec(parms, 1, parms.count());
            ISeq body = RT.next(RT.next(form));
            try
            {

                method.SpanMap = (IPersistentMap)Compiler.SourceSpanVar.deref();

                // register as the current method and set up a new env frame
                // PathNode pnade = new PathNode(PATHTYPE.PATH, (PathNode) CLEAR_PATH.get());
                Var.pushThreadBindings(
                    RT.mapUniqueKeys(
                        Compiler.MethodVar, method,
                        Compiler.LocalEnvVar, Compiler.LocalEnvVar.deref(),
                        Compiler.LoopLocalsVar, null,
                        Compiler.NextLocalNumVar, 0
                    // CLEAR_PATH, pnode,
                    // CLEAR_ROOT, pnode,
                    // CLEAR_SITES, PersistentHashMap.EMPTY
                        ));

                // register 'this' as local 0
                //method._thisBinding = Compiler.RegisterLocalThis(((thisName == null) ? dummyThis : thisName), thisTag, null);
                Compiler.RegisterLocalThis(((thisName == null) ? dummyThis : thisName), thisTag, null);

                IPersistentVector argLocals = PersistentVector.EMPTY;
                method._retType = Compiler.TagType(Compiler.TagOf(name));
                method._argTypes = new Type[parms.count()];
                bool hinted = Compiler.TagOf(name) != null;
                Type[] pTypes = new Type[parms.count()];
                Symbol[] pSyms = new Symbol[parms.count()];
                bool[] pRefs = new bool[parms.count()];

                for (int i = 0; i < parms.count(); i++)
                {
                    // Param should be symbol or (by-ref symbol)
                    Symbol p;
                    bool isByRef = false;

                    object pobj = parms.nth(i);
                    if (pobj is Symbol)
                        p = (Symbol)pobj;
                    else if (pobj is ISeq)
                    {
                        ISeq pseq = (ISeq)pobj;
                        object first = RT.first(pseq);
                        object second = RT.second(pseq);
                        if (!(first is Symbol && ((Symbol)first).Equals(HostExpr.ByRefSym)))
                            throw new ParseException("First element in parameter pair must be by-ref");
                        if (!(second is Symbol))
                            throw new ParseException("Params must be Symbols");
                        isByRef = true;
                        p = (Symbol)second;
                        hinted = true;
                    }
                    else
                        throw new ParseException("Params must be Symbols or of the form (by-ref Symbol)");

                    object tag = Compiler.TagOf(p);
                    if (tag != null)
                        hinted = true;
                    if (p.Namespace != null)
                        p = Symbol.intern(p.Name);
                    Type pType = Compiler.TagType(tag);
                    if (isByRef)
                        pType = pType.MakeByRefType();

                    pTypes[i] = pType;
                    pSyms[i] = p;
                    pRefs[i] = isByRef;
                }

                Dictionary<IPersistentVector, List<MethodInfo>> matches =
                    method.IsExplicit
                    ? FindMethodsWithNameAndArity(method._explicitInterface, methodName, parms.count(), overrideables)
                    : FindMethodsWithNameAndArity(methodName, parms.count(), overrideables);

                IPersistentVector mk = MSig(methodName, pTypes, method._retType);
                List<MethodInfo> ms = null;
                if (matches.Count > 0 )
                {
                    // multiple matches
                    if (matches.Count > 1)
                    {
                        // must be hinted and match one method
                        if (!hinted)
                            throw new ParseException("Must hint overloaded method: " + name.Name);
                        if (! matches.TryGetValue(mk,out ms) )
                            throw new ParseException("Can't find matching overloaded method: " + name.Name);

                        method._minfos = ms;

                        //if (m.ReturnType != method._retType)
                        //    throw new ArgumentException(String.Format("Mismatched return type: {0}, expected {1}, had: {2}",
                        //        name.Name, m.ReturnType.Name, method._retType.Name));
                    }
                    else // one match
                    {
                        // if hinted, validate match,
                        if (hinted)
                        {
                            if (!matches.TryGetValue(mk, out ms))
                                throw new ParseException("Can't find matching method: " + name.Name + ", leave off hints for auto match.");

                            method._minfos = ms;

                            //if (m.ReturnType != method._retType)
                            //    throw new ArgumentException(String.Format("Mismatched return type: {0}, expected {1}, had: {2}",
                            //        name.Name, m.ReturnType.Name, method._retType.Name));
                        }
                        else // adopt found method sig
                        {
                            using (var e = matches.GetEnumerator() )
                            {
                                e.MoveNext();
                                mk = e.Current.Key;
                                ms = e.Current.Value;
                            }
                            MethodInfo m = ms[0];
                            method._retType = m.ReturnType;
                            pTypes = Compiler.GetTypes(m.GetParameters());
                            method._minfos = ms;
                        }
                    }
                }
                else
                    throw new ParseException("Can't define method not in interfaces: " + name.Name);

                if (method.IsExplicit)
                    method._explicitMethodInfo = ms[0];

                // validate unique name + arity among additional methods

                for (int i = 0; i < parms.count(); i++)
                {
                    LocalBinding lb = Compiler.RegisterLocal(pSyms[i], null, new MethodParamExpr(pTypes[i]), true, pRefs[i]);
                    argLocals = argLocals.assocN(i, lb);
                    method._argTypes[i] = pTypes[i];
                }

                Compiler.LoopLocalsVar.set(argLocals);
                method._name = name.Name;
                method._methodMeta = GenInterface.ExtractAttributes(RT.meta(name));
                method._parms = parms;
                method._argLocals = argLocals;
                method._body = (new BodyExpr.Parser()).Parse(new ParserContext(RHC.Return), body);
                return method;
            }
            finally
            {
                Var.popThreadBindings();
            }
        }
Beispiel #5
0
        public static NewInstanceMethod Parse(ObjExpr objx, ISeq form, Symbol thisTag, Dictionary <IPersistentVector, IList <MethodInfo> > overrideables, Dictionary <IPersistentVector, IList <MethodInfo> > explicits)
        {
            // (methodname [this-name args*] body...)
            // this-name might be nil

            NewInstanceMethod method = new NewInstanceMethod(objx, (ObjMethod)Compiler.MethodVar.deref());

            Symbol dotName = (Symbol)RT.first(form);
            Symbol name;
            string methodName;

            int idx = dotName.Name.LastIndexOf(".");

            if (idx >= 0)
            {
                // we have an explicit interface implementation
                string dotNameStr    = dotName.Name;
                string interfaceName = dotNameStr.Substring(0, idx);

                method.ExplicitInterface = RT.classForName(interfaceName);
                if (method.ExplicitInterface == null)
                {
                    throw new ParseException(String.Format("Unable to find interface {0} for explicit method implemntation: {1}", interfaceName, dotNameStr));
                }

                methodName = dotNameStr.Substring(idx + 1);
                name       = (Symbol)Symbol.intern(null, Compiler.munge(dotName.Name)).withMeta(RT.meta(dotName));
            }
            else
            {
                name       = (Symbol)Symbol.intern(null, Compiler.munge(dotName.Name)).withMeta(RT.meta(dotName));
                methodName = name.Name;
            }

            IPersistentVector parms = (IPersistentVector)RT.second(form);

            if (parms.count() == 0 || !(parms.nth(0) is Symbol))
            {
                throw new ParseException("Must supply at least one argument for 'this' in: " + dotName);
            }

            Symbol thisName = (Symbol)parms.nth(0);

            parms = RT.subvec(parms, 1, parms.count());
            ISeq body = RT.next(RT.next(form));

            try
            {
                method.SpanMap = (IPersistentMap)Compiler.SourceSpanVar.deref();

                // register as the current method and set up a new env frame
                // PathNode pnade = new PathNode(PATHTYPE.PATH, (PathNode) CLEAR_PATH.get());
                Var.pushThreadBindings(
                    RT.mapUniqueKeys(
                        Compiler.MethodVar, method,
                        Compiler.LocalEnvVar, Compiler.LocalEnvVar.deref(),
                        Compiler.LoopLocalsVar, null,
                        Compiler.NextLocalNumVar, 0
                        // CLEAR_PATH, pnode,
                        // CLEAR_ROOT, pnode,
                        // CLEAR_SITES, PersistentHashMap.EMPTY
                        ));

                // register 'this' as local 0
                //method._thisBinding = Compiler.RegisterLocalThis(((thisName == null) ? dummyThis : thisName), thisTag, null);
                Compiler.RegisterLocalThis(((thisName == null) ? dummyThis : thisName), thisTag, null);

                IPersistentVector argLocals = PersistentVector.EMPTY;
                method._retType  = Compiler.TagType(Compiler.TagOf(name));
                method._argTypes = new Type[parms.count()];
                bool     hinted = Compiler.TagOf(name) != null;
                Type[]   pTypes = new Type[parms.count()];
                Symbol[] pSyms  = new Symbol[parms.count()];
                bool[]   pRefs  = new bool[parms.count()];

                for (int i = 0; i < parms.count(); i++)
                {
                    // Param should be symbol or (by-ref symbol)
                    Symbol p;
                    bool   isByRef = false;

                    object pobj = parms.nth(i);
                    if (pobj is Symbol)
                    {
                        p = (Symbol)pobj;
                    }
                    else if (pobj is ISeq)
                    {
                        ISeq   pseq   = (ISeq)pobj;
                        object first  = RT.first(pseq);
                        object second = RT.second(pseq);
                        if (!(first is Symbol && ((Symbol)first).Equals(HostExpr.ByRefSym)))
                        {
                            throw new ParseException("First element in parameter pair must be by-ref");
                        }
                        if (!(second is Symbol))
                        {
                            throw new ParseException("Params must be Symbols");
                        }
                        isByRef = true;
                        p       = (Symbol)second;
                        hinted  = true;
                    }
                    else
                    {
                        throw new ParseException("Params must be Symbols or of the form (by-ref Symbol)");
                    }

                    object tag = Compiler.TagOf(p);
                    if (tag != null)
                    {
                        hinted = true;
                    }
                    if (p.Namespace != null)
                    {
                        p = Symbol.intern(p.Name);
                    }
                    Type pType = Compiler.TagType(tag);
                    if (isByRef)
                    {
                        pType = pType.MakeByRefType();
                    }

                    pTypes[i] = pType;
                    pSyms[i]  = p;
                    pRefs[i]  = isByRef;
                }

                Dictionary <IPersistentVector, IList <MethodInfo> > matches =
                    method.IsExplicit
                    ? FindMethodsWithNameAndArity(method.ExplicitInterface, methodName, parms.count(), overrideables, explicits)
                    : FindMethodsWithNameAndArity(methodName, parms.count(), overrideables);

                IPersistentVector  mk = MSig(methodName, pTypes, method._retType);
                IList <MethodInfo> ms = null;
                if (matches.Count > 0)
                {
                    // multiple matches
                    if (matches.Count > 1)
                    {
                        // must be hinted and match one method
                        if (!hinted)
                        {
                            throw new ParseException("Must hint overloaded method: " + name.Name);
                        }
                        if (!matches.TryGetValue(mk, out ms))
                        {
                            throw new ParseException("Can't find matching overloaded method: " + name.Name);
                        }

                        method._minfos = ms;
                    }
                    else // one match
                    {
                        // if hinted, validate match,
                        if (hinted)
                        {
                            if (!matches.TryGetValue(mk, out ms))
                            {
                                throw new ParseException("Can't find matching method: " + name.Name + ", leave off hints for auto match.");
                            }

                            method._minfos = ms;

                            //if (m.ReturnType != method._retType)
                            //    throw new ArgumentException(String.Format("Mismatched return type: {0}, expected {1}, had: {2}",
                            //        name.Name, m.ReturnType.Name, method._retType.Name));
                        }
                        else // adopt found method sig
                        {
                            using (var e = matches.GetEnumerator())
                            {
                                e.MoveNext();
                                mk = e.Current.Key;
                                ms = e.Current.Value;
                            }
                            MethodInfo m = ms[0];
                            method._retType = m.ReturnType;
                            pTypes          = Compiler.GetTypes(m.GetParameters());
                            method._minfos  = ms;
                        }
                    }
                }
                else
                {
                    throw new ParseException("Can't define method not in interfaces: " + name.Name);
                }

                if (method.IsExplicit)
                {
                    method.ExplicitMethodInfo = ms[0];
                }

                // validate unique name + arity among additional methods

                for (int i = 0; i < parms.count(); i++)
                {
                    LocalBinding lb = Compiler.RegisterLocal(pSyms[i], null, new MethodParamExpr(pTypes[i]), true, pRefs[i]);
                    argLocals           = argLocals.assocN(i, lb);
                    method._argTypes[i] = pTypes[i];
                }

                Compiler.LoopLocalsVar.set(argLocals);
                method._name      = name.Name;
                method.MethodMeta = GenInterface.ExtractAttributes(RT.meta(name));
                method.Parms      = parms;
                method.ArgLocals  = argLocals;
                method.Body       = (new BodyExpr.Parser()).Parse(new ParserContext(RHC.Return), body);
                return(method);
            }
            finally
            {
                Var.popThreadBindings();
            }
        }