use std::str::FromStr;
use nom::branch::alt;
use nom::bytes::complete::{tag, take_while};
use nom::character::complete::{char as cchar, digit1, satisfy, space0};
use nom::combinator::{map, map_res, opt, recognize};
use nom::sequence::{preceded, tuple};
use nom::IResult;
#[derive(Debug, Clone, Copy)]
pub struct IntConstant(pub i64);
fn parse_int_constant(input: &str) -> IResult<&str, IntConstant> {
map_res(
recognize(tuple((opt(alt((tag("-"), tag("+")))), digit1))),
|d_str| -> Result<IntConstant, std::num::ParseIntError> {
let d = FromStr::from_str(d_str)?;
Ok(IntConstant(d))
},
)(input)
}
#[derive(Debug, Clone)]
pub struct Identifier(pub String);
fn parse_identifier(input: &str) -> IResult<&str, Identifier> {
map(
recognize(tuple((
opt(cchar('_')),
satisfy(|c| c.is_ascii_alphabetic()),
take_while(|c: char| c.is_ascii_alphanumeric() || c == '.' || c == '_'),
))),
|ident: &str| -> Identifier { Identifier(ident.to_string()) },
)(input)
}
#[derive(Debug, Clone)]
pub struct IntConstantExpr {
pub name: Identifier,
pub value: IntConstant,
}
fn parse_int_constant_expr(input: &str) -> IResult<&str, IntConstantExpr> {
map(
tuple((
tag("const"),
preceded(space0, parse_identifier),
preceded(space0, tag("=")),
preceded(space0, parse_int_constant),
)),
|(_, name, _, value)| -> IntConstantExpr { IntConstantExpr { name, value } },
)(input)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_identifier() {
assert_eq!(parse_identifier("_ihc123iah,").unwrap().1 .0, "_ihc123iah");
assert_eq!(parse_identifier("ihc123iah,").unwrap().1 .0, "ihc123iah");
assert!(parse_identifier("_123").is_err());
assert!(parse_identifier("_").is_err());
assert!(parse_identifier("123").is_err());
}
}
fn main() {
println!("{:?}", parse_int_constant("+123").unwrap().1);
println!("{:?}", parse_identifier("_My.N1me").unwrap().1);
println!("{:?}", parse_int_constant_expr("const aGe = +1").unwrap().1);
}