protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { if (node.Conversion != null) { throw new NotSupportedException("Coalesce with conversion is not supported"); } // note ich: баг решарпера // ReSharper disable HeuristicUnreachableCode var left = node.Left; var right = node.Right; GroboIL il = context.Il; GroboIL.Label valueIsNullLabel = il.DefineLabel("valueIsNull"); Type leftType; bool labelUsed = ExpressionEmittersCollection.Emit(left, context, valueIsNullLabel, out leftType); if (left.Type.IsValueType) { using (var temp = context.DeclareLocal(left.Type)) { il.Stloc(temp); il.Ldloca(temp); } } labelUsed |= context.EmitNullChecking(left.Type, valueIsNullLabel); if (left.Type.IsValueType) { if (!left.Type.IsNullable()) { throw new InvalidOperationException("Type '" + left.Type + "' cannot be null"); } if (node.Type != left.Type) { context.EmitValueAccess(left.Type); } else { il.Ldobj(left.Type); } } var valueIsNotNullLabel = il.DefineLabel("valueIsNotNull"); il.Br(valueIsNotNullLabel); if (labelUsed) { context.MarkLabelAndSurroundWithSP(valueIsNullLabel); il.Pop(); } Type rightType; var result = ExpressionEmittersCollection.Emit(right, context, returnDefaultValueLabel, out rightType); context.MarkLabelAndSurroundWithSP(valueIsNotNullLabel); resultType = node.Type; return(result); // ReSharper restore HeuristicUnreachableCode }
protected override bool EmitInternal(MethodCallExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { var result = false; GroboIL il = context.Il; var method = node.Method; Expression obj; IEnumerable <Expression> arguments; IEnumerable <ParameterInfo> parameters; bool isStatic = method.IsStatic; if (!isStatic) { obj = node.Object; arguments = node.Arguments; parameters = method.GetParameters(); } else if (method.DeclaringType == typeof(Enumerable)) { obj = node.Arguments[0]; arguments = node.Arguments.Skip(1); parameters = method.GetParameters().Skip(1); } else { obj = null; arguments = node.Arguments; parameters = method.GetParameters(); } Type type = obj == null ? null : obj.Type; if (obj != null) { Type actualType; result |= ExpressionEmittersCollection.Emit(obj, context, returnDefaultValueLabel, isStatic ? ResultType.Value : ResultType.ByRefValueTypesOnly, extend, out actualType); // stack: [obj] if (actualType == typeof(void)) { throw new InvalidOperationException("Unable to call method on void"); } if (actualType.IsValueType && !isStatic) { using (var temp = context.DeclareLocal(actualType)) { il.Stloc(temp); il.Ldloca(temp); } actualType = actualType.MakeByRefType(); } if (context.Options.HasFlag(CompilerOptions.CheckNullReferences) && !actualType.IsValueType) { if (method.DeclaringType != typeof(Enumerable)) { result |= context.EmitNullChecking(type, returnDefaultValueLabel); } else { var arrIsNotNullLabel = il.DefineLabel("arrIsNotNull"); il.Dup(); il.Brtrue(arrIsNotNullLabel); il.Pop(); il.Ldc_I4(0); il.Newarr(GetElementType(type)); context.MarkLabelAndSurroundWithSP(arrIsNotNullLabel); } } } var parametersArray = parameters.ToArray(); var argumentsArray = arguments.ToArray(); for (int i = 0; i < argumentsArray.Length; i++) { var argument = argumentsArray[i]; var parameter = parametersArray[i]; if (parameter.ParameterType.IsByRef) { Type argumentType; var options = context.Options; context.Options = CompilerOptions.None; ExpressionEmittersCollection.Emit(argument, context, null, ResultType.ByRefAll, false, out argumentType); context.Options = options; if (!argumentType.IsByRef) { throw new InvalidOperationException("Expected type by reference"); } } else { Type argumentType; context.EmitLoadArgument(argument, true, out argumentType); } } il.Call(method, type); resultType = node.Type; return(result); }
protected override bool EmitInternal(IndexExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { if (node.Object == null) { throw new InvalidOperationException("Indexing of null object is invalid"); } if (node.Object.Type.IsArray && node.Object.Type.GetArrayRank() == 1) { return(ExpressionEmittersCollection.Emit(Expression.ArrayIndex(node.Object, node.Arguments.Single()), context, returnDefaultValueLabel, whatReturn, extend, out resultType)); } if (node.Object.Type.IsList()) { return(ArrayIndexExpressionEmitter.Emit(node.Object, node.Arguments.Single(), context, returnDefaultValueLabel, whatReturn, extend, out resultType)); } Type objectType; bool result = ExpressionEmittersCollection.Emit(node.Object, context, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out objectType); if (objectType.IsValueType) { using (var temp = context.DeclareLocal(objectType)) { context.Il.Stloc(temp); context.Il.Ldloca(temp); } } if (context.Options.HasFlag(CompilerOptions.CheckNullReferences)) { result |= context.EmitNullChecking(objectType, returnDefaultValueLabel); } if (node.Indexer != null) { context.EmitLoadArguments(node.Arguments.ToArray()); MethodInfo getter = node.Indexer.GetGetMethod(context.SkipVisibility); if (getter == null) { throw new MissingMethodException(node.Indexer.ReflectedType.ToString(), "get_" + node.Indexer.Name); } GroboIL.Label doneLabel = null; if (node.Object.Type.IsDictionary()) { var valueType = node.Object.Type.GetGenericArguments()[1]; var constructor = valueType.GetConstructor(Type.EmptyTypes); extend &= (valueType.IsClass && constructor != null) || valueType.IsArray || valueType.IsValueType || valueType == typeof(string); doneLabel = context.Il.DefineLabel("done"); using (var dict = context.DeclareLocal(node.Object.Type)) using (var key = context.DeclareLocal(node.Arguments.Single().Type)) using (var value = context.DeclareLocal(valueType)) { context.Il.Stloc(key); // key = arg0; stack: [dict] context.Il.Dup(); // stack: [dict, dict] context.Il.Stloc(dict); // stack: [dict] context.Il.Ldloc(key); // stack: [dict, key] context.Il.Ldloca(value); // stack: [dict, key, ref value] var tryGetValueMethod = node.Object.Type.GetMethod("TryGetValue", BindingFlags.Public | BindingFlags.Instance); if (tryGetValueMethod == null) { throw new MissingMethodException(node.Object.Type.Name, "TryGetValue"); } context.Il.Call(tryGetValueMethod, node.Object.Type); // stack: [dict.TryGetValue(key, out value)] var loadResultLabel = context.Il.DefineLabel("loadResult"); context.Il.Brtrue(loadResultLabel); // if(dict.TryGetValue(key, out result)) goto loadResult; stack: [] if (valueType.IsValueType) { context.Il.Ldloca(value); context.Il.Initobj(valueType); // value = default(valueType) context.Il.Ldloc(value); // stack: [default(valueType)] } else if (valueType == typeof(string)) { context.Il.Ldstr(""); } else { context.Create(valueType); } context.Il.Stloc(value); if (extend) { context.Il.Ldloc(dict); // stack: [dict] context.Il.Ldloc(key); // stack: [dict, key] context.Il.Ldloc(value); // stack: [dict, key, value] var setter = node.Indexer.GetSetMethod(context.SkipVisibility); if (setter == null) { throw new MissingMethodException(node.Indexer.ReflectedType.ToString(), "set_" + node.Indexer.Name); } context.Il.Call(setter, node.Object.Type); // dict.set_Item(key, default(valueType)); stack: [] } context.MarkLabelAndSurroundWithSP(loadResultLabel); context.Il.Ldloc(value); } } if (doneLabel != null) { context.MarkLabelAndSurroundWithSP(doneLabel); } else { context.Il.Call(getter, node.Object.Type); } } else { Type arrayType = node.Object.Type; if (!arrayType.IsArray) { throw new InvalidOperationException("An array expected"); } int rank = arrayType.GetArrayRank(); if (rank != node.Arguments.Count) { throw new InvalidOperationException("Incorrect number of indeces '" + node.Arguments.Count + "' provided to access an array with rank '" + rank + "'"); } Type indexType = node.Arguments.First().Type; if (indexType != typeof(int)) { throw new InvalidOperationException("Indexing array with an index of type '" + indexType + "' is not allowed"); } context.EmitLoadArguments(node.Arguments.ToArray()); MethodInfo getMethod = arrayType.GetMethod("Get"); if (getMethod == null) { throw new MissingMethodException(arrayType.ToString(), "Get"); } context.Il.Call(getMethod, arrayType); } resultType = node.Type; return(result); }