Пример #1
0
        private Expression LightCatch(CatchBlock[] handlers) {
            // start off with the rethrow - just a return of the value.  Then
            // walk backwards and add each handler as a test in a cascading
            // conditional.  If all tests fail, we make it back to the return value.
            Expression rethrow = PropagateException(typeof(object));
            
            for (int i = handlers.Length - 1; i >= 0; i--) {
                var curHandler = handlers[i];

                Expression test = Expression.NotEqual(
                    Expression.Assign(
                        curHandler.Variable,
                        Expression.TypeAs(_lastException, curHandler.Test)
                    ),
                    Expression.Constant(null)
                );

                if (handlers[i].Filter != null) {
                    throw new NotSupportedException("filters for light exceptions");
                    // we could do this but the emulation wouldn't be perfect when filters
                    // run in relation to finallys
                    //test = Expression.AndAlso(test, handlers[i].Filter);
                }

                rethrow = Expression.Block(
                    new[] { curHandler.Variable },
                    Expression.Condition(
                        test,
                        Utils.Convert(handlers[i].Body, typeof(object)),
                        rethrow
                    )
                );
            }
            
            return rethrow;
        }
Пример #2
0
        private void MakeFieldRule(SetOrDeleteMemberInfo memInfo, DynamicMetaObject instance, DynamicMetaObject target, Type targetType, MemberGroup fields, DynamicMetaObject errorSuggestion)
        {
            FieldTracker field = (FieldTracker)fields[0];

            // TODO: Tmp variable for target
            if (instance != null && field.DeclaringType.IsGenericType && field.DeclaringType.GetGenericTypeDefinition() == typeof(StrongBox <>))
            {
                // work around a CLR bug where we can't access generic fields from dynamic methods.
                Type[] generic = field.DeclaringType.GetGenericArguments();
                memInfo.Body.FinishCondition(
                    MakeReturnValue(
                        Ast.Assign(
                            Ast.Field(
                                AstUtils.Convert(instance.Expression, field.DeclaringType),
                                field.DeclaringType.GetField("Value")
                                ),
                            AstUtils.Convert(target.Expression, generic[0])
                            ),
                        target
                        )
                    );
            }
            else if (field.IsInitOnly || field.IsLiteral)
            {
                memInfo.Body.FinishError(
                    errorSuggestion ?? MakeError(
                        MakeReadOnlyMemberError(targetType, memInfo.Name),
                        typeof(object)
                        )
                    );
            }
            else if (field.IsStatic && targetType != field.DeclaringType)
            {
                memInfo.Body.FinishError(
                    errorSuggestion ?? MakeError(
                        MakeStaticAssignFromDerivedTypeError(targetType, instance, field, target, memInfo.ResolutionFactory),
                        typeof(object)
                        )
                    );
            }
            else if (field.DeclaringType.IsValueType && !field.IsStatic)
            {
                memInfo.Body.FinishError(
                    errorSuggestion ?? MakeError(
                        MakeSetValueTypeFieldError(field, instance, target),
                        typeof(object)
                        )
                    );
            }
            else if (field.IsPublic && field.DeclaringType.IsVisible)
            {
                if (!field.IsStatic && instance == null)
                {
                    memInfo.Body.FinishError(
                        Ast.Throw(
                            Ast.New(
                                typeof(ArgumentException).GetConstructor(new Type[] { typeof(string) }),
                                AstUtils.Constant("assignment to instance field w/o instance")
                                ),
                            typeof(object)
                            )
                        );
                }
                else
                {
                    memInfo.Body.FinishCondition(
                        MakeReturnValue(
                            Ast.Assign(
                                Ast.Field(
                                    field.IsStatic ?
                                    null :
                                    AstUtils.Convert(instance.Expression, field.DeclaringType),
                                    field.Field
                                    ),
                                ConvertExpression(target.Expression, field.FieldType, ConversionResultKind.ExplicitCast, memInfo.ResolutionFactory)
                                ),
                            target
                            )
                        );
                }
            }
            else
            {
                Debug.Assert(field.IsStatic || instance != null);

                memInfo.Body.FinishCondition(
                    MakeReturnValue(
                        Ast.Call(
                            AstUtils.Convert(AstUtils.Constant(field.Field), typeof(FieldInfo)),
                            typeof(FieldInfo).GetMethod("SetValue", new Type[] { typeof(object), typeof(object) }),
                            field.IsStatic ?
                            AstUtils.Constant(null) :
                            (Expression)AstUtils.Convert(instance.Expression, typeof(object)),
                            AstUtils.Convert(target.Expression, typeof(object))
                            ),
                        target
                        )
                    );
            }
        }
 public override LightLambdaExpression ReduceAst(PythonAst instance, string name)
 {
     return(Utils.LightLambda <Func <FunctionCode, object> >(typeof(object), AstUtils.Convert(instance.ReduceWorker(), typeof(object)), name, new[] { PythonAst._functionCode }));
 }
Пример #4
0
        public override MSAst.Expression Reduce()
        {
            // allocated all variables here so they won't be shared w/ other
            // locals allocated during the body or except blocks.
            MSAst.ParameterExpression lineUpdated = null;
            MSAst.ParameterExpression runElse     = null;

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

            // don't allocate locals below here...
            MSAst.Expression          body = _body;
            MSAst.Expression          @else = _else;
            MSAst.Expression          @catch, result;
            MSAst.ParameterExpression exception;

            if (_handlers != null && _handlers.Length > 0)
            {
                exception = Ast.Variable(typeof(Exception), "$exception");
                @catch    = TransformHandlers(exception);
            }
            else
            {
                exception = null;
                @catch    = null;
            }

            // 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, AstUtils.Constant(true)),
                        // save existing line updated, we could choose to do this only for nested exception handlers.
                        PushLineUpdated(false, lineUpdated),
                        LightExceptions.RewriteExternal(
                            AstUtils.Try(
                                Parent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, GlobalParent.IndexToLocation(_headerIndex))),
                                body,
                                AstUtils.Constant(null)
                                ).Catch(exception,
                                        Ast.Assign(runElse, AstUtils.Constant(false)),
                                        @catch,
                                        // restore existing line updated after exception handler completes
                                        PopLineUpdated(lineUpdated),
                                        Ast.Assign(exception, Ast.Constant(null, typeof(Exception))),
                                        AstUtils.Constant(null)
                                        )
                            ),
                        AstUtils.IfThen(runElse,
                                        @else
                                        ),
                        AstUtils.Empty()
                        );
            }
            else if (@catch != null)            // no "else" clause
            //  try {
            //      <try body>
            //  } catch (Exception e) {
            //      ... catch handling ...
            //  }
            //
            {
                result =
                    LightExceptions.RewriteExternal(
                        AstUtils.Try(
                            GlobalParent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, GlobalParent.IndexToLocation(_headerIndex))),
                            // save existing line updated
                            PushLineUpdated(false, lineUpdated),
                            body,
                            AstUtils.Constant(null)
                            ).Catch(exception,
                                    @catch,
                                    // restore existing line updated after exception handler completes
                                    PopLineUpdated(lineUpdated),
                                    Ast.Call(AstMethods.ExceptionHandled, Parent.LocalContext),
                                    Ast.Assign(exception, Ast.Constant(null, typeof(Exception))),
                                    AstUtils.Constant(null)
                                    )
                        );
            }
            else
            {
                result = body;
            }

            return(Ast.Block(
                       GetVariables(lineUpdated, runElse),
                       AddFinally(result),
                       AstUtils.Default(typeof(void))
                       ));
        }
Пример #5
0
 public override MSAst.Expression GetConstant(object value)
 {
     return(AstUtils.Constant(value));
 }
Пример #6
0
        internal static Expression ExplicitConvert(Expression /*!*/ expr, Type /*!*/ fromType, Type /*!*/ toType)
        {
            expr = AstUtils.Convert(expr, fromType);

            if (HasExplicitNumericConversion(fromType, toType))
            {
                // special cases to mimic Ruby behavior precisely:
                if (fromType == typeof(BigInteger))
                {
                    if (toType == typeof(int))
                    {
                        return(Methods.ConvertBignumToFixnum.OpCall(expr));
                    }
                    else if (toType == typeof(double))
                    {
                        return(Methods.ConvertBignumToFloat.OpCall(expr));
                    }
                }
                else if (fromType == typeof(double) && toType == typeof(int))
                {
                    return(Methods.ConvertDoubleToFixnum.OpCall(expr));
                }

                return(Ast.ConvertChecked(expr, toType));
            }

            MethodInfo converter = CompilerHelpers.GetExplicitConverter(fromType, toType);

            if (converter != null)
            {
                return(Ast.Call(null, converter, expr));
            }

            if (fromType == typeof(char) && toType == typeof(string))
            {
                return(Ast.Call(null, fromType.GetMethod("ToString", BindingFlags.Public | BindingFlags.Static), expr));
            }

            if (toType == typeof(bool))
            {
                Debug.Assert(fromType != typeof(bool));
                return(fromType.IsValueType() ? AstUtils.Constant(true) : Ast.NotEqual(expr, AstUtils.Constant(null)));
            }

            // TODO:
            //if (TypeConverter...(fromType, toType)) {
            //    return true;
            //}

            return(null);
        }
Пример #7
0
 public override Expression /*!*/ CreateExpression()
 {
     return(Methods.GetMethod(GetType(), "MakeShared").OpCall(_signature.CreateExpression(), AstUtils.Constant(_lexicalScopeId)));
 }
Пример #8
0
        /// <summary>
        /// Translates our CallSignature into a DLR Argument list and gives the simple MetaObject's which are extracted
        /// from the tuple or dictionary parameters being splatted.
        /// </summary>
        private void TranslateArguments(DynamicMetaObject target, DynamicMetaObject /*!*/[] /*!*/ args, out CallInfo /*!*/ callInfo, out List <Expression /*!*/> /*!*/ metaArgs, out Expression test, out BindingRestrictions restrictions)
        {
            Argument[] argInfo = _signature.GetArgumentInfos();

            List <string> namedArgNames = new List <string>();

            metaArgs = new List <Expression>();
            metaArgs.Add(target.Expression);
            Expression splatArgTest   = null;
            Expression splatKwArgTest = null;

            restrictions = BindingRestrictions.Empty;

            for (int i = 0; i < argInfo.Length; i++)
            {
                Argument ai = argInfo[i];

                switch (ai.Kind)
                {
                case ArgumentType.Dictionary:
                    PythonDictionary iac      = (PythonDictionary)args[i].Value;
                    List <string>    argNames = new List <string>();

                    foreach (KeyValuePair <object, object> kvp in iac)
                    {
                        string key = (string)kvp.Key;
                        namedArgNames.Add(key);
                        argNames.Add(key);

                        metaArgs.Add(
                            Expression.Call(
                                AstUtils.Convert(args[i].Expression, typeof(PythonDictionary)),
                                typeof(PythonDictionary).GetMethod("get_Item", new[] { typeof(object) }),
                                AstUtils.Constant(key)
                                )
                            );
                    }

                    restrictions   = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[i].Expression, args[i].GetLimitType()));
                    splatKwArgTest = Expression.Call(
                        typeof(PythonOps).GetMethod("CheckDictionaryMembers"),
                        AstUtils.Convert(args[i].Expression, typeof(PythonDictionary)),
                        AstUtils.Constant(argNames.ToArray())
                        );
                    break;

                case ArgumentType.List:
                    IList <object> splattedArgs = (IList <object>)args[i].Value;
                    splatArgTest = Expression.Equal(
                        Expression.Property(AstUtils.Convert(args[i].Expression, args[i].GetLimitType()), typeof(ICollection <object>).GetProperty("Count")),
                        AstUtils.Constant(splattedArgs.Count)
                        );

                    for (int splattedArg = 0; splattedArg < splattedArgs.Count; splattedArg++)
                    {
                        metaArgs.Add(
                            Expression.Call(
                                AstUtils.Convert(args[i].Expression, typeof(IList <object>)),
                                typeof(IList <object>).GetMethod("get_Item"),
                                AstUtils.Constant(splattedArg)
                                )
                            );
                    }

                    restrictions = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[i].Expression, args[i].GetLimitType()));
                    break;

                case ArgumentType.Named:
                    namedArgNames.Add(ai.Name);
                    metaArgs.Add(args[i].Expression);
                    break;

                case ArgumentType.Simple:
                    metaArgs.Add(args[i].Expression);
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }

            callInfo = new CallInfo(metaArgs.Count - 1, namedArgNames.ToArray());

            test = splatArgTest;
            if (splatKwArgTest != null)
            {
                if (test != null)
                {
                    test = Expression.AndAlso(test, splatKwArgTest);
                }
                else
                {
                    test = splatKwArgTest;
                }
            }
        }
Пример #9
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>
        public override MSAst.Expression Reduce()
        {
            // Five statements in the result...
            ReadOnlyCollectionBuilder <MSAst.Expression>          statements = new ReadOnlyCollectionBuilder <MSAst.Expression>(6);
            ReadOnlyCollectionBuilder <MSAst.ParameterExpression> variables  = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>(6);

            MSAst.ParameterExpression lineUpdated = Ast.Variable(typeof(bool), "$lineUpdated_with");
            variables.Add(lineUpdated);

            //******************************************************************
            // 1. mgr = (EXPR)
            //******************************************************************
            MSAst.ParameterExpression manager = Ast.Variable(typeof(object), "with_manager");
            variables.Add(manager);
            statements.Add(
                GlobalParent.AddDebugInfo(
                    Ast.Assign(
                        manager,
                        _contextManager
                        ),
                    new SourceSpan(Start, _header)
                    )
                );

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

            //******************************************************************
            // 3. value = mgr.__enter__()
            //******************************************************************
            MSAst.ParameterExpression value = Ast.Variable(typeof(object), "with_value");
            variables.Add(value);
            statements.Add(
                GlobalParent.AddDebugInfoAndVoid(
                    MakeAssignment(
                        value,
                        Parent.Invoke(
                            new CallSignature(0),
                            Parent.LocalContext,
                            GlobalParent.Get(
                                "__enter__",
                                manager
                                )
                            )
                        ),
                    new SourceSpan(Start, _header)
                    )
                );

            //******************************************************************
            // 4. exc = True
            //******************************************************************
            MSAst.ParameterExpression exc = Ast.Variable(typeof(bool), "with_exc");
            variables.Add(exc);
            statements.Add(
                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;
            statements.Add(
                // try:
                AstUtils.Try(
                    AstUtils.Try(// try statement body
                        PushLineUpdated(false, lineUpdated),
                        _var != null ?
                        (MSAst.Expression)Ast.Block(
                            // VAR = value
                            _var.TransformSet(SourceSpan.None, value, PythonOperationKind.None),
                            // BLOCK
                            _body,
                            AstUtils.Empty()
                            ) :
                        // BLOCK
                        (MSAst.Expression)_body // except:, // try statement location
                        ).Catch(exception = Ast.Variable(typeof(Exception), "exception"),
                                                // Python specific exception handling code
                                TryStatement.GetTracebackHeader(
                                    this,
                                    exception,
                                    GlobalParent.AddDebugInfoAndVoid(
                                        Ast.Block(
                                            // exc = False
                                            MakeAssignment(
                                                exc,
                                                AstUtils.Constant(false)
                                                ),
                                            //  if not exit(*sys.exc_info()):
                                            //      raise
                                            AstUtils.IfThen(
                                                GlobalParent.Convert(
                                                    typeof(bool),
                                                    ConversionResultKind.ExplicitCast,
                                                    GlobalParent.Operation(
                                                        typeof(bool),
                                                        PythonOperationKind.IsFalse,
                                                        MakeExitCall(exit, exception)
                                                        )
                                                    ),
                                                UpdateLineUpdated(true),
                                                Ast.Throw(
                                                    Ast.Call(
                                                        AstMethods.MakeRethrowExceptionWorker,
                                                        exception
                                                        )
                                                    )
                                                )
                                            ),
                                        _body.Span
                                        )
                                    ),
                                PopLineUpdated(lineUpdated),
                                Ast.Empty()
                                )
                    // finally:
                    ).Finally(
                    //  if exc:
                    //      exit(None, None, None)
                    AstUtils.IfThen(
                        exc,
                        GlobalParent.AddDebugInfoAndVoid(
                            Ast.Block(
                                Ast.Dynamic(
                                    GlobalParent.PyContext.Invoke(
                                        new CallSignature(3)        // signature doesn't include function
                                        ),
                                    typeof(object),
                                    new MSAst.Expression[] {
                Parent.LocalContext,
                exit,
                AstUtils.Constant(null),
                AstUtils.Constant(null),
                AstUtils.Constant(null)
            }
                                    ),
                                Ast.Empty()
                                ),
                            _contextManager.Span
                            )
                        )
                    )
                );

            statements.Add(AstUtils.Empty());
            return(Ast.Block(variables.ToReadOnlyCollection(), statements.ToReadOnlyCollection()));
        }
Пример #10
0
        private static MethodMissingBinding BindToKernelMethodMissing(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ methodName,
                                                                      RubyMemberInfo methodMissing, RubyMethodVisibility incompatibleVisibility, bool isSuperCall)
        {
            // TODO: better specialization of method_missing methods
            if (methodMissing == null ||
                methodMissing.DeclaringModule == methodMissing.Context.KernelModule && methodMissing is RubyLibraryMethodInfo)
            {
                if (isSuperCall)
                {
                    metaBuilder.SetError(Methods.MakeMissingSuperException.OpCall(AstUtils.Constant(methodName)));
                }
                else if (incompatibleVisibility == RubyMethodVisibility.Private)
                {
                    metaBuilder.SetError(Methods.MakePrivateMethodCalledError.OpCall(
                                             AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName))
                                         );
                }
                else if (incompatibleVisibility == RubyMethodVisibility.Protected)
                {
                    metaBuilder.SetError(Methods.MakeProtectedMethodCalledError.OpCall(
                                             AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName))
                                         );
                }
                else
                {
                    return(MethodMissingBinding.Fallback);
                }

                return(MethodMissingBinding.Error);
            }

            return(MethodMissingBinding.Custom);
        }
Пример #11
0
        internal static MethodResolutionResult Resolve(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args,
                                                       out RubyMemberInfo methodMissing)
        {
            MethodResolutionResult method;
            var targetClass       = args.TargetClass;
            var visibilityContext = GetVisibilityContext(args.Signature, args.Scope);

            using (targetClass.Context.ClassHierarchyLocker()) {
                metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext,
                                              new[] { methodName, Symbols.MethodMissing }
                                              );

                if (args.Signature.IsSuperCall)
                {
                    Debug.Assert(!args.Signature.IsVirtualCall && args.Signature.HasImplicitSelf);
                    method = targetClass.ResolveSuperMethodNoLock(methodName, targetClass).InvalidateSitesOnOverride();
                }
                else
                {
                    var options = args.Signature.IsVirtualCall ? MethodLookup.Virtual : MethodLookup.Default;
                    method = targetClass.ResolveMethodForSiteNoLock(methodName, visibilityContext, options);
                }

                if (!method.Found)
                {
                    methodMissing = targetClass.ResolveMethodMissingForSite(methodName, method.IncompatibleVisibility);
                }
                else
                {
                    methodMissing = null;
                }
            }

            // Whenever the current self's class changes we need to invalidate the rule, if a protected method is being called.
            if (method.Info != null && method.Info.IsProtected && visibilityContext.Class != null)
            {
                // We don't need to compare versions, just the class objects (super-class relationship cannot be changed).
                // Since we don't want to hold on a class object (to make it collectible) we compare references to the version handlers.
                metaBuilder.AddCondition(Ast.Equal(
                                             Methods.GetSelfClassVersionHandle.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope))),
                                             Ast.Constant(visibilityContext.Class.Version)
                                             ));
            }

            return(method);
        }
Пример #12
0
        public void AddCallArguments(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            _callArguments = args;

            // calculate actual argument count:
            _actualArgumentCount = args.SimpleArgumentCount;
            if (args.Signature.HasSplattedArgument)
            {
                var splattedArg = args.GetSplattedMetaArgument();
                metaBuilder.AddSplattedArgumentTest((IList)splattedArg.Value, splattedArg.Expression, out _listLength, out _listVariable);
                _actualArgumentCount += _listLength;
            }
            if (args.Signature.HasRhsArgument)
            {
                _actualArgumentCount++;
            }

            // check:
            if (HasTooFewArguments)
            {
                metaBuilder.SetWrongNumberOfArgumentsError(_actualArgumentCount, _mandatoryParamCount);
                return;
            }

            if (HasTooManyArguments)
            {
                metaBuilder.SetWrongNumberOfArgumentsError(_actualArgumentCount, _mandatoryParamCount);
                return;
            }

            bool isSplatted;

            // leading mandatory:
            for (int i = 0; i < _leadingMandatoryParamCount; i++)
            {
                _arguments[LeadingMandatoryIndex + i] = GetArgument(i, out isSplatted);
            }

            // trailing mandatory:
            for (int i = 0; i < TrailingMandatoryCount; i++)
            {
                _arguments[TrailingMandatoryIndex + i] = GetArgument(_actualArgumentCount - TrailingMandatoryCount + i, out isSplatted);
            }

            int start = _leadingMandatoryParamCount;
            int end   = _actualArgumentCount - TrailingMandatoryCount;

            // optional:
            for (int i = 0; i < _optionalParamCount; i++)
            {
                _arguments[OptionalParameterIndex + i] = (start < end) ? GetArgument(start++, out isSplatted) : Ast.Field(null, Fields.DefaultArgument);
            }

            // unsplat:
            if (_hasUnsplatParameter)
            {
                Expression array;
                if (args.Signature.HasSplattedArgument)
                {
                    // simple:
                    var argsToUnsplat = new List <Expression>();
                    while (start < end)
                    {
                        var arg = GetArgument(start, out isSplatted);
                        if (isSplatted)
                        {
                            break;
                        }
                        argsToUnsplat.Add(AstUtils.Box(arg));
                        start++;
                    }
                    array = Methods.MakeArrayOpCall(argsToUnsplat);

                    int rangeStart  = start - args.SimpleArgumentCount;
                    int rangeLength = Math.Min(end - start, _listLength - rangeStart);

                    // splatted:
                    if (rangeLength > 0)
                    {
                        array  = Methods.AddSubRange.OpCall(array, _listVariable, Ast.Constant(rangeStart), Ast.Constant(rangeLength));
                        start += rangeLength;
                    }

                    // rhs:
                    while (start < end)
                    {
                        array = Methods.AddItem.OpCall(array, AstUtils.Box(GetArgument(start, out isSplatted)));
                        start++;
                    }
                }
                else
                {
                    var argsToUnsplat = new List <Expression>(end - start);
                    while (start < end)
                    {
                        argsToUnsplat.Add(AstUtils.Box(GetArgument(start++, out isSplatted)));
                    }
                    array = Methods.MakeArrayOpCall(argsToUnsplat);
                }

                _arguments[UnsplatParameterIndex] = array;
            }

            _callArguments = null;
            _listVariable  = null;
            Debug.Assert(CollectionUtils.TrueForAll(_arguments, (e) => e != null));
        }
Пример #13
0
        /// <summary>
        /// Creates the LambdaExpression which implements the body of the function.
        ///
        /// The functions signature is either "object Function(PythonFunction, ...)"
        /// where there is one object parameter for each user defined parameter or
        /// object Function(PythonFunction, object[]) for functions which take more
        /// than PythonCallTargets.MaxArgs arguments.
        /// </summary>
        private LightLambdaExpression CreateFunctionLambda()
        {
            bool     needsWrapperMethod = _parameters.Length > PythonCallTargets.MaxArgs;
            Delegate originalDelegate;
            Type     delegateType = GetDelegateType(_parameters, needsWrapperMethod, out originalDelegate);

            MSAst.ParameterExpression localContext = null;
            ReadOnlyCollectionBuilder <MSAst.ParameterExpression> locals = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>();

            if (NeedsLocalContext)
            {
                localContext = LocalCodeContextVariable;
                locals.Add(localContext);
            }

            MSAst.ParameterExpression[] parameters = CreateParameters(needsWrapperMethod, locals);

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

            foreach (var param in _parameters)
            {
                IPythonVariableExpression pyVar = GetVariableExpression(param.PythonVariable) as IPythonVariableExpression;
                if (pyVar != null)
                {
                    var varInit = pyVar.Create();
                    if (varInit != null)
                    {
                        init.Add(varInit);
                    }
                }
            }

            // Transform the parameters.
            init.Add(Ast.ClearDebugInfo(GlobalParent.Document));

            locals.Add(PythonAst._globalContext);
            init.Add(Ast.Assign(PythonAst._globalContext, new GetGlobalContextExpression(_parentContext)));

            GlobalParent.PrepareScope(locals, init);

            // Create variables and references. Since references refer to
            // parameters, do this after parameters have been created.

            CreateFunctionVariables(locals, init);

            // If the __class__ variable is used the a class method then we need to initialize it.
            // This must be done before parameter initialization (in case one of the parameters is called __class__).
            ClassDefinition parent = FindParentOfType <ClassDefinition>();
            PythonVariable  pVar;

            if (parent != null && TryGetVariable("__class__", out pVar))
            {
                init.Add(
                    AssignValue(
                        GetVariableExpression(pVar),
                        Ast.Call(AstMethods.LookupName, parent.Parent.LocalContext, Ast.Constant(parent.Name))
                        )
                    );
            }

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

            List <MSAst.Expression> statements = new List <MSAst.Expression>();
            // add beginning sequence point
            var start = GlobalParent.IndexToLocation(StartIndex);

            statements.Add(GlobalParent.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(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 = Ast.Parameter(typeof(Exception), "$ex");
                locals.Add(extracted);
            }

            if (_body.CanThrow && !(_body is SuiteStatement) && _body.StartIndex != -1)
            {
                statements.Add(UpdateLineNumber(GlobalParent.IndexToLocation(_body.StartIndex).Line));
            }

            statements.Add(Body);
            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(AstMethods.SaveCurrentException)
                        ),
                    body
                    ).Finally(
                    Ast.Call(
                        AstMethods.RestoreCurrentException, extracted
                        )
                    );
                body = s;
            }

            if (_body.CanThrow && GlobalParent.PyContext.PythonOptions.Frames)
            {
                body = AddFrame(LocalContext, Ast.Property(_functionParam, typeof(PythonFunction).GetProperty("__code__")), body);
                locals.Add(FunctionStackVariable);
            }

            body = AddProfiling(body);
            body = WrapScopeStatements(body, _body.CanThrow);
            body = Ast.Block(body, AstUtils.Empty());
            body = AddReturnTarget(body);


            MSAst.Expression bodyStmt = body;
            if (localContext != null)
            {
                var createLocal = CreateLocalContext(_parentContext);

                init.Add(
                    Ast.Assign(
                        localContext,
                        createLocal
                        )
                    );
            }

            init.Add(bodyStmt);

            bodyStmt = Ast.Block(init);

            // wrap a scope if needed
            bodyStmt = Ast.Block(locals.ToReadOnlyCollection(), bodyStmt);

            return(AstUtils.LightLambda(
                       typeof(object),
                       delegateType,
                       AddDefaultReturn(bodyStmt, typeof(object)),
                       Name + "$" + Interlocked.Increment(ref _lambdaId),
                       parameters
                       ));
        }
Пример #14
0
        /// <summary>
        /// Returns an expression which creates the function object.
        /// </summary>
        internal MSAst.Expression MakeFunctionExpression()
        {
            var defaults    = new List <MSAst.Expression>(0);
            var annotations = new List <MSAst.Expression>();

            if (ReturnAnnotation != null)
            {
                annotations.Add(Ast.Constant("return", typeof(string)));
                annotations.Add(ReturnAnnotation);
            }

            foreach (var param in _parameters)
            {
                if (param.DefaultValue != null)
                {
                    defaults.Add(AstUtils.Convert(param.DefaultValue, typeof(object)));
                }

                if (param.Annotation != null)
                {
                    annotations.Add(Ast.Constant(param.Name, typeof(string)));
                    annotations.Add(param.Annotation);
                }
            }

            MSAst.Expression funcCode = GlobalParent.Constant(GetOrMakeFunctionCode());
            FuncCodeExpr = funcCode;

            MSAst.Expression ret;
            if (EmitDebugFunction())
            {
                LightLambdaExpression code = CreateFunctionLambda();

                // 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(
                    AstMethods.MakeFunctionDebug,                                                   // method
                    Parent.LocalContext,                                                            // 1. Emit CodeContext
                    FuncCodeExpr,                                                                   // 2. FunctionCode
                    ((IPythonGlobalExpression)GetVariableExpression(_nameVariable)).RawValue(),     // 3. module name
                    defaults.Count == 0 ?                                                           // 4. default values
                    AstUtils.Constant(null, typeof(object[])) :
                    (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults),
                    annotations.Count == 0 ? AstUtils.Constant(null, typeof(PythonDictionary)) :
                    (MSAst.Expression)Ast.Call(                                                     // 5. annotations
                        AstMethods.MakeDictFromItems,
                        Ast.NewArrayInit(
                            typeof(object),
                            annotations
                            )
                        ),
                    IsGenerator ?
                    (MSAst.Expression) new PythonGeneratorExpression(code, GlobalParent.PyContext.Options.CompilationThreshold) :
                    (MSAst.Expression)code
                    );
            }
            else
            {
                ret = Ast.Call(
                    AstMethods.MakeFunction,                                                        // method
                    Parent.LocalContext,                                                            // 1. Emit CodeContext
                    FuncCodeExpr,                                                                   // 2. FunctionCode
                    ((IPythonGlobalExpression)GetVariableExpression(_nameVariable)).RawValue(),     // 3. module name
                    defaults.Count == 0 ?                                                           // 4. default values
                    AstUtils.Constant(null, typeof(object[])) :
                    (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults),
                    annotations.Count == 0 ? AstUtils.Constant(null, typeof(PythonDictionary)) :
                    (MSAst.Expression)Ast.Call(                                                     // 5. annotations
                        AstMethods.MakeDictFromItems,
                        Ast.NewArrayInit(
                            typeof(object),
                            annotations
                            )
                        )
                    );
            }

            return(AddDecorators(ret, _decorators));
        }
Пример #15
0
 protected override Expression ToExpression(OverloadResolver resolver, RestrictedArguments args, bool[] hasBeenUsed)
 {
     return(AstUtils.Constant(Activator.CreateInstance(ParameterInfo.ParameterType)));
 }
        protected override MSAst.Expression VisitTry(MSAst.TryExpression node)
        {
            MSAst.Expression b = Visit(node.Body);
            ReadOnlyCollection <MSAst.CatchBlock> h = Visit(node.Handlers, VisitCatchBlock);

            MSAst.Expression y = Visit(node.Finally);
            MSAst.Expression f;

            _insideConditionalBlock = true;
            try {
                f = Visit(node.Fault);
            } finally {
                _insideConditionalBlock = false;
            }

            node = Ast.MakeTry(node.Type, b, y, f, h);

            List <MSAst.CatchBlock> newHandlers = null;

            MSAst.Expression newFinally = null;

            // If the TryStatement has any Catch blocks we need to insert the exception
            // event as a first statement so that we can be notified of first-chance exceptions.
            if (node.Handlers != null && node.Handlers.Count > 0)
            {
                newHandlers = new List <MSAst.CatchBlock>();

                foreach (var catchBlock in node.Handlers)
                {
                    MSAst.ParameterExpression exceptionVar = catchBlock.Variable != null ? catchBlock.Variable : Ast.Parameter(catchBlock.Test, null);

                    MSAst.Expression debugMarker, thread;
                    if (_transformToGenerator)
                    {
                        debugMarker = Ast.Call(
                            typeof(RuntimeOps).GetMethod("GetCurrentSequencePointForGeneratorFrame"),
                            _frame
                            );

                        thread = Ast.Call(typeof(RuntimeOps).GetMethod("GetThread"), _frame);
                    }
                    else
                    {
                        debugMarker = _debugMarker;
                        thread      = _thread;
                    }

                    MSAst.Expression exceptionEvent = Ast.Block(
                        // Rethrow ForceToGeneratorLoopException
                        AstUtils.If(
                            Ast.TypeIs(
                                exceptionVar,
                                typeof(ForceToGeneratorLoopException)
                                ),
                            Ast.Throw(exceptionVar)
                            ),
                        AstUtils.If(
                            Ast.Equal(_globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled)),
                            (_pushFrame != null) ? _pushFrame : Ast.Empty(),
                            Ast.Call(
                                typeof(RuntimeOps).GetMethod("OnTraceEvent"),
                                thread,
                                debugMarker,
                                exceptionVar
                                )
                            )
                        );

                    newHandlers.Add(Ast.MakeCatchBlock(
                                        catchBlock.Test,
                                        exceptionVar,
                                        Ast.Block(
                                            exceptionEvent,
                                            catchBlock.Body
                                            ),
                                        catchBlock.Filter
                                        ));
                }
            }

            if (!_transformToGenerator && node.Finally != null)
            {
                // Prevent the user finally block from running if the frame is currently remapping to generator
                newFinally = AstUtils.If(
                    Ast.Not(
                        Ast.Call(
                            typeof(RuntimeOps).GetMethod("IsCurrentLeafFrameRemappingToGenerator"),
                            _thread
                            )
                        ),
                    node.Finally
                    );
            }

            if (newHandlers != null || newFinally != null)
            {
                node = Ast.MakeTry(
                    node.Type,
                    node.Body,
                    newFinally != null ? newFinally : node.Finally,
                    node.Fault,
                    newHandlers != null ? newHandlers : newHandlers
                    );
            }

            return(node);
        }
        protected override MSAst.Expression VisitDebugInfo(MSAst.DebugInfoExpression node)
        {
            if (!node.IsClear)
            {
                MSAst.Expression transformedExpression;

                // Verify that DebugInfoExpression has valid SymbolDocumentInfo
                if (node.Document == null || String.IsNullOrEmpty(node.Document.FileName))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ErrorStrings.DebugInfoWithoutSymbolDocumentInfo, _locationCookie));
                }

                DebugSourceFile sourceFile = _debugContext.GetDebugSourceFile(node.Document.FileName);

                // Update the location cookie
                int locationCookie = _locationCookie++;
                if (!_transformToGenerator)
                {
                    MSAst.Expression tracebackCall = null;
                    if (locationCookie == 0)
                    {
                        tracebackCall = Ast.Empty();
                    }
                    else
                    {
                        tracebackCall = Ast.Call(
                            typeof(RuntimeOps).GetMethod("OnTraceEvent"),
                            _thread,
                            AstUtils.Constant(locationCookie),
                            Ast.Convert(Ast.Constant(null), typeof(Exception))
                            );
                    }

                    transformedExpression = Ast.Block(
                        Ast.Assign(
                            _debugMarker,
                            AstUtils.Constant(locationCookie)
                            ),
                        Ast.IfThen(
                            Ast.GreaterThan(
                                Ast.Property(_sourceFilesToVariablesMap[sourceFile], "Mode"),
                                Ast.Constant((int)DebugMode.ExceptionsOnly)
                                ),
                            Ast.IfThen(
                                Ast.OrElse(
                                    Ast.Equal(
                                        Ast.Property(_sourceFilesToVariablesMap[sourceFile], "Mode"),
                                        Ast.Constant((int)DebugMode.FullyEnabled)
                                        ),
                                    Ast.ArrayIndex(
                                        _traceLocations,
                                        AstUtils.Constant(locationCookie)
                                        )
                                    ),
                                Ast.Block(
                                    (_pushFrame != null) ? _pushFrame : Ast.Empty(),
                                    tracebackCall
                                    )
                                )
                            )
                        );
                }
                else
                {
                    Debug.Assert(_generatorLabelTarget != null);

                    transformedExpression = Ast.Block(
                        AstUtils.YieldReturn(
                            _generatorLabelTarget,
                            _debugYieldValue,
                            locationCookie
                            )
                        );

                    // Update the variable scope map
                    if (_currentLocals.Count > 0)
                    {
                        IList <VariableInfo>  scopedVaribles;
                        MSAst.BlockExpression curentBlock = _currentLocals.Peek();
                        if (!_variableScopeMapCache.TryGetValue(curentBlock, out scopedVaribles))
                        {
                            scopedVaribles = new List <VariableInfo>();
                            MSAst.BlockExpression[] blocks = _currentLocals.ToArray();
                            for (int i = blocks.Length - 1; i >= 0; i--)
                            {
                                foreach (var variable in blocks[i].Variables)
                                {
                                    scopedVaribles.Add(_localsToVarInfos[variable]);
                                }
                            }

                            _variableScopeMapCache.Add(curentBlock, scopedVaribles);
                        }

                        _variableScopeMap.Add(locationCookie, scopedVaribles);
                    }

                    DebugSourceSpan span = new DebugSourceSpan(
                        sourceFile,
                        node.StartLine,
                        node.StartColumn,
                        node.EndLine,
                        node.EndColumn);

                    // Update the location-span map
                    _markerLocationMap.Add(locationCookie, span);
                }

                return(transformedExpression);
            }
            else
            {
                return(Ast.Empty());
            }
        }
Пример #18
0
        public override Expression /*!*/ Convert(DynamicMetaObject /*!*/ metaObject, Type restrictedType, ParameterInfo info, Type /*!*/ toType)
        {
            Expression expr     = metaObject.Expression;
            Type       fromType = restrictedType ?? expr.Type;

            // block:
            if (fromType == typeof(MissingBlockParam))
            {
                Debug.Assert(toType == typeof(BlockParam) || toType == typeof(MissingBlockParam));
                return(AstUtils.Constant(null));
            }

            if (fromType == typeof(BlockParam) && toType == typeof(MissingBlockParam))
            {
                return(AstUtils.Constant(null));
            }

            // protocol conversions:
            if (info != null && info.IsDefined(typeof(DefaultProtocolAttribute), false))
            {
                var action = RubyConversionAction.TryGetDefaultConversionAction(Context, toType);
                if (action != null)
                {
                    // TODO: inline implicit conversions:
                    return(AstUtils.LightDynamic(action, toType, expr));
                }

                // Do not throw an exception here to allow generic type parameters to be used with D.P. attribute.
                // The semantics should be to use DP if available for the current instantiation and ignore it otherwise.
            }

            if (restrictedType != null)
            {
                if (restrictedType == typeof(DynamicNull))
                {
                    if (!toType.IsValueType || toType.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable <>))
                    {
                        return(AstUtils.Constant(null, toType));
                    }
                    else if (toType == typeof(bool))
                    {
                        return(AstUtils.Constant(false));
                    }
                }

                if (toType.IsAssignableFrom(restrictedType))
                {
                    // expr can be converted to restrictedType, which can be converted toType => we can convert expr to toType:
                    return(AstUtils.Convert(expr, CompilerHelpers.GetVisibleType(toType)));
                }

                // if there is a simple conversion from restricted type, convert the expression to the restricted type and use that conversion:
                Type visibleRestrictedType = CompilerHelpers.GetVisibleType(restrictedType);
                if (Converter.CanConvertFrom(metaObject, visibleRestrictedType, toType, false, NarrowingLevel.None, false, false))
                {
                    expr = AstUtils.Convert(expr, visibleRestrictedType);
                }
            }

            return(Converter.ConvertExpression(expr, toType, _args.RubyContext, _args.MetaContext.Expression, _implicitProtocolConversions));
        }
        public override MSAst.Expression Reduce()
        {
            if (_names == _star)
            {
                // from a[.b] import *
                return(GlobalParent.AddDebugInfo(
                           Ast.Call(
                               AstMethods.ImportStar,
                               Parent.LocalContext,
                               AstUtils.Constant(_root.MakeString()),
                               AstUtils.Constant(GetLevel())
                               ),
                           Span
                           ));
            }
            else
            {
                // from a[.b] import x [as xx], [ y [ as yy] ] [ , ... ]

                ReadOnlyCollectionBuilder <MSAst.Expression> statements = new ReadOnlyCollectionBuilder <MSAst.Expression>();
                MSAst.ParameterExpression module = Ast.Variable(typeof(object), "module");

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

                // module = PythonOps.ImportWithNames(<context>, _root, make_array(_names))
                statements.Add(
                    GlobalParent.AddDebugInfoAndVoid(
                        AssignValue(
                            module,
                            LightExceptions.CheckAndThrow(
                                Expression.Call(
                                    AstMethods.ImportWithNames,
                                    Parent.LocalContext,
                                    AstUtils.Constant(_root.MakeString()),
                                    Ast.NewArrayInit(typeof(string), names),
                                    AstUtils.Constant(GetLevel())
                                    )
                                )
                            ),
                        _root.Span
                        )
                    );

                // now load all the names being imported and assign the variables
                for (int i = 0; i < names.Length; i++)
                {
                    statements.Add(
                        GlobalParent.AddDebugInfoAndVoid(
                            AssignValue(
                                Parent.GetVariableExpression(_variables[i]),
                                Ast.Call(
                                    AstMethods.ImportFrom,
                                    Parent.LocalContext,
                                    module,
                                    names[i]
                                    )
                                ),
                            Span
                            )
                        );
                }

                statements.Add(AstUtils.Empty());
                return(GlobalParent.AddDebugInfo(Ast.Block(new[] { module }, statements.ToArray()), Span));
            }
        }
Пример #20
0
 protected override Expression ToExpression(OverloadResolver /*!*/ resolver, RestrictedArguments /*!*/ args, bool[] /*!*/ hasBeenUsed)
 {
     return(AstUtils.Constant(Activator.CreateInstance(ParameterInfo.ParameterType, ((RubyOverloadResolver)resolver).Context)));
 }
Пример #21
0
        protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback)
        {
            RubyModule currentDeclaringModule;
            string     currentMethodName;

            var scope     = args.Scope;
            var scopeExpr = AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope));

            RubyScope targetScope;
            int       scopeNesting = scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out targetScope);

            if (scopeNesting == -1)
            {
                metaBuilder.AddCondition(Methods.IsSuperOutOfMethodScope.OpCall(scopeExpr));
                metaBuilder.SetError(Methods.MakeTopLevelSuperException.OpCall());
                return(true);
            }

            object target           = targetScope.SelfObject;
            var    targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self");
            var    assignTarget     = Ast.Assign(
                targetExpression,
                Methods.GetSuperCallTarget.OpCall(scopeExpr, AstUtils.Constant(scopeNesting))
                );

            if (_signature.HasImplicitArguments && targetScope.Kind == ScopeKind.BlockMethod)
            {
                metaBuilder.AddCondition(Ast.NotEqual(assignTarget, Ast.Field(null, Fields.NeedsUpdate)));
                metaBuilder.SetError(Methods.MakeImplicitSuperInBlockMethodError.OpCall());
                return(true);
            }

            // If we need to update we return RubyOps.NeedsUpdate instance that will cause the subsequent conditions to fail:
            metaBuilder.AddInitialization(assignTarget);

            args.SetTarget(targetExpression, target);

            Debug.Assert(currentDeclaringModule != null);

            RubyMemberInfo method;
            RubyMemberInfo methodMissing = null;

            // MRI bug: Uses currentDeclaringModule for method look-up so we can end up with an instance method of class C
            // called on a target of another class. See http://redmine.ruby-lang.org/issues/show/2419.

            // we need to lock the hierarchy of the target class:
            var targetClass = scope.RubyContext.GetImmediateClassOf(target);

            using (targetClass.Context.ClassHierarchyLocker()) {
                // initialize all methods in ancestors:
                targetClass.InitializeMethodsNoLock();

                // target is stored in a local, therefore it cannot be part of the restrictions:
                metaBuilder.TreatRestrictionsAsConditions = true;
                metaBuilder.AddTargetTypeTest(target, targetClass, targetExpression, args.MetaContext,
                                              new[] { Symbols.MethodMissing } // currentMethodName is resolved for super, which cannot be an instance singleton
                                              );
                metaBuilder.TreatRestrictionsAsConditions = false;

                method = targetClass.ResolveSuperMethodNoLock(currentMethodName, currentDeclaringModule).InvalidateSitesOnOverride().Info;

                if (_signature.ResolveOnly)
                {
                    metaBuilder.Result = AstUtils.Constant(method != null);
                    return(true);
                }

                if (method == null)
                {
                    // MRI: method_missing is called for the targetClass, not for the super:
                    methodMissing = targetClass.ResolveMethodMissingForSite(currentMethodName, RubyMethodVisibility.None);
                }
            }

            if (method != null)
            {
                method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule);
            }
            else
            {
                return(RubyCallAction.BuildMethodMissingCall(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, defaultFallback));
            }

            return(true);
        }
Пример #22
0
        private Expression MakeIncorrectArgumentCountError(BindingTarget target)
        {
            IList <int> available = target.ExpectedArgumentCount;
            int         expected;

            if (available.Count > 0)
            {
                int minGreater = Int32.MaxValue;
                int maxLesser  = Int32.MinValue;
                int max        = Int32.MinValue;
                foreach (int arity in available)
                {
                    if (arity > target.ActualArgumentCount)
                    {
                        minGreater = Math.Min(minGreater, arity);
                    }
                    else
                    {
                        maxLesser = Math.Max(maxLesser, arity);
                    }

                    max = Math.Max(max, arity);
                }

                expected = (target.ActualArgumentCount < maxLesser ? maxLesser : Math.Min(minGreater, max));
            }
            else
            {
                // no overload is callable:
                expected = 0;
            }

            return(Methods.MakeWrongNumberOfArgumentsError.OpCall(AstUtils.Constant(target.ActualArgumentCount), AstUtils.Constant(expected)));
        }
Пример #23
0
        // see Ruby Language.doc/Runtime/Control Flow Implementation/Break
        internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen)
        {
            MSA.Expression transformedReturnValue = TransformReturnValue(gen);

            // eval:
            if (gen.CompilerOptions.IsEval)
            {
                return(Methods.EvalBreak.OpCall(gen.CurrentScopeVariable, AstUtils.Box(transformedReturnValue)));
            }

            // loop:
            if (gen.CurrentLoop != null)
            {
                return(Ast.Block(
                           Ast.Assign(
                               gen.CurrentLoop.ResultVariable,
                               Ast.Convert(transformedReturnValue, gen.CurrentLoop.ResultVariable.Type)
                               ),
                           Ast.Break(gen.CurrentLoop.BreakLabel),
                           AstUtils.Empty()
                           ));
            }

            // block:
            if (gen.CurrentBlock != null)
            {
                return(gen.Return(Methods.BlockBreak.OpCall(gen.CurrentBlock.BfcVariable, AstUtils.Box(transformedReturnValue))));
            }

            // primary frame:
            return(Methods.MethodBreak.OpCall(AstUtils.Box(transformedReturnValue)));
        }
Пример #24
0
        public override DynamicMetaObject FallbackSetMember(DynamicMetaObject self, DynamicMetaObject value, DynamicMetaObject errorSuggestion)
        {
            if (self.NeedsDeferral())
            {
                return(Defer(self, value));
            }
#if !SILVERLIGHT
            DynamicMetaObject com;
            if (Microsoft.Scripting.ComInterop.ComBinder.TryBindSetMember(this, self, BindingHelpers.GetComArgument(value), out com))
            {
                return(com);
            }
#endif
            return(Context.Binder.SetMember(Name, self, value, errorSuggestion, new PythonOverloadResolverFactory(_context.Binder, AstUtils.Constant(Context.SharedContext))));
        }
Пример #25
0
        /// <summary>
        /// Transform multiple python except handlers for a try block into a single catch body.
        /// </summary>
        /// <param name="exception">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(MSAst.ParameterExpression exception)
        {
            Assert.NotEmpty(_handlers);

            MSAst.ParameterExpression extracted = Ast.Variable(typeof(object), "$extracted");

            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(
                            AstMethods.CheckException,
                            Parent.LocalContext,
                            extracted,
                            AstUtils.Convert(tsh.Test, typeof(object))
                            );

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

                        if (converted == null)
                        {
                            converted = Ast.Variable(typeof(object), "$converted");
                        }

                        ist = AstUtils.IfCondition(
                            Ast.NotEqual(
                                Ast.Assign(converted, test),
                                AstUtils.Constant(null)
                                ),
                            Ast.TryFinally(
                                Ast.Block(
                                    tsh.Target.TransformSet(SourceSpan.None, converted, PythonOperationKind.None),
                                    GlobalParent.AddDebugInfo(
                                        GetTracebackHeader(
                                            this,
                                            exception,
                                            tsh.Body
                                            ),
                                        new SourceSpan(GlobalParent.IndexToLocation(tsh.StartIndex), GlobalParent.IndexToLocation(tsh.HeaderIndex))
                                        ),
                                    AstUtils.Empty()
                                    ),
                                Ast.Block(
                                    tsh.Target.TransformSet(SourceSpan.None, AstUtils.Constant(null), PythonOperationKind.None),
                                    tsh.Target.TransformDelete()
                                    )
                                )
                            );
                    }
                    else
                    {
                        //  translating:
                        //      except Test:
                        //          <body>
                        //  into:
                        //      if (CheckException(exception, Test) != null) {
                        //          traceback-header
                        //          <body>
                        //      }
                        ist = AstUtils.IfCondition(
                            Ast.NotEqual(
                                test,
                                AstUtils.Constant(null)
                                ),
                            GlobalParent.AddDebugInfo(
                                GetTracebackHeader(
                                    this,
                                    exception,
                                    tsh.Body
                                    ),
                                new SourceSpan(GlobalParent.IndexToLocation(tsh.StartIndex), GlobalParent.IndexToLocation(tsh.HeaderIndex))
                                )
                            );
                    }

                    // 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 = GlobalParent.AddDebugInfo(
                        GetTracebackHeader(this, exception, tsh.Body),
                        new SourceSpan(GlobalParent.IndexToLocation(tsh.StartIndex), GlobalParent.IndexToLocation(tsh.HeaderIndex))
                        );
                }
            }

            MSAst.Expression body = null;

            if (tests.Count > 0)
            {
                // rethrow the exception if we have no catch-all block
                if (catchAll == null)
                {
                    catchAll = Ast.Block(
                        Parent.GetSaveLineNumberExpression(exception, true),
                        Ast.Throw(
                            Ast.Call(
                                typeof(ExceptionHelpers).GetMethod("UpdateForRethrow"),
                                exception
                                )
                            )
                        );
                }

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

            IList <MSAst.ParameterExpression> args;

            if (converted != null)
            {
                args = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression> {
                    converted, extracted
                };
            }
            else
            {
                args = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression> {
                    extracted
                };
            }

            // Codegen becomes:
            //     extracted = PythonOps.SetCurrentException(exception)
            //      < dynamic exception analysis >
            return(Ast.Block(
                       args,
                       Ast.Assign(
                           extracted,
                           Ast.Call(
                               AstMethods.SetCurrentException,
                               Parent.LocalContext,
                               exception
                               )
                           ),
                       body,
                       Ast.Assign(extracted, Ast.Constant(null)),
                       AstUtils.Empty()
                       ));
        }
Пример #26
0
 internal override MSA.Expression TransformDefinedCondition(AstGenerator /*!*/ gen)
 {
     return(Ast.NotEqual(TransformRead(gen), AstUtils.Constant(null)));
 }
Пример #27
0
        internal static MSAst.Expression TransformFor(ScopeStatement parent, MSAst.ParameterExpression enumerator,
                                                      Expression list, Expression left, MSAst.Expression body,
                                                      Statement else_, SourceSpan span, SourceLocation header,
                                                      MSAst.LabelTarget breakLabel, MSAst.LabelTarget continueLabel, bool isStatement)
        {
            // enumerator, isDisposable = Dynamic(GetEnumeratorBinder, list)
            MSAst.Expression init = Ast.Assign(
                enumerator,
                new PythonDynamicExpression1 <KeyValuePair <IEnumerator, IDisposable> >(
                    Binders.UnaryOperationBinder(
                        parent.GlobalParent.PyContext,
                        PythonOperationKind.GetEnumeratorForIteration
                        ),
                    parent.GlobalParent.CompilationMode,
                    AstUtils.Convert(list, typeof(object))
                    )
                );

            // while enumerator.MoveNext():
            //    left = enumerator.Current
            //    body
            // else:
            //    else
            MSAst.Expression ls = AstUtils.Loop(
                parent.GlobalParent.AddDebugInfo(
                    Ast.Call(
                        Ast.Property(
                            enumerator,
                            typeof(KeyValuePair <IEnumerator, IDisposable>).GetProperty("Key")
                            ),
                        typeof(IEnumerator).GetMethod("MoveNext")
                        ),
                    left.Span
                    ),
                null,
                Ast.Block(
                    left.TransformSet(
                        SourceSpan.None,
                        Ast.Call(
                            Ast.Property(
                                enumerator,
                                typeof(KeyValuePair <IEnumerator, IDisposable>).GetProperty("Key")
                                ),
                            typeof(IEnumerator).GetProperty("Current").GetGetMethod()
                            ),
                        PythonOperationKind.None
                        ),
                    body,
                    isStatement ? UpdateLineNumber(parent.GlobalParent.IndexToLocation(list.StartIndex).Line) : AstUtils.Empty(),
                    AstUtils.Empty()
                    ),
                else_,
                breakLabel,
                continueLabel
                );

            return(Ast.Block(
                       init,
                       Ast.TryFinally(
                           ls,
                           Ast.Call(AstMethods.ForLoopDispose, enumerator)
                           )
                       ));
        }
Пример #28
0
        private DynamicMetaObject MakeGetMemberTarget(GetMemberInfo getMemInfo, DynamicMetaObject target)
        {
            Type type = target.GetLimitType();
            BindingRestrictions restrictions = target.Restrictions;
            DynamicMetaObject   self         = target;

            target = target.Restrict(target.GetLimitType());

            // Specially recognized types: TypeTracker, NamespaceTracker, and StrongBox.
            // TODO: TypeTracker and NamespaceTracker should technically be IDO's.
            MemberGroup members = MemberGroup.EmptyGroup;

            if (typeof(TypeTracker).IsAssignableFrom(type))
            {
                restrictions = restrictions.Merge(
                    BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value)
                    );

                TypeGroup tg = target.Value as TypeGroup;
                Type      nonGen;
                if (tg == null || tg.TryGetNonGenericType(out nonGen))
                {
                    members = GetMember(MemberRequestKind.Get, ((TypeTracker)target.Value).Type, getMemInfo.Name);
                    if (members.Count > 0)
                    {
                        // we have a member that's on the type associated w/ the tracker, return that...
                        type = ((TypeTracker)target.Value).Type;
                        self = null;
                    }
                }
            }

            if (members.Count == 0)
            {
                // Get the members
                members = GetMember(MemberRequestKind.Get, type, getMemInfo.Name);
            }

            if (members.Count == 0)
            {
                if (typeof(TypeTracker).IsAssignableFrom(type))
                {
                    // ensure we don't have a non-generic type, and if we do report an error now.  This matches
                    // the rule version of the default binder but should probably be removed long term
                    Type x = ((TypeTracker)target.Value).Type;
                }
                else if (type.IsInterface)
                {
                    // all interfaces have object members
                    type    = typeof(object);
                    members = GetMember(MemberRequestKind.Get, type, getMemInfo.Name);
                }
            }

            DynamicMetaObject propSelf = self == null ? null : self;

            // if lookup failed try the strong-box type if available.
            if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(type) && propSelf != null)
            {
                // properties/fields need the direct value, methods hold onto the strong box.
                propSelf = new DynamicMetaObject(
                    Ast.Field(AstUtils.Convert(propSelf.Expression, type), type.GetField("Value")),
                    propSelf.Restrictions,
                    ((IStrongBox)propSelf.Value).Value
                    );

                type = type.GetGenericArguments()[0];

                members = GetMember(
                    MemberRequestKind.Get,
                    type,
                    getMemInfo.Name
                    );
            }

            MakeBodyHelper(getMemInfo, self, propSelf, type, members);

            getMemInfo.Body.Restrictions = restrictions;
            return(getMemInfo.Body.GetMetaObject(target));
        }
Пример #29
0
 internal DynamicMetaObject /*!*/ InvokeFallback(DynamicMetaObject /*!*/ target, DynamicMetaObject /*!*/[] /*!*/ args, CallSignature sig, DynamicMetaObject errorSuggestion)
 {
     return
         (PythonProtocol.Call(this, target, args) ??
          Context.Binder.Create(sig, target, args, AstUtils.Constant(_context.SharedContext)) ??
          Context.Binder.Call(sig, errorSuggestion, new PythonOverloadResolverFactory(Context.Binder, AstUtils.Constant(_context.SharedContext)), target, args));
 }
Пример #30
0
        // Ruby binders:
        internal CallArguments(RubyContext context, DynamicMetaObject /*!*/ scopeOrContextOrTargetOrArgArray, DynamicMetaObject /*!*/[] /*!*/ args, RubyCallSignature signature)
        {
            Assert.NotNull(scopeOrContextOrTargetOrArgArray);
            Assert.NotNullItems(args);

            ArgumentArray argArray = scopeOrContextOrTargetOrArgArray.Value as ArgumentArray;

            if (argArray != null)
            {
                Debug.Assert(args.Length == 0 && argArray.Count >= 1);

                // build meta-objects for arguments wrapped in the array:
                args = new DynamicMetaObject[argArray.Count - 1];
                for (int i = 0; i < args.Length; i++)
                {
                    args[i] = argArray.GetMetaObject(scopeOrContextOrTargetOrArgArray.Expression, 1 + i);
                }
                scopeOrContextOrTargetOrArgArray = argArray.GetMetaObject(scopeOrContextOrTargetOrArgArray.Expression, 0);
            }

            Debug.Assert(signature.HasScope == scopeOrContextOrTargetOrArgArray.Value is RubyScope);
            Debug.Assert((context == null && !signature.HasScope) == scopeOrContextOrTargetOrArgArray.Value is RubyContext);

            if (context != null)
            {
                // bound site:
                _context = new DynamicMetaObject(AstUtils.Constant(context), BindingRestrictions.Empty, context);
                if (signature.HasScope)
                {
                    _scope = scopeOrContextOrTargetOrArgArray;
                    _hasScopeOrContextArg = true;
                }
                else
                {
                    _target = scopeOrContextOrTargetOrArgArray;
                }
            }
            else if (signature.HasScope)
            {
                // unbound site with scope:
                _context = new DynamicMetaObject(
                    Methods.GetContextFromScope.OpCall(scopeOrContextOrTargetOrArgArray.Expression), BindingRestrictions.Empty,
                    ((RubyScope)scopeOrContextOrTargetOrArgArray.Value).RubyContext
                    );
                _scope = scopeOrContextOrTargetOrArgArray;
                _hasScopeOrContextArg = true;
                _target = null;
            }
            else
            {
                // unbound site with context:
                _context = scopeOrContextOrTargetOrArgArray;
                _hasScopeOrContextArg = true;
                _target = null;
            }

            Debug.Assert(_target != null || args.Length > 0);

            _args            = args;
            _copyArgsOnWrite = true;
            _signature       = signature;

            Debug.Assert(!signature.HasSplattedArgument || GetSplattedArgument() != null);
        }