Select Git revision
Forked from
Per Lindgren / D7050E
11 commits behind the upstream repository.
Per Lindgren authored
main3.rs 8.78 KiB
use nom::{branch, bytes::complete::tag, character::complete::digit1, error, Err};
use nom_locate::LocatedSpan;
const INPUT: &str = "-2+3**2*3/5-4";
//const INPUT: &str = "2+-3";
//const INPUT: &str = "2+30000000000000000000000";
//const INPUT: &str = "2";
//const INPUT: &str = "30000000000000000000000";
//const INPUT: &str = "3+2a";
const UNARYS: [Funcmap; 1] = [Funcmap {
keyword: "-",
prec: 4,
ass: Ass::Right,
func: Function::UnSub,
}];
const INFIXS: [Funcmap; 5] = [
Funcmap {
keyword: "**",
prec: 3,
ass: Ass::Right,
func: Function::Pow,
},
Funcmap {
keyword: "*",
prec: 2,
ass: Ass::Left,
func: Function::Mult,
},
Funcmap {
keyword: "/",
prec: 2,
ass: Ass::Left,
func: Function::Div,
},
Funcmap {
keyword: "+",
prec: 1,
ass: Ass::Left,
func: Function::Add,
},
Funcmap {
keyword: "-",
prec: 1,
ass: Ass::Left,
func: Function::Sub,
},
];
struct Expr<'a> {
span: Span<'a>,
val: Value<'a>,
}
enum Value<'a> {
Int(i32),
UnFunc(Function, Box<Expr<'a>>),
Func(Function, Box<Expr<'a>>, Box<Expr<'a>>),
}
#[derive(Clone, Copy)]
enum Function {
UnSub,
Pow,
Mult,
Div,
Add,
Sub,
}
struct Funcmap {
keyword: &'static str,
prec: u8,
ass: Ass,
func: Function,
}
enum Ass {
Left,
Right,
}
type Span<'a> = LocatedSpan<&'a str>;
type SpanFuncmap<'a> = (Span<'a>, &'a Funcmap);
type IResult<'a, I, O, E = Error<'a>> = Result<(I, O), Err<E>>;
fn main() {
match parse(Span::new(INPUT)) {
Ok(tree) => {
println!("{:#?}", SimpleExpr::new(&tree));
}
Err(Error {
val: Some(val),
error,
..
}) => println!(
"{:#?} at line {}, column {}:\n\t{}",
error.description(),
val.line,
val.get_utf8_column(),
val.fragment,
),
Err(err) => panic!(err),
}
}
fn parse<'a>(input: Span) -> Result<Expr, Error> {
match parse_expr(input) {
Ok((Span { fragment: "", .. }, tree)) => Ok(tree),
Ok((input, _)) => Err(Error {
input: input,
val: Some(input),
error: ErrorKind::NotRecognised,
}),
Err(Err::Incomplete(_)) => Err(Error {
input: input,
val: Some(input),
error: ErrorKind::Incomplete,
}),
Err(Err::Error(err)) => Err(err),
Err(Err::Failure(err)) => Err(err),
}
}
fn parse_expr<'a>(input: Span) -> IResult<Span, Expr> {
branch::alt((parse_infix, parse_expr_nobin))(input)
}
fn parse_expr_nobin<'a>(input: Span) -> IResult<Span, Expr> {
branch::alt((parse_unary, parse_expr_nobin_noun))(input)
}
fn parse_expr_nobin_noun<'a>(input: Span) -> IResult<Span, Expr> {
parse_value(input)
}
fn parse_value(input: Span) -> IResult<Span, Expr> {
// More primitive type categories go here (branch::alt() if > 1):
parse_number(input)
}
fn parse_number(input: Span) -> IResult<Span, Expr> {
// More number types go here (branch::alt() if > 1):
parse_int(input)
}
fn parse_int(input: Span) -> IResult<Span, Expr> {
let (input, digits) = digit1(input)?;
let int = match digits.fragment.parse() {
Ok(int) => int,
Err(err) => {
return Err(Err::Failure(Error {
input,
val: Some(digits),
error: ErrorKind::ParseInt(err),
}))
}
};
Ok((
input,
Expr {
span: digits,
val: Value::Int(int),
},
))
}
fn parse_unary(input: Span) -> IResult<Span, Expr> {
let (input, (span, func_map)) = tag_unary(input)?;
let (input, right) = parse_expr_nobin(input)?;
Ok((
input,
Expr {
span,
val: Value::UnFunc(func_map.func, Box::new(right)),
},
))
}
fn parse_infix(input: Span) -> IResult<Span, Expr> {
// Initialize with minimum precedence 1.
parse_infix_first(input, 1)
}
fn parse_infix_first<'a>(input: Span, min_prec: u8) -> IResult<Span, Expr> {
// First, find left hand side expression. Search for everything but BinOps.
let (input, left) = parse_expr_nobin(input)?;
parse_infix_left(input, min_prec, left)
}
fn parse_infix_prec<'a>(input: Span, min_prec: u8) -> IResult<Span, Expr> {
// Almost identical to parse_infix_first(), but we do not accept unary ops.
let (input, left) = parse_expr_nobin_noun(input)?;
parse_infix_left(input, min_prec, left)
}
fn parse_infix_left<'a>(
input_bin: Span<'a>,
min_prec: u8,
left: Expr<'a>,
) -> IResult<'a, Span<'a>, Expr<'a>> {
// See if we can find an infix function. If not, return what we have.
let (input, (span, func_map)) = match tag_infix(input_bin) {
Ok(res) => res,
Err(Err::Error(Error { input, .. })) => return Ok((input, left)),
Err(err) => return Err(err),
};
// Does the new infix fulfill our precedence criteria?
if func_map.prec < min_prec {
return Ok((input_bin, left));
}
// Parse the right-hand-side.
let new_min_prec = match func_map.ass {
Ass::Left => func_map.prec + 1,
Ass::Right => func_map.prec,
};
let (input, right) = parse_infix_prec(input, new_min_prec)?;
// Put together the infix function with arguments. Continue forward.
let expr = Expr {
span,
val: Value::Func(func_map.func, Box::new(left), Box::new(right)),
};
parse_infix_left(input, min_prec, expr)
}
fn tag_unary(input: Span) -> IResult<Span, SpanFuncmap> {
tag_func(input, &UNARYS)
}
fn tag_infix(input: Span) -> IResult<Span, SpanFuncmap> {
tag_func(input, &INFIXS)
}
fn tag_func<'a>(input: Span<'a>, funcs: &'a [Funcmap]) -> IResult<'a, Span<'a>, SpanFuncmap<'a>> {
for func_map in funcs.iter() {
match tag(func_map.keyword)(input) {
Ok((input, span)) => return Ok((input, (span, &func_map))),
Err(Err::Error(_)) => (),
Err(err) => return Err(err),
}
}
Err(Err::Error(Error {
input,
val: None,
error: ErrorKind::Nom(error::ErrorKind::Tag),
}))
}
#[derive(Debug)]
enum SimpleExpr<'a> {
Int(&'a i32),
UnSub(Box<SimpleExpr<'a>>),
Pow(Box<SimpleExpr<'a>>, Box<SimpleExpr<'a>>),
Mult(Box<SimpleExpr<'a>>, Box<SimpleExpr<'a>>),
Div(Box<SimpleExpr<'a>>, Box<SimpleExpr<'a>>),
Add(Box<SimpleExpr<'a>>, Box<SimpleExpr<'a>>),
Sub(Box<SimpleExpr<'a>>, Box<SimpleExpr<'a>>),
}
impl<'a> SimpleExpr<'a> {
fn new(tree: &'a Expr) -> Self {
match tree {
Expr {
val: Value::Int(int),
..
} => SimpleExpr::Int(&int),
Expr {
val: Value::UnFunc(Function::UnSub, x),
..
} => SimpleExpr::UnSub(Box::new(SimpleExpr::new(x))),
Expr {
val: Value::Func(Function::Pow, x, y),
..
} => SimpleExpr::Pow(Box::new(SimpleExpr::new(x)), Box::new(SimpleExpr::new(y))),
Expr {
val: Value::Func(Function::Mult, x, y),
..
} => SimpleExpr::Mult(Box::new(SimpleExpr::new(x)), Box::new(SimpleExpr::new(y))),
Expr {
val: Value::Func(Function::Div, x, y),
..
} => SimpleExpr::Div(Box::new(SimpleExpr::new(x)), Box::new(SimpleExpr::new(y))),
Expr {
val: Value::Func(Function::Add, x, y),
..
} => SimpleExpr::Add(Box::new(SimpleExpr::new(x)), Box::new(SimpleExpr::new(y))),
Expr {
val: Value::Func(Function::Sub, x, y),
..
} => SimpleExpr::Sub(Box::new(SimpleExpr::new(x)), Box::new(SimpleExpr::new(y))),
_ => panic!(),
}
}
}
impl<'a> error::ParseError<Span<'a>> for Error<'a> {
fn from_error_kind(input: Span<'a>, kind: error::ErrorKind) -> Self {
Error {
input,
val: None,
error: ErrorKind::Nom(kind),
}
}
fn append(_: Span<'a>, _: error::ErrorKind, other: Self) -> Self {
other
}
}
struct Error<'a> {
input: Span<'a>,
val: Option<Span<'a>>,
error: ErrorKind,
}
enum ErrorKind {
NotRecognised,
Incomplete,
ParseInt(std::num::ParseIntError),
Nom(error::ErrorKind),
}
impl ErrorKind {
fn description(&self) -> String {
match self {
ErrorKind::NotRecognised => String::from("Failed to parse input."),
ErrorKind::Incomplete => String::from("There was not enough data."),
ErrorKind::ParseInt(err) => format!("Parse Int Error ({})", &err),
ErrorKind::Nom(err) => String::from(err.description()),
}
}
}