diff --git a/hbasm/src/lib.rs b/hbasm/src/lib.rs index aba245e..cd3553d 100644 --- a/hbasm/src/lib.rs +++ b/hbasm/src/lib.rs @@ -33,7 +33,6 @@ macros::impl_both!( => [NOP, ECALL], ); - pub trait Imm { fn insert(&self, asm: &mut Assembler); } diff --git a/hbasm/src/macros/text.rs b/hbasm/src/macros/text.rs index ffa2df0..2bc0c5c 100644 --- a/hbasm/src/macros/text.rs +++ b/hbasm/src/macros/text.rs @@ -8,8 +8,12 @@ macro_rules! gen_text { ) => { pub mod text { use { + crate::{ + Assembler, + macros::text::*, + }, lasso::{Rodeo, Spur}, - logos::Logos, + logos::{Lexer, Logos, Span}, }; paste::paste!(literify::literify! { @@ -52,8 +56,93 @@ macro_rules! gen_text { #[token(",")] PSep, } }); + + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + pub enum ErrorKind { + UnexpectedToken, + InvalidToken, + UnexpectedEnd, + InvalidSymbol, + } + + #[derive(Clone, Debug, PartialEq, Eq)] + pub struct Error { + pub kind: ErrorKind, + pub span: Span, + } + + pub fn assemble(asm: &mut Assembler, code: &str) -> Result<(), Error> { + fn next(lexer: &mut Lexer) -> Result { + match lexer.next() { + Some(Ok(t)) => Ok(t), + Some(Err(())) => Err(ErrorKind::InvalidToken), + None => Err(ErrorKind::UnexpectedEnd), + } + } + + #[inline(always)] + fn inner(asm: &mut Assembler, lexer: &mut Lexer) -> Result<(), ErrorKind> { + loop { + match lexer.next() { + Some(Ok(Token::Opcode(op))) => { + match op { + $( + $(hbbytecode::opcode::$opcode)|* => paste::paste!({ + param_extract_iim!(lexer, $($param_i: $param_ty),*); + asm.[](op, $($param_i),*); + }), + )* + _ => unreachable!(), + } + } + Some(Ok(Token::Label(_))) => { + todo!("Labels"); + } + Some(Ok(Token::ISep)) => (), + Some(Ok(_)) => return Err(ErrorKind::UnexpectedToken), + Some(Err(())) => return Err(ErrorKind::InvalidToken), + None => return Ok(()), + } + } + } + + let mut lexer = Token::lexer(code); + inner(asm, &mut lexer) + .map_err(|kind| Error { kind, span: lexer.span() }) + } } }; } -pub(crate) use gen_text; +macro_rules! extract_pat { + ($lexer:expr, $pat:pat) => { + let $pat = next($lexer)? + else { return Err(ErrorKind::UnexpectedToken) }; + }; +} + +macro_rules! extract { + ($lexer:expr, R, $id:ident) => { + extract_pat!($lexer, Token::Register($id)); + }; + ($lexer:expr, I, $id:ident) => { + extract_pat!($lexer, Token::Integer($id)); + }; + ($lexer:expr, u16, $id:ident) => { + extract_pat!($lexer, Token::Integer($id)); + let $id = u16::try_from($id) + .map_err(|_| ErrorKind::InvalidToken)?; + }; +} + +macro_rules! param_extract_iim { + ($lexer:expr, $($id:ident: $ty:ident)? $(, $($tt:tt)*)?) => { + $(extract!($lexer, $ty, $id);)? + $( + extract_pat!($lexer, Token::PSep); + param_extract_iim!($lexer, $($tt)*); + )? + }; +} + +pub(crate) use {extract, extract_pat, gen_text, param_extract_iim};