/// <summary>
        /// Returns an expression which creates the function object.
        /// </summary>
        internal MSAst.Expression MakeFunctionExpression()
        {
            var defaults    = new List <MSAst.Expression>();
            var kwdefaults  = new List <MSAst.Expression>();
            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.Kind == ParameterKind.Normal && param.DefaultValue != null)
                {
                    defaults.Add(AstUtils.Convert(param.DefaultValue, typeof(object)));
                }

                if (param.Kind == ParameterKind.KeywordOnly && param.DefaultValue != null)
                {
                    kwdefaults.Add(Ast.Constant(param.Name, typeof(string)));
                    kwdefaults.Add(param.DefaultValue);
                }

                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),
                    kwdefaults.Count == 0 ? AstUtils.Constant(null, typeof(PythonDictionary)) :
                    (MSAst.Expression)Ast.Call(                                                     // 5. kwdefaults
                        AstMethods.MakeDictFromItems,
                        Ast.NewArrayInit(
                            typeof(object),
                            kwdefaults
                            )
                        ),
                    annotations.Count == 0 ? AstUtils.Constant(null, typeof(PythonDictionary)) :
                    (MSAst.Expression)Ast.Call(                                                     // 6. 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),
                    kwdefaults.Count == 0 ? AstUtils.Constant(null, typeof(PythonDictionary)) :
                    (MSAst.Expression)Ast.Call(                                                     // 5. kwdefaults
                        AstMethods.MakeDictFromItems,
                        Ast.NewArrayInit(
                            typeof(object),
                            kwdefaults
                            )
                        ),
                    annotations.Count == 0 ? AstUtils.Constant(null, typeof(PythonDictionary)) :
                    (MSAst.Expression)Ast.Call(                                                     // 6. annotations
                        AstMethods.MakeDictFromItems,
                        Ast.NewArrayInit(
                            typeof(object),
                            annotations
                            )
                        )
                    );
            }

            return(AddDecorators(ret, _decorators));
        }
Exemple #2
0
 internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen)
 {
     return(AstFactory.Block(Transform(gen), Ast.Constant(null)));
 }
Exemple #3
0
        internal MSAst.Expression ReduceWorker()
        {
            var retStmt = _body as ReturnStatement;

            if (retStmt != null &&
                (_languageFeatures == ModuleOptions.None ||
                 _languageFeatures == (ModuleOptions.ExecOrEvalCode | ModuleOptions.Interpret) ||
                 _languageFeatures == (ModuleOptions.ExecOrEvalCode | ModuleOptions.Interpret | ModuleOptions.LightThrow)))
            {
                // for simple eval's we can construct a simple tree which just
                // leaves the value on the stack.  Return's can't exist in modules
                // so this is always safe.
                Debug.Assert(!_isModule);

                var ret = (ReturnStatement)_body;
                Ast simpleBody;
                if ((_languageFeatures & ModuleOptions.LightThrow) != 0)
                {
                    simpleBody = LightExceptions.Rewrite(retStmt.Expression.Reduce());
                }
                else
                {
                    simpleBody = retStmt.Expression.Reduce();
                }

                var start = IndexToLocation(ret.Expression.StartIndex);
                var end   = IndexToLocation(ret.Expression.EndIndex);

                return(Ast.Block(
                           Ast.DebugInfo(
                               _document,
                               start.Line,
                               start.Column,
                               end.Line,
                               end.Column
                               ),
                           AstUtils.Convert(simpleBody, typeof(object))
                           ));
            }

            ReadOnlyCollectionBuilder <MSAst.Expression> block = new ReadOnlyCollectionBuilder <MSAst.Expression>();

            AddInitialiation(block);

            if (_isModule)
            {
                block.Add(AssignValue(GetVariableExpression(_docVariable), Ast.Constant(GetDocumentation(_body))));
            }

            if (!(_body is SuiteStatement) && _body.CanThrow)
            {
                // we only initialize line numbers in suite statements but if we don't generate a SuiteStatement
                // at the top level we can miss some line number updates.
                block.Add(UpdateLineNumber(_body.Start.Line));
            }

            block.Add(_body);

            MSAst.Expression body = Ast.Block(block.ToReadOnlyCollection());

            body = WrapScopeStatements(body, Body.CanThrow);   // new ComboActionRewriter().VisitNode(Transform(ag))

            body = AddModulePublishing(body);

            body = AddProfiling(body);

            if ((((PythonCompilerOptions)_compilerContext.Options).Module & ModuleOptions.LightThrow) != 0)
            {
                body = LightExceptions.Rewrite(body);
            }

            body = Ast.Label(FunctionDefinition._returnLabel, AstUtils.Convert(body, typeof(object)));
            if (body.Type == typeof(void))
            {
                body = Ast.Block(body, Ast.Constant(null));
            }

            return(body);
        }
Exemple #4
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, Target:
                        //          <body>
                        //  into:
                        //      if ((converted = CheckException(exception, Test)) != null) {
                        //          Target = converted;
                        //          traceback-header
                        //          <body>
                        //      }

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

                        ist = AstUtils.IfCondition(
                            Ast.NotEqual(
                                Ast.Assign(converted, test),
                                AstUtils.Constant(null)
                                ),
                            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()
                                )
                            );
                    }
                    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()
                       ));
        }
Exemple #5
0
 internal override void MakeGetExpression(PythonBinder /*!*/ binder, Expression /*!*/ codeContext, DynamicMetaObject instance, DynamicMetaObject /*!*/ owner, ConditionalBuilder /*!*/ builder)
 {
     builder.FinishCondition(Ast.Constant(this));
 }
Exemple #6
0
        // if (site.Version == <context>.ConstantAccessVersion) {
        //   object value = site.Value;
        //   if (value.GetType() == typeof(WeakReference)) {
        //     if (value == ConstantSiteCache.Missing) {
        //       <result> = ConstantMissing(...);
        //     } else {
        //       <result> = ((WeakReference)value).Target;
        //     }
        //   } else {
        //     <result> = value;
        //   }
        // } else {
        //   <result> = GetConstant(...);
        // }
        private static MSA.Expression /*!*/ MakeCachedRead(AstGenerator /*!*/ gen, int opKind, bool isGlobal, bool isQualified,
                                                           MSA.Expression /*!*/ name)
        {
            object siteCache;

            MSA.ParameterExpression siteVar, valueVar;
            FieldInfo versionField, valueField;

            MSA.Expression readValue;
            MSA.Expression fallback;

            if (opKind == OpIsDefined)
            {
                siteCache = new IsDefinedConstantSiteCache();
                gen.CurrentScope.GetIsDefinedConstantSiteCacheVariables(out siteVar);
                versionField = Fields.IsDefinedConstantSiteCache_Version;
                valueField   = Fields.IsDefinedConstantSiteCache_Value;

                readValue = Ast.Field(siteVar, valueField);

                fallback = (isQualified) ?
                           Methods.IsDefinedQualifiedConstant.OpCall(gen.CurrentScopeVariable, siteVar, name, AstUtils.Constant(isGlobal)) :
                           (isGlobal ? Methods.IsDefinedGlobalConstant : Methods.IsDefinedUnqualifiedConstant).
                           OpCall(gen.CurrentScopeVariable, siteVar, name);
            }
            else
            {
                siteCache = (ConstantSiteCache) new ConstantSiteCache();
                gen.CurrentScope.GetConstantSiteCacheVariables(out siteVar, out valueVar);
                versionField = Fields.ConstantSiteCache_Version;
                valueField   = Fields.ConstantSiteCache_Value;

                MSA.Expression weakValue = Ast.Call(Ast.Convert(valueVar, typeof(WeakReference)), Methods.WeakReference_get_Target);
                if (!isQualified)
                {
                    weakValue = Ast.Condition(
                        // const missing:
                        Ast.Equal(valueVar, AstUtils.Constant(ConstantSiteCache.WeakMissingConstant)),
                        (isGlobal ? Methods.GetGlobalMissingConstant : Methods.GetMissingConstant).
                        OpCall(gen.CurrentScopeVariable, siteVar, name),

                        // weak value:
                        weakValue
                        );
                }

                readValue = Ast.Condition(
                    Ast.TypeEqual(Ast.Assign(valueVar, Ast.Field(siteVar, valueField)), typeof(WeakReference)),
                    weakValue,
                    valueVar
                    );

                fallback = (isQualified ? Methods.GetQualifiedConstant : Methods.GetUnqualifiedConstant).
                           OpCall(gen.CurrentScopeVariable, siteVar, name, AstUtils.Constant(isGlobal));
            }

            return(Ast.Block(
                       Ast.Condition(
                           Ast.Equal(
                               Ast.Field(Ast.Assign(siteVar, Ast.Constant(siteCache)), versionField),
                               Ast.Field(Ast.Constant(gen.Context), Fields.RubyContext_ConstantAccessVersion)
                               ),
                           readValue,
                           fallback
                           )
                       ));
        }
        private DynamicMetaObject /*!*/ MakeMemberAccess(DynamicMetaObjectBinder /*!*/ member, string name, MemberAccess access, params DynamicMetaObject /*!*/[] /*!*/ args)
        {
            DynamicMetaObject self = Restrict(typeof(OldInstance));

            CustomInstanceDictionaryStorage dict;
            int key = GetCustomStorageSlot(name, out dict);

            if (key == -1)
            {
                PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldInstance " + access + " NoOptimized");
                return(MakeDynamicMemberAccess(member, name, access, args));
            }

            ParameterExpression tmp = Ast.Variable(typeof(object), "dict");
            Expression          target;

            ValidationInfo test = new ValidationInfo(
                Ast.NotEqual(
                    Ast.Assign(
                        tmp,
                        Ast.Call(
                            typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceGetOptimizedDictionary)),
                            self.Expression,
                            AstUtils.Constant(dict.KeyVersion)
                            )
                        ),
                    AstUtils.Constant(null)
                    )
                );

            PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldInstance " + access + " Optimized");
            switch (access)
            {
            case MemberAccess.Invoke:
                ParameterExpression value = Ast.Variable(typeof(object), "value");
                target = Ast.Block(
                    new[] { value },
                    Ast.Condition(
                        Ast.Call(
                            typeof(PythonOps).GetMethod(nameof(PythonOps.TryOldInstanceDictionaryGetValueHelper)),
                            tmp,
                            Ast.Constant(key),
                            AstUtils.Convert(Expression, typeof(object)),
                            value
                            ),
                        AstUtils.Convert(
                            ((InvokeMemberBinder)member).FallbackInvoke(new DynamicMetaObject(value, BindingRestrictions.Empty), args, null).Expression,
                            typeof(object)
                            ),
                        AstUtils.Convert(
                            ((InvokeMemberBinder)member).FallbackInvokeMember(self, args).Expression,
                            typeof(object)
                            )
                        )
                    );
                break;

            case MemberAccess.Get:
                // BUG: There's a missing Fallback path here that's always been present even
                // in the version that used rules.
                target = Ast.Call(
                    typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceDictionaryGetValueHelper)),
                    tmp,
                    AstUtils.Constant(key),
                    AstUtils.Convert(Expression, typeof(object))
                    );
                break;

            case MemberAccess.Set:
                target = Ast.Call(
                    typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceDictionarySetExtraValue)),
                    tmp,
                    AstUtils.Constant(key),
                    AstUtils.Convert(args[1].Expression, typeof(object))
                    );
                break;

            case MemberAccess.Delete:
                target = Ast.Call(
                    typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceDeleteCustomMember)),
                    AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
                    AstUtils.Convert(Expression, typeof(OldInstance)),
                    AstUtils.Constant(name)
                    );
                break;

            default:
                throw new InvalidOperationException();
            }

            return(BindingHelpers.AddDynamicTestAndDefer(
                       member,
                       new DynamicMetaObject(
                           target,
                           BindingRestrictions.Combine(args).Merge(self.Restrictions)
                           ),
                       args,
                       test,
                       tmp
                       ));
        }
            // TODO:
            // In Ruby 1.9 encoding of ASCII symbols is always BINARY (unlike strings).

            public MSA.Expression /*!*/ CreateExpression(AstGenerator /*!*/ gen, string /*!*/ literal)
            {
                return(Ast.Constant(gen.Context.CreateSymbol(literal, gen.Encoding)));
            }
        /// <summary>
        /// Adds a try/finally which enforces recursion limits around the target method.
        /// </summary>
        internal static Expression AddRecursionCheck(PythonContext pyContext, Expression expr)
        {
            ParameterExpression tmp = Ast.Variable(expr.Type, "callres");

            expr =
                Ast.Block(
                    new [] { tmp },
                    AstUtils.Try(
                        Ast.Call(typeof(PythonOps).GetMethod(nameof(PythonOps.FunctionPushFrame)), Ast.Constant(pyContext)),
                        Ast.Assign(tmp, expr)
                        ).Finally(
                        Ast.Call(typeof(PythonOps).GetMethod(nameof(PythonOps.FunctionPopFrame)))
                        ),
                    tmp
                    );
            return(expr);
        }
Exemple #10
0
        internal MSA.LambdaExpression /*!*/ TransformBody(AstGenerator /*!*/ gen, RubyScope /*!*/ declaringScope, RubyModule /*!*/ declaringModule)
        {
            string encodedName = RubyStackTraceBuilder.EncodeMethodName(_name, gen.SourcePath, Location, gen.DebugMode);

            AstParameters parameters;
            ScopeBuilder  scope = DefineLocals(out parameters);

            var scopeVariable  = scope.DefineHiddenVariable("#scope", typeof(RubyMethodScope));
            var selfParameter  = parameters[0];
            var blockParameter = parameters[1];

            // exclude block parameter even if it is explicitly specified:
            int visiblePrameterCountAndSignatureFlags = (parameters.Count - 2) << 2;

            if (_parameters.Block != null)
            {
                visiblePrameterCountAndSignatureFlags |= RubyMethodScope.HasBlockFlag;
            }
            if (_parameters.Array != null)
            {
                visiblePrameterCountAndSignatureFlags |= RubyMethodScope.HasUnsplatFlag;
            }

            gen.EnterMethodDefinition(
                scope,
                selfParameter,
                scopeVariable,
                blockParameter,
                _name,
                _parameters
                );

            // profiling:
            MSA.Expression profileStart, profileEnd;
            if (gen.Profiler != null)
            {
                int profileTickIndex = gen.Profiler.GetTickIndex(encodedName);
                var stampVariable    = scope.DefineHiddenVariable("#stamp", typeof(long));
                profileStart = Ast.Assign(stampVariable, Methods.Stopwatch_GetTimestamp.OpCall());
                profileEnd   = Methods.UpdateProfileTicks.OpCall(AstUtils.Constant(profileTickIndex), stampVariable);
            }
            else
            {
                profileStart = profileEnd = AstUtils.Empty();
            }

            // tracing:
            MSA.Expression traceCall, traceReturn;
            if (gen.TraceEnabled)
            {
                traceCall = Methods.TraceMethodCall.OpCall(
                    scopeVariable,
                    gen.SourcePathConstant,
                    AstUtils.Constant(Location.Start.Line)
                    );

                traceReturn = Methods.TraceMethodReturn.OpCall(
                    gen.CurrentScopeVariable,
                    gen.SourcePathConstant,
                    AstUtils.Constant(Location.End.Line)
                    );
            }
            else
            {
                traceCall = traceReturn = AstUtils.Empty();
            }

            MSA.ParameterExpression unwinder;

            MSA.Expression body = AstUtils.Try(
                profileStart,
                _parameters.TransformOptionalsInitialization(gen),
                traceCall,
                Body.TransformResult(gen, ResultOperation.Return)
                ).Filter(unwinder = Ast.Parameter(typeof(Exception), "#u"), Methods.IsMethodUnwinderTargetFrame.OpCall(scopeVariable, unwinder),
                         Ast.Return(gen.ReturnLabel, Methods.GetMethodUnwinderReturnValue.OpCall(unwinder))
                         ).Finally(
                // leave frame:
                Methods.LeaveMethodFrame.OpCall(scopeVariable),
                Ast.Empty(),
                profileEnd,
                traceReturn
                );

            body = gen.AddReturnTarget(
                scope.CreateScope(
                    scopeVariable,
                    Methods.CreateMethodScope.OpCall(new AstExpressions {
                scope.MakeLocalsStorage(),
                scope.GetVariableNamesExpression(),
                Ast.Constant(visiblePrameterCountAndSignatureFlags),
                Ast.Constant(declaringScope, typeof(RubyScope)),
                Ast.Constant(declaringModule, typeof(RubyModule)),
                Ast.Constant(_name),
                selfParameter, blockParameter,
                EnterInterpretedFrameExpression.Instance
            }),
                    body
                    )
                );

            gen.LeaveMethodDefinition();

            return(CreateLambda(encodedName, parameters, body));
        }
 public MSA.Expression /*!*/ CreateExpression(AstGenerator /*!*/ gen, string /*!*/ literal)
 {
     return(Methods.CreateMutableStringL.OpCall(Ast.Constant(literal), gen.EncodingConstant));
 }
Exemple #12
0
 public static Expression FxOdd(params Expression[] args)
 {
     if (Expect <int>(args, 1))
     {
         return(Ast.Equal(Ast.Add(UnwrapAndCast <int>(args[0]), Ast.Constant(1)), Ast.Constant(1)));
     }
     return(null);
 }
Exemple #13
0
 internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen)
 {
     return(Methods.CreateSymbolB.OpCall(Ast.Constant(_value)));
 }
        /// <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
                       ));
        }
Exemple #15
0
        private MSAst.LambdaExpression CreateOuterLambda(Type lambdaType, MSAst.Expression debuggableBody)
        {
            List <MSAst.Expression> bodyExpressions    = new List <MSAst.Expression>();
            List <MSAst.Expression> tryExpressions     = new List <MSAst.Expression>();
            List <MSAst.Expression> finallyExpressions = new List <MSAst.Expression>();

            Type returnType = lambdaType.GetMethod("Invoke").ReturnType;

            MSAst.LabelTarget returnLabelTarget = Ast.Label(returnType);

            // Init $funcInfo
            tryExpressions.Add(
                Ast.Assign(
                    _funcInfo,
                    Ast.Convert(_functionInfo, typeof(FunctionInfo))
                    )
                );

            // Init $traceLocations
            // $TODO: only do this if we're in TracePoints mode
            tryExpressions.Add(
                Ast.Assign(
                    _traceLocations,
                    Ast.Call(typeof(RuntimeOps).GetMethod("GetTraceLocations"), _funcInfo)
                    )
                );

            // Init sourceFile locals
            foreach (var entry in _sourceFilesMap)
            {
                tryExpressions.Add(
                    Ast.Assign(
                        entry.Value,
                        Ast.Constant(entry.Key, typeof(DebugSourceFile))
                        )
                    );
            }

            if (_noPushFrameOptimization)
            {
                tryExpressions.Add(_pushFrame);
            }

            tryExpressions.Add(Ast.Call(
                                   typeof(RuntimeOps).GetMethod("OnFrameEnterTraceEvent"),
                                   _thread
                                   ));

            var frameExit = AstUtils.If(
                Ast.Equal(
                    _debugMarkerLocationMap.Length > 0 ?
                    Ast.Property(_sourceFilesMap[_debugMarkerLocationMap[0].SourceFile], "Mode") :
                    _globalDebugMode,
                    AstUtils.Constant((int)DebugMode.FullyEnabled)
                    ),
                Ast.Call(
                    typeof(RuntimeOps).GetMethod("OnFrameExitTraceEvent"),
                    _thread,
                    _debugMarker,
                    _retVal != null ? (MSAst.Expression)Ast.Convert(_retVal, typeof(object)) : Ast.Constant(null)
                    )
                );

            // normal exit
            tryExpressions.Add(
                Ast.Block(
                    _retVal != null ? Ast.Assign(_retVal, debuggableBody) : debuggableBody,
                    Ast.Assign(_frameExitException, Ast.Constant(true)),
                    frameExit)
                );

            tryExpressions.Add(
                _retVal != null ? (MSAst.Expression)Ast.Return(returnLabelTarget, _retVal) : Ast.Empty()
                );

            MSAst.Expression[] popFrame = new MSAst.Expression[] {
                AstUtils.If(
                    // Fire thead-exit event if PopFrame returns true
                    Ast.AndAlso(
                        Ast.Equal(Ast.Call(typeof(RuntimeOps).GetMethod("PopFrame"), _thread), Ast.Constant(true)),
                        Ast.Equal(_globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled))
                        ),
                    Ast.Call(
                        typeof(RuntimeOps).GetMethod("OnThreadExitEvent"),
                        _thread
                        )
                    )
            };

            if (_noPushFrameOptimization)
            {
                finallyExpressions.AddRange(popFrame);
            }
            else
            {
                finallyExpressions.Add(
                    AstUtils.If(
                        Ast.Equal(_framePushed, Ast.Constant(true)),
                        popFrame
                        )
                    );
            }

            MSAst.ParameterExpression caughtException;

            // Run the function body
            bodyExpressions.Add(Ast.TryCatchFinally(
                                    Ast.TryCatch(
                                        Ast.Block(
                                            ArrayUtils.Append(tryExpressions.ToArray(), Ast.Default(returnType))
                                            ),
                                        Ast.Catch(
                                            caughtException = Ast.Variable(typeof(Exception), "$caughtException"),
                                            Ast.Block(
                                                // The expressions below will always throw.
                                                // If the exception needs to be cancelled then OnTraceEvent will throw ForceToGeneratorLoopException.
                                                // If the exception is not being cancelled then we'll just rethrow at the end of the catch block.
                                                AstUtils.If(
                                                    Ast.Not(
                                                        Ast.TypeIs(
                                                            caughtException,
                                                            typeof(ForceToGeneratorLoopException)
                                                            )
                                                        ),
                                                    AstUtils.If(
                                                        Ast.NotEqual(_globalDebugMode, AstUtils.Constant((int)DebugMode.Disabled)),
                                                        _noPushFrameOptimization ? Ast.Empty() : _conditionalPushFrame,
                                                        Ast.Call(
                                                            typeof(RuntimeOps).GetMethod("OnTraceEventUnwind"),
                                                            _thread,
                                                            _debugMarker,
                                                            caughtException
                                                            )
                                                        ),
                                                    // exception exit
                                                    AstUtils.If(
                                                        Ast.Not(_frameExitException),
                                                        frameExit
                                                        )
                                                    ),

                                                Ast.Rethrow(),

                                                // Ensuring that the catch block is of the same type as the try block
                                                Ast.Default(returnType)
                                                )
                                            )
                                        ),
                                    Ast.Block(finallyExpressions),
                                    Ast.Catch(
                                        typeof(ForceToGeneratorLoopException),
                                        Ast.TryFinally(
                                            // Handle ForceToGeneratorLoopException
                                            Ast.Block(
                                                returnType != typeof(void) ? Ast.Block(
                                                    Ast.Assign(
                                                        _retValFromGeneratorLoop,
                                                        Ast.Call(
                                                            typeof(RuntimeOps).GetMethod("GeneratorLoopProc"),
                                                            _thread
                                                            )
                                                        ),
                                                    AstUtils.If(
                                                        Ast.NotEqual(
                                                            _retValFromGeneratorLoop,
                                                            Ast.Constant(null)
                                                            ),
                                                        Ast.Assign(_retVal, Ast.Convert(_retValFromGeneratorLoop, returnType)),
                                                        Ast.Return(
                                                            returnLabelTarget,
                                                            Ast.Convert(_retValFromGeneratorLoop, returnType)
                                                            )
                                                        ).Else(
                                                        Ast.Assign(_retVal, Ast.Default(returnType)),
                                                        Ast.Return(
                                                            returnLabelTarget,
                                                            Ast.Default(returnType)
                                                            )
                                                        )
                                                    ) :
                                                Ast.Block(
                                                    Ast.Call(
                                                        typeof(RuntimeOps).GetMethod("GeneratorLoopProc"),
                                                        _thread
                                                        ),
                                                    Ast.Return(returnLabelTarget)
                                                    )
                                                ,
                                                // Ensuring that the catch block is of the same type as the try block
                                                Ast.Default(returnType)
                                                ),
                                            // Make sure that the debugMarker is up-to-date after the generator loop
                                            Ast.Assign(
                                                _debugMarker,
                                                Ast.Call(
                                                    typeof(RuntimeOps).GetMethod("GetCurrentSequencePointForLeafGeneratorFrame"),
                                                    _thread
                                                    )
                                                )
                                            )
                                        )
                                    ));

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

            if (body.Type == typeof(void) && returnType != typeof(void))
            {
                body = Ast.Block(body, Ast.Default(returnType));
            }

            return(Ast.Lambda(
                       lambdaType,
                       Ast.Block(
                           _lambdaVars,
                           Ast.Label(returnLabelTarget, body)
                           ),
                       _alias,
                       _lambdaParams));
        }
Exemple #16
0
        internal protected override Expression ToExpression(OverloadResolver resolver, RestrictedArguments args, bool[] hasBeenUsed)
        {
            var actualArgs     = resolver.GetActualArguments();
            int splatIndex     = actualArgs.SplatIndex;
            int collapsedCount = actualArgs.CollapsedCount;
            int firstSplatted  = actualArgs.FirstSplattedArg;

            var result        = new Expression[2 + _expandedCount + (collapsedCount > 0 ? 2 : 0)];
            var arrayVariable = resolver.GetTemporary(_elementType.MakeArrayType(), "a");
            int e             = 0;

            result[e++] = Ast.Assign(arrayVariable, Ast.NewArrayBounds(_elementType, Ast.Constant(_expandedCount + collapsedCount)));

            int itemIndex = 0;
            int i         = _start;

            while (true)
            {
                // inject loop copying collapsed items:
                if (i == splatIndex)
                {
                    var indexVariable = resolver.GetTemporary(typeof(int), "t");

                    // for (int t = 0; t <= {collapsedCount}; t++) {
                    //   a[{itemIndex} + t] = CONVERT<ElementType>(list.get_Item({splatIndex - firstSplatted} + t))
                    // }
                    result[e++] = Ast.Assign(indexVariable, AstUtils.Constant(0));
                    result[e++] = AstUtils.Loop(
                        Ast.LessThan(indexVariable, Ast.Constant(collapsedCount)),
                        // TODO: not implemented in the old interpreter
                        // Ast.PostIncrementAssign(indexVariable),
                        Ast.Assign(indexVariable, Ast.Add(indexVariable, AstUtils.Constant(1))),
                        Ast.Assign(
                            Ast.ArrayAccess(arrayVariable, Ast.Add(AstUtils.Constant(itemIndex), indexVariable)),
                            resolver.Convert(
                                new DynamicMetaObject(
                                    resolver.GetSplattedItemExpression(Ast.Add(AstUtils.Constant(splatIndex - firstSplatted), indexVariable)),
                                    BindingRestrictions.Empty
                                    ),
                                null,
                                ParameterInfo,
                                _elementType
                                )
                            ),
                        null
                        );

                    itemIndex += collapsedCount;
                }

                if (i >= _start + _expandedCount)
                {
                    break;
                }

                Debug.Assert(!hasBeenUsed[i]);
                hasBeenUsed[i] = true;

                result[e++] = Ast.Assign(
                    Ast.ArrayAccess(arrayVariable, AstUtils.Constant(itemIndex++)),
                    resolver.Convert(args.GetObject(i), args.GetType(i), ParameterInfo, _elementType)
                    );

                i++;
            }

            result[e++] = arrayVariable;

            Debug.Assert(e == result.Length);
            return(Ast.Block(result));
        }
        internal static void BuildConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, Type /*!*/ resultType,
                                             params ProtocolConversionAction /*!*/[] /*!*/ conversions)
        {
            Assert.NotNull(metaBuilder, args, conversions);
            Debug.Assert(args.SimpleArgumentCount == 0 && !args.Signature.HasBlock && !args.Signature.HasSplattedArgument && !args.Signature.HasRhsArgument);
            Debug.Assert(!args.Signature.HasScope);

            // implicit conversions should only depend on the static type:
            foreach (var conversion in conversions)
            {
                if (conversion.TryImplicitConversion(metaBuilder, args))
                {
                    metaBuilder.AddObjectTypeRestriction(args.Target, args.TargetExpression);

                    if (!metaBuilder.Error)
                    {
                        metaBuilder.Result = ConvertResult(metaBuilder.Result, resultType);
                    }
                    return;
                }
            }

            RubyClass                targetClass = args.RubyContext.GetImmediateClassOf(args.Target);
            Expression               targetClassNameConstant = AstUtils.Constant(targetClass.GetNonSingletonClass().Name, typeof(string));
            MethodResolutionResult   respondToMethod, methodMissing = MethodResolutionResult.NotFound;
            ProtocolConversionAction selectedConversion = null;
            RubyMemberInfo           conversionMethod   = null;

            using (targetClass.Context.ClassHierarchyLocker()) {
                // check for type version:
                metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext,
                                              ArrayUtils.Insert(Symbols.RespondTo, Symbols.MethodMissing, ArrayUtils.ConvertAll(conversions, (c) => c.ToMethodName))
                                              );

                // we can optimize if Kernel#respond_to? method is not overridden:
                respondToMethod = targetClass.ResolveMethodForSiteNoLock(Symbols.RespondTo, VisibilityContext.AllVisible);
                if (respondToMethod.Found && respondToMethod.Info.DeclaringModule == targetClass.Context.KernelModule && respondToMethod.Info is RubyLibraryMethodInfo)   // TODO: better override detection
                {
                    respondToMethod = MethodResolutionResult.NotFound;

                    // get the first applicable conversion:
                    foreach (var conversion in conversions)
                    {
                        selectedConversion = conversion;
                        conversionMethod   = targetClass.ResolveMethodForSiteNoLock(conversion.ToMethodName, VisibilityContext.AllVisible).Info;
                        if (conversionMethod != null)
                        {
                            break;
                        }
                        else
                        {
                            // find method_missing - we need to add "to_xxx" methods to the missing methods table:
                            if (!methodMissing.Found)
                            {
                                methodMissing = targetClass.ResolveMethodNoLock(Symbols.MethodMissing, VisibilityContext.AllVisible);
                            }
                            methodMissing.InvalidateSitesOnMissingMethodAddition(conversion.ToMethodName, targetClass.Context);
                        }
                    }
                }
            }

            if (!respondToMethod.Found)
            {
                if (conversionMethod == null)
                {
                    // error:
                    selectedConversion.SetError(metaBuilder, args, targetClassNameConstant, resultType);
                    return;
                }
                else
                {
                    // invoke target.to_xxx() and validate it; returns an instance of TTargetType:
                    conversionMethod.BuildCall(metaBuilder, args, selectedConversion.ToMethodName);

                    if (!metaBuilder.Error)
                    {
                        metaBuilder.Result = ConvertResult(
                            selectedConversion.MakeValidatorCall(args, targetClassNameConstant, metaBuilder.Result),
                            resultType
                            );
                    }
                    return;
                }
            }

            // slow path: invoke respond_to?, to_xxx and result validation:
            for (int i = conversions.Length - 1; i >= 0; i--)
            {
                string toMethodName = conversions[i].ToMethodName;

                var conversionCallSite = AstUtils.LightDynamic(
                    RubyCallAction.Make(args.RubyContext, toMethodName, RubyCallSignature.WithImplicitSelf(0)),
                    args.TargetExpression
                    );

                metaBuilder.Result = Ast.Condition(
                    // If

                    // respond_to?()
                    Methods.IsTrue.OpCall(
                        AstUtils.LightDynamic(
                            RubyCallAction.Make(args.RubyContext, Symbols.RespondTo, RubyCallSignature.WithImplicitSelf(1)),
                            args.TargetExpression,
                            Ast.Constant(args.RubyContext.CreateSymbol(toMethodName, RubyEncoding.Binary))
                            )
                        ),

                    // Then

                    // to_xxx():
                    ConvertResult(
                        conversions[i].MakeValidatorCall(args, targetClassNameConstant, conversionCallSite),
                        resultType
                        ),

                    // Else

                    (i < conversions.Length - 1) ? metaBuilder.Result :
                    conversions[i].MakeErrorExpression(args, targetClassNameConstant, resultType)
                    );
            }
        }
Exemple #18
0
 internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen)
 {
     return(Ast.Constant(gen.Context.CreateSymbol((string)Value, gen.Encoding)));
 }
Exemple #19
0
 protected static Expression MakeClosure(CodeBlock cb, bool varargs, bool typed)
 {
     if (varargs)
     {
         return(Ast.SimpleCallHelper(Closure_MakeVarArgsX, Ast.CodeBlockExpression(cb, false, typed),
                                     Ast.Constant(cb.ParameterCount)));
     }
     else
     {
         return(Ast.SimpleCallHelper(Closure_Make, Ast.CodeBlockExpression(cb, false, typed), Ast.Constant(cb.ParameterCount)));
     }
 }
            // Conversion to a delegate.
            // Explicit: convertible to any delegate type.
            // Implicit: convertible to a delegate type of the same arity as the block.
            public Convertibility IsConvertibleTo(Type /*!*/ type, bool @explicit)
            {
                if (!typeof(Delegate).IsAssignableFrom(type))
                {
                    return(Convertibility.NotConvertible);
                }

                if (@explicit)
                {
                    return(Convertibility.AlwaysConvertible);
                }

                if (!HasValue)
                {
                    return(Convertibility.NotConvertible);
                }

                MethodInfo invoke = type.GetMethod("Invoke");

                if (invoke == null)
                {
                    return(Convertibility.NotConvertible);
                }

                int delegateArity = invoke.GetParameters().Length;

                return(new Convertibility(
                           delegateArity == Value.Dispatcher.ParameterCount || delegateArity > Value.Dispatcher.ParameterCount && Value.Dispatcher.HasUnsplatParameter,
                           Ast.Equal(Methods.GetProcArity.OpCall(AstUtils.Convert(Expression, typeof(Proc))), Ast.Constant(Value.Dispatcher.Arity))
                           ));
            }
Exemple #21
0
        internal override void BuildSuperCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name, RubyModule /*!*/ declaringModule)
        {
            Assert.NotNull(declaringModule, metaBuilder, args);
            var visibleOverloads = GetVisibleOverloads(args, MethodBases, true);

            if (visibleOverloads.Count == 0)
            {
                metaBuilder.SetError(Methods.MakeClrVirtualMethodCalledError.OpCall(
                                         args.MetaContext.Expression, args.MetaTarget.Expression, Ast.Constant(name)
                                         ));
            }
            else
            {
                BuildCallNoFlow(metaBuilder, args, name, visibleOverloads, CallConvention, ImplicitProtocolConversions);
            }
        }
Exemple #22
0
        internal static MSA.Expression /*!*/ MakeUserMethodBody(AstGenerator gen, int lastLine,
                                                                MSA.Expression /*!*/ blockParameter, MSA.Expression /*!*/ rfcVariable,
                                                                MSA.ParameterExpression /*!*/ methodUnwinder, MSA.Expression /*!*/ bodyStatement, ResultOperation resultOperation,
                                                                int profileTickIndex, MSA.ParameterExpression stampVariable, MSA.LabelTarget returnLabel)
        {
            Assert.NotNull(blockParameter, rfcVariable, bodyStatement, methodUnwinder);
            Debug.Assert(!resultOperation.IsIgnore, "return value should not be ignored");
            Debug.Assert(returnLabel != null || resultOperation.Variable != null, "return label needed");

            MSA.Expression resultExpression = Ast.Field(methodUnwinder, MethodUnwinder.ReturnValueField);
            if (resultOperation.Variable != null)
            {
                resultExpression = Ast.Assign(resultOperation.Variable, resultExpression);
            }
            else
            {
                resultExpression = Ast.Return(returnLabel, resultExpression);
            }

            // TODO: move this to the caller:
            MSA.Expression profileStart, profileEnd;
            if (stampVariable != null)
            {
                profileStart = Ast.Assign(stampVariable, Methods.Stopwatch_GetTimestamp.OpCall());
                profileEnd   = Methods.UpdateProfileTicks.OpCall(Ast.Constant(profileTickIndex), stampVariable);
            }
            else
            {
                profileStart = profileEnd = Ast.Empty();
            }

            return(AstUtils.Try(
                       // initialize frame (RFC):
                       profileStart,
                       Ast.Assign(rfcVariable, Methods.CreateRfcForMethod.OpCall(AstUtils.Convert(blockParameter, typeof(Proc)))),
                       bodyStatement
                       ).Filter(methodUnwinder, Ast.Equal(Ast.Field(methodUnwinder, MethodUnwinder.TargetFrameField), rfcVariable),

                                // return unwinder.ReturnValue;
                                resultExpression

                                ).Finally(
                       Ast.Assign(Ast.Field(rfcVariable, RuntimeFlowControl.IsActiveMethodField), Ast.Constant(false)),
                       profileEnd,
                       gen != null && gen.TraceEnabled ? Methods.TraceMethodReturn.OpCall(
                           gen.CurrentScopeVariable,
                           Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)),
                           Ast.Constant(lastLine)
                           ) : Ast.Empty()
                       ));
        }
Exemple #23
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))
                       ));
        }
Exemple #24
0
        public void AddTargetTypeTest(object target, RubyClass /*!*/ targetClass, Expression /*!*/ targetParameter, DynamicMetaObject /*!*/ metaContext,
                                      IEnumerable <string> /*!*/ resolvedNames)
        {
            // no changes to the module's class hierarchy while building the test:
            targetClass.Context.RequiresClassHierarchyLock();

            // initialization changes the version number, so ensure that the module is initialized:
            targetClass.InitializeMethodsNoLock();

            var context = (RubyContext)metaContext.Value;

            if (target is IRubyObject)
            {
                Type type = target.GetType();
                AddTypeRestriction(type, targetParameter);

                // Ruby objects (get the method directly to prevent interface dispatch):
                MethodInfo classGetter = type.GetMethod(Methods.IRubyObject_get_ImmediateClass.Name, BindingFlags.Public | BindingFlags.Instance);
                if (type.IsVisible && classGetter != null && classGetter.ReturnType == typeof(RubyClass))
                {
                    AddCondition(
                        // (#{type})target.ImmediateClass.Version.Method == #{immediateClass.Version.Method}
                        Ast.Equal(
                            Ast.Field(
                                Ast.Field(
                                    Ast.Call(Ast.Convert(targetParameter, type), classGetter),
                                    Fields.RubyModule_Version
                                    ),
                                Fields.VersionHandle_Method
                                ),
                            AstUtils.Constant(targetClass.Version.Method)
                            )
                        );
                    return;
                }

                // TODO: explicit iface-implementation
                throw new NotSupportedException("Type implementing IRubyObject should be visible and have ImmediateClass getter");
            }

            AddRuntimeTest(metaContext);

            // singleton nil:
            if (target == null)
            {
                AddRestriction(Ast.Equal(targetParameter, AstUtils.Constant(null)));
                AddVersionTest(context.NilClass);
                return;
            }

            // singletons true, false:
            if (target is bool)
            {
                AddRestriction(Ast.AndAlso(
                                   Ast.TypeIs(targetParameter, typeof(bool)),
                                   Ast.Equal(Ast.Convert(targetParameter, typeof(bool)), AstUtils.Constant(target))
                                   ));

                AddVersionTest((bool)target ? context.TrueClass : context.FalseClass);
                return;
            }

            var nominalClass = targetClass.NominalClass;

            Debug.Assert(!nominalClass.IsSingletonClass);
            Debug.Assert(!nominalClass.IsRubyClass);

            // Do we need a singleton check?
            if (nominalClass.ClrSingletonMethods == null ||
                CollectionUtils.TrueForAll(resolvedNames, (methodName) => !nominalClass.ClrSingletonMethods.ContainsKey(methodName)))
            {
                // no: there is no singleton subclass of target class that defines any method being called:
                AddTypeRestriction(target.GetType(), targetParameter);
                AddVersionTest(targetClass);
            }
            else if (targetClass.IsSingletonClass)
            {
                // yes: check whether the incoming object is a singleton and the singleton has the right version:
                AddTypeRestriction(target.GetType(), targetParameter);
                AddCondition(Methods.IsClrSingletonRuleValid.OpCall(
                                 metaContext.Expression,
                                 targetParameter,
                                 AstUtils.Constant(targetClass.Version.Method)
                                 ));
            }
            else
            {
                // yes: check whether the incoming object is NOT a singleton and the class has the right version:
                AddTypeRestriction(target.GetType(), targetParameter);
                AddCondition(Methods.IsClrNonSingletonRuleValid.OpCall(
                                 metaContext.Expression,
                                 targetParameter,
                                 Ast.Constant(targetClass.Version),
                                 AstUtils.Constant(targetClass.Version.Method)
                                 ));
            }
        }
Exemple #25
0
        internal static DynamicMetaObject Call(DynamicMetaObjectBinder /*!*/ call, DynamicMetaObject target, DynamicMetaObject /*!*/[] /*!*/ args)
        {
            Assert.NotNull(call, args);
            Assert.NotNullItems(args);

            if (target.NeedsDeferral())
            {
                return(call.Defer(ArrayUtils.Insert(target, args)));
            }

            foreach (DynamicMetaObject mo in args)
            {
                if (mo.NeedsDeferral())
                {
                    RestrictTypes(args);

                    return(call.Defer(
                               ArrayUtils.Insert(target, args)
                               ));
                }
            }

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

            ValidationInfo valInfo   = BindingHelpers.GetValidationInfo(target);
            PythonType     pt        = DynamicHelpers.GetPythonType(target.Value);
            PythonContext  pyContext = PythonContext.GetPythonContext(call);

            // look for __call__, if it's present dispatch to it.  Otherwise fall back to the
            // default binder
            PythonTypeSlot callSlot;

            if (!typeof(Delegate).IsAssignableFrom(target.GetLimitType()) &&
                pt.TryResolveSlot(pyContext.SharedContext, "__call__", out callSlot))
            {
                ConditionalBuilder cb = new ConditionalBuilder(call);
                Expression         body;

                callSlot.MakeGetExpression(
                    pyContext.Binder,
                    PythonContext.GetCodeContext(call),
                    self,
                    GetPythonType(self),
                    cb
                    );

                if (!cb.IsFinal)
                {
                    cb.FinishCondition(GetCallError(call, self));
                }

                Expression[] callArgs = ArrayUtils.Insert(
                    PythonContext.GetCodeContext(call),
                    cb.GetMetaObject().Expression,
                    DynamicUtils.GetExpressions(args)
                    );

                body = DynamicExpression.Dynamic(
                    PythonContext.GetPythonContext(call).Invoke(
                        BindingHelpers.GetCallSignature(call)
                        ),
                    typeof(object),
                    callArgs
                    );

                body = Ast.TryFinally(
                    Ast.Block(
                        Ast.Call(typeof(PythonOps).GetMethod(nameof(PythonOps.FunctionPushFrame)), Ast.Constant(pyContext)),
                        body
                        ),
                    Ast.Call(typeof(PythonOps).GetMethod(nameof(PythonOps.FunctionPopFrame)))
                    );

                return(BindingHelpers.AddDynamicTestAndDefer(
                           call,
                           new DynamicMetaObject(body, self.Restrictions.Merge(BindingRestrictions.Combine(args))),
                           args,
                           valInfo
                           ));
            }

            return(null);
        }
Exemple #26
0
        protected internal static Expression GetAst(object args, CodeBlock cb, bool istailposition)
        {
            var spanHint = SpanHint;

            if (args is Annotation)
            {
                args = ((Annotation)args).stripped;
            }
            Cons c = args as Cons;

            if (c != null)
            {
                // in debug mode, this will be (annotated-call <location> . symbol)
                // TODO: see if the discarded annotation is useful
                if (ScriptDomainManager.Options.DebugMode && c.car is Cons)
                {
                    Cons ac = c.car as Cons;
                    if (ac.car == SymbolTable.StringToObject("annotated-call"))
                    {
                        object se = ((Cons)ac.cdr).cdr;
                        if (se is SymbolId)
                        {
                            c.car = se;
                        }
                    }
                }

                if (c.car is SymbolId)
                {
                    SymbolId f = (SymbolId)c.car;

                    Variable var = cb.Lookup(f);

                    if (var != null && !assigns.ContainsKey(f))
                    {
                        var = null;
                    }

                    object m;

#if OPTIMIZATIONS
#if !BLAH
                    CodeBlockExpression cbe;

                    //// needs to do the same for overloads...
                    if (SimpleGenerator.libraryglobals.TryGetValue(f, out cbe))
                    {
                        Expression[] ppp = GetAstListNoCast(c.cdr as Cons, cb);

                        if (cbe.Block.ParameterCount < 9 && cbe.Block.ParameterCount == ppp.Length)
                        {
                            //inline here? we could for simple bodies, but we need to copy the entire structure
                            if (!(cbe.Block.HasEnvironment || cbe.Block.IsClosure))
                            {
                                if (cbe.Block.Body is ReturnStatement)
                                {
                                    ReturnStatement rs = (ReturnStatement)cbe.Block.Body;

                                    if (!cb.IsGlobal && IsSimpleExpression(rs.Expression))
                                    {
                                        return(InlineCall(cb, Ast.CodeBlockExpression(RewriteBody(cbe.Block), false, cbe.IsStronglyTyped), ppp));
                                    }
                                }
                            }
                            if (cbe.Block != cb.Parent && cbe.Block != cb) // do TCE later
                            {
                                return(CallNormal(cbe, ppp));
                            }
                        }
                    }

                    // varargs
                    if (SimpleGenerator.libraryglobalsX.TryGetValue(f, out cbe))
                    {
                        Expression[] ppp = GetAstListNoCast(c.cdr as Cons, cb);

                        if (cbe.Block.ParameterCount < 9 && cbe.Block.ParameterCount - 1 <= ppp.Length)
                        {
                            //inline here?
                            return(CallVarArgs(cbe, ppp));
                        }
                    }

                    // overloads
                    CodeBlockDescriptor[] cbd;
                    if (SimpleGenerator.libraryglobalsN.TryGetValue(f, out cbd))
                    {
                        Expression[] ppp = GetAstListNoCast(c.cdr as Cons, cb);

                        foreach (CodeBlockDescriptor d in cbd)
                        {
                            if (d.codeblock.Block.ParameterCount < 9)
                            {
                                if (ppp.Length == d.arity || (d.varargs && ppp.Length > d.arity))
                                {
                                    if (d.varargs)
                                    {
                                        //inline here?
                                        return(CallVarArgs(d.codeblock, ppp));
                                    }
                                    else
                                    {
                                        //inline here?
                                        //if (d.codeblock.Block != cb.Parent && d.codeblock.Block != cb) // do TCE later, not yet
                                        {
                                            return(CallNormal(d.codeblock, ppp));
                                        }
                                    }
                                }
                            }
                        }
                    }
#endif

                    //if (!ScriptDomainManager.Options.DebugMode)
                    {
                        if (f == SymbolTable.StringToId("call-with-values"))
                        {
                            Expression[] ppp = GetAstListNoCast(c.cdr as Cons, cb);
                            if (ppp.Length == 2 && ppp[1] is MethodCallExpression)
                            {
                                MethodCallExpression consumer = ppp[1] as MethodCallExpression;

                                if (ppp[0] is MethodCallExpression)
                                {
                                    MethodCallExpression producer = ppp[0] as MethodCallExpression;
                                    if (consumer.Method == Closure_Make && producer.Method == Closure_Make)
                                    {
                                        CodeBlockExpression ccbe = consumer.Arguments[0] as CodeBlockExpression;
                                        CodeBlockExpression pcbe = producer.Arguments[0] as CodeBlockExpression;

                                        pcbe.Block.Bind();
                                        ccbe.Block.Bind();

                                        if (ccbe.Block.ParameterCount == 0)
                                        {
                                            return(InlineCall(cb, ccbe));
                                        }
                                        else if (ccbe.Block.ParameterCount == 1)
                                        {
                                            return(InlineCall(cb, ccbe, Ast.SimpleCallHelper(typeof(Helpers).GetMethod("UnwrapValue"), InlineCall(cb, pcbe))));
                                        }
                                        else
                                        {
                                            Variable values = cb.CreateTemporaryVariable((SymbolId)Builtins.GenSym("values"), typeof(object[]));

                                            Expression valuesarr = Ast.Read(values);

                                            Expression[] pppp = new Expression[ccbe.Block.ParameterCount];

                                            for (int i = 0; i < pppp.Length; i++)
                                            {
                                                pppp[i] = Ast.ArrayIndex(valuesarr, Ast.Constant(i));
                                            }

                                            return(Ast.Comma(
                                                       Ast.Void(
                                                           Ast.Write(
                                                               values,
                                                               Ast.ComplexCallHelper(
                                                                   Ast.SimpleCallHelper(typeof(Helpers).GetMethod("WrapValue"), InlineCall(cb, pcbe)),
                                                                   typeof(MultipleValues).GetMethod("ToArray", new Type[] { typeof(int) }),
                                                                   Ast.Constant(pppp.Length)))),
                                                       InlineCall(cb, ccbe, pppp)));
                                        }
                                    }
                                }
                                if (consumer.Method == Closure_Make)
                                {
                                    CodeBlockExpression ccbe = consumer.Arguments[0] as CodeBlockExpression;
                                    ccbe.Block.Bind();

                                    Expression producer = ppp[0];

                                    Expression exx = Ast.ConvertHelper(producer, typeof(Callable));

                                    MethodInfo callx = GetCallable(0);

                                    if (ccbe.Block.ParameterCount == 0)
                                    {
                                        return(InlineCall(cb, ccbe));
                                    }
                                    else if (ccbe.Block.ParameterCount == 1)
                                    {
                                        return(InlineCall(cb, ccbe, Ast.SimpleCallHelper(typeof(Helpers).GetMethod("UnwrapValue"), Ast.Call(exx, callx))));
                                    }
                                    else
                                    {
                                        Variable values = cb.CreateTemporaryVariable((SymbolId)Builtins.GenSym("values"), typeof(object[]));

                                        Expression valuesarr = Ast.Read(values);

                                        Expression[] pppp = new Expression[ccbe.Block.ParameterCount];

                                        for (int i = 0; i < pppp.Length; i++)
                                        {
                                            pppp[i] = Ast.ArrayIndex(valuesarr, Ast.Constant(i));
                                        }

                                        return(Ast.Comma(
                                                   Ast.Void(
                                                       Ast.Write(
                                                           values,
                                                           Ast.ComplexCallHelper(
                                                               Ast.SimpleCallHelper(typeof(Helpers).GetMethod("WrapValue"),
                                                                                    Ast.Call(exx, callx)),
                                                               typeof(MultipleValues).GetMethod("ToArray", new Type[] { typeof(int) }),
                                                               Ast.Constant(pppp.Length)))),
                                                   InlineCall(cb, ccbe, pppp)));
                                    }
                                }
                            }
                            else
                            {
                                ;
                            }
                        }
                    }
#endif
                    // this can be enabled once builtins are auto CPS'd.
                    // ok I tried, but there are issues still, not sure what
#if OPTIMIZATIONS
                    // check for inline emitter
                    InlineEmitter ie;
                    if (TryGetInlineEmitter(f, out ie))
                    {
                        Expression result = ie(GetAstList(c.cdr as Cons, cb));
                        // if null is returned, the method cannot be inlined
                        if (result != null)
                        {
                            if (spanHint.IsValid)
                            {
                                result.SetLoc(spanHint);
                            }
                            return(result);
                        }
                    }
#endif

                    if (Context.Scope.TryLookupName(f, out m))
                    {
                        if (var == null)
                        {
                            IGenerator gh = m as IGenerator;
                            if (gh != null)
                            {
                                return(gh.Generate(c.cdr, cb));
                            }

                            BuiltinMethod bf = m as BuiltinMethod;
                            if (bf != null)
                            {
                                MethodBinder mb   = bf.Binder;
                                Expression[] pars = Array.ConvertAll(GetAstList(c.cdr as Cons, cb), e => Unwrap(e));

                                if (bf.AllowConstantFold && !ScriptDomainManager.Options.DebugMode)
                                {
                                    bool constant = Array.TrueForAll(pars, e => e is ConstantExpression && e.Type != typeof(BigInteger));

                                    if (constant)
                                    {
                                        object[]    cargs = Array.ConvertAll(pars, e => GetRuntimeConstant((ConstantExpression)e));
                                        CallTarget0 disp  = delegate
                                        {
                                            return(bf.Call(cargs));
                                        };
                                        CallTarget1 handler = delegate(object e)
                                        {
                                            throw new CompileTimeEvaluationException();
                                        };

                                        try
                                        {
                                            object result = Runtime.R6RS.Exceptions.WithExceptionHandler(
                                                Closure.Create(handler),
                                                Closure.Create(disp));
                                            var rrrr = GetCons(result, cb);
                                            if (spanHint.IsValid)
                                            {
                                                rrrr.SetLoc(spanHint);
                                            }
                                            return(rrrr);
                                        }
                                        catch (CompileTimeEvaluationException)
                                        {
                                        }
                                    }
                                }

                                Type[]          types = GetExpressionTypes(pars);
                                MethodCandidate mc    = mb.MakeBindingTarget(CallType.None, types);
                                if (mc != null)
                                {
                                    if (mc.Target.NeedsContext)
                                    {
                                        pars = ArrayUtils.Insert <Expression>(Ast.CodeContext(), pars);
                                    }
                                    MethodBase meth = mc.Target.Method;

                                    var rrrr = Ast.ComplexCallHelper(meth as MethodInfo, pars);
                                    if (spanHint.IsValid)
                                    {
                                        rrrr.SetLoc(spanHint);
                                    }
                                    return(rrrr);
                                }
                            }

                            Closure clos = m as Closure;
                            if (clos != null && !SetGenerator.IsAssigned(f))
                            {
                                // no provision for varargs
                                MethodInfo[] mis = clos.Targets;
                                if (mis.Length > 0)
                                {
                                    MethodBinder mb = MethodBinder.MakeBinder(binder, SymbolTable.IdToString(f), mis, BinderType.Normal);

                                    Expression[] pars = Array.ConvertAll(GetAstList(c.cdr as Cons, cb), e => Unwrap(e));

                                    if (clos.AllowConstantFold && !ScriptDomainManager.Options.DebugMode)
                                    {
                                        bool constant = Array.TrueForAll(pars, e => e is ConstantExpression && e.Type != typeof(BigInteger));

                                        if (constant)
                                        {
                                            object[] cargs = Array.ConvertAll(pars, e => GetRuntimeConstant((ConstantExpression)e));

                                            CallTarget0 disp = delegate
                                            {
                                                var rrrr = clos.Call(cargs);
                                                return(rrrr);
                                            };

                                            CallTarget1 handler = delegate(object e)
                                            {
                                                throw new CompileTimeEvaluationException();
                                            };

                                            try
                                            {
                                                object result = Runtime.R6RS.Exceptions.WithExceptionHandler(
                                                    Closure.Create(handler),
                                                    Closure.Create(disp));
                                                var rrrr = GetCons(result, cb);
                                                if (spanHint.IsValid)
                                                {
                                                    rrrr.SetLoc(spanHint);
                                                }
                                                return(rrrr);
                                            }
                                            catch (CompileTimeEvaluationException)
                                            {
                                            }
                                        }
                                    }

                                    // exclude transient members if needed
                                    if (!AllowTransientBinding)
                                    {
                                        mis = Array.FindAll(mis, x => !IsTransient(x.Module));
                                    }

                                    if (mis.Length > 0)
                                    {
                                        Type[]          types = GetExpressionTypes(pars);
                                        MethodCandidate mc    = mb.MakeBindingTarget(CallType.None, types);
                                        if (mc != null)
                                        {
                                            if (mc.Target.NeedsContext)
                                            {
                                                pars = ArrayUtils.Insert <Expression>(Ast.CodeContext(), pars);
                                            }
                                            MethodBase meth = mc.Target.Method;

                                            var rrrr = Ast.ComplexCallHelper(meth as MethodInfo, pars);
                                            if (spanHint.IsValid)
                                            {
                                                rrrr.SetLoc(spanHint);
                                            }
                                            return(rrrr);
                                        }
                                    }
                                }
                                // check for overload thing
                            }
                        }
                    }
                }


                Expression ex = Unwrap(GetAst(c.car, cb));

                // a 'let'
                if (ex is MethodCallExpression)
                {
                    var ppp = GetAstList(c.cdr as Cons, cb);
                    MethodCallExpression mcexpr = (MethodCallExpression)ex;
                    if (mcexpr.Method == Closure_Make)
                    {
                        CodeBlockExpression cbe = mcexpr.Arguments[0] as CodeBlockExpression;

                        if (ppp.Length < 9 && cbe.Block.ParameterCount == ppp.Length)
                        {
                            return(InlineCall(cb, cbe, istailposition, ppp));
                        }
                    }

                    // cater for varargs more efficiently, this does not seem to hit, probably needed somewhere else, hits in ironscheme-test and cut test
                    if (mcexpr.Method == Closure_MakeVarArgsX)
                    {
                        CodeBlockExpression cbe = mcexpr.Arguments[0] as CodeBlockExpression;

                        if (ppp.Length < 9 && cbe.Block.ParameterCount <= ppp.Length && !NeedsContext(cbe))
                        {
                            // TODO: See why having a context fails here
                            return(CallVarArgs(cbe, ppp));
                        }
                    }
                }

                if (ex is NewExpression && typeof(ITypedCallable).IsAssignableFrom(ex.Type))
                {
                    NewExpression       mcexpr = ex as NewExpression;
                    CodeBlockExpression cbe    = mcexpr.Arguments[0] as CodeBlockExpression;
                    if (cbe == null && mcexpr.Arguments[0].Type == typeof(CodeContext) && mcexpr.Arguments[0] is ConstantExpression) // implies null
                    {
                        cbe = mcexpr.Arguments[1] as CodeBlockExpression;
                    }
                    if (cbe != null)
                    {
                        var ppp = GetAstListNoCast(c.cdr as Cons, cb);

                        if (ppp.Length < 9 && cbe.Block.ParameterCount == ppp.Length)
                        {
                            return(InlineCall(cb, cbe, istailposition, ppp));
                        }
                    }
                }

                if (ex is ConstantExpression)
                {
                    Builtins.SyntaxError(SymbolTable.StringToObject("generator"), "expecting a procedure", c.car, c);
                }

                Expression r = null;

                if (ex.Type.Name.StartsWith("TypedClosure"))
                {
                    Expression[] pp = GetAstListNoCast(c.cdr as Cons, cb);

                    var m = ex.Type.GetMethod("Invoke");
                    //TODO: add more checks, should we attempt some casting for types?
                    if (m.GetParameters().Length != pp.Length)
                    {
                        Builtins.SyntaxError(SymbolTable.StringToObject("apply-typed-lambda"),
                                             string.Format("incorrect number of parameters, expected {0} got {1}", m.GetParameters().Length, pp.Length),
                                             c.car, c);
                    }
                    r = Ast.SimpleCallHelper(ex, m, pp);
                }
                else
                {
                    Expression[] pp = GetAstList(c.cdr as Cons, cb);

                    if (ex.Type != typeof(Callable))
                    {
                        ex = Ast.ConvertHelper(ex, typeof(Callable));
                    }

                    MethodInfo call = GetCallable(pp.Length);

                    r = pp.Length > 8 ?
                        Ast.Call(ex, call, Ast.NewArray(typeof(object[]), pp)) :
                        Ast.Call(ex, call, pp);
                }

                if (spanHint.IsValid)
                {
                    r.SetLoc(spanHint);
                }

                return(r);
            }

            object[] v = args as object[];

            if (v != null)
            {
                return(GetConsVector(v, cb));
            }
            else if (args is byte[])
            {
                Expression[] ba = Array.ConvertAll(args as byte[], b => Ast.Constant(b));
                return(Ast.NewArray(typeof(byte[]), ba));
            }
            else
            {
                if (args is SymbolId)
                {
                    SymbolId sym = (SymbolId)args;
                    if (sym == SymbolTable.StringToId("uninitialized"))
                    {
                        return(Ast.ReadField(null, typeof(Uninitialized), "Instance"));
                    }
                    else
                    {
                        return(Read(sym, cb, typeof(object)));
                    }
                }
                if (args == Builtins.Unspecified)
                {
                    return(Ast.ReadField(null, Unspecified));
                }
                if (args is Fraction)
                {
                    Fraction f = (Fraction)args;
                    return(Ast.Constant(new FractionConstant(f)));
                }
                if (args is ComplexFraction)
                {
                    ComplexFraction f = (ComplexFraction)args;
                    return(Ast.Constant(new ComplexFractionConstant(f)));
                }
                if (args != null && args.GetType().Name == "stx")
                {
                    args = new SerializedConstant(args);
                }
                return(Ast.Constant(args));
            }
        }
Exemple #27
0
        private DynamicMetaObject /*!*/ MakeSetMember(SetMemberBinder /*!*/ member, DynamicMetaObject /*!*/ value)
        {
            PythonContext     state = PythonContext.GetPythonContext(member);
            DynamicMetaObject self  = Restrict(Value.GetType());

            if (Value.GetType() != typeof(PythonType) && DynamicHelpers.GetPythonType(Value).IsSystemType)
            {
                // built-in subclass of .NET type.  Usually __setattr__ is handled by MetaUserObject
                // but we can have a built-in subtype that's not a user type.
                PythonTypeSlot pts;
                if (Value.TryGetCustomSetAttr(state.SharedContext, out pts))
                {
                    Debug.Assert(pts.GetAlwaysSucceeds);

                    ParameterExpression tmp = Ast.Variable(typeof(object), "boundVal");

                    return(BindingHelpers.AddDynamicTestAndDefer(
                               member,
                               new DynamicMetaObject(
                                   Ast.Block(
                                       new[] { tmp },
                                       DynamicExpression.Dynamic(
                                           state.Invoke(new CallSignature(2)),
                                           typeof(object),
                                           AstUtils.Constant(state.SharedContext),
                                           Ast.Block(
                                               Ast.Call(
                                                   typeof(PythonOps).GetMethod(nameof(PythonOps.SlotTryGetValue)),
                                                   AstUtils.Constant(state.SharedContext),
                                                   AstUtils.Convert(AstUtils.WeakConstant(pts), typeof(PythonTypeSlot)),
                                                   AstUtils.Convert(Expression, typeof(object)),
                                                   AstUtils.Convert(AstUtils.WeakConstant(DynamicHelpers.GetPythonType(Value)), typeof(PythonType)),
                                                   tmp
                                                   ),
                                               tmp
                                               ),
                                           Ast.Constant(member.Name),
                                           value.Expression
                                           )
                                       ),
                                   self.Restrictions
                                   ),
                               new DynamicMetaObject[] { this, value },
                               TestUserType()
                               ));
                }
            }

            return(BindingHelpers.AddDynamicTestAndDefer(
                       member,
                       new DynamicMetaObject(
                           Ast.Call(
                               typeof(PythonOps).GetMethod(nameof(PythonOps.PythonTypeSetCustomMember)),
                               AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
                               self.Expression,
                               AstUtils.Constant(member.Name),
                               AstUtils.Convert(
                                   value.Expression,
                                   typeof(object)
                                   )
                               ),
                           self.Restrictions.Merge(value.Restrictions)
                           ),
                       new DynamicMetaObject[] { this, value },
                       TestUserType()
                       ));
        }
Exemple #28
0
        protected static Expression GetCons(object args, CodeBlock cb)
        {
            if (args is Annotation)
            {
                args = ((Annotation)args).stripped;
            }
            Cons c = args as Cons;

            if (c != null)
            {
                if (inconstant)
                {
                    return(GetConsList(c, cb));
                }
                else
                {
                    return(Ast.Constant(new IronSchemeConstant(c, cb)));
                }
            }
            object[] v = args as object[];
            if (v != null)
            {
                return(GetConsVector(v, cb));
            }
            else if (args is byte[])
            {
                return(Ast.Constant(new ArrayConstant <byte>((byte[])args)));
            }
            else if (args is int[])
            {
                return(Ast.Constant(new ArrayConstant <int>((int[])args)));
            }
            else if (args is double[])
            {
                return(Ast.Constant(new ArrayConstant <double>((double[])args)));
            }
            else if (args is Fraction)
            {
                Fraction f = (Fraction)args;
                return(Ast.Constant(new FractionConstant(f)));
            }
            else if (args is ComplexFraction)
            {
                ComplexFraction cf = (ComplexFraction)args;
                return(Ast.Constant(new ComplexFractionConstant(cf)));
            }
            else if (args is SchemeChar)
            {
                SchemeChar f = (SchemeChar)args;
                return(Ast.Constant(new SchemeCharConstant(f)));
            }
            else if (args is StringBuilder)
            {
                StringBuilder f = (StringBuilder)args;
                return(Ast.Constant(f.ToString()));
            }
            else
            {
                if (args is long)
                {
                    args = (BigInteger)(long)args;
                }
                if (args != null && args.GetType().Namespace.StartsWith("record."))
                {
                    args = new SerializedConstant(args);
                }
                return(Ast.Constant(args));
            }
        }
Exemple #29
0
        private MSAst.Expression AddModulePublishing(MSAst.Expression body)
        {
            if (_isModule)
            {
                PythonCompilerOptions pco = _compilerContext.Options as PythonCompilerOptions;

                string moduleName = ModuleName;

                if ((pco.Module & ModuleOptions.Initialize) != 0)
                {
                    var tmp = Ast.Variable(typeof(object), "$originalModule");
                    // TODO: Should be try/fault

                    body = Ast.Block(
                        new[] { tmp },
                        AstUtils.Try(
                            Ast.Assign(tmp, Ast.Call(AstMethods.PublishModule, LocalContext, Ast.Constant(moduleName))),
                            body
                            ).Catch(
                            typeof(Exception),
                            Ast.Call(AstMethods.RemoveModule, LocalContext, Ast.Constant(moduleName), tmp),
                            Ast.Rethrow(body.Type)
                            )
                        );
                }
            }
            return(body);
        }
Exemple #30
0
        /// <summary> if a member-injector is defined-on or registered-for this type call it </summary>
        protected void MakeOperatorGetMemberBody(Type type, string name)
        {
            MethodInfo getMem = GetMethod(type, name);

            if (getMem != null && getMem.IsSpecialName)
            {
                ParameterExpression tmp = Rule.GetTemporary(typeof(object), "getVal");
                AddToBody(
                    AstUtils.If(
                        Ast.NotEqual(
                            Ast.Assign(
                                tmp,
                                Binder.MakeCallExpression(Rule.Context, getMem, Instance, Ast.Constant(StringName))
                                ),
                            Ast.Field(null, typeof(OperationFailed).GetField("Value"))
                            ),
                        Rule.MakeReturn(Binder, tmp)
                        )
                    );
            }
        }