public void RevertContextualsIn(FrameScope fs, CodeGen cg) { foreach (var varname in MangledContextuals.Values) { if (fs.AssignedContextuals.Contains(varname)) { if (cg.This().Type.Name != "TopLevelFrame") { cg.If(cg.This().Field("_assigned_" + fs.ID + "_" + varname) > 0); { cg.Assign(cg.This().Field("TopLevelFrame").Field("_ctxl_" + varname), cg.This().Field("TopLevelFrame").Field("_stack_" + varname).Invoke("Pop")); cg.Assign(cg.This().Field("_assigned_" + fs.ID + "_" + varname), 0); } cg.End(); } else { cg.If(cg.This().Field("_assigned_" + fs.ID + "_" + varname) > 0); { cg.Assign(cg.This().Field("_ctxl_" + varname), cg.This().Field("_stack_" + varname).Invoke("Pop")); cg.Assign(cg.This().Field("_assigned_" + fs.ID + "_" + varname), 0); } cg.End(); } } } }
// this routine runs at parser-runtime (not parser-compiletime nor program-runtime) public string GetMangledContextual(TypeGen currentFrameBuilder, FrameScope currentScope, FrameScope topLevelScope, string varname) { string mangledName; if (!MangledContextuals.TryGetValue(varname, out mangledName)) { throw new InvalidOperationException("you must declare the contextual " + varname + ", including its type annotation"); } return(GetMangledContextual(currentFrameBuilder, currentScope, topLevelScope, topLevelScope[varname].Type, varname)); }
// generates code that resets the lexical slots in the enclosing frame for re-entering // a block (such as in a loop). Effectively emulates a parameterless closure. public void RevertLexicalsIn(FrameScope fs, CodeGen cg) { foreach (var varname in fs.OwnKeysList) { if (fs[varname].Type.IsValueType) { cg.This().Field(fs[varname].MangledName).ForceEmitAddress(cg); cg.IL.Emit(OpCodes.Initobj, fs[varname].Type); } else { cg.Assign(cg.This().Field(fs[varname].MangledName), null); } } }
// this routine runs at parser-runtime (not parser-compiletime nor program-runtime) public string GetMangledContextual(TypeGen currentFrameBuilder, FrameScope currentScope, FrameScope topLevelScope, Type type, string varname) { string mangledName; if (!MangledContextuals.TryGetValue(varname, out mangledName)) { var frameLocal = new FrameLocal(varname, type, topLevelScope); topLevelScope.AddHere(varname, frameLocal); currentFrameBuilder.FrameGen.MangledContextuals.Add(varname, mangledName = frameLocal.MangledName); // create a field in the toplevel frame class for the current contextual value Public.Field(type, "_ctxl_" + mangledName); // and create a runtime type representing the type of the Stack<TypeOfThisContextual> var stack_type = typeof(Stack <>).MakeGenericType(type); // create a field in the toplevel frame class for the stack of previously assigned dynamic // values of the contextual variable. Public.Field(stack_type, "_stack_" + mangledName); // push a closure that will run (parser-runtime) at the end of the toplevel routine declaration // (but at program-runtime will run as a prologue to the program) that initializes this stack PrologueEvents.Add((CodeGen cg) => { if (cg.This().Type.Name == "TopLevelFrame") { cg.Assign(cg.This().Field("_stack_" + mangledName), Exp.New(stack_type)); } else { cg.Assign(cg.This().Field("TopLevelFrame").Field("_stack_" + mangledName), Exp.New(stack_type)); } }); } // if we haven't already added a flag assigned slot for this contextual-scope tuple in this frame, if (!currentScope.AssignedContextuals.Contains(mangledName)) { // record that we've done so, currentScope.AssignedContextuals.Add(mangledName); // and create a field in the current frame class for a flag representing whether to pop the // contextual stack upon leaving this scope, currentFrameBuilder.FrameGen.Public.Field(typeof(int), "_assigned_" + currentScope.ID + "_" + mangledName); } return(mangledName); }