diff options
Diffstat (limited to 'src/parser.rs')
-rw-r--r-- | src/parser.rs | 58 |
1 files changed, 55 insertions, 3 deletions
diff --git a/src/parser.rs b/src/parser.rs index 3a020dc..d705a11 100644 --- a/src/parser.rs +++ b/src/parser.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | use nom::{ | 1 | use nom::{ |
2 | branch::alt, | 2 | branch::alt, |
3 | bytes::complete::tag, | 3 | bytes::complete::{is_not, tag}, |
4 | character::complete::{alpha1, alphanumeric1, char, multispace0, multispace1, one_of}, | 4 | character::complete::{alpha1, alphanumeric1, char, multispace0, multispace1, one_of}, |
5 | combinator::{map, opt, recognize, value}, | 5 | combinator::{map, opt, recognize, value}, |
6 | error::ParseError, | 6 | error::ParseError, |
7 | multi::{many0, many0_count, many1, separated_list0}, | 7 | multi::{many0, many0_count, many1, separated_list0, separated_list1}, |
8 | sequence::{delimited, pair, preceded, terminated, tuple}, | 8 | sequence::{delimited, pair, preceded, terminated, tuple}, |
9 | IResult, Parser, | 9 | IResult, Parser, |
10 | }; | 10 | }; |
@@ -21,6 +21,11 @@ where | |||
21 | delimited(multispace0, inner, multispace0) | 21 | delimited(multispace0, inner, multispace0) |
22 | } | 22 | } |
23 | 23 | ||
24 | // TODO use this | ||
25 | fn _parse_comment<'a>(i: &'a str) -> IResult<&'a str, ()> { | ||
26 | value((), pair(tag("//"), is_not("\n\r")))(i) | ||
27 | } | ||
28 | |||
24 | fn parse_unit<'a>(i: &'a str) -> IResult<&'a str, ()> { | 29 | fn parse_unit<'a>(i: &'a str) -> IResult<&'a str, ()> { |
25 | let open = char('('); | 30 | let open = char('('); |
26 | let close = char(')'); | 31 | let close = char(')'); |
@@ -169,8 +174,16 @@ fn parse_mul<'a>(i: &'a str) -> IResult<&'a str, Expr> { | |||
169 | alt((recursive, base)).parse(i) | 174 | alt((recursive, base)).parse(i) |
170 | } | 175 | } |
171 | 176 | ||
177 | fn parse_field_access<'a>(i: &'a str) -> IResult<&'a str, Vec<Identifier>> { | ||
178 | let node = tag("node"); | ||
179 | let dot = ws(char('.')); | ||
180 | let fields = separated_list1(ws(char('.')), map(parse_name, str::to_owned)); | ||
181 | map(tuple((node, dot, fields)), |(_, _, fields)| fields)(i) | ||
182 | } | ||
183 | |||
172 | fn parse_atom<'a>(i: &'a str) -> IResult<&'a str, Expr> { | 184 | fn parse_atom<'a>(i: &'a str) -> IResult<&'a str, Expr> { |
173 | let inner = alt(( | 185 | let inner = alt(( |
186 | map(parse_field_access, Expr::FieldAccess), | ||
174 | map(tag("node"), |_| Expr::Node), | 187 | map(tag("node"), |_| Expr::Node), |
175 | map(parse_block, Expr::Block), | 188 | map(parse_block, Expr::Block), |
176 | map(parse_if, Expr::IfExpr), | 189 | map(parse_if, Expr::IfExpr), |
@@ -337,7 +350,7 @@ fn parse_pattern<'a>(i: &str) -> IResult<&str, Pattern> { | |||
337 | tuple((parse_modifier, multispace0, parse_ident)), | 350 | tuple((parse_modifier, multispace0, parse_ident)), |
338 | |(modifier, _, kind)| Pattern::Node(NodePattern { modifier, kind }), | 351 | |(modifier, _, kind)| Pattern::Node(NodePattern { modifier, kind }), |
339 | ); | 352 | ); |
340 | alt((begin, end, node)).parse(i) | 353 | ws(alt((begin, end, node))).parse(i) |
341 | } | 354 | } |
342 | 355 | ||
343 | pub fn parse_stanza<'a>(i: &str) -> IResult<&str, Stanza> { | 356 | pub fn parse_stanza<'a>(i: &str) -> IResult<&str, Stanza> { |
@@ -358,6 +371,25 @@ pub fn parse_file(i: &str) -> IResult<&str, Vec<Stanza>> { | |||
358 | mod test { | 371 | mod test { |
359 | use super::*; | 372 | use super::*; |
360 | 373 | ||
374 | // test helpers | ||
375 | impl Expr { | ||
376 | pub fn int(int: i128) -> Expr { | ||
377 | Self::Lit(Literal::Int(int)) | ||
378 | } | ||
379 | |||
380 | pub fn str(s: &str) -> Expr { | ||
381 | Self::Lit(Literal::Str(s.to_owned())) | ||
382 | } | ||
383 | |||
384 | pub const fn false_() -> Expr { | ||
385 | Self::Lit(Literal::Bool(false)) | ||
386 | } | ||
387 | |||
388 | pub const fn true_() -> Expr { | ||
389 | Self::Lit(Literal::Bool(true)) | ||
390 | } | ||
391 | } | ||
392 | |||
361 | #[test] | 393 | #[test] |
362 | fn test_parse_unit() { | 394 | fn test_parse_unit() { |
363 | assert_eq!(parse_unit("()"), Ok(("", ()))) | 395 | assert_eq!(parse_unit("()"), Ok(("", ()))) |
@@ -535,6 +567,26 @@ mod test { | |||
535 | } | 567 | } |
536 | 568 | ||
537 | #[test] | 569 | #[test] |
570 | fn test_parse_node() { | ||
571 | assert_eq!(parse_expr(r#" node "#), Ok(("", Expr::Node))); | ||
572 | assert_eq!( | ||
573 | parse_expr(r#" node.foo "#), | ||
574 | Ok(("", Expr::FieldAccess(vec!["foo".to_owned()]))) | ||
575 | ); | ||
576 | assert_eq!( | ||
577 | parse_expr( | ||
578 | r#" node | ||
579 | .foo | ||
580 | .bar"# | ||
581 | ), | ||
582 | Ok(( | ||
583 | "", | ||
584 | Expr::FieldAccess(vec!["foo".to_owned(), "bar".to_owned()]) | ||
585 | )) | ||
586 | ); | ||
587 | } | ||
588 | |||
589 | #[test] | ||
538 | fn test_parse_if() { | 590 | fn test_parse_if() { |
539 | assert_eq!( | 591 | assert_eq!( |
540 | parse_expr( | 592 | parse_expr( |