631 lines
21 KiB
Rust
631 lines
21 KiB
Rust
#![feature(debug_closure_helpers, box_as_ptr, allocator_api)]
|
|
|
|
#[cfg(test)]
|
|
mod tests;
|
|
|
|
pub mod ffi {
|
|
#![allow(
|
|
non_camel_case_types,
|
|
dead_code,
|
|
non_upper_case_globals,
|
|
improper_ctypes
|
|
)]
|
|
|
|
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
|
pub struct FFISlice {
|
|
pub ptr: *const u8,
|
|
pub len: usize,
|
|
}
|
|
|
|
#[repr(transparent)]
|
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
|
pub struct MaybeFFISlice {
|
|
inner: FFISlice,
|
|
}
|
|
|
|
impl MaybeFFISlice {
|
|
pub fn is_none(&self) -> bool {
|
|
self.inner.ptr.is_null()
|
|
}
|
|
|
|
pub fn into_option(self) -> Option<FFISlice> {
|
|
if self.is_none() {
|
|
None
|
|
} else {
|
|
Some(self.inner)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FFISlice {
|
|
/// # Safety
|
|
/// The caller must ensure that the slice is valid for type T, and lasts for 'a.
|
|
pub unsafe fn as_slice_unchecked<'a, T: Sized>(self) -> &'a [T] {
|
|
// SAFETY: The caller ensures that the FFISlice is valid for type T.
|
|
unsafe { core::slice::from_raw_parts(self.ptr.cast(), self.len) }
|
|
}
|
|
|
|
/// # Safety
|
|
/// The caller ensures that the slice is valid byte slice.
|
|
/// Namely, the pointer must be well-aligned and point to `len` bytes, and
|
|
/// must last for at least 'a.
|
|
pub fn as_u8s_unchecked<'a>(self) -> &'a [u8] {
|
|
// SAFETY: The FFISlice is guaranteed to be a valid byte slice.
|
|
unsafe { self.as_slice_unchecked() }
|
|
}
|
|
/// # Safety
|
|
/// The caller must ensure that the slice is a valid utf8 string.
|
|
/// Furthermore, the pointer must be well-aligned, point to `len` bytes, and
|
|
/// must last for at least 'a.
|
|
pub unsafe fn as_str_unchecked<'a>(self) -> &'a str {
|
|
// SAFETY: The caller ensures that the FFISlice is a valid utf8 string.
|
|
unsafe { core::str::from_utf8_unchecked(self.as_u8s_unchecked()) }
|
|
}
|
|
}
|
|
|
|
pub mod vec {
|
|
#![allow(dead_code)]
|
|
|
|
impl Default for BlobVec {
|
|
fn default() -> Self {
|
|
Self {
|
|
data: core::ptr::null_mut(),
|
|
len: 0,
|
|
cap: 0,
|
|
elem_size: 0,
|
|
drop: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl Send for BlobVec {}
|
|
unsafe impl Sync for BlobVec {}
|
|
|
|
use super::ffi::*;
|
|
|
|
#[repr(transparent)]
|
|
#[derive(Debug)]
|
|
pub struct Vec<T> {
|
|
pub vec: BlobVec,
|
|
_marker: core::marker::PhantomData<T>,
|
|
}
|
|
|
|
impl<T> Default for Vec<T> {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl<T> Drop for Vec<T> {
|
|
fn drop(&mut self) {
|
|
// SAFETY: The vec is valid and owned by self.
|
|
unsafe {
|
|
vec_drop(&mut self.vec);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> Vec<T> {
|
|
pub fn new() -> Self {
|
|
Self::new_with(32)
|
|
}
|
|
|
|
pub fn new_with(capacity: usize) -> Self {
|
|
let mut vec = BlobVec {
|
|
data: core::ptr::null_mut(),
|
|
len: 0,
|
|
cap: 0,
|
|
elem_size: 0,
|
|
drop: None,
|
|
};
|
|
|
|
unsafe extern "C" fn drop_fn<T>(ptr: *mut ()) {
|
|
unsafe {
|
|
core::ptr::drop_in_place::<T>(ptr as *mut T);
|
|
}
|
|
}
|
|
|
|
unsafe {
|
|
vec_init_with(
|
|
&mut vec,
|
|
core::mem::size_of::<T>(),
|
|
Some(drop_fn::<T>),
|
|
capacity,
|
|
);
|
|
}
|
|
|
|
Self {
|
|
vec,
|
|
_marker: core::marker::PhantomData,
|
|
}
|
|
}
|
|
|
|
pub fn as_slice(&self) -> &[T] {
|
|
assert_eq!(self.vec.elem_size, core::mem::size_of::<T>());
|
|
unsafe { core::slice::from_raw_parts(self.vec.data as *const T, self.vec.len) }
|
|
}
|
|
|
|
pub fn as_slice_mut(&mut self) -> &mut [T] {
|
|
assert_eq!(self.vec.elem_size, core::mem::size_of::<T>());
|
|
unsafe { core::slice::from_raw_parts_mut(self.vec.data as *mut T, self.vec.len) }
|
|
}
|
|
|
|
pub fn extend(&mut self, elements: Box<[T]>) {
|
|
unsafe {
|
|
let elements =
|
|
core::mem::transmute::<Box<[T]>, Box<[core::mem::ManuallyDrop<T>]>>(elements);
|
|
vec_extend(&mut self.vec, elements.as_ptr() as *const _, elements.len());
|
|
}
|
|
}
|
|
|
|
pub fn push(&mut self, value: T) {
|
|
let value = core::mem::ManuallyDrop::new(value);
|
|
unsafe {
|
|
vec_push(&mut self.vec, &raw const value as *const T as *const _);
|
|
}
|
|
}
|
|
|
|
pub fn insert(&mut self, value: T, index: usize) {
|
|
if index > self.vec.len {
|
|
return;
|
|
}
|
|
let value = core::mem::ManuallyDrop::new(value);
|
|
unsafe {
|
|
vec_insert(
|
|
&mut self.vec,
|
|
index,
|
|
&raw const value as *const T as *const _,
|
|
);
|
|
}
|
|
}
|
|
|
|
pub fn insert_many(&mut self, index: usize, elements: Box<[T]>) {
|
|
unsafe {
|
|
let elements =
|
|
core::mem::transmute::<Box<[T]>, Box<[core::mem::ManuallyDrop<T>]>>(elements);
|
|
vec_insert_many(
|
|
&mut self.vec,
|
|
index,
|
|
elements.as_ptr() as *const _,
|
|
elements.len(),
|
|
);
|
|
}
|
|
}
|
|
|
|
pub fn pop(&mut self) -> Option<T> {
|
|
if self.vec.len == 0 {
|
|
return None;
|
|
}
|
|
unsafe {
|
|
let ptr = vec_get(&mut self.vec, self.vec.len - 1) as *mut T;
|
|
let value = ptr.read();
|
|
vec_pop(&mut self.vec);
|
|
Some(value)
|
|
}
|
|
}
|
|
|
|
pub fn get(&self, index: usize) -> Option<&T> {
|
|
if index >= self.vec.len {
|
|
return None;
|
|
}
|
|
unsafe {
|
|
let ptr = vec_get(&raw const self.vec as *mut _, index) as *mut T;
|
|
Some(&*ptr)
|
|
}
|
|
}
|
|
|
|
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
|
|
if index >= self.vec.len {
|
|
return None;
|
|
}
|
|
unsafe {
|
|
let ptr = vec_get(&raw mut self.vec, index) as *mut T;
|
|
Some(&mut *ptr)
|
|
}
|
|
}
|
|
|
|
pub fn remove(&mut self, index: usize) {
|
|
if index >= self.vec.len {
|
|
return;
|
|
}
|
|
unsafe {
|
|
vec_remove(&mut self.vec, index);
|
|
}
|
|
}
|
|
|
|
pub fn len(&self) -> usize {
|
|
self.vec.len
|
|
}
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
self.vec.len == 0
|
|
}
|
|
|
|
pub fn position<F>(&self, elem: &T, mut cmp: F) -> Option<usize>
|
|
where
|
|
F: FnMut(&T, &T) -> bool,
|
|
{
|
|
extern "C" fn cmp_trampoline<T, F: FnMut(&T, &T) -> bool>(
|
|
f: *const (),
|
|
a: *const (),
|
|
b: *const (),
|
|
) -> bool {
|
|
let f = unsafe { &mut *(f as *mut F) };
|
|
let a = unsafe { &*(a as *const T) };
|
|
let b = unsafe { &*(b as *const T) };
|
|
f(a, b)
|
|
}
|
|
|
|
unsafe {
|
|
let index = vec_find(
|
|
&raw const self.vec as *mut _,
|
|
elem as *const T as *const _,
|
|
cmp_trampoline::<T, F>,
|
|
&raw mut cmp as *mut (),
|
|
);
|
|
if index == usize::MAX {
|
|
None
|
|
} else {
|
|
Some(index)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn binary_search_by<F>(&self, elem: &T, mut cmp: F) -> Result<usize, usize>
|
|
where
|
|
F: FnMut(&T, &T) -> i32,
|
|
{
|
|
extern "C" fn cmp_trampoline<T, F: FnMut(&T, &T) -> i32>(
|
|
f: *const (),
|
|
a: *const (),
|
|
b: *const (),
|
|
) -> i32 {
|
|
let f = unsafe { &mut *(f as *mut F) };
|
|
let a = unsafe { &*(a as *const T) };
|
|
let b = unsafe { &*(b as *const T) };
|
|
f(a, b)
|
|
}
|
|
|
|
unsafe {
|
|
let (index, vacant) = vec_binary_search_by(
|
|
&raw const self.vec as *mut _,
|
|
elem as *const T as *const _,
|
|
cmp_trampoline::<T, F>,
|
|
&raw mut cmp as *mut (),
|
|
);
|
|
if vacant { Err(index) } else { Ok(index) }
|
|
}
|
|
}
|
|
|
|
pub fn insert_sorted<F>(&mut self, elem: T, mut cmp: F) -> Result<usize, usize>
|
|
where
|
|
F: FnMut(&T, &T) -> i32,
|
|
{
|
|
extern "C" fn cmp_trampoline<T, F: FnMut(&T, &T) -> i32>(
|
|
f: *const (),
|
|
a: *const (),
|
|
b: *const (),
|
|
) -> i32 {
|
|
let f = unsafe { &mut *(f as *mut F) };
|
|
let a = unsafe { &*(a as *const T) };
|
|
let b = unsafe { &*(b as *const T) };
|
|
f(a, b)
|
|
}
|
|
|
|
let mut elem = core::mem::ManuallyDrop::new(elem);
|
|
|
|
unsafe {
|
|
let (index, _inserted) = vec_insert_sorted(
|
|
&raw const self.vec as *mut _,
|
|
&raw mut elem as *const _,
|
|
cmp_trampoline::<T, F>,
|
|
&raw mut cmp as *mut (),
|
|
);
|
|
Ok(index)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
mod display {
|
|
use super::ffi::{self, Ast, AstNode};
|
|
|
|
impl core::fmt::Display for AstNode {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
use crate::ffi::{
|
|
AST_ADDRESS_OF, AST_ARG, AST_AS, AST_ASSIGNMENT, AST_BINARY_OP, AST_BLOCK,
|
|
AST_CALL, AST_DEREF, AST_FUNCTION, AST_IF, AST_NUMBER, AST_PLACE_TO_VALUE,
|
|
AST_RETURN_STATEMENT, AST_VALUE_TO_PLACE, AST_VAR_DECL, AST_VAR_REF, BinaryExpr,
|
|
};
|
|
match self.kind {
|
|
AST_NUMBER => {
|
|
write!(f, "Number({})", self.data as usize)
|
|
}
|
|
AST_DEREF => {
|
|
write!(f, "Deref(expr: {})", self.data as usize)
|
|
}
|
|
AST_ADDRESS_OF => {
|
|
write!(f, "AddressOf(expr: {})", self.data as usize)
|
|
}
|
|
AST_CALL => {
|
|
let call = unsafe { self.data.cast::<crate::ffi::AstCallExpr>().read() };
|
|
write!(f, "Call(callee: {}, params: {:?})", call.callee, unsafe {
|
|
std::slice::from_raw_parts(call.params.cast::<u64>(), call.params_len)
|
|
},)
|
|
}
|
|
AST_AS => {
|
|
let as_expr = unsafe { self.data.cast::<crate::ffi::AstAsExpr>().read() };
|
|
write!(f, "As(expr: {}, target_type: {})", as_expr.expr, as_expr.ty)
|
|
}
|
|
AST_ARG => {
|
|
let arg = unsafe { self.data.cast::<crate::ffi::AstArgument>().read() };
|
|
write!(
|
|
f,
|
|
"Arg(name: {:?}, arg_type: {})",
|
|
unsafe {
|
|
std::str::from_utf8(std::slice::from_raw_parts(arg.name, arg.name_len))
|
|
},
|
|
arg.arg_type,
|
|
)
|
|
}
|
|
AST_VAR_REF => {
|
|
let var_ref = unsafe { self.data.cast::<crate::ffi::AstVarRef>().read() };
|
|
if var_ref.resolved != u64::MAX {
|
|
write!(f, "VarRef({})", var_ref.resolved)
|
|
} else {
|
|
write!(f, "VarRef(name: {:?})", unsafe {
|
|
std::str::from_utf8(std::slice::from_raw_parts(
|
|
var_ref.name,
|
|
var_ref.name_len,
|
|
))
|
|
},)
|
|
}
|
|
}
|
|
AST_VAR_DECL => {
|
|
let var_decl = unsafe { self.data.cast::<crate::ffi::AstVarDecl>().read() };
|
|
write!(
|
|
f,
|
|
"VarDecl(name: {:?}, var_type: {})",
|
|
unsafe {
|
|
std::str::from_utf8(std::slice::from_raw_parts(
|
|
var_decl.name,
|
|
var_decl.name_len,
|
|
))
|
|
},
|
|
var_decl.var_type,
|
|
)
|
|
}
|
|
AST_ASSIGNMENT => {
|
|
write!(
|
|
f,
|
|
"Assignment(dest: {}, src: {})",
|
|
self.data as usize, self.extra
|
|
)
|
|
}
|
|
AST_BINARY_OP => {
|
|
let BinaryExpr {
|
|
left,
|
|
operator,
|
|
right,
|
|
} = unsafe { self.data.cast::<crate::ffi::BinaryExpr>().read() };
|
|
write!(
|
|
f,
|
|
"BinaryOp(op: {}, left: {}, right: {})",
|
|
operator, left, right
|
|
)
|
|
}
|
|
AST_RETURN_STATEMENT => {
|
|
let return_expr_id = self.data as usize;
|
|
write!(f, "ReturnStatement(expr: {})", return_expr_id)
|
|
}
|
|
AST_FUNCTION => {
|
|
let func = unsafe { self.data.cast::<crate::ffi::AstFunction>().read() };
|
|
write!(
|
|
f,
|
|
"Function(name: {:?}, args: {:?}, return_type: {}, body: {})",
|
|
unsafe {
|
|
std::str::from_utf8(std::slice::from_raw_parts(
|
|
func.name,
|
|
func.name_len,
|
|
))
|
|
},
|
|
unsafe {
|
|
std::slice::from_raw_parts(func.args.cast::<u64>(), func.args_len)
|
|
},
|
|
func.return_type,
|
|
func.body
|
|
)
|
|
}
|
|
AST_BLOCK => {
|
|
write!(f, "Block(statements: {:?})", unsafe {
|
|
std::slice::from_raw_parts(self.data.cast::<u64>(), self.extra)
|
|
})
|
|
}
|
|
AST_IF => {
|
|
let if_node = unsafe { self.data.cast::<crate::ffi::AstIfExpr>().read() };
|
|
write!(
|
|
f,
|
|
"If(cond: {}, then_branch: {}, else_branch: {:?})",
|
|
if_node.condition,
|
|
if_node.then,
|
|
match if_node.else_ {
|
|
u64::MAX => None,
|
|
v => Some(v),
|
|
}
|
|
)
|
|
}
|
|
AST_PLACE_TO_VALUE => {
|
|
write!(f, "PlaceToValue(place: {})", self.data as usize)
|
|
}
|
|
AST_VALUE_TO_PLACE => {
|
|
write!(f, "ValueToPlace(value: {})", self.data as usize)
|
|
}
|
|
kind => write!(f, "UnknownNode(kind: {kind})"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl core::fmt::Display for Ast {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
writeln!(f, "[")?;
|
|
for (i, item) in self.nodes.as_slice().iter().enumerate() {
|
|
if i > 0 {
|
|
writeln!(f, ", ")?;
|
|
}
|
|
write!(f, "\t{i}: {}", item)?;
|
|
}
|
|
write!(f, "\n]")
|
|
}
|
|
}
|
|
|
|
impl core::fmt::Display for ffi::SymEntry {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
f.debug_struct("SymEntry")
|
|
.field_with("key", |f| {
|
|
f.debug_struct("Key")
|
|
.field_with("kind", |f| {
|
|
f.write_str(match self.key.kind {
|
|
ffi::SYM_KEY_SCOPE => "Scope",
|
|
ffi::SYM_KEY_SCOPE_NAME => "ScopeName",
|
|
ffi::SYM_KEY_PARENT_SCOPE => "ParentScope",
|
|
ffi::SYM_KEY_ARG => "Argument",
|
|
ffi::SYM_KEY_VAR => "Variable",
|
|
ffi::SYM_KEY_FUNCTION => "Function",
|
|
_ => "Unknown",
|
|
})
|
|
})
|
|
.field("scope", &self.key.scope_index)
|
|
.field("span", &self.key.span)
|
|
.field_with("ident", |f| {
|
|
f.write_str(unsafe {
|
|
core::str::from_utf8_unchecked(core::slice::from_raw_parts(
|
|
self.key.ident,
|
|
self.key.ident_len,
|
|
))
|
|
})
|
|
})
|
|
.finish()
|
|
})
|
|
.field_with("value", |f| {
|
|
let stct = &mut f.debug_struct("Value");
|
|
if self.extra == 0 {
|
|
stct.field("ast_index", &self.index).finish()
|
|
} else if self.index != 0 {
|
|
stct.field_with("ident", |f| {
|
|
f.write_str(unsafe {
|
|
core::str::from_utf8_unchecked(core::slice::from_raw_parts(
|
|
self.index as *const u8,
|
|
self.extra as usize,
|
|
))
|
|
})
|
|
})
|
|
.finish()
|
|
} else {
|
|
stct.field("index", &self.index)
|
|
.field("extra", &self.extra)
|
|
.finish()
|
|
}
|
|
})
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl core::fmt::Display for ffi::Type {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
use ffi::{
|
|
TYPE_BOOL, TYPE_F32, TYPE_F64, TYPE_I8, TYPE_I16, TYPE_I32, TYPE_I64, TYPE_ISIZE,
|
|
TYPE_POINTER, TYPE_STR, TYPE_U8, TYPE_U16, TYPE_U32, TYPE_U64, TYPE_USIZE,
|
|
TYPE_VOID,
|
|
};
|
|
match self.kind {
|
|
TYPE_VOID => {
|
|
write!(f, "void")
|
|
}
|
|
TYPE_BOOL => {
|
|
write!(f, "bool")
|
|
}
|
|
TYPE_I32 => {
|
|
write!(f, "i32")
|
|
}
|
|
TYPE_U32 => {
|
|
write!(f, "u32")
|
|
}
|
|
TYPE_STR => {
|
|
write!(f, "str")
|
|
}
|
|
TYPE_POINTER => {
|
|
let pointee = unsafe { (self.data as *const ffi::Type).read() };
|
|
write!(f, "*{pointee}",)
|
|
}
|
|
TYPE_I8 => {
|
|
write!(f, "i8")
|
|
}
|
|
TYPE_U8 => {
|
|
write!(f, "u8")
|
|
}
|
|
TYPE_I16 => {
|
|
write!(f, "i16")
|
|
}
|
|
TYPE_U16 => {
|
|
write!(f, "u16")
|
|
}
|
|
TYPE_I64 => {
|
|
write!(f, "i64")
|
|
}
|
|
TYPE_U64 => {
|
|
write!(f, "u64")
|
|
}
|
|
TYPE_F32 => {
|
|
write!(f, "f32")
|
|
}
|
|
TYPE_F64 => {
|
|
write!(f, "f64")
|
|
}
|
|
TYPE_USIZE => {
|
|
write!(f, "usize")
|
|
}
|
|
TYPE_ISIZE => {
|
|
write!(f, "isize")
|
|
}
|
|
_ => {
|
|
write!(f, "UnknownType")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[repr(transparent)]
|
|
pub struct Displayed<T: core::fmt::Display>(pub T);
|
|
impl<T: core::fmt::Display> core::fmt::Debug for Displayed<T> {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
write!(f, "{}", self.0)
|
|
}
|
|
}
|
|
|
|
pub trait DisplayedSliceExt {
|
|
type Displayed: core::fmt::Debug;
|
|
fn displayed(self) -> Self::Displayed;
|
|
}
|
|
|
|
impl<'a, T: core::fmt::Display> DisplayedSliceExt for &'a [T] {
|
|
type Displayed = &'a [Displayed<T>];
|
|
fn displayed(self) -> Self::Displayed {
|
|
unsafe { core::mem::transmute(self) }
|
|
}
|
|
}
|
|
}
|
|
|
|
pub use display::{Displayed, DisplayedSliceExt};
|
|
|
|
impl Default for ffi::Ast {
|
|
fn default() -> Self {
|
|
ffi::Ast {
|
|
nodes: vec::Vec::default(),
|
|
}
|
|
}
|
|
}
|