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);
}
);
}