private void EmitGeneratorBody(CodeGen cg, CodeGen ocg) { // Create the GenerateNext function CodeGen ncg = cg.DefineMethod(name.GetString() + "$g" + counter++, typeof(bool), new Type[] { typeof(Generator), typeof(object).MakeByRefType() }, new String[] { "$gen", "$ret" }); ncg.Context = cg.Context; PromoteLocalsToEnvironment(); ncg.FuncOrClassName = name.ToString(); ncg.EmitSetTraceBackUpdateStatus(false); // Namespace without er factory - all locals must exist ahead of time ncg.Names = new Namespace(null); Slot generator = ncg.GetArgumentSlot(0); ncg.StaticLinkSlot = new FieldSlot(generator, typeof(Generator).GetField("staticLink")); if (HasEnvironment) { cg.EnvironmentSlot = CreateEnvironment(cg); EnvironmentFactory ef = this.environmentFactory; Slot envSlotCast = new CastSlot( new FieldSlot(generator, typeof(Generator).GetField("environment")), ef.EnvironmentType ); Slot envSlot = ncg.GetLocalTmp(ef.EnvironmentType); // setup the environment and static link slots ncg.EnvironmentSlot = envSlot; ncg.ContextSlot = envSlot; // pull the environment into typed local variable envSlot.EmitSet(ncg, envSlotCast); InheritEnvironment(ncg); CreateGeneratorTemps(ef, ncg); } else { ncg.ContextSlot = ncg.StaticLinkSlot; } ncg.ModuleSlot = new PropertySlot(ncg.ContextSlot, typeof(ICallerContext).GetProperty("Module")); CreateClosureSlots(ncg); CreateGlobalSlots(ncg, ocg); // Emit the generator body using the typed er EmitGenerator(ncg); // Initialize the generator EmitTupleParams(cg); // Create instance of the generator cg.EmitStaticLinkOrNull(); cg.EmitEnvironmentOrNull(); cg.EmitDelegate(ncg, typeof(Generator.NextTarget), null); cg.EmitNew(typeof(Generator), new Type[] { typeof(FunctionEnvironmentDictionary), typeof(FunctionEnvironmentDictionary), typeof(Generator.NextTarget) }); cg.EmitReturn(); }
private void CreateClosureSlots(Slot staticLink, Namespace nspace) { foreach (KeyValuePair<SymbolId, Binding> kv in names) { if (!kv.Value.IsFree) continue; // Find the slot Slot instance = staticLink; ScopeStatement current = parent; for (; ; ) { instance = new CastSlot(instance, current.environmentFactory.EnvironmentType); Debug.Assert(current != null, "cannot resolve closure", kv.Key.GetString()); if (current.environment != null) { EnvironmentReference er; // Is the slot in this environment? if (current.TryGetEnvironmentReference(kv.Key, out er)) { nspace.SetSlot(kv.Key, er.CreateSlot(instance)); break; } } instance = EnvironmentFactory.MakeParentSlot(instance); current = current.parent; } } }