private void GenerateAssemblyLookup(ModuleBuilder module)
        {
            if (_embeddedAssemblies.Count == 0) {
                return;
            }
            foreach (Assembly ass in _embeddedAssemblies) {
                string shortname = ass.FullName.Substring(0, ass.FullName.IndexOf(","));
                string tempfile = Path.GetTempFileName();
                File.Copy(new Uri(ass.EscapedCodeBase).LocalPath, tempfile, true);
                MemoryStream ms = new MemoryStream(File.ReadAllBytes(tempfile));
                ms.Seek(0, SeekOrigin.Begin);
                module.DefineManifestResource(shortname, ms, ResourceAttributes.Public);
                File.Delete(tempfile);
            }

            MethodBuilder resolveAssemblyMethod = module.DefineGlobalMethod("ResolveAssembly", MethodAttributes.Public | MethodAttributes.Static, typeof(Assembly), new Type[] { typeof(object), typeof(System.ResolveEventArgs) });
            ILGenerator ilResolve = resolveAssemblyMethod.GetILGenerator();
            CompileContext resolvecontext = new CompileContext();
            resolvecontext.PushIL(ilResolve);
            LocalBuilder localStream = ilResolve.DeclareLocal(typeof(Stream));
            LocalBuilder localBuf = ilResolve.DeclareLocal(typeof(byte[]));
            LocalBuilder localName = ilResolve.DeclareLocal(typeof(string));

            ilResolve.Emit(OpCodes.Ldarg_1);
            ilResolve.Emit(OpCodes.Call, typeof(ResolveEventArgs).GetMethod("get_Name"));
            ilResolve.Emit(OpCodes.Stloc, localName);

            ilResolve.Emit(OpCodes.Ldloc, localName);
            ilResolve.Emit(OpCodes.Ldc_I4_0);
            ilResolve.Emit(OpCodes.Ldloc, localName);
            ilResolve.Emit(OpCodes.Ldstr, ",");
            ilResolve.Emit(OpCodes.Call, typeof(string).GetMethod("IndexOf", new Type[] { typeof(string) }));
            ilResolve.Emit(OpCodes.Call, typeof(string).GetMethod("Substring", new Type[] { typeof(int), typeof(int) }));
            ilResolve.Emit(OpCodes.Stloc, localName);

            Assign(localStream, Call(Call(typeof(Assembly), "GetExecutingAssembly", false), "GetManifestResourceStream", false, localName), resolvecontext);

            Label notNull = ilResolve.DefineLabel();
            ilResolve.Emit(OpCodes.Ldloc, localStream);
            ilResolve.Emit(OpCodes.Brtrue, notNull);
            {
                //Not found, just return null
                ilResolve.Emit(OpCodes.Ldnull);
                ilResolve.Emit(OpCodes.Ret);
            }
            ilResolve.MarkLabel(notNull);
            Call(localStream, "get_Length", false).Compile(resolvecontext);
            ilResolve.Emit(OpCodes.Conv_Ovf_I);
            ilResolve.Emit(OpCodes.Newarr, typeof(System.Byte));
            ilResolve.Emit(OpCodes.Stloc, localBuf);

            ilResolve.Emit(OpCodes.Ldloc, localStream);
            ilResolve.Emit(OpCodes.Ldloc, localBuf);
            ilResolve.Emit(OpCodes.Ldc_I4_0);
            ilResolve.Emit(OpCodes.Ldloc, localBuf);
            ilResolve.Emit(OpCodes.Ldlen);
            ilResolve.Emit(OpCodes.Conv_I4);
            ilResolve.Emit(OpCodes.Callvirt, typeof(Stream).GetMethod("Read", new Type[] { typeof(byte[]), typeof(int), typeof(int) }));
            ilResolve.Emit(OpCodes.Pop);

            //Notify that we loaded this embedded...
            ilResolve.Emit(OpCodes.Ldarg_1);
            ilResolve.Emit(OpCodes.Call, typeof(ResolveEventArgs).GetMethod("get_Name"));
            ilResolve.Emit(OpCodes.Ldstr, " was not found externally, loading embedded version...");
            ilResolve.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }));
            ilResolve.Emit(OpCodes.Call, typeof(System.Console).GetMethod("WriteLine", new Type[] { typeof(string) }));

            Call(typeof(Assembly), "Load", false, localBuf).Compile(resolvecontext);
            ilResolve.Emit(OpCodes.Ret);
            resolvecontext.PopIL();

            MethodBuilder moduleInitializer = module.DefineGlobalMethod(".cctor", MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.RTSpecialName, null, new Type[] { });
            ILGenerator ilStartup = moduleInitializer.GetILGenerator();
            ilStartup.Emit(OpCodes.Call, typeof(System.AppDomain).GetMethod("get_CurrentDomain"));
            ilStartup.Emit(OpCodes.Ldnull);
            ilStartup.Emit(OpCodes.Ldftn, resolveAssemblyMethod);
            ilStartup.Emit(OpCodes.Newobj, MethodResolver.GetConstructor(typeof(System.ResolveEventHandler)));
            ilStartup.Emit(OpCodes.Callvirt, MethodResolver.GetMethod(typeof(System.AppDomain), "add_AssemblyResolve"));
            ilStartup.Emit(OpCodes.Ret);
        }
        public void Compile(CompileOptions options)
        {
            string absolutePath = Path.Combine(Environment.CurrentDirectory, options.OutputFile);
            string filename = Path.GetFileName(absolutePath);
            string folder = Path.GetDirectoryName(absolutePath);
            AssemblyName name = new AssemblyName(filename);
            AssemblyBuilder assembly = Thread.GetDomain().DefineDynamicAssembly(name, AssemblyBuilderAccess.Save, folder);
            ModuleBuilder module = assembly.DefineDynamicModule(options.OutputFile, filename, options.Debug);
            if (options.EmbedPLR) {
                EmbedAssembly(Assembly.GetExecutingAssembly());
            }

            if (_embeddedAssemblies.Count > 0) {
                GenerateAssemblyLookup(module);
            }

            CompileContext context = new CompileContext();
            context.Options = options;
            context.Module = module;
            MethodBuilder mainMethod = module.DefineGlobalMethod("Main", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { });
            if (options.Debug) {
                context.DebugWriter = module.DefineDocument(options.Arguments[0], Guid.Empty, Guid.Empty, SymDocumentType.Text);
                module.SetUserEntryPoint(mainMethod);
            }

            context.Module = module;
            context.ImportedClasses = _importedClasses;

            if (BeforeCompile != null) {
                BeforeCompile(context);
            }

            foreach (ProcessDefinition procdef in this) {
                procdef.CompileSignature(module, context);
            }

            if (!context.ImportedClasses.Contains(typeof(PLR.Runtime.BuiltIns).FullName)) {
                context.ImportedClasses.Add(typeof(PLR.Runtime.BuiltIns).FullName);
            }
            context.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly());
            if (options.References != "") {

                foreach (string assemblyName in options.References.Split(',')) {
                    string absoluteAssemblyPath = Path.Combine(Directory.GetCurrentDirectory(), assemblyName);
                    if (!File.Exists(absoluteAssemblyPath)) {
                        Console.Error.WriteLine("Assembly '{0}' does not exist!", absoluteAssemblyPath);
                        Environment.Exit(1);
                    }
                    context.ReferencedAssemblies.Add(Assembly.LoadFile(absoluteAssemblyPath));
                }
            }

            foreach (ProcessDefinition procdef in this) {
                context.CurrentMasterType = null;
                procdef.Compile(context);
                context.CurrentMasterType = null;
            }
            List<LocalBuilder> initial = new List<LocalBuilder>();
            context.PushIL(mainMethod.GetILGenerator());
            if (MainMethodStart != null) {
                MainMethodStart(context);
            }
            foreach (ProcessDefinition procdef in this) {
                if (procdef.EntryProc) {
                    TypeInfo startProc = context.GetType(procdef.FullName);
                    LocalBuilder loc = context.ILGenerator.DeclareLocal(startProc.Builder);
                    context.ILGenerator.Emit(OpCodes.Newobj, startProc.Constructor);
                    context.ILGenerator.Emit(OpCodes.Stloc, loc);
                }
            }

            //Run Scheduler, who now knows all the new Processes
            CallScheduler("Run", true, context);

            if (MainMethodEnd!= null) {
                MainMethodEnd(context);
            }

            //return 0;
            context.ILGenerator.Emit(OpCodes.Ldc_I4_0);
            context.ILGenerator.Emit(OpCodes.Ret);

            if (AfterCompile != null) {
                AfterCompile(context);
            }
            module.CreateGlobalFunctions();
            assembly.SetEntryPoint(mainMethod, PEFileKinds.ConsoleApplication);
            assembly.Save(filename);
        }
        /// <summary>
        /// Compiles the start block of
        /// </summary>
        /// <param name="context"></param>
        public TypeInfo CompileNewProcessStart(CompileContext context, string name)
        {
            try {
                //Get this before we push a new type on the stack, we are going to need it...
                Dictionary<string, LocalBuilder> currentLocals = null;

                if (context.Type != null) {
                    currentLocals = context.Type.Locals;
                }

                if (context.CurrentMasterType != null) { //Are in a type, so let's create a nested one
                    TypeInfo nestedType = new TypeInfo();
                    nestedType.Builder = context.Type.Builder.DefineNestedType(name, TypeAttributes.NestedPublic | TypeAttributes.Class | TypeAttributes.BeforeFieldInit, typeof(ProcessBase));
                    context.PushType(nestedType);
                } else {
                    context.PushType(context.GetType(name));
                    context.CurrentMasterType = context.Type;
                }
                Type baseType = typeof(ProcessBase);

                if (this.PreProcessActions != null) {
                    this.PreProcessActions.Compile(context);
                    context.Type.IsPreProcessed = true;
                }
                if (this.ActionRestrictions != null) {
                    this.ActionRestrictions.Compile(context);
                    context.Type.IsRestricted = true;
                }

                MethodBuilder methodStart = context.Type.Builder.DefineMethod("RunProcess", MethodAttributes.Public | MethodAttributes.Virtual);
                context.Type.Builder.DefineMethodOverride(methodStart, baseType.GetMethod("RunProcess"));
                context.PushIL(methodStart.GetILGenerator());
                Call(new ThisPointer(typeof(ProcessBase)), "InitSetID", true).Compile(context);
                if (this.WrapInTryCatch) {
                    context.ILGenerator.BeginExceptionBlock();
                }

                if (context.Type.Constructor == null) { //Nested type which hasn't defined its constructor yet

                    VariableCollection col = new VariableCollection();
                    col.Start(this);
                    List<Type> paramTypes = new List<Type>();
                    List<Variable> constructorParams = new List<Variable>();
                    foreach (Variable v in col.Variables) {
                        if (currentLocals != null && currentLocals.ContainsKey(v.Name)) { //We have defined this local variable and so should pass it to the new process
                            paramTypes.Add(typeof(object));
                            constructorParams.Add(v);
                            context.Type.ConstructorParameters.Add(v.Name); //Needed to pass the right parameters along later
                            context.Type.Fields.Add(context.Type.Builder.DefineField(v.Name, typeof(object), FieldAttributes.Private));
                        }
                    }
                    context.Type.Constructor = context.Type.Builder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, paramTypes.ToArray());
                    ILGenerator ilCon = context.Type.Constructor.GetILGenerator();
                    ilCon.Emit(OpCodes.Ldarg_0);
                    ilCon.Emit(OpCodes.Call, typeof(ProcessBase).GetConstructor(new Type[] { }));

                    for (int i = 0; i < constructorParams.Count; i++) {
                        context.Type.Constructor.DefineParameter(i + 1, ParameterAttributes.None, constructorParams[i].Name);
                        //save the variables argument we got passed in
                        ilCon.Emit(OpCodes.Ldarg_0);
                        ilCon.Emit(OpCodes.Ldarg, i + 1);
                        ilCon.Emit(OpCodes.Stfld, context.Type.GetField(constructorParams[i].Name));
                    }
                    ilCon.Emit(OpCodes.Ret);
                }

                //Do this after the constructor has been defined, because the fields
                //of the object are defined in the constructor...
                foreach (FieldBuilder field in context.Type.Fields) {
                    LocalBuilder local = context.ILGenerator.DeclareLocal(typeof(object));
                    if (context.Options.Debug) {
                        local.SetLocalSymInfo(field.Name);
                    }
                    context.Type.Locals.Add(field.Name, local);
                    //Add the field value to the local variable, so we can concentrate on only local vars
                    context.ILGenerator.Emit(OpCodes.Ldarg_0);
                    context.ILGenerator.Emit(OpCodes.Ldfld, field);
                    context.ILGenerator.Emit(OpCodes.Stloc, local);

                }

                return context.Type;
            } catch (Exception) {
                return null;
            }
        }