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"
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",

View file

@ -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"

View file

@ -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<u8>,
sub: HashSet<usize>,
pub sub: HashSet<usize>,
}
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());
}
}

View file

@ -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<Token>) -> Result<Token, ErrorKind> {
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<Spur, usize>,
}
#[inline(always)]
fn inner(asm: &mut Assembler, lexer: &mut Lexer<Token>) -> 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.[<i_param_ $ityn>](op, $($param_i),*);
}),
)*
_ => unreachable!(),
impl<'a> TextAsm<'a> {
fn next(&mut self) -> Result<Token, ErrorKind> {
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.[<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);
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::<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 {
($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)*);
)?
};
}

View file

@ -1,3 +1,5 @@
use std::io::Write;
use hbasm::Assembler;
use {
@ -25,22 +27,28 @@ fn main() -> Result<(), Box<dyn Error>> {
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(())