// Just splat the args and dispatch through a nested site public override Expression Bind(object[] args, ReadOnlyCollection<ParameterExpression> parameters, LabelTarget returnLabel) { Debug.Assert(args.Length == 2); int count = ((object[])args[1]).Length; ParameterExpression array = parameters[1]; var nestedArgs = new ReadOnlyCollectionBuilder<Expression>(count + 1); var delegateArgs = new Type[count + 3]; // args + target + returnType + CallSite nestedArgs.Add(parameters[0]); delegateArgs[0] = typeof(CallSite); delegateArgs[1] = typeof(object); for (int i = 0; i < count; i++) { nestedArgs.Add(Expression.ArrayAccess(array, Expression.Constant(i))); delegateArgs[i + 2] = typeof(object).MakeByRefType(); } delegateArgs[delegateArgs.Length - 1] = typeof(object); return Expression.IfThen( Expression.Equal(Expression.ArrayLength(array), Expression.Constant(count)), Expression.Return( returnLabel, Expression.MakeDynamic( Expression.GetDelegateType(delegateArgs), new ComInvokeAction(new CallInfo(count)), nestedArgs ) ) ); }
public override Expression Bind(object[] args, System.Collections.ObjectModel.ReadOnlyCollection<ParameterExpression> parameters, LabelTarget returnLabel) { //For this sample, we just always return a constant. return Expression.Return( returnLabel, Expression.Constant((int)args[0] + (int)args[1]) ); }
private LabelInfo EnsureLabel(LabelTarget node) { LabelInfo result; if (!_labelInfo.TryGetValue(node, out result)) { _labelInfo.Add(node, result = new LabelInfo(_ilg, node, false)); } return result; }
private LabelInfo DefineLabel(LabelTarget node) { if (node == null) { return new LabelInfo(_ilg, null, false); } LabelInfo result = EnsureLabel(node); result.Define(_ilg, _labelBlock); return result; }
internal LabelInfo(ILGen il, LabelTarget node, bool canReturn) { _ilg = il; Node = node; Label = il.DefineLabel(); _canReturn = canReturn; if (node != null && node.Type != typeof(void)) { Value = il.DeclareLocal(node.Type); } // Until we have more information, default to a leave instruction, which always works _opCode = OpCodes.Leave; }
public LambdaExpression Generate(Subroutine sub, bool is_main) { IsMain = is_main; SubLabel = Expression.Label(typeof(IP5Any)); for (int i = 0; i < sub.BasicBlocks.Count; ++i) if (sub.BasicBlocks[i] != null) BlockLabels[sub.BasicBlocks[i]] = Expression.Label("L" + i.ToString()); var scopes = GenerateScopes(sub); var vars = new List<ParameterExpression>(); AddVars(vars, Variables); AddVars(vars, Lexicals); AddVars(vars, Temporaries); AddVars(vars, LexStates); AddVars(vars, RxStates); var block = Expression.Block(typeof(IP5Any), vars, scopes); var args = new ParameterExpression[] { Runtime, Context, Pad, Arguments }; return Expression.Lambda<P5Code.Sub>(Expression.Label(SubLabel, block), args); }
/// <summary> /// Creates a <see cref="GotoExpression"/> representing a break statement with the specified type. /// </summary> /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param> /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param> /// <returns> /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Break, /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, /// and the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>. /// </returns> public static GotoExpression Break(LabelTarget target, Type type) { return MakeGoto(GotoExpressionKind.Break, target, null, type); }
private static void AddFuncHandlerExpressions(PredicateAndHandler handler, List <Expression> body, Expression argumentExpression, LabelTarget returnTarget) { //Add this code to the body: // if(func(castedValue)) // { // return true; // } body.Add( Expression.IfThen( Expression.Invoke(handler.ActionOrFuncExpression, argumentExpression), Expression.Return(returnTarget, Expression.Constant(true)) )); }
internal LabelInfo(ILGenerator il, LabelTarget node, bool canReturn) { _ilg = il; _node = node; _canReturn = canReturn; }
/// <summary> /// Creates a new expression that is like this one, but using the /// supplied children. If all of the children are the same, it will /// return this expression. /// </summary> /// <param name="target">The <see cref="Target" /> property of the result.</param> /// <param name="defaultValue">The <see cref="DefaultValue" /> property of the result.</param> /// <returns>This expression if no children changed, or an expression with the updated children.</returns> public LabelExpression Update(LabelTarget target, Expression defaultValue) { if (target == Target && defaultValue == DefaultValue) { return this; } return Expression.Label(target, defaultValue); }
/// <summary> /// Creates a new expression that is like this one, but using the /// supplied children. If all of the children are the same, it will /// return this expression. /// </summary> /// <param name="breakLabel">The <see cref="BreakLabel" /> property of the result.</param> /// <param name="continueLabel">The <see cref="ContinueLabel" /> property of the result.</param> /// <param name="body">The <see cref="Body" /> property of the result.</param> /// <returns>This expression if no children changed, or an expression with the updated children.</returns> public LoopExpression Update(LabelTarget breakLabel, LabelTarget continueLabel, Expression body) { if (breakLabel == BreakLabel && continueLabel == ContinueLabel && body == Body) { return this; } return Expression.Loop(body, breakLabel, continueLabel); }
/// <summary> /// Creates a <see cref="LoopExpression"/> with the given body. /// </summary> /// <param name="body">The body of the loop.</param> /// <param name="break">The break target used by the loop body.</param> /// <param name="continue">The continue target used by the loop body.</param> /// <returns>The created <see cref="LoopExpression"/>.</returns> public static LoopExpression Loop(Expression body, LabelTarget @break, LabelTarget @continue) { RequiresCanRead(body, "body"); ContractUtils.Requires(@continue == null || @continue.Type == typeof(void), "continue", Strings.LabelTypeMustBeVoid); return new LoopExpression(body, @break, @continue); }
/// <summary> /// Creates a <see cref="GotoExpression"/> representing a jump of the specified <see cref="GotoExpressionKind"/>. /// The value passed to the label upon jumping can also be specified. /// </summary> /// <param name="kind">The <see cref="GotoExpressionKind"/> of the <see cref="GotoExpression"/>.</param> /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param> /// <param name="value">The value that will be passed to the associated label upon jumping.</param> /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param> /// <returns> /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to <paramref name="kind"/>, /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, /// the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>, /// and <paramref name="value"/> to be passed to the target label upon jumping. /// </returns> public static GotoExpression MakeGoto(GotoExpressionKind kind, LabelTarget target, Expression value, Type type) { ValidateGoto(target, ref value, "target", "value"); return new GotoExpression(kind, target, value, type); }
protected override LabelTarget VisitLabelTarget(LabelTarget node) { return(GiveUp(node)); }
private static ConditionalExpression IfNullThenReturnExpression(ParameterExpression inputParameter, LabelTarget endLabel) { //// Expression output: //// //// if (input == null) //// { //// return null; //// } return (Expression.IfThen( Expression.Equal( inputParameter, Expression.Constant(null, ObjectType)), Expression.Return(endLabel))); }
private bool TryPushLabelBlock(Expression node) { // Anything that is "statement-like" -- e.g. has no associated // stack state can be jumped into, with the exception of try-blocks // We indicate this by a "Block" // // Otherwise, we push an "Expression" to indicate that it can't be // jumped into switch (node.NodeType) { default: if (_labelBlock.Kind != LabelScopeKind.Expression) { PushLabelBlock(LabelScopeKind.Expression); return(true); } return(false); case ExpressionType.Label: // LabelExpression is a bit special, if it's directly in a // block it becomes associate with the block's scope. Same // thing if it's in a switch case body. if (_labelBlock.Kind == LabelScopeKind.Block) { LabelTarget label = ((LabelExpression)node).Target; if (_labelBlock.ContainsTarget(label)) { return(false); } if (_labelBlock.Parent !.Kind == LabelScopeKind.Switch && _labelBlock.Parent.ContainsTarget(label)) { return(false); } } PushLabelBlock(LabelScopeKind.Statement); return(true); case ExpressionType.Block: if (node is SpilledExpressionBlock) { // treat it as an expression goto default; } PushLabelBlock(LabelScopeKind.Block); // Labels defined immediately in the block are valid for // the whole block. if (_labelBlock.Parent !.Kind != LabelScopeKind.Switch) { DefineBlockLabels(node); } return(true); case ExpressionType.Switch: PushLabelBlock(LabelScopeKind.Switch); // Define labels inside of the switch cases so they are in // scope for the whole switch. This allows "goto case" and // "goto default" to be considered as local jumps. var @switch = (SwitchExpression)node; foreach (SwitchCase c in @switch.Cases) { DefineBlockLabels(c.Body); } DefineBlockLabels(@switch.DefaultBody); return(true); // Remove this when Convert(Void) goes away. case ExpressionType.Convert: if (node.Type != typeof(void)) { // treat it as an expression goto default; } PushLabelBlock(LabelScopeKind.Statement); return(true); case ExpressionType.Conditional: case ExpressionType.Loop: case ExpressionType.Goto: PushLabelBlock(LabelScopeKind.Statement); return(true); } }
internal override Expression GetExpression(List <ParameterExpression> parameters, Dictionary <string, ConstantExpression> locals, List <DataContainer> dataContainers, Type dynamicContext, LabelTarget label) { Expression exp; if (ConstructorType != null) { if (Constructor != null) { ParameterInfo[] info = Constructor.GetParameters(); List <Expression> args = new List <Expression>(); for (int i = 0; i < info.Length; ++i) { args.Add(Expression.Dynamic(Binder.Convert(CSharpBinderFlags.None, info[i].ParameterType, dynamicContext ?? typeof(object)), info[i].ParameterType, Arguments.Arguments[i].GetExpression(parameters, locals, dataContainers, dynamicContext, label))); } exp = Expression.New(Constructor, args); } else { exp = Expression.New(ConstructorType); } if (Initializers != null) { if (Initializers.Arguments.Any(token => token is AssignmentToken)) { Func <MemberInfo, Type> getType = mem => mem is FieldInfo ? (mem as FieldInfo).FieldType : (mem as PropertyInfo).PropertyType; var inits = Initializers.Arguments.Cast <AssignmentToken>().Select(token => new Tuple <MemberInfo, Expression>(token.Member, Expression.Dynamic(Binder.Convert(CSharpBinderFlags.None, getType(token.Member), dynamicContext ?? typeof(object)), getType(token.Member), token.Value.GetExpression(parameters, locals, dataContainers, dynamicContext, label)))); exp = Expression.MemberInit(exp as NewExpression, inits.Select(init => (MemberBinding)Expression.Bind(init.Item1, init.Item2))); } else { exp = Expression.ListInit(exp as NewExpression, ConvertInitializers(Initializers, parameters, locals, dataContainers, dynamicContext, null, label).Cast <ElementInit>()); } } } else { if (Initializers != null) { CallSiteBinder binder = Binder.Convert(CSharpBinderFlags.None, ArrayType, dynamicContext ?? typeof(object)); exp = Expression.NewArrayInit(ArrayType, Initializers.Arguments.Select(token => Expression.Dynamic(binder, ArrayType, token.GetExpression(parameters, locals, dataContainers, dynamicContext, label)))); } else { CallSiteBinder binder = Binder.Convert(CSharpBinderFlags.None, typeof(int), dynamicContext ?? typeof(object)); exp = Expression.NewArrayBounds(ArrayType, Arguments.Arguments.Select(token => Expression.Dynamic(binder, typeof(int), token.GetExpression(parameters, locals, dataContainers, dynamicContext, label)))); } } return(Expression.Convert(exp, typeof(object))); }
private IEnumerable <object> ConvertInitializers(ArgumentListToken arguments, List <ParameterExpression> parameters, Dictionary <string, ConstantExpression> locals, List <DataContainer> dataContainers, Type dynamicContext, Type[] expectedTypes, LabelTarget label) { foreach (TokenBase token in arguments.Arguments) { if (token is ArgumentListToken) { MethodInfo add = Constructor.DeclaringType.GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(m => m.Name == "Add" && m.GetParameters().Length == (token as ArgumentListToken).Arguments.Length); int i = 0; Expression[] exps = new Expression[add.GetParameters().Length]; foreach (ParameterInfo info in add.GetParameters()) { CallSiteBinder binder = Binder.Convert(CSharpBinderFlags.None, info.ParameterType, dynamicContext); exps[i] = Expression.Dynamic(binder, info.ParameterType, (token as ArgumentListToken).Arguments[i++].GetExpression(parameters, locals, dataContainers, dynamicContext, label)); } yield return(Expression.ElementInit(add, exps)); } else { MethodInfo add = Constructor.DeclaringType.GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(m => m.Name == "Add" && m.GetParameters().Length == 1); CallSiteBinder binder = Binder.Convert(CSharpBinderFlags.None, add.GetParameters()[0].ParameterType, dynamicContext); yield return(Expression.ElementInit(add, Expression.Dynamic(binder, add.GetParameters()[0].ParameterType, token.GetExpression(parameters, locals, dataContainers, dynamicContext, label)))); } } }
private static void IfNullThenReturnNullExpression(ParameterExpression inputParameter, LabelTarget endLabel, List <Expression> expressions) { ///// Intended code: ///// ///// if (input == null) ///// { ///// return null; ///// } var ifNullThenReturnNullExpression = Expression.IfThen( Expression.Equal( inputParameter, Expression.Constant(null, ObjectType)), Expression.Return(endLabel)); expressions.Add(ifNullThenReturnNullExpression); }
/// <summary> /// Creates a <see cref="GotoExpression"/> representing a return statement with the specified type. /// </summary> /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param> /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param> /// <returns> /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Return, /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, /// the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>, /// and a null value to be passed to the target label upon jumping. /// </returns> public static GotoExpression Return(LabelTarget target, Type type) { return MakeGoto(GotoExpressionKind.Return, target, null, type); }
/// <summary> /// Creates a <see cref="GotoExpression"/> representing a goto. /// </summary> /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param> /// <returns> /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Goto, /// the <see cref="P:GotoExpression.Target"/> property set to the specified value, /// and a null value to be passed to the target label upon jumping. /// </returns> public static GotoExpression Goto(LabelTarget target) { return MakeGoto(GotoExpressionKind.Goto, target, null, typeof(void)); }
public static WhileExpression While(Expression test, Expression body, LabelTarget breakTarget, LabelTarget continueTarget) { if (test == null) { throw new ArgumentNullException("test"); } if (body == null) { throw new ArgumentNullException("body"); } if (test.Type != typeof(bool)) { throw new ArgumentException("Test must be a boolean expression", "test"); } if (continueTarget != null && continueTarget.Type != typeof(void)) { throw new ArgumentException("Continue label target must be void", "continueTarget"); } return(new WhileExpression(test, body, breakTarget, continueTarget)); }
internal GotoExpression(GotoExpressionKind kind, LabelTarget target, Expression value, Type type) { _kind = kind; _value = value; _target = target; _type = type; }
internal WhileExpression(Expression test, Expression body, LabelTarget breakTarget, LabelTarget continueTarget) { this.test = test; this.body = body; this.break_target = breakTarget; this.continue_target = continueTarget; }
/// <summary> /// Creates a <see cref="LoopExpression"/> with the given body. /// </summary> /// <param name="body">The body of the loop.</param> /// <param name="break">The break target used by the loop body.</param> /// <param name="continue">The continue target used by the loop body.</param> /// <returns>The created <see cref="LoopExpression"/>.</returns> public static LoopExpression Loop(Expression body, LabelTarget @break, LabelTarget @continue) { RequiresCanRead(body, "body"); if (@continue != null && @continue.Type != typeof(void)) throw Error.LabelTypeMustBeVoid(); return new LoopExpression(body, @break, @continue); }
public WhileExpression Update(Expression test, Expression body, LabelTarget breakTarget, LabelTarget continueTarget) { if (this.test == test && this.body == body && this.break_target == breakTarget && this.continue_target == continueTarget) { return(this); } return(CustomExpression.While(test, body, breakTarget, continueTarget)); }
/// <summary> /// Creates a <see cref="LabelExpression"/> representing a label with the given default value. /// </summary> /// <param name="target">The <see cref="LabelTarget"/> which this <see cref="LabelExpression"/> will be associated with.</param> /// <param name="defaultValue">The value of this <see cref="LabelExpression"/> when the label is reached through normal control flow.</param> /// <returns>A <see cref="LabelExpression"/> with the given default value.</returns> public static LabelExpression Label(LabelTarget target, Expression defaultValue) { ValidateGoto(target, ref defaultValue, "label", "defaultValue"); return new LabelExpression(target, defaultValue); }
bool IEvaluatableExpressionFilter.IsEvaluatableLabelTarget(LabelTarget node) => true;
internal bool TryGetLabelInfo(LabelTarget target, out LabelInfo info) { if (Labels == null) { info = null; return false; } return Labels.TryGetValue(target, out info); }
/// <summary> /// Performs the runtime binding of the dynamic operation on a set of arguments. /// </summary> /// <param name="args">An array of arguments to the dynamic operation.</param> /// <param name="parameters">The array of <see cref="ParameterExpression"/> instances that represent the parameters of the call site in the binding process.</param> /// <param name="returnLabel">A LabelTarget used to return the result of the dynamic binding.</param> /// <returns> /// An Expression that performs tests on the dynamic operation arguments, and /// performs the dynamic operation if hte tests are valid. If the tests fail on /// subsequent occurrences of the dynamic operation, Bind will be called again /// to produce a new <see cref="Expression"/> for the new argument types. /// </returns> public abstract Expression Bind(object[] args, ReadOnlyCollection <ParameterExpression> parameters, LabelTarget returnLabel);
private LabelInfo ReferenceLabel(LabelTarget node) { LabelInfo result = EnsureLabel(node); result.Reference(_labelBlock); return result; }
private static Action <object, TextWriter> CreateDumper(Type type) { MethodInfo writeLine1Obj = typeof(TextWriter).GetMethod("WriteLine", new[] { typeof(object) }); MethodInfo writeLine1String2Obj = typeof(TextWriter).GetMethod("WriteLine", new[] { typeof(string), typeof(object), typeof(object) }); ParameterExpression objParam = Expression.Parameter(typeof(object), "o"); ParameterExpression outputParam = Expression.Parameter(typeof(TextWriter), "output"); ParameterExpression objVariable = Expression.Variable(type, "o2"); LabelTarget returnTarget = Expression.Label(); List <Expression> bodyExpressions = new List <Expression>(); bodyExpressions.Add( // o2 = (<type>)o Expression.Assign(objVariable, Expression.Convert(objParam, type))); bodyExpressions.Add( // output.WriteLine(o) Expression.Call(outputParam, writeLine1Obj, objParam)); var properties = from prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public) where prop.CanRead && !prop.GetIndexParameters().Any() // exclude indexed properties to keep things simple select prop; foreach (var prop in properties) { bool isNullable = !prop.PropertyType.IsValueType || prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable <>); // (object)o2.<property> (cast to object to be passed to WriteLine) Expression propValue = Expression.Convert( Expression.Property(objVariable, prop), typeof(object)); if (isNullable) { // (<propertyValue> ?? "null") propValue = Expression.Coalesce( propValue, Expression.Constant("null", typeof(object))); } bodyExpressions.Add( // output.WriteLine("\t{0}: {1}", "<propertyName>", <propertyValue>) Expression.Call( outputParam, writeLine1String2Obj, Expression.Constant("\t{0}: {1}", typeof(string)), Expression.Constant(prop.Name, typeof(string)), propValue)); } bodyExpressions.Add(Expression.Label(returnTarget)); Expression <Action <object, TextWriter> > dumperExpr = Expression.Lambda <Action <object, TextWriter> >( Expression.Block(new[] { objVariable }, bodyExpressions), objParam, outputParam); return(dumperExpr.Compile()); }
// Generates code for predicateAndHandlers and adds it to bodyExpressions private static void AddCodeForHandlers(List <PredicateAndHandler> predicateAndHandlers, List <Expression> bodyExpressions, Expression castedValueExpression, LabelTarget returnTarget, Expression inputValueExpression) { foreach (var predicateAndHandler in predicateAndHandlers) { var valueExpression = predicateAndHandler.HandlerFirstArgumentShouldBeBaseType ? inputValueExpression : castedValueExpression; switch (predicateAndHandler.HandlerKind) { case HandlerKind.Action: AddActionHandlerExpressions(predicateAndHandler, bodyExpressions, valueExpression, returnTarget); break; case HandlerKind.ActionWithPredicate: AddActionHandlerWithPredicateExpressions(predicateAndHandler, bodyExpressions, valueExpression, returnTarget); break; case HandlerKind.Func: AddFuncHandlerExpressions(predicateAndHandler, bodyExpressions, valueExpression, returnTarget); break; default: throw new ArgumentOutOfRangeException( $"This should not happen. The value {typeof(HandlerKind)}.{predicateAndHandler.HandlerKind} is a new enum value that has been added without updating the code in this method."); } } }
public void NonVoidTargetReturnHasNoValueTypeExplicit(Type type) { LabelTarget target = Expression.Label(type); AssertExtensions.Throws <ArgumentException>("target", () => Expression.Return(target, type)); }
/// <summary> /// Creates a <see cref="GotoExpression"/> representing a continue statement with the specified type. /// </summary> /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param> /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param> /// <returns> /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Continue, /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, /// the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>, /// and a null value to be passed to the target label upon jumping. /// </returns> public static GotoExpression Continue(LabelTarget target, Type type) { return MakeGoto(GotoExpressionKind.Continue, target, null, type); }
protected override LabelTarget VisitLabelTarget(LabelTarget node) { return(base.VisitLabelTarget(node)); }
/// <summary> /// Creates a <see cref="GotoExpression"/> representing a return statement. The value passed to the label upon jumping can be specified. /// </summary> /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param> /// <param name="value">The value that will be passed to the associated label upon jumping.</param> /// <returns> /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Continue, /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, /// and <paramref name="value"/> to be passed to the target label upon jumping. /// </returns> public static GotoExpression Return(LabelTarget target, Expression value) { return MakeGoto(GotoExpressionKind.Return, target, value, typeof(void)); }
public LightExceptionRewrittenCode(LabelTarget target, Expression body) { _returnLabel = target; _body = body; }
/// <summary> /// Creates a <see cref="GotoExpression"/> representing a goto with the specified type. /// The value passed to the label upon jumping can be specified. /// </summary> /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param> /// <param name="value">The value that will be passed to the associated label upon jumping.</param> /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param> /// <returns> /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Goto, /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, /// the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>, /// and <paramref name="value"/> to be passed to the target label upon jumping. /// </returns> public static GotoExpression Goto(LabelTarget target, Expression value, Type type) { return MakeGoto(GotoExpressionKind.Goto, target, value, type); }
protected override LabelTarget VisitLabelTarget(LabelTarget node) { Console.WriteLine($"call {MethodBase.GetCurrentMethod().Name} : {node}"); return(base.VisitLabelTarget(node)); }
private static void ValidateGoto(LabelTarget target, ref Expression value, string targetParameter, string valueParameter) { ContractUtils.RequiresNotNull(target, targetParameter); if (value == null) { if (target.Type != typeof(void)) throw Error.LabelMustBeVoidOrHaveExpression(); } else { ValidateGotoType(target.Type, ref value, valueParameter); } }
public static WhileExpression While(Expression test, Expression body, LabelTarget breakTarget) => While(test, body, breakTarget, null);
/// <summary> /// Performs the runtime binding of the dynamic operation on a set of arguments. /// </summary> /// <param name="args">An array of arguments to the dynamic operation.</param> /// <param name="parameters">The array of <see cref="ParameterExpression"/> instances that represent the parameters of the call site in the binding process.</param> /// <param name="returnLabel">A LabelTarget used to return the result of the dynamic binding.</param> /// <returns> /// An Expression that performs tests on the dynamic operation arguments, and /// performs the dynamic operation if hte tests are valid. If the tests fail on /// subsequent occurrences of the dynamic operation, Bind will be called again /// to produce a new <see cref="Expression"/> for the new argument types. /// </returns> public sealed override Expression Bind(object[] args, ReadOnlyCollection<ParameterExpression> parameters, LabelTarget returnLabel) { ContractUtils.RequiresNotNull(args, "args"); ContractUtils.RequiresNotNull(parameters, "parameters"); ContractUtils.RequiresNotNull(returnLabel, "returnLabel"); if (args.Length == 0) { throw Error.OutOfRange("args.Length", 1); } if (parameters.Count == 0) { throw Error.OutOfRange("parameters.Count", 1); } if (args.Length != parameters.Count) { throw new ArgumentOutOfRangeException("args"); } // Ensure that the binder's ReturnType matches CallSite's return // type. We do this so meta objects and language binders can // compose trees together without needing to insert converts. Type expectedResult; if (IsStandardBinder) { expectedResult = ReturnType; if (returnLabel.Type != typeof(void) && !TypeUtils.AreReferenceAssignable(returnLabel.Type, expectedResult)) { throw Error.BinderNotCompatibleWithCallSite(expectedResult, this, returnLabel.Type); } } else { // Even for non-standard binders, we have to at least make sure // it works with the CallSite's type to build the return. expectedResult = returnLabel.Type; } DynamicMetaObject target = DynamicMetaObject.Create(args[0], parameters[0]); DynamicMetaObject[] metaArgs = CreateArgumentMetaObjects(args, parameters); DynamicMetaObject binding = Bind(target, metaArgs); if (binding == null) { throw Error.BindingCannotBeNull(); } Expression body = binding.Expression; BindingRestrictions restrictions = binding.Restrictions; // Ensure the result matches the expected result type. if (expectedResult != typeof(void) && !TypeUtils.AreReferenceAssignable(expectedResult, body.Type)) { // // Blame the last person that handled the result: assume it's // the dynamic object (if any), otherwise blame the language. // if (target.Value is IDynamicMetaObjectProvider) { throw Error.DynamicObjectResultNotAssignable(body.Type, target.Value.GetType(), this, expectedResult); } else { throw Error.DynamicBinderResultNotAssignable(body.Type, this, expectedResult); } } // if the target is IDO, standard binders ask it to bind the rule so we may have a target-specific binding. // it makes sense to restrict on the target's type in such cases. // ideally IDO metaobjects should do this, but they often miss that type of "this" is significant. if (IsStandardBinder && args[0] as IDynamicMetaObjectProvider != null) { if (restrictions == BindingRestrictions.Empty) { throw Error.DynamicBindingNeedsRestrictions(target.Value.GetType(), this); } } restrictions = AddRemoteObjectRestrictions(restrictions, args, parameters); // Add the return if (body.NodeType != ExpressionType.Goto) { body = Expression.Return(returnLabel, body); } // Finally, add restrictions if (restrictions != BindingRestrictions.Empty) { body = Expression.IfThen(restrictions.ToExpression(), body); } return body; }
internal WhileExpression(Expression test, Expression body, LabelTarget breakTarget, LabelTarget continueTarget) { Test = test; Body = body; BreakTarget = breakTarget; ContinueTarget = continueTarget; }
/// <summary> /// Creates a <see cref="LoopExpression"/> with the given body and break target. /// </summary> /// <param name="body">The body of the loop.</param> /// <param name="break">The break target used by the loop body.</param> /// <returns>The created <see cref="LoopExpression"/>.</returns> public static LoopExpression Loop(Expression body, LabelTarget @break) { return Loop(body, @break, null); }
/// <summary> /// Visits the children of <see cref="System.Linq.Expressions.LabelTarget"/>. /// </summary> /// <param name="node">The expression to visit.</param> /// <returns>The modified expression, if it or any subexpression was modified; otherwise, /// returns the original expression.</returns> protected override LabelTarget VisitLabelTarget(LabelTarget node) { throw new NotSupportedException(string.Format(Resources.EX_PROCESS_NODE_NOT_SUPPORT, node.GetType().Name)); }
internal LoopExpression(Expression body, LabelTarget @break, LabelTarget @continue) { _body = body; _break = @break; _continue = @continue; }
// Just splat the args and dispatch through a nested site public override Expression Bind(object[] args, ReadOnlyCollection <ParameterExpression> parameters, LabelTarget returnLabel) { Debug.Assert(args.Length == 2); int count = ((object[])args[1]).Length; ParameterExpression array = parameters[1]; var nestedArgs = new ReadOnlyCollectionBuilder <Expression>(count + 1); var delegateArgs = new Type[count + 3]; // args + target + returnType + CallSite nestedArgs.Add(parameters[0]); delegateArgs[0] = typeof(CallSite); delegateArgs[1] = typeof(object); for (int i = 0; i < count; i++) { nestedArgs.Add(Expression.ArrayAccess(array, Expression.Constant(i))); delegateArgs[i + 2] = typeof(object).MakeByRefType(); } delegateArgs[delegateArgs.Length - 1] = typeof(object); return(Expression.IfThen( Expression.Equal(Expression.ArrayLength(array), Expression.Constant(count)), Expression.Return( returnLabel, Expression.MakeDynamic( Expression.GetDelegateType(delegateArgs), new ComInvokeAction(new CallInfo(count)), nestedArgs ) ) )); }
/// <summary> /// Creates a <see cref="LabelExpression"/> representing a label with no default value. /// </summary> /// <param name="target">The <see cref="LabelTarget"/> which this <see cref="LabelExpression"/> will be associated with.</param> /// <returns>A <see cref="LabelExpression"/> with no default value.</returns> public static LabelExpression Label(LabelTarget target) { return Label(target, null); }
internal LabelInfo(LabelTarget node) { _node = node; }
internal LabelExpression(LabelTarget label, Expression defaultValue) { _target = label; _defaultValue = defaultValue; }
public TemplatedForeachExpression(Expression enumerable, Expression loopVariable, Expression beforeAll, Expression before, Expression odd, Expression even, Expression between, Expression after, Expression afterAll, Expression each, Expression noData, LabelTarget breakLabel, Expression loopIndex) { if (enumerable == null) { throw new ArgumentNullException(nameof(enumerable)); } if (!typeof(IEnumerable).IsAssignableFrom(enumerable.Type)) { throw new ArgumentOutOfRangeException(nameof(enumerable)); } if (loopVariable == null) { throw new ArgumentNullException(nameof(loopVariable)); } if (loopIndex == null) { throw new ArgumentNullException(nameof(loopIndex)); } if (breakLabel == null) { throw new ArgumentNullException(nameof(breakLabel)); } Enumerable = enumerable; LoopVariable = loopVariable; LoopIndex = loopIndex; BeforeAll = beforeAll; Before = before; Odd = odd; Even = even; Between = between; After = after; AfterAll = afterAll; Each = each; NoData = noData; _break = breakLabel; }
internal bool ContainsTarget(LabelTarget target) { if (Labels == null) { return false; } return Labels.ContainsKey(target); }
public void NonVoidTargetContinueHasNoValueTypeExplicit(Type type) { LabelTarget target = Expression.Label(type); Assert.Throws <ArgumentException>("target", () => Expression.Continue(target, type)); }
internal void AddLabelInfo(LabelTarget target, LabelInfo info) { Debug.Assert(CanJumpInto); if (Labels == null) { Labels = new Dictionary<LabelTarget, LabelInfo>(); } Labels.Add(target, info); }
protected override Expression VisitTry(TryExpression node) { // Visit finally/fault block first BlockInfo block = new BlockInfo { InFinally = true }; _blocks.Push(block); Expression @finally = Visit(node.Finally); Expression fault = Visit(node.Fault); block.InFinally = false; LabelTarget finallyEnd = block.FlowLabel; if (finallyEnd != null) { if (@finally != null) { @finally = Expression.Label(finallyEnd, @finally); } if (fault != null) { fault = Expression.Label(finallyEnd, fault); } // Make a new target, which will be emitted after the try block.FlowLabel = Expression.Label(); } Expression @try = Visit(node.Body); IList <CatchBlock> handlers = Visit(node.Handlers, VisitCatchBlock); _blocks.Pop(); if (@try == node.Body && handlers == node.Handlers && @finally == node.Finally && fault == node.Fault) { return(node); } if (!block.HasFlow) { return(Expression.MakeTry(@try, @finally, fault, handlers)); } // If there is a control flow in finally, emit outer: // try { // // try block body and all catch handling // } catch (Exception all) { // saved = all; // } finally { // finally_body // if (saved != null) { // throw saved; // } // } // // If we have a fault handler we turn this into the better: // try { // // try block body and all catch handling // } catch (Exception all) { // saved = all; // fault_body // throw saved // } if (handlers.Count > 0) { @try = Expression.MakeTry(@try, null, null, handlers); } var all = Expression.Variable(typeof(Exception), "$exception"); if (@finally != null) { handlers = new[] { Expression.Catch(all.Type, Expression.Empty()) }; @finally = Expression.Block( @finally, Expression.Condition( Expression.NotEqual(all, Expression.Constant(null, all.Type)), Expression.Throw(all), Expression.Empty() ) ); } else { handlers = new[] { Expression.Catch( all.Type, Expression.Block(fault, Expression.Throw(all)) ) }; fault = null; } // Emit flow control return(Expression.Block( new ParameterExpression[] { all }, Expression.MakeTry(@try, @finally, fault, handlers), Expression.Label(block.FlowLabel), MakeFlowControlSwitch(block) )); }
public void NonVoidTargetGotoHasNoValueTypeExplicit(Type type) { LabelTarget target = Expression.Label(type); Assert.Throws <ArgumentException>(() => Expression.Goto(target, type)); }
private static void AddActionHandlerExpressions(PredicateAndHandler handler, List <Expression> body, Expression argumentExpression, LabelTarget returnTarget) { //Add the action as an argument, and get the expression for retrieving it //Adds this code to the body: // action(arg); // return true; body.Add(Expression.Invoke(handler.ActionOrFuncExpression, argumentExpression)); body.Add(Expression.Return(returnTarget, Expression.Constant(true))); }
public override Expression Compile(ParameterExpression stateParameterExpression, LabelTarget returnTarget) { return(this.AssignmentTarget.Compile(stateParameterExpression, returnTarget, this.Expression)); }
private static void AddActionHandlerWithPredicateExpressions(PredicateAndHandler handler, List <Expression> body, Expression argumentExpression, LabelTarget returnTarget) { //Add this code to the body: // if(predicate(arg)) // { // action(arg); // return true; // } body.Add( Expression.IfThen( Expression.Invoke(handler.PredicateExpression, argumentExpression), Expression.Block( Expression.Invoke(handler.ActionOrFuncExpression, argumentExpression), Expression.Return(returnTarget, Expression.Constant(true)) ))); }