From 3c163eabc78ddbd26bb250ef5ad6da28cd61adc6 Mon Sep 17 00:00:00 2001 From: Sophie Forrest Date: Fri, 30 Aug 2024 23:35:45 +1200 Subject: feat: split engine into crates --- src/parser.rs | 170 ---------------------------------------------------------- 1 file changed, 170 deletions(-) delete mode 100644 src/parser.rs (limited to 'src/parser.rs') diff --git a/src/parser.rs b/src/parser.rs deleted file mode 100644 index e639516..0000000 --- a/src/parser.rs +++ /dev/null @@ -1,170 +0,0 @@ -//! Parser implementation for Brainfuck. Parses operator codes into instruction -//! sets. - -use miette::{Diagnostic, SourceSpan}; -use thiserror::Error; - -use crate::lexer::OperatorCode; - -/// Parsed instructions for Brainfuck. -#[derive(Clone, Debug)] -pub enum Instruction { - /// `>` - /// - /// Increment the data pointer by one (to point to the next cell to the - /// right). - IncrementPointer, - - /// `<` - /// - /// Decrement the data pointer by one (to point to the next cell to the - /// left). - DecrementPointer, - - /// `+` - /// - /// Increment the byte at the data pointer by one. - IncrementByte, - - /// `-` - /// - /// Decrement the byte at the data pointer by one. - DecrementByte, - - /// `.` - /// - /// Output the byte at the data pointer. - OutputByte, - - /// `,` - /// - /// Accept one byte of input, storing its value in the byte at the data - /// pointer. - InputByte, - - /// `[]` - /// - /// Loops through the inner instructions. - Loop(Vec), -} - -/// Error type for errors that occur during parsing from [`OperatorCode`]s to -/// [`Instruction`]s. -#[derive(Debug, Diagnostic, Error)] -pub enum Error { - /// Parser encountered a loop with no beginning. - #[diagnostic( - code(brainf_rs::parser::loop_with_no_beginning), - help("try closing the loop") - )] - #[error("loop closed at {loop_src:?} has no beginning")] - LoopWithNoBeginning { - /// Source code associated with diagnostic - #[source_code] - input: String, - - /// SourceSpan of the loop bracket. - #[label("loop ending")] - loop_src: SourceSpan, - }, - - /// Parser encountered a loop with no ending. - #[diagnostic( - code(brainf_rs::parser::loop_with_no_ending), - help("try closing the loop") - )] - #[error("loop beginning at {loop_src:?} has no ending")] - LoopWithNoEnding { - /// Source code associated with diagnostic - #[source_code] - input: String, - - /// SourceSpan of the loop bracket. - #[label("loop beginning")] - loop_src: SourceSpan, - }, - - /// Parser sliced out of bounds. - #[error("parser sliced out of bounds")] - SliceOutOfBounds(std::ops::Range), -} - -/// Parses the operator codes into instruction codes. -/// -/// # Parameters -/// -/// * `src` - The source the operator codes originate from. This is used for -/// error reporting. -/// * `operator_codes` - The operator codes reveiced from the lexer. -/// -/// # Errors -/// -/// This function will return an error if a loop is encountered with no -/// beginning, a loop is encountered with no ending, or if the parser attempts -/// to slice out of bounds. -pub fn parse(src: &str, operator_codes: &[OperatorCode]) -> Result, Error> { - let mut program: Vec = Vec::new(); - let mut loop_stack: i32 = 0; - let mut loop_start = 0; - let mut loop_source_offset: usize = 0; - - operator_codes - .iter() - .enumerate() - .try_for_each(|(i, operator_code)| -> Result<(), Error> { - match (loop_stack, *operator_code) { - (0i32, OperatorCode::StartLoop { offset }) => { - loop_start = i; - loop_source_offset = offset; - loop_stack += 1i32; - } - (0i32, _) => { - if let Some(instruction) = match *operator_code { - OperatorCode::IncrementPointer => Some(Instruction::IncrementPointer), - OperatorCode::DecrementPointer => Some(Instruction::DecrementPointer), - OperatorCode::IncrementByte => Some(Instruction::IncrementByte), - OperatorCode::DecrementByte => Some(Instruction::DecrementByte), - OperatorCode::OutputByte => Some(Instruction::OutputByte), - OperatorCode::InputByte => Some(Instruction::InputByte), - OperatorCode::EndLoop { offset } => { - return Err(Error::LoopWithNoBeginning { - input: src.to_owned(), - loop_src: (offset, 1).into(), - }) - } - // We don't care about this variant as it is handled in a subsequent arm - OperatorCode::StartLoop { .. } => None, - } { - program.push(instruction); - } - } - (_, OperatorCode::StartLoop { .. }) => loop_stack += 1i32, - (_, OperatorCode::EndLoop { .. }) => { - loop_stack -= 1i32; - if loop_stack == 0i32 { - let loop_program = parse( - src, - match operator_codes.get(loop_start + 1..i) { - Some(value) => value, - None => return Err(Error::SliceOutOfBounds(loop_start + 1..i)), - }, - )?; - - program.push(Instruction::Loop(loop_program)); - } - } - _ => (), - }; - - Ok(()) - })?; - - if loop_stack == 0i32 { - Ok(program) - } else { - Err(Error::LoopWithNoEnding { - input: src.to_owned(), - loop_src: (loop_source_offset, 1).into(), - }) - } -} -- cgit 1.4.1