Beispiel #1
0
 internal override MSAst.Expression TransformSet(AstGenerator ag, SourceSpan span, MSAst.Expression right, Operators op) {
     if (op == Operators.None) {
         return ag.AddDebugInfoAndVoid(
             Binders.Set(
                 ag.BinderState,
                 typeof(object),
                 SymbolTable.IdToString(_name),
                 ag.Transform(_target),
                 right
             ),
             span
         );
     } else {
         MSAst.ParameterExpression temp = ag.GetTemporary("inplace");
         return ag.AddDebugInfo(
             Ast.Block(
                 Ast.Assign(temp, ag.Transform(_target)),
                 SetMemberOperator(ag, right, op, temp),
                 Ast.Empty()
             ),
             Span.Start,
             span.End
         );
     }
 }
Beispiel #2
0
        internal override MSAst.Expression Transform(AstGenerator ag, Type type) {
            MSAst.Expression left = ag.Transform(_left);
            MSAst.Expression right = ag.Transform(_right);

            Type t = left.Type == right.Type ? left.Type : typeof(object);
            MSAst.ParameterExpression tmp = ag.GetTemporary("__all__", t);
            
            return Ast.Condition(
                Binders.Convert(
                    ag.BinderState,
                    typeof(bool),
                    ConversionResultKind.ExplicitCast,
                    AstUtils.Assign(
                        tmp,
                        AstUtils.Convert(
                            left,
                            t
                        )
                    )
                ),
                AstUtils.Convert(
                    right,
                    t
                ),
                tmp
            );            
        }
        internal override MSAst.Expression Transform(AstGenerator ag, Type type) {
            MSAst.ParameterExpression list = ag.GetTemporary("list_comprehension_list", typeof(List));

            // 1. Initialization code - create list and store it in the temp variable
            MSAst.Expression initialize =
                Ast.Assign(
                    list,
                    Ast.Call(
                        AstGenerator.GetHelperMethod("MakeList", Type.EmptyTypes) // method
                    )                    
                );

            // 2. Create body from _item:   list.Append(_item)
            MSAst.Expression body = ag.AddDebugInfo(
                Ast.Call(
                    AstGenerator.GetHelperMethod("ListAddForComprehension"),
                    list,
                    ag.TransformAsObject(_item)
                ),
                _item.Span
            );

            // 3. Transform all iterators in reverse order, building the true body:
            int current = _iterators.Length;
            while (current-- > 0) {
                ListComprehensionIterator iterator = _iterators[current];
                body = iterator.Transform(ag, body);
            }

            return Ast.Block(
                initialize,
                body,
                list                        // result
            );
        }
Beispiel #4
0
        internal override MSAst.Expression Transform(AstGenerator ag) {
            MSAst.Expression destination = ag.TransformAsObject(_dest);

            if (_expressions.Length == 0) {
                MSAst.Expression result;
                if (destination != null) {
                    result = Ast.Call(
                        AstGenerator.GetHelperMethod("PrintNewlineWithDest"),
                        ag.LocalContext,
                        destination
                    );
                } else {
                    result = Ast.Call(
                        AstGenerator.GetHelperMethod("PrintNewline"),
                        ag.LocalContext
                    );
                }
                return ag.AddDebugInfo(result, Span);
            } else {
                // Create list for the individual statements
                List<MSAst.Expression> statements = new List<MSAst.Expression>();

                // Store destination in a temp, if we have one
                if (destination != null) {
                    MSAst.ParameterExpression temp = ag.GetTemporary("destination");

                    statements.Add(
                        ag.MakeAssignment(temp, destination)
                    );

                    destination = temp;
                }
                for (int i = 0; i < _expressions.Length; i++) {
                    string method = (i < _expressions.Length - 1 || _trailingComma) ? "PrintComma" : "Print";
                    Expression current = _expressions[i];
                    MSAst.MethodCallExpression mce;

                    if (destination != null) {
                        mce = Ast.Call(
                            AstGenerator.GetHelperMethod(method + "WithDest"),
                            ag.LocalContext,
                            destination,
                            ag.TransformAsObject(current)
                        );
                    } else {
                        mce = Ast.Call(
                            AstGenerator.GetHelperMethod(method),
                            ag.LocalContext,
                            ag.TransformAsObject(current)
                        );
                    }

                    statements.Add(mce);
                }

                statements.Add(AstUtils.Empty());
                return ag.AddDebugInfo(Ast.Block(statements.ToArray()), Span);
            }
        }
Beispiel #5
0
        internal override MSAst.Expression Transform(AstGenerator ag) {
            // Temporary variable for the IEnumerator object
            MSAst.ParameterExpression enumerator = ag.GetTemporary("foreach_enumerator", typeof(IEnumerator));

            // Only the body is "in the loop" for the purposes of break/continue
            // The "else" clause is outside
            MSAst.LabelTarget breakLabel, continueLabel;
            MSAst.Expression body = ag.TransformLoopBody(_body, _left.Start, out breakLabel, out continueLabel);
            if (body == null) {
                // error recovery
                return null;
            }
            return TransformForStatement(ag, enumerator, _list, _left, body, _else, Span, _header, breakLabel, continueLabel);
        }
        private MSAst.Expression AssignComplex(AstGenerator ag, MSAst.Expression right) {
            // Python assignment semantics:
            // - only evaluate RHS once. 
            // - evaluates assignment from left to right
            // - does not evaluate getters.
            // 
            // So 
            //   a=b[c]=d=f() 
            // should be:
            //   $temp = f()
            //   a = $temp
            //   b[c] = $temp
            //   d = $temp

            List<MSAst.Expression> statements = new List<MSAst.Expression>();

            // 1. Create temp variable for the right value
            MSAst.ParameterExpression right_temp = ag.GetTemporary("assignment");

            // 2. right_temp = right
            statements.Add(
                ag.MakeAssignment(right_temp, right)
                );

            // Do left to right assignment
            foreach (Expression e in _left) {
                if (e == null) {
                    continue;
                }

                // 3. e = right_temp
                MSAst.Expression transformed = e.TransformSet(ag, Span, right_temp, Operators.None);
                if (transformed == null) {
                    throw PythonOps.SyntaxError(String.Format("can't assign to {0}", e.NodeName), ag.Context.SourceUnit, e.Span, -1);
                }

                statements.Add(transformed);
            }

            // 4. Create and return the resulting suite
            statements.Add(Ast.Empty());
            return ag.AddDebugInfo(
                Ast.Block(statements.ToArray()),
                Span
            );
        }
        private MSAst.Expression AssignComplex(AstGenerator ag, MSAst.Expression right) {
            // Python assignment semantics:
            // - only evaluate RHS once. 
            // - evaluates assignment from left to right
            // - does not evaluate getters.
            // 
            // So 
            //   a=b[c]=d=f() 
            // should be:
            //   $temp = f()
            //   a = $temp
            //   b[c] = $temp
            //   d = $temp

            List<MSAst.Expression> statements = new List<MSAst.Expression>();

            // 1. Create temp variable for the right value
            MSAst.ParameterExpression right_temp = ag.GetTemporary("assignment");

            // 2. right_temp = right
            statements.Add(
                AstGenerator.MakeAssignment(right_temp, right)
                );

            // Do left to right assignment
            foreach (Expression e in _left) {
                if (e == null) {
                    continue;
                }

                // 3. e = right_temp
                MSAst.Expression transformed = e.TransformSet(ag, Span, right_temp, PythonOperationKind.None);

                statements.Add(transformed);
            }

            // 4. Create and return the resulting suite
            statements.Add(AstUtils.Empty());
            return ag.AddDebugInfoAndVoid(
                Ast.Block(statements.ToArray()),
                Span
            );
        }
Beispiel #8
0
 internal override MSAst.Expression TransformSet(AstGenerator ag, SourceSpan span, MSAst.Expression right, PythonOperationKind op) {
     if (op == PythonOperationKind.None) {
         return ag.AddDebugInfoAndVoid(
             ag.Set(
                 typeof(object),
                 _name,
                 ag.Transform(_target),
                 right
             ),
             span
         );
     } else {
         MSAst.ParameterExpression temp = ag.GetTemporary("inplace");
         return ag.AddDebugInfo(
             Ast.Block(
                 Ast.Assign(temp, ag.Transform(_target)),
                 SetMemberOperator(ag, right, op, temp),
                 AstUtils.Empty()
             ),
             Span.Start,
             span.End
         );
     }
 }
        internal override MSAst.Expression Transform(AstGenerator ag) {            
            if (_names == _star) {
                // from a[.b] import *
                return ag.AddDebugInfo(
                    Ast.Call(
                        AstGenerator.GetHelperMethod("ImportStar"), 
                        AstUtils.CodeContext(), 
                        Ast.Constant(_root.MakeString()), 
                        Ast.Constant(GetLevel())
                    ),
                    Span
                );
            } else {
                // from a[.b] import x [as xx], [ y [ as yy] ] [ , ... ]

                List<MSAst.Expression> statements = new List<MSAst.Expression>();
                MSAst.ParameterExpression module = ag.GetTemporary("module");

                // Create initializer of the array of names being passed to ImportWithNames
                MSAst.ConstantExpression[] names = new MSAst.ConstantExpression[_names.Length];
                for (int i = 0; i < names.Length; i++) {
                    names[i] = Ast.Constant(SymbolTable.IdToString(_names[i]));
                }

                // module = PythonOps.ImportWithNames(<context>, _root, make_array(_names))
                statements.Add(
                    ag.AddDebugInfo(
                        AstUtils.Assign(
                            module, 
                            Ast.Call(
                                AstGenerator.GetHelperMethod("ImportWithNames"),
                                AstUtils.CodeContext(),
                                Ast.Constant(_root.MakeString()),
                                Ast.NewArrayInit(typeof(string), names),
                                Ast.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(
                        ag.AddDebugInfo(
                            AstUtils.Assign(
                                _variables[i].Variable, 
                                Ast.Call(
                                    AstGenerator.GetHelperMethod("ImportFrom"),
                                    AstUtils.CodeContext(),
                                    module,
                                    names[i]
                                )
                            ),
                            Span
                        )
                    );
                }

                statements.Add(Ast.Empty());
                return ag.AddDebugInfo(Ast.Block(statements.ToArray()), Span);
            }
        }
Beispiel #10
0
        private static MSAst.Expression MakeBinaryOperation(AstGenerator ag, PythonOperator op, MSAst.Expression left, MSAst.Expression right, Type type, SourceSpan span) {
            if (op == PythonOperator.NotIn) {                
                return AstUtils.Convert(
                    Ast.Not(
                        Binders.Operation(
                            ag.BinderState,
                            typeof(bool),
                            StandardOperators.Contains,
                            left,
                            right
                        )                            
                    ),
                    type
                );
            }

            Operators action = PythonOperatorToAction(op);
            if (action != Operators.None) {
                // Create action expression
                if (op == PythonOperator.Divide &&
                    (ag.DivisionOptions == PythonDivisionOptions.Warn || ag.DivisionOptions == PythonDivisionOptions.WarnAll)) {
                    MSAst.ParameterExpression tempLeft = ag.GetTemporary("left", left.Type);
                    MSAst.ParameterExpression tempRight = ag.GetTemporary("right", right.Type);
                    return Ast.Block(
                        Ast.Call(
                            AstGenerator.GetHelperMethod("WarnDivision"),
                            AstUtils.CodeContext(),
                            Ast.Constant(ag.DivisionOptions),
                            AstUtils.Convert(
                                Ast.Assign(tempLeft, left),
                                typeof(object)
                            ),
                            AstUtils.Convert(
                                Ast.Assign(tempRight, right),
                                typeof(object)
                            )
                        ),
                        Binders.Operation(
                            ag.BinderState,
                            type,
                            StandardOperators.FromOperator(action),
                            tempLeft,
                            tempRight
                        )
                    );
                }

                return Binders.Operation(
                    ag.BinderState,
                    type,
                    StandardOperators.FromOperator(action),
                    left,
                    right
                );
            } else {
                // Call helper method
                return Ast.Call(
                    AstGenerator.GetHelperMethod(GetHelperName(op)),
                    AstGenerator.ConvertIfNeeded(left, typeof(object)),
                    AstGenerator.ConvertIfNeeded(right, typeof(object))
                );
            }
        }
Beispiel #11
0
        internal override MSAst.Expression TransformSet(AstGenerator ag, 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 = ag.GetTemporary("unpacking");

            // 2. Add the assignment "right_temp = right" into the suite/block
            MSAst.Expression assignStmt1 = AstGenerator.MakeAssignment(right_temp, right);

            // 3. Call GetEnumeratorValues on the right side (stored in temp)
            MSAst.Expression enumeratorValues = Ast.Call(
                AstGenerator.GetHelperMethod("GetEnumeratorValues"),    // method
                // arguments
                ag.LocalContext,
                right_temp,
                AstUtils.Constant(_items.Length)
            );

            // 4. Create temporary variable for the array
            MSAst.ParameterExpression array_temp = ag.GetTemporary("array", typeof(object[]));

            // 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 = ag.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 = Ast.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(
                    ag,
                    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 = ag.AddDebugInfo(Ast.Block(sets.ToReadOnlyCollection()), leftSpan);

            // 10. Free the temps
            ag.FreeTemp(array_temp);
            ag.FreeTemp(right_temp);

            // 11. Return the suite statement (block)
            return ag.AddDebugInfo(Ast.Block(assignStmt1, assignStmt2, itemSet, AstUtils.Empty()), totalSpan);
        }
 internal override MSAst.Expression Transform(AstGenerator ag, MSAst.Expression body) {
     MSAst.ParameterExpression temp = ag.GetTemporary("list_comprehension_for", typeof(IEnumerator));
     return ForStatement.TransformForStatement(ag, temp, _list, _lhs, body, null, Span, _lhs.End, null, null);
 }
Beispiel #13
0
        internal override MSAst.Expression Transform(AstGenerator ag) {
            // allocated all variables here so they won't be shared w/ other 
            // locals allocated during the body or except blocks.
            MSAst.ParameterExpression noNestedException = null;
            if (_finally != null) {
                noNestedException = ag.GetTemporary("$noException", typeof(bool));
            }

            MSAst.ParameterExpression lineUpdated = null;
            MSAst.ParameterExpression runElse = null;

            if (_else != null || (_handlers != null && _handlers.Length > 0)) {
                lineUpdated = ag.GetTemporary("$lineUpdated", typeof(bool));
                if (_else != null) {
                    runElse = ag.GetTemporary("run_else", typeof(bool));
                }
            }

            // don't allocate locals below here...
            MSAst.Expression body = ag.Transform(_body);
            MSAst.Expression @else = ag.Transform(_else);

            if (body == null) {
                return null;
            }

            MSAst.ParameterExpression exception;
            MSAst.Expression @catch = TransformHandlers(ag, out exception);
            MSAst.Expression result;

            // We have else clause, must generate guard around it
            if (@else != null) {
                Debug.Assert(@catch != null);

                //  run_else = true;
                //  try {
                //      try_body
                //  } catch ( ... ) {
                //      run_else = false;
                //      catch_body
                //  }
                //  if (run_else) {
                //      else_body
                //  }
                result =
                    Ast.Block(
                        Ast.Assign(runElse, Ast.Constant(true)),
                        // save existing line updated, we could choose to do this only for nested exception handlers.
                        ag.PushLineUpdated(false, lineUpdated),
                        AstUtils.Try(
                            ag.AddDebugInfo(Ast.Empty(), new SourceSpan(Span.Start, _header)),
                            body
                        ).Catch(exception,
                            Ast.Assign(runElse, Ast.Constant(false)),
                            @catch,
                            // restore existing line updated after exception handler completes
                            ag.PopLineUpdated(lineUpdated),
                            Ast.Default(body.Type)
                        ),
                        AstUtils.IfThen(runElse,
                            @else
                        ),
                        Ast.Empty()
                    );

            } else if (@catch != null) {        // no "else" clause
                //  try {
                //      <try body>
                //  } catch (Exception e) {
                //      ... catch handling ...
                //  }
                //
                result = AstUtils.Try(
                        ag.AddDebugInfo(Ast.Empty(), new SourceSpan(Span.Start, _header)),
                        // save existing line updated
                        ag.PushLineUpdated(false, lineUpdated),
                        body
                    ).Catch(exception,
                        @catch,
                        // restore existing line updated after exception handler completes
                        ag.PopLineUpdated(lineUpdated),
                        Ast.Default(body.Type)
                    );
            } else {
                result = body;
            }

            try {
                return AddFinally(ag, result, noNestedException);
            } finally {
                // free all locals here after the children nodes have been generated
                if (lineUpdated != null) {
                    ag.FreeTemp(lineUpdated);
                }
                if (runElse != null) {
                    ag.FreeTemp(@runElse);
                }
            }
        }
Beispiel #14
0
        internal MSAst.Expression TransformToFunctionExpression(AstGenerator ag) {
            string name;

            if (IsLambda) {
                name = "<lambda$" + Interlocked.Increment(ref _lambdaId) + ">";
            } else {
                name = SymbolTable.IdToString(_name);
            }

            // Create AST generator to generate the body with
            AstGenerator bodyGen = new AstGenerator(ag, name, IsGenerator, false);
            bodyGen.DisableInterpreter = true;

            // Transform the parameters.
            // Populate the list of the parameter names and defaults.
            List<MSAst.Expression> defaults = new List<MSAst.Expression>(0);
            List<MSAst.Expression> names = new List<MSAst.Expression>();
            TransformParameters(ag, bodyGen, defaults, names);

            List<MSAst.Expression> statements = new List<MSAst.Expression>();

            // Create variables and references. Since references refer to
            // parameters, do this after parameters have been created.
            CreateVariables(bodyGen, statements);

            // Initialize parameters - unpack tuples.
            // Since tuples unpack into locals, this must be done after locals have been created.
            InitializeParameters(bodyGen, statements);

            // For generators, we need to do a check before the first statement for Generator.Throw() / Generator.Close().
            // The exception traceback needs to come from the generator's method body, and so we must do the check and throw
            // from inside the generator.
            if (IsGenerator) {
                MSAst.Expression s1 = YieldExpression.CreateCheckThrowExpression(bodyGen, SourceSpan.None);
                statements.Add(s1);
            }
            
            MSAst.ParameterExpression extracted = null;
            if (!IsGenerator && _canSetSysExcInfo) {
                // need to allocate the exception here so we don't share w/ exceptions made & freed
                // during the body.
                extracted = bodyGen.GetTemporary("$ex", typeof(Exception));
            }

            // Transform the body and add the resulting statements into the list
            TransformBody(bodyGen, statements);

            if (ag.DebugMode) {
                // add beginning and ending break points for the function.
                if (GetExpressionEnd(statements[statements.Count - 1]) != Body.End) {
                    statements.Add(ag.AddDebugInfo(Ast.Empty(), new SourceSpan(Body.End, Body.End)));
                }
            }

            MSAst.Expression body = Ast.Block(new ReadOnlyCollection<MSAst.Expression>(statements.ToArray()));

            // If this function can modify sys.exc_info() (_canSetSysExcInfo), then it must restore the result on finish.
            // 
            // Wrap in 
            //   $temp = PythonOps.SaveCurrentException()
            //   <body>
            //   PythonOps.RestoreCurrentException($temp)
            // Skip this if we're a generator. For generators, the try finally is handled by the PythonGenerator class 
            //  before it's invoked. This is because the restoration must occur at every place the function returns from 
            //  a yield point. That's different than the finally semantics in a generator.
            if (extracted != null) {
                MSAst.Expression s = AstUtils.Try(
                    Ast.Assign(
                        extracted,
                        Ast.Call(
                            AstGenerator.GetHelperMethod("SaveCurrentException")
                        )
                    ),
                    body
                ).Finally(
                    Ast.Call(
                        AstGenerator.GetHelperMethod("RestoreCurrentException"), extracted
                    )
                );
                body = s;
            }

            body = bodyGen.WrapScopeStatements(body);
            bodyGen.Block.Body = bodyGen.AddReturnTarget(body);

            FunctionAttributes flags = ComputeFlags(_parameters);
            bool needsWrapperMethod = flags != FunctionAttributes.None;
            if (_canSetSysExcInfo) {
                flags |= FunctionAttributes.CanSetSysExcInfo;
            }

            MSAst.Expression code;
            if (IsGenerator) {
                code = bodyGen.Block.MakeGenerator(bodyGen.GeneratorLabel, GetGeneratorDelegateType(_parameters, needsWrapperMethod));
                flags |= FunctionAttributes.Generator;
            } else {
                code = bodyGen.Block.MakeLambda(GetDelegateType(_parameters, needsWrapperMethod));
            }

            MSAst.Expression ret = Ast.Call(
                null,                                                                                   // instance
                typeof(PythonOps).GetMethod("MakeFunction"),                                            // method
                new ReadOnlyCollection<MSAst.Expression>(
                    new [] {
                        AstUtils.CodeContext(),                                                         // 1. Emit CodeContext
                        Ast.Constant(name),                                                             // 2. FunctionName
                        code,                                                                           // 3. delegate
                        names.Count == 0 ?                                                              // 4. parameter names
                            Ast.Constant(null, typeof(string[])) :
                            (MSAst.Expression)Ast.NewArrayInit(typeof(string), names),
                        defaults.Count == 0 ?                                                           // 5. default values
                            Ast.Constant(null, typeof(object[])) :
                            (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults),                                   
                        Ast.Constant(flags),                                                            // 6. flags
                        Ast.Constant(ag.GetDocumentation(_body), typeof(string)),                       // 7. doc string or null
                        Ast.Constant(this.Start.Line),                                                  // 8. line number
                        Ast.Constant(_sourceUnit.Path, typeof(string))                                  // 9. filename
                    }
                )
            );

            ret = ag.AddDecorators(ret, _decorators);

            return ret;
        }
Beispiel #15
0
        private MSAst.Expression AddFinally(AstGenerator/*!*/ ag, MSAst.Expression/*!*/ body, MSAst.ParameterExpression noNestedException) {
            if (_finally != null) {
                Debug.Assert(noNestedException != null);

                MSAst.ParameterExpression nestedFrames = ag.GetTemporary("$nestedFrames", typeof(List<DynamicStackFrame>));

                bool inFinally = ag.InFinally;
                ag.InFinally = true;
                MSAst.Expression @finally = ag.Transform(_finally);
                ag.InFinally = inFinally;
                if (@finally == null) {
                    // error reported during compilation
                    return null;
                }

                if (ag.TrackLines) {
                    // lots is going on here.  We need to consider:
                    //      1. Exceptions propagating out of try/except/finally.  Here we need to save the line #
                    //          from the exception block and not save the # from the finally block later.
                    //      2. Exceptions propagating out of the finally block.  Here we need to report the line number
                    //          from the finally block and leave the existing stack traces cleared.
                    //      3. Returning from the try block: Here we need to run the finally block and not update the
                    //          line numbers.
                    body = AstUtils.Try(// we use a filter to know when we have an exception and when control leaves normally (via
                        // either a return or the body completing successfully).
                        AstUtils.Try(
                            ag.AddDebugInfo(Ast.Empty(), new SourceSpan(Span.Start, _header)),
                            Ast.Assign(noNestedException, Ast.Constant(true)),
                            body
                        ).Filter(
                            typeof(Exception),
                        // condition is never true, just note the exception and let it propagate
                            Ast.Equal(
                                Ast.Assign(noNestedException, Ast.Constant(false)),
                                Ast.Constant(true)
                            ),
                            Ast.Default(body.Type)
                        )
                    ).Finally(
                        // if we had an exception save the line # that was last executing during the try
                        AstUtils.If(
                            Ast.Not(noNestedException),
                            ag.GetLineNumberUpdateExpression(false)
                        ),

                        // clear the frames incase thae finally throws, and allow line number
                        // updates to proceed
                        ag.UpdateLineUpdated(false),
                        Ast.Assign(
                            nestedFrames,
                            Ast.Call(AstGenerator.GetHelperMethod("GetAndClearDynamicStackFrames"))
                        ),

                        // run the finally code
                        @finally,

                        // if the finally exits normally restore any previous exception info
                        Ast.Call(
                            AstGenerator.GetHelperMethod("SetDynamicStackFrames"),
                            nestedFrames
                        ),
                        ag.UpdateLineUpdated(true)
                    );

                    ag.FreeTemp(nestedFrames);
                    ag.FreeTemp(noNestedException);
                } else {
                    body = AstUtils.Try(body).Finally(
                            Ast.Assign(
                                nestedFrames,
                                Ast.Call(AstGenerator.GetHelperMethod("GetAndClearDynamicStackFrames"))
                            ),

                            // run the finally code
                            @finally,

                            // if the finally exits normally restore any previous exception info
                            Ast.Call(
                                AstGenerator.GetHelperMethod("SetDynamicStackFrames"),
                                nestedFrames
                            )
                        );
                }
            }
            return body;
        }
Beispiel #16
0
        /// <summary>
        /// Transform multiple python except handlers for a try block into a single catch body.
        /// </summary>
        /// <param name="ag"></param>
        /// <param name="variable">The variable for the exception in the catch block.</param>
        /// <returns>Null if there are no except handlers. Else the statement to go inside the catch handler</returns>
        private MSAst.Expression TransformHandlers(AstGenerator ag, out MSAst.ParameterExpression variable) {
            if (_handlers == null || _handlers.Length == 0) {
                variable = null;
                return null;
            }

            MSAst.ParameterExpression exception = ag.GetTemporary("exception", typeof(Exception));
            MSAst.ParameterExpression extracted = ag.GetTemporary("extracted", typeof(object));

            // The variable where the runtime will store the exception.
            variable = exception;

            var tests = new List<Microsoft.Scripting.Ast.IfStatementTest>(_handlers.Length);
            MSAst.ParameterExpression converted = null;
            MSAst.Expression catchAll = null;

            for (int index = 0; index < _handlers.Length; index++) {
                TryStatementHandler tsh = _handlers[index];

                if (tsh.Test != null) {
                    Microsoft.Scripting.Ast.IfStatementTest ist;

                    //  translating:
                    //      except Test ...
                    //
                    //  generate following AST for the Test (common part):
                    //      CheckException(exception, Test)
                    MSAst.Expression test =
                        Ast.Call(
                            AstGenerator.GetHelperMethod("CheckException"),
                            extracted,
                            ag.TransformAsObject(tsh.Test)
                        );

                    if (tsh.Target != null) {
                        //  translating:
                        //      except Test, Target:
                        //          <body>
                        //  into:
                        //      if ((converted = CheckException(exception, Test)) != null) {
                        //          Target = converted;
                        //          traceback-header
                        //          <body>
                        //      }

                        if (converted == null) {
                            converted = ag.GetTemporary("converted");
                        }

                        ist = AstUtils.IfCondition(
                            Ast.NotEqual(
                                Ast.Assign(converted, test),
                                Ast.Constant(null)
                            ),
                            Ast.Block(
                                tsh.Target.TransformSet(ag, SourceSpan.None, converted, Operators.None),
                                GetTracebackHeader(
                                    new SourceSpan(tsh.Start, tsh.Header),
                                    ag,
                                    exception,
                                    ag.Transform(tsh.Body)
                                ),
                                Ast.Empty()
                            )
                        );
                    } else {
                        //  translating:
                        //      except Test:
                        //          <body>
                        //  into:
                        //      if (CheckException(exception, Test) != null) {
                        //          traceback-header
                        //          <body>
                        //      }
                        ist = AstUtils.IfCondition(
                            Ast.NotEqual(
                                test,
                                Ast.Constant(null)
                            ),
                            GetTracebackHeader(
                                new SourceSpan(tsh.Start, tsh.Header),
                                ag,
                                exception,
                                ag.Transform(tsh.Body)
                            )
                        );
                    }

                    // Add the test to the if statement test cascade
                    tests.Add(ist);
                } else {
                    Debug.Assert(index == _handlers.Length - 1);
                    Debug.Assert(catchAll == null);

                    //  translating:
                    //      except:
                    //          <body>
                    //  into:
                    //  {
                    //          traceback-header
                    //          <body>
                    //  }

                    catchAll = GetTracebackHeader(new SourceSpan(tsh.Start, tsh.Header), ag, exception, ag.Transform(tsh.Body));
                }
            }

            MSAst.Expression body = null;

            if (tests.Count > 0) {
                // rethrow the exception if we have no catch-all block
                if (catchAll == null) {
                    catchAll = Ast.Throw(exception);
                }

                body = AstUtils.If(
                    tests.ToArray(),
                    catchAll
                );
            } else {
                Debug.Assert(catchAll != null);
                body = catchAll;
            }

            if (converted != null) {
                ag.FreeTemp(converted);
            }
            ag.FreeTemp(exception);
            ag.FreeTemp(extracted);

            // Codegen becomes:
            //     extracted = PythonOps.SetCurrentException(exception)
            //      < dynamic exception analysis >
            return Ast.Block(
                Ast.Assign(
                    extracted,
                    Ast.Call(
                        AstGenerator.GetHelperMethod("SetCurrentException"),
                        AstUtils.CodeContext(),
                        exception
                    )
                ),
                body,
                Ast.Empty()
            );
        }
Beispiel #17
0
        private MSAst.Expression AddFinally(AstGenerator/*!*/ ag, MSAst.Expression/*!*/ body, MSAst.ParameterExpression nestedException) {
            if (_finally != null) {
                bool isEmitting = ag._isEmittingFinally;
                ag._isEmittingFinally = true;
                int loopId = ++ag._loopOrFinallyId;
                ag.LoopOrFinallyIds.Add(loopId, true);
                try {
                    Debug.Assert(nestedException != null);

                    MSAst.ParameterExpression nestedFrames = ag.GetTemporary("$nestedFrames", typeof(List<DynamicStackFrame>));

                    bool inFinally = ag.InFinally;
                    ag.InFinally = true;
                    MSAst.Expression @finally = ag.Transform(_finally);
                    ag.InFinally = inFinally;
                    if (@finally == null) {
                        // error reported during compilation
                        return null;
                    }

                    // lots is going on here.  We need to consider:
                    //      1. Exceptions propagating out of try/except/finally.  Here we need to save the line #
                    //          from the exception block and not save the # from the finally block later.
                    //      2. Exceptions propagating out of the finally block.  Here we need to report the line number
                    //          from the finally block and leave the existing stack traces cleared.
                    //      3. Returning from the try block: Here we need to run the finally block and not update the
                    //          line numbers.
                    body = AstUtils.Try( // we use a fault to know when we have an exception and when control leaves normally (via
                        // either a return or the body completing successfully).
                        AstUtils.Try(
                            ag.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, _header)),
                            Ast.Assign(nestedException, AstUtils.Constant(false)),
                            body
                        ).Fault(
                        // fault
                            Ast.Assign(nestedException, AstUtils.Constant(true))
                        )
                    ).FinallyWithJumps(
                        // if we had an exception save the line # that was last executing during the try
                        AstUtils.If(
                            nestedException,
                            ag.GetSaveLineNumberExpression(false)
                        ),

                        // clear the frames incase thae finally throws, and allow line number
                        // updates to proceed
                        ag.UpdateLineUpdated(false),
                        Ast.Assign(
                            nestedFrames,
                            Ast.Call(AstGenerator.GetHelperMethod("GetAndClearDynamicStackFrames"))
                        ),

                        // run the finally code
                        @finally,

                        // if the finally exits normally restore any previous exception info
                        Ast.Call(
                            AstGenerator.GetHelperMethod("SetDynamicStackFrames"),
                            nestedFrames
                        ),

                        // if we took an exception in the try block we have saved the line number.  Otherwise
                        // we have no line number saved and will need to continue saving them if
                        // other exceptions are thrown.
                        AstUtils.If(                            
                            nestedException,
                            ag.UpdateLineUpdated(true)
                        )
                    );
                    ag.FreeTemp(nestedFrames);
                    ag.FreeTemp(nestedException);
                } finally {
                    ag._isEmittingFinally = isEmitting;
                    ag.LoopOrFinallyIds.Remove(loopId);
                }
            }
            return body;
        }
        internal MSAst.Expression TransformToFunctionExpression(AstGenerator ag) {
            string name;

            if (IsLambda) {
                name = "<lambda$" + Interlocked.Increment(ref _lambdaId) + ">";
            } else {
                name = _name;
            }

            if (ag.PyContext.PythonOptions.FullFrames) {
                // force a dictionary if we have enabled full frames for sys._getframe support
                NeedsLocalsDictionary = true;
            }

            // Create AST generator to generate the body with
            AstGenerator bodyGen = new AstGenerator(ag, name, IsGenerator, MakeProfilerName(name));

            FunctionAttributes flags = ComputeFlags(_parameters);
            bool needsWrapperMethod = _parameters.Length > PythonCallTargets.MaxArgs;
            
            // Transform the parameters.
            // Populate the list of the parameter names and defaults.
            List<MSAst.Expression> defaults = new List<MSAst.Expression>(0);
            List<MSAst.Expression> names = new List<MSAst.Expression>();

            List<MSAst.Expression> init = new List<MSAst.Expression>();
            init.Add(Ast.ClearDebugInfo(ag.Document));

            TransformParameters(ag, bodyGen, defaults, names, needsWrapperMethod, init);

            MSAst.Expression parentContext;

            parentContext = MSAst.Expression.Call(_GetParentContextFromFunction, _functionParam);

            bodyGen.AddHiddenVariable(ArrayGlobalAllocator._globalContext);
            init.Add(Ast.Assign(ArrayGlobalAllocator._globalContext, Ast.Call(_GetGlobalContext, parentContext)));
            init.AddRange(bodyGen.Globals.PrepareScope(bodyGen));

            // Create variables and references. Since references refer to
            // parameters, do this after parameters have been created.
            CreateVariables(bodyGen, parentContext, init, NeedsLocalsDictionary, NeedsLocalsDictionary);

            // Initialize parameters - unpack tuples.
            // Since tuples unpack into locals, this must be done after locals have been created.
            InitializeParameters(bodyGen, init, needsWrapperMethod);

            List<MSAst.Expression> statements = new List<MSAst.Expression>();
            // add beginning sequence point
            statements.Add(bodyGen.AddDebugInfo(
                AstUtils.Empty(),
                new SourceSpan(new SourceLocation(0, Start.Line, Start.Column), new SourceLocation(0, Start.Line, Int32.MaxValue))));


            // For generators, we need to do a check before the first statement for Generator.Throw() / Generator.Close().
            // The exception traceback needs to come from the generator's method body, and so we must do the check and throw
            // from inside the generator.
            if (IsGenerator) {
                MSAst.Expression s1 = YieldExpression.CreateCheckThrowExpression(bodyGen, SourceSpan.None);
                statements.Add(s1);
            }

            if (NeedsLocalsDictionary || ContainsNestedFreeVariables) {
                bodyGen.CreateNestedContext();
            }

            MSAst.ParameterExpression extracted = null;
            if (!IsGenerator && _canSetSysExcInfo) {
                // need to allocate the exception here so we don't share w/ exceptions made & freed
                // during the body.
                extracted = bodyGen.GetTemporary("$ex", typeof(Exception));
            }

            // Transform the body and add the resulting statements into the list
            if (!TryTransformBody(bodyGen, statements)) {
                // there's an error in the body
                return null;
            }

            MSAst.Expression body = Ast.Block(statements);

            // If this function can modify sys.exc_info() (_canSetSysExcInfo), then it must restore the result on finish.
            // 
            // Wrap in 
            //   $temp = PythonOps.SaveCurrentException()
            //   <body>
            //   PythonOps.RestoreCurrentException($temp)
            // Skip this if we're a generator. For generators, the try finally is handled by the PythonGenerator class 
            //  before it's invoked. This is because the restoration must occur at every place the function returns from 
            //  a yield point. That's different than the finally semantics in a generator.
            if (extracted != null) {
                MSAst.Expression s = AstUtils.Try(
                    Ast.Assign(
                        extracted,
                        Ast.Call(
                            AstGenerator.GetHelperMethod("SaveCurrentException")
                        )
                    ),
                    body
                ).Finally(
                    Ast.Call(
                        AstGenerator.GetHelperMethod("RestoreCurrentException"), extracted
                    )
                );
                body = s;
            }

            if (_body.CanThrow && ag.PyContext.PythonOptions.Frames) {
                body = AstGenerator.AddFrame(bodyGen.LocalContext, Ast.Property(_functionParam, typeof(PythonFunction).GetProperty("__code__")), body);
                bodyGen.AddHiddenVariable(AstGenerator._functionStack);
            }

            body = bodyGen.AddProfiling(body);
            body = bodyGen.WrapScopeStatements(body);
            body = bodyGen.AddReturnTarget(body);

            if (_canSetSysExcInfo) {
                flags |= FunctionAttributes.CanSetSysExcInfo;
            }

            if (ContainsTryFinally) {
                flags |= FunctionAttributes.ContainsTryFinally;
            }

            if (IsGenerator) {
                flags |= FunctionAttributes.Generator;
            }

            MSAst.Expression bodyStmt = bodyGen.MakeBody(
                parentContext, 
                init.ToArray(), 
                body
            );

            Delegate originalDelegate;
            MSAst.LambdaExpression code = Ast.Lambda(
                GetDelegateType(_parameters, needsWrapperMethod, out originalDelegate),
                AstGenerator.AddDefaultReturn(bodyStmt, typeof(object)),
                bodyGen.Name + "$" + _lambdaId++,
                bodyGen.Parameters
            );

            // create the function code object which all function instances will share
            MSAst.Expression funcCode = ag.Globals.GetConstant(
                new FunctionCode(
                    ag.PyContext,
                    EmitDebugFunction(ag) ? null : originalDelegate,
                    code,
                    name,
                    ag.GetDocumentation(_body),
                    ArrayUtils.ConvertAll(_parameters, (val) => val.Name),
                    flags,
                    Span,
                    _sourceUnit.Path,
                    ag.EmitDebugSymbols,
                    ag.ShouldInterpret,
                    FreeVariables,
                    GlobalVariables,
                    CellVariables,
                    GetVarNames(),
                    Variables == null ? 0 : Variables.Count,
                    bodyGen.LoopLocationsNoCreate,
                    bodyGen.HandlerLocationsNoCreate
                )                
            );
            bodyGen.FuncCodeExpr = funcCode;

            MSAst.Expression ret;
            if (EmitDebugFunction(ag)) {
                // we need to compile all of the debuggable code together at once otherwise mdbg gets confused.  If we're
                // in tracing mode we'll still compile things one off though just to keep things simple.  The code will still
                // be debuggable but naive debuggers like mdbg will have more issues.
                ret = Ast.Call(
                    _MakeFunctionDebug,                                                             // method
                    ag.LocalContext,                                                                // 1. Emit CodeContext
                    funcCode,                                                                       // 2. FunctionCode
                    ((IPythonGlobalExpression)ag.Globals.GetVariable(ag, _nameVariable)).RawValue(),// 3. module name
                    defaults.Count == 0 ?                                                           // 4. default values
                        AstUtils.Constant(null, typeof(object[])) :
                        (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults),
                    IsGenerator ? 
                        (MSAst.Expression)new PythonGeneratorExpression(code) :
                        (MSAst.Expression)code
                );
            } else {
                ret = Ast.Call(
                    _MakeFunction,                                                                  // method
                    ag.LocalContext,                                                                // 1. Emit CodeContext
                    funcCode,                                                                       // 2. FunctionCode
                    ((IPythonGlobalExpression)ag.Globals.GetVariable(ag, _nameVariable)).RawValue(),// 3. module name
                    defaults.Count == 0 ?                                                           // 4. default values
                        AstUtils.Constant(null, typeof(object[])) :
                        (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults)
                );
            }

            ret = ag.AddDecorators(ret, _decorators);

            return ret;
        }
Beispiel #19
0
        internal MSAst.Expression TransformToFunctionExpression(AstGenerator ag) {
            string name;

            if (IsLambda) {
                name = "<lambda$" + Interlocked.Increment(ref _lambdaId) + ">";
            } else {
                name = SymbolTable.IdToString(_name);
            }

            // Create AST generator to generate the body with
            AstGenerator bodyGen = new AstGenerator(ag, name, IsGenerator, MakeProfilerName(name));
            FunctionAttributes flags = ComputeFlags(_parameters);
            bool needsWrapperMethod = flags != FunctionAttributes.None || _parameters.Length > PythonCallTargets.MaxArgs;
            
            // Transform the parameters.
            // Populate the list of the parameter names and defaults.
            List<MSAst.Expression> defaults = new List<MSAst.Expression>(0);
            List<MSAst.Expression> names = new List<MSAst.Expression>();

            List<MSAst.Expression> init = new List<MSAst.Expression>();
            TransformParameters(ag, bodyGen, defaults, names, needsWrapperMethod, init);

            MSAst.Expression parentContext;
            
            parentContext = MSAst.Expression.Call(typeof(PythonOps).GetMethod("GetParentContextFromFunction"), _functionParam);

            bodyGen.AddHiddenVariable(ArrayGlobalAllocator._globalContext);
            init.Add(Ast.Assign(ArrayGlobalAllocator._globalContext, Ast.Call(typeof(PythonOps).GetMethod("GetGlobalContext"), parentContext)));
            init.AddRange(bodyGen.Globals.PrepareScope(bodyGen));

            // Create variables and references. Since references refer to
            // parameters, do this after parameters have been created.
            CreateVariables(bodyGen, parentContext, init, NeedsLocalsDictionary, NeedsLocalsDictionary);

            // Initialize parameters - unpack tuples.
            // Since tuples unpack into locals, this must be done after locals have been created.
            InitializeParameters(bodyGen, init, needsWrapperMethod);

            List<MSAst.Expression> statements = new List<MSAst.Expression>();

            // For generators, we need to do a check before the first statement for Generator.Throw() / Generator.Close().
            // The exception traceback needs to come from the generator's method body, and so we must do the check and throw
            // from inside the generator.
            if (IsGenerator) {
                MSAst.Expression s1 = YieldExpression.CreateCheckThrowExpression(bodyGen, SourceSpan.None);
                statements.Add(s1);
            }

            if (NeedsLocalsDictionary || ContainsNestedFreeVariables) {
                bodyGen.CreateNestedContext();
            }

            MSAst.ParameterExpression extracted = null;
            if (!IsGenerator && _canSetSysExcInfo) {
                // need to allocate the exception here so we don't share w/ exceptions made & freed
                // during the body.
                extracted = bodyGen.GetTemporary("$ex", typeof(Exception));
            }

            // Transform the body and add the resulting statements into the list
            if (!TryTransformBody(bodyGen, statements)) {
                // there's an error in the body
                return null;
            }

            if (ag.DebugMode) {
                // add beginning and ending break points for the function.
                if (GetExpressionEnd(statements[statements.Count - 1]) != Body.End) {
                    statements.Add(ag.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Body.End, Body.End)));
                }
            }

            MSAst.Expression body = Ast.Block(new ReadOnlyCollection<MSAst.Expression>(statements.ToArray()));

            // If this function can modify sys.exc_info() (_canSetSysExcInfo), then it must restore the result on finish.
            // 
            // Wrap in 
            //   $temp = PythonOps.SaveCurrentException()
            //   <body>
            //   PythonOps.RestoreCurrentException($temp)
            // Skip this if we're a generator. For generators, the try finally is handled by the PythonGenerator class 
            //  before it's invoked. This is because the restoration must occur at every place the function returns from 
            //  a yield point. That's different than the finally semantics in a generator.
            if (extracted != null) {
                MSAst.Expression s = AstUtils.Try(
                    Ast.Assign(
                        extracted,
                        Ast.Call(
                            AstGenerator.GetHelperMethod("SaveCurrentException")
                        )
                    ),
                    body
                ).Finally(
                    Ast.Call(
                        AstGenerator.GetHelperMethod("RestoreCurrentException"), extracted
                    )
                );
                body = s;
            }

            body = bodyGen.AddProfiling(body);
            body = bodyGen.WrapScopeStatements(body);
            body = bodyGen.AddReturnTarget(body);

            if (_canSetSysExcInfo) {
                flags |= FunctionAttributes.CanSetSysExcInfo;
            }
            MSAst.Expression bodyStmt = bodyGen.MakeBody(
                parentContext, 
                init.ToArray(), 
                body, 
                true
            );

            if (ContainsTryFinally) {
                flags |= FunctionAttributes.ContainsTryFinally;
            }

            MSAst.LambdaExpression code;
            Delegate originalDelegate;
            if (IsGenerator) {
                code = Ast.Lambda(
                    GetDelegateType(_parameters, needsWrapperMethod, out originalDelegate),
                    new PythonGeneratorExpression(bodyGen.Name + "$" + _lambdaId++, bodyStmt, ag.ShouldInterpret, ag.EmitDebugSymbols, bodyGen.Parameters, bodyGen.GeneratorLabel),
                    bodyGen.Name + "$" + _lambdaId++,
                    bodyGen.Parameters
                );
                flags |= FunctionAttributes.Generator;
            } else {
                code = Ast.Lambda(
                    GetDelegateType(_parameters, needsWrapperMethod, out originalDelegate),
                    AstGenerator.AddDefaultReturn(bodyStmt, typeof(object)),
                    bodyGen.Name + "$" + _lambdaId++,
                    bodyGen.Parameters
                );
            }

            MSAst.Expression startingDelegate;
            if (ag.Globals is SavableGlobalAllocator || ag.EmitDebugSymbols) {
                startingDelegate = code;
            } else {
                startingDelegate = Ast.Constant(originalDelegate);
            }

            MSAst.Expression ret = Ast.Call(
                null,                                                                                   // instance
                typeof(PythonOps).GetMethod("MakeFunction"),                                            // method
                new ReadOnlyCollection<MSAst.Expression>(
                    new [] {
                        ag.LocalContext,                                                                // 1. Emit CodeContext
                        startingDelegate,                                                               // 2. initial callable delegate
                        Ast.Constant(                                                                   // 3. function info
                            new FunctionInfo(                                                               
                                name, 
                                ag.GetDocumentation(_body), 
                                ArrayUtils.ConvertAll<Parameter, string>(_parameters, (val) => SymbolTable.IdToString(val.Name)),
                                flags, 
                                Start.Line, 
                                _sourceUnit.Path,
                                code,
                                ag.ShouldInterpret
                            )
                        ),
                        ((IPythonGlobalExpression)ag.Globals.GetVariable(ag, _nameVariable)).RawValue(),
                        defaults.Count == 0 ?                                                           // 4. default values
                            AstUtils.Constant(null, typeof(object[])) :
                            (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults)
                    }
                )
            );

            ret = ag.AddDecorators(ret, _decorators);

            return ret;
        }
Beispiel #20
0
        private MSAst.Expression AssignOne(AstGenerator ag) {
            Debug.Assert(_left.Length == 1);

            SequenceExpression seLeft = _left[0] as SequenceExpression;
            SequenceExpression seRight = _right as SequenceExpression;

            if (seLeft != null && seRight != null && seLeft.Items.Length == seRight.Items.Length) {
                int cnt = seLeft.Items.Length;

                // a, b = 1, 2, or [a,b] = 1,2 - not something like a, b = range(2)
                // we can do a fast parallel assignment
                MSAst.ParameterExpression[] tmps = new MSAst.ParameterExpression[cnt];
                MSAst.Expression[] body = new MSAst.Expression[cnt * 2 + 1];

                // generate the body, the 1st n are the temporary assigns, the
                // last n are the assignments to the left hand side
                // 0: tmp0 = right[0]
                // ...
                // n-1: tmpn-1 = right[n-1]
                // n: right[0] = tmp0
                // ...
                // n+n-1: right[n-1] = tmpn-1

                // allocate the temps first before transforming so we don't pick up a bad temp...
                for (int i = 0; i < cnt; i++) {
                    MSAst.Expression tmpVal = ag.Transform(seRight.Items[i]);
                    tmps[i] = ag.GetTemporary("parallelAssign", tmpVal.Type);

                    body[i] = Ast.Assign(tmps[i], tmpVal);
                }

                // then transform which can allocate more temps
                for (int i = 0; i < cnt; i++) {
                    body[i + cnt] = seLeft.Items[i].TransformSet(ag, SourceSpan.None, tmps[i], PythonOperationKind.None);
                }

                // finally free the temps.
                foreach (MSAst.ParameterExpression variable in tmps) {
                    ag.FreeTemp(variable);
                }

                // 4. Create and return the resulting suite
                body[cnt * 2] = AstUtils.Empty();
                return ag.AddDebugInfo(Ast.Block(body), Span);
            }

            return _left[0].TransformSet(ag, Span, ag.Transform(_right), PythonOperationKind.None);
        }
Beispiel #21
0
        /// <summary>
        /// WithStatement is translated to the DLR AST equivalent to
        /// the following Python code snippet (from with statement spec):
        /// 
        /// mgr = (EXPR)
        /// exit = mgr.__exit__  # Not calling it yet
        /// value = mgr.__enter__()
        /// exc = True
        /// try:
        ///     VAR = value  # Only if "as VAR" is present
        ///     BLOCK
        /// except:
        ///     # The exceptional case is handled here
        ///     exc = False
        ///     if not exit(*sys.exc_info()):
        ///         raise
        ///     # The exception is swallowed if exit() returns true
        /// finally:
        ///     # The normal and non-local-goto cases are handled here
        ///     if exc:
        ///         exit(None, None, None)
        /// 
        /// </summary>
        internal override MSAst.Expression Transform(AstGenerator ag) {
            // Five statements in the result...
            MSAst.Expression[] statements = new MSAst.Expression[6];

            //******************************************************************
            // 1. mgr = (EXPR)
            //******************************************************************
            MSAst.ParameterExpression manager = ag.GetTemporary("with_manager");
            statements[0] = ag.MakeAssignment(
                manager,
                ag.Transform(_contextManager),
                new SourceSpan(Start, _header)
            );

            //******************************************************************
            // 2. exit = mgr.__exit__  # Not calling it yet
            //******************************************************************
            MSAst.ParameterExpression exit = ag.GetTemporary("with_exit");
            statements[1] = ag.MakeAssignment(
                exit,
                Binders.Get(
                    ag.BinderState,
                    typeof(object),
                    "__exit__",
                    manager
                )
            );

            //******************************************************************
            // 3. value = mgr.__enter__()
            //******************************************************************
            MSAst.ParameterExpression value = ag.GetTemporary("with_value");
            statements[2] = ag.MakeAssignment(
                value,
                Binders.Invoke(
                    ag.BinderState,
                    typeof(object),
                    new CallSignature(0),
                    Binders.Get(
                        ag.BinderState,
                        typeof(object),
                        "__enter__",
                        manager
                    )
                )
            );

            //******************************************************************
            // 4. exc = True
            //******************************************************************
            MSAst.ParameterExpression exc = ag.GetTemporary("with_exc", typeof(bool));
            statements[3] = ag.MakeAssignment(
                exc,
                Ast.Constant(true)
            );

            //******************************************************************
            //  5. The final try statement:
            //
            //  try:
            //      VAR = value  # Only if "as VAR" is present
            //      BLOCK
            //  except:
            //      # The exceptional case is handled here
            //      exc = False
            //      if not exit(*sys.exc_info()):
            //          raise
            //      # The exception is swallowed if exit() returns true
            //  finally:
            //      # The normal and non-local-goto cases are handled here
            //      if exc:
            //          exit(None, None, None)
            //******************************************************************

            MSAst.ParameterExpression exception = ag.GetTemporary("exception", typeof(Exception));

            statements[4] =
                // try:
                AstUtils.Try(// try statement body
                    _var != null ?
                        ag.AddDebugInfo(
                            Ast.Block(
                // VAR = value
                                _var.TransformSet(ag, SourceSpan.None, value, Operators.None),
                // BLOCK
                                ag.Transform(_body),
                                Ast.Empty()
                            ),
                            _body.Span
                        ) :
                // BLOCK
                        ag.Transform(_body) // except:, // try statement location
                ).Catch(exception,
                    Ast.Block(
                // Python specific exception handling code
                        Ast.Call(
                            AstGenerator.GetHelperMethod("ClearDynamicStackFrames")
                        ),
                // exc = False
                        ag.MakeAssignment(
                            exc,
                            Ast.Constant(false)
                        ),
                //  if not exit(*sys.exc_info()):
                //      raise
                        AstUtils.IfThen(
                            Binders.Convert(
                                ag.BinderState,
                                typeof(bool),
                                ConversionResultKind.ExplicitCast,
                                Binders.Operation(
                                    ag.BinderState,
                                    typeof(object),
                                    StandardOperators.Not,
                                    MakeExitCall(ag, exit, exception)
                                )
                            ),
                            Ast.Rethrow()
                        ),
                        Ast.Empty()
                    )
                // finally:
                ).Finally(
                //  if exc:
                //      exit(None, None, None)
                    AstUtils.IfThen(
                        exc,
                        ag.AddDebugInfo(
                            Ast.Dynamic(
                                new PythonInvokeBinder(
                                    ag.BinderState,
                                    new CallSignature(3)        // signature doesn't include function
                                ),
                                typeof(object),
                                new MSAst.Expression[] {
                                    AstUtils.CodeContext(),
                                    exit,
                                    Ast.Constant(null),
                                    Ast.Constant(null),
                                    Ast.Constant(null)
                                }
                            ),
                            _contextManager.Span
                        )
                    )
                );
            statements[4] = ag.AddDebugInfo(statements[4], Span);

            statements[5] = Ast.Empty();
            return ag.AddDebugInfo(Ast.Block(statements), _body.Span);
        }
Beispiel #22
0
        internal override MSAst.Expression TransformSet(AstGenerator ag, SourceSpan span, MSAst.Expression right, Operators op) {
            if (op != Operators.None) {
                ag.AddError("augmented assign to sequence prohibited", Span);
                return null;
            }

            // 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;
            }

            MSAst.Expression[] statements = new MSAst.Expression[4];

            // 1. Evaluate the expression and assign the value to the temp.
            MSAst.ParameterExpression right_temp = ag.GetTemporary("unpacking");

            // 2. Add the assignment "right_temp = right" into the suite/block
            statements[0] = ag.MakeAssignment(right_temp, right);

            // 3. Call GetEnumeratorValues on the right side (stored in temp)
            MSAst.Expression enumeratorValues = Ast.Call(
                AstGenerator.GetHelperMethod("GetEnumeratorValues"),    // method
                // arguments
                AstUtils.CodeContext(),
                right_temp,
                Ast.Constant(_items.Length)
            );

            // 4. Create temporary variable for the array
            MSAst.ParameterExpression array_temp = ag.GetTemporary("array", typeof(object[]));

            // 5. Assign the value of the method call (mce) into the array temp
            // And add the assignment "array_temp = Ops.GetEnumeratorValues(...)" into the block
            statements[1] = ag.MakeAssignment(
                array_temp, 
                enumeratorValues, 
                rightSpan
            );

            MSAst.Expression[] sets = new 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 = Ast.ArrayAccess(
                    array_temp,                             // array expression
                    Ast.Constant(i)                         // index
                );

                // 7. target = array_temp[i], and add the transformed assignment into the list of sets
                MSAst.Expression set = target.TransformSet(
                    ag,
                    emitIndividualSets ?                    // span
                        target.Span :
                        SourceSpan.None,
                    element,
                    Operators.None
                );
                if (set == null) {
                    throw PythonOps.SyntaxError(string.Format("can't assign to {0}", target.NodeName), ag.Context.SourceUnit, target.Span, -1);
                }

                sets[i] = set;
            }
            // 9. add the sets as their own block so they can be marked as a single span, if necessary.
            sets[_items.Length] = Ast.Empty();
            statements[2] = ag.AddDebugInfo(Ast.Block(sets), leftSpan);

            // 10. Free the temps
            ag.FreeTemp(array_temp);
            ag.FreeTemp(right_temp);

            // 11. Return the suite statement (block)
            statements[3] = Ast.Empty();
            return ag.AddDebugInfo(Ast.Block(statements), totalSpan);
        }
Beispiel #23
0
        private static MSAst.Expression MakeBinaryOperation(AstGenerator ag, PythonOperator op, MSAst.Expression left, MSAst.Expression right, Type type, SourceSpan span) {
            if (op == PythonOperator.NotIn) {                
                return AstUtils.Convert(
                    Ast.Not(
                        ag.Operation(
                            typeof(bool),
                            PythonOperationKind.Contains,
                            left,
                            right
                        )                            
                    ),
                    type
                );
            } else if (op == PythonOperator.In) {
                return AstUtils.Convert(
                    ag.Operation(
                        typeof(bool),
                        PythonOperationKind.Contains,
                        left,
                        right
                    ),
                    type
                );
            }

            PythonOperationKind action = PythonOperatorToAction(op);
            if (action != PythonOperationKind.None) {
                // Create action expression
                if (CanEmitWarning(ag, op)) {
                    MSAst.ParameterExpression tempLeft = ag.GetTemporary("left", left.Type);
                    MSAst.ParameterExpression tempRight = ag.GetTemporary("right", right.Type);
                    return Ast.Block(
                        Ast.Call(
                            AstGenerator.GetHelperMethod("WarnDivision"),
                            ag.LocalContext,
                            AstUtils.Constant(ag.DivisionOptions),
                            AstUtils.Convert(
                                Ast.Assign(tempLeft, left),
                                typeof(object)
                            ),
                            AstUtils.Convert(
                                Ast.Assign(tempRight, right),
                                typeof(object)
                            )
                        ),
                        ag.Operation(
                            type,
                            action,
                            tempLeft,
                            tempRight
                        )
                    );
                }

                return ag.Operation(
                    type,
                    action,
                    left,
                    right
                );
            } else {
                // Call helper method
                return Ast.Call(
                    AstGenerator.GetHelperMethod(GetHelperName(op)),
                    AstGenerator.ConvertIfNeeded(left, typeof(object)),
                    AstGenerator.ConvertIfNeeded(right, typeof(object))
                );
            }
        }
Beispiel #24
0
        // This is a compound comparison operator like: a < b < c.
        // That's represented as binary operators, but it's not the same as (a<b) < c, so we do special transformations.
        // We need to:
        // - return true iff (a<b) && (b<c), but ensure that b is only evaluated once. 
        // - ensure evaluation order is correct (a,b,c)
        // - don't evaluate c if a<b is false.
        private MSAst.Expression FinishCompare(MSAst.Expression left, AstGenerator ag) {
            Debug.Assert(_right is BinaryExpression);

            BinaryExpression bright = (BinaryExpression)_right;

            // Transform the left child of my right child (the next node in sequence)
            MSAst.Expression rleft = ag.Transform(bright.Left);

            // Store it in the temp
            MSAst.ParameterExpression temp = ag.GetTemporary("chained_comparison");

            // Create binary operation: left <_op> (temp = rleft)
            MSAst.Expression comparison = MakeBinaryOperation(
                ag,
                _op,
                left,
                Ast.Assign(temp, AstUtils.Convert(rleft, temp.Type)),
                typeof(object),
                Span
            );

            MSAst.Expression rright;

            // Transform rright, comparing to temp
            if (IsComparison(bright._right)) {
                rright = bright.FinishCompare(temp, ag);
            } else {
                MSAst.Expression transformedRight = ag.Transform(bright.Right);
                rright = MakeBinaryOperation(
                    ag,
                    bright.Operator,
                    temp,
                    transformedRight,
                    typeof(object),
                    bright.Span
                );
            }

            ag.FreeTemp(temp);

            // return (left (op) (temp = rleft)) and (rright)
            return AstUtils.CoalesceTrue(
                ag.Block,
                comparison,
                rright,
                AstGenerator.GetHelperMethod("IsTrue")
            );
        }
Beispiel #25
0
        /// <summary>
        /// WithStatement is translated to the DLR AST equivalent to
        /// the following Python code snippet (from with statement spec):
        /// 
        /// mgr = (EXPR)
        /// exit = mgr.__exit__  # Not calling it yet
        /// value = mgr.__enter__()
        /// exc = True
        /// try:
        ///     VAR = value  # Only if "as VAR" is present
        ///     BLOCK
        /// except:
        ///     # The exceptional case is handled here
        ///     exc = False
        ///     if not exit(*sys.exc_info()):
        ///         raise
        ///     # The exception is swallowed if exit() returns true
        /// finally:
        ///     # The normal and non-local-goto cases are handled here
        ///     if exc:
        ///         exit(None, None, None)
        /// 
        /// </summary>
        internal override MSAst.Expression Transform(AstGenerator ag) {            
            MSAst.ParameterExpression lineUpdated = ag.GetTemporary("$lineUpdated_with", typeof(bool));
            // Five statements in the result...
            ReadOnlyCollectionBuilder<MSAst.Expression> statements = new ReadOnlyCollectionBuilder<MSAst.Expression>(6);
            

            //******************************************************************
            // 1. mgr = (EXPR)
            //******************************************************************
            MSAst.ParameterExpression manager = ag.GetTemporary("with_manager");
            statements.Add(
                ag.MakeAssignment(
                    manager,
                    ag.Transform(_contextManager),
                    new SourceSpan(Start, _header)
                )
            );

            //******************************************************************
            // 2. exit = mgr.__exit__  # Not calling it yet
            //******************************************************************
            MSAst.ParameterExpression exit = ag.GetTemporary("with_exit");
            statements.Add(
                AstGenerator.MakeAssignment(
                    exit,
                    ag.Get(
                        typeof(object),
                        "__exit__",
                        manager
                    )
                )
            );

            //******************************************************************
            // 3. value = mgr.__enter__()
            //******************************************************************
            MSAst.ParameterExpression value = ag.GetTemporary("with_value");
            statements.Add(
                ag.AddDebugInfoAndVoid(
                    AstGenerator.MakeAssignment(
                        value,
                        ag.Invoke(
                            typeof(object),
                            new CallSignature(0),
                            ag.Get(
                                typeof(object),
                                "__enter__",
                                manager
                            )
                        )
                    ),
                    new SourceSpan(Start, _header)
                )
            );

            //******************************************************************
            // 4. exc = True
            //******************************************************************
            MSAst.ParameterExpression exc = ag.GetTemporary("with_exc", typeof(bool));
            statements.Add(
                AstGenerator.MakeAssignment(
                    exc,
                    AstUtils.Constant(true)
                )
            );

            //******************************************************************
            //  5. The final try statement:
            //
            //  try:
            //      VAR = value  # Only if "as VAR" is present
            //      BLOCK
            //  except:
            //      # The exceptional case is handled here
            //      exc = False
            //      if not exit(*sys.exc_info()):
            //          raise
            //      # The exception is swallowed if exit() returns true
            //  finally:
            //      # The normal and non-local-goto cases are handled here
            //      if exc:
            //          exit(None, None, None)
            //******************************************************************

            MSAst.ParameterExpression exception = ag.GetTemporary("exception", typeof(Exception));
            MSAst.ParameterExpression nestedFrames = ag.GetTemporary("$nestedFrames", typeof(List<DynamicStackFrame>));
            statements.Add(
                // try:
                AstUtils.Try(
                    AstUtils.Try(// try statement body
                        ag.PushLineUpdated(false, lineUpdated),
                        _var != null ?
                            Ast.Block(
                                // VAR = value
                                _var.TransformSet(ag, SourceSpan.None, value, PythonOperationKind.None),
                                // BLOCK
                                ag.Transform(_body),
                                AstUtils.Empty()
                            ) :
                            // BLOCK
                            ag.Transform(_body) // except:, // try statement location
                    ).Catch(exception,
                    // Python specific exception handling code
                        TryStatement.GetTracebackHeader(                        
                            ag,
                            exception,
                            ag.AddDebugInfoAndVoid(
                                Ast.Block(
                                    // exc = False
                                    AstGenerator.MakeAssignment(
                                        exc,
                                        AstUtils.Constant(false)
                                    ),
                                    Ast.Assign(
                                        nestedFrames,
                                        Ast.Call(AstGenerator.GetHelperMethod("GetAndClearDynamicStackFrames"))
                                    ),
                                    //  if not exit(*sys.exc_info()):
                                    //      raise
                                    AstUtils.IfThen(
                                        ag.Convert(
                                            typeof(bool),
                                            ConversionResultKind.ExplicitCast,
                                            ag.Operation(
                                                typeof(bool),
                                                PythonOperationKind.Not,
                                                MakeExitCall(ag, exit, exception)
                                            )
                                        ),
                                        ag.UpdateLineUpdated(true),
                                        Ast.Call(
                                            AstGenerator.GetHelperMethod("SetDynamicStackFrames"),
                                            nestedFrames
                                        ),
                                        Ast.Throw(
                                            Ast.Call(
                                                AstGenerator.GetHelperMethod("MakeRethrowExceptionWorker"),
                                                exception
                                            )
                                        )
                                    )
                                ),
                                _body.Span
                            )
                        ),
                        Ast.Call(
                            AstGenerator.GetHelperMethod("SetDynamicStackFrames"),
                            nestedFrames
                        ),
                        ag.PopLineUpdated(lineUpdated),
                        Ast.Empty()
                    )
                // finally:                    
                ).Finally(
                //  if exc:
                //      exit(None, None, None)
                    AstUtils.IfThen(
                        exc,
                        ag.AddDebugInfoAndVoid(
                            Ast.Block(
                                Ast.Dynamic(
                                    ag.PyContext.Invoke(
                                        new CallSignature(3)        // signature doesn't include function
                                    ),
                                    typeof(object),
                                    new MSAst.Expression[] {
                                        ag.LocalContext,
                                        exit,
                                        AstUtils.Constant(null),
                                        AstUtils.Constant(null),
                                        AstUtils.Constant(null)
                                    }
                                ),                                    
                                Ast.Empty()
                            ),
                            _contextManager.Span
                        )
                    )
                )
            );

            statements.Add(AstUtils.Empty());
            return Ast.Block(statements.ToReadOnlyCollection());
        }