Labels
This commit is contained in:
parent
51e0db9c7d
commit
c648bf0b24
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)*);
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(())
|
||||||
|
|
Loading…
Reference in a new issue