/// <inheritdoc /> public override Func <ITag, CompileContext, Type> BuildGuessMethod() { return((tag, c) => { var t = tag as ArithmeticTag; var types = new List <Type>(); var opts = new List <Operator>(); for (var i = 0; i < t.Children.Count; i++) { var opt = t.Children[i] as OperatorTag; if (opt == null) { types.Add(c.GuessType(t.Children[i])); } } if (types.Count == 1) { return types[0]; } if (types.Contains(typeof(string))) { return typeof(string); } if (types.Count > 0) { return TypeGuesser.FindBestType(types.ToArray()); } return typeof(int); }); }
private void RegiserCompile(IHost host) { host.RegisterCompileFunc <ReferenceTag>((tag, c) => { return(c.CompileTag(((ReferenceTag)tag).Child)); }); host.RegisterCompileFunc <LogicTag>((tag, c) => { var t = tag as LogicTag; var type = c.GuessType(t); var mb = c.CreateReutrnMethod <LogicTag>(type); var il = mb.GetILGenerator(); Label labelEnd = il.DefineLabel(); il.DeclareLocal(type); var array = new object[t.Children.Count]; var types = new List <Type>(); var opts = new List <Operator>(); var message = new List <string>(); for (int i = 0; i < t.Children.Count; i++) { var opt = t.Children[i] as OperatorTag; if (opt != null) { if (!opts.Contains(opt.Value)) { opts.Add(opt.Value); } array[i] = opt.Value; message.Add(OperatorConvert.ToString(opt.Value)); } else { array[i] = t.Children[i]; types.Add(c.GuessType(t.Children[i])); message.Add(types[types.Count - 1].Name); } } if (opts.Contains(Operator.Or) || opts.Contains(Operator.And)) { Label labelTrue = il.DefineLabel(); Label labelFalse = il.DefineLabel(); Operator pre = Operator.None; for (int i = 0; i < t.Children.Count; i++) { var opt = t.Children[i] as OperatorTag; if (opt != null) { pre = opt.Value; continue; } var m = c.CompileTag(t.Children[i]); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, m); if (m.ReturnType.Name != "Boolean") { var cm = typeof(Utility).GetMethodInfo("ToBoolean", new Type[] { m.ReturnType }); if (cm == null) { cm = typeof(Utility).GetMethodInfo("ToBoolean", new Type[] { typeof(object) }); if (m.ReturnType.IsValueType) { il.Emit(OpCodes.Box, typeof(object)); } else { il.Emit(OpCodes.Castclass, typeof(object)); } } il.Emit(OpCodes.Call, cm); } //il.Emit(OpCodes.Stloc_0); if (pre == Operator.None) { pre = (t.Children[i + 1] as OperatorTag).Value; } if (pre == Operator.Or) { il.Emit(OpCodes.Brtrue, labelTrue); } if (pre == Operator.And) { il.Emit(OpCodes.Brfalse, labelFalse); } } if (pre == Operator.Or) { il.Emit(OpCodes.Br, labelEnd); } if (pre == Operator.And) { il.Emit(OpCodes.Br, labelTrue); } il.MarkLabel(labelTrue); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Br, labelEnd); il.MarkLabel(labelFalse); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_0); } else { if (t.Children.Count == 1) { var m = c.CompileTag(t.Children[0]); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, m); il.Emit(OpCodes.Stloc_0); } else if (t.Children.Count == 3) { var bestType = TypeGuesser.FindBestType(types.ToArray()); var stack = ExpressionEvaluator.ProcessExpression(array); var arr = stack.ToArray(); for (var i = arr.Length - 1; i >= 0; i--) { var obj = arr[i]; var childTag = obj as ITag; if (childTag != null) { var m = c.CompileTag(childTag); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, m); if (m.ReturnType.FullName != bestType.FullName) { switch (bestType.FullName) { case "System.Decimal": Type cType = m.ReturnType; switch (cType.FullName) { case "System.Int16": case "System.UInt16": case "System.Byte": il.Emit(OpCodes.Conv_I4); break; } il.Emit(OpCodes.Call, typeof(decimal).GetConstructor(new Type[] { cType })); break; case "System.Double": il.Emit(OpCodes.Conv_R8); break; case "System.Single": il.Emit(OpCodes.Conv_R4); break; case "System.Int64": il.Emit(OpCodes.Conv_I8); break; case "System.UInt64": il.Emit(OpCodes.Conv_U8); break; case "System.Int32": il.Emit(OpCodes.Conv_I4); break; case "System.UInt32": il.Emit(OpCodes.Conv_U4); break; case "System.Int16": il.Emit(OpCodes.Conv_I2); break; case "System.UInt16": il.Emit(OpCodes.Conv_U2); break; case "System.Byte": il.Emit(OpCodes.Conv_U1); break; case "System.String": if (m.ReturnType.IsValueType) { var p = il.DeclareLocal(m.ReturnType); il.Emit(OpCodes.Stloc, p.LocalIndex); il.Emit(OpCodes.Ldloca, p.LocalIndex); } il.Call(m.ReturnType, typeof(object).GetMethodInfo("ToString", Type.EmptyTypes)); break; default: if (m.ReturnType.IsValueType) { if (bestType.IsValueType) { il.Emit(OpCodes.Isinst, bestType); } else { il.Emit(OpCodes.Box, bestType); } } else { if (bestType.IsValueType) { il.Emit(OpCodes.Unbox, bestType); } else { il.Emit(OpCodes.Castclass, bestType); } } break; } } } else { switch ((Operator)obj) { case Operator.GreaterThan: if (TypeGuesser.CanUseEqual(bestType)) { il.Emit(OpCodes.Cgt); } else { var m = bestType.GetMethodInfo("op_GreaterThan", new Type[] { bestType, bestType }); if (m == null) { throw new TemplateException($"Operator \">\" can not be applied operand \"{bestType.FullName}\" and \"{bestType.FullName}\""); } il.Emit(OpCodes.Call, m); } break; case Operator.GreaterThanOrEqual: if (TypeGuesser.CanUseEqual(bestType)) { il.Emit(OpCodes.Clt_Un); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); } else { var m = bestType.GetMethodInfo("op_GreaterThanOrEqual", new Type[] { bestType, bestType }); if (m == null) { throw new TemplateException($"Operator \">=\" can not be applied operand \"{bestType.FullName}\" and \"{bestType.FullName}\""); } il.Emit(OpCodes.Call, m); } break; case Operator.LessThan: if (TypeGuesser.CanUseEqual(bestType)) { il.Emit(OpCodes.Clt); } else { var m = bestType.GetMethodInfo("op_LessThan", new Type[] { bestType, bestType }); if (m == null) { throw new TemplateException($"Operator \"<\" can not be applied operand \"{bestType.FullName}\" and \"{bestType.FullName}\""); } il.Emit(OpCodes.Call, m); } break; case Operator.LessThanOrEqual: if (TypeGuesser.CanUseEqual(bestType)) { il.Emit(OpCodes.Cgt_Un); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); } else { var m = bestType.GetMethodInfo("op_LessThanOrEqual", new Type[] { bestType, bestType }); if (m == null) { throw new TemplateException($"Operator \"<=\" can not be applied operand \"{bestType.FullName}\" and \"{bestType.FullName}\""); } il.Emit(OpCodes.Call, m); } break; case Operator.Equal: if (TypeGuesser.CanUseEqual(bestType)) { il.Emit(OpCodes.Ceq); } else { il.EmitEquals(bestType); //il.Emit(OpCodes.Call, DynamicHelpers.GetMethodInfo(bestType, "Equals", new Type[] { bestType })); } break; case Operator.NotEqual: if (TypeGuesser.CanUseEqual(bestType)) { il.Emit(OpCodes.Ceq); } else { il.EmitEquals(bestType); //il.Emit(OpCodes.Call, DynamicHelpers.GetMethodInfo(bestType, "Equals", new Type[] { bestType })); } il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); break; default: throw new CompileException(tag, $"The operator \"{obj}\" is not supported on type \"{bestType.FullName}\" ."); } } } il.Emit(OpCodes.Stloc_0); } else { throw new CompileException(tag, $"[LogicExpressionTag] : The expression \"{string.Concat(message)}\" is not supported ."); } } il.MarkLabel(labelEnd); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ret); return(mb.GetBaseDefinition()); }); host.RegisterCompileFunc <ArithmeticTag>((tag, c) => { var stringBuilderType = typeof(StringBuilder); var t = tag as ArithmeticTag; var type = c.GuessType(t); var mb = c.CreateReutrnMethod <ArithmeticTag>(type); var il = mb.GetILGenerator(); Label labelEnd = il.DefineLabel(); il.DeclareLocal(type); var array = new object[t.Children.Count]; var types = new List <Type>(); var opts = new List <Operator>(); var message = new List <string>(); for (int i = 0; i < t.Children.Count; i++) { var opt = t.Children[i] as OperatorTag; if (opt != null) { if (!opts.Contains(opt.Value)) { opts.Add(opt.Value); } array[i] = opt.Value; message.Add(OperatorConvert.ToString(opt.Value)); } else { array[i] = t.Children[i]; types.Add(c.GuessType(t.Children[i])); message.Add(types[types.Count - 1].Name); } } if (types.Contains(typeof(string)) && opts.Count == 1 && opts[0] == Operator.Add) { il.DeclareLocal(stringBuilderType); il.Emit(OpCodes.Newobj, stringBuilderType.GetConstructor(Type.EmptyTypes)); il.Emit(OpCodes.Stloc_1); for (int i = 0; i < t.Children.Count; i++) { var opt = t.Children[i] as OperatorTag; if (opt != null) { continue; } il.Emit(OpCodes.Ldloc_1); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); var m = c.CompileTag(t.Children[i]); il.Emit(OpCodes.Call, m); il.StringAppend(c, m.ReturnType); il.Emit(OpCodes.Pop); } il.Emit(OpCodes.Ldloc_1); il.Call(stringBuilderType, typeof(object).GetMethodInfo("ToString", Type.EmptyTypes)); il.Emit(OpCodes.Stloc_0); } else { var bestType = TypeGuesser.FindBestType(types.ToArray()); var stack = ExpressionEvaluator.ProcessExpression(array); var arr = stack.ToArray(); for (var i = arr.Length - 1; i >= 0; i--) { var obj = arr[i]; var childTag = obj as ITag; if (childTag != null) { var m = c.CompileTag(childTag); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, m); if (m.ReturnType.FullName != bestType.FullName) { switch (bestType.FullName) { case "System.Decimal": Type cType = m.ReturnType; switch (cType.FullName) { case "System.Int16": case "System.UInt16": case "System.Byte": il.Emit(OpCodes.Conv_I4); break; } il.Emit(OpCodes.Call, typeof(decimal).GetConstructor(new Type[] { cType })); break; case "System.Double": il.Emit(OpCodes.Conv_R8); break; case "System.Single": il.Emit(OpCodes.Conv_R4); break; case "System.Int64": il.Emit(OpCodes.Conv_I8); break; case "System.UInt64": il.Emit(OpCodes.Conv_U8); break; case "System.Int32": il.Emit(OpCodes.Conv_I4); break; case "System.UInt32": il.Emit(OpCodes.Conv_U4); break; case "System.Int16": il.Emit(OpCodes.Conv_I2); break; case "System.UInt16": il.Emit(OpCodes.Conv_U2); break; case "System.Byte": il.Emit(OpCodes.Conv_U1); break; default: throw new CompileException(tag, $"[ExpressionTag] : The type \"{bestType.FullName}\" is not supported ."); } } } else { switch ((Operator)obj) { case Operator.Add: il.Emit(OpCodes.Add); break; case Operator.Subtract: il.Emit(OpCodes.Sub); break; case Operator.Multiply: il.Emit(OpCodes.Mul); break; case Operator.Divided: il.Emit(OpCodes.Div); break; case Operator.Remainder: il.Emit(OpCodes.Rem); break; case Operator.GreaterThan: il.Emit(OpCodes.Cgt); break; case Operator.GreaterThanOrEqual: il.Emit(OpCodes.Clt_Un); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); break; case Operator.LessThan: il.Emit(OpCodes.Clt); break; case Operator.LessThanOrEqual: il.Emit(OpCodes.Cgt_Un); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); break; case Operator.Equal: il.Emit(OpCodes.Ceq); break; case Operator.NotEqual: il.Emit(OpCodes.Ceq); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); break; default: throw new CompileException(tag, $"[ExpressionTag] : The expression \"{string.Concat(message)}\" is not supported ."); //throw new CompileException($"The operator \"{obj}\" is not supported on type \"{bestType.FullName}\" ."); //case Operator.Or: // il.Emit(OpCodes.Blt); // break; } } } il.Emit(OpCodes.Stloc_0); } il.MarkLabel(labelEnd); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ret); return(mb.GetBaseDefinition()); }); host.RegisterGuessFunc <ReferenceTag>((tag, c) => { return(c.GuessType(((ReferenceTag)tag).Child)); }); host.RegisterGuessFunc <LogicTag>((tag, ctx) => { return(typeof(bool)); }); host.RegisterGuessFunc <ArithmeticTag>((tag, ctx) => { var t = tag as ArithmeticTag; var types = new List <Type>(); var opts = new List <Operator>(); for (var i = 0; i < t.Children.Count; i++) { var opt = t.Children[i] as OperatorTag; if (opt == null) { types.Add(ctx.GuessType(t.Children[i])); } } if (types.Count == 1) { return(types[0]); } if (types.Contains(typeof(string))) { return(typeof(string)); } if (types.Count > 0) { return(TypeGuesser.FindBestType(types.ToArray())); } return(typeof(int)); }); }
/// <inheritdoc /> public override Func <ITag, CompileContext, MethodInfo> BuildCompileMethod() { return((tag, c) => { var t = tag as LogicTag; var type = c.GuessType(t); var mb = c.CreateReutrnMethod <LogicTag>(type); var il = mb.GetILGenerator(); Label labelEnd = il.DefineLabel(); il.DeclareLocal(type); var array = new object[t.Children.Count]; var types = new List <Type>(); var opts = new List <Operator>(); var message = new List <string>(); for (int i = 0; i < t.Children.Count; i++) { var opt = t.Children[i] as OperatorTag; if (opt != null) { if (!opts.Contains(opt.Value)) { opts.Add(opt.Value); } array[i] = opt.Value; message.Add(OperatorConvert.ToString(opt.Value)); } else { array[i] = t.Children[i]; types.Add(c.GuessType(t.Children[i])); message.Add(types[types.Count - 1].Name); } } if (opts.Contains(Operator.Or) || opts.Contains(Operator.And)) { Label labelTrue = il.DefineLabel(); Label labelFalse = il.DefineLabel(); Operator pre = Operator.None; for (int i = 0; i < t.Children.Count; i++) { var opt = t.Children[i] as OperatorTag; if (opt != null) { pre = opt.Value; continue; } var m = c.CompileTag(t.Children[i]); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, m); if (m.ReturnType.Name != "Boolean") { var cm = typeof(Utility).GetMethodInfo("ToBoolean", new Type[] { m.ReturnType }); if (cm == null) { cm = typeof(Utility).GetMethodInfo("ToBoolean", new Type[] { typeof(object) }); if (m.ReturnType.IsValueType) { il.Emit(OpCodes.Box, typeof(object)); } else { il.Emit(OpCodes.Castclass, typeof(object)); } } il.Emit(OpCodes.Call, cm); } //il.Emit(OpCodes.Stloc_0); if (pre == Operator.None) { pre = (t.Children[i + 1] as OperatorTag).Value; } if (pre == Operator.Or) { il.Emit(OpCodes.Brtrue, labelTrue); } if (pre == Operator.And) { il.Emit(OpCodes.Brfalse, labelFalse); } } if (pre == Operator.Or) { il.Emit(OpCodes.Br, labelEnd); } if (pre == Operator.And) { il.Emit(OpCodes.Br, labelTrue); } il.MarkLabel(labelTrue); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Br, labelEnd); il.MarkLabel(labelFalse); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_0); } else { if (t.Children.Count == 1) { var m = c.CompileTag(t.Children[0]); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, m); il.Emit(OpCodes.Stloc_0); } else if (t.Children.Count == 3) { var bestType = TypeGuesser.FindBestType(types.ToArray()); var stack = ExpressionEvaluator.ProcessExpression(array); var arr = stack.ToArray(); for (var i = arr.Length - 1; i >= 0; i--) { var obj = arr[i]; var childTag = obj as ITag; if (childTag != null) { var m = c.CompileTag(childTag); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, m); if (m.ReturnType.FullName != bestType.FullName) { il.ConvertTo(m.ReturnType, bestType); } } else { switch ((Operator)obj) { case Operator.GreaterThan: if (TypeGuesser.CanUseEqual(bestType)) { il.Emit(OpCodes.Cgt); } else { var m = bestType.GetMethodInfo("op_GreaterThan", new Type[] { bestType, bestType }); if (m == null) { throw new TemplateException($"Operator \">\" can not be applied operand \"{bestType.FullName}\" and \"{bestType.FullName}\""); } il.Emit(OpCodes.Call, m); } break; case Operator.GreaterThanOrEqual: if (TypeGuesser.CanUseEqual(bestType)) { il.Emit(OpCodes.Clt_Un); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); } else { var m = bestType.GetMethodInfo("op_GreaterThanOrEqual", new Type[] { bestType, bestType }); if (m == null) { throw new TemplateException($"Operator \">=\" can not be applied operand \"{bestType.FullName}\" and \"{bestType.FullName}\""); } il.Emit(OpCodes.Call, m); } break; case Operator.LessThan: if (TypeGuesser.CanUseEqual(bestType)) { il.Emit(OpCodes.Clt); } else { var m = bestType.GetMethodInfo("op_LessThan", new Type[] { bestType, bestType }); if (m == null) { throw new TemplateException($"Operator \"<\" can not be applied operand \"{bestType.FullName}\" and \"{bestType.FullName}\""); } il.Emit(OpCodes.Call, m); } break; case Operator.LessThanOrEqual: if (TypeGuesser.CanUseEqual(bestType)) { il.Emit(OpCodes.Cgt_Un); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); } else { var m = bestType.GetMethodInfo("op_LessThanOrEqual", new Type[] { bestType, bestType }); if (m == null) { throw new TemplateException($"Operator \"<=\" can not be applied operand \"{bestType.FullName}\" and \"{bestType.FullName}\""); } il.Emit(OpCodes.Call, m); } break; case Operator.Equal: if (TypeGuesser.CanUseEqual(bestType)) { il.Emit(OpCodes.Ceq); } else { il.EmitEquals(bestType); //il.Emit(OpCodes.Call, DynamicHelpers.GetMethodInfo(bestType, "Equals", new Type[] { bestType })); } break; case Operator.NotEqual: if (TypeGuesser.CanUseEqual(bestType)) { il.Emit(OpCodes.Ceq); } else { il.EmitEquals(bestType); //il.Emit(OpCodes.Call, DynamicHelpers.GetMethodInfo(bestType, "Equals", new Type[] { bestType })); } il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); break; default: throw new CompileException(tag, $"The operator \"{obj}\" is not supported on type \"{bestType.FullName}\" ."); } } } il.Emit(OpCodes.Stloc_0); } else { throw new CompileException(tag, $"[LogicExpressionTag] : The expression \"{string.Concat(message)}\" is not supported ."); } } il.MarkLabel(labelEnd); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ret); return mb.GetBaseDefinition(); }); }
/// <inheritdoc /> public override Func <ITag, CompileContext, MethodInfo> BuildCompileMethod() { return((tag, c) => { var stringBuilderType = typeof(StringBuilder); var t = tag as ArithmeticTag; var type = c.GuessType(t); var mb = c.CreateReutrnMethod <ArithmeticTag>(type); var il = mb.GetILGenerator(); Label labelEnd = il.DefineLabel(); il.DeclareLocal(type); var array = new object[t.Children.Count]; var types = new List <Type>(); var opts = new List <Operator>(); var message = new List <string>(); for (int i = 0; i < t.Children.Count; i++) { var opt = t.Children[i] as OperatorTag; if (opt != null) { if (!opts.Contains(opt.Value)) { opts.Add(opt.Value); } array[i] = opt.Value; message.Add(OperatorConvert.ToString(opt.Value)); } else { array[i] = t.Children[i]; types.Add(c.GuessType(t.Children[i])); message.Add(types[types.Count - 1].Name); } } if (types.Contains(typeof(string)) && opts.Count == 1 && opts[0] == Operator.Add) { il.DeclareLocal(stringBuilderType); il.Emit(OpCodes.Newobj, stringBuilderType.GetConstructor(Type.EmptyTypes)); il.Emit(OpCodes.Stloc_1); for (int i = 0; i < t.Children.Count; i++) { var opt = t.Children[i] as OperatorTag; if (opt != null) { continue; } il.Emit(OpCodes.Ldloc_1); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); var m = c.CompileTag(t.Children[i]); il.Emit(OpCodes.Call, m); il.StringAppend(c, m.ReturnType); il.Emit(OpCodes.Pop); } il.Emit(OpCodes.Ldloc_1); il.Call(stringBuilderType, typeof(object).GetMethodInfo("ToString", Type.EmptyTypes)); il.Emit(OpCodes.Stloc_0); } else { var bestType = TypeGuesser.FindBestType(types.ToArray()); var stack = ExpressionEvaluator.ProcessExpression(array); var arr = stack.ToArray(); for (var i = arr.Length - 1; i >= 0; i--) { var obj = arr[i]; var childTag = obj as ITag; if (childTag != null) { var m = c.CompileTag(childTag); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, m); if (m.ReturnType.FullName != bestType.FullName) { switch (bestType.FullName) { case "System.Decimal": Type cType = m.ReturnType; switch (cType.FullName) { case "System.Int16": case "System.UInt16": case "System.Byte": il.Emit(OpCodes.Conv_I4); break; } il.Emit(OpCodes.Call, typeof(decimal).GetConstructor(new Type[] { cType })); break; case "System.Double": il.Emit(OpCodes.Conv_R8); break; case "System.Single": il.Emit(OpCodes.Conv_R4); break; case "System.Int64": il.Emit(OpCodes.Conv_I8); break; case "System.UInt64": il.Emit(OpCodes.Conv_U8); break; case "System.Int32": il.Emit(OpCodes.Conv_I4); break; case "System.UInt32": il.Emit(OpCodes.Conv_U4); break; case "System.Int16": il.Emit(OpCodes.Conv_I2); break; case "System.UInt16": il.Emit(OpCodes.Conv_U2); break; case "System.Byte": il.Emit(OpCodes.Conv_U1); break; default: throw new CompileException(tag, $"[ExpressionTag] : The type \"{bestType.FullName}\" is not supported ."); } } } else { switch ((Operator)obj) { case Operator.Add: il.Emit(OpCodes.Add); break; case Operator.Subtract: il.Emit(OpCodes.Sub); break; case Operator.Multiply: il.Emit(OpCodes.Mul); break; case Operator.Divided: il.Emit(OpCodes.Div); break; case Operator.Remainder: il.Emit(OpCodes.Rem); break; case Operator.GreaterThan: il.Emit(OpCodes.Cgt); break; case Operator.GreaterThanOrEqual: il.Emit(OpCodes.Clt_Un); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); break; case Operator.LessThan: il.Emit(OpCodes.Clt); break; case Operator.LessThanOrEqual: il.Emit(OpCodes.Cgt_Un); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); break; case Operator.Equal: il.Emit(OpCodes.Ceq); break; case Operator.NotEqual: il.Emit(OpCodes.Ceq); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); break; default: throw new CompileException(tag, $"[ExpressionTag] : The expression \"{string.Concat(message)}\" is not supported ."); //throw new CompileException($"The operator \"{obj}\" is not supported on type \"{bestType.FullName}\" ."); //case Operator.Or: // il.Emit(OpCodes.Blt); // break; } } } il.Emit(OpCodes.Stloc_0); } il.MarkLabel(labelEnd); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ret); return mb.GetBaseDefinition(); }); }