From 13b95941183666fadd090314e4e9af33283084cd Mon Sep 17 00:00:00 2001 From: Sophie Forrest Date: Fri, 30 Aug 2024 23:35:45 +1200 Subject: feat(engine)!: implement u32 engine --- Cargo.lock | 14 ++++++++++++++ Cargo.toml | 7 ++++++- src/engine.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++++----- src/executor.rs | 12 ++++++++---- src/lib.rs | 1 - src/main.rs | 1 - src/utility.rs | 5 +---- 7 files changed, 78 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0be8c23..d4c6389 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,13 +106,21 @@ checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" name = "brainf_rs" version = "0.1.0" dependencies = [ + "byteorder", "clap", "fs-err", "miette", "num-traits", "thiserror", + "widestring", ] +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "cc" version = "1.0.82" @@ -479,6 +487,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index eca44e9..b3403d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,12 +5,17 @@ edition = "2021" resolver = "2" [dependencies] +byteorder = { optional = true, version = "1.4.3" } clap = { features = ["derive"], version = "4.3.21" } num-traits = "0.2.16" fs-err = "2.9.0" miette = { features = ["fancy"], version = "5.10.0" } thiserror = "1.0.44" +widestring = { default-features = false, optional = true, version = "1.0.2" } [features] -default = ["utilities"] +default = ["engine-u16", "engine-u32", "utilities"] +bigint-engine = ["dep:byteorder", "dep:widestring"] +engine-u16 = ["bigint-engine"] +engine-u32 = ["bigint-engine"] utilities = [] diff --git a/src/engine.rs b/src/engine.rs index 8cf2726..6c69bc1 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -2,11 +2,29 @@ //! //! This predominantly allows implementation of a [`u16`] executor. -use std::io::Read; +use std::io::{Cursor, Read}; +use byteorder::{BigEndian, ReadBytesExt}; use num_traits::{One, Unsigned, WrappingAdd, WrappingSub, Zero}; +use thiserror::Error; -use crate::executor::{self, Error}; +use crate::executor; + +/// Error type for engine errors +#[derive(Debug, Error)] +pub enum Error { + /// Engine ran into an io Error + #[error(transparent)] + Io(#[from] std::io::Error), + + /// Utf16 error from widestring + #[error("could not convert byte to Utf16Str")] + Utf16, + + /// Utf32 error from widestring + #[error("could not convert byte to Utf32Str")] + Utf32, +} /// Generic engine implementation for the Brainfuck interpreter. pub trait Engine { @@ -56,13 +74,39 @@ impl Engine for executor::U16 { std::io::stdin().read_exact(&mut input)?; - let number = ((u16::from(input[0])) << 8i32) | u16::from(input[1]); + let mut reader = Cursor::new(input); - Ok(number) + Ok(reader.read_u16::()?) } fn write_byte(byte: u16) -> Result<(), Error> { - print!("{}", String::from_utf16_lossy(&[byte])); + print!( + "{}", + widestring::Utf16Str::from_slice(&[byte]).map_err(|_err| Error::Utf16)? + ); + + Ok(()) + } +} + +impl Engine for executor::U32 { + type TapeInner = u32; + + fn read_byte() -> Result { + let mut input: [u8; 4] = [0; 4]; + + std::io::stdin().read_exact(&mut input)?; + + let mut reader = Cursor::new(input); + + Ok(reader.read_u32::()?) + } + + fn write_byte(byte: u32) -> Result<(), Error> { + print!( + "{}", + widestring::Utf32Str::from_slice(&[byte]).map_err(|_err| Error::Utf32)? + ); Ok(()) } diff --git a/src/executor.rs b/src/executor.rs index eddf443..da7d676 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -9,14 +9,14 @@ use crate::{engine::Engine, parser::Instruction}; /// Runtime errors that can occur in brainfuck executor. #[derive(Debug, Diagnostic, Error)] pub enum Error { + /// Brainfuck engine ran into an error at runtime. + #[error(transparent)] + Engine(#[from] crate::engine::Error), + /// Brainfuck code performed an out of bounds index on the tape during /// runtime. #[error("tape indexed out of bounds, attempted index at `{0}`")] IndexOutOfBounds(usize), - - /// Executor was unable to read an input byte from stdin. - #[error("could not read input from stdin")] - ReadInput(#[from] std::io::Error), } /// Struct for executor implementation, allows u8 Engine to be implemented. @@ -27,6 +27,10 @@ pub struct U8; #[derive(Clone, Copy, Debug)] pub struct U16; +/// Struct for executor implementation, allows u32 Engine to be implemented. +#[derive(Clone, Copy, Debug)] +pub struct U32; + /// Executes the provided instruction set, utilising the provided tape.. /// /// # Errors diff --git a/src/lib.rs b/src/lib.rs index b806b4c..2c40797 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ #![feature(custom_inner_attributes)] #![feature(lint_reasons)] #![feature(never_type)] -#![feature(once_cell)] #![feature(test)] #![deny(clippy::complexity)] #![deny(clippy::nursery)] diff --git a/src/main.rs b/src/main.rs index f5c4740..13868a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,6 @@ #![feature(custom_inner_attributes)] #![feature(lint_reasons)] #![feature(never_type)] -#![feature(once_cell)] #![deny(clippy::complexity)] #![deny(clippy::nursery)] #![deny(clippy::pedantic)] diff --git a/src/utility.rs b/src/utility.rs index 4eba853..514343c 100644 --- a/src/utility.rs +++ b/src/utility.rs @@ -37,10 +37,7 @@ pub fn execute_from_file( /// This function will return an error if parsing or /// execution fails. See documentation for [`crate::parser::parse`] and /// [`crate::executor::execute`]. -pub fn execute_from_str>( - input: &str, - tape: &mut [E::TapeInner], -) -> Result<(), Error> { +pub fn execute_from_str(input: &str, tape: &mut [E::TapeInner]) -> Result<(), Error> { let operator_codes = lex(input); let instructions = parse(input, &operator_codes)?; -- cgit 1.4.1