/// <summary>
        ///		Obtiene el valor de una variable
        /// </summary>
        private async Task <VariableModel> GetVariableValueAsync(string name, ExpressionsCollection expressions, CancellationToken cancellationToken)
        {
            VariableModel variable = new VariableModel(name, VariableModel.VariableType.Unknown);

            // Asigna el valor
            if (expressions.Count > 0)
            {
                variable.Value = await ExecuteExpressionAsync(expressions, cancellationToken);
            }
            // Devuelve la variable
            return(variable);
        }
        /// <summary>
        ///		Lee las expresiones
        /// </summary>
        private ExpressionsCollection ReadExpression(ExpressionReaderMode mode, out string error)
        {
            ExpressionsCollection expressions = new ExpressionsCollection();
            Token nextToken = GetToken(true);

            // Inicializa los valores de salida
            error = "";
            // Lee las expresiones
            while (!IsEof(nextToken) && nextToken.IsExpressionPart && string.IsNullOrWhiteSpace(error))
            {
                // Añade el token a la colección de expresiones
                if (nextToken.Type == Token.TokenType.Variable)
                {
                    expressions.Add(ReadVariableIdentifier(GetToken(), out error));
                }
                else
                {
                    expressions.Add(new ExpressionBase(GetToken()));
                }
                // Obtiene el siguiente token
                nextToken = GetToken(true);
            }
            // Comprueba si ha habido algún error
            switch (mode)
            {
            case ExpressionReaderMode.Normal:
                if (nextToken.Type != Token.TokenType.EndSentenceBlock &&
                    nextToken.Type != Token.TokenType.RightLlave && nextToken.Type != Token.TokenType.Sentence)
                {
                    error = "Falta el final de sentencia en la expresión";
                }
                break;

            case ExpressionReaderMode.AtVariable:
                if (nextToken.Type != Token.TokenType.RightCorchete)
                {
                    error = "Falta el corchete final en la definición de variable";
                }
                break;

            case ExpressionReaderMode.AtAttributes:
                if (nextToken.Type != Token.TokenType.RightLlave && nextToken.Type != Token.TokenType.Literal)
                {
                    error = "Falta el final de sentencia en la definición de atributos";
                }
                break;
            }
            // Devuelve la colección de expresiones
            return(expressions);
        }
        /// <summary>
        ///		Ejecuta una expresión
        /// </summary>
        protected async Task <VariableModel> ExecuteExpressionAsync(ExpressionsCollection expressions, CancellationToken cancellationToken)
        {
            (string error, VariableModel result) = await ExpressionEvaluator.EvaluateAsync(Context.Actual, expressions, cancellationToken);

            // Añade el error si es necesario
            if (!string.IsNullOrWhiteSpace(error))
            {
                // Añade el error
                AddError(error);
                // El resultado no es válido
                result = null;
            }
            // Devuelve el resultado
            return(result);
        }
        /// <summary>
        ///		Transforma las expresiones
        /// </summary>
        private string TransformExpressions(ExpressionsCollection expressions)
        {
            string result = string.Empty;

            // Añade las expresiones
            foreach (ExpressionBase expressionBase in expressions)
            {
                switch (expressionBase)
                {
                case ExpressionConstant expression:
                    result += TransformExpressionConstant(expression);
                    break;

                case ExpressionFunction expression:
                    result += TransformExpressionFunction(expression);
                    break;

                case ExpressionParenthesis expression:
                    result += TransformExpressionParenthesis(expression);
                    break;

                case ExpressionOperatorLogical expression:
                    result += TransformExpressionOperatorLogical(expression);
                    break;

                case ExpressionOperatorMath expression:
                    result += TransformExpressionOperatorMath(expression);
                    break;

                case ExpressionOperatorRelational expression:
                    result += TransformExpressionOperatorRelational(expression);
                    break;

                case ExpressionVariableIdentifier expression:
                    result += TransformExpressionVariable(expression);
                    break;
                }
            }
            // Devuelve el resultado
            return(result);
        }
Exemple #5
0
        /// <summary>
        ///		Calcula una expresión
        /// </summary>
        private VariableModel Compute(ContextModel context, ExpressionsCollection stackExpressions, out string error)
        {
            Stack <VariableModel> stackOperators = new Stack <VariableModel>();

            // Inicializa los argumentos de salida
            error = string.Empty;
            // Calcula el resultado
            foreach (ExpressionBase expressionBase in stackExpressions)
            {
                if (string.IsNullOrWhiteSpace(error))
                {
                    switch (expressionBase)
                    {
                    case ExpressionConstant expression:
                        stackOperators.Push(new VariableModel("Constant", expression.Value));
                        break;

                    case ExpressionVariableIdentifier expression:
                        VariableModel variable = Search(context, expression, out error);

                        // Comprueba que se haya encontrado la variable
                        if (variable == null)
                        {
                            error = "Cant find the variable value";
                        }
                        // Si no hay ningún error, se añade la variable a la pila
                        if (string.IsNullOrWhiteSpace(error))
                        {
                            stackOperators.Push(variable);
                        }
                        break;

                    case ExpressionOperatorBase expression:
                        if (stackOperators.Count < 2)
                        {
                            error = "Ther is not enough operators in stack for execute this operation";
                        }
                        else
                        {
                            VariableModel second = stackOperators.Pop();                                                     //? cuidado al sacar de la pila, están al revés
                            VariableModel first  = stackOperators.Pop();
                            VariableModel result = ComputeBinary(expression, first, second, out error);

                            // Si no ha habido ningún error, se añade a la pila
                            if (string.IsNullOrEmpty(error))
                            {
                                stackOperators.Push(result);
                            }
                        }
                        break;
                    }
                }
            }
            // Obtiene el resultado
            if (string.IsNullOrWhiteSpace(error) && stackOperators.Count == 1)
            {
                return(stackOperators.Pop());
            }
            else if (stackOperators.Count == 0)
            {
                error = "There is no operators in the operations stack";
                return(null);
            }
            else
            {
                error = "There are too much operator in the operations stack";
                return(null);
            }
        }
Exemple #6
0
 /// <summary>
 ///		Evalúa una serie de expresiones pasadas a notación polaca
 /// </summary>
 public VariableModel EvaluateRpn(ContextModel context, ExpressionsCollection expressionsRpn, out string error)
 {
     return(Compute(context, expressionsRpn.Clone(), out error));
 }
Exemple #7
0
 /// <summary>
 ///		Evalúa una serie de expresiones
 /// </summary>
 public VariableModel Evaluate(ContextModel context, ExpressionsCollection expressions, out string error)
 {
     return(Compute(context, new ExpressionConversorRpn().ConvertToRPN(expressions), out error));
 }
Exemple #8
0
        /// <summary>
        ///		Interpreta una expresión hasta encontrar un token de cierre
        /// </summary>
        private ExpressionsCollection ParseExpression(Token.TokenType[] tokensTypeEnd, out string error)
        {
            ExpressionsCollection expressions = new ExpressionsCollection();
            int  parenthesisOpen = 0;
            bool isEnd           = false;

            // Inicializa los argumentos de salida
            error = string.Empty;
            // Interpreta las expresiones
            while (!isEnd && string.IsNullOrEmpty(error))
            {
                // Añade el token actual a la colección de expresiones
                switch (ActualToken.Type)
                {
                case Token.TokenType.ArithmeticOperator:
                    expressions.Add(GetExpressionMath(ActualToken.Value));
                    break;

                case Token.TokenType.LeftParentesis:
                case Token.TokenType.RightParentesis:
                    // Añade la expresión del paréntesis
                    expressions.Add(new ExpressionParenthesis(ActualToken.Type == Token.TokenType.LeftParentesis));
                    // Añade o quita el paréntesis del contador
                    if (ActualToken.Type == Token.TokenType.LeftParentesis)
                    {
                        parenthesisOpen++;
                    }
                    else if (ActualToken.Type == Token.TokenType.RightParentesis)
                    {
                        parenthesisOpen--;
                    }
                    break;

                case Token.TokenType.LogicalOperator:
                    expressions.Add(GetExpressionLogical(ActualToken.Value));
                    break;

                case Token.TokenType.RelationalOperator:
                    expressions.Add(GetExpressionRelation(ActualToken.Value));
                    break;

                case Token.TokenType.Number:
                    expressions.Add(new ExpressionConstant(Context.Variables.VariableModel.VariableType.Numeric,
                                                           ActualToken.Value.GetDouble(0)));
                    break;

                case Token.TokenType.String:
                    expressions.Add(new ExpressionConstant(Context.Variables.VariableModel.VariableType.String,
                                                           ActualToken.Value));
                    break;

                case Token.TokenType.UserDefined:
                    switch ((TokenSubType)(ActualToken.SubType ?? 2000))
                    {
                    case TokenSubType.Date:
                        expressions.Add(new ExpressionConstant(Context.Variables.VariableModel.VariableType.Date,
                                                               ActualToken.Value.GetDateTime()));
                        break;

                    case TokenSubType.Variable:
                        expressions.Add(new ExpressionVariableIdentifier(ActualToken.Value));
                        break;

                    default:
                        expressions.Add(new ExpressionError("Unknown token"));
                        break;
                    }
                    break;

                case Token.TokenType.Variable:
                    expressions.Add(new ExpressionVariableIdentifier(ActualToken.Value));
                    break;

                default:
                    expressions.Add(new ExpressionError("Unknown expression"));
                    break;
                }
                // Si la última expresión es un error, se detiene
                if (expressions.Count > 0 && expressions[0] is ExpressionError expression)
                {
                    error = expression.Message;
                }
                else
                {
                    // Pasa al siguiente token
                    NextToken();
                    // Comprueba si es el final de la expresión
                    isEnd = IsEndExpression(tokensTypeEnd, parenthesisOpen);
                }
            }
            // Devuelve la colección de expresiones
            return(expressions);
        }
 public DynamicExpression()
 {
     Values = new ExpressionsCollection(Reserved);
 }
        /// <summary>
        ///		Convierte una colección de expresiones en una pila de expresiones en notación polaca inversa (sin paréntesis)
        /// </summary>
        internal ExpressionsCollection ConvertToRPN(ExpressionsCollection expressions)
        {
            ExpressionsCollection  stackOutput     = new ExpressionsCollection();
            Stack <ExpressionBase> stackoperations = new Stack <ExpressionBase>();

            // Convierte las expresiones en una pila
            foreach (ExpressionBase expression in expressions)
            {
                if (expression is ExpressionBase)
                {
                    switch (expression.Token.Type)
                    {
                    case Tokens.Token.TokenType.LeftParentesis:
                        // Paréntesis izquierdo, se mete directamente en la pila de operadores
                        stackoperations.Push(expression);
                        break;

                    case Tokens.Token.TokenType.RightParentesis:
                        bool end = false;

                        // Paréntesis derecho. Saca todos los elementos del stack hasta encontrar un paréntesis izquierdo
                        while (stackoperations.Count > 0 && !end)
                        {
                            ExpressionBase expressionoperation = stackoperations.Pop();

                            if (expressionoperation.Token.Type == Tokens.Token.TokenType.LeftParentesis)
                            {
                                end = true;
                            }
                            else
                            {
                                stackOutput.Add(expressionoperation);
                            }
                        }
                        break;

                    case Tokens.Token.TokenType.Arithmeticoperation:
                    case Tokens.Token.TokenType.Logicaloperation:
                    case Tokens.Token.TokenType.Relationaloperation:
                        bool endoperation = false;

                        // Recorre los operadores de la pila
                        while (stackoperations.Count > 0 && !endoperation)
                        {
                            ExpressionBase objLastoperation = null;

                            // Obtiene el último operador de la pila (sin sacarlo)
                            objLastoperation = stackoperations.Peek();
                            // Si no hay ningún operador en la pila o la prioridad del operador actual es mayor que la del último de la pila se mete el último operador
                            if (objLastoperation == null || expression.Token.Type == Tokens.Token.TokenType.LeftParentesis ||
                                expression.Priority > objLastoperation.Priority)
                            {
                                endoperation = true;
                            }
                            else                                                             // ... si el operador tiene una prioridad menor que el último de la fila, se quita el último operador de la pila y se compara de nuevo
                            {
                                stackOutput.Add(stackoperations.Pop());
                            }
                        }
                        // Añade el operador a la pila de operadores
                        stackoperations.Push(expression);
                        break;

                    case Tokens.Token.TokenType.Number:
                    case Tokens.Token.TokenType.String:
                    case Tokens.Token.TokenType.Variable:
                        // Si es un número o una cadena o una variable se copia directamente en la pila de salida
                        stackOutput.Add(expression);
                        break;

                    default:
                        stackOutput.Add(new ExpressionBase(new Tokens.Token {
                            Type = Tokens.Token.TokenType.Error, Content = "Expresión desconocida"
                        }));
                        break;
                    }
                }
            }
            // Añade todos los elementos que queden en el stack de operadores al stack de salida
            while (stackoperations.Count > 0)
            {
                stackOutput.Add(stackoperations.Pop());
            }
            // Devuelve la pila convertida a notación polaca inversa
            return(stackOutput);
        }
        ///// <summary>
        /////		Evalúa una serie de expresiones pasadas a notación polaca (RPN)
        ///// </summary>
        //internal VariableModel EvaluateRpn(ContextModel context, ExpressionsCollection expressionsRpn, out string error)
        //{
        //	return Compute(context, expressionsRpn.Clone(), out error);
        //}

        /// <summary>
        ///		Calcula una expresión
        /// </summary>
        private async Task <(string error, VariableModel variable)> ComputeAsync(ContextModel context, ExpressionsCollection stackExpressions,
                                                                                 CancellationToken cancellationToken)
        {
            string error = string.Empty;
            Stack <VariableModel> stackOperators = new Stack <VariableModel>();

            // Calcula el resultado
            foreach (ExpressionBase expressionBase in stackExpressions)
            {
                if (string.IsNullOrWhiteSpace(error))
                {
                    switch (expressionBase)
                    {
                    case ExpressionConstant expression:
                        stackOperators.Push(new VariableModel("Constant", expression.Value));
                        break;

                    case ExpressionVariableIdentifier expression:
                        (string errorSearch, VariableModel variable) = await SearchAsync(context, expression, cancellationToken);

                        // Comprueba que se haya encontrado la variable
                        if (!string.IsNullOrWhiteSpace(errorSearch))
                        {
                            error = errorSearch;
                        }
                        else if (variable == null)
                        {
                            error = "Cant find the variable value";
                        }
                        // Si no hay ningún error, se añade la variable a la pila
                        if (string.IsNullOrWhiteSpace(error))
                        {
                            stackOperators.Push(variable);
                        }
                        break;

                    case ExpressionFunction expression:
                        VariableModel resultFunction = await Processor.ExecuteFunctionAsync(expression, cancellationToken);

                        // Si se ha podido ejecutar la función, la añade a la pila
                        if (resultFunction == null)
                        {
                            error = $"Cant execute function {expression.Function}";
                        }
                        else
                        {
                            stackOperators.Push(resultFunction);
                        }
                        break;

                    case ExpressionOperatorBase expression:
                        if (stackOperators.Count < 2)
                        {
                            error = "There is not enough operators in stack for execute this operation";
                        }
                        else
                        {
                            VariableModel second = stackOperators.Pop();                                                     //? cuidado al sacar de la pila, están al revés
                            VariableModel first  = stackOperators.Pop();
                            VariableModel result = ComputeBinary(expression, first, second, out error);

                            // Si no ha habido ningún error, se añade a la pila
                            if (string.IsNullOrEmpty(error))
                            {
                                stackOperators.Push(result);
                            }
                        }
                        break;
                    }
                }
            }
            // Obtiene el resultado
            if (!string.IsNullOrWhiteSpace(error))
            {
                return(error, null);
            }
            else if (string.IsNullOrWhiteSpace(error) && stackOperators.Count == 1)
            {
                return(error, stackOperators.Pop());
            }
            else if (stackOperators.Count == 0)
            {
                return("There is no operators in the operations stack", null);
            }
            else
            {
                return("There are too much operator in the operations stack", null);
            }
        }
 /// <summary>
 ///		Evalúa una serie de expresiones
 /// </summary>
 internal async Task <(string error, VariableModel variable)> EvaluateAsync(ContextModel context, ExpressionsCollection expressions, CancellationToken cancellationToken)
 {
     return(await ComputeAsync(context, new ExpressionConversorRpn().ConvertToRPN(expressions), cancellationToken));
 }
        /// <summary>
        ///		Convierte una colección de expresiones en una pila de expresiones en notación polaca inversa (sin paréntesis)
        /// </summary>
        internal ExpressionsCollection ConvertToRPN(ExpressionsCollection expressions)
        {
            ExpressionsCollection  stackOutput    = new ExpressionsCollection();
            Stack <ExpressionBase> stackOperators = new Stack <ExpressionBase>();

            // Convierte las expresiones en una pila
            foreach (ExpressionBase expressionBase in expressions)
            {
                switch (expressionBase)
                {
                case ExpressionParenthesis expression:
                    // El paréntesis izquierdo, se mete directamente en la pila de operadores
                    if (expression.Open)
                    {
                        stackOperators.Push(expression);
                    }
                    else
                    {
                        bool end = false;

                        // Paréntesis derecho. Saca todos los elementos del stack hasta encontrar un paréntesis izquierdo
                        while (stackOperators.Count > 0 && !end)
                        {
                            ExpressionBase expressionOperator = stackOperators.Pop();

                            if (expressionOperator is ExpressionParenthesis expressionStack)
                            {
                                if (!expressionStack.Open)
                                {
                                    end = true;
                                }
                                else
                                {
                                    stackOutput.Add(expressionStack);
                                }
                            }
                            else
                            {
                                stackOutput.Add(expressionOperator);
                            }
                        }
                    }
                    break;

                case ExpressionOperatorBase expression:
                    bool endOperator = false;

                    // Recorre los operadores de la pila
                    while (stackOperators.Count > 0 && !endOperator)
                    {
                        ExpressionBase lastOperator = stackOperators.Peek();

                        // Si no hay ningún operador en la pila o la prioridad del operador actual
                        // es mayor que la del último de la pila, se mete el último operador
                        if (EndSearchOperator(expression, lastOperator))
                        {
                            endOperator = true;
                        }
                        else                                                                 // ... si el operador tiene una prioridad menor que el último de la pila, se quita el último operador de la pila y se compara de nuevo
                        {
                            stackOutput.Add(stackOperators.Pop());
                        }
                    }
                    // Añade el operador a la pila de operadores
                    stackOperators.Push(expression);
                    break;

                case ExpressionConstant expression:
                    stackOutput.Add(expression);
                    break;

                case ExpressionVariableIdentifier expression:
                    stackOutput.Add(expression);
                    break;

                default:
                    stackOutput.Add(new ExpressionError("Unknown expression"));
                    break;
                }
            }
            // Añade todos los elementos que queden en el stack de operadores al stack de salida
            while (stackOperators.Count > 0)
            {
                stackOutput.Add(stackOperators.Pop());
            }
            // Devuelve la pila convertida a notación polaca inversa
            return(stackOutput);
        }
        /// <summary>
        ///		Calcula una expresión
        /// </summary>
        private ValueBase Compute(ExpressionsCollection stackExpressions)
        {
            Stack <ValueBase> stackoperations = new Stack <ValueBase>();
            bool hasError = false;

            // Calcula el resultado
            foreach (ExpressionBase expression in stackExpressions)
            {
                if (!hasError)
                {
                    if (expression.Token.Type == Tokens.Token.TokenType.String || expression.Token.Type == Tokens.Token.TokenType.Number)
                    {
                        stackoperations.Push(ValueBase.GetInstance(expression.Token.Content));
                    }
                    else if (expression is ExpressionVariableIdentifier)
                    {
                        ValueBase variableValue = GetValueVariable(expression as ExpressionVariableIdentifier);

                        // Añade el resultado a la pila (aunque haya un error, para que así este sea el último operando en la pila)
                        if (variableValue != null)
                        {
                            hasError = variableValue.HasError;
                            stackoperations.Push(variableValue);
                        }
                        else
                        {
                            hasError = true;
                            stackoperations.Push(ValueBase.GetError("No se encuentra el valor de la variable"));
                        }
                    }
                    else
                    {
                        ValueBase result = null;

                        // Realiza la operación
                        switch (expression.Token.Content)
                        {
                        case "+":
                        case "-":
                        case "*":
                        case "/":
                        case ">=":
                        case "<=":
                        case "==":
                        case "!=":
                        case ">":
                        case "<":
                        case "||":
                        case "&&":
                            result = ComputeBinary(stackoperations, expression.Token.Content);
                            break;

                        default:
                            result = ValueBase.GetError($"Operador desconocido: {expression.Token.Content}");
                            break;
                        }
                        // Añade el resultado a la pila (aunque haya error, para que así sea el último operador de la pila)
                        hasError = result.HasError;
                        stackoperations.Push(result);
                    }
                }
            }
            // Obtiene el resultado
            if (hasError || stackoperations.Count == 1)
            {
                return(stackoperations.Pop());
            }
            else if (stackoperations.Count == 0)
            {
                return(ValueBase.GetError("No hay ningún operador en la pila de operaciones"));
            }
            else
            {
                return(ValueBase.GetError("Hay más de un operador en la pila de instrucciones"));
            }
        }
 /// <summary>
 ///		Evalúa una serie de expresiones
 /// </summary>
 internal ValueBase Evaluate(ExpressionsCollection stackExpressions)
 {
     return(Compute(stackExpressions.Clone()));
 }