use super::ast::*;
use super::error::{GqlError, GqlResult};
use super::lexer::{Token, TokenKind};
use serde_json::Value;
use std::collections::HashMap;
pub struct Parser {
tokens: Vec<Token>,
current: usize,
}
impl Parser {
pub fn new(tokens: Vec<Token>) -> Self {
Self { tokens, current: 0 }
}
pub fn parse(&mut self) -> GqlResult<GqlStatement> {
self.skip_newlines();
if self.match_token(&TokenKind::Graph) {
let graph_name = self.consume_identifier("Expected graph name")?;
let query = self.parse_linear_query()?;
Ok(GqlStatement::GraphQuery { graph_name, query })
} else {
let query = self.parse_linear_query()?;
Ok(GqlStatement::LinearQuery(query))
}
}
fn parse_linear_query(&mut self) -> GqlResult<LinearQuery> {
let mut query = LinearQuery::new();
while !self.is_at_end() && !self.check(&TokenKind::Eof) {
self.skip_newlines();
if self.is_at_end() || self.check(&TokenKind::Eof) {
break;
}
let clause = self.parse_query_clause()?;
query.add_clause(clause);
self.skip_newlines();
}
Ok(query)
}
fn parse_query_clause(&mut self) -> GqlResult<QueryClause> {
match &self.peek().kind {
TokenKind::Match => {
self.advance(); let optional = false; let patterns = self.parse_graph_patterns()?;
Ok(QueryClause::Match(MatchClause { optional, patterns }))
}
TokenKind::Optional => {
self.advance(); self.consume(&TokenKind::Match, "Expected MATCH after OPTIONAL")?;
let patterns = self.parse_graph_patterns()?;
Ok(QueryClause::Match(MatchClause {
optional: true,
patterns,
}))
}
TokenKind::Where | TokenKind::Filter => {
self.advance(); let condition = self.parse_expression()?;
Ok(QueryClause::Filter(FilterClause { condition }))
}
TokenKind::Return => {
self.advance(); let distinct = self.match_token(&TokenKind::Distinct);
let items = self.parse_return_items()?;
Ok(QueryClause::Return(ReturnClause { distinct, items }))
}
TokenKind::With => {
self.advance(); let items = self.parse_return_items()?;
Ok(QueryClause::With(WithClause { items }))
}
TokenKind::OrderBy => {
self.advance(); let items = self.parse_order_by_items()?;
Ok(QueryClause::OrderBy(OrderByClause { items }))
}
TokenKind::Limit => {
self.advance(); let count = self.parse_expression()?;
Ok(QueryClause::Limit(LimitClause { count }))
}
TokenKind::Offset => {
self.advance(); let count = self.parse_expression()?;
Ok(QueryClause::Offset(OffsetClause { count }))
}
TokenKind::Insert | TokenKind::Create => {
self.advance(); let patterns = self.parse_graph_patterns()?;
Ok(QueryClause::Insert(InsertClause { patterns }))
}
TokenKind::Delete => {
self.advance(); let detach = false; let expressions = self.parse_expression_list()?;
Ok(QueryClause::Delete(DeleteClause {
detach,
expressions,
}))
}
TokenKind::Set => {
self.advance(); let items = self.parse_set_items()?;
Ok(QueryClause::Set(SetClause { items }))
}
TokenKind::Remove => {
self.advance(); let items = self.parse_remove_items()?;
Ok(QueryClause::Remove(RemoveClause { items }))
}
_ => {
if let TokenKind::Identifier(name) = &self.peek().kind {
if name.to_uppercase() == "ORDER" {
return self.parse_order_by_clause();
}
}
Err(GqlError::ParseError {
message: format!("Unexpected token in query clause: {:?}", self.peek().kind),
token: Some(self.peek().lexeme.clone()),
position: self.peek().position,
})
}
}
}
fn parse_order_by_clause(&mut self) -> GqlResult<QueryClause> {
self.consume_identifier_with_value("ORDER", "Expected ORDER")?;
self.consume_identifier_with_value("BY", "Expected BY after ORDER")?;
let items = self.parse_order_by_items()?;
Ok(QueryClause::OrderBy(OrderByClause { items }))
}
fn parse_graph_patterns(&mut self) -> GqlResult<Vec<GraphPattern>> {
let mut patterns = Vec::new();
patterns.push(self.parse_graph_pattern()?);
while self.match_token(&TokenKind::Comma) {
patterns.push(self.parse_graph_pattern()?);
}
Ok(patterns)
}
fn parse_graph_pattern(&mut self) -> GqlResult<GraphPattern> {
if self.check(&TokenKind::LeftParen) {
self.parse_node_or_path_pattern()
} else {
Err(GqlError::ParseError {
message: "Expected node or path pattern".to_string(),
token: Some(self.peek().lexeme.clone()),
position: self.peek().position,
})
}
}
fn parse_node_or_path_pattern(&mut self) -> GqlResult<GraphPattern> {
let start_node = self.parse_node_pattern()?;
if self.check(&TokenKind::Minus) || self.check(&TokenKind::LessThan) {
let mut relationships = Vec::new();
while self.check(&TokenKind::Minus) || self.check(&TokenKind::LessThan) {
let rel = self.parse_relationship_pattern()?;
let node = self.parse_node_pattern()?;
relationships.push((rel, Box::new(node)));
}
Ok(GraphPattern::Path(PathPattern {
start: Box::new(start_node),
relationships,
}))
} else {
Ok(GraphPattern::Node(start_node))
}
}
fn parse_node_pattern(&mut self) -> GqlResult<NodePattern> {
self.consume(&TokenKind::LeftParen, "Expected '(' to start node pattern")?;
let mut node = NodePattern::new(None);
if let TokenKind::Identifier(name) = &self.peek().kind {
node.variable = Some(name.clone());
self.advance();
}
if self.match_token(&TokenKind::Colon) {
loop {
let label = self.consume_identifier("Expected label name")?;
node.labels.push(label);
if !self.match_token(&TokenKind::Pipe) {
break;
}
}
}
if self.check(&TokenKind::LeftBrace) {
node.properties = Some(self.parse_property_pattern()?);
}
if self.match_token(&TokenKind::Where) {
node.where_clause = Some(Box::new(self.parse_expression()?));
}
self.consume(&TokenKind::RightParen, "Expected ')' to end node pattern")?;
Ok(node)
}
fn parse_relationship_pattern(&mut self) -> GqlResult<RelationshipPattern> {
let is_incoming = if self.match_token(&TokenKind::LessThan) {
self.consume(
&TokenKind::Minus,
"Expected '-' after '<' in relationship pattern",
)?;
true
} else if self.match_token(&TokenKind::Minus) {
false
} else {
return Err(GqlError::ParseError {
message: "Expected relationship pattern starting with '-' or '<-'".to_string(),
token: Some(self.peek().lexeme.clone()),
position: self.peek().position,
});
};
let mut rel = RelationshipPattern::new(RelationshipDirection::Undirected);
if self.match_token(&TokenKind::LeftBracket) {
if let TokenKind::Identifier(name) = &self.peek().kind {
rel.variable = Some(name.clone());
self.advance();
}
if self.match_token(&TokenKind::Colon) {
rel.rel_type = Some(self.consume_identifier("Expected relationship type")?);
}
if self.match_token(&TokenKind::Multiply) {
rel.length = Some(self.parse_path_length()?);
}
if self.check(&TokenKind::LeftBrace) {
rel.properties = Some(self.parse_property_pattern()?);
}
self.consume(
&TokenKind::RightBracket,
"Expected ']' to end relationship pattern",
)?;
if self.match_token(&TokenKind::Arrow) {
rel.direction = if is_incoming {
RelationshipDirection::Undirected } else {
RelationshipDirection::Outgoing };
} else if self.match_token(&TokenKind::Minus) {
if self.match_token(&TokenKind::GreaterThan) {
rel.direction = if is_incoming {
RelationshipDirection::Undirected } else {
RelationshipDirection::Outgoing };
} else {
rel.direction = if is_incoming {
RelationshipDirection::Incoming } else {
RelationshipDirection::Undirected };
}
} else {
return Err(GqlError::ParseError {
message: "Expected '->' or '-' after relationship bracket".to_string(),
token: Some(self.peek().lexeme.clone()),
position: self.peek().position,
});
}
} else {
if self.match_token(&TokenKind::Arrow) || self.match_token(&TokenKind::GreaterThan) {
rel.direction = if is_incoming {
RelationshipDirection::Undirected } else {
RelationshipDirection::Outgoing };
} else {
rel.direction = if is_incoming {
RelationshipDirection::Incoming } else {
RelationshipDirection::Undirected };
}
}
Ok(rel)
}
fn parse_property_pattern(&mut self) -> GqlResult<PropertyPattern> {
self.consume(
&TokenKind::LeftBrace,
"Expected '{' to start property pattern",
)?;
let mut properties = HashMap::new();
if !self.check(&TokenKind::RightBrace) {
loop {
let key = self.consume_identifier("Expected property name")?;
self.consume(&TokenKind::Colon, "Expected ':' after property name")?;
let value = self.parse_expression()?;
properties.insert(key, value);
if !self.match_token(&TokenKind::Comma) {
break;
}
}
}
self.consume(
&TokenKind::RightBrace,
"Expected '}' to end property pattern",
)?;
Ok(PropertyPattern { properties })
}
fn parse_return_items(&mut self) -> GqlResult<Vec<ReturnItem>> {
let mut items = Vec::new();
items.push(self.parse_return_item()?);
while self.match_token(&TokenKind::Comma) {
items.push(self.parse_return_item()?);
}
Ok(items)
}
fn parse_return_item(&mut self) -> GqlResult<ReturnItem> {
let expression = self.parse_expression()?;
let alias = if self.match_token(&TokenKind::As) {
Some(self.consume_identifier("Expected alias name after AS")?)
} else {
None
};
Ok(ReturnItem { expression, alias })
}
fn parse_order_by_items(&mut self) -> GqlResult<Vec<OrderByItem>> {
let mut items = Vec::new();
items.push(self.parse_order_by_item()?);
while self.match_token(&TokenKind::Comma) {
items.push(self.parse_order_by_item()?);
}
Ok(items)
}
fn parse_order_by_item(&mut self) -> GqlResult<OrderByItem> {
let expression = self.parse_expression()?;
let direction = if self.match_token(&TokenKind::Asc) {
SortDirection::Asc
} else if self.match_token(&TokenKind::Desc) {
SortDirection::Desc
} else {
SortDirection::Asc };
Ok(OrderByItem {
expression,
direction,
})
}
fn parse_expression_list(&mut self) -> GqlResult<Vec<Expression>> {
let mut expressions = Vec::new();
expressions.push(self.parse_expression()?);
while self.match_token(&TokenKind::Comma) {
expressions.push(self.parse_expression()?);
}
Ok(expressions)
}
fn parse_set_items(&mut self) -> GqlResult<Vec<SetItem>> {
let mut items = Vec::new();
items.push(self.parse_set_item()?);
while self.match_token(&TokenKind::Comma) {
items.push(self.parse_set_item()?);
}
Ok(items)
}
fn parse_set_item(&mut self) -> GqlResult<SetItem> {
let target = self.parse_set_target()?;
self.consume(&TokenKind::Assign, "Expected '=' in SET clause")?;
let value = self.parse_expression()?;
Ok(SetItem { target, value })
}
fn parse_set_target(&mut self) -> GqlResult<Expression> {
let name = self.consume_identifier("Expected variable name in SET clause")?;
let mut expr = Expression::Variable(name);
while self.match_token(&TokenKind::Dot) {
let property = self.consume_identifier("Expected property name after '.'")?;
expr = Expression::property(expr, property);
}
Ok(expr)
}
fn parse_remove_items(&mut self) -> GqlResult<Vec<RemoveItem>> {
let mut items = Vec::new();
items.push(self.parse_remove_item()?);
while self.match_token(&TokenKind::Comma) {
items.push(self.parse_remove_item()?);
}
Ok(items)
}
fn parse_remove_item(&mut self) -> GqlResult<RemoveItem> {
let expr = self.parse_expression()?;
Ok(RemoveItem::Property(expr))
}
fn parse_expression(&mut self) -> GqlResult<Expression> {
self.parse_or_expression()
}
fn parse_or_expression(&mut self) -> GqlResult<Expression> {
let mut expr = self.parse_and_expression()?;
while self.match_token(&TokenKind::Or) {
let right = self.parse_and_expression()?;
expr = Expression::binary(expr, BinaryOperator::Or, right);
}
Ok(expr)
}
fn parse_and_expression(&mut self) -> GqlResult<Expression> {
let mut expr = self.parse_equality_expression()?;
while self.match_token(&TokenKind::And) {
let right = self.parse_equality_expression()?;
expr = Expression::binary(expr, BinaryOperator::And, right);
}
Ok(expr)
}
fn parse_equality_expression(&mut self) -> GqlResult<Expression> {
let mut expr = self.parse_comparison_expression()?;
while let Some(op) = self.match_equality_operator() {
let right = self.parse_comparison_expression()?;
expr = Expression::binary(expr, op, right);
}
Ok(expr)
}
fn parse_comparison_expression(&mut self) -> GqlResult<Expression> {
let mut expr = self.parse_additive_expression()?;
while let Some(op) = self.match_comparison_operator() {
let right = self.parse_additive_expression()?;
expr = Expression::binary(expr, op, right);
}
Ok(expr)
}
fn parse_additive_expression(&mut self) -> GqlResult<Expression> {
let mut expr = self.parse_multiplicative_expression()?;
while let Some(op) = self.match_additive_operator() {
let right = self.parse_multiplicative_expression()?;
expr = Expression::binary(expr, op, right);
}
Ok(expr)
}
fn parse_multiplicative_expression(&mut self) -> GqlResult<Expression> {
let mut expr = self.parse_unary_expression()?;
while let Some(op) = self.match_multiplicative_operator() {
let right = self.parse_unary_expression()?;
expr = Expression::binary(expr, op, right);
}
Ok(expr)
}
fn parse_unary_expression(&mut self) -> GqlResult<Expression> {
if let Some(op) = self.match_unary_operator() {
let operand = self.parse_unary_expression()?;
Ok(Expression::Unary {
operator: op,
operand: Box::new(operand),
})
} else {
self.parse_primary_expression()
}
}
fn parse_primary_expression(&mut self) -> GqlResult<Expression> {
match &self.peek().kind {
TokenKind::Integer(value) => {
let value = *value;
self.advance();
Ok(Expression::Literal(Value::Number(value.into())))
}
TokenKind::Float(value) => {
let value = *value;
self.advance();
Ok(Expression::Literal(Value::Number(
serde_json::Number::from_f64(value).unwrap(),
)))
}
TokenKind::String(value) => {
let value = value.clone();
self.advance();
Ok(Expression::Literal(Value::String(value)))
}
TokenKind::Boolean(value) => {
let value = *value;
self.advance();
Ok(Expression::Literal(Value::Bool(value)))
}
TokenKind::Null => {
self.advance();
Ok(Expression::Literal(Value::Null))
}
TokenKind::Parameter(name) => {
let name = name.clone();
self.advance();
Ok(Expression::Parameter(name))
}
TokenKind::Identifier(name) => {
let name = name.clone();
self.advance();
if self.match_token(&TokenKind::LeftParen) {
let args = if self.check(&TokenKind::RightParen) {
Vec::new()
} else if self.check(&TokenKind::Multiply) {
self.advance(); Vec::new() } else {
self.parse_expression_list()?
};
self.consume(
&TokenKind::RightParen,
"Expected ')' after function arguments",
)?;
Ok(Expression::FunctionCall { name, args })
} else {
let mut expr = Expression::Variable(name);
while self.match_token(&TokenKind::Dot) {
let property =
self.consume_identifier("Expected property name after '.'")?;
expr = Expression::property(expr, property);
}
Ok(expr)
}
}
TokenKind::LeftParen => {
self.advance(); let expr = self.parse_expression()?;
self.consume(&TokenKind::RightParen, "Expected ')' after expression")?;
Ok(expr)
}
TokenKind::LeftBracket => {
self.advance(); let mut elements = Vec::new();
if !self.check(&TokenKind::RightBracket) {
elements.push(self.parse_expression()?);
while self.match_token(&TokenKind::Comma) {
elements.push(self.parse_expression()?);
}
}
self.consume(&TokenKind::RightBracket, "Expected ']' after list elements")?;
Ok(Expression::List(elements))
}
_ => Err(GqlError::ParseError {
message: format!("Unexpected token in expression: {:?}", self.peek().kind),
token: Some(self.peek().lexeme.clone()),
position: self.peek().position,
}),
}
}
fn match_equality_operator(&mut self) -> Option<BinaryOperator> {
match self.peek().kind {
TokenKind::Equal => {
self.advance();
Some(BinaryOperator::Equal)
}
TokenKind::NotEqual => {
self.advance();
Some(BinaryOperator::NotEqual)
}
_ => None,
}
}
fn match_comparison_operator(&mut self) -> Option<BinaryOperator> {
match self.peek().kind {
TokenKind::LessThan => {
self.advance();
Some(BinaryOperator::LessThan)
}
TokenKind::LessEqual => {
self.advance();
Some(BinaryOperator::LessEqual)
}
TokenKind::GreaterThan => {
self.advance();
Some(BinaryOperator::GreaterThan)
}
TokenKind::GreaterEqual => {
self.advance();
Some(BinaryOperator::GreaterEqual)
}
TokenKind::Assign => {
self.advance();
Some(BinaryOperator::Equal)
}
TokenKind::In => {
self.advance();
Some(BinaryOperator::In)
}
TokenKind::Contains => {
self.advance();
Some(BinaryOperator::Contains)
}
_ => None,
}
}
fn match_additive_operator(&mut self) -> Option<BinaryOperator> {
match self.peek().kind {
TokenKind::Plus => {
self.advance();
Some(BinaryOperator::Add)
}
TokenKind::Minus => {
self.advance();
Some(BinaryOperator::Subtract)
}
_ => None,
}
}
fn match_multiplicative_operator(&mut self) -> Option<BinaryOperator> {
match self.peek().kind {
TokenKind::Multiply => {
self.advance();
Some(BinaryOperator::Multiply)
}
TokenKind::Divide => {
self.advance();
Some(BinaryOperator::Divide)
}
TokenKind::Modulo => {
self.advance();
Some(BinaryOperator::Modulo)
}
_ => None,
}
}
fn match_unary_operator(&mut self) -> Option<UnaryOperator> {
match self.peek().kind {
TokenKind::Not => {
self.advance();
Some(UnaryOperator::Not)
}
TokenKind::Minus => {
self.advance();
Some(UnaryOperator::Minus)
}
TokenKind::Plus => {
self.advance();
Some(UnaryOperator::Plus)
}
_ => None,
}
}
fn match_token(&mut self, kind: &TokenKind) -> bool {
if self.check(kind) {
self.advance();
true
} else {
false
}
}
fn check(&self, kind: &TokenKind) -> bool {
if self.is_at_end() {
false
} else {
std::mem::discriminant(&self.peek().kind) == std::mem::discriminant(kind)
}
}
fn advance(&mut self) -> &Token {
if !self.is_at_end() {
self.current += 1;
}
self.previous()
}
fn is_at_end(&self) -> bool {
self.current >= self.tokens.len() || matches!(self.peek().kind, TokenKind::Eof)
}
fn peek(&self) -> &Token {
if self.current >= self.tokens.len() {
static EOF_TOKEN: Token = Token {
kind: TokenKind::Eof,
lexeme: String::new(),
position: 0,
};
&EOF_TOKEN
} else {
&self.tokens[self.current]
}
}
fn previous(&self) -> &Token {
&self.tokens[self.current - 1]
}
fn consume(&mut self, kind: &TokenKind, message: &str) -> GqlResult<()> {
if self.check(kind) {
self.advance();
Ok(())
} else {
Err(GqlError::ParseError {
message: message.to_string(),
token: Some(self.peek().lexeme.clone()),
position: self.peek().position,
})
}
}
fn consume_identifier(&mut self, message: &str) -> GqlResult<String> {
if let TokenKind::Identifier(name) = &self.peek().kind {
let name = name.clone();
self.advance();
Ok(name)
} else {
Err(GqlError::ParseError {
message: message.to_string(),
token: Some(self.peek().lexeme.clone()),
position: self.peek().position,
})
}
}
fn consume_identifier_with_value(
&mut self,
expected: &str,
message: &str,
) -> GqlResult<String> {
if let TokenKind::Identifier(name) = &self.peek().kind {
if name.to_uppercase() == expected.to_uppercase() {
let name = name.clone();
self.advance();
Ok(name)
} else {
Err(GqlError::ParseError {
message: message.to_string(),
token: Some(self.peek().lexeme.clone()),
position: self.peek().position,
})
}
} else {
Err(GqlError::ParseError {
message: message.to_string(),
token: Some(self.peek().lexeme.clone()),
position: self.peek().position,
})
}
}
fn skip_newlines(&mut self) {
while self.match_token(&TokenKind::Newline) {
}
}
fn parse_path_length(&mut self) -> GqlResult<PathLength> {
if let TokenKind::Integer(n) = &self.peek().kind {
let length = *n as usize;
self.advance();
if self.match_token(&TokenKind::DotDot) {
if let TokenKind::Integer(end) = &self.peek().kind {
let end_length = *end as usize;
self.advance();
Ok(PathLength::Range(Some(length), Some(end_length)))
} else {
Ok(PathLength::Range(Some(length), None))
}
} else {
Ok(PathLength::Exact(length))
}
} else if self.match_token(&TokenKind::DotDot) {
if let TokenKind::Integer(end) = &self.peek().kind {
let end_length = *end as usize;
self.advance();
Ok(PathLength::Range(Some(0), Some(end_length)))
} else {
Ok(PathLength::Variable)
}
} else {
Ok(PathLength::Variable)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::gql::lexer::Lexer;
fn parse_query(query: &str) -> GqlResult<GqlStatement> {
let mut lexer = Lexer::new(query);
let tokens = lexer.tokenize()?;
let mut parser = Parser::new(tokens);
parser.parse()
}
#[test]
fn test_simple_match_return() {
let result = parse_query("MATCH (n) RETURN n");
assert!(result.is_ok());
if let Ok(GqlStatement::LinearQuery(query)) = result {
assert_eq!(query.clauses.len(), 2);
assert!(matches!(query.clauses[0], QueryClause::Match(_)));
assert!(matches!(query.clauses[1], QueryClause::Return(_)));
}
}
#[test]
fn test_match_with_labels() {
let result = parse_query("MATCH (p:Person) RETURN p.name");
assert!(result.is_ok());
}
#[test]
fn test_path_pattern() {
let result = parse_query("MATCH (a)-[:KNOWS]->(b) RETURN a, b");
assert!(result.is_ok());
}
#[test]
fn test_where_clause() {
let result = parse_query("MATCH (p:Person) WHERE p.age > 30 RETURN p");
assert!(result.is_ok());
}
#[test]
fn test_graph_query() {
let result = parse_query("GRAPH myGraph MATCH (n) RETURN n");
assert!(result.is_ok());
if let Ok(GqlStatement::GraphQuery {
graph_name,
query: _,
}) = result
{
assert_eq!(graph_name, "myGraph");
}
}
#[test]
fn test_variable_length_patterns() {
let result = parse_query("MATCH (a)-[:KNOWS*]->(b) RETURN a, b");
assert!(result.is_ok());
let result = parse_query("MATCH (a)-[:KNOWS*2]->(b) RETURN a, b");
assert!(result.is_ok());
let result = parse_query("MATCH (a)-[:KNOWS*1..3]->(b) RETURN a, b");
assert!(result.is_ok());
let result = parse_query("MATCH (a)-[:KNOWS*2..]->(b) RETURN a, b");
assert!(result.is_ok());
let result = parse_query("MATCH (a)-[:KNOWS*..5]->(b) RETURN a, b");
assert!(result.is_ok());
}
}