This commit is contained in:
Erin 2023-07-12 02:12:23 +02:00 committed by ondra05
parent 51e0db9c7d
commit c648bf0b24
5 changed files with 129 additions and 61 deletions

7
Cargo.lock generated
View file

@ -35,6 +35,12 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
[[package]]
name = "bytemuck"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -101,6 +107,7 @@ name = "hbasm"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ariadne", "ariadne",
"bytemuck",
"hashbrown 0.14.0", "hashbrown 0.14.0",
"hbbytecode", "hbbytecode",
"lasso", "lasso",

View file

@ -9,6 +9,7 @@ hbbytecode = { path = "../hbbytecode" }
literify = "0.1" literify = "0.1"
paste = "1.0" paste = "1.0"
hashbrown = "0.14.0" hashbrown = "0.14.0"
bytemuck = "1.13.1"
[dependencies.lasso] [dependencies.lasso]
version = "0.7" version = "0.7"

View file

@ -1,18 +1,20 @@
#![no_std] #![no_std]
#![feature(error_in_core)] #![feature(error_in_core)]
use lasso::Key;
extern crate alloc; extern crate alloc;
pub mod text_r; pub mod text_r;
mod macros; mod macros;
use {alloc::vec::Vec, hashbrown::HashSet}; use {alloc::vec::Vec, hashbrown::HashSet, lasso::Spur};
#[derive(Default)] #[derive(Default)]
pub struct Assembler { pub struct Assembler {
pub buf: Vec<u8>, pub buf: Vec<u8>,
sub: HashSet<usize>, pub sub: HashSet<usize>,
} }
macros::impl_both!( macros::impl_both!(
@ -53,11 +55,11 @@ macro_rules! impl_imm_le_bytes {
impl_imm_le_bytes!(u64, i64, f64); impl_imm_le_bytes!(u64, i64, f64);
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Symbol(pub u64); struct Symbol(pub Spur);
impl Imm for Symbol { impl Imm for Symbol {
#[inline(always)] #[inline(always)]
fn insert(&self, asm: &mut Assembler) { fn insert(&self, asm: &mut Assembler) {
asm.sub.insert(asm.buf.len()); 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());
} }
} }

View file

@ -12,7 +12,8 @@ macro_rules! gen_text {
Assembler, Assembler,
macros::text::*, macros::text::*,
}, },
lasso::{Rodeo, Spur}, hashbrown::HashMap,
lasso::{Key, Rodeo, Spur},
logos::{Lexer, Logos, Span}, logos::{Lexer, Logos, Span},
}; };
@ -72,75 +73,124 @@ macro_rules! gen_text {
} }
pub fn assemble(asm: &mut Assembler, code: &str) -> Result<(), Error> { pub fn assemble(asm: &mut Assembler, code: &str) -> Result<(), Error> {
fn next(lexer: &mut Lexer<Token>) -> Result<Token, ErrorKind> { pub struct TextAsm<'a> {
match lexer.next() { asm: &'a mut Assembler,
Some(Ok(t)) => Ok(t), lexer: Lexer<'a, Token>,
Some(Err(())) => Err(ErrorKind::InvalidToken), symloc: HashMap<Spur, usize>,
None => Err(ErrorKind::UnexpectedEnd),
}
} }
#[inline(always)] impl<'a> TextAsm<'a> {
fn inner(asm: &mut Assembler, lexer: &mut Lexer<Token>) -> Result<(), ErrorKind> { fn next(&mut self) -> Result<Token, ErrorKind> {
loop { match self.lexer.next() {
match lexer.next() { Some(Ok(t)) => Ok(t),
Some(Ok(Token::Opcode(op))) => { Some(Err(())) => Err(ErrorKind::InvalidToken),
match op { None => Err(ErrorKind::UnexpectedEnd),
$( }
$(hbbytecode::opcode::$opcode)|* => paste::paste!({ }
param_extract_itm!(lexer, $($param_i: $param_ty),*);
asm.[<i_param_ $ityn>](op, $($param_i),*); #[inline(always)]
}), fn run(&mut self) -> Result<(), ErrorKind> {
)* loop {
_ => unreachable!(), 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.[<i_param_ $ityn>](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); let mut asm = TextAsm {
inner(asm, &mut lexer) asm,
.map_err(|kind| Error { kind, span: lexer.span() }) 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::<u64>(&asm.asm.buf[loc..loc+core::mem::size_of::<u64>()]) 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 { macro_rules! extract_pat {
($lexer:expr, $pat:pat) => { ($self:expr, $pat:pat) => {
let $pat = next($lexer)? let $pat = $self.next()?
else { return Err(ErrorKind::UnexpectedToken) }; else { return Err(ErrorKind::UnexpectedToken) };
}; };
} }
macro_rules! extract { macro_rules! extract {
($lexer:expr, R, $id:ident) => { ($self:expr, R, $id:ident) => {
extract_pat!($lexer, Token::Register($id)); 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)); ($self:expr, u16, $id:ident) => {
let $id = u16::try_from($id) extract_pat!($self, Token::Integer($id));
.map_err(|_| ErrorKind::InvalidToken)?; let $id = u16::try_from($id).map_err(|_| ErrorKind::InvalidToken)?;
}; };
} }
macro_rules! param_extract_itm { macro_rules! param_extract_itm {
($lexer:expr, $($id:ident: $ty:ident)? $(, $($tt:tt)*)?) => { ($self:expr, $($id:ident: $ty:ident)? $(, $($tt:tt)*)?) => {
$(extract!($lexer, $ty, $id);)? $(extract!($self, $ty, $id);)?
$( $(
extract_pat!($lexer, Token::PSep); extract_pat!($self, Token::PSep);
param_extract_itm!($lexer, $($tt)*); param_extract_itm!($self, $($tt)*);
)? )?
}; };
} }

View file

@ -1,3 +1,5 @@
use std::io::Write;
use hbasm::Assembler; use hbasm::Assembler;
use { use {
@ -25,22 +27,28 @@ fn main() -> Result<(), Box<dyn Error>> {
let message = match e.kind { let message = match e.kind {
hbasm::text::ErrorKind::UnexpectedToken => "This token is not expected!", hbasm::text::ErrorKind::UnexpectedToken => "This token is not expected!",
hbasm::text::ErrorKind::InvalidToken => "The token is not valid!", hbasm::text::ErrorKind::InvalidToken => "The token is not valid!",
hbasm::text::ErrorKind::UnexpectedEnd => "The assembler reached the end of input unexpectedly!", hbasm::text::ErrorKind::UnexpectedEnd => {
hbasm::text::ErrorKind::InvalidSymbol => "This referenced symbol doesn't have a corresponding label!", "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(); let a = colors.next();
Report::build(ReportKind::Error, "engine_internal", e.span.clone().start) Report::build(ReportKind::Error, "engine_internal", e.span.clone().start)
.with_code(e_code) .with_code(e_code)
.with_message(format!("{:?}", e.kind)) .with_message(format!("{:?}", e.kind))
.with_label( .with_label(
Label::new(("engine_internal", e.span.clone())) Label::new(("engine_internal", e.span.clone()))
.with_message(message) .with_message(message)
.with_color(a), .with_color(a),
) )
.finish() .finish()
.eprint(("engine_internal", Source::from(&code))) .eprint(("engine_internal", Source::from(&code)))
.unwrap(); .unwrap();
} else {
std::io::stdout().lock().write_all(&assembler.buf).unwrap();
} }
Ok(()) Ok(())