Exemple #1
0
        /// <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);
            });
        }
Exemple #2
0
        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();
            });
        }
Exemple #4
0
        /// <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();
            });
        }