// Restriction public override ExpressionContext CompileExtractExpression(Compiler compiler, Frame frame, ExpressionContext left, Parse.ExtractExpression expression, BaseType typeHint) { var memberType = ((NaryType)left.Type).Of; var memberNative = left.NativeType ?? memberType.GetNative(compiler.Emitter); var local = compiler.AddFrame(frame, expression); // Prepare index and value symbols var indexSymbol = PrepareValueIndexContext(compiler, left, expression.Condition, memberType, memberNative, local); // Compile condition var condition = compiler.CompileExpression(local, expression.Condition, SystemTypes.Boolean); if (!(condition.Type is BooleanType)) throw new CompilerException(expression.Condition, CompilerException.Codes.IncorrectType, condition.Type, "Boolean"); var indexReferenced = compiler.References.ContainsKey(indexSymbol); return new ExpressionContext ( expression, left.Type, Compiler.MergeCharacteristics(left.Characteristics, condition.Characteristics), m => { // Create a new private method for the condition var typeBuilder = (TypeBuilder)m.Builder.DeclaringType; var innerMethod = new MethodContext ( typeBuilder.DefineMethod ( "Where" + expression.GetHashCode(), MethodAttributes.Private | MethodAttributes.Static, typeof(bool), // return type indexReferenced ? new System.Type[] { memberNative, typeof(int) } : new System.Type[] { memberNative } // param types ) ); condition.EmitGet(innerMethod); innerMethod.IL.Emit(OpCodes.Ret); left.EmitGet(m); // TODO: Force ordering to left if Set and index is referenced // Instantiate a delegate pointing to the new method m.IL.Emit(OpCodes.Ldnull); // instance m.IL.Emit(OpCodes.Ldftn, innerMethod.Builder); // method var funcType = indexReferenced ? System.Linq.Expressions.Expression.GetFuncType(memberNative, typeof(int), typeof(bool)) : System.Linq.Expressions.Expression.GetFuncType(memberNative, typeof(bool)); m.IL.Emit ( OpCodes.Newobj, funcType.GetConstructor(new[] { typeof(object), typeof(IntPtr) }) ); funcType = indexReferenced ? typeof(Func<ReflectionUtility.T, int, bool>) : typeof(Func<ReflectionUtility.T, bool>); var where = typeof(System.Linq.Enumerable).GetMethodExt("Where", new System.Type[] { typeof(IEnumerable<ReflectionUtility.T>), funcType }); where = where.MakeGenericMethod(memberNative); m.IL.EmitCall(OpCodes.Call, where, null); } ); }
protected virtual ExpressionContext CompileDereference(Compiler compiler, Frame frame, ExpressionContext left, Parse.BinaryExpression expression, Type.BaseType typeHint) { var memberType = ((NaryType)left.Type).Of; var memberNative = left.NativeType ?? memberType.GetNative(compiler.Emitter); var local = compiler.AddFrame(frame, expression); // Prepare index and value symbols var indexSymbol = PrepareValueIndexContext(compiler, left, expression.Right, memberType, memberNative, local); // Compile selection var selection = compiler.CompileExpression(local, expression.Right); var indexReferenced = compiler.References.ContainsKey(indexSymbol); return new ExpressionContext ( expression, new ListType(selection.Type), Compiler.MergeCharacteristics(left.Characteristics, selection.Characteristics), m => { // Create a new private method for the condition var typeBuilder = (TypeBuilder)m.Builder.DeclaringType; var innerMethod = new MethodContext ( typeBuilder.DefineMethod ( "Select" + expression.GetHashCode(), MethodAttributes.Private | MethodAttributes.Static, selection.ActualNative(compiler.Emitter), // temporary return type indexReferenced ? new System.Type[] { memberNative, typeof(int) } : new System.Type[] { memberNative } // param types ) ); selection.EmitGet(innerMethod); innerMethod.IL.Emit(OpCodes.Ret); left.EmitGet(m); // TODO: Force ordering of Left if a set and index is referenced // Instantiate a delegate pointing to the new method m.IL.Emit(OpCodes.Ldnull); // instance m.IL.Emit(OpCodes.Ldftn, innerMethod.Builder); // method var funcType = indexReferenced ? System.Linq.Expressions.Expression.GetFuncType(memberNative, typeof(int), innerMethod.Builder.ReturnType) : System.Linq.Expressions.Expression.GetFuncType(memberNative, innerMethod.Builder.ReturnType); m.IL.Emit ( OpCodes.Newobj, funcType.GetConstructor(new[] { typeof(object), typeof(IntPtr) }) ); funcType = indexReferenced ? typeof(Func<ReflectionUtility.T, int, ReflectionUtility.T>) : typeof(Func<ReflectionUtility.T, ReflectionUtility.T>); var select = typeof(Enumerable).GetMethodExt ( "Select", new System.Type[] { typeof(IEnumerable<ReflectionUtility.T>), funcType } ); select = select.MakeGenericMethod(memberNative, innerMethod.Builder.ReturnType); m.IL.EmitCall(OpCodes.Call, select, null); } ); }