tokenize breaks the expression string into tokens
(expression string)
| 84 | |
| 85 | // tokenize breaks the expression string into tokens |
| 86 | func (p *ExpressionParser) tokenize(expression string) ([]token, error) { |
| 87 | expressionsLog.Printf("Tokenizing expression of length %d", len(expression)) |
| 88 | var tokens []token |
| 89 | i := 0 |
| 90 | |
| 91 | for i < len(expression) { |
| 92 | // Skip whitespace |
| 93 | if unicode.IsSpace(rune(expression[i])) { |
| 94 | i++ |
| 95 | continue |
| 96 | } |
| 97 | |
| 98 | switch { |
| 99 | case i+1 < len(expression) && expression[i:i+2] == "&&": |
| 100 | tokens = append(tokens, token{tokenAnd, "&&", i}) |
| 101 | i += 2 |
| 102 | case i+1 < len(expression) && expression[i:i+2] == "||": |
| 103 | tokens = append(tokens, token{tokenOr, "||", i}) |
| 104 | i += 2 |
| 105 | case expression[i] == '!' && (i+1 >= len(expression) || expression[i+1] != '='): |
| 106 | // Only treat ! as NOT if not followed by = (to avoid conflicting with !=) |
| 107 | tokens = append(tokens, token{tokenNot, "!", i}) |
| 108 | i++ |
| 109 | case expression[i] == '(': |
| 110 | tokens = append(tokens, token{tokenLeftParen, "(", i}) |
| 111 | i++ |
| 112 | case expression[i] == ')': |
| 113 | tokens = append(tokens, token{tokenRightParen, ")", i}) |
| 114 | i++ |
| 115 | default: |
| 116 | // Parse literal expression - everything until we hit a logical operator or paren |
| 117 | start := i |
| 118 | parenCount := 0 |
| 119 | |
| 120 | for i < len(expression) { |
| 121 | ch := expression[i] |
| 122 | |
| 123 | // Handle quoted strings - skip everything inside quotes |
| 124 | // Support single quotes ('), double quotes ("), and backticks (`) |
| 125 | if ch == '\'' || ch == '"' || ch == '`' { |
| 126 | quote := ch |
| 127 | i++ // skip opening quote |
| 128 | for i < len(expression) { |
| 129 | if expression[i] == quote { |
| 130 | i++ // skip closing quote |
| 131 | break |
| 132 | } |
| 133 | if expression[i] == '\\' && i+1 < len(expression) { |
| 134 | i += 2 // skip escaped character |
| 135 | } else { |
| 136 | i++ |
| 137 | } |
| 138 | } |
| 139 | continue |
| 140 | } |
| 141 | |
| 142 | // Track parentheses that are part of the expression (e.g., function calls) |
| 143 | if ch == '(' { |
no test coverage detected