mod api;
pub mod context;
pub mod error;
pub mod io_traits;
pub mod parser;
pub use api::*;
pub mod prelude {
pub use super::context::*;
pub use super::error::*;
pub use super::io_traits::*;
pub use super::parser::Expression;
}
#[cfg(test)]
mod test {
use crate::prelude::*;
use std::{error::Error, fmt::Display};
#[derive(Debug)]
struct TestError(String);
impl Display for TestError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl Error for TestError {}
impl BfInStream<TestError> for Vec<u8> {
fn bf_read(&mut self) -> Result<u8, TestError> {
Ok(self.remove(0))
}
}
impl BfOutStream<TestError> for Vec<u8> {
fn bf_write(&mut self, byte: u8) -> Result<(), TestError> {
Ok(self.push(byte))
}
}
#[test]
fn hello_world() {
let code = "\
'H' >++++++++[<+++++++++>-]<.\n\
'e' >++++[<+++++++>-]<+.\n\
'l' +++++++.\n\
'l' .\n\
'o' +++.\n\
comma >>++++++[<+++++++>-]<++.\n\
' ' ------------.\n\
'W' >++++++[<+++++++++>-]<+.\n\
'o' <.\n\
'r' +++.\n\
'l' ------.\n\
'd' --------.\n\
'!' >>>++++[<++++++++>-]<+.\n\
reading 4 chars >>>++++[>,.<-]";
#[rustfmt::skip]
let correct_parse = {
use crate::parser::Expression::{
Comment,
Decrement as Dec,
Increment as Inc,
Input as In,
Output as Out,
Loop, Next, Prev
};
[
Comment("'H' ".to_string()),
Next,
Inc, Inc, Inc, Inc, Inc, Inc, Inc, Inc,
Loop(vec![
Prev,
Inc, Inc, Inc, Inc, Inc, Inc, Inc, Inc, Inc,
Next, Dec,
]),
Prev, Out,
Comment("\n'e' ".to_string()),
Next,
Inc,
Inc,
Inc,
Inc,
Loop(vec![
Prev,
Inc, Inc, Inc, Inc, Inc, Inc, Inc,
Next, Dec,
]),
Prev, Inc, Out,
Comment("\n'l' ".to_string()),
Inc, Inc, Inc, Inc, Inc, Inc, Inc,
Out,
Comment("\n'l' ".to_string()),
Out,
Comment("\n'o' ".to_string()),
Inc, Inc, Inc,
Out,
Comment("\ncomma ".to_string()),
Next, Next,
Inc, Inc, Inc, Inc, Inc, Inc,
Loop(vec![
Prev, Inc, Inc, Inc, Inc, Inc, Inc,
Inc, Next, Dec,
]),
Prev, Inc, Inc, Out,
Comment("\n' ' ".to_string()),
Dec, Dec, Dec, Dec, Dec, Dec,
Dec, Dec, Dec, Dec, Dec, Dec,
Out,
Comment("\n'W' ".to_string()),
Next,
Inc, Inc, Inc, Inc, Inc, Inc,
Loop(vec![
Prev,
Inc, Inc, Inc, Inc, Inc, Inc, Inc, Inc, Inc,
Next, Dec,
]),
Prev, Inc, Out,
Comment("\n'o' ".to_string()),
Prev, Out,
Comment("\n'r' ".to_string()),
Inc, Inc, Inc, Out,
Comment("\n'l' ".to_string()),
Dec, Dec, Dec, Dec, Dec, Dec, Out,
Comment("\n'd' ".to_string()),
Dec, Dec, Dec, Dec, Dec, Dec, Dec, Dec, Out,
Comment("\n'!' ".to_string()),
Next, Next, Next,
Inc, Inc, Inc, Inc,
Loop(vec![
Prev,
Inc, Inc, Inc, Inc, Inc, Inc, Inc, Inc,
Next, Dec,
]),
Prev, Inc, Out,
Comment("\nreading 4 chars ".to_string()),
Next, Next, Next, Inc, Inc, Inc, Inc, Loop(vec![Next, In, Out, Prev, Dec])
]
};
let (leftover_input, parse_result) =
crate::parser::parse(code).expect("Parsing hello world");
assert_eq!(leftover_input, "");
assert_eq!(parse_result, correct_parse);
let mut context = Context::new();
let mut in_stream: Vec<u8> = b"testing".to_vec();
let mut out_stream: Vec<u8> = Vec::new();
let mut out_expected = b"Hello, World!".to_vec();
out_expected.extend_from_slice(&in_stream[0..4]);
context
.eval_many(&parse_result, &mut in_stream, &mut out_stream)
.expect("Evaluating hello world");
println!("{}", String::from_utf8(out_stream.clone()).unwrap());
assert_eq!(out_stream, out_expected);
}
}