starting the compiler wasm
This commit is contained in:
parent
5ef1ec4811
commit
07638caff0
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -808,6 +808,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-hbc"
|
name = "wasm-hbc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"hblang",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-hbfmt"
|
name = "wasm-hbfmt"
|
||||||
|
|
|
@ -20,8 +20,8 @@ hbjit = { path = "jit" }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
debug = true
|
#debug = true
|
||||||
#strip = true
|
strip = true
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,11 @@ pub fn handle_panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
core::arch::wasm32::unreachable();
|
core::arch::wasm32::unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#[no_mangle]
|
||||||
|
//static mut PANIC_MESSAGE: [u8; 1024] = [0; 1024];
|
||||||
|
//#[no_mangle]
|
||||||
|
//static mut PANIC_MESSAGE_LEN: usize = 0;
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOCATOR: ArenaAllocator = ArenaAllocator::new();
|
static ALLOCATOR: ArenaAllocator = ArenaAllocator::new();
|
||||||
|
|
||||||
|
@ -94,20 +99,15 @@ impl core::fmt::Write for Write<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//#[no_mangle]
|
|
||||||
//static mut PANIC_MESSAGE: [u8; 1024] = unsafe { core::mem::zeroed() };
|
|
||||||
//#[no_mangle]
|
|
||||||
//static mut PANIC_MESSAGE_LEN: usize = 0;
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static mut OUTPUT: [u8; MAX_OUTPUT_SIZE] = unsafe { core::mem::zeroed() };
|
static mut OUTPUT: [u8; MAX_OUTPUT_SIZE] = [0; MAX_OUTPUT_SIZE];
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static mut OUTPUT_LEN: usize = 0;
|
static mut OUTPUT_LEN: usize = 0;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static MAX_INPUT: usize = MAX_INPUT_SIZE;
|
static MAX_INPUT: usize = MAX_INPUT_SIZE;
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static mut INPUT: [u8; MAX_INPUT_SIZE] = unsafe { core::mem::zeroed() };
|
static mut INPUT: [u8; MAX_INPUT_SIZE] = [0; MAX_INPUT_SIZE];
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static mut INPUT_LEN: usize = 0;
|
static mut INPUT_LEN: usize = 0;
|
||||||
|
|
||||||
|
|
|
@ -3,4 +3,8 @@ name = "wasm-hbc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
hblang.workspace = true
|
||||||
|
|
|
@ -1,14 +1,151 @@
|
||||||
pub fn add(left: u64, right: u64) -> u64 {
|
#![feature(alloc_error_handler)]
|
||||||
left + right
|
#![no_std]
|
||||||
|
|
||||||
|
use {
|
||||||
|
alloc::{borrow::ToOwned, string::String, vec::Vec},
|
||||||
|
core::{
|
||||||
|
alloc::{GlobalAlloc, Layout},
|
||||||
|
cell::UnsafeCell,
|
||||||
|
},
|
||||||
|
hblang::{codegen::Codegen, parser::FileId},
|
||||||
|
};
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
const ARENA_SIZE: usize = 4 * 128 * 1024;
|
||||||
|
const MAX_PANIC_SIZE: usize = 1024 * 4;
|
||||||
|
const MAX_INPUT_SIZE: usize = 32 * 4 * 1024;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
#[panic_handler]
|
||||||
|
pub fn handle_panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
unsafe {
|
||||||
|
use core::fmt::Write;
|
||||||
|
let mut f = Write(&mut PANIC_MESSAGE[..]);
|
||||||
|
_ = writeln!(f, "{}", info);
|
||||||
|
PANIC_MESSAGE_LEN = 1024 - f.0.len();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
core::arch::wasm32::unreachable();
|
||||||
mod tests {
|
}
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
#[no_mangle]
|
||||||
fn it_works() {
|
static mut PANIC_MESSAGE: [u8; MAX_PANIC_SIZE] = [0; MAX_PANIC_SIZE];
|
||||||
let result = add(2, 2);
|
#[no_mangle]
|
||||||
assert_eq!(result, 4);
|
static mut PANIC_MESSAGE_LEN: usize = 0;
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: ArenaAllocator = ArenaAllocator::new();
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn alloc_error(_: core::alloc::Layout) -> ! {
|
||||||
|
core::arch::wasm32::unreachable()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, align(32))]
|
||||||
|
struct ArenaAllocator {
|
||||||
|
arena: UnsafeCell<[u8; ARENA_SIZE]>,
|
||||||
|
head: UnsafeCell<*mut u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArenaAllocator {
|
||||||
|
const fn new() -> Self {
|
||||||
|
ArenaAllocator {
|
||||||
|
arena: UnsafeCell::new([0; ARENA_SIZE]),
|
||||||
|
head: UnsafeCell::new(core::ptr::null_mut()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn reset(&self) {
|
||||||
|
(*self.head.get()) = self.arena.get().cast::<u8>().add(ARENA_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for ArenaAllocator {}
|
||||||
|
|
||||||
|
unsafe impl GlobalAlloc for ArenaAllocator {
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
|
let size = layout.size();
|
||||||
|
let align = layout.align();
|
||||||
|
|
||||||
|
let until = self.arena.get() as *mut u8;
|
||||||
|
|
||||||
|
let new_head = (*self.head.get()).sub(size);
|
||||||
|
let aligned_head = (new_head as usize & !(1 << (align - 1))) as *mut u8;
|
||||||
|
|
||||||
|
if until > aligned_head {
|
||||||
|
return core::ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
*self.head.get() = aligned_head;
|
||||||
|
aligned_head
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
|
||||||
|
/* lol */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
static MAX_INPUT: usize = MAX_INPUT_SIZE;
|
||||||
|
#[no_mangle]
|
||||||
|
static mut INPUT_LEN: usize = 0;
|
||||||
|
#[no_mangle]
|
||||||
|
static mut INPUT: [u8; MAX_INPUT_SIZE] = [0; MAX_INPUT_SIZE];
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe fn compile_and_run() {
|
||||||
|
ALLOCATOR.reset();
|
||||||
|
|
||||||
|
struct File<'a> {
|
||||||
|
path: &'a str,
|
||||||
|
code: &'a mut str,
|
||||||
|
}
|
||||||
|
|
||||||
|
let files = {
|
||||||
|
let mut input_bytes =
|
||||||
|
core::slice::from_raw_parts_mut(core::ptr::addr_of_mut!(INPUT).cast::<u8>(), INPUT_LEN);
|
||||||
|
|
||||||
|
let mut files = Vec::with_capacity(32);
|
||||||
|
while let Some((&mut path_len, rest)) = input_bytes.split_first_chunk_mut() {
|
||||||
|
let (path, rest) = rest.split_at_mut(u16::from_le_bytes(path_len) as usize);
|
||||||
|
let (&mut code_len, rest) = rest.split_first_chunk_mut().unwrap();
|
||||||
|
let (code, rest) = rest.split_at_mut(u16::from_le_bytes(code_len) as usize);
|
||||||
|
files.push(File {
|
||||||
|
path: core::str::from_utf8_unchecked(path),
|
||||||
|
code: core::str::from_utf8_unchecked_mut(code),
|
||||||
|
});
|
||||||
|
input_bytes = rest;
|
||||||
|
}
|
||||||
|
files.sort_unstable_by_key(|f| f.path);
|
||||||
|
files
|
||||||
|
};
|
||||||
|
|
||||||
|
let files = {
|
||||||
|
let mut ctx = hblang::parser::ParserCtx::default();
|
||||||
|
let paths = files.iter().map(|f| f.path).collect::<Vec<_>>();
|
||||||
|
let mut loader = |path: &str, _: &str| Ok(paths.binary_search(&path).unwrap() as FileId);
|
||||||
|
files
|
||||||
|
.into_iter()
|
||||||
|
.map(|f| {
|
||||||
|
hblang::parser::Ast::new(
|
||||||
|
f.path,
|
||||||
|
// since 'free' does nothing this is fine
|
||||||
|
String::from_raw_parts(f.code.as_mut_ptr(), f.code.len(), f.code.len()),
|
||||||
|
&mut ctx,
|
||||||
|
&mut loader,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
};
|
||||||
|
|
||||||
|
let code = {
|
||||||
|
let mut c = Codegen::default();
|
||||||
|
c.files = files;
|
||||||
|
c.generate();
|
||||||
|
let mut buf = Vec::with_capacity(1024 * 8);
|
||||||
|
c.assemble(&mut buf);
|
||||||
|
buf
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -2703,9 +2703,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_log(&self, pos: Pos, msg: impl core::fmt::Display) {
|
fn report_log(&self, pos: Pos, msg: impl core::fmt::Display) {
|
||||||
let mut out = String::new();
|
log::error!("{}", self.cfile().report(pos, msg));
|
||||||
self.cfile().report_to(pos, msg, &mut out);
|
|
||||||
log::error!("{out}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
@ -2716,13 +2714,11 @@ impl Codegen {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn report_unhandled_ast(&self, ast: &Expr, hint: &str) -> ! {
|
fn report_unhandled_ast(&self, ast: &Expr, hint: &str) -> ! {
|
||||||
|
log::debug!("{ast:#?}");
|
||||||
self.report(
|
self.report(
|
||||||
ast.pos(),
|
ast.pos(),
|
||||||
format_args!(
|
format_args!(
|
||||||
"compiler does not (yet) know how to handle ({hint}):\n\
|
"compiler does not (yet) know how to handle ({hint}):\n{}",
|
||||||
{:}\n\
|
|
||||||
info for weak people:\n\
|
|
||||||
{ast:#?}",
|
|
||||||
self.ast_display(ast)
|
self.ast_display(ast)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -583,11 +583,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn report(&self, pos: Pos, msg: impl fmt::Display) -> ! {
|
fn report(&self, pos: Pos, msg: impl fmt::Display) -> ! {
|
||||||
log::error!("{}", {
|
log::error!("{}", Report::new(self.lexer.source(), self.path, pos, msg));
|
||||||
let mut str = String::new();
|
|
||||||
report_to(self.lexer.source(), self.path, pos, msg, &mut str);
|
|
||||||
str
|
|
||||||
});
|
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1011,18 +1007,12 @@ impl AstInner<[Symbol]> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report_to(&self, pos: Pos, msg: impl fmt::Display, out: &mut impl fmt::Write) {
|
pub fn report<D>(&self, pos: Pos, msg: D) -> Report<D> {
|
||||||
report_to(&self.file, &self.path, pos, msg, out);
|
Report::new(&self.file, &self.path, pos, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report_to(
|
fn report_to(file: &str, path: &str, pos: Pos, msg: impl fmt::Display, out: &mut impl fmt::Write) {
|
||||||
file: &str,
|
|
||||||
path: &str,
|
|
||||||
pos: Pos,
|
|
||||||
msg: impl fmt::Display,
|
|
||||||
out: &mut impl fmt::Write,
|
|
||||||
) {
|
|
||||||
let (line, mut col) = lexer::line_col(file.as_bytes(), pos);
|
let (line, mut col) = lexer::line_col(file.as_bytes(), pos);
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
let disp = crate::fs::display_rel_path(path);
|
let disp = crate::fs::display_rel_path(path);
|
||||||
|
@ -1038,6 +1028,26 @@ pub fn report_to(
|
||||||
_ = writeln!(out, "{}^", " ".repeat(col - 1));
|
_ = writeln!(out, "{}^", " ".repeat(col - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Report<'a, D> {
|
||||||
|
file: &'a str,
|
||||||
|
path: &'a str,
|
||||||
|
pos: Pos,
|
||||||
|
msg: D,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, D> Report<'a, D> {
|
||||||
|
pub fn new(file: &'a str, path: &'a str, pos: Pos, msg: D) -> Self {
|
||||||
|
Self { file, path, pos, msg }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: core::fmt::Display> core::fmt::Display for Report<'_, D> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
report_to(self.file, self.path, self.pos, &self.msg, f);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash)]
|
#[derive(PartialEq, Eq, Hash)]
|
||||||
pub struct Ast(NonNull<AstInner<[Symbol]>>);
|
pub struct Ast(NonNull<AstInner<[Symbol]>>);
|
||||||
|
|
||||||
|
|
|
@ -1101,8 +1101,6 @@ impl Codegen {
|
||||||
inps.push(m.node);
|
inps.push(m.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
let out = &mut String::new();
|
|
||||||
self.report_log_to(pos, "returning here", out);
|
|
||||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Return, inps);
|
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Return, inps);
|
||||||
|
|
||||||
self.ci.nodes[NEVER].inputs.push(self.ci.ctrl);
|
self.ci.nodes[NEVER].inputs.push(self.ci.ctrl);
|
||||||
|
@ -2153,20 +2151,6 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_log(&self, pos: Pos, msg: impl core::fmt::Display) {
|
|
||||||
let mut buf = self.errors.borrow_mut();
|
|
||||||
self.report_log_to(pos, msg, &mut *buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn report_log_to(
|
|
||||||
&self,
|
|
||||||
pos: Pos,
|
|
||||||
msg: impl core::fmt::Display,
|
|
||||||
out: &mut impl core::fmt::Write,
|
|
||||||
) {
|
|
||||||
self.cfile().report_to(pos, msg, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn assert_report(&self, cond: bool, pos: Pos, msg: impl core::fmt::Display) {
|
fn assert_report(&self, cond: bool, pos: Pos, msg: impl core::fmt::Display) {
|
||||||
if !cond {
|
if !cond {
|
||||||
|
@ -2176,20 +2160,16 @@ impl Codegen {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn report(&self, pos: Pos, msg: impl core::fmt::Display) {
|
fn report(&self, pos: Pos, msg: impl core::fmt::Display) {
|
||||||
self.report_log(pos, msg);
|
let mut buf = self.errors.borrow_mut();
|
||||||
|
writeln!(buf, "{}", self.cfile().report(pos, msg)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn report_unhandled_ast(&self, ast: &Expr, hint: &str) {
|
fn report_unhandled_ast(&self, ast: &Expr, hint: &str) {
|
||||||
|
log::debug!("{ast:#?}");
|
||||||
self.report(
|
self.report(
|
||||||
ast.pos(),
|
ast.pos(),
|
||||||
fa!(
|
fa!("compiler does not (yet) know how to handle ({hint}):\n{}", self.ast_display(ast)),
|
||||||
"compiler does not (yet) know how to handle ({hint}):\n\
|
|
||||||
{:}\n\
|
|
||||||
info for weak people:\n\
|
|
||||||
{ast:#?}",
|
|
||||||
self.ast_display(ast)
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue