use std::fmt::{Display, Formatter}; use vcore::opcodes::InvalidMnemonic; #[derive(Debug, PartialEq, Clone)] pub struct Location { pub line_num: usize, pub file: String, } #[derive(Debug, PartialEq, Clone)] pub enum ParseError { LineParseFailure, InvalidInstruction(String), } impl Display for Location { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}:{}", self.file, self.line_num) } } impl Default for Location { fn default() -> Self { Location { line_num: 0, file: "".to_string(), } } } impl From for Location { fn from(line: usize) -> Self { Self { line_num: line, file: "".to_string(), } } } impl<'a> From> for ParseError { fn from(err: InvalidMnemonic<'a>) -> Self { Self::InvalidInstruction(err.0.into()) } } impl Display for ParseError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { use ParseError::*; match self { LineParseFailure => write!(f, "Failed to parse line"), InvalidInstruction(p) => write!(f, "Cannot parse {} as instruction", p), } } } #[derive(Debug, Clone, PartialEq)] pub enum AssembleError { ParseError(Location, ParseError), EquResolveError(Location, String, EvalError), EquDuplicateError(Location, String), OrgResolveError(Location, EvalError), ArgError(Location, EvalError), NoCode, IncludeError(Location, String), FileError(String), MacroError(Location), } impl AssembleError { pub fn message(&self) -> String { match self { AssembleError::ParseError(_, err) => format!("Parse error: {}", err), AssembleError::EquResolveError(_, name, _) => format!("Cannot resolve .equ {}", name), AssembleError::EquDuplicateError(_, name) => format!("Duplicate .equ {}", name), AssembleError::OrgResolveError(_, _) => "Cannot resolve .org".to_string(), AssembleError::ArgError(_, _) => "Cannot calculate argument".to_string(), AssembleError::NoCode => "No output would be generated by this code".to_string(), AssembleError::IncludeError(_, file) => format!("Cannot read \"{}\"", file), AssembleError::FileError(_) => "File read error".to_string(), AssembleError::MacroError(_) => "Malformed macro control structure".to_string() } } } impl Display for AssembleError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { AssembleError::EquResolveError(line, name, err) => { write!(f, "{} {} at {}: {}", self.message(), name, line, err) } AssembleError::EquDuplicateError(line, name) => { write!(f, "{} {} at {}", self.message(), name, line) } AssembleError::OrgResolveError(line, err) | AssembleError::ArgError(line, err) => { write!(f, "{} at {}: {}", self.message(), line, err) } AssembleError::ParseError(line, err) => { write!(f, "{} at {}: {}", self.message(), line, err) } AssembleError::NoCode => { write!(f, "{}", self.message()) } AssembleError::IncludeError(line, _) | AssembleError::MacroError(line) => { write!(f, "{} at {}", self.message(), line) } AssembleError::FileError(file) => { write!(f, "{} in {}", self.message(), file) } } } } #[derive(Debug, Clone, PartialEq)] pub enum EvalError { MissingLabel(String), UnknownAddress(usize), OffsetError(usize, i32), } impl Display for EvalError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { EvalError::MissingLabel(label) => write!(f, "Unable to resolve label {}", label), EvalError::UnknownAddress(line_num) => write!( f, "Unable to calculate starting address of line {}", line_num ), EvalError::OffsetError(line_num, offset) => { write!(f, "Invalid line offset {} on line {}", offset, line_num) } } } }