summary refs log tree commit diff
path: root/src/lib.rs
diff options
context:
space:
mode:
authorSophie Forrest <git@sophieforrest.com>2024-08-30 23:35:45 +1200
committerSophie Forrest <git@sophieforrest.com>2024-08-30 23:35:45 +1200
commit5126c9ed83fe6169463566e74f966a4a63e57ca0 (patch)
tree99be8b093f6736eba59c529300519985d9c1c5c6 /src/lib.rs
feat: initial commit of brainf interpreter
Diffstat (limited to '')
-rw-r--r--src/lib.rs154
1 files changed, 154 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..725084a
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,154 @@
+#![allow(incomplete_features)]
+#![feature(async_fn_in_trait)]
+#![feature(custom_inner_attributes)]
+#![feature(lint_reasons)]
+#![feature(never_type)]
+#![feature(once_cell)]
+#![feature(test)]
+#![deny(clippy::complexity)]
+#![deny(clippy::nursery)]
+#![deny(clippy::pedantic)]
+#![deny(clippy::perf)]
+#![deny(clippy::suspicious)]
+#![deny(clippy::alloc_instead_of_core)]
+#![deny(clippy::as_underscore)]
+#![deny(clippy::clone_on_ref_ptr)]
+#![deny(clippy::create_dir)]
+#![warn(clippy::dbg_macro)]
+#![deny(clippy::default_numeric_fallback)]
+#![deny(clippy::default_union_representation)]
+#![deny(clippy::deref_by_slicing)]
+#![deny(clippy::empty_structs_with_brackets)]
+#![deny(clippy::exit)]
+#![deny(clippy::expect_used)]
+#![deny(clippy::filetype_is_file)]
+#![deny(clippy::fn_to_numeric_cast)]
+#![deny(clippy::format_push_string)]
+#![deny(clippy::get_unwrap)]
+#![deny(clippy::if_then_some_else_none)]
+#![allow(
+	clippy::implicit_return,
+	reason = "returns should be done implicitly, not explicitly"
+)]
+#![deny(clippy::indexing_slicing)]
+#![deny(clippy::large_include_file)]
+#![deny(clippy::let_underscore_must_use)]
+#![deny(clippy::lossy_float_literal)]
+#![deny(clippy::map_err_ignore)]
+#![deny(clippy::mem_forget)]
+#![deny(clippy::missing_docs_in_private_items)]
+#![deny(clippy::missing_trait_methods)]
+#![deny(clippy::mod_module_files)]
+#![deny(clippy::multiple_inherent_impl)]
+#![deny(clippy::mutex_atomic)]
+#![deny(clippy::needless_return)]
+#![deny(clippy::non_ascii_literal)]
+#![deny(clippy::panic_in_result_fn)]
+#![deny(clippy::pattern_type_mismatch)]
+#![deny(clippy::rc_buffer)]
+#![deny(clippy::rc_mutex)]
+#![deny(clippy::rest_pat_in_fully_bound_structs)]
+#![deny(clippy::same_name_method)]
+#![deny(clippy::separated_literal_suffix)]
+#![deny(clippy::str_to_string)]
+#![deny(clippy::string_add)]
+#![deny(clippy::string_slice)]
+#![deny(clippy::string_to_string)]
+#![allow(
+	clippy::tabs_in_doc_comments,
+	reason = "tabs are preferred for this project"
+)]
+#![deny(clippy::try_err)]
+#![deny(clippy::undocumented_unsafe_blocks)]
+#![deny(clippy::unnecessary_self_imports)]
+#![deny(clippy::unneeded_field_pattern)]
+#![deny(clippy::unwrap_in_result)]
+#![deny(clippy::unwrap_used)]
+#![warn(clippy::use_debug)]
+#![deny(clippy::verbose_file_reads)]
+#![deny(clippy::wildcard_dependencies)]
+#![deny(clippy::wildcard_enum_match_arm)]
+#![deny(missing_copy_implementations)]
+#![deny(missing_debug_implementations)]
+#![deny(missing_docs)]
+#![deny(single_use_lifetimes)]
+#![deny(unsafe_code)]
+#![deny(unused)]
+
+//! Brainfuck RS
+//!
+//! Implementation of a Brainfuck interpreter written in Rust.
+
+#[cfg(test)]
+extern crate test;
+
+mod constants;
+pub mod executor;
+pub mod lexer;
+pub mod parser;
+#[cfg(feature = "utilities")]
+pub mod utility;
+
+pub use executor::execute;
+pub use lexer::{lex, OperatorCode};
+use miette::Diagnostic;
+pub use parser::{parse, Instruction};
+use thiserror::Error;
+
+/// Top-level error type for Brainfuck interpreter.
+#[derive(Debug, Diagnostic, Error)]
+pub enum Error {
+	/// Error occurred when reading input from a file.
+	#[error(transparent)]
+	Io(#[from] std::io::Error),
+
+	/// An error that occurred while parsing Brainfuck code.
+	#[diagnostic(transparent)]
+	#[error(transparent)]
+	Parser(#[from] parser::Error),
+
+	/// An error that occurred during runtime.
+	#[error(transparent)]
+	Runtime(#[from] executor::Error),
+}
+
+#[cfg(test)]
+mod tests {
+	use test::Bencher;
+
+	use super::*;
+	use crate::constants::TapeInner;
+
+	#[test]
+	fn hello_world() -> Result<(), Error> {
+		let mut tape: Vec<TapeInner> = vec![0; 1024];
+
+		utility::execute_from_file("./test_programs/hello_world.bf", &mut tape)?;
+
+		Ok(())
+	}
+
+	#[bench]
+	fn hello_world_from_hell(b: &mut Bencher) {
+		b.iter(|| {
+			let mut tape: Vec<TapeInner> = vec![0; 1024];
+
+			#[allow(clippy::expect_used)]
+			utility::execute_from_file("./test_programs/hello_world.bf", &mut tape)
+				.expect("failed to run");
+		});
+	}
+
+	#[test]
+	fn hello_world_short() -> Result<(), Error> {
+		let mut tape: Vec<TapeInner> = vec![0; 1024];
+
+		utility::execute_from_str(
+			"--[+++++++<---->>-->+>+>+<<<<]<.>++++[-<++++>>->--<<]>>-.>--..>+.<<<.<<-.>>+>->>.\
+			 +++[.<]",
+			&mut tape,
+		)?;
+
+		Ok(())
+	}
+}