diff --git a/Cargo.lock b/Cargo.lock index 63862e7..0c53369 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + [[package]] name = "cfg-if" version = "1.0.0" @@ -101,6 +107,7 @@ name = "hbasm" version = "0.1.0" dependencies = [ "ariadne", + "bytemuck", "hashbrown 0.14.0", "hbbytecode", "lasso", diff --git a/hbasm/Cargo.toml b/hbasm/Cargo.toml index 4659ae5..889bdd4 100644 --- a/hbasm/Cargo.toml +++ b/hbasm/Cargo.toml @@ -9,6 +9,7 @@ hbbytecode = { path = "../hbbytecode" } literify = "0.1" paste = "1.0" hashbrown = "0.14.0" +bytemuck = "1.13.1" [dependencies.lasso] version = "0.7" diff --git a/hbasm/src/lib.rs b/hbasm/src/lib.rs index cd3553d..d0b344a 100644 --- a/hbasm/src/lib.rs +++ b/hbasm/src/lib.rs @@ -1,18 +1,20 @@ #![no_std] #![feature(error_in_core)] +use lasso::Key; + extern crate alloc; pub mod text_r; mod macros; -use {alloc::vec::Vec, hashbrown::HashSet}; +use {alloc::vec::Vec, hashbrown::HashSet, lasso::Spur}; #[derive(Default)] pub struct Assembler { pub buf: Vec, - sub: HashSet, + pub sub: HashSet, } macros::impl_both!( @@ -53,11 +55,11 @@ macro_rules! impl_imm_le_bytes { impl_imm_le_bytes!(u64, i64, f64); #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Symbol(pub u64); +struct Symbol(pub Spur); impl Imm for Symbol { #[inline(always)] fn insert(&self, asm: &mut Assembler) { asm.sub.insert(asm.buf.len()); - asm.buf.extend(self.0.to_le_bytes()); + asm.buf.extend((self.0.into_usize() as u64).to_le_bytes()); } } diff --git a/hbasm/src/macros/text.rs b/hbasm/src/macros/text.rs index 9a4e803..485050f 100644 --- a/hbasm/src/macros/text.rs +++ b/hbasm/src/macros/text.rs @@ -12,7 +12,8 @@ macro_rules! gen_text { Assembler, macros::text::*, }, - lasso::{Rodeo, Spur}, + hashbrown::HashMap, + lasso::{Key, Rodeo, Spur}, logos::{Lexer, Logos, Span}, }; @@ -72,75 +73,124 @@ macro_rules! gen_text { } 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), - } + pub struct TextAsm<'a> { + asm: &'a mut Assembler, + lexer: Lexer<'a, Token>, + symloc: HashMap, } - #[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_itm!(lexer, $($param_i: $param_ty),*); - asm.[](op, $($param_i),*); - }), - )* - _ => unreachable!(), + impl<'a> TextAsm<'a> { + fn next(&mut self) -> Result { + match self.lexer.next() { + Some(Ok(t)) => Ok(t), + Some(Err(())) => Err(ErrorKind::InvalidToken), + None => Err(ErrorKind::UnexpectedEnd), + } + } + + #[inline(always)] + fn run(&mut self) -> Result<(), ErrorKind> { + loop { + match self.lexer.next() { + Some(Ok(Token::Opcode(op))) => { + match op { + $( + $(hbbytecode::opcode::$opcode)|* => paste::paste!({ + param_extract_itm!(self, $($param_i: $param_ty),*); + self.asm.[](op, $($param_i),*); + }), + )* + _ => unreachable!(), + } } + Some(Ok(Token::Label(lbl))) => { + self.symloc.insert(lbl, self.asm.buf.len()); + } + Some(Ok(Token::ISep)) => (), + Some(Ok(_)) => return Err(ErrorKind::UnexpectedToken), + Some(Err(())) => return Err(ErrorKind::InvalidToken), + None => return Ok(()), } - 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() }) + let mut asm = TextAsm { + asm, + lexer: Token::lexer(code), + symloc: HashMap::default(), + }; + + asm.run() + .map_err(|kind| Error { kind, span: asm.lexer.span() })?; + for &loc in &asm.asm.sub { + let val = asm.symloc + .get( + &Spur::try_from_usize(bytemuck::pod_read_unaligned::(&asm.asm.buf[loc..loc+core::mem::size_of::()]) as _) + .unwrap() + ) + .ok_or(Error { kind: ErrorKind::InvalidSymbol, span: 0..0 })? + .to_le_bytes(); + + asm.asm.buf[loc..] + .iter_mut() + .zip(val) + .for_each(|(dst, src)| *dst = src); + } + + Ok(()) + } + + enum InternalImm { + Const(u64), + Named(Spur), + } + + impl $crate::Imm for InternalImm { + #[inline] + fn insert(&self, asm: &mut Assembler) { + match self { + Self::Const(a) => a.insert(asm), + Self::Named(a) => $crate::Symbol(*a).insert(asm), + } + } } } }; } macro_rules! extract_pat { - ($lexer:expr, $pat:pat) => { - let $pat = next($lexer)? - else { return Err(ErrorKind::UnexpectedToken) }; + ($self:expr, $pat:pat) => { + let $pat = $self.next()? + else { return Err(ErrorKind::UnexpectedToken) }; }; } macro_rules! extract { - ($lexer:expr, R, $id:ident) => { - extract_pat!($lexer, Token::Register($id)); + ($self:expr, R, $id:ident) => { + extract_pat!($self, Token::Register($id)); }; - ($lexer:expr, I, $id:ident) => { - extract_pat!($lexer, Token::Integer($id)); + + ($self:expr, I, $id:ident) => { + let $id = match $self.next()? { + Token::Integer(a) => InternalImm::Const(a), + Token::Symbol(a) => InternalImm::Named(a), + _ => return Err(ErrorKind::UnexpectedToken), + }; }; - ($lexer:expr, u16, $id:ident) => { - extract_pat!($lexer, Token::Integer($id)); - let $id = u16::try_from($id) - .map_err(|_| ErrorKind::InvalidToken)?; + + ($self:expr, u16, $id:ident) => { + extract_pat!($self, Token::Integer($id)); + let $id = u16::try_from($id).map_err(|_| ErrorKind::InvalidToken)?; }; } macro_rules! param_extract_itm { - ($lexer:expr, $($id:ident: $ty:ident)? $(, $($tt:tt)*)?) => { - $(extract!($lexer, $ty, $id);)? + ($self:expr, $($id:ident: $ty:ident)? $(, $($tt:tt)*)?) => { + $(extract!($self, $ty, $id);)? $( - extract_pat!($lexer, Token::PSep); - param_extract_itm!($lexer, $($tt)*); + extract_pat!($self, Token::PSep); + param_extract_itm!($self, $($tt)*); )? }; } diff --git a/hbasm/src/main.rs b/hbasm/src/main.rs index f3abbbd..d569669 100644 --- a/hbasm/src/main.rs +++ b/hbasm/src/main.rs @@ -1,3 +1,5 @@ +use std::io::Write; + use hbasm::Assembler; use { @@ -25,22 +27,28 @@ fn main() -> Result<(), Box> { let message = match e.kind { hbasm::text::ErrorKind::UnexpectedToken => "This token is not expected!", hbasm::text::ErrorKind::InvalidToken => "The token is not valid!", - hbasm::text::ErrorKind::UnexpectedEnd => "The assembler reached the end of input unexpectedly!", - hbasm::text::ErrorKind::InvalidSymbol => "This referenced symbol doesn't have a corresponding label!", + hbasm::text::ErrorKind::UnexpectedEnd => { + "The assembler reached the end of input unexpectedly!" + } + hbasm::text::ErrorKind::InvalidSymbol => { + "This referenced symbol doesn't have a corresponding label!" + } }; let a = colors.next(); Report::build(ReportKind::Error, "engine_internal", e.span.clone().start) - .with_code(e_code) - .with_message(format!("{:?}", e.kind)) - .with_label( - Label::new(("engine_internal", e.span.clone())) - .with_message(message) - .with_color(a), - ) - .finish() - .eprint(("engine_internal", Source::from(&code))) - .unwrap(); + .with_code(e_code) + .with_message(format!("{:?}", e.kind)) + .with_label( + Label::new(("engine_internal", e.span.clone())) + .with_message(message) + .with_color(a), + ) + .finish() + .eprint(("engine_internal", Source::from(&code))) + .unwrap(); + } else { + std::io::stdout().lock().write_all(&assembler.buf).unwrap(); } Ok(())