1pub use nom::types::CompleteByteSlice;
2
3use crate::ast::{Block, Node};
4use nom::{alt, call, complete, do_parse, eof, is_not, many0, many_till, map, preceded, tag};
5
6const ALLOWED: &'static str = "<>+-.,[]";
7
8pub fn bf_skip_unknown<T>(i: T) -> nom::IResult<T, T, u32>
9 where T: nom::InputTake+nom::InputTakeAtPosition+Copy,
10 &'static str: nom::FindToken<<T as nom::InputTakeAtPosition>::Item> {
11 is_not!(i, ALLOWED).or_else(|e| match e {
12 nom::Err::Incomplete(size) => Err(nom::Err::Incomplete(size)),
13 _ => Ok((i, i.take(0))),
14 })
15}
16
17pub fn bf_skip_unknown_no_incomplete<T>(i: T) -> nom::IResult<T, T, u32>
18 where T: nom::InputTake+nom::InputTakeAtPosition+Copy,
19 &'static str: nom::FindToken<<T as nom::InputTakeAtPosition>::Item> {
20 bf_skip_unknown(i).or(Ok((i, i.take(0))))
21}
22
23macro_rules! bf_tag (
24 ($i: expr, $tag: expr) => ({
25 do_parse!($i,
26 bf_skip_unknown >>
27 res: tag!($tag) >>
28 bf_skip_unknown_no_incomplete >>
29 (res)
30 )
31 });
32);
33
34macro_rules! bf_named {
35 (pub $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => (
36 fn $name<T>( i: T ) -> nom::IResult<T, $o, u32>
37 where T: nom::InputTake+nom::InputTakeAtPosition+nom::AtEof+nom::Compare<&'static str>+Copy+PartialEq,
38 &'static str: nom::FindToken<<T as nom::InputTakeAtPosition>::Item> {
39 $submac!(i, $($args)*)
40 }
41 );
42}
43
44bf_named!(pub lshift<Node>, do_parse!(bf_tag!("<") >> (Node::LShift)));
45bf_named!(pub rshift<Node>, do_parse!(bf_tag!(">") >> (Node::RShift)));
46bf_named!(pub plus<Node>, do_parse!(bf_tag!("+") >> (Node::Inc)));
47bf_named!(pub minus<Node>, do_parse!(bf_tag!("-") >> (Node::Dec)));
48bf_named!(pub dot<Node>, do_parse!(bf_tag!(".") >> (Node::PutCh)));
49bf_named!(pub comma<Node>, do_parse!(bf_tag!(",") >> (Node::GetCh)));
50bf_named!(pub parse_loop<Node>, preceded!(bf_tag!("["), map!(many_till!(call!(node), bf_tag!("]")), |(nodes, _)| Node::Loop(From::from(nodes)))));
51bf_named!(pub node<Node>, alt!(lshift | rshift | plus | minus | dot | comma | parse_loop));
52
53pub fn parse<T>(i: T) -> Result<Block, nom::Err<T, u32>>
54 where T: nom::InputTake+nom::InputTakeAtPosition+nom::InputLength+nom::AtEof+nom::Compare<&'static str>+Copy+PartialEq,
55 &'static str: nom::FindToken<<T as nom::InputTakeAtPosition>::Item> {
56 do_parse!(i,
57 res: map!(many0!(complete!(node)), From::from) >>
58 eof!() >>
59 (res)
60 ).map(|(_, block)| block)
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 use crate::ast::{Block, Node};
68 use nom::{self, Needed};
69
70 const EMPTY: &'static [u8] = b"";
71
72 #[test]
73 fn test_lshift() {
74 assert_eq!(lshift(&b"<"[..]), Ok((EMPTY, Node::LShift)));
75 assert_eq!(lshift(&b"a"[..]), Err(nom::Err::Incomplete(Needed::Size(1))));
76 assert_eq!(lshift(&b"a<b"[..]), Ok((&b"b"[..], Node::LShift)));
77 }
78
79 #[test]
80 fn test_rshift() {
81 assert_eq!(rshift(&b">"[..]), Ok((EMPTY, Node::RShift)));
82 assert_eq!(rshift(&b"a"[..]), Err(nom::Err::Incomplete(Needed::Size(1))));
83 assert_eq!(rshift(&b"a>b"[..]), Ok((&b"b"[..], Node::RShift)));
84 }
85
86 #[test]
87 fn test_plus() {
88 assert_eq!(plus(&b"+"[..]), Ok((EMPTY, Node::Inc)));
89 assert_eq!(plus(&b"a"[..]), Err(nom::Err::Incomplete(Needed::Size(1))));
90 assert_eq!(plus(&b"a+b"[..]), Ok((&b"b"[..], Node::Inc)));
91 }
92
93 #[test]
94 fn test_minus() {
95 assert_eq!(minus(&b"-"[..]), Ok((EMPTY, Node::Dec)));
96 assert_eq!(minus(&b"a"[..]), Err(nom::Err::Incomplete(Needed::Size(1))));
97 assert_eq!(minus(&b"a-b"[..]), Ok((&b"b"[..], Node::Dec)));
98 }
99
100 #[test]
101 fn test_dot() {
102 assert_eq!(dot(&b"."[..]), Ok((EMPTY, Node::PutCh)));
103 assert_eq!(dot(&b"a"[..]), Err(nom::Err::Incomplete(Needed::Size(1))));
104 assert_eq!(dot(&b"a.b"[..]), Ok((&b"b"[..], Node::PutCh)));
105 }
106
107 #[test]
108 fn test_comma() {
109 assert_eq!(comma(&b","[..]), Ok((EMPTY, Node::GetCh)));
110 assert_eq!(comma(&b"a"[..]), Err(nom::Err::Incomplete(Needed::Size(1))));
111 assert_eq!(comma(&b"a,b"[..]), Ok((&b"b"[..], Node::GetCh)));
112 }
113
114 #[test]
115 fn test_parse_loop() {
116 let nodes1 = vec![Node::RShift, Node::Inc, Node::LShift, Node::PutCh];
117 let nodes2 = vec![Node::RShift, Node::Inc, Node::LShift, Node::PutCh];
118 assert_eq!(parse_loop(&b"[>+<.]"[..]), Ok((EMPTY, Node::Loop(From::from(nodes1)))));
119 assert_eq!(parse_loop(&b"a"[..]), Err(nom::Err::Incomplete(Needed::Size(1))));
120 assert_eq!(parse_loop(&b"a[ b> +e<//.'r]@"[..]), Ok((&b"@"[..], Node::Loop(From::from(nodes2)))));
121 }
122
123 #[test]
124 fn test_parse_nested_loop() {
125 let iinodes = vec![Node::Inc, Node::LShift];
126 let inodes = vec![Node::RShift, Node::Loop(From::from(iinodes)), Node::Dec];
127 let nodes = vec![Node::GetCh, Node::Loop(From::from(inodes)), Node::PutCh];
128 assert_eq!(parse_loop(&b"[,[>[+<]-].]"[..]), Ok((EMPTY, Node::Loop(From::from(nodes)))));
129 }
130
131 #[test]
132 fn test_node() {
133 let nodes = vec![Node::RShift, Node::Inc, Node::LShift, Node::PutCh];
134 assert_eq!(node(&b"<"[..]), Ok((EMPTY, Node::LShift)));
135 assert_eq!(node(&b">"[..]), Ok((EMPTY, Node::RShift)));
136 assert_eq!(node(&b"+"[..]), Ok((EMPTY, Node::Inc)));
137 assert_eq!(node(&b"-"[..]), Ok((EMPTY, Node::Dec)));
138 assert_eq!(node(&b"."[..]), Ok((EMPTY, Node::PutCh)));
139 assert_eq!(node(&b","[..]), Ok((EMPTY, Node::GetCh)));
140 assert_eq!(node(&b"[>+<.]"[..]), Ok((EMPTY, Node::Loop(From::from(nodes)))));
141 assert_eq!(node(&b"a"[..]), Err(nom::Err::Incomplete(Needed::Size(1))));
142 }
143
144 #[test]
145 fn test_parse() {
146 let mut block = Block::new();
147 block.push(Node::Loop(From::from(vec![Node::LShift, Node::RShift])));
148 block.push(Node::PutCh);
149 assert_eq!(parse(CompleteByteSlice(&b"abc[<>]."[..])), Ok(block));
150 assert_eq!(parse(CompleteByteSlice(EMPTY)), Ok(Block::new()));
151 }
152}