tree-based source processing language
at main 948 lines 28 kB view raw
1use nom::{ 2 branch::alt, 3 bytes::complete::{is_not, tag}, 4 character::complete::{alpha1, alphanumeric1, char, multispace0, multispace1, one_of}, 5 combinator::{map, opt, recognize, value}, 6 error::ParseError, 7 multi::{fold_many0, many0, many0_count, many1, separated_list0, separated_list1}, 8 sequence::{delimited, pair, preceded, terminated, tuple}, 9 IResult, Parser, 10}; 11// use tree_sitter::Query; 12 13use crate::ast::*; 14use crate::string::parse_string; 15 16fn ws<'a, F: 'a, O, E>(inner: F) -> impl FnMut(&'a str) -> IResult<&'a str, O, E> 17where 18 F: FnMut(&'a str) -> IResult<&'a str, O, E>, 19 E: ParseError<&'a str>, 20{ 21 delimited(multispace0, inner, multispace0) 22} 23 24// TODO use this 25fn _parse_comment<'a>(i: &'a str) -> IResult<&'a str, ()> { 26 value((), pair(tag("//"), is_not("\n\r")))(i) 27} 28 29fn parse_unit<'a>(i: &'a str) -> IResult<&'a str, ()> { 30 let open = char('('); 31 let close = char(')'); 32 let unit = tuple((open, close)); 33 value((), unit)(i) 34} 35 36fn parse_bool(i: &str) -> IResult<&str, bool> { 37 let t = value(true, tag("true")); 38 let f = value(false, tag("false")); 39 alt((t, f)).parse(i) 40} 41 42fn parse_int<'a>(i: &'a str) -> IResult<&'a str, i128> { 43 map(recognize(many1(one_of("0123456789"))), |s: &str| { 44 s.parse::<i128>().unwrap() 45 })(i) 46} 47 48fn parse_name(i: &str) -> IResult<&str, &str> { 49 recognize(pair( 50 alt((alpha1, tag("_"))), 51 many0_count(alt((alphanumeric1, tag("_")))), 52 )) 53 .parse(i) 54} 55 56fn parse_ident(i: &str) -> IResult<&str, Identifier> { 57 map(parse_name, str::to_owned)(i) 58} 59 60fn parse_lit<'a>(i: &'a str) -> IResult<&'a str, Literal> { 61 alt(( 62 map(parse_string, Literal::Str), 63 map(parse_int, Literal::Int), 64 map(parse_bool, Literal::Bool), 65 )) 66 .parse(i) 67} 68 69fn parse_cmp_op(i: &str) -> IResult<&str, CmpOp> { 70 alt(( 71 value(CmpOp::Eq, tag("==")), 72 value(CmpOp::Neq, tag("!=")), 73 value(CmpOp::Gte, tag(">=")), 74 value(CmpOp::Lte, tag("<=")), 75 value(CmpOp::Gt, tag(">")), 76 value(CmpOp::Lt, tag("<")), 77 )) 78 .parse(i) 79} 80 81fn parse_assign_op(i: &str) -> IResult<&str, AssignOp> { 82 let parse_arith_op = alt(( 83 value(ArithOp::Add, char('+')), 84 value(ArithOp::Sub, char('-')), 85 value(ArithOp::Mul, char('*')), 86 value(ArithOp::Div, char('/')), 87 value(ArithOp::Mod, char('%')), 88 )); 89 map(tuple((opt(parse_arith_op), char('='))), |(op, _)| { 90 AssignOp { op } 91 })(i) 92} 93 94fn parse_op<'a, E, T>( 95 op_str: &'static str, 96 op: T, 97) -> impl FnMut(&'a str) -> Result<(&'a str, T), nom::Err<E>> 98where 99 E: ParseError<&'a str>, 100 T: Copy, 101{ 102 value(op, tag(op_str)) 103} 104 105fn parse_binary<'a, P1, P2, P3, E>( 106 lhs: P1, 107 op: P2, 108 rhs: P3, 109) -> impl FnMut(&'a str) -> Result<(&'a str, Expr), nom::Err<E>> 110where 111 P1: Parser<&'a str, Expr, E>, 112 P2: Parser<&'a str, BinOp, E>, 113 P3: Parser<&'a str, Expr, E>, 114 E: ParseError<&'a str>, 115{ 116 map(tuple((lhs, op, rhs)), |(l, o, r)| { 117 Expr::Bin(l.boxed(), o, r.boxed()) 118 }) 119} 120 121fn parse_assign<'a>(i: &'a str) -> IResult<&'a str, Expr> { 122 let op = map(parse_assign_op, BinOp::Assign); 123 let recursive = parse_binary(parse_atom, op, parse_assign); 124 let base = parse_union; 125 alt((recursive, base)).parse(i) 126} 127 128fn parse_union<'a>(i: &'a str) -> IResult<&'a str, Expr> { 129 let op = parse_op("||", BinOp::Logic(LogicOp::Or)); 130 let recursive = parse_binary(parse_intersection, op, parse_union); 131 let base = parse_intersection; 132 alt((recursive, base)).parse(i) 133} 134 135fn parse_intersection<'a>(i: &'a str) -> IResult<&'a str, Expr> { 136 let op = parse_op("&&", BinOp::Logic(LogicOp::And)); 137 let recursive = parse_binary(parse_negated, op, parse_intersection); 138 let base = parse_negated; 139 alt((recursive, base)).parse(i) 140} 141 142fn parse_negated<'a>(i: &'a str) -> IResult<&'a str, Expr> { 143 let op = parse_op("!", UnaryOp::Not); 144 let recursive = map(tuple((op, parse_rel)), |(op, expr)| { 145 Expr::Unary(expr.boxed(), op) 146 }); 147 let base = parse_rel; 148 alt((recursive, base)).parse(i) 149} 150 151fn parse_rel<'a>(i: &'a str) -> IResult<&'a str, Expr> { 152 let op = map(parse_cmp_op, BinOp::Cmp); 153 let recursive = parse_binary(parse_sum, op, parse_rel); 154 let base = parse_sum; 155 alt((recursive, base)).parse(i) 156} 157 158fn parse_sum<'a>(i: &'a str) -> IResult<&'a str, Expr> { 159 let add = parse_op("+", BinOp::Arith(ArithOp::Add)); 160 let sub = parse_op("-", BinOp::Arith(ArithOp::Sub)); 161 let op = alt((add, sub)); 162 let recursive = parse_binary(parse_mul, op, parse_sum); 163 let base = parse_mul; 164 alt((recursive, base)).parse(i) 165} 166 167fn parse_mul<'a>(i: &'a str) -> IResult<&'a str, Expr> { 168 let mul = parse_op("*", BinOp::Arith(ArithOp::Mul)); 169 let div = parse_op("/", BinOp::Arith(ArithOp::Div)); 170 let mod_ = parse_op("%", BinOp::Arith(ArithOp::Mod)); 171 let op = alt((mul, div, mod_)); 172 let recursive = parse_binary(parse_field_or_index, op, parse_mul); 173 let base = parse_field_or_index; 174 alt((recursive, base)).parse(i) 175} 176 177fn parse_field_or_index<'a>(i: &'a str) -> IResult<&'a str, Expr> { 178 enum FieldOrIndex { 179 Field(String), 180 Index(Expr), 181 } 182 183 let (i, base) = parse_atom(i)?; 184 185 let field = map(tuple((ws(char('.')), ws(parse_ident))), |(_, i)| { 186 FieldOrIndex::Field(i) 187 }); 188 let index = map( 189 tuple((ws(char('[')), parse_expr, ws(char(']')))), 190 |(_, idx, _)| FieldOrIndex::Index(idx), 191 ); 192 193 fold_many0( 194 alt((field, index)), 195 move || base.clone(), 196 move |acc, new| match new { 197 FieldOrIndex::Field(f) => Expr::FieldAccess(acc.boxed(), f), 198 FieldOrIndex::Index(idx) => Expr::Index(acc.boxed(), idx.boxed()), 199 }, 200 )(i) 201} 202 203fn parse_list<'a>(i: &'a str) -> IResult<&'a str, List> { 204 let open = ws(char('[')); 205 let items = separated_list0(char(','), parse_expr); 206 let close = ws(char(']')); 207 map(tuple((open, items, close)), |(_, items, _)| List { items }).parse(i) 208} 209 210fn parse_atom<'a>(i: &'a str) -> IResult<&'a str, Expr> { 211 let inner = alt(( 212 map(tag("node"), |_| Expr::Node), 213 map(parse_block, Expr::Block), 214 map(parse_if, Expr::If), 215 map(parse_call, Expr::Call), 216 map(parse_list, Expr::List), 217 map(parse_lit, Expr::Lit), 218 map(parse_ident, Expr::Ident), 219 map(parse_unit, |_| Expr::Unit), 220 )); 221 ws(inner).parse(i) 222} 223 224fn parse_call<'a>(i: &'a str) -> IResult<&'a str, Call> { 225 let ident = parse_ident; 226 let open = ws(char('(')); 227 let args = separated_list0(char(','), parse_expr); 228 let close = ws(char(')')); 229 map( 230 tuple((ident, open, args, close)), 231 |(function, _, parameters, _)| Call { 232 function, 233 parameters, 234 }, 235 ) 236 .parse(i) 237} 238 239fn parse_block<'a>(i: &'a str) -> IResult<&'a str, Block> { 240 let open = ws(char('{')); 241 let statements = map(many0(parse_statement), |body| Block { body }); 242 let close = ws(char('}')); 243 delimited(open, statements, close).parse(i) 244} 245 246fn parse_if<'a>(i: &'a str) -> IResult<&'a str, IfExpr> { 247 let if_ = delimited(multispace0, tag("if"), multispace1); 248 249 let open = char('('); 250 let condition = ws(parse_expr); 251 let close = terminated(char(')'), multispace0); 252 253 let then = parse_block; 254 255 let else_kw = ws(tag("else")); 256 let else_ = opt(preceded(else_kw, parse_block)); 257 258 map( 259 tuple((if_, open, condition, close, then, else_)), 260 |(_, _, condition, _, then, else_)| IfExpr { 261 condition: condition.boxed(), 262 then, 263 else_: else_.unwrap_or_default(), 264 }, 265 )(i) 266} 267 268fn parse_expr<'a>(i: &'a str) -> IResult<&'a str, Expr> { 269 parse_assign.parse(i) 270} 271 272fn parse_bare<'a>(i: &'a str) -> IResult<&'a str, Expr> { 273 parse_expr(i) 274} 275 276fn parse_type<'a>(i: &'a str) -> IResult<&'a str, Type> { 277 let int = value(Type::Integer, tag("int")); 278 let string = value(Type::String, tag("string")); 279 let bool_ = value(Type::Boolean, tag("bool")); 280 let list = value(Type::List, tag("list")); 281 alt((int, string, bool_, list)).parse(i) 282} 283 284fn parse_declaration<'a>(i: &'a str) -> IResult<&'a str, Declaration> { 285 let ty = parse_type; 286 let name = parse_ident; 287 let op = ws(char('=')); 288 let init = opt(preceded(op, map(parse_expr, Expr::boxed))); 289 map( 290 tuple((ty, multispace0, name, init)), 291 |(ty, _, name, init)| Declaration { ty, name, init }, 292 )(i) 293} 294 295fn parse_statement<'a>(i: &'a str) -> IResult<&'a str, Statement> { 296 let semicolon = ws(char(';')); 297 let inner = alt(( 298 map(parse_declaration, Statement::Declaration), 299 map(parse_bare, Statement::Bare), 300 )); 301 terminated(inner, semicolon).parse(i) 302} 303 304// pub fn skip_query(mut i: &str) -> IResult<&str, ()> { 305// let mut paren_depth = 0; 306// let mut in_string = false; 307// let mut in_escape = false; 308// let mut in_comment = false; 309// loop { 310// let ch = i 311// .chars() 312// .next() 313// .ok_or(nom::Err::Error(nom::error::Error::new( 314// i, 315// nom::error::ErrorKind::Eof, 316// )))?; 317// if in_escape { 318// in_escape = false; 319// } else if in_string { 320// match ch { 321// '\\' => { 322// in_escape = true; 323// } 324// '"' | '\n' => { 325// in_string = false; 326// } 327// _ => {} 328// } 329// } else if in_comment { 330// if ch == '\n' { 331// in_comment = false; 332// } 333// } else { 334// match ch { 335// '"' => in_string = true, 336// '(' => paren_depth += 1, 337// ')' => { 338// if paren_depth > 0 { 339// paren_depth -= 1; 340// } 341// } 342// '{' => return Ok((i, ())), 343// ';' => in_comment = true, 344// _ => {} 345// } 346// } 347// i = &i[1..]; 348// } 349// } 350 351// fn parse_query<'a>( 352// language: tree_sitter::Language, 353// ) -> impl FnMut(&'a str) -> IResult<&'a str, Query> { 354// return move |initial: &'a str| { 355// let query_start = 0; 356// let (skipped, _) = skip_query(initial)?; 357// let query_end = initial.len() - skipped.len(); 358// let query_source = &initial[query_start..query_end].to_owned(); 359// 360// let query = Query::new(language, &query_source).map_err(|mut _e| { 361// nom::Err::Error(nom::error::Error::new(initial, nom::error::ErrorKind::Fail)) 362// })?; 363// Ok((skipped, query)) 364// }; 365// } 366 367fn parse_modifier<'a>(i: &str) -> IResult<&str, Modifier> { 368 let pre = value(Modifier::Enter, tag("enter")); 369 let post = value(Modifier::Leave, tag("leave")); 370 map(opt(alt((pre, post))), Option::unwrap_or_default)(i) 371} 372 373fn parse_pattern<'a>(i: &str) -> IResult<&str, Pattern> { 374 let begin = value(Pattern::Begin, ws(tag("BEGIN"))); 375 let end = value(Pattern::End, ws(tag("END"))); 376 ws(alt((begin, end, parse_tree_pattern))).parse(i) 377} 378 379// fn parse_node_pattern<'a>(i: &str) -> IResult<&str, Pattern> { 380// map( 381// tuple((parse_modifier, multispace0, parse_ident)), 382// |(modifier, _, kind)| Pattern::Node(NodePattern { modifier, kind }), 383// ) 384// .parse(i) 385// } 386 387fn parse_tree_pattern<'a>(i: &str) -> IResult<&str, Pattern> { 388 let parse_matcher = alt((parse_tree_atom, parse_tree_list)); 389 tuple((parse_modifier, multispace0, parse_matcher)) 390 .map(|(modifier, _, matcher)| Pattern::Tree { modifier, matcher }) 391 .parse(i) 392} 393 394fn parse_tree_atom<'a>(i: &str) -> IResult<&str, TreePattern> { 395 parse_ident.map(TreePattern::Atom).parse(i) 396} 397 398fn parse_tree_list<'a>(i: &str) -> IResult<&str, TreePattern> { 399 let open = terminated(char('('), multispace0); 400 let close = preceded(multispace0, char(')')); 401 let list = separated_list1(multispace1, alt((parse_tree_atom, parse_tree_list))); 402 tuple((open, list, close)) 403 .map(|(_, list, _)| TreePattern::List(list)) 404 .parse(i) 405} 406 407pub fn parse_stanza<'a>(i: &str) -> IResult<&str, Stanza> { 408 map( 409 tuple((parse_pattern, parse_block)), 410 |(pattern, statements)| Stanza { 411 pattern, 412 statements, 413 }, 414 )(i) 415} 416 417pub fn parse_file(i: &str) -> IResult<&str, Vec<Stanza>> { 418 many0(parse_stanza).parse(i) 419} 420 421#[cfg(test)] 422mod test { 423 use super::*; 424 425 // test helpers 426 impl Expr { 427 pub fn int(int: i128) -> Expr { 428 Self::Lit(Literal::Int(int)) 429 } 430 431 pub fn str(s: &str) -> Expr { 432 Self::Lit(Literal::Str(s.to_owned())) 433 } 434 435 pub const fn false_() -> Expr { 436 Self::Lit(Literal::Bool(false)) 437 } 438 439 pub const fn true_() -> Expr { 440 Self::Lit(Literal::Bool(true)) 441 } 442 } 443 444 #[test] 445 fn test_parse_unit() { 446 assert_eq!(parse_unit("()"), Ok(("", ()))) 447 } 448 449 #[test] 450 fn test_parse_int() { 451 assert_eq!(parse_int("123456"), Ok(("", 123456))); 452 assert_eq!(parse_int("00123456"), Ok(("", 123456))); 453 } 454 455 #[test] 456 fn test_parse_bool() { 457 assert_eq!(parse_bool("true"), Ok(("", true))); 458 assert_eq!(parse_bool("false"), Ok(("", false))); 459 } 460 461 #[test] 462 fn test_parse_name() { 463 assert_eq!(parse_name("true"), Ok(("", "true"))); 464 assert_eq!(parse_name("_abc"), Ok(("", "_abc"))); 465 } 466 467 #[test] 468 fn test_parse_literal() { 469 assert_eq!( 470 parse_lit(r#""foobarbaz""#), 471 Ok(("", Literal::Str("foobarbaz".to_owned()))) 472 ); 473 assert_eq!(parse_lit("123"), Ok(("", Literal::Int(123)))); 474 assert_eq!(parse_lit("true"), Ok(("", Literal::Bool(true)))); 475 } 476 477 #[test] 478 fn test_parse_expr() { 479 assert_eq!(parse_expr(" () "), Ok(("", Expr::Unit))); 480 assert_eq!(parse_expr(" 55 "), Ok(("", Expr::int(55)))); 481 assert_eq!( 482 parse_expr(" true || true "), 483 Ok(( 484 "", 485 Expr::Bin( 486 Expr::true_().boxed(), 487 BinOp::Logic(LogicOp::Or), 488 Expr::true_().boxed() 489 ) 490 )) 491 ); 492 assert_eq!( 493 parse_expr("true || false && 5 == 5 "), 494 Ok(( 495 "", 496 Expr::Bin( 497 Expr::true_().boxed(), 498 BinOp::Logic(LogicOp::Or), 499 Expr::Bin( 500 Expr::false_().boxed(), 501 BinOp::Logic(LogicOp::And), 502 Expr::Bin( 503 Expr::int(5).boxed(), 504 BinOp::Cmp(CmpOp::Eq), 505 Expr::int(5).boxed(), 506 ) 507 .boxed() 508 ) 509 .boxed() 510 ) 511 )) 512 ); 513 assert_eq!( 514 parse_expr(" foo ( 1, 2,3 , 1 == 1)"), 515 Ok(( 516 "", 517 Expr::Call(Call { 518 function: "foo".to_owned(), 519 parameters: vec![ 520 Expr::int(1), 521 Expr::int(2), 522 Expr::int(3), 523 Expr::Bin( 524 Expr::int(1).boxed(), 525 BinOp::Cmp(CmpOp::Eq), 526 Expr::int(1).boxed() 527 ) 528 ], 529 }) 530 )) 531 ); 532 assert_eq!( 533 parse_expr("a = b"), 534 Ok(( 535 "", 536 Expr::Bin( 537 Expr::Ident("a".to_owned()).boxed(), 538 BinOp::Assign(AssignOp { op: None }), 539 Expr::Ident("b".to_owned()).boxed(), 540 ) 541 )) 542 ); 543 assert_eq!( 544 parse_expr(" a += 4 + 5"), 545 Ok(( 546 "", 547 Expr::Bin( 548 Expr::Ident("a".to_owned()).boxed(), 549 BinOp::Assign(AssignOp { 550 op: Some(ArithOp::Add) 551 }), 552 Expr::Bin( 553 Expr::int(4).boxed(), 554 BinOp::Arith(ArithOp::Add), 555 Expr::int(5).boxed(), 556 ) 557 .boxed() 558 ) 559 )) 560 ); 561 assert_eq!( 562 parse_expr("a[0]"), 563 Ok(( 564 "", 565 Expr::Index(Expr::Ident("a".to_owned()).boxed(), Expr::int(0).boxed()) 566 )) 567 ); 568 assert_eq!( 569 parse_expr("children(node)[0]"), 570 Ok(( 571 "", 572 Expr::Index( 573 Expr::Call(Call { 574 function: "children".to_owned(), 575 parameters: vec![Expr::Node] 576 }) 577 .boxed(), 578 Expr::int(0).boxed() 579 ) 580 )) 581 ); 582 } 583 584 #[test] 585 fn test_parse_statement() { 586 assert_eq!( 587 parse_statement("true;"), 588 Ok(("", Statement::Bare(Expr::true_()))) 589 ); 590 assert_eq!( 591 parse_statement("true ; "), 592 Ok(("", Statement::Bare(Expr::true_()))) 593 ); 594 assert_eq!( 595 parse_statement("int a ; "), 596 Ok(( 597 "", 598 Statement::Declaration(Declaration { 599 ty: Type::Integer, 600 name: "a".to_owned(), 601 init: None 602 }) 603 )) 604 ); 605 assert_eq!( 606 parse_statement("int a =5 ; "), 607 Ok(( 608 "", 609 Statement::Declaration(Declaration { 610 ty: Type::Integer, 611 name: "a".to_owned(), 612 init: Some(Expr::int(5).boxed()) 613 }) 614 )) 615 ); 616 assert_eq!( 617 parse_statement(r#"list a =["a", "b", "c"]; "#), 618 Ok(( 619 "", 620 Statement::Declaration(Declaration { 621 ty: Type::List, 622 name: "a".to_owned(), 623 init: Some( 624 Expr::List(List { 625 items: vec![Expr::str("a"), Expr::str("b"), Expr::str("c"),] 626 }) 627 .boxed() 628 ) 629 }) 630 )) 631 ); 632 } 633 634 #[test] 635 fn test_parse_block() { 636 assert_eq!( 637 parse_expr( 638 r#" 639 { 640 true; 641 1; 642 } 643 "# 644 ), 645 Ok(( 646 "", 647 Expr::Block(Block { 648 body: vec![ 649 Statement::Bare(Expr::true_()), 650 Statement::Bare(Expr::int(1)), 651 ] 652 }) 653 )) 654 ); 655 } 656 657 #[test] 658 fn test_parse_node() { 659 assert_eq!(parse_expr(r#" node "#), Ok(("", Expr::Node))); 660 assert_eq!( 661 parse_expr(r#" node.foo "#), 662 Ok(("", Expr::FieldAccess(Expr::Node.boxed(), "foo".to_owned()))) 663 ); 664 assert_eq!( 665 parse_expr( 666 r#" node 667 .foo 668 .bar"# 669 ), 670 Ok(( 671 "", 672 Expr::FieldAccess( 673 Expr::FieldAccess(Expr::Node.boxed(), "foo".to_owned()).boxed(), 674 "bar".to_owned() 675 ) 676 )) 677 ); 678 } 679 680 #[test] 681 fn test_parse_if() { 682 assert_eq!( 683 parse_expr( 684 r#" 685 if (1 == true) { 686 5; 687 } else { 688 10; 689 } 690 "# 691 ), 692 Ok(( 693 "", 694 Expr::If(IfExpr { 695 condition: Expr::Bin( 696 Expr::int(1).boxed(), 697 BinOp::Cmp(CmpOp::Eq), 698 Expr::true_().boxed() 699 ) 700 .boxed(), 701 then: Block { 702 body: vec![Statement::Bare(Expr::int(5)),] 703 }, 704 else_: Block { 705 body: vec![Statement::Bare(Expr::int(10)),] 706 } 707 }) 708 )) 709 ); 710 } 711 712 #[test] 713 fn test_parse_index() { 714 assert_eq!( 715 parse_expr( 716 r#" 717 a[0] 718 "# 719 ), 720 Ok(( 721 "", 722 Expr::Index(Expr::Ident("a".to_owned()).boxed(), Expr::int(0).boxed()), 723 )) 724 ); 725 assert_eq!( 726 parse_expr(r#"node.children[idx]"#), 727 Ok(( 728 "", 729 Expr::Index( 730 Expr::FieldAccess(Expr::Node.boxed(), Identifier::from("children")).boxed(), 731 Expr::Ident("idx".to_owned()).boxed() 732 ) 733 )) 734 ); 735 assert_eq!( 736 parse_expr(r#"foo[i].bar[j]"#), 737 Ok(( 738 "", 739 Expr::Index( 740 Expr::FieldAccess( 741 Expr::Index( 742 Expr::Ident("foo".to_owned()).boxed(), 743 Expr::Ident("i".to_owned()).boxed() 744 ) 745 .boxed(), 746 "bar".to_owned() 747 ) 748 .boxed(), 749 Expr::Ident("j".to_owned()).boxed() 750 ), 751 )) 752 ); 753 } 754 755 // #[test] 756 // fn test_skip_query() { 757 // assert_eq!( 758 // skip_query( 759 // r#"(heading 760 // (paragraph) @foo) {}"# 761 // ), 762 // Ok(("{}", ())) 763 // ); 764 // } 765 766 #[test] 767 fn test_parse_pattern() { 768 assert_eq!( 769 parse_pattern("enter function_definition"), 770 Ok(( 771 "", 772 Pattern::Tree { 773 modifier: Modifier::Enter, 774 matcher: TreePattern::Atom("function_definition".to_owned()), 775 } 776 )) 777 ); 778 assert_eq!( 779 parse_pattern("function_definition"), 780 Ok(( 781 "", 782 Pattern::Tree { 783 modifier: Modifier::Enter, 784 matcher: TreePattern::Atom("function_definition".to_owned()), 785 } 786 )) 787 ); 788 assert_eq!( 789 parse_pattern("leave function_definition"), 790 Ok(( 791 "", 792 Pattern::Tree { 793 modifier: Modifier::Leave, 794 matcher: TreePattern::Atom("function_definition".to_owned()), 795 } 796 )) 797 ); 798 } 799 800 // #[test] 801 // fn test_parse_stanza() { 802 // assert_eq!( 803 // parse_stanza("enter function_definition { true; }"), 804 // Ok(( 805 // "", 806 // Stanza { 807 // pattern: Pattern::Node(NodePattern { 808 // modifier: Modifier::Enter, 809 // kind: "function_definition".to_owned() 810 // }), 811 // statements: Block { 812 // body: vec![Statement::Bare(Expr::true_())] 813 // } 814 // } 815 // )) 816 // ); 817 // assert_eq!( 818 // parse_stanza("BEGIN { true; }"), 819 // Ok(( 820 // "", 821 // Stanza { 822 // pattern: Pattern::Begin, 823 // statements: Block { 824 // body: vec![Statement::Bare(Expr::true_())] 825 // } 826 // } 827 // )) 828 // ); 829 // assert_eq!( 830 // parse_block( 831 // " { 832 // true; 833 // }" 834 // ), 835 // Ok(( 836 // "", 837 // Block { 838 // body: vec![Statement::Bare(Expr::true_())] 839 // } 840 // )) 841 // ); 842 // } 843 844 #[test] 845 fn test_parse_if_statement_regression() { 846 assert_eq!( 847 parse_statement("if (true) { true; };"), 848 Ok(( 849 "", 850 Statement::Bare(Expr::If(IfExpr { 851 condition: Expr::true_().boxed(), 852 then: Block { 853 body: vec![Statement::Bare(Expr::true_())] 854 }, 855 else_: Block::default(), 856 })) 857 )) 858 ); 859 assert_eq!( 860 parse_expr("if (true) { true; } else { true; }"), 861 Ok(( 862 "", 863 Expr::If(IfExpr { 864 condition: Expr::true_().boxed(), 865 then: Block { 866 body: vec![Statement::Bare(Expr::true_())] 867 }, 868 else_: Block { 869 body: vec![Statement::Bare(Expr::true_())] 870 }, 871 }) 872 )) 873 ); 874 } 875 #[test] 876 fn test_parse_tree_pattern() { 877 assert_eq!( 878 parse_tree_pattern("enter foo"), 879 Ok(( 880 "", 881 Pattern::Tree { 882 modifier: Modifier::Enter, 883 matcher: TreePattern::Atom("foo".to_owned()) 884 } 885 )) 886 ); 887 assert_eq!( 888 parse_tree_pattern("enter (foo)"), 889 Ok(( 890 "", 891 Pattern::Tree { 892 modifier: Modifier::Enter, 893 matcher: TreePattern::List(vec![TreePattern::Atom("foo".to_owned())]) 894 } 895 )) 896 ); 897 assert_eq!( 898 parse_tree_pattern("leave (foo bar baz)"), 899 Ok(( 900 "", 901 Pattern::Tree { 902 modifier: Modifier::Leave, 903 matcher: TreePattern::List(vec![ 904 TreePattern::Atom("foo".to_owned()), 905 TreePattern::Atom("bar".to_owned()), 906 TreePattern::Atom("baz".to_owned()), 907 ]) 908 } 909 )) 910 ); 911 assert_eq!( 912 parse_tree_pattern("leave (foo (bar quux) baz)"), 913 Ok(( 914 "", 915 Pattern::Tree { 916 modifier: Modifier::Leave, 917 matcher: TreePattern::List(vec![ 918 TreePattern::Atom("foo".to_owned()), 919 TreePattern::List(vec![ 920 TreePattern::Atom("bar".to_owned()), 921 TreePattern::Atom("quux".to_owned()) 922 ]), 923 TreePattern::Atom("baz".to_owned()), 924 ]) 925 } 926 )) 927 ); 928 assert_eq!( 929 parse_tree_pattern("enter ( foo (bar quux ) baz)"), 930 Ok(( 931 "", 932 Pattern::Tree { 933 modifier: Modifier::Enter, 934 matcher: TreePattern::List(vec![ 935 TreePattern::Atom("foo".to_owned()), 936 TreePattern::List(vec![ 937 TreePattern::Atom("bar".to_owned()), 938 TreePattern::Atom("quux".to_owned()) 939 ]), 940 TreePattern::Atom("baz".to_owned()), 941 ]) 942 } 943 )) 944 ); 945 assert!(parse_tree_pattern("( )").is_err()); 946 assert!(parse_tree_pattern("()").is_err()); 947 } 948}