Improve error messages and doc comments
This commit is contained in:
parent
7286d93e63
commit
8ba781bf69
@ -16,6 +16,8 @@ pub enum Error {
|
|||||||
/// Produced by [Parser](crate::parser::Parser::parse<T>())
|
/// Produced by [Parser](crate::parser::Parser::parse<T>())
|
||||||
ParseError(parser::root::Root, Box<dyn std::error::Error + 'static>),
|
ParseError(parser::root::Root, Box<dyn std::error::Error + 'static>),
|
||||||
Contextual(Context, Box<Self>),
|
Contextual(Context, Box<Self>),
|
||||||
|
/// Produced by [Token] when the input is entirely unexpected.
|
||||||
|
UnexpectedSymbol(String),
|
||||||
/// Produced by [`TokenStream::expect`] when the next [Token] isn't the expected [Type]
|
/// Produced by [`TokenStream::expect`] when the next [Token] isn't the expected [Type]
|
||||||
UnexpectedToken {
|
UnexpectedToken {
|
||||||
expected: Type,
|
expected: Type,
|
||||||
@ -45,7 +47,7 @@ pub enum Error {
|
|||||||
RegisterTooHigh(u16),
|
RegisterTooHigh(u16),
|
||||||
/// Produced by
|
/// Produced by
|
||||||
/// [SecondaryOperand](parser::instruction::encoding::secondary_operand)
|
/// [SecondaryOperand](parser::instruction::encoding::secondary_operand)
|
||||||
/// when the joke "secondary immediate" form is specified
|
/// when the joke "secondary immediate" form is out of range 0..=1
|
||||||
FatSecondaryImmediate(isize),
|
FatSecondaryImmediate(isize),
|
||||||
/// Produced by [Number](parser::instruction::encoding::number) when the number is too
|
/// Produced by [Number](parser::instruction::encoding::number) when the number is too
|
||||||
/// wide to fit in 16 bits (outside the range `(-2^15) .. (2^16-1)` )
|
/// wide to fit in 16 bits (outside the range `(-2^15) .. (2^16-1)` )
|
||||||
@ -93,9 +95,10 @@ impl Display for Error {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Error::Contextual(ctx, error) => write!(f, "{ctx}: {error}"),
|
Error::Contextual(ctx, error) => write!(f, "{ctx}: {error}"),
|
||||||
Error::ParseError(_, error) => write!(f, "Error encountered while parsing:\n{error}"),
|
Error::ParseError(_, error) => write!(f, "{error}"),
|
||||||
|
Error::UnexpectedSymbol(sym) => write!(f, "Unexpected item in bagging area: \"{sym}\""),
|
||||||
Error::UnexpectedToken { expected, got } => write!(f, "Expected {expected}, got {got}."),
|
Error::UnexpectedToken { expected, got } => write!(f, "Expected {expected}, got {got}."),
|
||||||
Error::AllExpectationsFailed { expected, got } => write!(f, "Expected one of {expected}, got {got}."),
|
Error::AllExpectationsFailed { expected, got } => write!(f, "Expected {expected}, got {got}."),
|
||||||
Error::UnexpectedDigits(number, radix) => write!(f, "Number `{number}` is not base {radix}."),
|
Error::UnexpectedDigits(number, radix) => write!(f, "Number `{number}` is not base {radix}."),
|
||||||
Error::UnrecognizedOpcode(op) => write!(f, "{op} is not an opcode"),
|
Error::UnrecognizedOpcode(op) => write!(f, "{op} is not an opcode"),
|
||||||
Error::NotARegister(reg) => write!(f, "{reg} is not a register"),
|
Error::NotARegister(reg) => write!(f, "{reg} is not a register"),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// © 2023 John Breaux
|
// © 2023 John Breaux
|
||||||
//! An assembler for the TI MSP430
|
//! A bare-bones toy assembler for the TI MSP430, for use in MicroCorruption
|
||||||
pub mod preamble {
|
pub mod preamble {
|
||||||
use super::*;
|
use super::*;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
|
@ -19,7 +19,7 @@ pub trait Parsable {
|
|||||||
match Self::parse(p, stream).map_err(|e| e.bare()) {
|
match Self::parse(p, stream).map_err(|e| e.bare()) {
|
||||||
Ok(tt) => Ok(Some(tt)),
|
Ok(tt) => Ok(Some(tt)),
|
||||||
Err(Error::UnexpectedToken { .. }) | Err(Error::AllExpectationsFailed { .. }) => Ok(None),
|
Err(Error::UnexpectedToken { .. }) | Err(Error::AllExpectationsFailed { .. }) => Ok(None),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e.context(stream.context())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,14 +6,14 @@
|
|||||||
// ✔ 1. Instructions
|
// ✔ 1. Instructions
|
||||||
// ✔ 1. Instruction mnemonics /ad.../
|
// ✔ 1. Instruction mnemonics /ad.../
|
||||||
// ✔ 2. Byte/Word Mode Marker /(.\[bw\])?/
|
// ✔ 2. Byte/Word Mode Marker /(.\[bw\])?/
|
||||||
// ✔ 2. Src operands
|
// ✔ 2. Operands
|
||||||
// ✔ 1. Registers /(r1[0-5]|r[0-9])/
|
// ✔ 1. Registers /(r1[0-5]|r[0-9])/
|
||||||
// ✔ 2. Immediate Values /#/
|
// ✔ 2. Immediate Values /#/
|
||||||
// ✔ 3. Absolute addresses /&/
|
// ✔ 3. Absolute addresses /&/
|
||||||
// ✔ 4. Numbers /[0-9A-Fa-f]+
|
// ✔ 4. Numbers /[0-9A-Fa-f]+
|
||||||
// ✔ 5. Jump Offsets: basically numbers /$?([+-]?[0-9A-Fa-f]{1,4})/
|
// ✔ 5. Jump Offsets: basically numbers /$?([+-]?[0-9A-Fa-f]{1,4})/
|
||||||
// ✔ 4. Label definitions /(^.*):/
|
// ✔ 3. Label definitions /(^.*):/
|
||||||
// ✔ 5. Comments (may be useful for debugging)
|
// ✔ 4. Comments (may be useful for debugging)
|
||||||
|
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
@ -22,7 +22,7 @@ use crate::Error;
|
|||||||
use context::Context;
|
use context::Context;
|
||||||
use token::{Token, Type};
|
use token::{Token, Type};
|
||||||
|
|
||||||
/// Backtracking through bifurcated timelines
|
/// A TokenStream is a specialized [Iterator] which produces [Tokens](Token)
|
||||||
pub trait TokenStream<'text>: Iterator<Item = Token<'text>> {
|
pub trait TokenStream<'text>: Iterator<Item = Token<'text>> {
|
||||||
/// Gets this stream's [Context]
|
/// Gets this stream's [Context]
|
||||||
fn context(&self) -> Context;
|
fn context(&self) -> Context;
|
||||||
@ -50,7 +50,7 @@ pub trait TokenStream<'text>: Iterator<Item = Token<'text>> {
|
|||||||
/// Ignores a [Token] of the expected [Type], discarding errors.
|
/// Ignores a [Token] of the expected [Type], discarding errors.
|
||||||
fn allow(&mut self, expected: Type) { let _ = self.expect(expected); }
|
fn allow(&mut self, expected: Type) { let _ = self.expect(expected); }
|
||||||
|
|
||||||
/// Runs a functor on each
|
/// Runs a function on each
|
||||||
fn any_of<T, U>(&mut self, f: fn(&mut Self, Type) -> Result<U, Error>, expected: T) -> Result<U, Error>
|
fn any_of<T, U>(&mut self, f: fn(&mut Self, Type) -> Result<U, Error>, expected: T) -> Result<U, Error>
|
||||||
where T: AsRef<[Type]> {
|
where T: AsRef<[Type]> {
|
||||||
for &expected in expected.as_ref() {
|
for &expected in expected.as_ref() {
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
// © 2023 John Breaux
|
// © 2023 John Breaux
|
||||||
//! Defines the [Token]
|
//! Defines the [Token]
|
||||||
//!
|
//!
|
||||||
//! A [Token] represents all valid sequences of characters,
|
//! A [Token] is a [semantically tagged](Type) sequence of characters
|
||||||
//! sorted by meaning
|
|
||||||
|
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
@ -57,6 +56,7 @@ impl<$t> From<&$t str> for $type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A [Token] is a [semantically tagged](Type) sequence of characters
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct Token<'text> {
|
pub struct Token<'text> {
|
||||||
/// The type of this token
|
/// The type of this token
|
||||||
@ -96,12 +96,13 @@ impl<'text> Debug for Token<'text> {
|
|||||||
impl<'text> Display for Token<'text> {
|
impl<'text> Display for Token<'text> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self.variant {
|
match self.variant {
|
||||||
Type::Endl | Type::EndOfFile => write!(f, "{}", self.variant),
|
Type::Endl | Type::EndOfFile | Type::Invalid => Display::fmt(&self.variant, f),
|
||||||
v => write!(f, "\"{}\" ({v})", self.lexeme),
|
v => write!(f, "{v} \"{}\"", self.lexeme),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A [token Type](Type) is a semantic tag for a sequence of characters
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
/// contiguous whitespace, excluding newline
|
/// contiguous whitespace, excluding newline
|
||||||
@ -152,6 +153,8 @@ pub enum Type {
|
|||||||
Separator,
|
Separator,
|
||||||
/// End of File marker
|
/// End of File marker
|
||||||
EndOfFile,
|
EndOfFile,
|
||||||
|
/// Invalid token
|
||||||
|
Invalid,
|
||||||
}
|
}
|
||||||
|
|
||||||
regex_impl! {<'text> Token<'text> {
|
regex_impl! {<'text> Token<'text> {
|
||||||
@ -201,10 +204,10 @@ regex_impl! {<'text> Token<'text> {
|
|||||||
pub fn expect_plus(text: &str) -> Option<Self> {
|
pub fn expect_plus(text: &str) -> Option<Self> {
|
||||||
regex!(Type::Plus = r"^\+")
|
regex!(Type::Plus = r"^\+")
|
||||||
}
|
}
|
||||||
pub fn expect_open_idx(text: &str) -> Option<Self> {
|
pub fn expect_l_paren(text: &str) -> Option<Self> {
|
||||||
regex!(Type::LParen = r"^\(")
|
regex!(Type::LParen = r"^\(")
|
||||||
}
|
}
|
||||||
pub fn expect_close_idx(text: &str) -> Option<Self> {
|
pub fn expect_r_paren(text: &str) -> Option<Self> {
|
||||||
regex!(Type::RParen = r"^\)")
|
regex!(Type::RParen = r"^\)")
|
||||||
}
|
}
|
||||||
pub fn expect_indrect(text: &str) -> Option<Self> {
|
pub fn expect_indrect(text: &str) -> Option<Self> {
|
||||||
@ -228,40 +231,44 @@ regex_impl! {<'text> Token<'text> {
|
|||||||
pub fn expect_end_of_file(text: &str) -> Option<Self> {
|
pub fn expect_end_of_file(text: &str) -> Option<Self> {
|
||||||
regex!(Type::EndOfFile = r"^$")
|
regex!(Type::EndOfFile = r"^$")
|
||||||
}
|
}
|
||||||
|
pub fn expect_anything(text: &str) -> Option<Self> {
|
||||||
|
regex!(Type::Invalid = r"^.*")
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
impl Display for Type {
|
impl Display for Type {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Space => write!(f, "space"),
|
Self::Space => Display::fmt("space", f),
|
||||||
Self::Endl => write!(f, "newline"),
|
Self::Endl => Display::fmt("newline", f),
|
||||||
Self::Comment => write!(f, "comment"),
|
Self::Comment => Display::fmt("comment", f),
|
||||||
Self::Label => write!(f, "label definition"),
|
Self::Label => Display::fmt("label definition", f),
|
||||||
Self::Insn => write!(f, "instruction mnemonic"),
|
Self::Insn => Display::fmt("opcode", f),
|
||||||
Self::ByteWidth => write!(f, "byte-width marker"),
|
Self::ByteWidth => Display::fmt("byte-width", f),
|
||||||
Self::WordWidth => write!(f, "word-width marker"),
|
Self::WordWidth => Display::fmt("word-width", f),
|
||||||
Self::Register => write!(f, "register mnemonic"),
|
Self::Register => Display::fmt("register", f),
|
||||||
Self::RadixMarkerDec => write!(f, "decimal radix marker"),
|
Self::RadixMarkerDec => Display::fmt("decimal marker", f),
|
||||||
Self::RadixMarkerHex => write!(f, "hexadecimal radix marker"),
|
Self::RadixMarkerHex => Display::fmt("hexadecimal marker", f),
|
||||||
Self::RadixMarkerOct => write!(f, "octal radix marker"),
|
Self::RadixMarkerOct => Display::fmt("octal marker", f),
|
||||||
Self::RadixMarkerBin => write!(f, "binary radix marker"),
|
Self::RadixMarkerBin => Display::fmt("binary marker", f),
|
||||||
Self::Number => write!(f, "number"),
|
Self::Number => Display::fmt("number", f),
|
||||||
Self::Minus => write!(f, "minus sign"),
|
Self::Minus => Display::fmt("minus sign", f),
|
||||||
Self::Plus => write!(f, "plus sign"),
|
Self::Plus => Display::fmt("plus sign", f),
|
||||||
Self::LParen => write!(f, "left parenthesis"),
|
Self::LParen => Display::fmt("left parenthesis", f),
|
||||||
Self::RParen => write!(f, "right parenthesis"),
|
Self::RParen => Display::fmt("right parenthesis", f),
|
||||||
Self::Indirect => write!(f, "indirect mode marker"),
|
Self::Indirect => Display::fmt("indirect", f),
|
||||||
Self::Absolute => write!(f, "absolute mode marker"),
|
Self::Absolute => Display::fmt("absolute", f),
|
||||||
Self::Immediate => write!(f, "immediate mode marker"),
|
Self::Immediate => Display::fmt("immediate", f),
|
||||||
Self::Identifier => write!(f, "identifier"),
|
Self::Identifier => Display::fmt("identifier", f),
|
||||||
Self::Directive => write!(f, "directive"),
|
Self::Directive => Display::fmt("directive", f),
|
||||||
Self::Separator => write!(f, "comma"),
|
Self::Separator => Display::fmt("comma", f),
|
||||||
Self::EndOfFile => write!(f, "EOF"),
|
Self::EndOfFile => Display::fmt("EOF", f),
|
||||||
|
Self::Invalid => Display::fmt("invalid token", f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Owned version of a token, which can outlive its parent buffer
|
/// A [Token] which can outlive its parent buffer
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct OwnedToken {
|
pub struct OwnedToken {
|
||||||
/// The type of this token
|
/// The type of this token
|
||||||
@ -285,6 +292,7 @@ impl From<Token<'_>> for OwnedToken {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [Types] are an owned array of [types](Type), with a custom [Display] implementation
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct Types(Vec<Type>);
|
pub struct Types(Vec<Type>);
|
||||||
|
|
||||||
@ -296,10 +304,10 @@ impl<T: AsRef<[Type]>> From<T> for Types {
|
|||||||
impl Display for Types {
|
impl Display for Types {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
for (idx, t) in self.0.iter().enumerate() {
|
for (idx, t) in self.0.iter().enumerate() {
|
||||||
write!(f, "{t}")?;
|
Display::fmt(t, f)?;
|
||||||
match idx {
|
match idx {
|
||||||
i if i < self.0.len() - 2 => write!(f, ", ")?,
|
i if i < self.0.len() - 2 => Display::fmt(", ", f)?,
|
||||||
i if i < self.0.len() - 1 => write!(f, " or ")?,
|
i if i < self.0.len() - 1 => Display::fmt(" or ", f)?,
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user