// © 2023 John Breaux //! Parses [Tokens](crate::Token) into an [abstract syntax tree](Root) use crate::{Error, Hash, TokenStream, Type}; use std::fmt::{Debug, Display, LowerHex}; pub mod preamble { //! All the different AST node types use super::*; // Traits pub use parsable::Parsable; pub use comment::Comment; pub use directive::Directive; pub use identifier::Identifier; pub use instruction::{ encoding::{ encoding_parser::EncodingParser, jump_target::JumpTarget, number::Number, primary_operand::PrimaryOperand, register::Register, secondary_operand::SecondaryOperand, width::Width, Encoding, }, opcode::Opcode, Instruction, }; pub use label::Label; pub use line::Line; pub use root::Root; } use preamble::*; pub(crate) mod parsable; pub(crate) mod comment; pub(crate) mod directive; pub(crate) mod identifier; pub(crate) mod instruction; pub(crate) mod label; pub(crate) mod line { // © 2023 John Breaux use super::*; /// A line is one of: /// - [`Label`] (definition) /// - [`Instruction`] /// - [`Directive`] /// - [`Comment`] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Line { Empty, Insn(Instruction), Comment(Comment), Directive(Directive), Label(Label), // TODO: Label resolution EndOfFile, // Expected end of file } impl Parsable for Line { fn parse<'text, T>(p: &Parser, stream: &mut T) -> Result where T: TokenStream<'text> { if let Ok(token) = stream.peek_expect_any_of([Type::Insn, Type::Comment, Type::Directive, Type::Identifier]) { return Ok(match token.variant() { Type::Insn => Self::Insn(Instruction::parse(p, stream)?), Type::Comment => Self::Comment(Comment::parse(p, stream)?), Type::Directive => Self::Directive(Directive::parse(p, stream)?), Type::Identifier => Self::Label(Label::parse(p, stream)?), _ => unreachable!(), }); } let token = stream.expect_any_of([Type::EndOfFile])?; Ok(match token.variant() { Type::EndOfFile => Self::EndOfFile, _ => unreachable!(), }) } } impl Display for Line { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Empty => writeln!(f, "\n"), Self::Label(arg0) => Display::fmt(arg0, f), Self::Insn(arg0) => Display::fmt(arg0, f), Self::Directive(arg0) => Display::fmt(arg0, f), Self::Comment(arg0) => Display::fmt(arg0, f), Self::EndOfFile => write!(f, "; End of file."), } } } impl LowerHex for Line { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Line::Insn(arg0) => LowerHex::fmt(arg0, f), _ => Ok(()), } } } } pub(crate) mod root { // © 2023 John Breaux use super::*; /// Contains the entire AST #[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Root(pub Vec); // TODO: Get data out of ParseTree // TODO: Maybe implement some sort of follower impl Parsable for Root { fn parse<'text, T>(p: &Parser, stream: &mut T) -> Result where T: TokenStream<'text> { let mut lines = vec![]; loop { match Line::parse(p, stream) { Ok(Line::EndOfFile) => break, Ok(line) => lines.push(line), Err(e) => { let ret = Self(lines); eprintln!("{ret}"); eprintln!("Error:{e}\n"); eprint!("Remaining:"); stream.for_each(|t| eprint!("{t}")); eprintln!(); return Err(Error::ParseError(ret, Box::new(e))); } } } Ok(Root(lines)) } } impl Display for Root { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for line in self.0.iter() { f.pad(&format!("{line} "))?; } Ok(()) } } impl LowerHex for Root { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for line in self.0.iter() { LowerHex::fmt(line, f)?; } Ok(()) } } impl Debug for Root { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for line in self.0.iter() { Display::fmt(line, f)?; Debug::fmt(line, f)?; } Ok(()) } } } /// The type for [Parser] callbacks pub type EmitComment = Box; pub type DefineLabel = Box Result<(), Error>>; pub struct Parser { radix: u32, // TODO: callbacks for emitted token sequences?! on_label: Option, on_comment: Option, } impl Parser { pub fn parse_with<'t, T>(self, stream: &'t mut T) -> Result where T: TokenStream<'t> { Root::parse(&self, &mut stream.ignore_spaces()) } pub fn parse(self, input: &T) -> Result where T: AsRef + ?Sized { Root::parse(&self, &mut super::Tokenizer::new(input).ignore_spaces()) } pub fn parse_one(self, input: &T) -> Result where T: AsRef + ?Sized { Line::parse(&self, &mut super::Tokenizer::new(input).ignore_spaces()) } /// Sets the default radix for [Token](crate::tokenizer::token::Token) -> [Number] /// conversion pub fn radix(mut self, radix: u32) { self.radix = radix; } /// Inform the caller of a new identifier definition pub fn define_label(&mut self, l: &Identifier) -> Result<(), Error> { match self.on_label.as_mut() { Some(f) => f(l), _ => Ok(()), } } /// Inform the caller of an identifier being used pub fn emit_comment(&mut self, d: &str) { if let Some(f) = self.on_comment.as_mut() { f(d) } } } impl Default for Parser { fn default() -> Self { Self { radix: 16, on_label: None, on_comment: None } } } impl Debug for Parser { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Parser").field("radix", &self.radix).finish_non_exhaustive() } }