yabfi/
lib.rs

1mod api;
2pub mod context;
3pub mod error;
4pub mod io_traits;
5pub mod parser;
6
7pub use api::*;
8
9pub mod prelude {
10    pub use super::context::*;
11    pub use super::error::*;
12    pub use super::io_traits::*;
13    pub use super::parser::Expression;
14}
15
16#[cfg(test)]
17mod test {
18    use crate::prelude::*;
19    use std::{error::Error, fmt::Display};
20
21    #[derive(Debug)]
22    struct TestError(String);
23
24    impl Display for TestError {
25        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26            self.0.fmt(f)
27        }
28    }
29
30    impl Error for TestError {}
31
32    impl BfInStream<TestError> for Vec<u8> {
33        fn bf_read(&mut self) -> Result<u8, TestError> {
34            Ok(self.remove(0))
35        }
36    }
37
38    impl BfOutStream<TestError> for Vec<u8> {
39        fn bf_write(&mut self, byte: u8) -> Result<(), TestError> {
40            Ok(self.push(byte))
41        }
42    }
43
44    #[test]
45    fn hello_world() {
46        let code = "\
47        'H' >++++++++[<+++++++++>-]<.\n\
48        'e' >++++[<+++++++>-]<+.\n\
49        'l' +++++++.\n\
50        'l' .\n\
51        'o' +++.\n\
52        comma  >>++++++[<+++++++>-]<++.\n\
53        ' ' ------------.\n\
54        'W' >++++++[<+++++++++>-]<+.\n\
55        'o' <.\n\
56        'r' +++.\n\
57        'l' ------.\n\
58        'd' --------.\n\
59        '!' >>>++++[<++++++++>-]<+.\n\
60        reading 4 chars >>>++++[>,.<-]";
61
62        #[rustfmt::skip]
63        let correct_parse = {
64            use crate::parser::Expression::{
65                Comment,
66                Decrement as Dec,
67                Increment as Inc,
68                Input as In,
69                Output as Out,
70                Loop, Next, Prev
71            };
72            [
73                Comment("'H' ".to_string()),
74                Next,
75                Inc, Inc, Inc, Inc, Inc, Inc, Inc, Inc,
76                Loop(vec![
77                    Prev,
78                    Inc, Inc, Inc, Inc, Inc, Inc, Inc, Inc, Inc,
79                    Next, Dec,
80                ]),
81                Prev, Out,
82
83                Comment("\n'e' ".to_string()),
84                Next,
85                Inc,
86                Inc,
87                Inc,
88                Inc,
89                Loop(vec![
90                    Prev,
91                    Inc, Inc, Inc, Inc, Inc, Inc, Inc,
92                    Next, Dec,
93                ]),
94                Prev, Inc, Out,
95
96                Comment("\n'l' ".to_string()),
97                Inc, Inc, Inc, Inc, Inc, Inc, Inc,
98                Out,
99                
100                Comment("\n'l' ".to_string()),
101                Out,
102
103                Comment("\n'o' ".to_string()),
104                Inc, Inc, Inc,
105                Out,
106                
107                Comment("\ncomma  ".to_string()),
108                Next, Next,
109                Inc, Inc, Inc, Inc, Inc, Inc,
110                Loop(vec![
111                    Prev, Inc, Inc, Inc, Inc, Inc, Inc,
112                    Inc, Next, Dec,
113                ]),
114                Prev, Inc, Inc, Out,
115
116                Comment("\n' ' ".to_string()),
117                Dec, Dec, Dec, Dec, Dec, Dec,
118                Dec, Dec, Dec, Dec, Dec, Dec,
119                Out,
120
121                Comment("\n'W' ".to_string()),
122                Next,
123                Inc, Inc, Inc, Inc, Inc, Inc,
124                Loop(vec![
125                    Prev,
126                    Inc, Inc, Inc, Inc, Inc, Inc, Inc, Inc, Inc,
127                    Next, Dec,
128                ]),
129                Prev, Inc, Out,
130
131                Comment("\n'o' ".to_string()),
132                Prev, Out,
133
134                Comment("\n'r' ".to_string()),
135                Inc, Inc, Inc, Out,
136
137                Comment("\n'l' ".to_string()),
138                Dec, Dec, Dec, Dec, Dec, Dec, Out,
139                
140                Comment("\n'd' ".to_string()),
141                Dec, Dec, Dec, Dec, Dec, Dec, Dec, Dec, Out,
142                
143                Comment("\n'!' ".to_string()),
144                Next, Next, Next,
145                Inc, Inc, Inc, Inc,
146                Loop(vec![
147                    Prev,
148                    Inc, Inc, Inc, Inc, Inc, Inc, Inc, Inc,
149                    Next, Dec,
150                ]),
151                Prev, Inc, Out,
152
153                Comment("\nreading 4 chars ".to_string()),
154                Next, Next, Next, Inc, Inc, Inc, Inc, Loop(vec![Next, In, Out, Prev, Dec])
155            ]
156        };
157
158        let (leftover_input, parse_result) =
159            crate::parser::parse(code).expect("Parsing hello world");
160        assert_eq!(leftover_input, "");
161        assert_eq!(parse_result, correct_parse);
162
163        let mut context = Context::new();
164
165        let mut in_stream: Vec<u8> = b"testing".to_vec();
166        let mut out_stream: Vec<u8> = Vec::new();
167
168        let mut out_expected = b"Hello, World!".to_vec();
169        out_expected.extend_from_slice(&in_stream[0..4]);
170
171        context
172            .eval_many(&parse_result, &mut in_stream, &mut out_stream)
173            .expect("Evaluating hello world");
174
175        println!("{}", String::from_utf8(out_stream.clone()).unwrap());
176
177        assert_eq!(out_stream, out_expected);
178    }
179}