private static void EmitAssign(AssigneeKind assigneeKind, Expression node, EmittingContext context, object[] arguments, EmittingContext.LocalHolder value) { var il = context.Il; switch (assigneeKind) { case AssigneeKind.Parameter: il.Ldloc(value); var index = Array.IndexOf(context.Parameters, node); if (index >= 0) { il.Starg(index); } else { GroboIL.Local variable; if (context.VariablesToLocals.TryGetValue((ParameterExpression)node, out variable)) { il.Stloc(variable); } else { throw new InvalidOperationException("Unknown parameter " + node); } } break; case AssigneeKind.SimpleArray: il.Ldloc(value); il.Stind(node.Type); break; case AssigneeKind.InstanceField: case AssigneeKind.StaticField: il.Ldloc(value); il.Stfld((FieldInfo)((MemberExpression)node).Member); break; case AssigneeKind.InstanceProperty: case AssigneeKind.StaticProperty: il.Ldloc(value); var memberExpression = (MemberExpression)node; il.Call(((PropertyInfo)memberExpression.Member).GetSetMethod(context.SkipVisibility), memberExpression.Expression == null ? null : memberExpression.Expression.Type); break; case AssigneeKind.IndexedProperty: { var indexExpression = (IndexExpression)node; if (arguments == null) { context.EmitLoadArguments(indexExpression.Arguments.ToArray()); } else { foreach (var argument in arguments) { if (argument is Expression) { context.EmitLoadArguments((Expression)argument); } else { var local = (EmittingContext.LocalHolder)argument; il.Ldloc(local); local.Dispose(); } } } il.Ldloc(value); MethodInfo setter = indexExpression.Indexer.GetSetMethod(context.SkipVisibility); if (setter == null) { throw new MissingMethodException(indexExpression.Indexer.ReflectedType.ToString(), "set_" + indexExpression.Indexer.Name); } context.Il.Call(setter, indexExpression.Object.Type); } break; case AssigneeKind.MultiDimensionalArray: { var indexExpression = (IndexExpression)node; Type arrayType = indexExpression.Object.Type; if (!arrayType.IsArray) { throw new InvalidOperationException("An array expected"); } int rank = arrayType.GetArrayRank(); if (rank != indexExpression.Arguments.Count) { throw new InvalidOperationException("Incorrect number of indeces '" + indexExpression.Arguments.Count + "' provided to access an array with rank '" + rank + "'"); } Type indexType = indexExpression.Arguments.First().Type; if (indexType != typeof(int)) { throw new InvalidOperationException("Indexing array with an index of type '" + indexType + "' is not allowed"); } if (arguments == null) { context.EmitLoadArguments(indexExpression.Arguments.ToArray()); } else { foreach (var argument in arguments) { if (argument is Expression) { context.EmitLoadArguments((Expression)argument); } else { var local = (EmittingContext.LocalHolder)argument; il.Ldloc(local); local.Dispose(); } } } il.Ldloc(value); MethodInfo setMethod = arrayType.GetMethod("Set"); if (setMethod == null) { throw new MissingMethodException(arrayType.ToString(), "Set"); } context.Il.Call(setMethod, arrayType); } break; } }
private static object[] EmitAccess(AssigneeKind assigneeKind, Expression node, EmittingContext context) { object[] arguments = null; var il = context.Il; switch (assigneeKind) { case AssigneeKind.Parameter: var index = Array.IndexOf(context.Parameters, node); if (index >= 0) { il.Ldarg(index); } else { GroboIL.Local variable; if (context.VariablesToLocals.TryGetValue((ParameterExpression)node, out variable)) { il.Ldloc(variable); } else { throw new InvalidOperationException("Unknown parameter " + node); } } break; case AssigneeKind.InstanceField: case AssigneeKind.StaticField: il.Ldfld((FieldInfo)((MemberExpression)node).Member); break; case AssigneeKind.InstanceProperty: case AssigneeKind.StaticProperty: var memberExpression = (MemberExpression)node; il.Call(((PropertyInfo)memberExpression.Member).GetGetMethod(context.SkipVisibility), memberExpression.Expression == null ? null : memberExpression.Expression.Type); break; case AssigneeKind.SimpleArray: il.Ldind(node.Type); break; case AssigneeKind.IndexedProperty: { var indexExpression = (IndexExpression)node; var args = new List <object>(); foreach (var argument in indexExpression.Arguments) { context.EmitLoadArguments(argument); if (argument.NodeType == ExpressionType.Constant || (argument.NodeType == ExpressionType.MemberAccess && ((MemberExpression)argument).Member.MemberType == MemberTypes.Field && ((FieldInfo)((MemberExpression)argument).Member).IsStatic)) { args.Add(argument); } else { var local = context.DeclareLocal(argument.Type); args.Add(local); il.Stloc(local); il.Ldloc(local); } } arguments = args.ToArray(); MethodInfo getter = indexExpression.Indexer.GetGetMethod(context.SkipVisibility); if (getter == null) { throw new MissingMethodException(indexExpression.Indexer.ReflectedType.ToString(), "get_" + indexExpression.Indexer.Name); } context.Il.Call(getter, indexExpression.Object.Type); } break; case AssigneeKind.MultiDimensionalArray: { var indexExpression = (IndexExpression)node; Type arrayType = indexExpression.Object.Type; if (!arrayType.IsArray) { throw new InvalidOperationException("An array expected"); } int rank = arrayType.GetArrayRank(); if (rank != indexExpression.Arguments.Count) { throw new InvalidOperationException("Incorrect number of indeces '" + indexExpression.Arguments.Count + "' provided to access an array with rank '" + rank + "'"); } Type indexType = indexExpression.Arguments.First().Type; if (indexType != typeof(int)) { throw new InvalidOperationException("Indexing array with an index of type '" + indexType + "' is not allowed"); } var args = new List <object>(); foreach (var argument in indexExpression.Arguments) { context.EmitLoadArguments(argument); if (argument.NodeType == ExpressionType.Constant || (argument.NodeType == ExpressionType.MemberAccess && ((MemberExpression)argument).Member.MemberType == MemberTypes.Field && ((FieldInfo)((MemberExpression)argument).Member).IsStatic)) { args.Add(argument); } else { var local = context.DeclareLocal(argument.Type); args.Add(local); il.Stloc(local); il.Ldloc(local); } } arguments = args.ToArray(); MethodInfo getMethod = arrayType.GetMethod("Get"); if (getMethod == null) { throw new MissingMethodException(arrayType.ToString(), "Get"); } context.Il.Call(getMethod, arrayType); } break; } return(arguments); }