Created
August 4, 2017 09:59
-
-
Save emersion/26c1a90866e95728ce1e358a921e8eca to your computer and use it in GitHub Desktop.
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
#[macro_use] | |
extern crate nom; | |
use nom::{IResult,digit}; | |
// Parser definition | |
use std::str; | |
use std::str::FromStr; | |
#[derive(Debug)] | |
enum Expr { | |
Value(i64), | |
Op { | |
op: char, | |
left: Box<Expr>, | |
right: Box<Expr>, | |
}, | |
} | |
// We parse any expr surrounded by parens, ignoring all whitespaces around those | |
named!(parens<Expr>, ws!(delimited!( tag!("("), expr, tag!(")") )) ); | |
// We transform an integer string into a i64, ignoring surrounding whitespaces | |
// We look for a digit suite, and try to convert it. | |
// If either str::from_utf8 or FromStr::from_str fail, | |
// we fallback to the parens parser defined above | |
named!(factor<Expr>, alt!( | |
map!( | |
map_res!( | |
map_res!( | |
ws!(digit), | |
str::from_utf8 | |
), | |
FromStr::from_str | |
), | |
|i| Expr::Value(i) | |
) | |
| parens | |
) | |
); | |
// We read an initial factor and for each time we find | |
// a * or / operator followed by another factor, we do | |
// the math by folding everything | |
named!(term <Expr>, do_parse!( | |
init: factor >> | |
res: fold_many0!( | |
pair!(alt!(tag!("*") | tag!("/")), factor), | |
init, | |
|acc, (op, val): (&[u8], Expr)| { | |
Expr::Op{ | |
op: op[0] as char, | |
left: Box::new(acc), | |
right: Box::new(val), | |
} | |
} | |
) >> | |
(res) | |
) | |
); | |
named!(expr <Expr>, do_parse!( | |
init: term >> | |
res: fold_many0!( | |
pair!(alt!(tag!("+") | tag!("-")), term), | |
init, | |
|acc, (op, val): (&[u8], Expr)| { | |
Expr::Op{ | |
op: op[0] as char, | |
left: Box::new(acc), | |
right: Box::new(val), | |
} | |
} | |
) >> | |
(res) | |
) | |
); | |
fn main() { | |
let e = expr(b"1+2*3+4").unwrap(); | |
println!("{:?}", e); | |
// assert_eq!(expr(b"1+2"), IResult::Done(&b""[..], 3)); | |
// assert_eq!(expr(b"12+6-4+3"), IResult::Done(&b""[..], 17)); | |
// assert_eq!(expr(b"1+2*3+4"), IResult::Done(&b""[..], 11)); | |
// | |
// assert_eq!(expr(b"(2)"), IResult::Done(&b""[..], 2)); | |
// assert_eq!(expr(b"2*(3+4)"), IResult::Done(&b""[..], 14)); | |
// assert_eq!(expr(b"2*2/(5-1)+3"), IResult::Done(&b""[..], 4)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment