public override MSAst.Expression Reduce() { if (_names == _star) { // from a[.b] import * return GlobalParent.AddDebugInfo( Ast.Call( AstMethods.ImportStar, Parent.LocalContext, AstUtils.Constant(_root.MakeString()), AstUtils.Constant(GetLevel()) ), Span ); } else { // from a[.b] import x [as xx], [ y [ as yy] ] [ , ... ] ReadOnlyCollectionBuilder<MSAst.Expression> statements = new ReadOnlyCollectionBuilder<MSAst.Expression>(); MSAst.ParameterExpression module = Ast.Variable(typeof(object), "module"); // Create initializer of the array of names being passed to ImportWithNames MSAst.Expression[] names = new MSAst.Expression[_names.Length]; for (int i = 0; i < names.Length; i++) { names[i] = AstUtils.Constant(_names[i]); } // module = PythonOps.ImportWithNames(<context>, _root, make_array(_names)) statements.Add( GlobalParent.AddDebugInfoAndVoid( AssignValue( module, LightExceptions.CheckAndThrow( Expression.Call( AstMethods.ImportWithNames, Parent.LocalContext, AstUtils.Constant(_root.MakeString()), Ast.NewArrayInit(typeof(string), names), AstUtils.Constant(GetLevel()) ) ) ), _root.Span ) ); // now load all the names being imported and assign the variables for (int i = 0; i < names.Length; i++) { statements.Add( GlobalParent.AddDebugInfoAndVoid( AssignValue( Parent.GetVariableExpression(_variables[i]), Ast.Call( AstMethods.ImportFrom, Parent.LocalContext, module, names[i] ) ), Span ) ); } statements.Add(AstUtils.Empty()); return GlobalParent.AddDebugInfo(Ast.Block(new[] { module }, statements.ToArray()), Span); } }
internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op) { // if we just have a simple named multi-assignment (e.g. a, b = 1,2) // then go ahead and step over the entire statement at once. If we have a // more complex statement (e.g. a.b, c.d = 1, 2) then we'll step over the // sets individually as they could be property sets the user wants to step // into. TODO: Enable stepping of the right hand side? bool emitIndividualSets = false; foreach (Expression e in _items) { if (IsComplexAssignment(e)) { emitIndividualSets = true; break; } } SourceSpan rightSpan = SourceSpan.None; SourceSpan leftSpan = (Span.Start.IsValid && span.IsValid) ? new SourceSpan(Span.Start, span.End) : SourceSpan.None; SourceSpan totalSpan = SourceSpan.None; if (emitIndividualSets) { rightSpan = span; leftSpan = SourceSpan.None; totalSpan = (Span.Start.IsValid && span.IsValid) ? new SourceSpan(Span.Start, span.End) : SourceSpan.None; } // 1. Evaluate the expression and assign the value to the temp. MSAst.ParameterExpression right_temp = Expression.Variable(typeof(object), "unpacking"); // 2. Add the assignment "right_temp = right" into the suite/block MSAst.Expression assignStmt1 = MakeAssignment(right_temp, right); int expected = _items.Length; int argcntafter = -1; for (var i = 0; i < _items.Length; i++) { var item = _items[i]; if (item is StarredExpression) { expected = i; argcntafter = _items.Length - i - 1; break; } } // 3. Call GetEnumeratorValues on the right side (stored in temp) MSAst.Expression enumeratorValues = Expression.Convert(LightExceptions.CheckAndThrow( Expression.Call( // method argcntafter != -1 ? AstMethods.UnpackIterable : emitIndividualSets ? AstMethods.GetEnumeratorValues : AstMethods.GetEnumeratorValuesNoComplexSets, // arguments Parent.LocalContext, right_temp, AstUtils.Constant(expected), AstUtils.Constant(argcntafter) ) ), typeof(object[])); // 4. Create temporary variable for the array MSAst.ParameterExpression array_temp = Expression.Variable(typeof(object[]), "array"); // 5. Assign the value of the method call (mce) into the array temp // And add the assignment "array_temp = Ops.GetEnumeratorValues(...)" into the block MSAst.Expression assignStmt2 = MakeAssignment( array_temp, enumeratorValues, rightSpan ); ReadOnlyCollectionBuilder <MSAst.Expression> sets = new ReadOnlyCollectionBuilder <MSAst.Expression>(_items.Length + 1); for (int i = 0; i < _items.Length; i++) { // target = array_temp[i] Expression target = _items[i]; if (target == null) { continue; } // 6. array_temp[i] MSAst.Expression element = Expression.ArrayAccess( array_temp, // array expression AstUtils.Constant(i) // index ); // 7. target = array_temp[i], and add the transformed assignment into the list of sets MSAst.Expression set = target.TransformSet( emitIndividualSets ? // span target.Span : SourceSpan.None, element, PythonOperationKind.None ); sets.Add(set); } // 9. add the sets as their own block so they can be marked as a single span, if necessary. sets.Add(AstUtils.Empty()); MSAst.Expression itemSet = GlobalParent.AddDebugInfo(Expression.Block(sets.ToReadOnlyCollection()), leftSpan); // 10. Return the suite statement (block) return(GlobalParent.AddDebugInfo(Expression.Block(new[] { array_temp, right_temp }, assignStmt1, assignStmt2, itemSet, AstUtils.Empty()), totalSpan)); }