Example #1
0
        private Type CompileNode(CompilationContext ctx, IBranch b)
        {
#if FORCE_SINGLE_THREADED
            Application.DoEvents();
#endif
            // vault modifications guard
            if (!ctx.StillInTouch()) throw new CompilerOutOfTouchException();

            // type
            var t_parent = ctx.PrevSuccessfulType(b.VPath) ?? typeof(CompiledNode);
            (t_parent == typeof(CompiledNode) ^ (ctx.CumulativeCompilation && ctx.ScheduledCumulations.ContainsKey(b))).AssertTrue();
            var t = _mod.DefineType(ctx.RequestName(b.GetClassName()), TA.Public, t_parent);

#if TRACE
            try
            {
#endif
                // constructor
                var ctor = t.DefineConstructor(MA.PublicCtor, CallingConventions.Standard, typeof(CompiledNode).MkArray());
                ctor.DefineParameter(1, ParmA.None, "parent");
                ctor.il().ld_args(2).basector(typeof(CompiledNode), typeof(CompiledNode)).ret();

                // the [VPath(...)] attribute for reflection-based analysis
                t.SetCustomAttribute(new CustomAttributeBuilder(
                    typeof(VPathAttribute).GetConstructor(typeof(String).MkArray()),
                    b.VPath.ToString().MkArray()));

                // the [Revision(...)] attribute for reflection-based analysis
                t.SetCustomAttribute(new CustomAttributeBuilder(
                    typeof(RevisionAttribute).GetConstructor(new[] { typeof(ulong) }),
                    new object[] { Vault.Revision }));

                // the [Seq(...)] attribute for synchronization and namespacing purposes
                t.SetCustomAttribute(new CustomAttributeBuilder(
                    typeof(SeqAttribute).GetConstructor(new[] { typeof(int) }),
                    new object[] { ctx.WorkerSeq }));

                // trivial overrides
                t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Name"))
                    .il()
                    .ldstr(b.GetClassName() + "_seq" + ctx.WorkerSeq)
                    .ret();

                t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("VPath"))
                    .il()
                    .ldstr(b.VPath)
                    .newobj(typeof(VPath), typeof(String))
                    .ret();

                t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Revision"))
                    .il()
                    .ldc_i8(Vault.Revision)
                    .ret();

                t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Seq"))
                    .il()
                    .ldc_i4(ctx.WorkerSeq)
                    .ret();

                ImplementCreateChildren(ctx, t, b);
                ImplementCreateProperties(ctx, t, b);

                // finalize the type
                var t_created = t.CreateType();
                _types.Add(t_created);

                // create a factory method for this class
                var factoryName = b.GetClassName().Substring(b.GetClassName().LastIndexOf(".") + 1);
                var factoryMethod = ctx.FactoryType.DefineMethod("Create_" + ctx.RequestName(factoryName), MA.PublicStatic, typeof(CompiledNode), typeof(CompiledNode).MkArray());
                factoryMethod.SetCustomAttribute(new CustomAttributeBuilder(
                    typeof(VPathAttribute).GetConstructor(typeof(String).MkArray()),
                    b.VPath.ToString().MkArray()));
                factoryMethod.il().ldarg(0).newobj(t_created, typeof(CompiledNode).MkArray()).ret();

                // register self within the factory
                ctx.Factory.il()
                    .ldarg(0)
                    .ldstr(b.VPath.ToString())
                    .newobj(typeof(VPath), typeof(String))
                    .ldnull()
                    .ldftn(factoryMethod)
                    .newobj(typeof(Func<CompiledNode, CompiledNode>), typeof(Object), typeof(IntPtr))
                    .callvirt(typeof(NodeFactory).GetMethod("Register", BF.All));

                return t_created;
#if TRACE
            }
            finally
            {
                // attempts to finalize the type so that we can dump an assembly to disk after certain exceptions
                if (!t.IsCreated())
                {
                    Action<Action> neverFail = code => {try{code();}catch{}};
                    neverFail(() => t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Name")).il().ldnull().ret());
                    neverFail(() => t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("VPath")).il().ldnull().ret());
                    neverFail(() => t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Revision")).il().ldc_i8(0).ret());
                    neverFail(() => t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Seq")).il().ldc_i4(0).ret());
                    neverFail(() => t.DefineOverride(typeof(CompiledNode).GetMethod("CreateChildren", BF.All)).il().ret());
                    neverFail(() => t.DefineOverride(typeof(CompiledNode).GetMethod("CreateProperties", BF.All)).il().ret());
                    neverFail(() => ctx.CCs[t].il().ret());
                    neverFail(() => ctx.CPs[t].il().ret());
                    neverFail(() => t.CreateType());
                }
            }
#endif
        }