Skip to content
Snippets Groups Projects
Select Git revision
  • f55e0a2c8a81c32a96271f72595bad50fdfacbc2
  • master default protected
  • home_exam
  • wip
4 results

main3.rs

Blame
  • Forked from Per Lindgren / D7050E
    11 commits behind the upstream repository.
    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()),
            }
        }
    }