Last active
March 28, 2020 17:57
-
-
Save baetheus/c7d4525b0775fa7a752cc7afe31d052a to your computer and use it in GitHub Desktop.
Playing around with nom and parsing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use nom::{ | |
| branch::alt, | |
| bytes::complete::{tag, take_until, take_while}, | |
| character::{complete::line_ending, is_alphabetic}, | |
| combinator::{map, opt, rest}, | |
| sequence::tuple, | |
| IResult, | |
| }; | |
| use std::str::from_utf8; | |
| const FEAT_COMMIT: &str = r#"feat(my-feature): a good new feature | |
| This is some body text | |
| "#; | |
| const BREAKING_COMMIT: &str = r#"fix(my-feature)!: changed the api to work better | |
| This is some body text | |
| "#; | |
| #[derive(Debug, PartialEq, Eq)] | |
| enum CommitType { | |
| Feature, | |
| Fix, | |
| Other(String), | |
| } | |
| #[derive(Debug, PartialEq, Eq)] | |
| struct Commit { | |
| commit_type: CommitType, | |
| breaking_change: bool, | |
| scope: Option<String>, | |
| message: String, | |
| body: Option<String>, | |
| } | |
| // Hiding errors is bad practice | |
| fn from_utf8_string(input: &[u8]) -> Option<String> { | |
| match from_utf8(input).map(|s| s.to_string()) { | |
| Ok(s) => Some(s), | |
| _ => None, | |
| } | |
| } | |
| fn to_commit_type(input: &[u8]) -> String { | |
| from_utf8_string(input).unwrap_or("unknown".to_string()) | |
| } | |
| fn alpha(input: &[u8]) -> IResult<&[u8], &[u8]> { | |
| take_while(is_alphabetic)(input) | |
| } | |
| fn commit_type(input: &[u8]) -> IResult<&[u8], CommitType> { | |
| alt(( | |
| map(tag("feat"), |_| CommitType::Feature), | |
| map(tag("fix"), |_| CommitType::Fix), | |
| // While this is alphabetic, it's not necessarily utf8 | |
| // Consider shunting to error here or dropping Other's internal value. | |
| map(alpha, |r| CommitType::Other(to_commit_type(r))), | |
| ))(input) | |
| } | |
| fn commit_split(input: &[u8]) -> IResult<&[u8], &[u8]> { | |
| tag(": ")(input) | |
| } | |
| fn scope(input: &[u8]) -> IResult<&[u8], (&[u8], &[u8], &[u8])> { | |
| tuple((tag("("), take_until(")"), tag(")")))(input) | |
| } | |
| fn opt_scope(input: &[u8]) -> IResult<&[u8], Option<&[u8]>> { | |
| map(opt(scope), |o| o.map(|(_, m, _)| m))(input) | |
| } | |
| fn breaking_change(input: &[u8]) -> IResult<&[u8], bool> { | |
| map(opt(tag("!")), |o| o.is_some())(input) | |
| } | |
| fn rest_of_line(input: &[u8]) -> IResult<&[u8], &[u8]> { | |
| map(tuple((take_until("\n"), line_ending)), |(o, _)| o)(input) | |
| } | |
| fn body(input: &[u8]) -> IResult<&[u8], Option<&[u8]>> { | |
| opt(rest)(input) | |
| } | |
| // At some point we should deal with encoding. Somewhere around here is probably best | |
| fn commit(input: &[u8]) -> IResult<&[u8], Commit> { | |
| map( | |
| tuple(( | |
| commit_type, | |
| opt_scope, | |
| breaking_change, | |
| commit_split, | |
| rest_of_line, | |
| body, | |
| )), | |
| |(commit_type, scope, breaking_change, _, message, body)| Commit { | |
| commit_type, | |
| // Here is where chain/bind would be great | |
| scope: scope.map(from_utf8_string).flatten(), | |
| breaking_change, | |
| message: from_utf8_string(message).unwrap_or("No message".to_string()), | |
| body: body.map(from_utf8_string).flatten(), | |
| }, | |
| )(input) | |
| } | |
| fn main() { | |
| if let Ok(feat_result) = commit(FEAT_COMMIT.as_bytes()) { | |
| dbg!(feat_result); | |
| }; | |
| if let Ok(fix_result) = commit(BREAKING_COMMIT.as_bytes()) { | |
| dbg!(fix_result); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [src/main.rs:111] feat_result = ( | |
| [], | |
| Commit { | |
| commit_type: Feature, | |
| breaking_change: false, | |
| scope: Some( | |
| "my-feature", | |
| ), | |
| message: "a good new feature", | |
| body: Some( | |
| "\nThis is some body text\n", | |
| ), | |
| }, | |
| ) | |
| [src/main.rs:114] fix_result = ( | |
| [], | |
| Commit { | |
| commit_type: Fix, | |
| breaking_change: true, | |
| scope: Some( | |
| "my-feature", | |
| ), | |
| message: "changed the api to work better", | |
| body: Some( | |
| "\nThis is some body text\n", | |
| ), | |
| }, | |
| ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment