/// <summary> /// Creates variables which are defined in a parent scope and used by a child scope. /// </summary> private void CreateChildReferencedVariables(AstGenerator ag, MSAst.Expression parentContext, List<MSAst.Expression> init) { MSAst.Expression localTuple = null; foreach (KeyValuePair<SymbolId, PythonReference> kv in _childReferences) { // a child scope refers to this closure value but we don't refer // to it directly. int index = ag.TupleIndex(kv.Value.PythonVariable); Type tupleType = ag.GetParentTupleType(); if (localTuple == null) { // pull the tuple from the context once localTuple = ag.HiddenVariable(tupleType, "$parentClosureTuple"); init.Add( MSAst.Expression.Assign( localTuple, MSAst.Expression.Convert( MSAst.Expression.Call( typeof(PythonOps).GetMethod("GetClosureTupleFromContext"), parentContext ), tupleType ) ) ); } ag.ReferenceVariable(kv.Value.PythonVariable, index, localTuple, false); } }
/// <summary> /// Creates variables which are defined in a parent scope and accessed in this scope. /// </summary> private void CreateReferencedVariables(AstGenerator ag, List<MSAst.Expression> init, bool emitDictionary, bool needsLocals) { MSAst.Expression localTuple = null; foreach (KeyValuePair<SymbolId, PythonReference> kv in _references) { PythonVariable var = kv.Value.PythonVariable; if (var == null || var.Scope == this) { continue; } if ((var.Kind == VariableKind.Local || var.Kind == VariableKind.Parameter) && !var.Scope.IsGlobal) { // closed over local, we need to pull in the closure variable Type tupleType = ag.GetParentTupleType(); int index = ag.TupleIndex(var); localTuple = EnsureLocalTuple(ag, init, localTuple, tupleType); // get the closure cell from the tuple MSAst.Expression tuplePath = localTuple; foreach (var v in MutableTuple.GetAccessPath(tupleType, index)) { tuplePath = MSAst.Expression.Property(tuplePath, v); } MSAst.ParameterExpression pe = ag.HiddenVariable(typeof(ClosureCell), SymbolTable.IdToString(var.Name)); init.Add(MSAst.Expression.Assign(pe, tuplePath)); ag.SetLocalLiftedVariable(var, new ClosureExpression(var, pe, null)); if (emitDictionary) { ag.ReferenceVariable(var, index, localTuple, needsLocals); } } } }