private MSAst.Expression AssignComplex(MSAst.Expression right) { // Python assignment semantics: // - only evaluate RHS once. // - evaluates assignment from left to right // - does not evaluate getters. // // So // a=b[c]=d=f() // should be: // $temp = f() // a = $temp // b[c] = $temp // d = $temp List <MSAst.Expression> statements = new List <MSAst.Expression>(); // 1. Create temp variable for the right value MSAst.ParameterExpression right_temp = Expression.Variable(typeof(object), "assignment"); // 2. right_temp = right statements.Add(MakeAssignment(right_temp, right)); // Do left to right assignment foreach (Expression e in _left) { if (e == null) { continue; } // 3. e = right_temp MSAst.Expression transformed = e.TransformSet(Span, right_temp, PythonOperationKind.None); statements.Add(transformed); } // 4. Create and return the resulting suite statements.Add(AstUtils.Empty()); return(GlobalParent.AddDebugInfoAndVoid( Ast.Block(new[] { right_temp }, statements.ToArray()), Span )); }
internal void SetRule(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { RubyModule currentDeclaringModule; string currentMethodName; var scope = args.Scope; object target; scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out target); var targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self"); metaBuilder.AddCondition( Methods.IsSuperCallTarget.OpCall( AstUtils.Convert(args.ScopeExpression, typeof(RubyScope)), Ast.Constant(currentDeclaringModule), AstUtils.Constant(currentMethodName), targetExpression ) ); args.SetTarget(targetExpression, target); Debug.Assert(currentDeclaringModule != null); // target is stored in a local, therefore it cannot be part of the restrictions: metaBuilder.TreatRestrictionsAsConditions = true; metaBuilder.AddTargetTypeTest(target, targetExpression, scope.RubyContext, args.ContextExpression); metaBuilder.TreatRestrictionsAsConditions = false; RubyMemberInfo method = scope.RubyContext.ResolveSuperMethod(target, currentMethodName, currentDeclaringModule); // super calls don't go to method_missing if (method == null) { metaBuilder.SetError(Methods.MakeMissingSuperException.OpCall(Ast.Constant(currentMethodName))); } else { method.InvalidateSitesOnOverride = true; method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule); } }
private static Expression CoalesceInternal(Expression left, Expression right, MethodInfo isTrue, bool isReverse, out ParameterExpression temp) { ContractUtils.RequiresNotNull(left, "left"); ContractUtils.RequiresNotNull(right, "right"); // A bit too strict, but on a safe side. ContractUtils.Requires(left.Type == right.Type, "Expression types must match"); temp = Expression.Variable(left.Type, "tmp_left"); Expression condition; if (isTrue != null) { ContractUtils.Requires(isTrue.ReturnType == typeof(bool), "isTrue", "Predicate must return bool."); ParameterInfo[] parameters = isTrue.GetParameters(); ContractUtils.Requires(parameters.Length == 1, "isTrue", "Predicate must take one parameter."); ContractUtils.Requires(isTrue.IsStatic && isTrue.IsPublic, "isTrue", "Predicate must be public and static."); Type pt = parameters[0].ParameterType; ContractUtils.Requires(TypeUtils.CanAssign(pt, left.Type), "left", "Incorrect left expression type"); condition = Expression.Call(isTrue, Expression.Assign(temp, left)); } else { ContractUtils.Requires(TypeUtils.CanCompareToNull(left.Type), "left", "Incorrect left expression type"); condition = Expression.Equal(Expression.Assign(temp, left), AstUtils.Constant(null, left.Type)); } Expression t, f; if (isReverse) { t = temp; f = right; } else { t = right; f = temp; } return(Expression.Condition(condition, t, f)); }
/// <summary> /// Produces a rule for comparing a value to null - supports comparing object references and nullable types. /// </summary> private static DynamicMetaObject TryNullComparisonRule(DynamicMetaObject[] args) { Type otherType = args[1].GetLimitType(); BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[0].Expression, args[0].GetLimitType()).Merge(BindingRestrictions.Combine(args)); if (args[0].GetLimitType() == typeof(DynamicNull)) { if (!otherType.IsValueType) { return(new DynamicMetaObject( Expression.Equal(args[0].Expression, AstUtils.Constant(null)), restrictions )); } if (otherType.GetGenericTypeDefinition() == typeof(Nullable <>)) { return(new DynamicMetaObject( Expression.Property(args[0].Expression, otherType.GetDeclaredProperty("HasValue")), restrictions )); } } else if (otherType == typeof(DynamicNull)) { if (!args[0].GetLimitType().IsValueType) { return(new DynamicMetaObject( Expression.Equal(args[0].Expression, AstUtils.Constant(null)), restrictions )); } if (args[0].GetLimitType().GetGenericTypeDefinition() == typeof(Nullable <>)) { return(new DynamicMetaObject( Expression.Property(args[0].Expression, otherType.GetDeclaredProperty("HasValue")), restrictions )); } } return(null); }
/// <summary> /// Builds an expression for a call to the provided method using the given expressions. If the /// method is not static the first parameter is used for the instance. /// /// Parameters are converted using the binder's conversion rules. /// /// If an incorrect number of parameters is provided MakeCallExpression returns null. /// </summary> public Expression MakeCallExpression(Expression context, MethodInfo method, IList <Expression> parameters) { ParameterInfo[] infos = method.GetParameters(); Expression callInst = null; int parameter = 0, startArg = 0; Expression[] callArgs = new Expression[infos.Length]; if (!method.IsStatic) { callInst = AstUtils.Convert(parameters[0], method.DeclaringType); parameter = 1; } if (infos.Length > 0 && typeof(CodeContext).IsAssignableFrom(infos[0].ParameterType)) { startArg = 1; callArgs[0] = context; } for (int arg = startArg; arg < infos.Length; arg++) { if (parameter < parameters.Count) { callArgs[arg] = ConvertExpression( parameters[parameter++], infos[arg].ParameterType, ConversionResultKind.ExplicitCast, context ); } else { return(null); } } // check that we used all parameters if (parameter != parameters.Count) { return(null); } return(AstUtils.SimpleCallHelper(callInst, method, callArgs)); }
public override MSAst TransformCore(ScriptGenerator generator) { var target = Target; var type = (Type)null; var targetType = target as TypeExpression; MSAst transformedTarget; if (targetType != null) { type = targetType.Type; transformedTarget = MSAst.Constant(type, typeof(Type)); } else { transformedTarget = target.Transform(generator); } var method = Method; if (method != null) { return(MSAstUtil.ComplexCallHelper( (type != null) ? null : transformedTarget, method, Arguments.Select(o => o.Value.Transform(generator)).ToArray())); } if (type != null) { return(MSAst.Call( type, MethodName, TypeArguments.ResolvedTypes, _arguments.Transform(generator))); } return(MSAst.Call( transformedTarget, MethodName, TypeArguments.ResolvedTypes, _arguments.Transform(generator))); }
private void AddInitialiation(ReadOnlyCollectionBuilder <MSAst.Expression> block) { if (IsModule) { block.Add(AssignValue(GetVariableExpression(FileVariable), Ast.Constant(ModuleFileName))); block.Add(AssignValue(GetVariableExpression(NameVariable), Ast.Constant(ModuleName))); } if (_languageFeatures != ModuleOptions.None || IsModule) { block.Add( Ast.Call( AstMethods.ModuleStarted, LocalContext, AstUtils.Constant(_languageFeatures) ) ); } }
/// <summary> /// Helper to wrap explicit conversion call into try/catch incase it throws an exception. If /// it throws the default value is returned. /// </summary> private static Expression WrapForThrowingTry(ConversionResultKind kind, bool isImplicit, Expression ret, Type retType) { if (!isImplicit && kind == ConversionResultKind.ExplicitTry) { Expression convFailed = GetTryConvertReturnValue(retType); ParameterExpression tmp = Expression.Variable(convFailed.Type == typeof(object) ? typeof(object) : ret.Type, "tmp"); ret = Expression.Block( new ParameterExpression[] { tmp }, AstUtils.Try( Expression.Assign(tmp, AstUtils.Convert(ret, tmp.Type)) ).Catch( typeof(Exception), Expression.Assign(tmp, convFailed) ), tmp ); } return(ret); }
private MetaObject TryNumericComparison(OperatorInfo info, MetaObject[] args) { MethodInfo[] targets = FilterNonMethods( args[0].LimitType, GetMember(OldDoOperationAction.Make(this, info.Operator), args[0].LimitType, "Compare") ); if (targets.Length > 0) { MethodBinder mb = MethodBinder.MakeBinder(this, targets[0].Name, targets); BindingTarget target = mb.MakeBindingTarget(CallTypes.None, args); if (target.Success) { Expression call = AstUtils.Convert(target.MakeExpression(), typeof(int)); switch (info.Operator) { case Operators.GreaterThan: call = Ast.GreaterThan(call, Ast.Constant(0)); break; case Operators.LessThan: call = Ast.LessThan(call, Ast.Constant(0)); break; case Operators.GreaterThanOrEqual: call = Ast.GreaterThanOrEqual(call, Ast.Constant(0)); break; case Operators.LessThanOrEqual: call = Ast.LessThanOrEqual(call, Ast.Constant(0)); break; case Operators.Equals: call = Ast.Equal(call, Ast.Constant(0)); break; case Operators.NotEquals: call = Ast.NotEqual(call, Ast.Constant(0)); break; case Operators.Compare: break; } return(new MetaObject( call, Restrictions.Combine(target.RestrictedArguments) )); } } return(null); }
public override MSAst.Expression Reduce() { var codeObj = GetOrMakeFunctionCode(); var funcCode = GlobalParent.Constant(codeObj); FuncCodeExpr = funcCode; MSAst.Expression lambda; if (EmitDebugSymbols) { lambda = GetLambda(); } else { lambda = NullLambda; ThreadPool.QueueUserWorkItem((x) => { // class defs are almost always run, so start // compiling the code now so it might be ready // when we actually go and execute it codeObj.UpdateDelegate(PyContext, true); }); } MSAst.Expression classDef = Ast.Call( AstMethods.MakeClass, funcCode, lambda, Parent.LocalContext, AstUtils.Constant(_name), UnpackBasesHelper(_bases), Metaclass is null ? AstUtils.Constant(null, typeof(object)) : AstUtils.Convert(Metaclass, typeof(object)), AstUtils.Constant(FindSelfNames()) ); classDef = AddDecorators(classDef, Decorators); return(GlobalParent.AddDebugInfoAndVoid( AssignValue(Parent.GetVariableExpression(PythonVariable), classDef), new SourceSpan( GlobalParent.IndexToLocation(StartIndex), GlobalParent.IndexToLocation(HeaderIndex) ) ));
private static void AddArgument(List <Expression> /*!*/ actualArgs, object arg, Expression /*!*/ expr) { if (arg == null) { actualArgs.Add(Ast.Constant(null)); } else { var type = CompilerHelpers.GetVisibleType(arg); if (type.IsValueType) { actualArgs.Add(expr); } else { actualArgs.Add(AstUtils.Convert(expr, type)); } } }
public MSAst.Expression CreateExpression() { MSAst.Expression[] items = new MSAst.Expression[Count * 2]; int index = 0; foreach (var item in GetItems()) { items[index++] = Utils.Convert(Utils.Constant(item.Value), typeof(object)); items[index++] = Utils.Convert(Utils.Constant(item.Key), typeof(object)); } return(MSAst.Expression.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.MakeConstantDictStorage)), MSAst.Expression.NewArrayInit( typeof(object), items ) )); }
internal override DynamicMetaObject Call(OverloadResolverFactory resolverFactory, ActionBinder binder, params DynamicMetaObject[] arguments) { if (Method.IsPublic && Method.DeclaringType.IsVisible()) { return(binder.MakeCallExpression(resolverFactory, Method, arguments)); } //methodInfo.Invoke(obj, object[] params) if (Method.IsStatic) { return(new DynamicMetaObject( Expression.Convert( Expression.Call( AstUtils.Constant(Method), typeof(MethodInfo).GetMethod("Invoke", new Type[] { typeof(object), typeof(object[]) }), AstUtils.Constant(null), AstUtils.NewArrayHelper(typeof(object), ArrayUtils.ConvertAll(arguments, x => x.Expression)) ), Method.ReturnType ), BindingRestrictions.Empty ) ); } if (arguments.Length == 0) { throw Error.NoInstanceForCall(); } return(new DynamicMetaObject( Expression.Convert( Expression.Call( AstUtils.Constant(Method), typeof(MethodInfo).GetMethod("Invoke", new Type[] { typeof(object), typeof(object[]) }), arguments[0].Expression, AstUtils.NewArrayHelper(typeof(object), ArrayUtils.ConvertAll(ArrayUtils.RemoveFirst(arguments), x => x.Expression)) ), Method.ReturnType ), BindingRestrictions.Empty )); }
/// <summary> /// Helper to produce a rule when no conversion is required (the strong type of the expression /// input matches the type we're converting to or has an implicit conversion at the IL level) /// </summary> private static DynamicMetaObject MakeSimpleConversionTarget(Type toType, BindingRestrictions restrictions, DynamicMetaObject arg) { return(new DynamicMetaObject( AstUtils.Convert(arg.Expression, CompilerHelpers.GetVisibleType(toType)), restrictions)); /* * if (toType.IsValueType && _rule.ReturnType == typeof(object) && Expression.Type == typeof(object)) { * // boxed value type is being converted back to object. We've done * // the type check, there's no need to unbox & rebox the value. infact * // it breaks calls on instance methods so we need to avoid it. * _rule.Target = * _rule.MakeReturn( * Binder, * Expression * ); * } * */ }
private DynamicMetaObject TryNumericComparison(OperatorInfo info, OverloadResolverFactory resolverFactory, DynamicMetaObject[] args) { MethodInfo[] targets = FilterNonMethods( args[0].GetLimitType(), GetMember( MemberRequestKind.Operation, args[0].GetLimitType(), "Compare" ) ); if (targets.Length > 0) { var resolver = resolverFactory.CreateOverloadResolver(args, new CallSignature(args.Length), CallTypes.None); BindingTarget target = resolver.ResolveOverload(targets[0].Name, targets, NarrowingLevel.None, NarrowingLevel.All); if (target.Success) { Expression call = AstUtils.Convert(target.MakeExpression(), typeof(int)); switch (info.Operator) { case ExpressionType.GreaterThan: call = Expression.GreaterThan(call, AstUtils.Constant(0)); break; case ExpressionType.LessThan: call = Expression.LessThan(call, AstUtils.Constant(0)); break; case ExpressionType.GreaterThanOrEqual: call = Expression.GreaterThanOrEqual(call, AstUtils.Constant(0)); break; case ExpressionType.LessThanOrEqual: call = Expression.LessThanOrEqual(call, AstUtils.Constant(0)); break; case ExpressionType.Equal: call = Expression.Equal(call, AstUtils.Constant(0)); break; case ExpressionType.NotEqual: call = Expression.NotEqual(call, AstUtils.Constant(0)); break; } return(new DynamicMetaObject( call, target.RestrictedArguments.GetAllRestrictions() )); } } return(null); }
internal static void SetCallActionRule(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool testTarget) { Assert.NotNull(metaBuilder, args); var convertedTarget = AstUtils.Convert(args.TargetExpression, typeof(Proc)); // test for target type: if (testTarget) { metaBuilder.AddTypeRestriction(args.Target.GetType(), args.TargetExpression); } SetProcCallRule( metaBuilder, convertedTarget, // proc object Ast.Property(convertedTarget, SelfProperty), // self captured by the block closure null, args ); }
protected internal static MSAst.BlockExpression UnpackSequenceHelper <T>(IList <Expression> items, MethodInfo makeEmpty, MethodInfo append, MethodInfo extend) { var expressions = new ReadOnlyCollectionBuilder <MSAst.Expression>(items.Count + 2); var varExpr = Expression.Variable(typeof(T), "$coll"); expressions.Add(Expression.Assign(varExpr, Expression.Call(makeEmpty))); foreach (var item in items) { if (item is StarredExpression starredExpression) { expressions.Add(Expression.Call(extend, varExpr, AstUtils.Convert(starredExpression.Value, typeof(object)))); } else { expressions.Add(Expression.Call(append, varExpr, AstUtils.Convert(item, typeof(object)))); } } expressions.Add(varExpr); return(Expression.Block(typeof(T), new MSAst.ParameterExpression[] { varExpr }, expressions)); }
/// <summary> /// Helper to wrap explicit conversion call into try/catch incase it throws an exception. If /// it throws the default value is returned. /// </summary> private static MSAst WrapForThrowingTry(ConversionResultKind kind, bool isImplicit, MSAst ret, Type retType) { if (!isImplicit && kind == ConversionResultKind.ExplicitTry) { var convFailed = GetTryConvertReturnValue(retType); //var tmp = MSAst.Variable(convFailed.Type == typeof(object) ? typeof(object) : ret.Type, "tmp"); return(AstUtils.Convert(ret, convFailed.Type == typeof(object) ? typeof(object) : ret.Type)); //ret = MSAst.Block( // new[] { tmp }, // AstUtils.Try( // MSAst.Assign(tmp, AstUtils.Convert(ret, tmp.Type)) // ).Catch( // typeof(Exception), // MSAst.Assign(tmp, convFailed) // ), // tmp // ); } return(ret); }
public Expression CreateExpression() { if (_infos == null) { return(Expression.New( typeof(CallSignature).GetConstructor(new Type[] { typeof(int) }), AstUtils.Constant(ArgumentCount) )); } Expression[] args = new Expression[_infos.Length]; for (int i = 0; i < args.Length; i++) { args[i] = _infos[i].CreateExpression(); } return(Expression.New( typeof(CallSignature).GetConstructor(new Type[] { typeof(Argument[]) }), Expression.NewArrayInit(typeof(Argument), args) )); }
public override MetaObject /*!*/ BindInvoke(InvokeBinder /*!*/ action, MetaObject /*!*/[] /*!*/ args) { RubyCallSignature callSignature; if (RubyCallSignature.TryCreate(action.Arguments, out callSignature)) { return(action.FallbackInvoke(this, args)); } var metaBuilder = new MetaObjectBuilder(); var context = new MetaObject( Methods.GetContextFromBlockParam.OpCall(AstUtils.Convert(Expression, typeof(BlockParam))), Restrictions.Empty, RubyOps.GetContextFromBlockParam((BlockParam)Value) ); BlockParam.SetCallActionRule(metaBuilder, new CallArguments(context, this, args, callSignature)); return(metaBuilder.CreateMetaObject(action, args)); }
protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { object target = args.Target; var targetExpression = args.TargetExpression; if (args.Target == null) { metaBuilder.SetError(Methods.CreateTypeConversionError.OpCall(Ast.Constant("nil"), Ast.Constant(TargetTypeName))); return(true); } var str = target as MutableString; if (str != null) { metaBuilder.Result = Methods.ConvertMutableStringToSymbol.OpCall(AstUtils.Convert(targetExpression, typeof(MutableString))); return(true); } var sym = target as string; if (sym != null) { metaBuilder.Result = AstUtils.Convert(targetExpression, typeof(string)); return(true); } if (target is SymbolId) { metaBuilder.Result = Methods.ConvertSymbolIdToSymbol.OpCall(AstUtils.Convert(targetExpression, typeof(SymbolId))); return(true); } if (target is int) { metaBuilder.Result = Methods.ConvertFixnumToSymbol.OpCall(args.ContextExpression, AstUtils.Convert(targetExpression, typeof(int))); return(true); } return(false); }
public MetaObject Restrict(Type type) { if (type == LimitType) { return(this); } if (HasValue) { return(new RestrictedMetaObject( AstUtils.Convert(Expression, type), Restrictions.GetTypeRestriction(Expression, type), Value )); } return(new RestrictedMetaObject( AstUtils.Convert(Expression, type), Restrictions.GetTypeRestriction(Expression, type) )); }
public DynamicMetaObject Restrict(Type type) { if (type == LimitType) { return(this); } if (HasValue) { return(new RestrictedMetaObject( AstUtils.Convert(Expression, type), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(Expression, type), Value )); } return(new RestrictedMetaObject( AstUtils.Convert(Expression, type), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(Expression, type) )); }
// see Ruby Language.doc/Runtime/Control Flow Implementation/Yield internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { MSA.Expression bfcVariable = gen.CurrentScope.DefineHiddenVariable("#yielded-bfc", typeof(BlockParam)); MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#result", typeof(object)); MSA.Expression evalUnwinder = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(EvalUnwinder)); MSA.Expression postYield; if (gen.CompilerOptions.IsEval) { // eval: postYield = Methods.EvalYield.OpCall(gen.CurrentRfcVariable, bfcVariable, resultVariable); } else if (gen.CurrentBlock != null) { // block: postYield = Methods.BlockYield.OpCall(gen.CurrentRfcVariable, gen.CurrentBlock.BfcVariable, bfcVariable, resultVariable); } else { // method: postYield = Methods.MethodYield.OpCall(gen.CurrentRfcVariable, bfcVariable, resultVariable); } return(AstFactory.Block( gen.DebugMarker("#RB: yield begin"), Ast.Assign(bfcVariable, Methods.CreateBfcForYield.OpCall(gen.MakeMethodBlockParameterRead())), Ast.Assign(resultVariable, (Arguments ?? Arguments.Empty).TransformToYield(gen, bfcVariable, Ast.Property(AstUtils.Convert(gen.MakeMethodBlockParameterRead(), typeof(Proc)), Proc.SelfProperty) )), AstUtils.IfThen(postYield, gen.Return(resultVariable)), gen.DebugMarker("#RB: yield end"), resultVariable )); }
/// <summary> /// Adds the non-conditional terminating node. /// </summary> public void FinishCondition(Expression body) { if (_body != null) { throw new InvalidOperationException(); } for (int i = _bodies.Count - 1; i >= 0; i--) { Type t = _bodies[i].Type; if (t != body.Type) { if (t.IsSubclassOf(body.Type)) { // subclass t = body.Type; } else if (body.Type.IsSubclassOf(t)) { // keep t } else { // incompatible, both go to object t = typeof(object); } } body = Expression.Condition( _conditions[i], AstUtils.Convert(_bodies[i], t), AstUtils.Convert(body, t) ); } _body = Expression.Block( _variables, body ); }
/// <summary> /// Builds the restrictions for calling with keyword arguments. The restrictions include /// tests on the individual keys of the dictionary to ensure they have the same names. /// </summary> private static BindingRestrictions MakeParamsDictionaryTest(IList <DynamicMetaObject> args, bool testTypes) { IDictionary dict = (IDictionary)args[args.Count - 1].Value; IDictionaryEnumerator dictEnum = dict.GetEnumerator(); // verify the dictionary has the same count and arguments. string[] names = new string[dict.Count]; Type[] types = testTypes ? new Type[dict.Count] : null; int index = 0; while (dictEnum.MoveNext()) { string name = dictEnum.Entry.Key as string; if (name == null) { throw ScriptingRuntimeHelpers.SimpleTypeError( $"expected string for dictionary argument got {dictEnum.Entry.Key}"); } names[index] = name; if (types != null) { types[index] = CompilerHelpers.GetType(dictEnum.Entry.Value); } index++; } return(BindingRestrictions.GetExpressionRestriction( Ast.AndAlso( Ast.TypeIs(args[args.Count - 1].Expression, typeof(IDictionary)), Ast.Call( typeof(BinderOps).GetMethod("CheckDictionaryMembers"), Ast.Convert(args[args.Count - 1].Expression, typeof(IDictionary)), AstUtils.Constant(names), testTypes ? AstUtils.Constant(types) : AstUtils.Constant(null, typeof(Type[])) ) ) )); }
// TODO: support for IgnoreCase in underlying ScriptScope APIs public override MetaObject BindGetMember(GetMemberBinder action) { var result = Expression.Variable(typeof(object), "result"); var fallback = action.FallbackGetMember(this); return(new MetaObject( Expression.Block( new ParameterExpression[] { result }, Expression.Condition( Expression.Call( AstUtils.Convert(Expression, typeof(ScriptScope)), typeof(ScriptScope).GetMethod("TryGetVariable", new[] { typeof(string), typeof(object).MakeByRefType() }), Expression.Constant(action.Name), result ), result, Expression.Convert(fallback.Expression, typeof(object)) ) ), Restrictions.GetTypeRestriction(Expression, typeof(ScriptScope)).Merge(fallback.Restrictions) )); }
internal static MSA.Expression /*!*/ MakeCallWithBlockRetryable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ invoke, MSA.Expression blockArgVariable, MSA.Expression transformedBlock, bool isBlockDefinition) { Assert.NotNull(invoke); Debug.Assert((blockArgVariable == null) == (transformedBlock == null)); // see Ruby Language.doc/Control Flow Implementation/Method Call With a Block MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#method-result", typeof(object)); MSA.ParameterExpression evalUnwinder = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(EvalUnwinder)); MSA.LabelTarget label = Ast.Label(); return(AstFactory.Block( Ast.Assign(blockArgVariable, Ast.Convert(transformedBlock, blockArgVariable.Type)), AstFactory.Infinite(label, null, (!isBlockDefinition) ? (MSA.Expression)Ast.Empty() : (MSA.Expression)Methods.InitializeBlock.OpCall(blockArgVariable), AstUtils.Try( Ast.Assign(resultVariable, invoke) ).Catch(evalUnwinder, Ast.Assign( resultVariable, Ast.Field(evalUnwinder, EvalUnwinder.ReturnValueField) ) ), // if result != RetrySingleton then break end AstUtils.Unless(Methods.IsRetrySingleton.OpCall(AstFactory.Box(resultVariable)), Ast.Break(label)), // if blockParam == #block then retry end (gen.CurrentMethod.IsTopLevelCode) ? Ast.Empty() : AstUtils.IfThen(Ast.Equal(gen.MakeMethodBlockParameterRead(), blockArgVariable), RetryStatement.TransformRetry(gen)) ), resultVariable )); }
/// <summary> /// Provides default binding for performing a call on the specified meta objects. /// </summary> /// <param name="signature">The signature describing the call</param> /// <param name="target">The meta object to be called.</param> /// <param name="args"> /// Additional meta objects are the parameters for the call as specified by the CallSignature in the CallAction. /// </param> /// <param name="resolverFactory">Overload resolver factory.</param> /// <param name="errorSuggestion">The result should the object be uncallable.</param> /// <returns>A MetaObject representing the call or the error.</returns> public DynamicMetaObject Call(CallSignature signature, DynamicMetaObject errorSuggestion, OverloadResolverFactory resolverFactory, DynamicMetaObject target, params DynamicMetaObject[] args) { ContractUtils.RequiresNotNullItems(args, nameof(args)); ContractUtils.RequiresNotNull(resolverFactory, nameof(resolverFactory)); TargetInfo targetInfo = GetTargetInfo(target, args); if (targetInfo != null) { // we're calling a well-known MethodBase DynamicMetaObject res = MakeMetaMethodCall(signature, resolverFactory, targetInfo); if (res.Expression.Type.IsValueType) { res = new DynamicMetaObject( AstUtils.Convert(res.Expression, typeof(object)), res.Restrictions ); } return res; } // we can't call this object return errorSuggestion ?? MakeCannotCallRule(target, target.GetLimitType()); }
public DynamicMetaObject GetIsCallable(DynamicMetaObject target) { // IsCallable() is tightly tied to Call actions. So in general, we need the call-action providers to also // provide IsCallable() status. // This is just a rough fallback. We could also attempt to simulate the default CallBinder logic to see // if there are any applicable calls targets, but that would be complex (the callbinder wants the argument list, // which we don't have here), and still not correct. BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType); bool callable = false; if (typeof(Delegate).IsAssignableFrom(target.LimitType) || typeof(MethodGroup).IsAssignableFrom(target.LimitType)) { callable = true; } return(new DynamicMetaObject( AstUtils.Constant(callable), restrictions )); }