An example of how to use nom
to create parsers in Rust
Last active
January 9, 2023 22:48
-
-
Save lmammino/0c3e7e6dbaf41303d1059c6a279c59d1 to your computer and use it in GitHub Desktop.
Simple example of using nom, Rust parser combinator
This file contains 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
[package] | |
name = "learning-nom" | |
version = "0.1.0" | |
edition = "2021" | |
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
[dependencies] | |
nom = "7.1.2" |
This file contains 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 | |
use nom::{ | |
branch::permutation, | |
bytes::complete::tag_no_case, | |
character::complete::{alpha1, digit1, space0}, | |
combinator::{map_res, opt}, | |
sequence::tuple, | |
IResult, | |
}; | |
#[derive(Debug)] | |
struct Person { | |
name: String, | |
age: u8, | |
language: String, | |
} | |
fn and_parser(input: &str) -> IResult<&str, ()> { | |
let (input, _) = opt(tag_no_case(" and "))(input)?; | |
Ok((input, ())) | |
} | |
fn age_parser(input: &str) -> IResult<&str, u8> { | |
let (input, _) = and_parser(input)?; | |
let (input, _) = tuple((space0, tag_no_case("i am ")))(input)?; | |
let (input, age) = map_res(digit1, |x: &str| x.parse::<u8>())(input)?; | |
let (input, _) = tag_no_case(" years old")(input)?; | |
Ok((input, age)) | |
} | |
fn language_parse(input: &str) -> IResult<&str, String> { | |
let (input, _) = and_parser(input)?; | |
let (input, _) = tuple((space0, tag_no_case("i like ")))(input)?; | |
let (input, language) = alpha1(input)?; | |
Ok((input, language.to_string())) | |
} | |
fn name_parser(input: &str) -> IResult<&str, String> { | |
let (input, _) = and_parser(input)?; | |
let (input, _) = tuple((space0, tag_no_case("my name is ")))(input)?; | |
let (input, name) = alpha1(input)?; | |
Ok((input, name.to_string())) | |
} | |
fn parse_person(input: &str) -> IResult<&str, Person> { | |
let (input, _) = tag_no_case("Hello, ")(input)?; | |
let (input, (name, age, language)) = | |
permutation((name_parser, age_parser, language_parse))(input)?; | |
Ok(( | |
input, | |
Person { | |
name, | |
age, | |
language, | |
}, | |
)) | |
} | |
fn main() { | |
let testdata = [ | |
"Hello, my name is Tommaso and i am 32 years old and I like Rust", | |
"Hello, my name is Roberto and i like Python and I am 44 years old", | |
"Hello, I like JavaScript my name is Luciano I am 35 years old", | |
]; | |
for input in testdata.iter() { | |
let (_, person) = parse_person(input).unwrap(); | |
println!("{:?}", person); | |
} | |
// Outputs: | |
// Person { name: "Tommaso", age: 32, language: "Rust" } | |
// Person { name: "Roberto", age: 44, language: "Python" } | |
// Person { name: "Luciano", age: 35, language: "JavaScript" } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment