Add OrParse trait to simplify chained parsers

old-bit-manip
Nick Krichevsky 2023-11-21 20:29:48 -05:00
parent 827aef74f8
commit fc76248853
3 changed files with 24 additions and 22 deletions

View File

@ -34,6 +34,22 @@ trait OpcodeParser {
fn parse_opcode(data: &View) -> ParseResult; fn parse_opcode(data: &View) -> ParseResult;
} }
trait OrParse<T> {
/// If the current parse failed to parse the given opcode (i.e. this is Err(UnknownOpcode)), attempt to
/// parse again with the given parse function. Otherwise, this result itself is returned.
fn or_parse<F: Fn(u8) -> Result<T, Error>>(self, parse_func: F) -> Result<T, Error>;
}
impl<T> OrParse<T> for Result<T, Error> {
fn or_parse<F: Fn(u8) -> Result<T, Error>>(self, parse_func: F) -> Result<T, Error> {
if let Err(Error::UnknownOpcode(opcode)) = self {
parse_func(opcode)
} else {
self
}
}
}
/// `next_instruction` will parse the next instruction from the given data stream. Returns either an error, /// `next_instruction` will parse the next instruction from the given data stream. Returns either an error,
/// or the parsed instruction, and the number of bytes read. /// or the parsed instruction, and the number of bytes read.
pub fn next_instruction(data: &View) -> ParseResult { pub fn next_instruction(data: &View) -> ParseResult {

View File

@ -9,7 +9,7 @@ use crate::{
register, register,
}; };
use super::{OpcodeParser, ParseOutput}; use super::{OpcodeParser, OrParse, ParseOutput};
// similar to `arith8::Operand`, but only for the parts that can be uniquely determined from the opcode // similar to `arith8::Operand`, but only for the parts that can be uniquely determined from the opcode
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -25,7 +25,7 @@ pub struct Parser;
impl OpcodeParser for Parser { impl OpcodeParser for Parser {
fn parse_opcode(data: &View) -> super::ParseResult { fn parse_opcode(data: &View) -> super::ParseResult {
parse_eight_bit_arithmetic_instruction(data) parse_eight_bit_arithmetic_instruction(data)
.or_else(|_err| parse_stack_pointer_adjust_instruction(data)) .or_parse(|_opcode| parse_stack_pointer_adjust_instruction(data))
} }
} }
@ -57,7 +57,7 @@ fn parse_stack_pointer_adjust_instruction(data: &View) -> super::ParseResult {
} }
fn operation_for_opcode(opcode: u8) -> Result<Operation, super::Error> { fn operation_for_opcode(opcode: u8) -> Result<Operation, super::Error> {
operation_for_binary_opcode(opcode).or_else(|_err| operation_for_unary_opcode(opcode)) operation_for_binary_opcode(opcode).or_parse(operation_for_unary_opcode)
} }
fn operand_for_opcode(opcode: u8) -> Result<OpcodeOperand, super::Error> { fn operand_for_opcode(opcode: u8) -> Result<OpcodeOperand, super::Error> {

View File

@ -1,6 +1,6 @@
use crate::cpu::instructions::load8::EightBitLoadInstruction; use crate::cpu::instructions::load8::EightBitLoadInstruction;
use crate::cpu::instructions::Instruction; use crate::cpu::instructions::Instruction;
use crate::cpu::parse::{self, Error, OpcodeParser, ParseOutput, ParseResult}; use crate::cpu::parse::{self, Error, OpcodeParser, OrParse, ParseOutput, ParseResult};
use crate::memory::{GetViewTuple, View}; use crate::memory::{GetViewTuple, View};
use crate::register; use crate::register;
@ -8,25 +8,11 @@ use crate::register;
pub struct Parser; pub struct Parser;
impl OpcodeParser for Parser { impl OpcodeParser for Parser {
// Parses a single 8 bit instruction to load an 8 bit value to/from memory
fn parse_opcode(data: &View) -> ParseResult { fn parse_opcode(data: &View) -> ParseResult {
let parse_funcs = &[ parse_load_from_register_to_address(data)
parse_load_from_register_to_address, .or_parse(|_opcode| parse_load_from_address_to_register(data))
parse_load_from_address_to_register, .or_parse(|_opcode| parse_load_immediate_instructions(data))
parse_load_immediate_instructions, .or_parse(|_opcode| parse_load_from_register_to_address_and_do_arithmetic(data))
parse_load_from_register_to_address_and_do_arithmetic,
];
for parse_func in parse_funcs {
match parse_func(data) {
Ok(parsed_data) => return Ok(parsed_data),
Err(Error::UnknownOpcode(_)) => continue,
Err(err) => return Err(err),
}
}
let opcode = parse::get_opcode_from_data(data);
Err(Error::UnknownOpcode(opcode))
} }
} }