Skip to content

Instantly share code, notes, and snippets.

@jaytaph
Last active May 4, 2024 15:56
Show Gist options
  • Save jaytaph/02cc00f46499c6c86f90f22d8775e5ba to your computer and use it in GitHub Desktop.
Save jaytaph/02cc00f46499c6c86f90f22d8775e5ba to your computer and use it in GitHub Desktop.
extern crate nom;
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::{char, multispace0},
combinator::{map, recognize},
multi::separated_list1,
sequence::delimited,
IResult,
};
use nom::character::complete::alphanumeric1;
use nom::multi::{many1, separated_list0};
#[derive(Debug)]
enum Component {
Value(String),
List(Vec<Component>),
DoubleList(Vec<Component>),
Group(Box<Component>),
}
fn parse_value(input: &str) -> IResult<&str, Component> {
println!("-> parse_value: {}", input);
let (input, result) = map(
recognize(many1(alt((alphanumeric1, tag("_"))))), // Accept alphanumeric characters and underscores
|s: &str| Component::Value(s.to_string())
)(input)?;
println!("<- parse_value: {:?}", result);
Ok((input, result))
}
fn parse_list_with_single_separator(input: &str) -> IResult<&str, Component> {
println!("-> parse_list_with_single_separator: {}", input);
let (input, first) = parse_group_value(input)?;
let (input, _) = delimited(multispace0, tag("|"), multispace0)(input)?;
let (input, mut rest) = separated_list0(delimited(multispace0, tag("|"), multispace0), parse_group_value)(input)?;
rest.insert(0, first);
println!("<- parse_list_with_single_separator: {:?}", rest);
Ok((input, Component::List(rest)))
}
fn parse_list_with_double_separator(input: &str) -> IResult<&str, Component> {
println!("-> parse_list_with_double_separator: {}", input);
let (input, first) = parse_group_value(input)?;
let (input, _) = delimited(multispace0, tag("||"), multispace0)(input)?;
let (input, mut rest) = separated_list0(delimited(multispace0, tag("||"), multispace0), parse_group_value)(input)?;
rest.insert(0, first);
println!("<- parse_list_with_double_separator: {:?}", rest);
Ok((input, Component::DoubleList(rest)))
}
fn parse_group(input: &str) -> IResult<&str, Component> {
println!("-> parse_group: {}", input);
let (input, result) = delimited(
delimited(multispace0, char('['), multispace0),
map(parse_expression, |c| Component::Group(Box::new(c))),
delimited(multispace0, char(']'), multispace0)
)(input)?;
println!("<- parse_group: {:?}", result);
Ok((input, result))
}
fn parse_group_value(input: &str) -> IResult<&str, Component> {
println!("-> parse_group_value: {}", input);
let (input, result) = alt((
parse_group,
parse_value,
))(input)?;
println!("<- parse_group_value: {:?}", result);
Ok((input, result))
}
fn parse_expression(input: &str) -> IResult<&str, Component> {
println!("-> parse_expression: {:?}", input);
let (input, result) = alt((
parse_list_with_double_separator,
parse_list_with_single_separator,
parse_group,
parse_value,
))(input)?;
println!("<- parse_expression: {:?}", result);
Ok((input, result))
}
fn main() {
let inputs = [
"123", // Component::Value("123")
"value1", // Component::Value("value1")
"value1 | value2", // Component::List([Component::Value("value1"), Component::Value("value2")])
"value1 | value2 | value3", // Component::List([Component::Value("value1"), Component::Value("value2"), Component::Value("value3")])
"value1 || value2 || value3", // Component::DoubleList([Component::Value("value1"), Component::Value("value2"), Component::Value("value3")])
"value1 || value2 | value3", // Fail due to mixed separators
"[value1 | value2 ]", // Component::Group([Component::List([Component::Value("value1"), Component::Value("value2")])])
"[value1 | [value2] ]", // Component::Group([Component::List([Component::Value("value1"), Component::Group([Component::Value("value2")])])])
"[value1 | value2 ] || value3", // Component::DoubleList([Component::Group([Component::List([Component::Value("value1"), Component::Value("value2")])]), Component::Value("value3")])
"[ [value1 | value2 ] || value3 ] | value4",
// Component::List([
// Component::Group([
// Component::DoubleList([
// Component::Group(
// Component::List[
// Component::Value("value1"),
// Component::Value("value2")
// ]),
// ]),
// Component::Value("value3")])
// ]),
// ]),
// Component::Value("value4")
// ])
];
for input in inputs.iter() {
println!("\n\nParsing: {}", input);
match parse_expression(input) {
Ok((_, component)) => println!("Parsed successfully: {:?}", component),
Err(e) => println!("Failed to parse '{}': {:?}", input, e),
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment