public override void EmitLiteral(MethodContext method, object value) { switch (System.Runtime.InteropServices.Marshal.SizeOf(Native)) { case 4: method.IL.Emit(OpCodes.Ldc_I4, (int)value); break; case 8: method.IL.Emit(OpCodes.Ldc_I8, (long)value); break; default: throw new NotSupportedException(); } }
protected override void EmitUnaryOperator(MethodContext method, Compiler compiler, ExpressionContext inner, Parse.UnaryExpression expression) { switch (expression.Operator) { case Parse.Operator.Exists: case Parse.Operator.IsNull: case Parse.Operator.Not: case Parse.Operator.BitwiseNot: base.EmitUnaryOperator(method, compiler, inner, expression); break; default: throw NotSupported(expression); } }
protected override void EmitBinaryOperator(MethodContext method, Compiler compiler, ExpressionContext left, ExpressionContext right, Parse.BinaryExpression expression) { switch (expression.Operator) { case Parse.Operator.Power: var intPower = typeof(Runtime.Runtime).GetMethod("IntPower", new[] { typeof(int), typeof(int) }); if (intPower == null) throw new NotSupportedException(); left.EmitGet(method); right.EmitGet(method); method.IL.EmitCall(OpCodes.Call, intPower, null); break; default: base.EmitBinaryOperator(method, compiler, left, right, expression); break; } }
protected override void EmitBinaryOperator(MethodContext method, Compiler compiler, ExpressionContext left, ExpressionContext right, Parse.BinaryExpression expression) { switch (expression.Operator) { case Parse.Operator.BitwiseAnd: case Parse.Operator.BitwiseOr: case Parse.Operator.BitwiseXor: case Parse.Operator.Xor: case Parse.Operator.ShiftLeft: case Parse.Operator.ShiftRight: case Parse.Operator.And: case Parse.Operator.Or: case Parse.Operator.Equal: case Parse.Operator.NotEqual: case Parse.Operator.InclusiveGreater: case Parse.Operator.InclusiveLess: case Parse.Operator.Greater: case Parse.Operator.Less: base.EmitBinaryOperator(method, compiler, left, right, expression); break; default: throw NotSupported(expression); } }
/// <summary> Overridden to determine what operators a type supports and to change how they are implemented. </summary> protected virtual void EmitUnaryOperator(MethodContext method, Compiler compiler, ExpressionContext inner, Parse.UnaryExpression expression) { var innerType = inner.Type.GetNative(compiler.Emitter); inner.EmitGet(method); switch (expression.Operator) { case Parse.Operator.Exists: method.IL.Emit(OpCodes.Pop); method.IL.Emit(OpCodes.Ldc_I4_1); // true break; case Parse.Operator.IsNull: method.IL.Emit(OpCodes.Pop); method.IL.Emit(OpCodes.Ldc_I4_0); // false break; case Parse.Operator.Negate: if (!CallClassOp(method, "op_UnaryNegation", innerType)) method.IL.Emit(OpCodes.Neg); break; case Parse.Operator.Not: if (!CallClassOp(method, "op_Negation", innerType)) method.IL.Emit(OpCodes.Not); break; case Parse.Operator.BitwiseNot: if (!CallClassOp(method, "op_OnesComplement", innerType)) method.IL.Emit(OpCodes.Not); break; case Parse.Operator.Successor: method.IL.Emit(OpCodes.Ldc_I4_1); method.IL.Emit(OpCodes.Add); break; case Parse.Operator.Predicessor: method.IL.Emit(OpCodes.Ldc_I4_1); method.IL.Emit(OpCodes.Sub); break; default: throw NotSupported(expression); } }
/// <summary> Overridden to determine what operators a type supports and to change how they are implemented. </summary> /// <remarks> Override this rather than CompileBinaryOperator when nothing special is necessary when compiling the right-hand expression. </remarks> protected virtual void EmitShortCircuit(MethodContext method, Compiler compiler, Frame frame, ExpressionContext left, ExpressionContext right, Parse.BinaryExpression expression, Type.BaseType typeHint) { var leftType = left.Type.GetNative(compiler.Emitter); var rightType = right.Type.GetNative(compiler.Emitter); left.EmitGet(method); right.EmitGet(method); switch (expression.Operator) { case Parse.Operator.And: if (!CallClassOp(method, "op_LogicalAnd", leftType, leftType)) { var label = method.IL.DefineLabel(); method.IL.Emit(OpCodes.Dup); method.IL.Emit(OpCodes.Brfalse_S, label); right.EmitGet(method); method.IL.Emit(OpCodes.And); method.IL.MarkLabel(label); } break; case Parse.Operator.Or: if (!CallClassOp(method, "op_LogicalOr", leftType, leftType)) { var label = method.IL.DefineLabel(); method.IL.Emit(OpCodes.Dup); method.IL.Emit(OpCodes.Brtrue_S, label); right.EmitGet(method); method.IL.Emit(OpCodes.Or); method.IL.MarkLabel(label); } break; default: throw new NotSupportedException(String.Format("Operator {0} is not supported.", expression.Operator)); } }
/// <summary> Overridden to determine what operators a type supports and to change how they are implemented. </summary> /// <remarks> Override this rather than CompileBinaryOperator when nothing special is necessary when compiling the right-hand expression. </remarks> protected virtual void EmitBinaryOperator(MethodContext method, Compiler compiler, ExpressionContext left, ExpressionContext right, Parse.BinaryExpression expression) { var leftType = left.Type.GetNative(compiler.Emitter); var rightType = right.Type.GetNative(compiler.Emitter); left.EmitGet(method); right.EmitGet(method); switch (expression.Operator) { case Parse.Operator.Addition: if (!CallClassOp(method, "op_Addition", leftType, rightType)) method.IL.Emit(OpCodes.Add); break; case Parse.Operator.Subtract: if (!CallClassOp(method, "op_Subtraction", leftType, rightType)) method.IL.Emit(OpCodes.Sub); break; case Parse.Operator.Multiply: if (!CallClassOp(method, "op_Multiply", leftType, rightType)) method.IL.Emit(OpCodes.Mul); break; case Parse.Operator.Modulo: if (!CallClassOp(method, "op_Modulus", leftType, rightType)) method.IL.Emit(OpCodes.Rem); break; case Parse.Operator.Divide: if (!CallClassOp(method, "op_Division", leftType, rightType)) method.IL.Emit(OpCodes.Div); break; case Parse.Operator.Power: var mathPower = typeof(System.Math).GetMethod("Pow", new[] { left.Type.GetNative(compiler.Emitter), right.Type.GetNative(compiler.Emitter) }); if (mathPower == null) throw new NotSupportedException(); method.IL.EmitCall(OpCodes.Call, mathPower, null); break; case Parse.Operator.BitwiseAnd: if (!CallClassOp(method, "op_BitwiseOr", leftType, rightType)) method.IL.Emit(OpCodes.And); break; case Parse.Operator.BitwiseOr: if (!CallClassOp(method, "op_Addition", leftType, rightType)) method.IL.Emit(OpCodes.Or); break; case Parse.Operator.BitwiseXor: case Parse.Operator.Xor: if (!CallClassOp(method, "op_ExclusiveOr", leftType, rightType)) method.IL.Emit(OpCodes.Xor); break; case Parse.Operator.ShiftLeft: if (!CallClassOp(method, "op_LeftShift", leftType, rightType)) method.IL.Emit(OpCodes.Shl); break; case Parse.Operator.ShiftRight: if (!CallClassOp(method, "op_RightShift", leftType, rightType)) method.IL.Emit(OpCodes.Shr); break; case Parse.Operator.Equal: if (!CallClassOp(method, "op_Equality", leftType, rightType)) method.IL.Emit(OpCodes.Ceq); break; case Parse.Operator.NotEqual: if (!CallClassOp(method, "op_Inequality", leftType, rightType)) { method.IL.Emit(OpCodes.Ceq); method.IL.Emit(OpCodes.Ldc_I4_0); method.IL.Emit(OpCodes.Ceq); } break; case Parse.Operator.InclusiveGreater: if (!CallClassOp(method, "op_GreaterThanOrEqual", leftType, rightType)) { method.IL.Emit(OpCodes.Clt); method.IL.Emit(OpCodes.Ldc_I4_0); method.IL.Emit(OpCodes.Ceq); } break; case Parse.Operator.InclusiveLess: if (!CallClassOp(method, "op_LessThanOrEqual", leftType, rightType)) { method.IL.Emit(OpCodes.Cgt); method.IL.Emit(OpCodes.Ldc_I4_0); method.IL.Emit(OpCodes.Ceq); } break; case Parse.Operator.Greater: if (!CallClassOp(method, "op_GreaterThan", leftType, rightType)) method.IL.Emit(OpCodes.Cgt); break; case Parse.Operator.Less: if (!CallClassOp(method, "op_LessThan", leftType, rightType)) method.IL.Emit(OpCodes.Clt); break; default: throw NotSupported(expression); } }
/// <summary> Attempt to invoke an operator overload on the left-hand class if there is one. </summary> protected bool CallClassOp(MethodContext method, string opName, params System.Type[] types) { var classOp = types[0].GetMethod(opName, types); if (classOp != null) { method.IL.EmitCall(OpCodes.Call, classOp, null); return true; } return false; }
public virtual void EmitLiteral(MethodContext method, object value) { throw new NotSupportedException(); }
public System.Type CompleteMain(MethodContext main) { main.IL.Emit(OpCodes.Ret); return ((TypeBuilder)main.Builder.DeclaringType).CreateType(); }
protected override void EmitBinaryOperator(MethodContext method, Compiler compiler, ExpressionContext left, ExpressionContext right, Parse.BinaryExpression expression) { switch (expression.Operator) { case Parse.Operator.Addition: left.EmitGet(method); right.EmitGet(method); method.IL.EmitCall(OpCodes.Call, ReflectionUtility.StringConcat, null); break; case Parse.Operator.Equal: base.EmitBinaryOperator(method, compiler, left, right, expression); break; case Parse.Operator.NotEqual: left.EmitGet(method); right.EmitGet(method); method.IL.EmitCall(OpCodes.Call, ReflectionUtility.StringCompare, null); method.IL.Emit(OpCodes.Ldc_I4_0); method.IL.Emit(OpCodes.Ceq); // Not method.IL.Emit(OpCodes.Ldc_I4_0); method.IL.Emit(OpCodes.Ceq); break; case Parse.Operator.InclusiveGreater: left.EmitGet(method); right.EmitGet(method); method.IL.EmitCall(OpCodes.Call, ReflectionUtility.StringCompare, null); method.IL.Emit(OpCodes.Ldc_I4_0); method.IL.Emit(OpCodes.Clt); // Not method.IL.Emit(OpCodes.Ldc_I4_0); method.IL.Emit(OpCodes.Ceq); break; case Parse.Operator.InclusiveLess: left.EmitGet(method); right.EmitGet(method); method.IL.EmitCall(OpCodes.Call, ReflectionUtility.StringCompare, null); method.IL.Emit(OpCodes.Ldc_I4_0); method.IL.Emit(OpCodes.Cgt); // Not method.IL.Emit(OpCodes.Ldc_I4_0); method.IL.Emit(OpCodes.Ceq); break; case Parse.Operator.Greater: left.EmitGet(method); right.EmitGet(method); method.IL.EmitCall(OpCodes.Call, ReflectionUtility.StringCompare, null); method.IL.Emit(OpCodes.Ldc_I4_0); method.IL.Emit(OpCodes.Cgt); break; case Parse.Operator.Less: left.EmitGet(method); right.EmitGet(method); method.IL.EmitCall(OpCodes.Call, ReflectionUtility.StringCompare, null); method.IL.Emit(OpCodes.Ldc_I4_0); method.IL.Emit(OpCodes.Clt); break; default: throw NotSupported(expression); } }
public override void EmitLiteral(MethodContext method, object value) { method.IL.Emit(OpCodes.Ldstr, (string)value); }
protected override void EmitBinaryOperator(MethodContext method, Compiler compiler, ExpressionContext left, ExpressionContext right, Parse.BinaryExpression expression) { switch (expression.Operator) { case Parse.Operator.Equal: case Parse.Operator.NotEqual: base.EmitBinaryOperator(method, compiler, left, right, expression); break; //// TODO: Tuple union //case Parse.Operator.BitwiseOr: default: throw NotSupported(expression); } }
// 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 override void EmitUnaryOperator(MethodContext method, Compiler compiler, ExpressionContext inner, Parse.UnaryExpression expression) { switch (expression.Operator) { case Parse.Operator.Exists: method.IL.EmitCall(OpCodes.Callvirt, typeof(ICollection<>).MakeGenericType(inner.Type.GetNative(compiler.Emitter)).GetProperty("Count").GetGetMethod(), null); method.IL.Emit(OpCodes.Ldc_I4_0); method.IL.Emit(OpCodes.Cgt); break; case Parse.Operator.IsNull: method.IL.Emit(OpCodes.Pop); method.IL.Emit(OpCodes.Ldc_I4_0); break; default: throw NotSupported(expression); } }
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); } ); }
// TODO: define operators for TimeSpan public override void EmitLiteral(MethodContext method, object value) { method.IL.Emit(OpCodes.Ldc_I8, ((TimeSpan)value).Ticks); method.IL.Emit(OpCodes.Newobj, ReflectionUtility.TimeSpanTicksConstructor); }
public override void EmitLiteral(MethodContext method, object value) { method.IL.Emit(((bool)value) ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); }