Tokenize a PromQL expression.
(input: &str)
| 47 | |
| 48 | /// Tokenize a PromQL expression. |
| 49 | pub fn tokenize(input: &str) -> Result<Vec<Token>, PromqlError> { |
| 50 | let mut tokens = Vec::new(); |
| 51 | let bytes = input.as_bytes(); |
| 52 | let mut i = 0; |
| 53 | |
| 54 | while i < bytes.len() { |
| 55 | // Skip whitespace. |
| 56 | if bytes[i].is_ascii_whitespace() { |
| 57 | i += 1; |
| 58 | continue; |
| 59 | } |
| 60 | |
| 61 | // Skip line comments. |
| 62 | if bytes[i] == b'#' { |
| 63 | while i < bytes.len() && bytes[i] != b'\n' { |
| 64 | i += 1; |
| 65 | } |
| 66 | continue; |
| 67 | } |
| 68 | |
| 69 | // String literals. |
| 70 | if bytes[i] == b'"' || bytes[i] == b'\'' || bytes[i] == b'`' { |
| 71 | let (tok, end) = lex_string(bytes, i)?; |
| 72 | tokens.push(tok); |
| 73 | i = end; |
| 74 | continue; |
| 75 | } |
| 76 | |
| 77 | // Number or duration. |
| 78 | if bytes[i].is_ascii_digit() |
| 79 | || (bytes[i] == b'.' && i + 1 < bytes.len() && bytes[i + 1].is_ascii_digit()) |
| 80 | { |
| 81 | let (tok, end) = lex_number_or_duration(bytes, i)?; |
| 82 | tokens.push(tok); |
| 83 | i = end; |
| 84 | continue; |
| 85 | } |
| 86 | |
| 87 | // Identifier or keyword. |
| 88 | if bytes[i].is_ascii_alphabetic() || bytes[i] == b'_' || bytes[i] == b':' { |
| 89 | let (tok, end) = lex_ident(bytes, i); |
| 90 | tokens.push(tok); |
| 91 | i = end; |
| 92 | continue; |
| 93 | } |
| 94 | |
| 95 | // Multi-char operators. |
| 96 | if i + 1 < bytes.len() { |
| 97 | match (bytes[i], bytes[i + 1]) { |
| 98 | (b'=', b'=') => { |
| 99 | tokens.push(Token::Eq); |
| 100 | i += 2; |
| 101 | continue; |
| 102 | } |
| 103 | (b'!', b'=') => { |
| 104 | tokens.push(Token::Neq); |
| 105 | i += 2; |
| 106 | continue; |