Skip to content

Instantly share code, notes, and snippets.

@remexre
Created February 5, 2017 06:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save remexre/5ca628a1390eebe262d43661459626d6 to your computer and use it in GitHub Desktop.
Save remexre/5ca628a1390eebe262d43661459626d6 to your computer and use it in GitHub Desktop.
use ::expr::Expr;
use nom::{hex_digit, oct_digit};
use num::{BigInt, ToPrimitive};
use std::mem;
named!(pub parse_number(&str) -> Expr, complete!(alt!(
based_number
)));
named!(foo(&str) -> &str, alt!(
tag!("foo")
| tag!("bar")
));
named!(based_number<&str, Expr>, alt!(
do_parse!(
tag!("0b") >>
digits: many1!(alt!(tag!("0"), tag!("1"))) >>
(parse_digits(digits, 2).unwrap())
) |
do_parse!(
tag!("0o") >>
digits: oct_digit >>
(parse_digits(digits, 8).unwrap())
) |
do_parse!(
tag!("0x") >>
digits: hex_digit >>
(parse_digits(digits, 16).unwrap())
)
));
struct BaseIter {
base: usize,
last: BigInt,
}
impl BaseIter {
pub fn new(base: usize) -> BaseIter {
BaseIter {
base: base,
last: BigInt::from(1),
}
}
}
impl Iterator for BaseIter {
type Item = BigInt;
fn next(&mut self) -> Option<BigInt> {
let mut next = &self.last * BigInt::from(self.base);
mem::swap(&mut next, &mut self.last);
Some(next)
}
}
fn parse_digit(c: char) -> Option<usize> {
match c {
'0' => Some( 0),
'1' => Some( 1),
'2' => Some( 2),
'3' => Some( 3),
'4' => Some( 4),
'5' => Some( 5),
'6' => Some( 6),
'7' => Some( 7),
'8' => Some( 8),
'9' => Some( 9),
'a' => Some(10),
'b' => Some(11),
'c' => Some(12),
'd' => Some(13),
'e' => Some(14),
'f' => Some(15),
_ => None,
}
}
fn parse_digits(s: &str, base: usize) -> Option<Expr> {
let digits = s.chars()
.flat_map(char::to_lowercase)
.map(|c| {
if let Some(n) = parse_digit(c) {
if n < base {
return Some(n)
}
}
None
})
.collect::<Option<Vec<_>>>();
digits.map(|mut digits| {
digits.reverse();
let n = digits.into_iter()
.map(BigInt::from)
.zip(BaseIter::new(base))
.map(|(d, n)| d*n)
.fold(BigInt::from(0), |l, r| l + r);
if let Some(n) = n.to_isize() {
Expr::Fixnum(n)
} else {
Expr::Bignum(n)
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment