use nom::{
branch::alt,
bytes::complete::{tag, take_while, take_while1},
character::complete::{alpha1, alphanumeric1, char, digit1},
combinator::{map, opt, peek, recognize},
multi::many0,
sequence::{pair, tuple},
IResult,
};
#[derive(Debug, Clone, PartialEq)]
pub enum Token {
Match,
Where,
Return,
Select,
From,
With,
Create,
Insert,
Delete,
Set,
Remove,
Merge,
Unwind,
Call,
Load,
Store,
Distinct,
Order,
By,
Asc,
Ascending,
Desc,
Descending,
Nulls,
First,
Last,
Limit,
Group,
Having,
All,
Any,
Some,
Offset,
Skip,
On,
Detach,
NoDetach,
Yield,
As,
And,
Or,
Not,
Xor,
In,
Union,
Intersect,
Except,
Contains,
Starts,
Ends,
Exists,
Like,
Matches, Case,
Cast,
When,
Then,
Else,
End,
Within, Leading, Trailing, Both, Schema,
Data,
Graph,
Home,
If,
Drop,
Register,
Unregister,
Truncate,
Clear,
Cascade,
Restrict,
Type,
File,
Url,
Inline,
Validate,
Against,
Show,
Describe,
Alter,
Version,
Description,
Copy,
Of,
Replace, Property,
Vertex,
Node,
Edge,
Types,
Source,
Destination,
Is,
Session,
Reset,
Close,
Value,
Binding,
Table,
Parameters,
Characteristics,
Time,
Zone,
Current,
Parameter,
User,
Role,
Password,
Roles,
Grant,
Revoke,
To,
Unknown,
Normalized,
Directed,
Typed,
Let, For, Filter,
Declare, Next, At, Procedure,
Start, Commit, Rollback, Work, Begin, Isolation, Level, Read, Uncommitted, Committed, Repeatable, Serializable, Only, Write,
Walk,
Trail,
Simple,
Path,
Acyclic,
BooleanType,
StringType,
IntegerType,
FloatType,
RealType,
DoubleType,
BigIntType,
SmallIntType,
DecimalType,
Plus, Minus, Star, Slash, Percent, Caret, Equal, NotEqual, LessThan, LessEqual, GreaterThan, GreaterEqual, Regex, FuzzyEqual, Concat,
LeftParen, RightParen, LeftBracket, RightBracket, LeftBrace, RightBrace, Comma, Semicolon, Colon, Dot, Arrow, ArrowLeft, ArrowBoth, Dash, AtSign, Dollar, Ampersand, Pipe, Question,
String(String),
BacktickString(String), Integer(i64),
Float(f64),
Boolean(bool),
Null,
Vector(Vec<f64>),
Identifier(String),
Variable(String),
PropertyAccess(String),
Whitespace,
Comment(String),
EOF,
}
#[derive(Debug, Clone)]
pub struct Lexer {
input: String,
_position: usize,
tokens: Vec<Token>,
}
impl Lexer {
pub fn new(input: String) -> Self {
Self {
input,
_position: 0,
tokens: Vec::new(),
}
}
pub fn tokenize(&mut self) -> Result<Vec<Token>, String> {
let mut remaining = self.input.as_str();
let mut tokens = Vec::new();
let mut iteration = 0;
while !remaining.is_empty() {
iteration += 1;
if iteration > 1000 {
return Err("Infinite loop detected in lexer".to_string());
}
match token(remaining) {
Ok((next_remaining, token)) => {
if next_remaining == remaining {
return Err(format!(
"Parser function not consuming input. Token: {:?}, Remaining: '{}'",
token, remaining
));
}
if !matches!(token, Token::Whitespace | Token::Comment(_)) {
tokens.push(token);
}
remaining = next_remaining;
}
Err(e) => {
return Err(format!("Lexer error: {:?}", e));
}
}
}
tokens.push(Token::EOF);
self.tokens = tokens.clone();
Ok(tokens)
}
}
fn token(input: &str) -> IResult<&str, Token> {
alt((
whitespace,
map(comment, |s| Token::Comment(s.to_string())),
map(variable, |s| Token::Variable(s.to_string())),
map(vector_literal, |v| Token::Vector(v)),
map(float_literal, |f| Token::Float(f)),
map(integer_literal, |n| Token::Integer(n)),
map(backtick_identifier, |s| {
Token::BacktickString(s.to_string())
}), map(string_literal, |s| Token::String(s.to_string())),
map(property_access, |s| Token::PropertyAccess(s.to_string())),
simple_patterns,
map(identifier, |s| Token::Identifier(s.to_string())),
))(input)
}
fn is_word_boundary(c: char) -> bool {
!c.is_alphanumeric() && c != '_'
}
fn is_keyword_match(input: &str, keyword: &str) -> bool {
if input.len() < keyword.len() {
return false;
}
if !input[..keyword.len()].eq_ignore_ascii_case(keyword) {
return false;
}
if input.len() > keyword.len() {
let next_char = input.chars().nth(keyword.len()).unwrap_or(' ');
is_word_boundary(next_char)
} else {
true }
}
fn simple_patterns(input: &str) -> IResult<&str, Token> {
if input.starts_with("||") {
Ok((&input[2..], Token::Concat))
} else if input.starts_with("!=") {
Ok((&input[2..], Token::NotEqual))
} else if input.starts_with("<>") {
Ok((&input[2..], Token::NotEqual))
} else if input.starts_with("<=") {
Ok((&input[2..], Token::LessEqual))
} else if input.starts_with(">=") {
Ok((&input[2..], Token::GreaterEqual))
} else if input.starts_with("=~") {
Ok((&input[2..], Token::Regex))
} else if input.starts_with("~=") {
Ok((&input[2..], Token::FuzzyEqual))
} else if input.starts_with("<->") {
Ok((&input[3..], Token::ArrowBoth))
} else if input.starts_with("->") {
Ok((&input[2..], Token::Arrow))
} else if input.starts_with("<-") {
Ok((&input[2..], Token::ArrowLeft))
}
else if input.len() >= 11
&& input[..11].eq_ignore_ascii_case("DESTINATION")
&& (input.len() == 11
|| (!input.chars().nth(11).unwrap().is_alphanumeric()
&& input.chars().nth(11).unwrap() != '_'))
{
Ok((&input[11..], Token::Destination))
} else if input.len() >= 10
&& input[..10].eq_ignore_ascii_case("NORMALIZED")
&& (input.len() == 10
|| (!input.chars().nth(10).unwrap().is_alphanumeric()
&& input.chars().nth(10).unwrap() != '_'))
{
Ok((&input[10..], Token::Normalized))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("DIRECTED")
&& (input.len() == 8
|| (!input.chars().nth(8).unwrap().is_alphanumeric()
&& input.chars().nth(8).unwrap() != '_'))
{
Ok((&input[8..], Token::Directed))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("PROPERTY")
&& (input.len() == 8
|| (!input.chars().nth(8).unwrap().is_alphanumeric()
&& input.chars().nth(8).unwrap() != '_'))
{
Ok((&input[8..], Token::Property))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("DISTINCT")
&& (input.len() == 8
|| (!input.chars().nth(8).unwrap().is_alphanumeric()
&& input.chars().nth(8).unwrap() != '_'))
{
Ok((&input[8..], Token::Distinct))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("CONTAINS")
&& (input.len() == 8
|| (!input.chars().nth(8).unwrap().is_alphanumeric()
&& input.chars().nth(8).unwrap() != '_'))
{
Ok((&input[8..], Token::Contains))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("WITHIN")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Within))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("REPLACE")
&& (input.len() == 7
|| (input.chars().nth(7).unwrap_or(' ') != '('
&& !input.chars().nth(7).unwrap_or(' ').is_alphanumeric()))
{
Ok((&input[7..], Token::Replace))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("BOOLEAN")
&& (input.len() == 7
|| (!input.chars().nth(7).unwrap().is_alphanumeric()
&& input.chars().nth(7).unwrap() != '_'))
{
Ok((&input[7..], Token::BooleanType))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("INTEGER")
&& (input.len() == 7
|| (!input.chars().nth(7).unwrap().is_alphanumeric()
&& input.chars().nth(7).unwrap() != '_'))
{
Ok((&input[7..], Token::IntegerType))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("SMALLINT")
&& (input.len() == 8
|| (!input.chars().nth(8).unwrap().is_alphanumeric()
&& input.chars().nth(8).unwrap() != '_'))
{
Ok((&input[8..], Token::SmallIntType))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("BIGINT")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::BigIntType))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("DECIMAL")
&& (input.len() == 7
|| (!input.chars().nth(7).unwrap().is_alphanumeric()
&& input.chars().nth(7).unwrap() != '_'))
{
Ok((&input[7..], Token::DecimalType))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("DOUBLE")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::DoubleType))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("FLOAT")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::FloatType))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("REAL")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::RealType))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("CASCADE")
&& (input.len() == 7
|| (!input.chars().nth(7).unwrap().is_alphanumeric()
&& input.chars().nth(7).unwrap() != '_'))
{
Ok((&input[7..], Token::Cascade))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("UNKNOWN")
&& (input.len() == 7
|| (!input.chars().nth(7).unwrap().is_alphanumeric()
&& input.chars().nth(7).unwrap() != '_'))
{
Ok((&input[7..], Token::Unknown))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("RESTRICT")
&& (input.len() == 8
|| (!input.chars().nth(8).unwrap().is_alphanumeric()
&& input.chars().nth(8).unwrap() != '_'))
{
Ok((&input[8..], Token::Restrict))
} else if input.len() >= 14
&& input[..14].eq_ignore_ascii_case("CHARACTERISTICS")
&& (input.len() == 14
|| (!input.chars().nth(14).unwrap().is_alphanumeric()
&& input.chars().nth(14).unwrap() != '_'))
{
Ok((&input[14..], Token::Characteristics))
} else if input.len() >= 10
&& input[..10].eq_ignore_ascii_case("PARAMETERS")
&& (input.len() == 10
|| (!input.chars().nth(10).unwrap().is_alphanumeric()
&& input.chars().nth(10).unwrap() != '_'))
{
Ok((&input[10..], Token::Parameters))
} else if input.len() >= 9
&& input[..9].eq_ignore_ascii_case("PARAMETER")
&& (input.len() == 9
|| (!input.chars().nth(9).unwrap().is_alphanumeric()
&& input.chars().nth(9).unwrap() != '_'))
{
Ok((&input[9..], Token::Parameter))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("SESSION")
&& (input.len() == 7
|| (!input.chars().nth(7).unwrap().is_alphanumeric()
&& input.chars().nth(7).unwrap() != '_'))
{
Ok((&input[7..], Token::Session))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("BINDING")
&& (input.len() == 7
|| (!input.chars().nth(7).unwrap().is_alphanumeric()
&& input.chars().nth(7).unwrap() != '_'))
{
Ok((&input[7..], Token::Binding))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("CURRENT")
&& (input.len() == 7
|| !input.chars().nth(7).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(7).unwrap_or(' ') != '_')
{
Ok((&input[7..], Token::Current))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("PASSWORD")
&& (input.len() == 8
|| (!input.chars().nth(8).unwrap().is_alphanumeric()
&& input.chars().nth(8).unwrap() != '_'))
{
Ok((&input[8..], Token::Password))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("STRING")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::StringType))
} else if input.len() >= 11
&& input[..11].eq_ignore_ascii_case("DESCRIPTION")
&& (input.len() == 11
|| !input.chars().nth(11).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(11).unwrap_or(' ') != '_')
{
Ok((&input[11..], Token::Description))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("DESCRIBE")
&& (input.len() == 8
|| !input.chars().nth(8).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(8).unwrap_or(' ') != '_')
{
Ok((&input[8..], Token::Describe))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("VALIDATE")
&& (input.len() == 8
|| !input.chars().nth(8).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(8).unwrap_or(' ') != '_')
{
Ok((&input[8..], Token::Validate))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("VERSION")
&& (input.len() == 7
|| !input.chars().nth(7).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(7).unwrap_or(' ') != '_')
{
Ok((&input[7..], Token::Version))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("AGAINST")
&& (input.len() == 7
|| !input.chars().nth(7).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(7).unwrap_or(' ') != '_')
{
Ok((&input[7..], Token::Against))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("SCHEMA")
&& (input.len() == 6
|| !input.chars().nth(6).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(6).unwrap_or(' ') != '_')
{
Ok((&input[6..], Token::Schema))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("INLINE")
&& (input.len() == 6
|| !input.chars().nth(6).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(6).unwrap_or(' ') != '_')
{
Ok((&input[6..], Token::Inline))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("ALTER")
&& (input.len() == 5
|| !input.chars().nth(5).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(5).unwrap_or(' ') != '_')
{
Ok((&input[5..], Token::Alter))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("SHOW")
&& (input.len() == 4
|| !input.chars().nth(4).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(4).unwrap_or(' ') != '_')
{
Ok((&input[4..], Token::Show))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("DATA")
&& (input.len() == 4
|| !input.chars().nth(4).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(4).unwrap_or(' ') != '_')
{
Ok((&input[4..], Token::Data))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("FILE")
&& (input.len() == 4
|| !input.chars().nth(4).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(4).unwrap_or(' ') != '_')
{
Ok((&input[4..], Token::File))
} else if input.len() >= 3
&& input[..3].eq_ignore_ascii_case("URL")
&& (input.len() == 3
|| !input.chars().nth(3).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(3).unwrap_or(' ') != '_')
{
Ok((&input[3..], Token::Url))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("ACYCLIC")
&& (input.len() == 7
|| (!input.chars().nth(7).unwrap().is_alphanumeric()
&& input.chars().nth(7).unwrap() != '_'))
{
Ok((&input[7..], Token::Acyclic))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("SIMPLE")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(6).unwrap_or(' ') != '_'))
{
Ok((&input[6..], Token::Simple))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("TRAIL")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Trail))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("WALK")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Walk))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("PATH")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Path))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("CREATE")
&& (input.len() == 6 || !input.chars().nth(6).unwrap_or(' ').is_alphanumeric())
{
Ok((&input[6..], Token::Create))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("INSERT")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Insert))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("DELETE")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Delete))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("REMOVE")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Remove))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("UNWIND")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Unwind))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("STARTS")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Starts))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("EXISTS")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Exists))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("MATCHES")
&& (input.len() == 7
|| (!input.chars().nth(7).unwrap().is_alphanumeric()
&& input.chars().nth(7).unwrap() != '_'))
{
Ok((&input[7..], Token::Matches))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("SOURCE")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Source))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("CASE")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Case))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("CAST")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Cast))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("WHEN")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::When))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("THEN")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Then))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("ELSE")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Else))
} else if input.len() >= 3
&& input[..3].eq_ignore_ascii_case("END")
&& (input.len() == 3
|| (!input.chars().nth(3).unwrap().is_alphanumeric()
&& input.chars().nth(3).unwrap() != '_'))
{
Ok((&input[3..], Token::End))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("LEADING")
&& (input.len() == 7 || !input.chars().nth(7).unwrap_or(' ').is_alphanumeric())
{
Ok((&input[7..], Token::Leading))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("TRAILING")
&& (input.len() == 8 || !input.chars().nth(8).unwrap_or(' ').is_alphanumeric())
{
Ok((&input[8..], Token::Trailing))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("BOTH")
&& (input.len() == 4 || !input.chars().nth(4).unwrap_or(' ').is_alphanumeric())
{
Ok((&input[4..], Token::Both))
} else if input.len() >= 3
&& input[..3].eq_ignore_ascii_case("LET")
&& (input.len() == 3 || !input.chars().nth(3).unwrap_or(' ').is_alphanumeric())
{
Ok((&input[3..], Token::Let))
} else if input.len() >= 3
&& input[..3].eq_ignore_ascii_case("FOR")
&& (input.len() == 3 || !input.chars().nth(3).unwrap_or(' ').is_alphanumeric())
{
Ok((&input[3..], Token::For))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("FILTER")
&& (input.len() == 6 || !input.chars().nth(6).unwrap_or(' ').is_alphanumeric())
{
Ok((&input[6..], Token::Filter))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("DECLARE")
&& (input.len() == 7 || !input.chars().nth(7).unwrap_or(' ').is_alphanumeric())
{
Ok((&input[7..], Token::Declare))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("NEXT")
&& (input.len() == 4 || !input.chars().nth(4).unwrap_or(' ').is_alphanumeric())
{
Ok((&input[4..], Token::Next))
} else if input.len() >= 2
&& input[..2].eq_ignore_ascii_case("AT")
&& (input.len() == 2
|| (!input.chars().nth(2).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(2).unwrap_or(' ') != '_'))
{
Ok((&input[2..], Token::At))
} else if is_keyword_match(input, "UNCOMMITTED") {
Ok((&input[11..], Token::Uncommitted))
} else if is_keyword_match(input, "SERIALIZABLE") {
Ok((&input[12..], Token::Serializable))
} else if is_keyword_match(input, "REPEATABLE") {
Ok((&input[10..], Token::Repeatable))
} else if is_keyword_match(input, "ISOLATION") {
Ok((&input[9..], Token::Isolation))
} else if is_keyword_match(input, "COMMITTED") {
Ok((&input[9..], Token::Committed))
} else if is_keyword_match(input, "ROLLBACK") {
Ok((&input[8..], Token::Rollback))
} else if is_keyword_match(input, "START") {
Ok((&input[5..], Token::Start))
} else if is_keyword_match(input, "LEVEL") {
Ok((&input[5..], Token::Level))
} else if is_keyword_match(input, "BEGIN") {
Ok((&input[5..], Token::Begin))
} else if is_keyword_match(input, "WRITE") {
Ok((&input[5..], Token::Write))
} else if is_keyword_match(input, "WORK") {
Ok((&input[4..], Token::Work))
} else if is_keyword_match(input, "ONLY") {
Ok((&input[4..], Token::Only))
} else if is_keyword_match(input, "READ") {
Ok((&input[4..], Token::Read))
} else if is_keyword_match(input, "COMMIT") {
Ok((&input[6..], Token::Commit))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("VERTEX")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Vertex))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("NODETACH")
&& (input.len() == 8
|| (!input.chars().nth(8).unwrap().is_alphanumeric()
&& input.chars().nth(8).unwrap() != '_'))
{
Ok((&input[8..], Token::NoDetach))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("DETACH")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Detach))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("SELECT")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Select))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("FROM")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::From))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("RETURN")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Return))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("MATCH")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(5).unwrap_or(' ') != '_'))
{
Ok((&input[5..], Token::Match))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("WHERE")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Where))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("MERGE")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Merge))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("STORE")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Store))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("ORDER")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Order))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("LIMIT")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Limit))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("HAVING")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Having))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("OFFSET")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Offset))
} else if is_keyword_match(input, "GRAPH") {
Ok((&input[5..], Token::Graph))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("GROUP")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Group))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("TYPES")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Types))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("ROLES")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Roles))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("YIELD")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Yield))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("RESET")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Reset))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("CLOSE")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Close))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("VALUE")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Value))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("TABLE")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Table))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("TYPED")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Typed))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("TIME")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Time))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("ZONE")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Zone))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("HOME")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Home))
} else if input.len() >= 4
&& &input[..4] == "USER"
&& (input.len() == 4
|| !input.chars().nth(4).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(4).unwrap_or(' ') != '_')
{
Ok((&input[4..], Token::User))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("ROLE")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Role))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("GRANT")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Grant))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("REVOKE")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Revoke))
} else if input.len() >= 9
&& input[..9].eq_ignore_ascii_case("PROCEDURE")
&& (input.len() == 9
|| (!input.chars().nth(9).unwrap().is_alphanumeric()
&& input.chars().nth(9).unwrap() != '_'))
{
Ok((&input[9..], Token::Procedure))
} else if input.len() >= 2
&& input[..2].eq_ignore_ascii_case("TO")
&& (input.len() == 2
|| (!input.chars().nth(2).unwrap().is_alphanumeric()
&& input.chars().nth(2).unwrap() != '_'))
{
Ok((&input[2..], Token::To))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("NODE")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
if &input[..4] == "NODE" {
Ok((&input[4..], Token::Node))
} else {
Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Tag,
)))
}
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("EDGE")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Edge))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("WITH")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::With))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("CALL")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Call))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("LOAD")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Load))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("ENDS")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Ends))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("LIKE")
&& (input.len() == 4 || is_word_boundary(input.chars().nth(4).unwrap_or(' ')))
{
Ok((&input[4..], Token::Like))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("TYPE")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Type))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("COPY")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Copy))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("TRUNCATE")
&& (input.len() == 8
|| (!input.chars().nth(8).unwrap().is_alphanumeric()
&& input.chars().nth(8).unwrap() != '_'))
{
Ok((&input[8..], Token::Truncate))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("CLEAR")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Clear))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("DROP")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Drop))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("REGISTER")
&& (input.len() == 8
|| (!input.chars().nth(8).unwrap().is_alphanumeric()
&& input.chars().nth(8).unwrap() != '_'))
{
Ok((&input[8..], Token::Register))
} else if input.len() >= 10
&& input[..10].eq_ignore_ascii_case("UNREGISTER")
&& (input.len() == 10
|| (!input.chars().nth(10).unwrap().is_alphanumeric()
&& input.chars().nth(10).unwrap() != '_'))
{
Ok((&input[10..], Token::Unregister))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("SKIP")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Skip))
} else if input.len() >= 7
&& input[..7].eq_ignore_ascii_case("LEADING")
&& (input.len() == 7
|| (!input.chars().nth(7).unwrap().is_alphanumeric()
&& input.chars().nth(7).unwrap() != '_'))
{
Ok((&input[7..], Token::Leading))
} else if input.len() >= 8
&& input[..8].eq_ignore_ascii_case("TRAILING")
&& (input.len() == 8
|| (!input.chars().nth(8).unwrap().is_alphanumeric()
&& input.chars().nth(8).unwrap() != '_'))
{
Ok((&input[8..], Token::Trailing))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("BOTH")
&& (input.len() == 4
|| !input.chars().nth(4).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(4).unwrap_or(' ') != '_')
{
Ok((&input[4..], Token::Both))
} else if input.len() >= 3
&& input[..3].eq_ignore_ascii_case("SET")
&& (input.len() == 3
|| (!input.chars().nth(3).unwrap().is_alphanumeric()
&& input.chars().nth(3).unwrap() != '_'))
{
Ok((&input[3..], Token::Set))
} else if input.len() >= 10
&& input[..10].eq_ignore_ascii_case("DESCENDING")
&& (input.len() == 10
|| (!input.chars().nth(10).unwrap().is_alphanumeric()
&& input.chars().nth(10).unwrap() != '_'))
{
Ok((&input[10..], Token::Descending))
} else if input.len() >= 9
&& input[..9].eq_ignore_ascii_case("INTERSECT")
&& (input.len() == 9
|| (!input.chars().nth(9).unwrap().is_alphanumeric()
&& input.chars().nth(9).unwrap() != '_'))
{
Ok((&input[9..], Token::Intersect))
} else if input.len() >= 9
&& input[..9].eq_ignore_ascii_case("ASCENDING")
&& (input.len() == 9
|| (!input.chars().nth(9).unwrap().is_alphanumeric()
&& input.chars().nth(9).unwrap() != '_'))
{
Ok((&input[9..], Token::Ascending))
} else if input.len() >= 6
&& input[..6].eq_ignore_ascii_case("EXCEPT")
&& (input.len() == 6
|| (!input.chars().nth(6).unwrap().is_alphanumeric()
&& input.chars().nth(6).unwrap() != '_'))
{
Ok((&input[6..], Token::Except))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("UNION")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Union))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("NULLS")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Nulls))
} else if is_keyword_match(input, "FIRST") {
Ok((&input[5..], Token::First))
} else if is_keyword_match(input, "LAST") {
Ok((&input[4..], Token::Last))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("DESC")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Desc))
} else if input.len() >= 3
&& input[..3].eq_ignore_ascii_case("ASC")
&& (input.len() == 3
|| (!input.chars().nth(3).unwrap().is_alphanumeric()
&& input.chars().nth(3).unwrap() != '_'))
{
Ok((&input[3..], Token::Asc))
} else if input.len() >= 3
&& input[..3].eq_ignore_ascii_case("ALL")
&& (input.len() == 3
|| (!input.chars().nth(3).unwrap().is_alphanumeric()
&& input.chars().nth(3).unwrap() != '_'))
{
Ok((&input[3..], Token::All))
} else if input.len() >= 3
&& input[..3].eq_ignore_ascii_case("ANY")
&& (input.len() == 3
|| (!input.chars().nth(3).unwrap().is_alphanumeric()
&& input.chars().nth(3).unwrap() != '_'))
{
Ok((&input[3..], Token::Any))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("SOME")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Some))
} else if input.len() >= 3
&& input[..3].eq_ignore_ascii_case("AND")
&& (input.len() == 3
|| (!input.chars().nth(3).unwrap().is_alphanumeric()
&& input.chars().nth(3).unwrap() != '_'))
{
Ok((&input[3..], Token::And))
} else if input.len() >= 3
&& input[..3].eq_ignore_ascii_case("NOT")
&& (input.len() == 3
|| (!input.chars().nth(3).unwrap().is_alphanumeric()
&& input.chars().nth(3).unwrap() != '_'))
{
Ok((&input[3..], Token::Not))
} else if input.len() >= 3
&& input[..3].eq_ignore_ascii_case("XOR")
&& (input.len() == 3
|| (!input.chars().nth(3).unwrap().is_alphanumeric()
&& input.chars().nth(3).unwrap() != '_'))
{
Ok((&input[3..], Token::Xor))
} else if input.len() >= 2
&& input[..2].eq_ignore_ascii_case("BY")
&& (input.len() == 2
|| (!input.chars().nth(2).unwrap().is_alphanumeric()
&& input.chars().nth(2).unwrap() != '_'))
{
Ok((&input[2..], Token::By))
} else if input.len() >= 2
&& input[..2].eq_ignore_ascii_case("ON")
&& (input.len() == 2
|| (!input.chars().nth(2).unwrap().is_alphanumeric()
&& input.chars().nth(2).unwrap() != '_'))
{
Ok((&input[2..], Token::On))
} else if input.len() >= 2
&& input[..2].eq_ignore_ascii_case("AS")
&& (input.len() == 2
|| (!input.chars().nth(2).unwrap().is_alphanumeric()
&& input.chars().nth(2).unwrap() != '_'))
{
Ok((&input[2..], Token::As))
} else if input.len() >= 2
&& input[..2].eq_ignore_ascii_case("OR")
&& (input.len() == 2
|| (!input.chars().nth(2).unwrap().is_alphanumeric()
&& input.chars().nth(2).unwrap() != '_'))
{
Ok((&input[2..], Token::Or))
} else if input.len() >= 2
&& input[..2].eq_ignore_ascii_case("OF")
&& (input.len() == 2
|| (!input.chars().nth(2).unwrap().is_alphanumeric()
&& input.chars().nth(2).unwrap() != '_'))
{
Ok((&input[2..], Token::Of))
} else if input.len() >= 2
&& input[..2].eq_ignore_ascii_case("IS")
&& (input.len() == 2
|| (!input.chars().nth(2).unwrap_or(' ').is_alphanumeric()
&& input.chars().nth(2).unwrap_or(' ') != '_'))
{
Ok((&input[2..], Token::Is))
} else if input.len() >= 2
&& input[..2].eq_ignore_ascii_case("IF")
&& (input.len() == 2
|| (!input.chars().nth(2).unwrap().is_alphanumeric()
&& input.chars().nth(2).unwrap() != '_'))
{
Ok((&input[2..], Token::If))
} else if input.len() >= 2
&& input[..2].eq_ignore_ascii_case("IN")
&& (input.len() == 2
|| (!input.chars().nth(2).unwrap().is_alphanumeric()
&& input.chars().nth(2).unwrap() != '_'))
{
Ok((&input[2..], Token::In))
}
else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("true")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Boolean(true)))
} else if input.len() >= 5
&& input[..5].eq_ignore_ascii_case("false")
&& (input.len() == 5
|| (!input.chars().nth(5).unwrap().is_alphanumeric()
&& input.chars().nth(5).unwrap() != '_'))
{
Ok((&input[5..], Token::Boolean(false)))
} else if input.len() >= 4
&& input[..4].eq_ignore_ascii_case("NULL")
&& (input.len() == 4
|| (!input.chars().nth(4).unwrap().is_alphanumeric()
&& input.chars().nth(4).unwrap() != '_'))
{
Ok((&input[4..], Token::Null))
}
else if input.starts_with('+') {
Ok((&input[1..], Token::Plus))
} else if input.starts_with('-') {
if input.len() > 1 && input.chars().nth(1).unwrap().is_ascii_digit() {
Ok((&input[1..], Token::Minus))
} else {
Ok((&input[1..], Token::Dash))
}
} else if input.starts_with('*') {
Ok((&input[1..], Token::Star))
} else if input.starts_with('/') {
Ok((&input[1..], Token::Slash))
} else if input.starts_with('%') {
Ok((&input[1..], Token::Percent))
} else if input.starts_with('^') {
Ok((&input[1..], Token::Caret))
} else if input.starts_with('=') {
Ok((&input[1..], Token::Equal))
} else if input.starts_with('<') {
Ok((&input[1..], Token::LessThan))
} else if input.starts_with('>') {
Ok((&input[1..], Token::GreaterThan))
} else if input.starts_with('@') {
Ok((&input[1..], Token::AtSign))
} else if input.starts_with('$') {
Ok((&input[1..], Token::Dollar))
} else if input.starts_with('.') {
Ok((&input[1..], Token::Dot))
} else if input.starts_with(',') {
Ok((&input[1..], Token::Comma))
} else if input.starts_with(';') {
Ok((&input[1..], Token::Semicolon))
} else if input.starts_with(':') {
Ok((&input[1..], Token::Colon))
} else if input.starts_with('&') {
Ok((&input[1..], Token::Ampersand))
} else if input.starts_with('|') {
Ok((&input[1..], Token::Pipe))
} else if input.starts_with('(') {
Ok((&input[1..], Token::LeftParen))
} else if input.starts_with(')') {
Ok((&input[1..], Token::RightParen))
} else if input.starts_with('[') {
Ok((&input[1..], Token::LeftBracket))
} else if input.starts_with(']') {
Ok((&input[1..], Token::RightBracket))
} else if input.starts_with('{') {
Ok((&input[1..], Token::LeftBrace))
} else if input.starts_with('}') {
Ok((&input[1..], Token::RightBrace))
} else if input.starts_with('?') {
Ok((&input[1..], Token::Question))
} else {
Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Tag,
)))
}
}
fn whitespace(input: &str) -> IResult<&str, Token> {
let (remaining, whitespace_chars) = take_while(|c: char| c.is_whitespace())(input)?;
if whitespace_chars.is_empty() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Tag,
)));
}
Ok((remaining, Token::Whitespace))
}
fn comment(input: &str) -> IResult<&str, &str> {
alt((
recognize(pair(tag("//"), take_while(|c| c != '\n'))),
recognize(tuple((tag("/*"), take_while(|c| c != '*'), tag("*/")))),
))(input)
}
fn property_access(input: &str) -> IResult<&str, &str> {
recognize(tuple((
pair(
alt((alpha1, tag("_"))),
many0(alt((alphanumeric1, tag("_")))),
),
char('.'),
pair(
alt((alpha1, tag("_"))),
many0(alt((alphanumeric1, tag("_")))),
),
)))(input)
}
fn string_literal(input: &str) -> IResult<&str, &str> {
alt((
map(
recognize(pair(
char('"'),
pair(escaped_string_content('"'), char('"')),
)),
|s: &str| &s[1..s.len() - 1], ),
map(
recognize(pair(
char('\''),
pair(escaped_string_content('\''), char('\'')),
)),
|s: &str| &s[1..s.len() - 1], ),
))(input)
}
fn backtick_identifier(input: &str) -> IResult<&str, &str> {
map(
recognize(pair(char('`'), pair(escaped_backtick_content, char('`')))),
|s: &str| &s[1..s.len() - 1], )(input)
}
fn escaped_backtick_content(input: &str) -> IResult<&str, &str> {
let mut pos = 0;
let input_bytes = input.as_bytes();
while pos < input_bytes.len() {
if input_bytes[pos] == b'`' {
if pos + 1 < input_bytes.len() && input_bytes[pos + 1] == b'`' {
pos += 2;
} else {
break;
}
} else {
pos += 1;
}
}
Ok((&input[pos..], &input[0..pos]))
}
fn escaped_string_content(quote_char: char) -> impl Fn(&str) -> IResult<&str, &str> {
move |input: &str| {
let mut pos = 0;
let input_bytes = input.as_bytes();
while pos < input_bytes.len() {
if input_bytes[pos] == b'\\' && pos + 1 < input_bytes.len() {
pos += 2;
} else if input_bytes[pos] == quote_char as u8 {
break;
} else {
pos += 1;
}
}
Ok((&input[pos..], &input[0..pos]))
}
}
fn integer_literal(input: &str) -> IResult<&str, i64> {
map(recognize(pair(opt(char('-')), digit1)), |s: &str| {
s.parse::<i64>().unwrap()
})(input)
}
fn float_literal(input: &str) -> IResult<&str, f64> {
map(
recognize(pair(opt(char('-')), pair(digit1, pair(char('.'), digit1)))),
|s: &str| s.parse::<f64>().unwrap(),
)(input)
}
fn _timewindow_literal(input: &str) -> IResult<&str, &str> {
if input.starts_with("TIME_WINDOW(") {
let mut paren_count = 0;
let mut end_pos = 0;
for (i, c) in input.chars().enumerate() {
if c == '(' {
paren_count += 1;
} else if c == ')' {
paren_count -= 1;
if paren_count == 0 {
end_pos = i + 1;
break;
}
}
}
if end_pos > 0 {
Ok((&input[end_pos..], &input[..end_pos]))
} else {
Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Tag,
)))
}
} else {
Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Tag,
)))
}
}
fn vector_literal(input: &str) -> IResult<&str, Vec<f64>> {
map(
recognize(tuple((
char('['),
alt((
tuple((
take_while1(|c: char| c.is_ascii_digit() || c == '.' || c == ' ' || c == '-'),
char(','),
take_while(|c: char| {
c.is_ascii_digit() || c == '.' || c == ',' || c == ' ' || c == '-'
}),
)),
tuple((
take_while(|c: char| c == ' '),
peek(char(']')),
take_while(|c: char| c == ' '),
)),
)),
char(']'),
))),
|s: &str| {
let content = &s[1..s.len() - 1]; if content.trim().is_empty() {
vec![]
} else {
content
.split(',')
.map(|x| x.trim().parse::<f64>().unwrap_or(0.0))
.collect()
}
},
)(input)
}
fn variable(input: &str) -> IResult<&str, &str> {
map(
recognize(pair(char('$'), identifier)),
|s: &str| &s[1..], )(input)
}
fn identifier(input: &str) -> IResult<&str, &str> {
recognize(pair(
alt((alpha1, tag("_"))),
many0(alt((alphanumeric1, tag("_")))),
))(input)
}
pub fn tokenize(input: &str) -> Result<Vec<Token>, String> {
let mut lexer = Lexer::new(input.to_string());
lexer.tokenize()
}