diff options
Diffstat (limited to 'src/parser.rs')
-rw-r--r-- | src/parser.rs | 118 |
1 files changed, 111 insertions, 7 deletions
diff --git a/src/parser.rs b/src/parser.rs index 4ec8e57..15d03fe 100644 --- a/src/parser.rs +++ b/src/parser.rs | |||
@@ -169,28 +169,51 @@ fn parse_mul<'a>(i: &'a str) -> IResult<&'a str, Expr> { | |||
169 | let div = parse_op("/", BinOp::Arith(ArithOp::Div)); | 169 | let div = parse_op("/", BinOp::Arith(ArithOp::Div)); |
170 | let mod_ = parse_op("%", BinOp::Arith(ArithOp::Mod)); | 170 | let mod_ = parse_op("%", BinOp::Arith(ArithOp::Mod)); |
171 | let op = alt((mul, div, mod_)); | 171 | let op = alt((mul, div, mod_)); |
172 | let recursive = parse_binary(parse_field_access, op, parse_mul); | 172 | let recursive = parse_binary(parse_field_or_index, op, parse_mul); |
173 | let base = parse_field_access; | 173 | let base = parse_field_or_index; |
174 | alt((recursive, base)).parse(i) | 174 | alt((recursive, base)).parse(i) |
175 | } | 175 | } |
176 | 176 | ||
177 | fn parse_field_access<'a>(i: &'a str) -> IResult<&'a str, Expr> { | 177 | fn parse_field_or_index<'a>(i: &'a str) -> IResult<&'a str, Expr> { |
178 | let trailing = map(tuple((ws(char('.')), ws(parse_ident))), |(_, i)| i); | 178 | enum FieldOrIndex { |
179 | Field(String), | ||
180 | Index(Expr), | ||
181 | } | ||
182 | |||
179 | let (i, base) = parse_atom(i)?; | 183 | let (i, base) = parse_atom(i)?; |
180 | 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 | |||
181 | fold_many0( | 193 | fold_many0( |
182 | trailing, | 194 | alt((field, index)), |
183 | move || base.clone(), | 195 | move || base.clone(), |
184 | move |acc, new| Expr::FieldAccess(acc.boxed(), new), | 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 | }, | ||
185 | )(i) | 200 | )(i) |
186 | } | 201 | } |
187 | 202 | ||
203 | fn 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 | |||
188 | fn parse_atom<'a>(i: &'a str) -> IResult<&'a str, Expr> { | 210 | fn parse_atom<'a>(i: &'a str) -> IResult<&'a str, Expr> { |
189 | let inner = alt(( | 211 | let inner = alt(( |
190 | map(tag("node"), |_| Expr::Node), | 212 | map(tag("node"), |_| Expr::Node), |
191 | map(parse_block, Expr::Block), | 213 | map(parse_block, Expr::Block), |
192 | map(parse_if, Expr::If), | 214 | map(parse_if, Expr::If), |
193 | map(parse_call, Expr::Call), | 215 | map(parse_call, Expr::Call), |
216 | map(parse_list, Expr::List), | ||
194 | map(parse_lit, Expr::Lit), | 217 | map(parse_lit, Expr::Lit), |
195 | map(parse_ident, Expr::Ident), | 218 | map(parse_ident, Expr::Ident), |
196 | map(parse_unit, |_| Expr::Unit), | 219 | map(parse_unit, |_| Expr::Unit), |
@@ -254,7 +277,8 @@ fn parse_type<'a>(i: &'a str) -> IResult<&'a str, Type> { | |||
254 | let int = value(Type::Integer, tag("int")); | 277 | let int = value(Type::Integer, tag("int")); |
255 | let string = value(Type::String, tag("string")); | 278 | let string = value(Type::String, tag("string")); |
256 | let bool_ = value(Type::Boolean, tag("bool")); | 279 | let bool_ = value(Type::Boolean, tag("bool")); |
257 | alt((int, string, bool_)).parse(i) | 280 | let list = value(Type::List, tag("list")); |
281 | alt((int, string, bool_, list)).parse(i) | ||
258 | } | 282 | } |
259 | 283 | ||
260 | fn parse_declaration<'a>(i: &'a str) -> IResult<&'a str, Declaration> { | 284 | fn parse_declaration<'a>(i: &'a str) -> IResult<&'a str, Declaration> { |
@@ -510,6 +534,27 @@ mod test { | |||
510 | ) | 534 | ) |
511 | )) | 535 | )) |
512 | ); | 536 | ); |
537 | assert_eq!( | ||
538 | parse_expr("a[0]"), | ||
539 | Ok(( | ||
540 | "", | ||
541 | Expr::Index(Expr::Ident("a".to_owned()).boxed(), Expr::int(0).boxed()) | ||
542 | )) | ||
543 | ); | ||
544 | assert_eq!( | ||
545 | parse_expr("children(node)[0]"), | ||
546 | Ok(( | ||
547 | "", | ||
548 | Expr::Index( | ||
549 | Expr::Call(Call { | ||
550 | function: "children".to_owned(), | ||
551 | parameters: vec![Expr::Node] | ||
552 | }) | ||
553 | .boxed(), | ||
554 | Expr::int(0).boxed() | ||
555 | ) | ||
556 | )) | ||
557 | ); | ||
513 | } | 558 | } |
514 | 559 | ||
515 | #[test] | 560 | #[test] |
@@ -544,6 +589,22 @@ mod test { | |||
544 | }) | 589 | }) |
545 | )) | 590 | )) |
546 | ); | 591 | ); |
592 | assert_eq!( | ||
593 | parse_statement(r#"list a =["a", "b", "c"]; "#), | ||
594 | Ok(( | ||
595 | "", | ||
596 | Statement::Declaration(Declaration { | ||
597 | ty: Type::List, | ||
598 | name: "a".to_owned(), | ||
599 | init: Some( | ||
600 | Expr::List(List { | ||
601 | items: vec![Expr::str("a"), Expr::str("b"), Expr::str("c"),] | ||
602 | }) | ||
603 | .boxed() | ||
604 | ) | ||
605 | }) | ||
606 | )) | ||
607 | ); | ||
547 | } | 608 | } |
548 | 609 | ||
549 | #[test] | 610 | #[test] |
@@ -624,6 +685,49 @@ mod test { | |||
624 | ); | 685 | ); |
625 | } | 686 | } |
626 | 687 | ||
688 | #[test] | ||
689 | fn test_parse_index() { | ||
690 | assert_eq!( | ||
691 | parse_expr( | ||
692 | r#" | ||
693 | a[0] | ||
694 | "# | ||
695 | ), | ||
696 | Ok(( | ||
697 | "", | ||
698 | Expr::Index(Expr::Ident("a".to_owned()).boxed(), Expr::int(0).boxed()), | ||
699 | )) | ||
700 | ); | ||
701 | assert_eq!( | ||
702 | parse_expr(r#"node.children[idx]"#), | ||
703 | Ok(( | ||
704 | "", | ||
705 | Expr::Index( | ||
706 | Expr::FieldAccess(Expr::Node.boxed(), Identifier::from("children")).boxed(), | ||
707 | Expr::Ident("idx".to_owned()).boxed() | ||
708 | ) | ||
709 | )) | ||
710 | ); | ||
711 | assert_eq!( | ||
712 | parse_expr(r#"foo[i].bar[j]"#), | ||
713 | Ok(( | ||
714 | "", | ||
715 | Expr::Index( | ||
716 | Expr::FieldAccess( | ||
717 | Expr::Index( | ||
718 | Expr::Ident("foo".to_owned()).boxed(), | ||
719 | Expr::Ident("i".to_owned()).boxed() | ||
720 | ) | ||
721 | .boxed(), | ||
722 | "bar".to_owned() | ||
723 | ) | ||
724 | .boxed(), | ||
725 | Expr::Ident("j".to_owned()).boxed() | ||
726 | ), | ||
727 | )) | ||
728 | ); | ||
729 | } | ||
730 | |||
627 | // #[test] | 731 | // #[test] |
628 | // fn test_skip_query() { | 732 | // fn test_skip_query() { |
629 | // assert_eq!( | 733 | // assert_eq!( |