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}