Ejemplo n.º 1
0
        public double ExecAst(IAstNode root)
        {
            switch (root)
            {
            case AstNumberNode numberNode:
                return(numberNode.Number);

            case AstVariableNode varNode:
                if (Constants.TryGetValue(varNode.Id, out var val))
                {
                    return((double)val);
                }
                else if (Variables.TryGetValue(varNode.Id, out val))
                {
                    return((double)val);
                }
                else
                {
                    //Sync.Tools.IO.CurrentIO.WriteColor($"[RTPP:Expression]No Variable found (return zero). Variable name: { varNode.Id }", ConsoleColor.Yellow);

                    return(0);
                }

            case AstOpNode opNode:
                switch (opNode.Op)
                {
                case "+":
                    return(ExecAst(opNode.LNode) + ExecAst(opNode.RNode));

                case "-":
                    return(ExecAst(opNode.LNode) - ExecAst(opNode.RNode));

                case "*":
                    return(ExecAst(opNode.LNode) * ExecAst(opNode.RNode));

                case "/":
                    return(ExecAst(opNode.LNode) / ExecAst(opNode.RNode));

                case "%":
                    return(ExecAst(opNode.LNode) % ExecAst(opNode.RNode));

                case "^":
                    return(Math.Pow(ExecAst(opNode.LNode), ExecAst(opNode.RNode)));

                case ">":
                    return((ExecAst(opNode.LNode) > ExecAst(opNode.RNode)) ? 1 : 0);

                case "<":
                    return((ExecAst(opNode.LNode) < ExecAst(opNode.RNode)) ? 1 : 0);

                case ">=":
                    return((ExecAst(opNode.LNode) >= ExecAst(opNode.RNode)) ? 1 : 0);

                case "<=":
                    return((ExecAst(opNode.LNode) <= ExecAst(opNode.RNode)) ? 1 : 0);

                case "==":
                    return(IsNotZero(ExecAst(opNode.LNode) - ExecAst(opNode.RNode)) ? 0 : 1);

                case "!=":
                    return(IsNotZero(ExecAst(opNode.LNode) - ExecAst(opNode.RNode)) ? 1 : 0);

                case "!":
                    return(IsNotZero(ExecAst(opNode.LNode)) ? 0 : 1);

                case "&&":
                    return((IsNotZero(ExecAst(opNode.LNode)) && IsNotZero(ExecAst(opNode.RNode))) ? 1 : 0);

                case "||":
                    return((IsNotZero(ExecAst(opNode.LNode)) || IsNotZero(ExecAst(opNode.RNode))) ? 1 : 0);
                }
                break;

            case AstFunctionNode funcNode:
                try
                {
                    if (funcNode.Id == "set")
                    {
                        AstVariableNode varNode = funcNode.Args[0] as AstVariableNode;
                        string          varName = varNode?.Id ?? throw new ExpressionException($"The \"{funcNode.Id}()\"  first parameter is the variable name.");

                        double varVal = ExecAst(funcNode.Args[1]);
                        Variables[varName] = ValueBase.Create(varVal);
                        return(0);
                    }
                    else if (funcNode.Id == "if")
                    {
                        IAstNode condNode       = funcNode.Args[0];
                        double   condNodeResult = ExecAst(condNode);
                        if (Math.Abs(condNodeResult) <= 1e-5)
                        {
                            return(ExecAst(funcNode.Args[2]));
                        }
                        else
                        {
                            return(ExecAst(funcNode.Args[1]));
                        }
                    }
                    else if (funcNode.Id == "smooth")
                    {
                        /* Todo?
                         * AstVariableNode varNode = funcNode.Args[0] as AstVariableNode;
                         * string varName = varNode?.Id ?? throw new ExpressionException($"The \"{funcNode.Id}()\" first parameter is the variable name.");
                         * double varVal = ExecAst(funcNode.Args[0]);
                         *
                         * return SmoothMath.SmoothVariable(varName, varVal);
                         */
                        throw new ExpressionException($"not support function smooth() yet");
                    }
                    else
                    {
                        if (Functions.TryGetValue(funcNode.Id, out var func))
                        {
                            return(func(funcNode.Args.Select(x => ValueBase.Create(ExecAst(x))).OfType <ValueBase>().ToList()));
                        }
                        else
                        {
                            throw new ExpressionException($"No function found. Fucntion: {funcNode.Id}");
                        }
                    }
                }
                catch (ArgumentOutOfRangeException)
                {
                    throw new ExpressionException($"The function is missing a parameter. Fucntion: {funcNode.Id}");
                }
            }

            return(double.NaN);
        }
Ejemplo n.º 2
0
        public Func <ValueBase> ConvertAstToComplexLambda(IAstNode root, Func <string, ValueBase> variableRequireFunc, Func <string, List <ValueBase>, ValueBase> funcRequireFunc)
        {
            switch (root)
            {
            case AstStringNode stringNode:
                return(() => ValueBase.Create(stringNode.String));

            case AstNumberNode numberNode:
                return(() => ValueBase.Create(numberNode.Number));

            case AstVariableNode varNode:
                if (Constants.TryGetValue(varNode.Id, out var val))
                {
                    return(() => variableRequireFunc(varNode.Id));
                }
                else if (Variables.TryGetValue(varNode.Id, out val))
                {
                    return(() => variableRequireFunc(varNode.Id));
                }
                else
                {
                    return(() => NumberValue.Zero);
                }

            case AstOpNode opNode:
                var leftValue  = ConvertAstToComplexLambda(opNode.LNode, variableRequireFunc, funcRequireFunc);
                var rightValue = ConvertAstToComplexLambda(opNode.RNode, variableRequireFunc, funcRequireFunc);

                ValueBase NumberOpCheck(Func <double, double, double> func)
                {
                    var a = leftValue();

                    if (a.ValueType != ValueBase.Type.Number)
                    {
                        throw new ExpressionException("Invaild Number Operations.");
                    }
                    var b = rightValue();

                    if (b.ValueType != ValueBase.Type.Number)
                    {
                        throw new ExpressionException("Invaild Number Operations.");
                    }

                    return(ValueBase.Create(func(a, b)));
                }

                ValueBase BoolOpCheck(Func <double, double, bool> func)
                {
                    var a = leftValue();

                    if (a.ValueType != ValueBase.Type.Number)
                    {
                        throw new ExpressionException("Invaild Number Operations.");
                    }
                    var b = rightValue();

                    if (b.ValueType != ValueBase.Type.Number)
                    {
                        throw new ExpressionException("Invaild Number Operations.");
                    }

                    return(func(a, b) ? NumberValue.One : NumberValue.Zero);
                }

                ValueBase NumberOpCheck2(Func <double, double> func)
                {
                    var a = leftValue();

                    if (a.ValueType != ValueBase.Type.Number)
                    {
                        throw new ExpressionException("Invaild Number Operations.");
                    }

                    return(ValueBase.Create(func(a)));
                }

                switch (opNode.Op)
                {
                case "+":
                    return(() =>
                    {
                        var a = leftValue();
                        var b = rightValue();

                        if (a.ValueType == ValueBase.Type.String || b.ValueType == ValueBase.Type.String)
                        {
                            return ValueBase.Create(a.ValueToString() + b.ValueToString());
                        }

                        return ValueBase.Create(((NumberValue)a).Value + ((NumberValue)b).Value);
                    });

                case "-":
                    return(() => NumberOpCheck((a, b) => a - b));

                case "*":
                    return(() => NumberOpCheck((a, b) => a * b));

                case "/":
                    return(() => NumberOpCheck((a, b) => a / b));

                case "%":
                    return(() => NumberOpCheck((a, b) => a % b));

                case "^":
                    return(() => NumberOpCheck((a, b) => Math.Pow(a, b)));

                case ">":
                    return(() => BoolOpCheck((a, b) => a > b));

                case "<":
                    return(() => BoolOpCheck((a, b) => a < b));

                case ">=":
                    return(() => BoolOpCheck((a, b) => a >= b));

                case "<=":
                    return(() => BoolOpCheck((a, b) => a <= b));

                case "==":
                    return(() => BoolOpCheck((a, b) => a == b));

                case "!=":
                    return(() => BoolOpCheck((a, b) => a != b));

                case "!":
                    return(() => NumberOpCheck2(a => IsNotZero(a) ? NumberValue.One : NumberValue.Zero));

                case "&&":
                    return(() => BoolOpCheck((a, b) => IsNotZero(a)));

                case "||":
                    return(() => BoolOpCheck((a, b) => IsNotZero(a)));
                }
                break;

            case AstFunctionNode funcNode:
                try
                {
                    if (funcNode.Id == "set")
                    {
                        AstVariableNode varNode = funcNode.Args[0] as AstVariableNode;
                        string          varName = varNode?.Id ?? throw new ExpressionException($"The \"{funcNode.Id}()\"  first parameter is the variable name.");

                        var varVal = ConvertAstToComplexLambda(funcNode.Args[1], variableRequireFunc, funcRequireFunc)();
                        Variables[varName] = varVal;
                        return(() => NumberValue.Zero);
                    }
                    else if (funcNode.Id == "if")
                    {
                        var condExpr    = ConvertAstToComplexLambda(funcNode.Args[0], variableRequireFunc, funcRequireFunc);
                        var falseResult = ConvertAstToComplexLambda(funcNode.Args[2], variableRequireFunc, funcRequireFunc);
                        var trueResult  = ConvertAstToComplexLambda(funcNode.Args[1], variableRequireFunc, funcRequireFunc);

                        return(() => condExpr() <= 1e-5 ? falseResult() : trueResult());
                    }
                    else if (funcNode.Id == "smooth")
                    {
                        /* Todo?
                         * AstVariableNode varNode = funcNode.Args[0] as AstVariableNode;
                         * string varName = varNode?.Id ?? throw new ExpressionException($"The \"{funcNode.Id}()\" first parameter is the variable name.");
                         * double varVal = ExecAst(funcNode.Args[0]);
                         *
                         * return SmoothMath.SmoothVariable(varName, varVal);
                         */
                        throw new ExpressionException($"not support function smooth() yet");
                    }
                    else
                    {
                        return(() => funcRequireFunc(funcNode.Id, funcNode.Args.Select(arg => ConvertAstToComplexLambda(arg, variableRequireFunc, funcRequireFunc)()).ToList()));
                    }
                }
                catch (ArgumentOutOfRangeException)
                {
                    throw new ExpressionException($"The function is missing some parameters. Fucntion: {funcNode.Id}");
                }
            }

            return(() => NumberValue.Nan);
        }