Ejemplo n.º 1
0
        internal IExpression CompileExpression(string expression, IList <string> variables)
        {
            if (ExtensionMethods.IsNullOrWhiteSpace(expression))
            {
                throw new ExpressiveException("An Expression cannot be empty.");
            }

            var tokens = Tokenise(expression);

            var openCount  = tokens.Select(t => t.CurrentToken).Count(t => string.Equals(t, "(", StringComparison.Ordinal));
            var closeCount = tokens.Select(t => t.CurrentToken).Count(t => string.Equals(t, ")", StringComparison.Ordinal));

            // Bail out early if there isn't a matching set of ( and ) characters.
            if (openCount > closeCount)
            {
                throw new ArgumentException("There aren't enough ')' symbols. Expected " + openCount + " but there is only " + closeCount);
            }
            else if (openCount < closeCount)
            {
                throw new ArgumentException("There are too many ')' symbols. Expected " + openCount + " but there is " + closeCount);
            }

            return(CompileExpression(new Queue <Token>(tokens), OperatorPrecedence.Minimum, variables, false));
        }
Ejemplo n.º 2
0
        private IList <Token> Tokenise(string expression)
        {
            if (ExtensionMethods.IsNullOrWhiteSpace(expression))
            {
                return(null);
            }

            var          expressionLength = expression.Length;
            var          operators        = _registeredOperators.OrderByDescending(op => op.Key.Length);
            var          tokens           = new List <Token>();
            IList <char> unrecognised     = null;

            var index = 0;

            while (index < expressionLength)
            {
                var  lengthProcessed            = 0;
                bool foundUnrecognisedCharacter = false;

                // Functions would tend to have longer tags so check for these first.
                foreach (var kvp in _registeredFunctions.OrderByDescending(f => f.Key.Length))
                {
                    var lookAhead = expression.Substring(index, Math.Min(kvp.Key.Length, expressionLength - index));

                    if (CheckForTag(kvp.Key, lookAhead, _options))
                    {
                        CheckForUnrecognised(unrecognised, tokens, index);
                        lengthProcessed = kvp.Key.Length;
                        tokens.Add(new Token(lookAhead, index));
                        break;
                    }
                }

                if (lengthProcessed == 0)
                {
                    // Loop through and find any matching operators.
                    foreach (var op in operators)
                    {
                        var lookAhead = expression.Substring(index, Math.Min(op.Key.Length, expressionLength - index));

                        if (CheckForTag(op.Key, lookAhead, _options))
                        {
                            CheckForUnrecognised(unrecognised, tokens, index);
                            lengthProcessed = op.Key.Length;
                            tokens.Add(new Token(lookAhead, index));
                            break;
                        }
                    }
                }

                // If an operator wasn't found then process the current character.
                if (lengthProcessed == 0)
                {
                    var character = expression[index];

                    if (character == '[')
                    {
                        char closingCharacter = ']';

                        if (!CanGetString(expression, index, closingCharacter))
                        {
                            throw new MissingTokenException($"Missing closing token '{closingCharacter}'", closingCharacter);
                        }

                        var variable = expression.SubstringUpTo(index, closingCharacter);

                        CheckForUnrecognised(unrecognised, tokens, index);
                        tokens.Add(new Token(variable, index));
                        lengthProcessed = variable.Length;
                    }
                    else if (char.IsDigit(character))
                    {
                        var number = GetNumber(expression, index);

                        CheckForUnrecognised(unrecognised, tokens, index);
                        tokens.Add(new Token(number, index));
                        lengthProcessed = number.Length;
                    }
                    else if (IsQuote(character))
                    {
                        if (!CanGetString(expression, index, character))
                        {
                            throw new MissingTokenException($"Missing closing token '{character}'", character);
                        }

                        var text = GetString(expression, index, character);

                        CheckForUnrecognised(unrecognised, tokens, index);
                        tokens.Add(new Token(text, index));
                        lengthProcessed = text.Length;
                    }
                    else if (character == DateSeparator)
                    {
                        if (!CanGetString(expression, index, character))
                        {
                            throw new MissingTokenException($"Missing closing token '{character}'", character);
                        }

                        // Ignore the first # when checking to allow us to find the second.
                        var dateString = "#" + expression.SubstringUpTo(index + 1, DateSeparator);

                        CheckForUnrecognised(unrecognised, tokens, index);
                        tokens.Add(new Token(dateString, index));
                        lengthProcessed = dateString.Length;
                    }
                    else if (character == ParameterSeparator)
                    {
                        CheckForUnrecognised(unrecognised, tokens, index);
                        tokens.Add(new Token(character.ToString(), index));
                        lengthProcessed = 1;
                    }
                    else if ((character == 't' || character == 'T') && CanExtractValue(expression, expressionLength, index, "true"))
                    {
                        CheckForUnrecognised(unrecognised, tokens, index);
                        var trueString = ExtractValue(expression, expressionLength, index, "true");

                        if (!ExtensionMethods.IsNullOrWhiteSpace(trueString))
                        {
                            tokens.Add(new Token(trueString, index));
                            lengthProcessed = 4;
                        }
                    }
                    else if ((character == 'f' || character == 'F') && CanExtractValue(expression, expressionLength, index, "false"))
                    {
                        CheckForUnrecognised(unrecognised, tokens, index);
                        var falseString = ExtractValue(expression, expressionLength, index, "false");

                        if (!ExtensionMethods.IsNullOrWhiteSpace(falseString))
                        {
                            tokens.Add(new Token(falseString, index));
                            lengthProcessed = 5;
                        }
                    }
                    else if ((character == 'n' || character == 'N') && CanExtractValue(expression, expressionLength, index, "null")) // Check for null
                    {
                        CheckForUnrecognised(unrecognised, tokens, index);
                        var nullString = ExtractValue(expression, expressionLength, index, "null");

                        if (!ExtensionMethods.IsNullOrWhiteSpace(nullString))
                        {
                            tokens.Add(new Token(nullString, index));
                            lengthProcessed = 4;
                        }
                    }
                    else if (!char.IsWhiteSpace(character))
                    {
                        // If we don't recognise this item then we had better keep going until we find something we know about.
                        if (unrecognised == null)
                        {
                            unrecognised = new List <char>();
                        }

                        foundUnrecognisedCharacter = true;
                        unrecognised.Add(character);
                    }
                }

                // Clear down the unrecognised buffer;
                if (!foundUnrecognisedCharacter)
                {
                    CheckForUnrecognised(unrecognised, tokens, index);
                    unrecognised = null;
                }
                index += (lengthProcessed == 0) ? 1 : lengthProcessed;
            }

            // Double check whether the last part is unrecognised.
            CheckForUnrecognised(unrecognised, tokens, index);

            return(tokens);
        }
Ejemplo n.º 3
0
 private static bool CanGetString(string expression, int startIndex, char quoteCharacter)
 {
     return(!ExtensionMethods.IsNullOrWhiteSpace(GetString(expression, startIndex, quoteCharacter)));
 }