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);
            }
        }
Exemplo n.º 2
0
        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));
        }