A Claude-written graph database in Rust. Use at your own risk.
at main 387 lines 12 kB view raw
1use nom::{ 2 IResult, 3 branch::alt, 4 combinator::{map, opt, value}, 5 multi::{many0, many1, separated_list0, separated_list1}, 6 sequence::{preceded, terminated, tuple, delimited, pair}, 7}; 8use std::collections::HashMap; 9use crate::core::PropertyValue; 10use crate::cypher::ast::*; 11use crate::cypher::lexer::{Token, lex}; 12 13pub fn parse_cypher(input: &str) -> Result<CypherQuery, String> { 14 let (_, tokens) = lex(input).map_err(|e| format!("Lexing error: {:?}", e))?; 15 let (remaining, query) = cypher_query(&tokens).map_err(|e| format!("Parse error: {:?}", e))?; 16 17 if !remaining.is_empty() { 18 return Err(format!("Unexpected tokens after query: {:?}", remaining)); 19 } 20 21 Ok(query) 22} 23 24type Tokens<'a> = &'a [Token]; 25 26fn cypher_query(input: Tokens) -> IResult<Tokens, CypherQuery> { 27 alt(( 28 // Handle compound queries (MATCH ... RETURN ...) 29 map( 30 tuple(( 31 match_clause, 32 opt(return_clause), 33 )), 34 |(match_clause, return_clause)| { 35 if let Some(return_clause) = return_clause { 36 CypherQuery::Compound(vec![ 37 CypherQuery::Match(match_clause), 38 CypherQuery::Return(return_clause), 39 ]) 40 } else { 41 CypherQuery::Match(match_clause) 42 } 43 } 44 ), 45 map(create_clause, CypherQuery::Create), 46 map(return_clause, CypherQuery::Return), 47 map( 48 separated_list1( 49 |i| expect_token(i, &Token::Semicolon), 50 alt(( 51 map(match_clause, CypherQuery::Match), 52 map(create_clause, CypherQuery::Create), 53 map(return_clause, CypherQuery::Return), 54 )) 55 ), 56 CypherQuery::Compound 57 ), 58 ))(input) 59} 60 61fn match_clause(input: Tokens) -> IResult<Tokens, MatchClause> { 62 map( 63 tuple(( 64 opt(|i| expect_token(i, &Token::Optional)), 65 |i| expect_token(i, &Token::Match), 66 pattern, 67 opt(where_clause), 68 )), 69 |(optional, _, pattern, where_clause)| MatchClause { 70 pattern, 71 where_clause, 72 optional: optional.is_some(), 73 }, 74 )(input) 75} 76 77fn create_clause(input: Tokens) -> IResult<Tokens, CreateClause> { 78 map( 79 preceded( 80 |i| expect_token(i, &Token::Create), 81 pattern, 82 ), 83 |pattern| CreateClause { pattern }, 84 )(input) 85} 86 87fn return_clause(input: Tokens) -> IResult<Tokens, ReturnClause> { 88 map( 89 tuple(( 90 |i| expect_token(i, &Token::Return), 91 opt(|i| expect_token(i, &Token::Distinct)), 92 separated_list1(|i| expect_token(i, &Token::Comma), return_item), 93 opt(order_by), 94 opt(preceded(|i| expect_token(i, &Token::Skip), expression)), 95 opt(preceded(|i| expect_token(i, &Token::Limit), expression)), 96 )), 97 |(_, distinct, items, order_by, skip, limit)| ReturnClause { 98 distinct: distinct.is_some(), 99 items, 100 order_by, 101 skip, 102 limit, 103 }, 104 )(input) 105} 106 107fn return_item(input: Tokens) -> IResult<Tokens, ReturnItem> { 108 map( 109 tuple(( 110 expression, 111 opt(preceded(|i| expect_token(i, &Token::As), identifier)), 112 )), 113 |(expression, alias)| ReturnItem { expression, alias }, 114 )(input) 115} 116 117fn order_by(input: Tokens) -> IResult<Tokens, Vec<OrderByItem>> { 118 preceded( 119 tuple(( 120 |i| expect_token(i, &Token::Order), 121 |i| expect_token(i, &Token::By), 122 )), 123 separated_list1(|i| expect_token(i, &Token::Comma), order_by_item), 124 )(input) 125} 126 127fn order_by_item(input: Tokens) -> IResult<Tokens, OrderByItem> { 128 map( 129 tuple(( 130 expression, 131 opt(alt(( 132 value(true, |i| expect_token(i, &Token::Asc)), 133 value(false, |i| expect_token(i, &Token::Desc)), 134 ))), 135 )), 136 |(expression, ascending)| OrderByItem { 137 expression, 138 ascending: ascending.unwrap_or(true), 139 }, 140 )(input) 141} 142 143fn where_clause(input: Tokens) -> IResult<Tokens, Expression> { 144 preceded( 145 |i| expect_token(i, &Token::Where), 146 expression, 147 )(input) 148} 149 150fn pattern(input: Tokens) -> IResult<Tokens, Pattern> { 151 map( 152 separated_list1(|i| expect_token(i, &Token::Comma), pattern_part), 153 |parts| Pattern { 154 elements: parts.into_iter().flatten().collect(), 155 }, 156 )(input) 157} 158 159fn pattern_part(input: Tokens) -> IResult<Tokens, Vec<PatternElement>> { 160 many1(pattern_element)(input) 161} 162 163fn pattern_element(input: Tokens) -> IResult<Tokens, PatternElement> { 164 alt(( 165 map(node_pattern, PatternElement::Node), 166 map(relationship_pattern, PatternElement::Relationship), 167 ))(input) 168} 169 170fn node_pattern(input: Tokens) -> IResult<Tokens, NodePattern> { 171 delimited( 172 |i| expect_token(i, &Token::LeftParen), 173 map( 174 tuple(( 175 opt(identifier), 176 many0(preceded(|i| expect_token(i, &Token::Colon), identifier)), 177 opt(properties_map), 178 )), 179 |(variable, labels, properties)| NodePattern { 180 variable, 181 labels, 182 properties, 183 }, 184 ), 185 |i| expect_token(i, &Token::RightParen), 186 )(input) 187} 188 189fn relationship_pattern(input: Tokens) -> IResult<Tokens, RelationshipPattern> { 190 alt(( 191 map( 192 tuple(( 193 |i| expect_token(i, &Token::Minus), 194 delimited( 195 |i| expect_token(i, &Token::LeftBracket), 196 relationship_detail, 197 |i| expect_token(i, &Token::RightBracket), 198 ), 199 |i| expect_token(i, &Token::Arrow), 200 )), 201 |(_, detail, _)| RelationshipPattern { 202 direction: RelationshipDirection::Outgoing, 203 ..detail 204 }, 205 ), 206 map( 207 tuple(( 208 |i| expect_token(i, &Token::LeftArrow), 209 delimited( 210 |i| expect_token(i, &Token::LeftBracket), 211 relationship_detail, 212 |i| expect_token(i, &Token::RightBracket), 213 ), 214 |i| expect_token(i, &Token::Minus), 215 )), 216 |(_, detail, _)| RelationshipPattern { 217 direction: RelationshipDirection::Incoming, 218 ..detail 219 }, 220 ), 221 ))(input) 222} 223 224fn relationship_detail(input: Tokens) -> IResult<Tokens, RelationshipPattern> { 225 map( 226 tuple(( 227 opt(identifier), 228 many0(preceded(|i| expect_token(i, &Token::Colon), identifier)), 229 opt(properties_map), 230 )), 231 |(variable, types, properties)| RelationshipPattern { 232 variable, 233 types, 234 properties, 235 direction: RelationshipDirection::Both, 236 length: None, 237 }, 238 )(input) 239} 240 241fn properties_map(input: Tokens) -> IResult<Tokens, HashMap<String, Expression>> { 242 delimited( 243 |i| expect_token(i, &Token::LeftBrace), 244 map( 245 separated_list0( 246 |i| expect_token(i, &Token::Comma), 247 tuple(( 248 identifier, 249 |i| expect_token(i, &Token::Colon), 250 expression, 251 )), 252 ), 253 |items| items.into_iter().map(|(k, _, v)| (k, v)).collect(), 254 ), 255 |i| expect_token(i, &Token::RightBrace), 256 )(input) 257} 258 259fn expression(input: Tokens) -> IResult<Tokens, Expression> { 260 or_expression(input) 261} 262 263fn or_expression(input: Tokens) -> IResult<Tokens, Expression> { 264 let (input, left) = and_expression(input)?; 265 266 let (input, rights) = many0(preceded( 267 |i| expect_token(i, &Token::Or), 268 and_expression, 269 ))(input)?; 270 271 Ok((input, rights.into_iter().fold(left, |acc, right| { 272 Expression::Or(Box::new(acc), Box::new(right)) 273 }))) 274} 275 276fn and_expression(input: Tokens) -> IResult<Tokens, Expression> { 277 let (input, left) = comparison_expression(input)?; 278 279 let (input, rights) = many0(preceded( 280 |i| expect_token(i, &Token::And), 281 comparison_expression, 282 ))(input)?; 283 284 Ok((input, rights.into_iter().fold(left, |acc, right| { 285 Expression::And(Box::new(acc), Box::new(right)) 286 }))) 287} 288 289fn comparison_expression(input: Tokens) -> IResult<Tokens, Expression> { 290 let (input, left) = additive_expression(input)?; 291 292 if let Ok((input, _)) = expect_token(input, &Token::Equal) { 293 let (input, right) = additive_expression(input)?; 294 return Ok((input, Expression::Equal(Box::new(left), Box::new(right)))); 295 } 296 297 Ok((input, left)) 298} 299 300fn additive_expression(input: Tokens) -> IResult<Tokens, Expression> { 301 let (input, left) = multiplicative_expression(input)?; 302 303 let (input, ops) = many0(tuple(( 304 alt(( 305 value(true, |i| expect_token(i, &Token::Plus)), 306 value(false, |i| expect_token(i, &Token::Minus)), 307 )), 308 multiplicative_expression, 309 )))(input)?; 310 311 Ok((input, ops.into_iter().fold(left, |acc, (is_add, right)| { 312 if is_add { 313 Expression::Add(Box::new(acc), Box::new(right)) 314 } else { 315 Expression::Subtract(Box::new(acc), Box::new(right)) 316 } 317 }))) 318} 319 320fn multiplicative_expression(input: Tokens) -> IResult<Tokens, Expression> { 321 let (input, left) = primary_expression(input)?; 322 Ok((input, left)) 323} 324 325fn primary_expression(input: Tokens) -> IResult<Tokens, Expression> { 326 alt(( 327 // Try property access first (a.name) 328 map( 329 tuple(( 330 identifier, 331 |i| expect_token(i, &Token::Dot), 332 identifier, 333 )), 334 |(obj, _, prop)| Expression::Property(PropertyExpression { 335 expression: Box::new(Expression::Variable(obj)), 336 property: prop, 337 }), 338 ), 339 // Then literals and simple variables 340 map(literal, |lit| Expression::Literal(lit)), 341 map(identifier, Expression::Variable), 342 delimited( 343 |i| expect_token(i, &Token::LeftParen), 344 expression, 345 |i| expect_token(i, &Token::RightParen), 346 ), 347 ))(input) 348} 349 350fn literal(input: Tokens) -> IResult<Tokens, PropertyValue> { 351 if input.is_empty() { 352 return Err(nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Eof))); 353 } 354 355 match &input[0] { 356 Token::Integer(n) => Ok((&input[1..], PropertyValue::Integer(*n))), 357 Token::Float(f) => Ok((&input[1..], PropertyValue::Float(*f))), 358 Token::String(s) => Ok((&input[1..], PropertyValue::String(s.clone()))), 359 Token::True => Ok((&input[1..], PropertyValue::Boolean(true))), 360 Token::False => Ok((&input[1..], PropertyValue::Boolean(false))), 361 Token::Null => Ok((&input[1..], PropertyValue::Null)), 362 _ => Err(nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Tag))), 363 } 364} 365 366fn identifier(input: Tokens) -> IResult<Tokens, String> { 367 if input.is_empty() { 368 return Err(nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Eof))); 369 } 370 371 match &input[0] { 372 Token::Identifier(s) => Ok((&input[1..], s.clone())), 373 _ => Err(nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Tag))), 374 } 375} 376 377fn expect_token<'a>(input: &'a [Token], expected: &Token) -> IResult<&'a [Token], &'a Token> { 378 if input.is_empty() { 379 return Err(nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Eof))); 380 } 381 382 if std::mem::discriminant(&input[0]) == std::mem::discriminant(expected) { 383 Ok((&input[1..], &input[0])) 384 } else { 385 Err(nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Tag))) 386 } 387}