private Expression LightCatch(CatchBlock[] handlers) { // start off with the rethrow - just a return of the value. Then // walk backwards and add each handler as a test in a cascading // conditional. If all tests fail, we make it back to the return value. Expression rethrow = PropagateException(typeof(object)); for (int i = handlers.Length - 1; i >= 0; i--) { var curHandler = handlers[i]; Expression test = Expression.NotEqual( Expression.Assign( curHandler.Variable, Expression.TypeAs(_lastException, curHandler.Test) ), Expression.Constant(null) ); if (handlers[i].Filter != null) { throw new NotSupportedException("filters for light exceptions"); // we could do this but the emulation wouldn't be perfect when filters // run in relation to finallys //test = Expression.AndAlso(test, handlers[i].Filter); } rethrow = Expression.Block( new[] { curHandler.Variable }, Expression.Condition( test, Utils.Convert(handlers[i].Body, typeof(object)), rethrow ) ); } return rethrow; }
private void MakeFieldRule(SetOrDeleteMemberInfo memInfo, DynamicMetaObject instance, DynamicMetaObject target, Type targetType, MemberGroup fields, DynamicMetaObject errorSuggestion) { FieldTracker field = (FieldTracker)fields[0]; // TODO: Tmp variable for target if (instance != null && field.DeclaringType.IsGenericType && field.DeclaringType.GetGenericTypeDefinition() == typeof(StrongBox <>)) { // work around a CLR bug where we can't access generic fields from dynamic methods. Type[] generic = field.DeclaringType.GetGenericArguments(); memInfo.Body.FinishCondition( MakeReturnValue( Ast.Assign( Ast.Field( AstUtils.Convert(instance.Expression, field.DeclaringType), field.DeclaringType.GetField("Value") ), AstUtils.Convert(target.Expression, generic[0]) ), target ) ); } else if (field.IsInitOnly || field.IsLiteral) { memInfo.Body.FinishError( errorSuggestion ?? MakeError( MakeReadOnlyMemberError(targetType, memInfo.Name), typeof(object) ) ); } else if (field.IsStatic && targetType != field.DeclaringType) { memInfo.Body.FinishError( errorSuggestion ?? MakeError( MakeStaticAssignFromDerivedTypeError(targetType, instance, field, target, memInfo.ResolutionFactory), typeof(object) ) ); } else if (field.DeclaringType.IsValueType && !field.IsStatic) { memInfo.Body.FinishError( errorSuggestion ?? MakeError( MakeSetValueTypeFieldError(field, instance, target), typeof(object) ) ); } else if (field.IsPublic && field.DeclaringType.IsVisible) { if (!field.IsStatic && instance == null) { memInfo.Body.FinishError( Ast.Throw( Ast.New( typeof(ArgumentException).GetConstructor(new Type[] { typeof(string) }), AstUtils.Constant("assignment to instance field w/o instance") ), typeof(object) ) ); } else { memInfo.Body.FinishCondition( MakeReturnValue( Ast.Assign( Ast.Field( field.IsStatic ? null : AstUtils.Convert(instance.Expression, field.DeclaringType), field.Field ), ConvertExpression(target.Expression, field.FieldType, ConversionResultKind.ExplicitCast, memInfo.ResolutionFactory) ), target ) ); } } else { Debug.Assert(field.IsStatic || instance != null); memInfo.Body.FinishCondition( MakeReturnValue( Ast.Call( AstUtils.Convert(AstUtils.Constant(field.Field), typeof(FieldInfo)), typeof(FieldInfo).GetMethod("SetValue", new Type[] { typeof(object), typeof(object) }), field.IsStatic ? AstUtils.Constant(null) : (Expression)AstUtils.Convert(instance.Expression, typeof(object)), AstUtils.Convert(target.Expression, typeof(object)) ), target ) ); } }
public override LightLambdaExpression ReduceAst(PythonAst instance, string name) { return(Utils.LightLambda <Func <FunctionCode, object> >(typeof(object), AstUtils.Convert(instance.ReduceWorker(), typeof(object)), name, new[] { PythonAst._functionCode })); }
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)) )); }
public override MSAst.Expression GetConstant(object value) { return(AstUtils.Constant(value)); }
internal static Expression ExplicitConvert(Expression /*!*/ expr, Type /*!*/ fromType, Type /*!*/ toType) { expr = AstUtils.Convert(expr, fromType); if (HasExplicitNumericConversion(fromType, toType)) { // special cases to mimic Ruby behavior precisely: if (fromType == typeof(BigInteger)) { if (toType == typeof(int)) { return(Methods.ConvertBignumToFixnum.OpCall(expr)); } else if (toType == typeof(double)) { return(Methods.ConvertBignumToFloat.OpCall(expr)); } } else if (fromType == typeof(double) && toType == typeof(int)) { return(Methods.ConvertDoubleToFixnum.OpCall(expr)); } return(Ast.ConvertChecked(expr, toType)); } MethodInfo converter = CompilerHelpers.GetExplicitConverter(fromType, toType); if (converter != null) { return(Ast.Call(null, converter, expr)); } if (fromType == typeof(char) && toType == typeof(string)) { return(Ast.Call(null, fromType.GetMethod("ToString", BindingFlags.Public | BindingFlags.Static), expr)); } if (toType == typeof(bool)) { Debug.Assert(fromType != typeof(bool)); return(fromType.IsValueType() ? AstUtils.Constant(true) : Ast.NotEqual(expr, AstUtils.Constant(null))); } // TODO: //if (TypeConverter...(fromType, toType)) { // return true; //} return(null); }
public override Expression /*!*/ CreateExpression() { return(Methods.GetMethod(GetType(), "MakeShared").OpCall(_signature.CreateExpression(), AstUtils.Constant(_lexicalScopeId))); }
/// <summary> /// Translates our CallSignature into a DLR Argument list and gives the simple MetaObject's which are extracted /// from the tuple or dictionary parameters being splatted. /// </summary> private void TranslateArguments(DynamicMetaObject target, DynamicMetaObject /*!*/[] /*!*/ args, out CallInfo /*!*/ callInfo, out List <Expression /*!*/> /*!*/ metaArgs, out Expression test, out BindingRestrictions restrictions) { Argument[] argInfo = _signature.GetArgumentInfos(); List <string> namedArgNames = new List <string>(); metaArgs = new List <Expression>(); metaArgs.Add(target.Expression); Expression splatArgTest = null; Expression splatKwArgTest = null; restrictions = BindingRestrictions.Empty; for (int i = 0; i < argInfo.Length; i++) { Argument ai = argInfo[i]; switch (ai.Kind) { case ArgumentType.Dictionary: PythonDictionary iac = (PythonDictionary)args[i].Value; List <string> argNames = new List <string>(); foreach (KeyValuePair <object, object> kvp in iac) { string key = (string)kvp.Key; namedArgNames.Add(key); argNames.Add(key); metaArgs.Add( Expression.Call( AstUtils.Convert(args[i].Expression, typeof(PythonDictionary)), typeof(PythonDictionary).GetMethod("get_Item", new[] { typeof(object) }), AstUtils.Constant(key) ) ); } restrictions = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[i].Expression, args[i].GetLimitType())); splatKwArgTest = Expression.Call( typeof(PythonOps).GetMethod("CheckDictionaryMembers"), AstUtils.Convert(args[i].Expression, typeof(PythonDictionary)), AstUtils.Constant(argNames.ToArray()) ); break; case ArgumentType.List: IList <object> splattedArgs = (IList <object>)args[i].Value; splatArgTest = Expression.Equal( Expression.Property(AstUtils.Convert(args[i].Expression, args[i].GetLimitType()), typeof(ICollection <object>).GetProperty("Count")), AstUtils.Constant(splattedArgs.Count) ); for (int splattedArg = 0; splattedArg < splattedArgs.Count; splattedArg++) { metaArgs.Add( Expression.Call( AstUtils.Convert(args[i].Expression, typeof(IList <object>)), typeof(IList <object>).GetMethod("get_Item"), AstUtils.Constant(splattedArg) ) ); } restrictions = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[i].Expression, args[i].GetLimitType())); break; case ArgumentType.Named: namedArgNames.Add(ai.Name); metaArgs.Add(args[i].Expression); break; case ArgumentType.Simple: metaArgs.Add(args[i].Expression); break; default: throw new InvalidOperationException(); } } callInfo = new CallInfo(metaArgs.Count - 1, namedArgNames.ToArray()); test = splatArgTest; if (splatKwArgTest != null) { if (test != null) { test = Expression.AndAlso(test, splatKwArgTest); } else { test = splatKwArgTest; } } }
/// <summary> /// WithStatement is translated to the DLR AST equivalent to /// the following Python code snippet (from with statement spec): /// /// mgr = (EXPR) /// exit = mgr.__exit__ # Not calling it yet /// value = mgr.__enter__() /// exc = True /// try: /// VAR = value # Only if "as VAR" is present /// BLOCK /// except: /// # The exceptional case is handled here /// exc = False /// if not exit(*sys.exc_info()): /// raise /// # The exception is swallowed if exit() returns true /// finally: /// # The normal and non-local-goto cases are handled here /// if exc: /// exit(None, None, None) /// /// </summary> public override MSAst.Expression Reduce() { // Five statements in the result... ReadOnlyCollectionBuilder <MSAst.Expression> statements = new ReadOnlyCollectionBuilder <MSAst.Expression>(6); ReadOnlyCollectionBuilder <MSAst.ParameterExpression> variables = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>(6); MSAst.ParameterExpression lineUpdated = Ast.Variable(typeof(bool), "$lineUpdated_with"); variables.Add(lineUpdated); //****************************************************************** // 1. mgr = (EXPR) //****************************************************************** MSAst.ParameterExpression manager = Ast.Variable(typeof(object), "with_manager"); variables.Add(manager); statements.Add( GlobalParent.AddDebugInfo( Ast.Assign( manager, _contextManager ), new SourceSpan(Start, _header) ) ); //****************************************************************** // 2. exit = mgr.__exit__ # Not calling it yet //****************************************************************** MSAst.ParameterExpression exit = Ast.Variable(typeof(object), "with_exit"); variables.Add(exit); statements.Add( MakeAssignment( exit, GlobalParent.Get( "__exit__", manager ) ) ); //****************************************************************** // 3. value = mgr.__enter__() //****************************************************************** MSAst.ParameterExpression value = Ast.Variable(typeof(object), "with_value"); variables.Add(value); statements.Add( GlobalParent.AddDebugInfoAndVoid( MakeAssignment( value, Parent.Invoke( new CallSignature(0), Parent.LocalContext, GlobalParent.Get( "__enter__", manager ) ) ), new SourceSpan(Start, _header) ) ); //****************************************************************** // 4. exc = True //****************************************************************** MSAst.ParameterExpression exc = Ast.Variable(typeof(bool), "with_exc"); variables.Add(exc); statements.Add( MakeAssignment( exc, AstUtils.Constant(true) ) ); //****************************************************************** // 5. The final try statement: // // try: // VAR = value # Only if "as VAR" is present // BLOCK // except: // # The exceptional case is handled here // exc = False // if not exit(*sys.exc_info()): // raise // # The exception is swallowed if exit() returns true // finally: // # The normal and non-local-goto cases are handled here // if exc: // exit(None, None, None) //****************************************************************** MSAst.ParameterExpression exception; statements.Add( // try: AstUtils.Try( AstUtils.Try(// try statement body PushLineUpdated(false, lineUpdated), _var != null ? (MSAst.Expression)Ast.Block( // VAR = value _var.TransformSet(SourceSpan.None, value, PythonOperationKind.None), // BLOCK _body, AstUtils.Empty() ) : // BLOCK (MSAst.Expression)_body // except:, // try statement location ).Catch(exception = Ast.Variable(typeof(Exception), "exception"), // Python specific exception handling code TryStatement.GetTracebackHeader( this, exception, GlobalParent.AddDebugInfoAndVoid( Ast.Block( // exc = False MakeAssignment( exc, AstUtils.Constant(false) ), // if not exit(*sys.exc_info()): // raise AstUtils.IfThen( GlobalParent.Convert( typeof(bool), ConversionResultKind.ExplicitCast, GlobalParent.Operation( typeof(bool), PythonOperationKind.IsFalse, MakeExitCall(exit, exception) ) ), UpdateLineUpdated(true), Ast.Throw( Ast.Call( AstMethods.MakeRethrowExceptionWorker, exception ) ) ) ), _body.Span ) ), PopLineUpdated(lineUpdated), Ast.Empty() ) // finally: ).Finally( // if exc: // exit(None, None, None) AstUtils.IfThen( exc, GlobalParent.AddDebugInfoAndVoid( Ast.Block( Ast.Dynamic( GlobalParent.PyContext.Invoke( new CallSignature(3) // signature doesn't include function ), typeof(object), new MSAst.Expression[] { Parent.LocalContext, exit, AstUtils.Constant(null), AstUtils.Constant(null), AstUtils.Constant(null) } ), Ast.Empty() ), _contextManager.Span ) ) ) ); statements.Add(AstUtils.Empty()); return(Ast.Block(variables.ToReadOnlyCollection(), statements.ToReadOnlyCollection())); }
private static MethodMissingBinding BindToKernelMethodMissing(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ methodName, RubyMemberInfo methodMissing, RubyMethodVisibility incompatibleVisibility, bool isSuperCall) { // TODO: better specialization of method_missing methods if (methodMissing == null || methodMissing.DeclaringModule == methodMissing.Context.KernelModule && methodMissing is RubyLibraryMethodInfo) { if (isSuperCall) { metaBuilder.SetError(Methods.MakeMissingSuperException.OpCall(AstUtils.Constant(methodName))); } else if (incompatibleVisibility == RubyMethodVisibility.Private) { metaBuilder.SetError(Methods.MakePrivateMethodCalledError.OpCall( AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName)) ); } else if (incompatibleVisibility == RubyMethodVisibility.Protected) { metaBuilder.SetError(Methods.MakeProtectedMethodCalledError.OpCall( AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName)) ); } else { return(MethodMissingBinding.Fallback); } return(MethodMissingBinding.Error); } return(MethodMissingBinding.Custom); }
internal static MethodResolutionResult Resolve(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args, out RubyMemberInfo methodMissing) { MethodResolutionResult method; var targetClass = args.TargetClass; var visibilityContext = GetVisibilityContext(args.Signature, args.Scope); using (targetClass.Context.ClassHierarchyLocker()) { metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext, new[] { methodName, Symbols.MethodMissing } ); if (args.Signature.IsSuperCall) { Debug.Assert(!args.Signature.IsVirtualCall && args.Signature.HasImplicitSelf); method = targetClass.ResolveSuperMethodNoLock(methodName, targetClass).InvalidateSitesOnOverride(); } else { var options = args.Signature.IsVirtualCall ? MethodLookup.Virtual : MethodLookup.Default; method = targetClass.ResolveMethodForSiteNoLock(methodName, visibilityContext, options); } if (!method.Found) { methodMissing = targetClass.ResolveMethodMissingForSite(methodName, method.IncompatibleVisibility); } else { methodMissing = null; } } // Whenever the current self's class changes we need to invalidate the rule, if a protected method is being called. if (method.Info != null && method.Info.IsProtected && visibilityContext.Class != null) { // We don't need to compare versions, just the class objects (super-class relationship cannot be changed). // Since we don't want to hold on a class object (to make it collectible) we compare references to the version handlers. metaBuilder.AddCondition(Ast.Equal( Methods.GetSelfClassVersionHandle.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope))), Ast.Constant(visibilityContext.Class.Version) )); } return(method); }
public void AddCallArguments(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { _callArguments = args; // calculate actual argument count: _actualArgumentCount = args.SimpleArgumentCount; if (args.Signature.HasSplattedArgument) { var splattedArg = args.GetSplattedMetaArgument(); metaBuilder.AddSplattedArgumentTest((IList)splattedArg.Value, splattedArg.Expression, out _listLength, out _listVariable); _actualArgumentCount += _listLength; } if (args.Signature.HasRhsArgument) { _actualArgumentCount++; } // check: if (HasTooFewArguments) { metaBuilder.SetWrongNumberOfArgumentsError(_actualArgumentCount, _mandatoryParamCount); return; } if (HasTooManyArguments) { metaBuilder.SetWrongNumberOfArgumentsError(_actualArgumentCount, _mandatoryParamCount); return; } bool isSplatted; // leading mandatory: for (int i = 0; i < _leadingMandatoryParamCount; i++) { _arguments[LeadingMandatoryIndex + i] = GetArgument(i, out isSplatted); } // trailing mandatory: for (int i = 0; i < TrailingMandatoryCount; i++) { _arguments[TrailingMandatoryIndex + i] = GetArgument(_actualArgumentCount - TrailingMandatoryCount + i, out isSplatted); } int start = _leadingMandatoryParamCount; int end = _actualArgumentCount - TrailingMandatoryCount; // optional: for (int i = 0; i < _optionalParamCount; i++) { _arguments[OptionalParameterIndex + i] = (start < end) ? GetArgument(start++, out isSplatted) : Ast.Field(null, Fields.DefaultArgument); } // unsplat: if (_hasUnsplatParameter) { Expression array; if (args.Signature.HasSplattedArgument) { // simple: var argsToUnsplat = new List <Expression>(); while (start < end) { var arg = GetArgument(start, out isSplatted); if (isSplatted) { break; } argsToUnsplat.Add(AstUtils.Box(arg)); start++; } array = Methods.MakeArrayOpCall(argsToUnsplat); int rangeStart = start - args.SimpleArgumentCount; int rangeLength = Math.Min(end - start, _listLength - rangeStart); // splatted: if (rangeLength > 0) { array = Methods.AddSubRange.OpCall(array, _listVariable, Ast.Constant(rangeStart), Ast.Constant(rangeLength)); start += rangeLength; } // rhs: while (start < end) { array = Methods.AddItem.OpCall(array, AstUtils.Box(GetArgument(start, out isSplatted))); start++; } } else { var argsToUnsplat = new List <Expression>(end - start); while (start < end) { argsToUnsplat.Add(AstUtils.Box(GetArgument(start++, out isSplatted))); } array = Methods.MakeArrayOpCall(argsToUnsplat); } _arguments[UnsplatParameterIndex] = array; } _callArguments = null; _listVariable = null; Debug.Assert(CollectionUtils.TrueForAll(_arguments, (e) => e != null)); }
/// <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 )); }
/// <summary> /// Returns an expression which creates the function object. /// </summary> internal MSAst.Expression MakeFunctionExpression() { var defaults = new List <MSAst.Expression>(0); var annotations = new List <MSAst.Expression>(); if (ReturnAnnotation != null) { annotations.Add(Ast.Constant("return", typeof(string))); annotations.Add(ReturnAnnotation); } foreach (var param in _parameters) { if (param.DefaultValue != null) { defaults.Add(AstUtils.Convert(param.DefaultValue, typeof(object))); } if (param.Annotation != null) { annotations.Add(Ast.Constant(param.Name, typeof(string))); annotations.Add(param.Annotation); } } MSAst.Expression funcCode = GlobalParent.Constant(GetOrMakeFunctionCode()); FuncCodeExpr = funcCode; MSAst.Expression ret; if (EmitDebugFunction()) { LightLambdaExpression code = CreateFunctionLambda(); // we need to compile all of the debuggable code together at once otherwise mdbg gets confused. If we're // in tracing mode we'll still compile things one off though just to keep things simple. The code will still // be debuggable but naive debuggers like mdbg will have more issues. ret = Ast.Call( AstMethods.MakeFunctionDebug, // method Parent.LocalContext, // 1. Emit CodeContext FuncCodeExpr, // 2. FunctionCode ((IPythonGlobalExpression)GetVariableExpression(_nameVariable)).RawValue(), // 3. module name defaults.Count == 0 ? // 4. default values AstUtils.Constant(null, typeof(object[])) : (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults), annotations.Count == 0 ? AstUtils.Constant(null, typeof(PythonDictionary)) : (MSAst.Expression)Ast.Call( // 5. annotations AstMethods.MakeDictFromItems, Ast.NewArrayInit( typeof(object), annotations ) ), IsGenerator ? (MSAst.Expression) new PythonGeneratorExpression(code, GlobalParent.PyContext.Options.CompilationThreshold) : (MSAst.Expression)code ); } else { ret = Ast.Call( AstMethods.MakeFunction, // method Parent.LocalContext, // 1. Emit CodeContext FuncCodeExpr, // 2. FunctionCode ((IPythonGlobalExpression)GetVariableExpression(_nameVariable)).RawValue(), // 3. module name defaults.Count == 0 ? // 4. default values AstUtils.Constant(null, typeof(object[])) : (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults), annotations.Count == 0 ? AstUtils.Constant(null, typeof(PythonDictionary)) : (MSAst.Expression)Ast.Call( // 5. annotations AstMethods.MakeDictFromItems, Ast.NewArrayInit( typeof(object), annotations ) ) ); } return(AddDecorators(ret, _decorators)); }
protected override Expression ToExpression(OverloadResolver resolver, RestrictedArguments args, bool[] hasBeenUsed) { return(AstUtils.Constant(Activator.CreateInstance(ParameterInfo.ParameterType))); }
protected override MSAst.Expression VisitTry(MSAst.TryExpression node) { MSAst.Expression b = Visit(node.Body); ReadOnlyCollection <MSAst.CatchBlock> h = Visit(node.Handlers, VisitCatchBlock); MSAst.Expression y = Visit(node.Finally); MSAst.Expression f; _insideConditionalBlock = true; try { f = Visit(node.Fault); } finally { _insideConditionalBlock = false; } node = Ast.MakeTry(node.Type, b, y, f, h); List <MSAst.CatchBlock> newHandlers = null; MSAst.Expression newFinally = null; // If the TryStatement has any Catch blocks we need to insert the exception // event as a first statement so that we can be notified of first-chance exceptions. if (node.Handlers != null && node.Handlers.Count > 0) { newHandlers = new List <MSAst.CatchBlock>(); foreach (var catchBlock in node.Handlers) { MSAst.ParameterExpression exceptionVar = catchBlock.Variable != null ? catchBlock.Variable : Ast.Parameter(catchBlock.Test, null); MSAst.Expression debugMarker, thread; if (_transformToGenerator) { debugMarker = Ast.Call( typeof(RuntimeOps).GetMethod("GetCurrentSequencePointForGeneratorFrame"), _frame ); thread = Ast.Call(typeof(RuntimeOps).GetMethod("GetThread"), _frame); } else { debugMarker = _debugMarker; thread = _thread; } MSAst.Expression exceptionEvent = Ast.Block( // Rethrow ForceToGeneratorLoopException AstUtils.If( Ast.TypeIs( exceptionVar, typeof(ForceToGeneratorLoopException) ), Ast.Throw(exceptionVar) ), AstUtils.If( Ast.Equal(_globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled)), (_pushFrame != null) ? _pushFrame : Ast.Empty(), Ast.Call( typeof(RuntimeOps).GetMethod("OnTraceEvent"), thread, debugMarker, exceptionVar ) ) ); newHandlers.Add(Ast.MakeCatchBlock( catchBlock.Test, exceptionVar, Ast.Block( exceptionEvent, catchBlock.Body ), catchBlock.Filter )); } } if (!_transformToGenerator && node.Finally != null) { // Prevent the user finally block from running if the frame is currently remapping to generator newFinally = AstUtils.If( Ast.Not( Ast.Call( typeof(RuntimeOps).GetMethod("IsCurrentLeafFrameRemappingToGenerator"), _thread ) ), node.Finally ); } if (newHandlers != null || newFinally != null) { node = Ast.MakeTry( node.Type, node.Body, newFinally != null ? newFinally : node.Finally, node.Fault, newHandlers != null ? newHandlers : newHandlers ); } return(node); }
protected override MSAst.Expression VisitDebugInfo(MSAst.DebugInfoExpression node) { if (!node.IsClear) { MSAst.Expression transformedExpression; // Verify that DebugInfoExpression has valid SymbolDocumentInfo if (node.Document == null || String.IsNullOrEmpty(node.Document.FileName)) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ErrorStrings.DebugInfoWithoutSymbolDocumentInfo, _locationCookie)); } DebugSourceFile sourceFile = _debugContext.GetDebugSourceFile(node.Document.FileName); // Update the location cookie int locationCookie = _locationCookie++; if (!_transformToGenerator) { MSAst.Expression tracebackCall = null; if (locationCookie == 0) { tracebackCall = Ast.Empty(); } else { tracebackCall = Ast.Call( typeof(RuntimeOps).GetMethod("OnTraceEvent"), _thread, AstUtils.Constant(locationCookie), Ast.Convert(Ast.Constant(null), typeof(Exception)) ); } transformedExpression = Ast.Block( Ast.Assign( _debugMarker, AstUtils.Constant(locationCookie) ), Ast.IfThen( Ast.GreaterThan( Ast.Property(_sourceFilesToVariablesMap[sourceFile], "Mode"), Ast.Constant((int)DebugMode.ExceptionsOnly) ), Ast.IfThen( Ast.OrElse( Ast.Equal( Ast.Property(_sourceFilesToVariablesMap[sourceFile], "Mode"), Ast.Constant((int)DebugMode.FullyEnabled) ), Ast.ArrayIndex( _traceLocations, AstUtils.Constant(locationCookie) ) ), Ast.Block( (_pushFrame != null) ? _pushFrame : Ast.Empty(), tracebackCall ) ) ) ); } else { Debug.Assert(_generatorLabelTarget != null); transformedExpression = Ast.Block( AstUtils.YieldReturn( _generatorLabelTarget, _debugYieldValue, locationCookie ) ); // Update the variable scope map if (_currentLocals.Count > 0) { IList <VariableInfo> scopedVaribles; MSAst.BlockExpression curentBlock = _currentLocals.Peek(); if (!_variableScopeMapCache.TryGetValue(curentBlock, out scopedVaribles)) { scopedVaribles = new List <VariableInfo>(); MSAst.BlockExpression[] blocks = _currentLocals.ToArray(); for (int i = blocks.Length - 1; i >= 0; i--) { foreach (var variable in blocks[i].Variables) { scopedVaribles.Add(_localsToVarInfos[variable]); } } _variableScopeMapCache.Add(curentBlock, scopedVaribles); } _variableScopeMap.Add(locationCookie, scopedVaribles); } DebugSourceSpan span = new DebugSourceSpan( sourceFile, node.StartLine, node.StartColumn, node.EndLine, node.EndColumn); // Update the location-span map _markerLocationMap.Add(locationCookie, span); } return(transformedExpression); } else { return(Ast.Empty()); } }
public override Expression /*!*/ Convert(DynamicMetaObject /*!*/ metaObject, Type restrictedType, ParameterInfo info, Type /*!*/ toType) { Expression expr = metaObject.Expression; Type fromType = restrictedType ?? expr.Type; // block: if (fromType == typeof(MissingBlockParam)) { Debug.Assert(toType == typeof(BlockParam) || toType == typeof(MissingBlockParam)); return(AstUtils.Constant(null)); } if (fromType == typeof(BlockParam) && toType == typeof(MissingBlockParam)) { return(AstUtils.Constant(null)); } // protocol conversions: if (info != null && info.IsDefined(typeof(DefaultProtocolAttribute), false)) { var action = RubyConversionAction.TryGetDefaultConversionAction(Context, toType); if (action != null) { // TODO: inline implicit conversions: return(AstUtils.LightDynamic(action, toType, expr)); } // Do not throw an exception here to allow generic type parameters to be used with D.P. attribute. // The semantics should be to use DP if available for the current instantiation and ignore it otherwise. } if (restrictedType != null) { if (restrictedType == typeof(DynamicNull)) { if (!toType.IsValueType || toType.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable <>)) { return(AstUtils.Constant(null, toType)); } else if (toType == typeof(bool)) { return(AstUtils.Constant(false)); } } if (toType.IsAssignableFrom(restrictedType)) { // expr can be converted to restrictedType, which can be converted toType => we can convert expr to toType: return(AstUtils.Convert(expr, CompilerHelpers.GetVisibleType(toType))); } // if there is a simple conversion from restricted type, convert the expression to the restricted type and use that conversion: Type visibleRestrictedType = CompilerHelpers.GetVisibleType(restrictedType); if (Converter.CanConvertFrom(metaObject, visibleRestrictedType, toType, false, NarrowingLevel.None, false, false)) { expr = AstUtils.Convert(expr, visibleRestrictedType); } } return(Converter.ConvertExpression(expr, toType, _args.RubyContext, _args.MetaContext.Expression, _implicitProtocolConversions)); }
public override MSAst.Expression Reduce() { if (_names == _star) { // from a[.b] import * return(GlobalParent.AddDebugInfo( Ast.Call( AstMethods.ImportStar, Parent.LocalContext, AstUtils.Constant(_root.MakeString()), AstUtils.Constant(GetLevel()) ), Span )); } else { // from a[.b] import x [as xx], [ y [ as yy] ] [ , ... ] ReadOnlyCollectionBuilder <MSAst.Expression> statements = new ReadOnlyCollectionBuilder <MSAst.Expression>(); MSAst.ParameterExpression module = Ast.Variable(typeof(object), "module"); // Create initializer of the array of names being passed to ImportWithNames MSAst.Expression[] names = new MSAst.Expression[_names.Length]; for (int i = 0; i < names.Length; i++) { names[i] = AstUtils.Constant(_names[i]); } // module = PythonOps.ImportWithNames(<context>, _root, make_array(_names)) statements.Add( GlobalParent.AddDebugInfoAndVoid( AssignValue( module, LightExceptions.CheckAndThrow( Expression.Call( AstMethods.ImportWithNames, Parent.LocalContext, AstUtils.Constant(_root.MakeString()), Ast.NewArrayInit(typeof(string), names), AstUtils.Constant(GetLevel()) ) ) ), _root.Span ) ); // now load all the names being imported and assign the variables for (int i = 0; i < names.Length; i++) { statements.Add( GlobalParent.AddDebugInfoAndVoid( AssignValue( Parent.GetVariableExpression(_variables[i]), Ast.Call( AstMethods.ImportFrom, Parent.LocalContext, module, names[i] ) ), Span ) ); } statements.Add(AstUtils.Empty()); return(GlobalParent.AddDebugInfo(Ast.Block(new[] { module }, statements.ToArray()), Span)); } }
protected override Expression ToExpression(OverloadResolver /*!*/ resolver, RestrictedArguments /*!*/ args, bool[] /*!*/ hasBeenUsed) { return(AstUtils.Constant(Activator.CreateInstance(ParameterInfo.ParameterType, ((RubyOverloadResolver)resolver).Context))); }
protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback) { RubyModule currentDeclaringModule; string currentMethodName; var scope = args.Scope; var scopeExpr = AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)); RubyScope targetScope; int scopeNesting = scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out targetScope); if (scopeNesting == -1) { metaBuilder.AddCondition(Methods.IsSuperOutOfMethodScope.OpCall(scopeExpr)); metaBuilder.SetError(Methods.MakeTopLevelSuperException.OpCall()); return(true); } object target = targetScope.SelfObject; var targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self"); var assignTarget = Ast.Assign( targetExpression, Methods.GetSuperCallTarget.OpCall(scopeExpr, AstUtils.Constant(scopeNesting)) ); if (_signature.HasImplicitArguments && targetScope.Kind == ScopeKind.BlockMethod) { metaBuilder.AddCondition(Ast.NotEqual(assignTarget, Ast.Field(null, Fields.NeedsUpdate))); metaBuilder.SetError(Methods.MakeImplicitSuperInBlockMethodError.OpCall()); return(true); } // If we need to update we return RubyOps.NeedsUpdate instance that will cause the subsequent conditions to fail: metaBuilder.AddInitialization(assignTarget); args.SetTarget(targetExpression, target); Debug.Assert(currentDeclaringModule != null); RubyMemberInfo method; RubyMemberInfo methodMissing = null; // MRI bug: Uses currentDeclaringModule for method look-up so we can end up with an instance method of class C // called on a target of another class. See http://redmine.ruby-lang.org/issues/show/2419. // we need to lock the hierarchy of the target class: var targetClass = scope.RubyContext.GetImmediateClassOf(target); using (targetClass.Context.ClassHierarchyLocker()) { // initialize all methods in ancestors: targetClass.InitializeMethodsNoLock(); // target is stored in a local, therefore it cannot be part of the restrictions: metaBuilder.TreatRestrictionsAsConditions = true; metaBuilder.AddTargetTypeTest(target, targetClass, targetExpression, args.MetaContext, new[] { Symbols.MethodMissing } // currentMethodName is resolved for super, which cannot be an instance singleton ); metaBuilder.TreatRestrictionsAsConditions = false; method = targetClass.ResolveSuperMethodNoLock(currentMethodName, currentDeclaringModule).InvalidateSitesOnOverride().Info; if (_signature.ResolveOnly) { metaBuilder.Result = AstUtils.Constant(method != null); return(true); } if (method == null) { // MRI: method_missing is called for the targetClass, not for the super: methodMissing = targetClass.ResolveMethodMissingForSite(currentMethodName, RubyMethodVisibility.None); } } if (method != null) { method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule); } else { return(RubyCallAction.BuildMethodMissingCall(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, defaultFallback)); } return(true); }
private Expression MakeIncorrectArgumentCountError(BindingTarget target) { IList <int> available = target.ExpectedArgumentCount; int expected; if (available.Count > 0) { int minGreater = Int32.MaxValue; int maxLesser = Int32.MinValue; int max = Int32.MinValue; foreach (int arity in available) { if (arity > target.ActualArgumentCount) { minGreater = Math.Min(minGreater, arity); } else { maxLesser = Math.Max(maxLesser, arity); } max = Math.Max(max, arity); } expected = (target.ActualArgumentCount < maxLesser ? maxLesser : Math.Min(minGreater, max)); } else { // no overload is callable: expected = 0; } return(Methods.MakeWrongNumberOfArgumentsError.OpCall(AstUtils.Constant(target.ActualArgumentCount), AstUtils.Constant(expected))); }
// see Ruby Language.doc/Runtime/Control Flow Implementation/Break internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { MSA.Expression transformedReturnValue = TransformReturnValue(gen); // eval: if (gen.CompilerOptions.IsEval) { return(Methods.EvalBreak.OpCall(gen.CurrentScopeVariable, AstUtils.Box(transformedReturnValue))); } // loop: if (gen.CurrentLoop != null) { return(Ast.Block( Ast.Assign( gen.CurrentLoop.ResultVariable, Ast.Convert(transformedReturnValue, gen.CurrentLoop.ResultVariable.Type) ), Ast.Break(gen.CurrentLoop.BreakLabel), AstUtils.Empty() )); } // block: if (gen.CurrentBlock != null) { return(gen.Return(Methods.BlockBreak.OpCall(gen.CurrentBlock.BfcVariable, AstUtils.Box(transformedReturnValue)))); } // primary frame: return(Methods.MethodBreak.OpCall(AstUtils.Box(transformedReturnValue))); }
public override DynamicMetaObject FallbackSetMember(DynamicMetaObject self, DynamicMetaObject value, DynamicMetaObject errorSuggestion) { if (self.NeedsDeferral()) { return(Defer(self, value)); } #if !SILVERLIGHT DynamicMetaObject com; if (Microsoft.Scripting.ComInterop.ComBinder.TryBindSetMember(this, self, BindingHelpers.GetComArgument(value), out com)) { return(com); } #endif return(Context.Binder.SetMember(Name, self, value, errorSuggestion, new PythonOverloadResolverFactory(_context.Binder, AstUtils.Constant(Context.SharedContext)))); }
/// <summary> /// Transform multiple python except handlers for a try block into a single catch body. /// </summary> /// <param name="exception">The variable for the exception in the catch block.</param> /// <returns>Null if there are no except handlers. Else the statement to go inside the catch handler</returns> private MSAst.Expression TransformHandlers(MSAst.ParameterExpression exception) { Assert.NotEmpty(_handlers); MSAst.ParameterExpression extracted = Ast.Variable(typeof(object), "$extracted"); var tests = new List <Microsoft.Scripting.Ast.IfStatementTest>(_handlers.Length); MSAst.ParameterExpression converted = null; MSAst.Expression catchAll = null; for (int index = 0; index < _handlers.Length; index++) { TryStatementHandler tsh = _handlers[index]; if (tsh.Test != null) { Microsoft.Scripting.Ast.IfStatementTest ist; // translating: // except Test ... // // generate following AST for the Test (common part): // CheckException(exception, Test) MSAst.Expression test = Ast.Call( AstMethods.CheckException, Parent.LocalContext, extracted, AstUtils.Convert(tsh.Test, typeof(object)) ); if (tsh.Target != null) { // translating: // except Test as Target: // <body> // into: // if ((converted = CheckException(exception, Test)) != null) { // try { // Target = converted; // traceback-header // <body> // } // finally { // del Target // } // } if (converted == null) { converted = Ast.Variable(typeof(object), "$converted"); } ist = AstUtils.IfCondition( Ast.NotEqual( Ast.Assign(converted, test), AstUtils.Constant(null) ), Ast.TryFinally( Ast.Block( tsh.Target.TransformSet(SourceSpan.None, converted, PythonOperationKind.None), GlobalParent.AddDebugInfo( GetTracebackHeader( this, exception, tsh.Body ), new SourceSpan(GlobalParent.IndexToLocation(tsh.StartIndex), GlobalParent.IndexToLocation(tsh.HeaderIndex)) ), AstUtils.Empty() ), Ast.Block( tsh.Target.TransformSet(SourceSpan.None, AstUtils.Constant(null), PythonOperationKind.None), tsh.Target.TransformDelete() ) ) ); } else { // translating: // except Test: // <body> // into: // if (CheckException(exception, Test) != null) { // traceback-header // <body> // } ist = AstUtils.IfCondition( Ast.NotEqual( test, AstUtils.Constant(null) ), GlobalParent.AddDebugInfo( GetTracebackHeader( this, exception, tsh.Body ), new SourceSpan(GlobalParent.IndexToLocation(tsh.StartIndex), GlobalParent.IndexToLocation(tsh.HeaderIndex)) ) ); } // Add the test to the if statement test cascade tests.Add(ist); } else { Debug.Assert(index == _handlers.Length - 1); Debug.Assert(catchAll == null); // translating: // except: // <body> // into: // { // traceback-header // <body> // } catchAll = GlobalParent.AddDebugInfo( GetTracebackHeader(this, exception, tsh.Body), new SourceSpan(GlobalParent.IndexToLocation(tsh.StartIndex), GlobalParent.IndexToLocation(tsh.HeaderIndex)) ); } } MSAst.Expression body = null; if (tests.Count > 0) { // rethrow the exception if we have no catch-all block if (catchAll == null) { catchAll = Ast.Block( Parent.GetSaveLineNumberExpression(exception, true), Ast.Throw( Ast.Call( typeof(ExceptionHelpers).GetMethod("UpdateForRethrow"), exception ) ) ); } body = AstUtils.If( tests.ToArray(), catchAll ); } else { Debug.Assert(catchAll != null); body = catchAll; } IList <MSAst.ParameterExpression> args; if (converted != null) { args = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression> { converted, extracted }; } else { args = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression> { extracted }; } // Codegen becomes: // extracted = PythonOps.SetCurrentException(exception) // < dynamic exception analysis > return(Ast.Block( args, Ast.Assign( extracted, Ast.Call( AstMethods.SetCurrentException, Parent.LocalContext, exception ) ), body, Ast.Assign(extracted, Ast.Constant(null)), AstUtils.Empty() )); }
internal override MSA.Expression TransformDefinedCondition(AstGenerator /*!*/ gen) { return(Ast.NotEqual(TransformRead(gen), AstUtils.Constant(null))); }
internal static MSAst.Expression TransformFor(ScopeStatement parent, MSAst.ParameterExpression enumerator, Expression list, Expression left, MSAst.Expression body, Statement else_, SourceSpan span, SourceLocation header, MSAst.LabelTarget breakLabel, MSAst.LabelTarget continueLabel, bool isStatement) { // enumerator, isDisposable = Dynamic(GetEnumeratorBinder, list) MSAst.Expression init = Ast.Assign( enumerator, new PythonDynamicExpression1 <KeyValuePair <IEnumerator, IDisposable> >( Binders.UnaryOperationBinder( parent.GlobalParent.PyContext, PythonOperationKind.GetEnumeratorForIteration ), parent.GlobalParent.CompilationMode, AstUtils.Convert(list, typeof(object)) ) ); // while enumerator.MoveNext(): // left = enumerator.Current // body // else: // else MSAst.Expression ls = AstUtils.Loop( parent.GlobalParent.AddDebugInfo( Ast.Call( Ast.Property( enumerator, typeof(KeyValuePair <IEnumerator, IDisposable>).GetProperty("Key") ), typeof(IEnumerator).GetMethod("MoveNext") ), left.Span ), null, Ast.Block( left.TransformSet( SourceSpan.None, Ast.Call( Ast.Property( enumerator, typeof(KeyValuePair <IEnumerator, IDisposable>).GetProperty("Key") ), typeof(IEnumerator).GetProperty("Current").GetGetMethod() ), PythonOperationKind.None ), body, isStatement ? UpdateLineNumber(parent.GlobalParent.IndexToLocation(list.StartIndex).Line) : AstUtils.Empty(), AstUtils.Empty() ), else_, breakLabel, continueLabel ); return(Ast.Block( init, Ast.TryFinally( ls, Ast.Call(AstMethods.ForLoopDispose, enumerator) ) )); }
private DynamicMetaObject MakeGetMemberTarget(GetMemberInfo getMemInfo, DynamicMetaObject target) { Type type = target.GetLimitType(); BindingRestrictions restrictions = target.Restrictions; DynamicMetaObject self = target; target = target.Restrict(target.GetLimitType()); // Specially recognized types: TypeTracker, NamespaceTracker, and StrongBox. // TODO: TypeTracker and NamespaceTracker should technically be IDO's. MemberGroup members = MemberGroup.EmptyGroup; if (typeof(TypeTracker).IsAssignableFrom(type)) { restrictions = restrictions.Merge( BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value) ); TypeGroup tg = target.Value as TypeGroup; Type nonGen; if (tg == null || tg.TryGetNonGenericType(out nonGen)) { members = GetMember(MemberRequestKind.Get, ((TypeTracker)target.Value).Type, getMemInfo.Name); if (members.Count > 0) { // we have a member that's on the type associated w/ the tracker, return that... type = ((TypeTracker)target.Value).Type; self = null; } } } if (members.Count == 0) { // Get the members members = GetMember(MemberRequestKind.Get, type, getMemInfo.Name); } if (members.Count == 0) { if (typeof(TypeTracker).IsAssignableFrom(type)) { // ensure we don't have a non-generic type, and if we do report an error now. This matches // the rule version of the default binder but should probably be removed long term Type x = ((TypeTracker)target.Value).Type; } else if (type.IsInterface) { // all interfaces have object members type = typeof(object); members = GetMember(MemberRequestKind.Get, type, getMemInfo.Name); } } DynamicMetaObject propSelf = self == null ? null : self; // if lookup failed try the strong-box type if available. if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(type) && propSelf != null) { // properties/fields need the direct value, methods hold onto the strong box. propSelf = new DynamicMetaObject( Ast.Field(AstUtils.Convert(propSelf.Expression, type), type.GetField("Value")), propSelf.Restrictions, ((IStrongBox)propSelf.Value).Value ); type = type.GetGenericArguments()[0]; members = GetMember( MemberRequestKind.Get, type, getMemInfo.Name ); } MakeBodyHelper(getMemInfo, self, propSelf, type, members); getMemInfo.Body.Restrictions = restrictions; return(getMemInfo.Body.GetMetaObject(target)); }
internal DynamicMetaObject /*!*/ InvokeFallback(DynamicMetaObject /*!*/ target, DynamicMetaObject /*!*/[] /*!*/ args, CallSignature sig, DynamicMetaObject errorSuggestion) { return (PythonProtocol.Call(this, target, args) ?? Context.Binder.Create(sig, target, args, AstUtils.Constant(_context.SharedContext)) ?? Context.Binder.Call(sig, errorSuggestion, new PythonOverloadResolverFactory(Context.Binder, AstUtils.Constant(_context.SharedContext)), target, args)); }
// Ruby binders: internal CallArguments(RubyContext context, DynamicMetaObject /*!*/ scopeOrContextOrTargetOrArgArray, DynamicMetaObject /*!*/[] /*!*/ args, RubyCallSignature signature) { Assert.NotNull(scopeOrContextOrTargetOrArgArray); Assert.NotNullItems(args); ArgumentArray argArray = scopeOrContextOrTargetOrArgArray.Value as ArgumentArray; if (argArray != null) { Debug.Assert(args.Length == 0 && argArray.Count >= 1); // build meta-objects for arguments wrapped in the array: args = new DynamicMetaObject[argArray.Count - 1]; for (int i = 0; i < args.Length; i++) { args[i] = argArray.GetMetaObject(scopeOrContextOrTargetOrArgArray.Expression, 1 + i); } scopeOrContextOrTargetOrArgArray = argArray.GetMetaObject(scopeOrContextOrTargetOrArgArray.Expression, 0); } Debug.Assert(signature.HasScope == scopeOrContextOrTargetOrArgArray.Value is RubyScope); Debug.Assert((context == null && !signature.HasScope) == scopeOrContextOrTargetOrArgArray.Value is RubyContext); if (context != null) { // bound site: _context = new DynamicMetaObject(AstUtils.Constant(context), BindingRestrictions.Empty, context); if (signature.HasScope) { _scope = scopeOrContextOrTargetOrArgArray; _hasScopeOrContextArg = true; } else { _target = scopeOrContextOrTargetOrArgArray; } } else if (signature.HasScope) { // unbound site with scope: _context = new DynamicMetaObject( Methods.GetContextFromScope.OpCall(scopeOrContextOrTargetOrArgArray.Expression), BindingRestrictions.Empty, ((RubyScope)scopeOrContextOrTargetOrArgArray.Value).RubyContext ); _scope = scopeOrContextOrTargetOrArgArray; _hasScopeOrContextArg = true; _target = null; } else { // unbound site with context: _context = scopeOrContextOrTargetOrArgArray; _hasScopeOrContextArg = true; _target = null; } Debug.Assert(_target != null || args.Length > 0); _args = args; _copyArgsOnWrite = true; _signature = signature; Debug.Assert(!signature.HasSplattedArgument || GetSplattedArgument() != null); }