You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
322 lines
7.5 KiB
322 lines
7.5 KiB
/*
|
|
#[macro_use]
|
|
extern crate nom;
|
|
extern crate bytes;
|
|
|
|
use nom::{Compare,CompareResult,InputLength,InputIter,Slice,HexDisplay};
|
|
|
|
use std::str;
|
|
use std::str::FromStr;
|
|
use bytes::{Buf,MutBuf};
|
|
use bytes::buf::{BlockBuf,BlockBufCursor};
|
|
use std::ops::{Range,RangeTo,RangeFrom,RangeFull};
|
|
use std::iter::{Enumerate,Iterator};
|
|
use std::fmt;
|
|
use std::cmp::{min,PartialEq};
|
|
|
|
#[derive(Clone,Copy)]
|
|
#[repr(C)]
|
|
pub struct BlockSlice<'a> {
|
|
buf: &'a BlockBuf,
|
|
start: usize,
|
|
end: usize,
|
|
}
|
|
|
|
impl<'a> BlockSlice<'a> {
|
|
fn cursor(&self) -> WrapCursor<'a> {
|
|
let mut cur = self.buf.buf();
|
|
cur.advance(self.start);
|
|
WrapCursor {
|
|
cursor: cur,
|
|
length: self.end - self.start,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> fmt::Debug for BlockSlice<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "BlockSlice {{ start: {}, end: {}, data:\n{}\n}}", self.start, self.end, self.buf.bytes().unwrap_or(&b""[..]).to_hex(16))
|
|
}
|
|
}
|
|
|
|
impl<'a> PartialEq for BlockSlice<'a> {
|
|
fn eq(&self, other: &BlockSlice<'a>) -> bool {
|
|
let bufs = (self.buf as *const BlockBuf) == (other.buf as *const BlockBuf);
|
|
self.start == other.start && self.end == other.end && bufs
|
|
}
|
|
}
|
|
|
|
impl<'a> Slice<Range<usize>> for BlockSlice<'a> {
|
|
fn slice(&self, range:Range<usize>) -> Self {
|
|
BlockSlice {
|
|
buf: self.buf,
|
|
start: self.start + range.start,
|
|
//FIXME: check for valid end here
|
|
end: self.start + range.end,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Slice<RangeTo<usize>> for BlockSlice<'a> {
|
|
fn slice(&self, range:RangeTo<usize>) -> Self {
|
|
self.slice(0..range.end)
|
|
}
|
|
}
|
|
|
|
impl<'a> Slice<RangeFrom<usize>> for BlockSlice<'a> {
|
|
fn slice(&self, range:RangeFrom<usize>) -> Self {
|
|
self.slice(range.start..self.end - self.start)
|
|
}
|
|
}
|
|
|
|
impl<'a> Slice<RangeFull> for BlockSlice<'a> {
|
|
fn slice(&self, _:RangeFull) -> Self {
|
|
BlockSlice {
|
|
buf: self.buf,
|
|
start: self.start,
|
|
end: self.end,
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl<'a> InputIter for BlockSlice<'a> {
|
|
type Item = u8;
|
|
type RawItem = u8;
|
|
type Iter = Enumerate<WrapCursor<'a>>;
|
|
type IterElem = WrapCursor<'a>;
|
|
|
|
fn iter_indices(&self) -> Self::Iter {
|
|
self.cursor().enumerate()
|
|
}
|
|
fn iter_elements(&self) -> Self::IterElem {
|
|
self.cursor()
|
|
}
|
|
fn position<P>(&self, predicate: P) -> Option<usize> where P: Fn(Self::RawItem) -> bool {
|
|
self.cursor().position(|b| predicate(b))
|
|
}
|
|
fn slice_index(&self, count:usize) -> Option<usize> {
|
|
if self.end - self.start >= count {
|
|
Some(count)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl<'a> InputLength for BlockSlice<'a> {
|
|
fn input_len(&self) -> usize {
|
|
self.end - self.start
|
|
}
|
|
}
|
|
|
|
impl<'a,'b> Compare<&'b[u8]> for BlockSlice<'a> {
|
|
fn compare(&self, t: &'b[u8]) -> CompareResult {
|
|
let len = self.end - self.start;
|
|
let blen = t.len();
|
|
let m = if len < blen { len } else { blen };
|
|
let reduced = self.slice(..m);
|
|
let b = &t[..m];
|
|
|
|
for (a,b) in reduced.cursor().zip(b.iter()) {
|
|
if a != *b {
|
|
return CompareResult::Error;
|
|
}
|
|
}
|
|
if m < blen {
|
|
CompareResult::Incomplete
|
|
} else {
|
|
CompareResult::Ok
|
|
}
|
|
}
|
|
|
|
|
|
#[inline(always)]
|
|
fn compare_no_case(&self, t: &'b[u8]) -> CompareResult {
|
|
let len = self.end - self.start;
|
|
let blen = t.len();
|
|
let m = if len < blen { len } else { blen };
|
|
let reduced = self.slice(..m);
|
|
let other = &t[..m];
|
|
|
|
if !reduced.cursor().zip(other).all(|(a, b)| {
|
|
match (a,*b) {
|
|
(0...64, 0...64) | (91...96, 91...96) | (123...255, 123...255) => a == *b,
|
|
(65...90, 65...90) | (97...122, 97...122) | (65...90, 97...122 ) |(97...122, 65...90) => {
|
|
a & 0b01000000 == *b & 0b01000000
|
|
}
|
|
_ => false
|
|
}
|
|
}) {
|
|
CompareResult::Error
|
|
} else if m < blen {
|
|
CompareResult::Incomplete
|
|
} else {
|
|
CompareResult::Ok
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a,'b> Compare<&'b str> for BlockSlice<'a> {
|
|
fn compare(&self, t: &'b str) -> CompareResult {
|
|
self.compare(str::as_bytes(t))
|
|
}
|
|
fn compare_no_case(&self, t: &'b str) -> CompareResult {
|
|
self.compare_no_case(str::as_bytes(t))
|
|
}
|
|
}
|
|
|
|
//Wrapper to implement Iterator on BlockBufCursor
|
|
pub struct WrapCursor<'a> {
|
|
pub cursor: BlockBufCursor<'a>,
|
|
pub length: usize,
|
|
}
|
|
|
|
impl<'a> Iterator for WrapCursor<'a> {
|
|
type Item = u8;
|
|
fn next(&mut self) -> Option<u8> {
|
|
//println!("NEXT: length={}, remaining={}", self.length, self.cursor.remaining());
|
|
if min(self.length, self.cursor.remaining()) > 0 {
|
|
self.length -=1;
|
|
Some(self.cursor.read_u8())
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
//Reimplement eat_separator instead of fixing iterators
|
|
#[macro_export]
|
|
macro_rules! block_eat_separator (
|
|
($i:expr, $arr:expr) => (
|
|
{
|
|
use nom::{InputLength,InputIter,Slice};
|
|
if ($i).input_len() == 0 {
|
|
Ok(($i, ($i).slice(0..0)))
|
|
} else {
|
|
match ($i).iter_indices().position(|(_, item)| {
|
|
for (_,c) in ($arr).iter_indices() {
|
|
if *c == item { return false; }
|
|
}
|
|
true
|
|
}) {
|
|
Some(index) => {
|
|
Ok((($i).slice(index..), ($i).slice(..index)))
|
|
},
|
|
None => {
|
|
Ok((($i).slice(($i).input_len()..), $i))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
)
|
|
);
|
|
|
|
#[macro_export]
|
|
macro_rules! block_named (
|
|
($name:ident, $submac:ident!( $($args:tt)* )) => (
|
|
fn $name<'a>( i: BlockSlice<'a> ) -> nom::IResult<BlockSlice<'a>, BlockSlice<'a>, u32> {
|
|
$submac!(i, $($args)*)
|
|
}
|
|
);
|
|
($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => (
|
|
fn $name<'a>( i: BlockSlice<'a> ) -> nom::IResult<BlockSlice<'a>, $o, u32> {
|
|
$submac!(i, $($args)*)
|
|
}
|
|
);
|
|
);
|
|
|
|
block_named!(sp, block_eat_separator!(&b" \t\r\n"[..]));
|
|
|
|
macro_rules! block_ws (
|
|
($i:expr, $($args:tt)*) => (
|
|
{
|
|
sep!($i, sp, $($args)*)
|
|
}
|
|
)
|
|
);
|
|
|
|
block_named!(digit, is_a!("0123456789"));
|
|
|
|
block_named!(parens<i64>, block_ws!(delimited!( tag!("("), expr, tag!(")") )) );
|
|
|
|
|
|
block_named!(factor<i64>, alt!(
|
|
map_res!(
|
|
block_ws!(digit),
|
|
to_i64
|
|
)
|
|
| parens
|
|
)
|
|
);
|
|
|
|
block_named!(term <i64>, do_parse!(
|
|
init: factor >>
|
|
res: fold_many0!(
|
|
pair!(alt!(tag!("*") | tag!("/")), factor),
|
|
init,
|
|
|acc, (op, val): (BlockSlice, i64)| {
|
|
if (op.cursor().next().unwrap() as char) == '*' { acc * val } else { acc / val }
|
|
}
|
|
) >>
|
|
(res)
|
|
)
|
|
);
|
|
|
|
block_named!(expr <i64>, do_parse!(
|
|
init: term >>
|
|
res: fold_many0!(
|
|
pair!(alt!(tag!("+") | tag!("-")), term),
|
|
init,
|
|
|acc, (op, val): (BlockSlice, i64)| {
|
|
if (op.cursor().next().unwrap() as char) == '+' { acc + val } else { acc - val }
|
|
}
|
|
) >>
|
|
(res)
|
|
)
|
|
);
|
|
|
|
|
|
fn blockbuf_from(input: &[u8]) -> BlockBuf {
|
|
let mut b = BlockBuf::new(2, 100);
|
|
b.copy_from(input);
|
|
b
|
|
}
|
|
|
|
|
|
fn sl<'a>(input: &'a BlockBuf) -> BlockSlice<'a> {
|
|
BlockSlice {
|
|
buf: input,
|
|
start: 0,
|
|
end: input.len(),
|
|
}
|
|
}
|
|
|
|
fn to_i64<'a>(input: BlockSlice<'a>) -> Result<i64, ()> {
|
|
let v: Vec<u8> = input.cursor().collect();
|
|
|
|
match str::from_utf8(&v) {
|
|
Err(_) => Err(()),
|
|
Ok(s) => match FromStr::from_str(s) {
|
|
Err(_) => Err(()),
|
|
Ok(i) => Ok(i)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn factor_test() {
|
|
let a = blockbuf_from(&b"3"[..]);
|
|
println!("calculated: {:?}", factor(sl(&a)));
|
|
}
|
|
|
|
#[test]
|
|
fn parens_test() {
|
|
let input1 = blockbuf_from(&b" 2* ( 3 + 4 ) "[..]);
|
|
println!("calculated 1: {:?}", expr(sl(&input1)));
|
|
let input2 = blockbuf_from(&b" 2*2 / ( 5 - 1) + 3"[..]);
|
|
println!("calculated 2: {:?}", expr(sl(&input2)));
|
|
}
|
|
*/
|