Compare commits
10 commits
a90a01bc28
...
ae2cf5f9d3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae2cf5f9d3 | ||
|
|
32b8e84891 | ||
|
|
fe350da24d | ||
|
|
192c123373 | ||
|
|
07dcaf6a64 | ||
|
|
fd8a1f74bf | ||
|
|
22d85c1473 | ||
|
|
d276dd9d88 | ||
|
|
b1b48813d2 | ||
|
|
9abd3f0f69 |
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,2 +1,4 @@
|
||||||
/.direnv/
|
/.direnv/
|
||||||
lang/target
|
lang/target
|
||||||
|
lang/libcompiler/target
|
||||||
|
/target/
|
||||||
|
|
|
||||||
39
Cargo.lock
generated
Normal file
39
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.2.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3"
|
||||||
|
dependencies = [
|
||||||
|
"find-msvc-tools",
|
||||||
|
"shlex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "find-msvc-tools"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcompiler"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typeck"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"libcompiler",
|
||||||
|
]
|
||||||
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
[workspace]
|
||||||
|
resolver = "3"
|
||||||
|
|
||||||
|
members = [
|
||||||
|
"lang/libcompiler",
|
||||||
|
"lang/typeck",
|
||||||
|
]
|
||||||
9
lang/libcompiler/Cargo.toml
Normal file
9
lang/libcompiler/Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "libcompiler"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = "1.0"
|
||||||
70
lang/libcompiler/build.rs
Normal file
70
lang/libcompiler/build.rs
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let out_dir = std::env::var_os("OUT_DIR").unwrap();
|
||||||
|
let out_dir = Path::new(&out_dir);
|
||||||
|
let manifest_dir = std::env::var_os("CARGO_MANIFEST_DIR").unwrap();
|
||||||
|
let manifest_dir = Path::new(&manifest_dir);
|
||||||
|
|
||||||
|
let assembly_files = [
|
||||||
|
"src/alloc.asm",
|
||||||
|
"src/ast.asm",
|
||||||
|
"src/codegen.asm",
|
||||||
|
"src/vec.asm",
|
||||||
|
"src/tokeniser.asm",
|
||||||
|
"src/lib.asm",
|
||||||
|
"src/int_to_str.asm",
|
||||||
|
"src/file.asm",
|
||||||
|
];
|
||||||
|
|
||||||
|
let include_files = ["src/tokeniser.inc", "src/ast.inc"];
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
for file in assembly_files.iter().chain(include_files.iter()) {
|
||||||
|
println!(
|
||||||
|
"cargo:rerun-if-changed={}/{}",
|
||||||
|
manifest_dir.parent().unwrap().display(),
|
||||||
|
file
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-search=native={}", out_dir.display());
|
||||||
|
let working_dir = manifest_dir.parent().unwrap();
|
||||||
|
for file in assembly_files.iter().map(|f| Path::new(f)) {
|
||||||
|
let path = working_dir.join(file);
|
||||||
|
let obj = file.with_extension("o").file_name().unwrap().to_owned();
|
||||||
|
let lib = format!("lib{}.a", file.file_stem().unwrap().to_str().unwrap());
|
||||||
|
std::process::Command::new("nasm")
|
||||||
|
.current_dir(working_dir)
|
||||||
|
.arg(path)
|
||||||
|
.arg("-g")
|
||||||
|
.arg("-f")
|
||||||
|
.arg("elf64")
|
||||||
|
.arg("-o")
|
||||||
|
.arg(out_dir.join(&obj))
|
||||||
|
.status()
|
||||||
|
.expect("Failed to assemble assembly files");
|
||||||
|
std::process::Command::new("ar")
|
||||||
|
.current_dir(working_dir)
|
||||||
|
.arg("crs")
|
||||||
|
.arg(out_dir.join(lib))
|
||||||
|
.arg(out_dir.join(obj))
|
||||||
|
.status()
|
||||||
|
.expect("Failed to create static library from object files");
|
||||||
|
println!(
|
||||||
|
"cargo:rustc-link-lib=static={}",
|
||||||
|
file.file_stem().unwrap().to_str().unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::process::Command::new("../tools/asm2rust")
|
||||||
|
.current_dir(working_dir)
|
||||||
|
.args(&assembly_files)
|
||||||
|
.args(&include_files)
|
||||||
|
.arg("-o")
|
||||||
|
.arg(out_dir
|
||||||
|
.join("bindings.rs")
|
||||||
|
)
|
||||||
|
.status().expect("Failed to generate Rust bindings from assembly files");
|
||||||
|
}
|
||||||
612
lang/libcompiler/src/lib.rs
Normal file
612
lang/libcompiler/src/lib.rs
Normal file
|
|
@ -0,0 +1,612 @@
|
||||||
|
#![feature(debug_closure_helpers)]
|
||||||
|
|
||||||
|
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)]
|
||||||
|
pub struct FFISlice {
|
||||||
|
pub ptr: *const u8,
|
||||||
|
pub len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
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.
|
||||||
|
pub unsafe fn as_slice<T: Sized>(&self) -> &[T] {
|
||||||
|
// SAFETY: The caller ensures that the FFISlice is valid for type T.
|
||||||
|
unsafe { core::slice::from_raw_parts(self.ptr.cast(), self.len) }
|
||||||
|
}
|
||||||
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
|
// SAFETY: The FFISlice is guaranteed to be a valid byte slice.
|
||||||
|
unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
|
||||||
|
}
|
||||||
|
/// # Safety
|
||||||
|
/// The caller must ensure that the slice is a valid utf8 string.
|
||||||
|
pub unsafe fn as_str(&self) -> &str {
|
||||||
|
// SAFETY: The caller ensures that the FFISlice is a valid utf8 string.
|
||||||
|
unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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};
|
||||||
|
|
@ -15,6 +15,7 @@ extern allocate
|
||||||
extern vec_init
|
extern vec_init
|
||||||
extern vec_push
|
extern vec_push
|
||||||
extern vec_get
|
extern vec_get
|
||||||
|
extern vec_try_grow_with
|
||||||
|
|
||||||
|
|
||||||
global bump_init
|
global bump_init
|
||||||
|
|
@ -29,14 +30,21 @@ mmap_alloc:
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
;; define-fn: fn bump_init()
|
||||||
bump_init:
|
bump_init:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
||||||
lea rdi, [rel free_list]
|
mov rdi, 0x1000
|
||||||
mov rsi, 16
|
call mmap_alloc
|
||||||
mov rdx, 0
|
lea rdx, [rel free_list]
|
||||||
call vec_init
|
mov [rdx], rax
|
||||||
|
mov qword [rdx + 8], 0 ; size 0
|
||||||
|
mov rax, 0x1000
|
||||||
|
shr rax, 4 ; capacity in blocks of 16 bytes
|
||||||
|
mov qword [rdx + 16], rax ; capacity
|
||||||
|
mov qword [rdx + 24], 16 ; elem_size = 16
|
||||||
|
mov qword [rdx + 32], 0 ; drop = None
|
||||||
|
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
@ -50,6 +58,20 @@ bump_new_block:
|
||||||
ja .mmap
|
ja .mmap
|
||||||
mov rdi, 4096
|
mov rdi, 4096
|
||||||
.mmap:
|
.mmap:
|
||||||
|
|
||||||
|
push rdi
|
||||||
|
|
||||||
|
lea rdi, [rel free_list]
|
||||||
|
mov rsi, [rdi + 8]
|
||||||
|
mov rax, rsi
|
||||||
|
shr rax, 1
|
||||||
|
add rax, 1
|
||||||
|
add rsi, rax
|
||||||
|
mov rdx, mmap_alloc
|
||||||
|
call vec_try_grow_with
|
||||||
|
|
||||||
|
pop rdi
|
||||||
|
|
||||||
; next power of 2
|
; next power of 2
|
||||||
lea rax, [rdi - 1]
|
lea rax, [rdi - 1]
|
||||||
lzcnt rax, rax
|
lzcnt rax, rax
|
||||||
|
|
@ -75,8 +97,38 @@ bump_new_block:
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
;; rdi: num
|
||||||
|
;; rsi: multiple
|
||||||
|
next_multiple_of:
|
||||||
|
test rsi, rsi
|
||||||
|
je .l1
|
||||||
|
mov rax, rdi
|
||||||
|
or rax, rsi
|
||||||
|
shr rax, 32
|
||||||
|
je .l2
|
||||||
|
mov rax, rdi
|
||||||
|
xor edx, edx
|
||||||
|
div rsi
|
||||||
|
jmp .l3
|
||||||
|
.l2:
|
||||||
|
mov eax, edi
|
||||||
|
xor edx, edx
|
||||||
|
div esi
|
||||||
|
.l3:
|
||||||
|
sub rsi, rdx
|
||||||
|
test rdx, rdx
|
||||||
|
cmove rsi, rdx
|
||||||
|
add rsi, rdi
|
||||||
|
mov rax, rsi
|
||||||
|
ret
|
||||||
|
.l1:
|
||||||
|
mov rax, rdi
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
;; rdi: number of bytes to allocate
|
;; rdi: number of bytes to allocate
|
||||||
;; rsi: alignment
|
;; rsi: alignment
|
||||||
|
;; define-fn: fn bump_alloc(size: usize, alignment: usize) -> *mut u8
|
||||||
bump_alloc:
|
bump_alloc:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -104,25 +156,21 @@ bump_alloc:
|
||||||
|
|
||||||
; check for space
|
; check for space
|
||||||
; block_ptr.next_multiple_of(alignment) + size <= block_ptr + block_size
|
; block_ptr.next_multiple_of(alignment) + size <= block_ptr + block_size
|
||||||
mov rcx, [rsp + 8] ; alignment
|
mov rdi, rdx
|
||||||
; let ptr = block_ptr | alignment
|
mov rsi, [rsp + 8] ; alignment
|
||||||
or rax, rcx ; align up
|
call next_multiple_of
|
||||||
xor rdx, rdx ; clear high qword
|
; rax = aligned_ptr
|
||||||
; let rem = ptr % alignment
|
|
||||||
div rcx
|
mov rdx, rax
|
||||||
; let diff = alignment - rem
|
add rdx, qword [rsp] ; ptr + size
|
||||||
sub rcx, rdx
|
; rdx = new_end
|
||||||
mov rax, [rsp + 16] ; block+ptr
|
|
||||||
; let aligned_ptr = block_ptr + diff
|
mov rcx, [rsp + 16] ; block_ptr
|
||||||
add rax, rcx
|
add rcx, [rsp + 24] ; block_size
|
||||||
; let aligned_end = aligned_ptr + size
|
|
||||||
add rax, [rsp] ; size
|
cmp rdx, rcx
|
||||||
; let block_end = block_ptr + block_size
|
|
||||||
mov rdx, [rsp + 16] ; block_ptr
|
|
||||||
add rdx, [rsp + 24] ; block_ptr + block_size
|
|
||||||
; if aligned_end <= block_end
|
|
||||||
cmp rax, rdx
|
|
||||||
jle .found_space
|
jle .found_space
|
||||||
|
|
||||||
; else try next block
|
; else try next block
|
||||||
inc r13
|
inc r13
|
||||||
jmp .alloc_loop
|
jmp .alloc_loop
|
||||||
|
|
@ -136,13 +184,17 @@ bump_alloc:
|
||||||
dec r13
|
dec r13
|
||||||
jmp .alloc_loop
|
jmp .alloc_loop
|
||||||
.found_space:
|
.found_space:
|
||||||
sub rdx, rax ; remaining size in block
|
mov r12, [rsp + 32] ; block entry ptr
|
||||||
mov r13, [rsp + 32] ; block entry ptr
|
mov rcx, [r12] ; block_ptr
|
||||||
mov [r13], rax
|
mov [r12], rdx ; update block_ptr
|
||||||
mov rax, [rsp + 24] ; block_size
|
|
||||||
sub rax, rdx
|
; new_end - old_ptr
|
||||||
mov [r13 + 8], rax
|
sub rdx, rcx
|
||||||
mov rax, [r13]
|
|
||||||
|
mov rcx, [r12 + 8] ; block_size
|
||||||
|
sub rcx, rdx
|
||||||
|
mov [r12 + 8], rcx
|
||||||
|
|
||||||
add rsp, 0x28
|
add rsp, 0x28
|
||||||
pop r13
|
pop r13
|
||||||
pop r12
|
pop r12
|
||||||
|
|
|
||||||
331
lang/src/ast.asm
331
lang/src/ast.asm
|
|
@ -48,6 +48,7 @@ global parse_expr
|
||||||
global parse_binary_expr
|
global parse_binary_expr
|
||||||
global parse_primary_expr
|
global parse_primary_expr
|
||||||
global parse_if_expr
|
global parse_if_expr
|
||||||
|
global parse_postfix_expr
|
||||||
global parse_statement
|
global parse_statement
|
||||||
global parse_block
|
global parse_block
|
||||||
global ast_build_symtable
|
global ast_build_symtable
|
||||||
|
|
@ -314,6 +315,191 @@ parse_number:
|
||||||
.panic:
|
.panic:
|
||||||
call panic
|
call panic
|
||||||
|
|
||||||
|
;; rdi: *mut Ast
|
||||||
|
;; define-fn: fn parse_as_expr(ast: *mut Ast) -> (u64, bool)
|
||||||
|
parse_as_expr:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
|
||||||
|
; start-structs
|
||||||
|
; struct AstAsExpr {
|
||||||
|
; expr: u64,
|
||||||
|
; ty: Type,
|
||||||
|
; }
|
||||||
|
; end-structs
|
||||||
|
|
||||||
|
; Type [32..48]
|
||||||
|
; prefix_expr [16..32]
|
||||||
|
; span [8..16]
|
||||||
|
; ast [0..8]
|
||||||
|
sub rsp, 48
|
||||||
|
mov [rsp], rdi ; Ast
|
||||||
|
call parse_prefix_expr
|
||||||
|
mov [rsp + 16], rax ; prefix_expr
|
||||||
|
mov [rsp + 24], rdx ; placeness
|
||||||
|
|
||||||
|
call tokeniser_get_cursor
|
||||||
|
mov [rsp + 8], rax ; span
|
||||||
|
|
||||||
|
mov dil, TOKEN_AS
|
||||||
|
call expect_token
|
||||||
|
test rax, rax
|
||||||
|
jz .done
|
||||||
|
|
||||||
|
; convert prefix_expr to value
|
||||||
|
.as_expr:
|
||||||
|
mov rdi, [rsp] ; Ast
|
||||||
|
mov rsi, [rsp + 16] ; prefix_expr
|
||||||
|
mov dl, [rsp + 24] ; placeness
|
||||||
|
call ast_place_to_value
|
||||||
|
mov [rsp + 24], rax ; AstAsExpr.expr
|
||||||
|
|
||||||
|
; parse type
|
||||||
|
mov rdi, [rsp] ; Ast
|
||||||
|
call parse_type
|
||||||
|
mov [rsp + 32], rax ; AstAsExpr.Type.kind
|
||||||
|
mov [rsp + 40], rdx ; AstAsExpr.Type.data
|
||||||
|
|
||||||
|
mov rdi, 16 ; size_of::<AstAsExpr>
|
||||||
|
mov rsi, 8 ; align_of::<AstAsExpr>
|
||||||
|
call bump_alloc
|
||||||
|
mov rdi, rax ; dst
|
||||||
|
lea rsi, [rsp + 24] ; &AstAsExpr
|
||||||
|
mov rdx, 16 ; size_of::<AstAsExpr>
|
||||||
|
call memcpy
|
||||||
|
|
||||||
|
mov qword [rsp + 16], AST_AS ; AstNode.kind
|
||||||
|
mov [rsp + 24], rdi ; AstNode.data
|
||||||
|
mov qword [rsp + 32], 0 ; AstNode.extra
|
||||||
|
mov rdi, [rsp + 8] ; span
|
||||||
|
mov [rsp + 40], rdi ; AstNode.span
|
||||||
|
|
||||||
|
mov rdi, [rsp] ; Ast
|
||||||
|
lea rsi, [rsp + 16] ; &AstNode
|
||||||
|
call vec_push
|
||||||
|
; rax = index of pushed node
|
||||||
|
mov rdx, 0 ; placeness = false
|
||||||
|
jmp .epilogue
|
||||||
|
|
||||||
|
.done:
|
||||||
|
mov rax, [rsp + 16] ; prefix_expr
|
||||||
|
mov rdx, [rsp + 24] ; placeness
|
||||||
|
.epilogue:
|
||||||
|
add rsp, 48
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
|
||||||
|
;; rdi: *mut Ast
|
||||||
|
;; define-fn: fn parse_postfix_expr(ast: *mut Ast) -> (u64, bool)
|
||||||
|
parse_postfix_expr:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
push rbx
|
||||||
|
|
||||||
|
; scratch [64..80]
|
||||||
|
; params: Vec [24..64]
|
||||||
|
; expr [16..24]
|
||||||
|
; span: u64 [8..16]
|
||||||
|
; ast [0..8]
|
||||||
|
sub rsp, 80
|
||||||
|
mov [rsp], rdi ; Ast
|
||||||
|
|
||||||
|
call parse_primary_expr
|
||||||
|
mov [rsp + 16], rax ; expr
|
||||||
|
mov [rsp + 24], rdx ; placeness
|
||||||
|
|
||||||
|
call tokeniser_get_cursor
|
||||||
|
mov [rsp + 8], rax ; span
|
||||||
|
|
||||||
|
mov dil, TOKEN_LPARENS
|
||||||
|
call expect_token
|
||||||
|
test rax, rax
|
||||||
|
jnz .call_expr
|
||||||
|
mov rax, [rsp + 16] ; expr
|
||||||
|
mov rdx, [rsp + 24] ; placeness
|
||||||
|
jmp .epilogue
|
||||||
|
|
||||||
|
.call_expr:
|
||||||
|
; start-structs
|
||||||
|
; struct AstCallExpr {
|
||||||
|
; callee: u64,
|
||||||
|
; params: *const u64,
|
||||||
|
; params_len: usize,
|
||||||
|
; }
|
||||||
|
; end-structs
|
||||||
|
|
||||||
|
; scratch [64..80]
|
||||||
|
; params: Vec [24..64]
|
||||||
|
|
||||||
|
mov rdi, [rsp] ; Ast
|
||||||
|
mov rsi, [rsp + 16] ; callee
|
||||||
|
mov rdx, [rsp + 24] ; placeness
|
||||||
|
call ast_place_to_value
|
||||||
|
mov [rsp + 16], rax ; callee
|
||||||
|
|
||||||
|
lea rdi, [rsp + 24] ; params
|
||||||
|
mov rsi, 8 ; size of u64
|
||||||
|
mov rdx, 0 ; drop = None
|
||||||
|
mov rcx, 16 ; capacity
|
||||||
|
call vec_init_with
|
||||||
|
|
||||||
|
.params_loop:
|
||||||
|
mov dil, TOKEN_RPARENS
|
||||||
|
call expect_token
|
||||||
|
test rax, rax
|
||||||
|
jnz .params_done
|
||||||
|
|
||||||
|
mov rdi, [rsp] ; Ast
|
||||||
|
call parse_expr
|
||||||
|
|
||||||
|
mov rdi, [rsp] ; Ast
|
||||||
|
mov rsi, rax ; expr
|
||||||
|
call ast_place_to_value
|
||||||
|
mov [rsp + 64], rax ; value
|
||||||
|
lea rdi, [rsp + 24] ; params
|
||||||
|
lea rsi, [rsp + 64] ; &value
|
||||||
|
call vec_push
|
||||||
|
|
||||||
|
mov dil, TOKEN_COMMA
|
||||||
|
call expect_token
|
||||||
|
test rax, rax
|
||||||
|
jz .close_parens
|
||||||
|
jmp .params_loop
|
||||||
|
|
||||||
|
.close_parens:
|
||||||
|
mov dil, TOKEN_RPARENS
|
||||||
|
call unwrap_token
|
||||||
|
.params_done:
|
||||||
|
|
||||||
|
mov rdi, 24 ; size_of::<AstCallExpr>
|
||||||
|
mov rsi, 8 ; align_of::<AstCallExpr>
|
||||||
|
call bump_alloc
|
||||||
|
|
||||||
|
mov rdi, rax ; dst
|
||||||
|
lea rsi, [rsp + 16] ; &callee
|
||||||
|
mov rdx, 24 ; size_of::<AstCallExpr>
|
||||||
|
call memcpy
|
||||||
|
|
||||||
|
mov [rsp + 16], rdi ; AstNode.data = *AstCallExpr
|
||||||
|
mov qword [rsp + 24], 0 ; AstNode.extra = 0
|
||||||
|
mov rax, [rsp + 8] ; span
|
||||||
|
mov [rsp + 32], rax ; AstNode.span
|
||||||
|
mov qword [rsp + 8], AST_CALL ; AstNode.kind
|
||||||
|
|
||||||
|
mov rdi, [rsp] ; Ast
|
||||||
|
lea rsi, [rsp + 8] ; &AstNode
|
||||||
|
call vec_push
|
||||||
|
mov rdi, [rsp] ; Ast
|
||||||
|
mov rax, [rdi + 8] ; return Ast.nodes.len()
|
||||||
|
dec rax
|
||||||
|
mov rdx, 0 ; placeness = false
|
||||||
|
|
||||||
|
.epilogue:
|
||||||
|
add rsp, 80
|
||||||
|
pop rbx
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
|
||||||
;; rdi: *mut Ast
|
;; rdi: *mut Ast
|
||||||
;; define-fn: fn parse_primary_expr(ast: *mut Ast) -> (u64, bool)
|
;; define-fn: fn parse_primary_expr(ast: *mut Ast) -> (u64, bool)
|
||||||
parse_primary_expr:
|
parse_primary_expr:
|
||||||
|
|
@ -439,7 +625,7 @@ parse_binary_expr:
|
||||||
call tokeniser_get_cursor
|
call tokeniser_get_cursor
|
||||||
mov [rsp + 56], rax ; span
|
mov [rsp + 56], rax ; span
|
||||||
|
|
||||||
call parse_prefix_expr
|
call parse_as_expr
|
||||||
mov [rsp + 8], rax ; left
|
mov [rsp + 8], rax ; left
|
||||||
mov [rsp + 19], dl ; left_placeness
|
mov [rsp + 19], dl ; left_placeness
|
||||||
|
|
||||||
|
|
@ -463,11 +649,11 @@ parse_binary_expr:
|
||||||
cmove bx, word [rel PRECEDENCE_EQ]
|
cmove bx, word [rel PRECEDENCE_EQ]
|
||||||
cmp al, TOKEN_LT
|
cmp al, TOKEN_LT
|
||||||
cmove bx, word [rel PRECEDENCE_CMP]
|
cmove bx, word [rel PRECEDENCE_CMP]
|
||||||
cmp al, TOKEN_LTEQ
|
cmp al, TOKEN_LEQ
|
||||||
cmove bx, word [rel PRECEDENCE_CMP]
|
cmove bx, word [rel PRECEDENCE_CMP]
|
||||||
cmp al, TOKEN_GT
|
cmp al, TOKEN_GT
|
||||||
cmove bx, word [rel PRECEDENCE_CMP]
|
cmove bx, word [rel PRECEDENCE_CMP]
|
||||||
cmp al, TOKEN_GTEQ
|
cmp al, TOKEN_GEQ
|
||||||
cmove bx, word [rel PRECEDENCE_CMP]
|
cmove bx, word [rel PRECEDENCE_CMP]
|
||||||
cmp bx, -1
|
cmp bx, -1
|
||||||
je .done
|
je .done
|
||||||
|
|
@ -722,13 +908,63 @@ parse_type:
|
||||||
je .bool_type
|
je .bool_type
|
||||||
cmp al, TOKEN_STAR
|
cmp al, TOKEN_STAR
|
||||||
je .pointer_type
|
je .pointer_type
|
||||||
|
cmp al, TOKEN_U8
|
||||||
|
je .u8_type
|
||||||
|
cmp al, TOKEN_I8
|
||||||
|
je .i8_type
|
||||||
|
cmp al, TOKEN_U16
|
||||||
|
je .u16_type
|
||||||
|
cmp al, TOKEN_I16
|
||||||
|
je .i16_type
|
||||||
|
cmp al, TOKEN_U64
|
||||||
|
je .u64_type
|
||||||
|
cmp al, TOKEN_I64
|
||||||
|
je .i64_type
|
||||||
|
cmp al, TOKEN_F32
|
||||||
|
je .f32_type
|
||||||
|
cmp al, TOKEN_F64
|
||||||
|
je .f64_type
|
||||||
|
cmp al, TOKEN_USIZE
|
||||||
|
je .usize_type
|
||||||
|
cmp al, TOKEN_ISIZE
|
||||||
|
je .isize_type
|
||||||
jmp .panic
|
jmp .panic
|
||||||
.i32_type:
|
.u8_type:
|
||||||
mov rax, TYPE_I32
|
mov rax, TYPE_U8
|
||||||
|
jmp .epilogue
|
||||||
|
.i8_type:
|
||||||
|
mov rax, TYPE_I8
|
||||||
|
jmp .epilogue
|
||||||
|
.u16_type:
|
||||||
|
mov rax, TYPE_U16
|
||||||
|
jmp .epilogue
|
||||||
|
.i16_type:
|
||||||
|
mov rax, TYPE_I16
|
||||||
jmp .epilogue
|
jmp .epilogue
|
||||||
.u32_type:
|
.u32_type:
|
||||||
mov rax, TYPE_U32
|
mov rax, TYPE_U32
|
||||||
jmp .epilogue
|
jmp .epilogue
|
||||||
|
.i32_type:
|
||||||
|
mov rax, TYPE_I32
|
||||||
|
jmp .epilogue
|
||||||
|
.u64_type:
|
||||||
|
mov rax, TYPE_U64
|
||||||
|
jmp .epilogue
|
||||||
|
.i64_type:
|
||||||
|
mov rax, TYPE_I64
|
||||||
|
jmp .epilogue
|
||||||
|
.usize_type:
|
||||||
|
mov rax, TYPE_USIZE
|
||||||
|
jmp .epilogue
|
||||||
|
.isize_type:
|
||||||
|
mov rax, TYPE_ISIZE
|
||||||
|
jmp .epilogue
|
||||||
|
.f32_type:
|
||||||
|
mov rax, TYPE_F32
|
||||||
|
jmp .epilogue
|
||||||
|
.f64_type:
|
||||||
|
mov rax, TYPE_F64
|
||||||
|
jmp .epilogue
|
||||||
.void_type:
|
.void_type:
|
||||||
mov rax, TYPE_VOID
|
mov rax, TYPE_VOID
|
||||||
jmp .epilogue
|
jmp .epilogue
|
||||||
|
|
@ -782,7 +1018,7 @@ parse_prefix_expr:
|
||||||
jnz .address_of
|
jnz .address_of
|
||||||
|
|
||||||
mov rdi, [rsp] ; Ast
|
mov rdi, [rsp] ; Ast
|
||||||
call parse_primary_expr
|
call parse_postfix_expr
|
||||||
jmp .done
|
jmp .done
|
||||||
.dereference:
|
.dereference:
|
||||||
mov rdi, [rsp] ; Ast
|
mov rdi, [rsp] ; Ast
|
||||||
|
|
@ -1193,11 +1429,11 @@ symkey_cmp:
|
||||||
mov [rsp], rsi
|
mov [rsp], rsi
|
||||||
mov [rsp + 8], rdx
|
mov [rsp + 8], rdx
|
||||||
|
|
||||||
mov al, byte [rsi] ; a.kind
|
; mov al, byte [rsi] ; a.kind
|
||||||
mov bl, byte [rdx] ; b.kind
|
; mov bl, byte [rdx] ; b.kind
|
||||||
cmp al, bl
|
; cmp al, bl
|
||||||
jl .a_less
|
; jl .a_less
|
||||||
jg .a_greater
|
; jg .a_greater
|
||||||
|
|
||||||
mov rax, [rsi + 8] ; a.scope_index
|
mov rax, [rsi + 8] ; a.scope_index
|
||||||
mov rbx, [rdx + 8] ; b.scope_index
|
mov rbx, [rdx + 8] ; b.scope_index
|
||||||
|
|
@ -1216,6 +1452,12 @@ symkey_cmp:
|
||||||
|
|
||||||
mov rsi, [rsp]
|
mov rsi, [rsp]
|
||||||
mov rdx, [rsp + 8]
|
mov rdx, [rsp + 8]
|
||||||
|
mov al, byte [rsi] ; a.kind
|
||||||
|
mov bl, byte [rdx] ; b.kind
|
||||||
|
cmp al, bl
|
||||||
|
jl .a_less
|
||||||
|
jg .a_greater
|
||||||
|
|
||||||
mov rax, [rsi + 16] ; a.span
|
mov rax, [rsi + 16] ; a.span
|
||||||
mov rbx, [rdx + 16] ; b.span
|
mov rbx, [rdx + 16] ; b.span
|
||||||
cmp rax, rbx
|
cmp rax, rbx
|
||||||
|
|
@ -1241,9 +1483,10 @@ section .rdata
|
||||||
SYM_KEY_SCOPE_NAME equ 2 ; :u8
|
SYM_KEY_SCOPE_NAME equ 2 ; :u8
|
||||||
SYM_KEY_PARENT_SCOPE equ 3 ; :u8
|
SYM_KEY_PARENT_SCOPE equ 3 ; :u8
|
||||||
SYM_KEY_START_LOCALS equ 4 ; :u8
|
SYM_KEY_START_LOCALS equ 4 ; :u8
|
||||||
SYM_KEY_ARG equ 5 ; :u8
|
SYM_KEY_FUNCTION equ 5 ; :u8
|
||||||
SYM_KEY_VAR equ 6 ; :u8
|
SYM_KEY_ARG equ 6 ; :u8
|
||||||
SYM_KEY_END_LOCALS equ 7 ; :u8
|
SYM_KEY_VAR equ 7 ; :u8
|
||||||
|
SYM_KEY_END_LOCALS equ 8 ; :u8
|
||||||
;; end-consts
|
;; end-consts
|
||||||
|
|
||||||
section .text
|
section .text
|
||||||
|
|
@ -1395,9 +1638,29 @@ ast_build_symtable_for_each:
|
||||||
jmp .insert_scope
|
jmp .insert_scope
|
||||||
|
|
||||||
.func:
|
.func:
|
||||||
; use function name as scope name
|
|
||||||
|
|
||||||
mov rbx, [rax + 8] ; AstNode.data
|
mov rbx, [rax + 8] ; AstNode.data
|
||||||
|
|
||||||
|
; insert function symbol
|
||||||
|
mov byte [rsp + 32], SYM_KEY_FUNCTION ; SymKey.kind
|
||||||
|
mov rdx, [rsp + 88] ; index
|
||||||
|
mov qword [rsp + 40], rdx ; SymKey.scope_index
|
||||||
|
mov rdx, [rax + 24] ; AstNode.span
|
||||||
|
mov qword [rsp + 48], rdx ; SymKey.span
|
||||||
|
mov rdx, [rbx + 0] ; Func.name
|
||||||
|
mov rcx, [rbx + 8] ; Func.name_len
|
||||||
|
mov [rsp + 56], rdx ; SymKey.ident
|
||||||
|
mov [rsp + 64], rcx ; SymKey.ident_len
|
||||||
|
mov rdx, [rsp + 16] ; index
|
||||||
|
mov [rsp + 72], rdx ; SymEntry.index
|
||||||
|
mov qword [rsp + 80], 0 ; SymEntry.extra
|
||||||
|
|
||||||
|
mov rdi, [rsp + 8] ; Ctx.symtable
|
||||||
|
lea rsi, [rsp + 32] ; &SymEntry
|
||||||
|
mov rcx, 0 ; cmp_ctx
|
||||||
|
mov rdx, symkey_cmp ; cmp
|
||||||
|
call vec_insert_sorted
|
||||||
|
|
||||||
|
; use function name as scope name
|
||||||
mov rdx, [rbx + 0] ; Func.name
|
mov rdx, [rbx + 0] ; Func.name
|
||||||
mov rcx, [rbx + 8] ; Func.name_len
|
mov rcx, [rbx + 8] ; Func.name_len
|
||||||
|
|
||||||
|
|
@ -1409,6 +1672,7 @@ ast_build_symtable_for_each:
|
||||||
mov byte [rsp + 32], SYM_KEY_SCOPE ; SymKey.kind
|
mov byte [rsp + 32], SYM_KEY_SCOPE ; SymKey.kind
|
||||||
mov rdx, [rsp + 16] ; index
|
mov rdx, [rsp + 16] ; index
|
||||||
mov qword [rsp + 40], rdx ; SymKey.scope_index
|
mov qword [rsp + 40], rdx ; SymKey.scope_index
|
||||||
|
mov rax, [rsp + 24] ; *AstNode
|
||||||
mov rdx, [rax + 24] ; AstNode.span
|
mov rdx, [rax + 24] ; AstNode.span
|
||||||
mov qword [rsp + 48], rdx ; SymKey.span
|
mov qword [rsp + 48], rdx ; SymKey.span
|
||||||
mov qword [rsp + 56], 1 ; SymKey.ident
|
mov qword [rsp + 56], 1 ; SymKey.ident
|
||||||
|
|
@ -1587,6 +1851,35 @@ ast_walk_for_each:
|
||||||
je .return_statement
|
je .return_statement
|
||||||
cmp bl, AST_IF
|
cmp bl, AST_IF
|
||||||
je .if_expr
|
je .if_expr
|
||||||
|
cmp bl, AST_CALL
|
||||||
|
je .call
|
||||||
|
cmp bl, AST_AS
|
||||||
|
je .as_expr
|
||||||
|
jmp .check_scope
|
||||||
|
|
||||||
|
.as_expr:
|
||||||
|
mov rbx, [rax + 8] ; AstNode.data = *AstAsExpr
|
||||||
|
mov rax, [rbx + 0] ; AstCallExpr.expr
|
||||||
|
push rax ; push expr index
|
||||||
|
jmp .check_scope
|
||||||
|
|
||||||
|
.call:
|
||||||
|
mov rbx, [rax + 8] ; AstNode.data = *AstCallExpr
|
||||||
|
mov rax, [rbx + 0] ; AstCallExpr.callee
|
||||||
|
push rax ; push callee index
|
||||||
|
|
||||||
|
mov r15, [rbx + 16] ; AstCallExpr.args_len
|
||||||
|
xor r14, r14 ; index
|
||||||
|
.call_params:
|
||||||
|
cmp r14, r15
|
||||||
|
jge .call_params_done
|
||||||
|
mov rdx, [rbx + 8] ; AstCallExpr.args
|
||||||
|
lea rdx, [rdx + r14*8]
|
||||||
|
mov rax, [rdx] ; arg index
|
||||||
|
push rax ; push arg index
|
||||||
|
inc r14
|
||||||
|
jmp .call_params
|
||||||
|
.call_params_done:
|
||||||
jmp .check_scope
|
jmp .check_scope
|
||||||
|
|
||||||
.func:
|
.func:
|
||||||
|
|
@ -1786,6 +2079,11 @@ ast_resolve_var_refs_for_each:
|
||||||
call vec_get
|
call vec_get
|
||||||
mov rbx, rax ; *SymEntry
|
mov rbx, rax ; *SymEntry
|
||||||
|
|
||||||
|
; check symbol entry kind
|
||||||
|
mov al, byte [rbx + 0] ; SymEntry.key.kind
|
||||||
|
cmp al, SYM_KEY_START_LOCALS
|
||||||
|
jb .parent
|
||||||
|
|
||||||
; compare symbol ident with var_ref ident
|
; compare symbol ident with var_ref ident
|
||||||
mov rdi, [rbx + 24] ; SymEntry.key.ident
|
mov rdi, [rbx + 24] ; SymEntry.key.ident
|
||||||
mov rsi, [rbx + 32] ; SymEntry.key.ident_len
|
mov rsi, [rbx + 32] ; SymEntry.key.ident_len
|
||||||
|
|
@ -1841,6 +2139,7 @@ ast_resolve_var_refs_for_each:
|
||||||
ret
|
ret
|
||||||
.panic:
|
.panic:
|
||||||
call panic
|
call panic
|
||||||
|
;; } ast_resolve_var_refs_for_each
|
||||||
|
|
||||||
;; rdi: Ast
|
;; rdi: Ast
|
||||||
;; rsi: *mut SymbolTable
|
;; rsi: *mut SymbolTable
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,22 @@ section .rdata
|
||||||
AST_IF equ 16 ; :u8
|
AST_IF equ 16 ; :u8
|
||||||
AST_ELSE equ 17 ; :u8
|
AST_ELSE equ 17 ; :u8
|
||||||
AST_CALL equ 18 ; :u8
|
AST_CALL equ 18 ; :u8
|
||||||
|
AST_AS equ 19 ; :u8
|
||||||
|
|
||||||
TYPE_VOID equ 1 ; :u8
|
TYPE_VOID equ 1 ; :u8
|
||||||
TYPE_BOOL equ 2 ; :u8
|
TYPE_BOOL equ 2 ; :u8
|
||||||
TYPE_I32 equ 3 ; :u8
|
TYPE_U8 equ 3 ; :u8
|
||||||
TYPE_U32 equ 4 ; :u8
|
TYPE_U16 equ 4 ; :u8
|
||||||
TYPE_STR equ 5 ; :u8
|
TYPE_U32 equ 5 ; :u8
|
||||||
TYPE_POINTER equ 6 ; :u8
|
TYPE_U64 equ 6 ; :u8
|
||||||
|
TYPE_USIZE equ 7 ; :u8
|
||||||
|
TYPE_I8 equ 8 ; :u8
|
||||||
|
TYPE_I16 equ 9 ; :u8
|
||||||
|
TYPE_I32 equ 10 ; :u8
|
||||||
|
TYPE_I64 equ 11 ; :u8
|
||||||
|
TYPE_ISIZE equ 12 ; :u8
|
||||||
|
TYPE_STR equ 13 ; :u8
|
||||||
|
TYPE_POINTER equ 14 ; :u8
|
||||||
|
TYPE_F32 equ 15 ; :u8
|
||||||
|
TYPE_F64 equ 16 ; :u8
|
||||||
;; end-consts
|
;; end-consts
|
||||||
|
|
|
||||||
|
|
@ -376,7 +376,7 @@ codegen_allocate_stack_value:
|
||||||
mov rsi, 0xF
|
mov rsi, 0xF
|
||||||
not rsi
|
not rsi
|
||||||
and rax, rsi ; clear kind to make it a value
|
and rax, rsi ; clear kind to make it a value
|
||||||
and rax, OPERAND_RBP_VALUE ; Operand.kind = OPERAND_RBP_VALUE
|
or rax, OPERAND_RBP_VALUE ; Operand.kind = OPERAND_RBP_VALUE
|
||||||
|
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
@ -971,6 +971,243 @@ codegen_block:
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
;; rdi: ctx
|
||||||
|
;; rsi: &function_ctx
|
||||||
|
;; rdx: *AstCallExpr
|
||||||
|
;; define-fn: fn codegen_call_expr(ctx: *const CodegenCtx, function_ctx: &FunctionCtx, call_expr: *const AstCallExpr) -> (u64, bool)
|
||||||
|
codegen_call_expr:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
push rbx
|
||||||
|
push r15
|
||||||
|
push r14
|
||||||
|
|
||||||
|
; scratch [80..112]
|
||||||
|
; callee_operand [64..80]
|
||||||
|
; param_operands [24..64]
|
||||||
|
; *AstCallExpr [16..24]
|
||||||
|
; function_ctx [8..16]
|
||||||
|
; ctx [0..8]
|
||||||
|
sub rsp, 112
|
||||||
|
mov [rsp], rdi ; ctx
|
||||||
|
mov [rsp + 8], rsi ; &function_ctx
|
||||||
|
mov [rsp + 16], rdx ; *AstCallExpr
|
||||||
|
mov rbx, rdx ; copy of *AstCallExpr
|
||||||
|
|
||||||
|
; initialize param_operands
|
||||||
|
lea rdi, [rsp + 24] ; param_operands
|
||||||
|
mov rsi, 16 ; size_of::<Operand>
|
||||||
|
mov rdx, 0 ; drop = None
|
||||||
|
mov rcx, 16 ; initial capacity
|
||||||
|
call vec_init_with
|
||||||
|
|
||||||
|
; codegen callee
|
||||||
|
mov rdx, [rbx + 0] ; AstCallExpr.callee
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
mov rsi, [rsp + 8] ; &function_ctx
|
||||||
|
call codegen_expr
|
||||||
|
mov [rsp + 64], rax ; callee operand
|
||||||
|
mov [rsp + 72], rdx
|
||||||
|
|
||||||
|
; If callee is in a param-register, move to stack
|
||||||
|
cmp al, OPERAND_REGISTER
|
||||||
|
jne .arg_loop_init
|
||||||
|
mov rdx, 0b00000011_00111100
|
||||||
|
movzx rcx, byte [rsp + 64 + 1] ; callee register
|
||||||
|
bt rdx, rcx
|
||||||
|
jnc .arg_loop_init
|
||||||
|
|
||||||
|
; allocate stack slot
|
||||||
|
mov rdi, [rsp + 8] ; &function_ctx
|
||||||
|
movzx rsi, word [rsp + 64 + 2] ; Operand.width
|
||||||
|
call codegen_allocate_stack_value
|
||||||
|
mov [rsp + 80], rax ; new stack operand
|
||||||
|
mov [rsp + 88], rdx
|
||||||
|
|
||||||
|
; move from register to stack
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rsp + 80] ; dst
|
||||||
|
lea rdx, [rsp + 64] ; src
|
||||||
|
call codegen_move_dst_src
|
||||||
|
; free original callee operand
|
||||||
|
mov rdi, [rsp + 8] ; &function_ctx
|
||||||
|
lea rsi, [rsp + 64] ; callee operand
|
||||||
|
call codegen_free_operand
|
||||||
|
|
||||||
|
mov rax, [rsp + 80] ; callee operand = new stack operand
|
||||||
|
mov rdx, [rsp + 88]
|
||||||
|
mov [rsp + 64], rax
|
||||||
|
mov [rsp + 72], rdx
|
||||||
|
|
||||||
|
.arg_loop_init:
|
||||||
|
mov r15, [rbx + 16] ; AstCallExpr.args_len
|
||||||
|
xor r14, r14 ; arg index
|
||||||
|
.arg_loop:
|
||||||
|
cmp r14, r15
|
||||||
|
jge .arg_loop_done
|
||||||
|
mov rdx, [rbx + 8] ; AstCallExpr.args
|
||||||
|
lea rsi, [rdx + r14 * 8]
|
||||||
|
mov rdx, [rsi] ; arg ast index
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
mov rsi, [rsp + 8] ; &function_ctx
|
||||||
|
call codegen_expr
|
||||||
|
mov [rsp + 80], rax ; param operand
|
||||||
|
mov [rsp + 88], rdx
|
||||||
|
|
||||||
|
; store param operand
|
||||||
|
; if the operand is in a register, move it to the stack
|
||||||
|
; we know already that these are values
|
||||||
|
|
||||||
|
cmp byte [rsp + 80], OPERAND_REGISTER
|
||||||
|
jne .store_param
|
||||||
|
; allocate stack slot
|
||||||
|
mov rdi, [rsp + 8] ; &function_ctx
|
||||||
|
movzx rsi, word [rsp + 80 + 2] ; Operand.width
|
||||||
|
call codegen_allocate_stack_value
|
||||||
|
mov [rsp + 96], rax ; new stack operand
|
||||||
|
mov [rsp + 104], rdx
|
||||||
|
|
||||||
|
; move from register to stack
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rsp + 96] ; dst
|
||||||
|
lea rdx, [rsp + 80] ; src
|
||||||
|
call codegen_move_dst_src
|
||||||
|
|
||||||
|
; free original param operand
|
||||||
|
mov rdi, [rsp + 8] ; &function_ctx
|
||||||
|
lea rsi, [rsp + 80] ; param operand
|
||||||
|
call codegen_free_operand
|
||||||
|
mov rax, [rsp + 96] ; param operand = new stack operand
|
||||||
|
mov rdx, [rsp + 104]
|
||||||
|
mov [rsp + 80], rax
|
||||||
|
mov [rsp + 88], rdx
|
||||||
|
|
||||||
|
.store_param:
|
||||||
|
; push param operand to param_operands
|
||||||
|
lea rdi, [rsp + 24] ; param_operands
|
||||||
|
lea rsi, [rsp + 80] ; ¶m operand
|
||||||
|
call vec_push
|
||||||
|
|
||||||
|
inc r14
|
||||||
|
jmp .arg_loop
|
||||||
|
.arg_loop_done:
|
||||||
|
|
||||||
|
; push volatile registers
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rsp + 8] ; &function_ctx
|
||||||
|
mov rdx, 0 ; pop = false
|
||||||
|
call codegen_push_pop_used_registers
|
||||||
|
|
||||||
|
; move params to appropriate registers/stack slots
|
||||||
|
; reverse order to allow freeing the allocated stack slots
|
||||||
|
mov r15, [rbx + 16] ; AstCallExpr.args_len
|
||||||
|
cmp r15, 6
|
||||||
|
jg .panic ; more than 6 params not supported yet
|
||||||
|
.param_move_loop:
|
||||||
|
dec r15
|
||||||
|
cmp r15, 0
|
||||||
|
jl .param_move_done
|
||||||
|
|
||||||
|
mov rdi, r15 ; param index
|
||||||
|
call codegen_arg_to_operand
|
||||||
|
mov [rsp + 80], rax ; target operand
|
||||||
|
mov [rsp + 88], rdx
|
||||||
|
|
||||||
|
lea rdi, [rsp + 24] ; param_operands
|
||||||
|
mov rsi, r15
|
||||||
|
call vec_get
|
||||||
|
mov r14, rax ; source operand
|
||||||
|
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rsp + 80] ; dst
|
||||||
|
mov rdx, r14 ; src
|
||||||
|
call codegen_move_dst_src
|
||||||
|
; free param operand
|
||||||
|
mov rdi, [rsp + 8] ; &function_ctx
|
||||||
|
mov rdx, r14 ; param operand
|
||||||
|
call codegen_free_operand
|
||||||
|
|
||||||
|
jmp .param_move_loop
|
||||||
|
.param_move_done:
|
||||||
|
|
||||||
|
; align stack
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rel ALIGN_STACK]
|
||||||
|
mov rdx, ALIGN_STACK_LEN
|
||||||
|
call vec_extend
|
||||||
|
; mov rax, rsp
|
||||||
|
; sub rsp, 8
|
||||||
|
; and rsp, -16
|
||||||
|
; mov [rsp], rax
|
||||||
|
|
||||||
|
; call callee
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rel CALL_]
|
||||||
|
mov rdx, CALL_LEN
|
||||||
|
call vec_extend
|
||||||
|
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rsp + 64] ; callee operand
|
||||||
|
call codegen_write_operand
|
||||||
|
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rel NEWLINE]
|
||||||
|
call vec_push
|
||||||
|
|
||||||
|
; de-align stack
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rel RESTORE_STACK]
|
||||||
|
mov rdx, RESTORE_STACK_LEN
|
||||||
|
call vec_extend
|
||||||
|
|
||||||
|
; free callee operand
|
||||||
|
mov rdi, [rsp + 8] ; &function_ctx
|
||||||
|
lea rsi, [rsp + 64] ; callee operand
|
||||||
|
call codegen_free_operand
|
||||||
|
|
||||||
|
; pop volatile registers
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rsp + 8] ; &function_ctx
|
||||||
|
mov rdx, 1 ; pop = true
|
||||||
|
call codegen_push_pop_used_registers
|
||||||
|
|
||||||
|
; allocate return value operand
|
||||||
|
mov rdi, [rsp + 8] ; &function_ctx
|
||||||
|
mov rsi, 8 ; size_of::<u64>
|
||||||
|
call codegen_allocate_value
|
||||||
|
mov [rsp + 80], rax ; return value operand
|
||||||
|
mov [rsp + 88], rdx
|
||||||
|
|
||||||
|
; mov dst, rax
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rsp + 80] ; dst
|
||||||
|
lea rdx, [rel OPERAND_RAX] ; src
|
||||||
|
call codegen_move_dst_src
|
||||||
|
|
||||||
|
; return return value operand
|
||||||
|
mov rax, [rsp + 80]
|
||||||
|
mov rdx, [rsp + 88]
|
||||||
|
|
||||||
|
add rsp, 112
|
||||||
|
pop r14
|
||||||
|
pop r15
|
||||||
|
pop rbx
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
.panic:
|
||||||
|
call panic
|
||||||
|
|
||||||
;; rdi: ctx
|
;; rdi: ctx
|
||||||
;; rsi: &function_ctx
|
;; rsi: &function_ctx
|
||||||
;; rdx: expr index
|
;; rdx: expr index
|
||||||
|
|
@ -1022,8 +1259,17 @@ codegen_expr:
|
||||||
je .address_of
|
je .address_of
|
||||||
cmp bl, AST_IF
|
cmp bl, AST_IF
|
||||||
je .if_expr
|
je .if_expr
|
||||||
|
cmp bl, AST_CALL
|
||||||
|
je .call_expr
|
||||||
jmp .panic
|
jmp .panic
|
||||||
|
|
||||||
|
.call_expr:
|
||||||
|
mov rdx, [rax + 8] ; AstNode.data = *AstCallExpr
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
mov rsi, [rsp + 8] ; &function_ctx
|
||||||
|
call codegen_call_expr
|
||||||
|
jmp .done
|
||||||
|
|
||||||
.if_expr:
|
.if_expr:
|
||||||
mov rbx, [rax + 8] ; AstNode.data = *AstIfExpr
|
mov rbx, [rax + 8] ; AstNode.data = *AstIfExpr
|
||||||
mov [rsp + 16], rax ; scratch = AstNode
|
mov [rsp + 16], rax ; scratch = AstNode
|
||||||
|
|
@ -1614,9 +1860,29 @@ codegen_expr:
|
||||||
jmp .done
|
jmp .done
|
||||||
|
|
||||||
.var_ref:
|
.var_ref:
|
||||||
mov rax, [rax + 8] ; AstNode.data
|
mov rbx, [rax + 8] ; AstNode.data
|
||||||
mov rax, [rax] ; variable index
|
mov rax, [rbx] ; variable index
|
||||||
|
|
||||||
|
; check if we're trying to get a reference to a function
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
mov rdi, [rdi] ; ast
|
||||||
|
mov rsi, rax ; variable index
|
||||||
|
call vec_get
|
||||||
|
cmp byte [rax], AST_FUNCTION
|
||||||
|
jne .var_ref_var
|
||||||
|
|
||||||
|
mov rax, [rax + 8] ; *AstFunction
|
||||||
|
; create label operand for function
|
||||||
|
mov rcx, [rel OPERAND_LABEL0]
|
||||||
|
movzx rdx, word [rax + 8] ; AstFunction.name_len
|
||||||
|
shl rdx, 32
|
||||||
|
or rcx, rdx
|
||||||
|
mov rdx, [rax + 0] ; AstFunction.name
|
||||||
|
mov rax, rcx
|
||||||
|
jmp .done
|
||||||
|
|
||||||
|
.var_ref_var:
|
||||||
|
mov rax, [rbx]
|
||||||
mov [rsp + 16], rax
|
mov [rsp + 16], rax
|
||||||
mov qword [rsp + 24], 0
|
mov qword [rsp + 24], 0
|
||||||
; lookup variable in stack_vars
|
; lookup variable in stack_vars
|
||||||
|
|
@ -1656,6 +1922,9 @@ codegen_expr:
|
||||||
je .ptv_register_place
|
je .ptv_register_place
|
||||||
cmp al, OPERAND_RBP_PLACE
|
cmp al, OPERAND_RBP_PLACE
|
||||||
je .ptv_rbp_place
|
je .ptv_rbp_place
|
||||||
|
cmp al, OPERAND_LABEL
|
||||||
|
je .done
|
||||||
|
jmp .panic
|
||||||
|
|
||||||
.ptv_rbp_offset:
|
.ptv_rbp_offset:
|
||||||
mov byte [rsp + 16], OPERAND_RBP_PVALUE
|
mov byte [rsp + 16], OPERAND_RBP_PVALUE
|
||||||
|
|
@ -1830,10 +2099,12 @@ codegen_expr:
|
||||||
;; register: u8,
|
;; register: u8,
|
||||||
;; width: u16,
|
;; width: u16,
|
||||||
;; len: u16,
|
;; len: u16,
|
||||||
|
;; align: u8,
|
||||||
|
;; bitset: u8,
|
||||||
;; value: u64,
|
;; value: u64,
|
||||||
;; }
|
;; }
|
||||||
;; end-structs
|
;; end-structs
|
||||||
;; or: register: u4, width: u4
|
;; bitset[0]: signed
|
||||||
section .rdata
|
section .rdata
|
||||||
;; start-consts
|
;; start-consts
|
||||||
; Register containing a Value
|
; Register containing a Value
|
||||||
|
|
@ -1887,6 +2158,8 @@ section .rdata
|
||||||
OPERAND_RBP_P dq 0x0008_0009, 0
|
OPERAND_RBP_P dq 0x0008_0009, 0
|
||||||
align 8
|
align 8
|
||||||
OPERAND_ZERO dq 0x0001_000b, 0
|
OPERAND_ZERO dq 0x0001_000b, 0
|
||||||
|
align 8
|
||||||
|
OPERAND_LABEL0 dq 0x0008_000d, 0
|
||||||
|
|
||||||
section .text
|
section .text
|
||||||
|
|
||||||
|
|
@ -2031,8 +2304,7 @@ codegen_write_operand:
|
||||||
mov rax, [rsp + 8] ; op
|
mov rax, [rsp + 8] ; op
|
||||||
mov rdi, [rsp] ; *text
|
mov rdi, [rsp] ; *text
|
||||||
mov rsi, [rax + 8] ; Operand.value
|
mov rsi, [rax + 8] ; Operand.value
|
||||||
mov rdx, [rax + 4] ; Operand.len
|
movzx rdx, word [rax + 4] ; Operand.len
|
||||||
mov dx, dx ; low 16 bits
|
|
||||||
call vec_extend
|
call vec_extend
|
||||||
|
|
||||||
mov byte [rsp + 16], ']'
|
mov byte [rsp + 16], ']'
|
||||||
|
|
@ -2060,13 +2332,18 @@ codegen_write_operand:
|
||||||
mov rax, [rsp + 8] ; op
|
mov rax, [rsp + 8] ; op
|
||||||
mov rdi, [rsp] ; *text
|
mov rdi, [rsp] ; *text
|
||||||
mov rsi, [rax + 8] ; op.value
|
mov rsi, [rax + 8] ; op.value
|
||||||
mov rdx, [rax + 2] ; op.len
|
movzx rdx, word [rax + 4] ; Operand.len
|
||||||
mov dx, dx ; low 16 bits
|
|
||||||
call vec_extend
|
call vec_extend
|
||||||
jmp .epilogue
|
jmp .epilogue
|
||||||
|
|
||||||
.label:
|
.label:
|
||||||
jmp .panic
|
; write address name
|
||||||
|
mov rax, [rsp + 8] ; op
|
||||||
|
mov rdi, [rsp] ; *text
|
||||||
|
mov rsi, [rax + 8] ; Operand.value
|
||||||
|
movzx rdx, word [rax + 4] ; Operand.len
|
||||||
|
call vec_extend
|
||||||
|
jmp .epilogue
|
||||||
|
|
||||||
.epilogue:
|
.epilogue:
|
||||||
add rsp, 40
|
add rsp, 40
|
||||||
|
|
@ -2436,7 +2713,10 @@ codegen_move_dst_src:
|
||||||
mov cx, word [rsi + 2] ; dst.width
|
mov cx, word [rsi + 2] ; dst.width
|
||||||
mov bx, word [rdx + 2] ; src.width
|
mov bx, word [rdx + 2] ; src.width
|
||||||
cmp cx, bx
|
cmp cx, bx
|
||||||
jne .panic ; mismatched widths
|
jb .panic ; dst.width < src.width
|
||||||
|
je .width_ok
|
||||||
|
mov qword [rsp + 24], 'movzx '
|
||||||
|
.width_ok:
|
||||||
|
|
||||||
; ; if dst.width == 8 && src.kind == OPERAND_ADDRESS
|
; ; if dst.width == 8 && src.kind == OPERAND_ADDRESS
|
||||||
; xor rbx, rbx
|
; xor rbx, rbx
|
||||||
|
|
@ -2545,4 +2825,14 @@ section .rdata
|
||||||
JE_B_len equ $ - JE_B
|
JE_B_len equ $ - JE_B
|
||||||
JMP_PHI dq "jmp .PHI"
|
JMP_PHI dq "jmp .PHI"
|
||||||
JMP_PHI_len equ $ - JMP_PHI
|
JMP_PHI_len equ $ - JMP_PHI
|
||||||
|
ALIGN_STACK db "mov rax, rsp", 10, "sub rsp, 8", 10, "and rsp, -16", 10, "mov [rsp], rax", 10
|
||||||
|
ALIGN_STACK_LEN equ $ - ALIGN_STACK
|
||||||
|
RESTORE_STACK db "pop rsp", 10
|
||||||
|
RESTORE_STACK_LEN equ $ - RESTORE_STACK
|
||||||
|
CALL_ dq "call "
|
||||||
|
CALL_LEN equ $ - CALL_
|
||||||
|
NEWLINE db 10
|
||||||
|
align 8
|
||||||
|
MOVZX_ dq "movzx "
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ section .text
|
||||||
|
|
||||||
;; rdi: pointer to buffer
|
;; rdi: pointer to buffer
|
||||||
;; rsi: length of buffer
|
;; rsi: length of buffer
|
||||||
|
;; define-fn: fn tokeniser_init_buf(buf: *const u8, buf_len: usize)
|
||||||
tokeniser_init_buf:
|
tokeniser_init_buf:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ extern memswap
|
||||||
extern oom
|
extern oom
|
||||||
extern panic
|
extern panic
|
||||||
extern eprint_str
|
extern eprint_str
|
||||||
extern allocate
|
extern bump_alloc
|
||||||
|
|
||||||
global vec_init
|
global vec_init
|
||||||
global vec_init_with
|
global vec_init_with
|
||||||
|
|
@ -26,6 +26,8 @@ global vec_insert
|
||||||
global vec_insert_many
|
global vec_insert_many
|
||||||
global vec_insert_sorted
|
global vec_insert_sorted
|
||||||
global vec_binary_search_by
|
global vec_binary_search_by
|
||||||
|
global vec_try_grow
|
||||||
|
global vec_try_grow_with
|
||||||
|
|
||||||
global vec_tests
|
global vec_tests
|
||||||
|
|
||||||
|
|
@ -33,11 +35,11 @@ global vec_tests
|
||||||
;; Byte vector structure
|
;; Byte vector structure
|
||||||
;; start-structs
|
;; start-structs
|
||||||
;; struct BlobVec {
|
;; struct BlobVec {
|
||||||
;; data: *mut u8,
|
;; data: *mut (),
|
||||||
;; len: usize,
|
;; len: usize,
|
||||||
;; cap: usize,
|
;; cap: usize,
|
||||||
;; elem_size: usize,
|
;; elem_size: usize,
|
||||||
;; drop: Option<extern "C" fn(*mut u8)>,
|
;; drop: Option<unsafe extern "C" fn(*mut ())>,
|
||||||
;; }
|
;; }
|
||||||
;; end-structs
|
;; end-structs
|
||||||
;; size: 40 bytes
|
;; size: 40 bytes
|
||||||
|
|
@ -48,7 +50,7 @@ global vec_tests
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
;; rsi: item_size
|
;; rsi: item_size
|
||||||
;; rdx: drop function pointer
|
;; rdx: drop function pointer
|
||||||
;; fn vec_init(vec: *mut Vec, item_size: usize, drop: Option<fn(*mut u8)>)
|
;; define-fn: fn vec_init(vec: *mut BlobVec, item_size: usize, drop: Option<unsafe extern "C" fn(*mut ())>)
|
||||||
vec_init:
|
vec_init:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -57,7 +59,8 @@ vec_init:
|
||||||
push rdi
|
push rdi
|
||||||
; (*vec).data = allocate(INIT_CAPACITY);
|
; (*vec).data = allocate(INIT_CAPACITY);
|
||||||
mov rdi, INIT_CAPACITY
|
mov rdi, INIT_CAPACITY
|
||||||
call allocate
|
mov rsi, 8
|
||||||
|
call bump_alloc
|
||||||
pop r15
|
pop r15
|
||||||
mov [r15], rax
|
mov [r15], rax
|
||||||
; (*vec).len = 0;
|
; (*vec).len = 0;
|
||||||
|
|
@ -79,7 +82,7 @@ vec_init:
|
||||||
;; rsi: item_size
|
;; rsi: item_size
|
||||||
;; rdx: drop function pointer
|
;; rdx: drop function pointer
|
||||||
;; rcx: capacity
|
;; rcx: capacity
|
||||||
;; fn vec_init_with(vec: *mut Vec, item_size: usize, drop: Option<fn(*mut u8)>, capacity: usize)
|
;; define-fn: fn vec_init_with(vec: *mut BlobVec, item_size: usize, drop: Option<unsafe extern "C" fn(*mut ())>, capacity: usize)
|
||||||
vec_init_with:
|
vec_init_with:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -94,7 +97,8 @@ vec_init_with:
|
||||||
mov rax, rcx
|
mov rax, rcx
|
||||||
mul rsi ; capacity * item_size
|
mul rsi ; capacity * item_size
|
||||||
mov rdi, rax
|
mov rdi, rax
|
||||||
call allocate
|
mov rsi, 8
|
||||||
|
call bump_alloc
|
||||||
pop r15
|
pop r15
|
||||||
mov [r15], rax
|
mov [r15], rax
|
||||||
; (*vec).len = 0;
|
; (*vec).len = 0;
|
||||||
|
|
@ -112,7 +116,7 @@ vec_init_with:
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
;; rsi: index
|
;; rsi: index
|
||||||
;; rdx: pointer to default value
|
;; rdx: pointer to default value
|
||||||
;; fn vec_get(vec: *mut Vec, index: usize, default: *mut u8) -> *mut u8
|
;; define-fn: fn vec_get_or(vec: *mut BlobVec, index: usize, default: *mut ()) -> *mut ()
|
||||||
vec_get_or:
|
vec_get_or:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -134,7 +138,7 @@ vec_get_or:
|
||||||
|
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
;; rsi: index
|
;; rsi: index
|
||||||
;; fn vec_get(vec: *mut Vec, index: usize) -> *mut u8
|
;; define-fn: fn vec_get(vec: *mut BlobVec, index: usize) -> *mut ()
|
||||||
vec_get:
|
vec_get:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -157,7 +161,8 @@ vec_get:
|
||||||
|
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
;; rsi: pointer to data to push
|
;; rsi: pointer to data to push
|
||||||
;; fn vec_push(vec: *mut Vec, data: &[u8])
|
;; returns the index at which the item was pushed (the old length of the vector)
|
||||||
|
;; define-fn: fn vec_push(vec: *mut BlobVec, data: *const ()) -> usize
|
||||||
vec_push:
|
vec_push:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -182,15 +187,16 @@ vec_push:
|
||||||
mov rdx, [rax + 24] ; item_size
|
mov rdx, [rax + 24] ; item_size
|
||||||
call memcpy
|
call memcpy
|
||||||
; vec.len += 1;
|
; vec.len += 1;
|
||||||
mov rax, [rsp] ; vec
|
mov rdx, [rsp] ; vec
|
||||||
add qword [rax + 8], 1
|
mov rax, [rdx + 8]
|
||||||
|
add qword [rdx + 8], 1
|
||||||
add rsp, 24
|
add rsp, 24
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
;; fn vec_pop(vec: *mut Vec)
|
;; define-fn: fn vec_pop(vec: *mut BlobVec)
|
||||||
vec_pop:
|
vec_pop:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -210,7 +216,7 @@ vec_pop:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
;; fn vec_pop(vec: *mut Vec)
|
;; define-fn: fn vec_drop_last(vec: *mut BlobVec)
|
||||||
vec_drop_last:
|
vec_drop_last:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -244,7 +250,7 @@ vec_drop_last:
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
;; rsi: index a
|
;; rsi: index a
|
||||||
;; rdx: index b
|
;; rdx: index b
|
||||||
;; fn vec_swap(vec: *mut Vec, a: usize, b: usize)
|
;; define-fn: fn vec_swap(vec: *mut BlobVec, a: usize, b: usize)
|
||||||
vec_swap:
|
vec_swap:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -291,7 +297,7 @@ vec_swap:
|
||||||
|
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
;; rsi: index
|
;; rsi: index
|
||||||
;; fn vec_remove(vec: *mut Vec, index: usize)
|
;; define-fn: fn vec_remove(vec: *mut BlobVec, index: usize)
|
||||||
vec_remove:
|
vec_remove:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -337,8 +343,18 @@ vec_remove:
|
||||||
;; essentially a reserve() function
|
;; essentially a reserve() function
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
;; rsi: desired size
|
;; rsi: desired size
|
||||||
;; fn vec_try_grow(vec: *mut Vec, new_size: usize) -> bool
|
;; define-fn: fn vec_try_grow(vec: *mut BlobVec, new_size: usize) -> bool
|
||||||
vec_try_grow:
|
vec_try_grow:
|
||||||
|
mov rdx, bump_alloc
|
||||||
|
call vec_try_grow_with
|
||||||
|
ret
|
||||||
|
|
||||||
|
;; essentially a reserve() function
|
||||||
|
;; rdi: pointer to Vec struct
|
||||||
|
;; rsi: desired size
|
||||||
|
;; rdx: allocate function pointer
|
||||||
|
;; define-fn: fn vec_try_grow_with(vec: *mut BlobVec, new_size: usize, alloc: unsafe extern "C" fn(usize, usize) -> *const ()) -> bool
|
||||||
|
vec_try_grow_with:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
push rbx
|
push rbx
|
||||||
|
|
@ -366,7 +382,8 @@ vec_try_grow:
|
||||||
mul qword [rdi + 24] ; new_capacity * item_size
|
mul qword [rdi + 24] ; new_capacity * item_size
|
||||||
; new_data = allocate(new_capacity);
|
; new_data = allocate(new_capacity);
|
||||||
mov rdi, rax
|
mov rdi, rax
|
||||||
call allocate
|
mov rsi, 8
|
||||||
|
call rdx
|
||||||
mov [rsp + 16], rax
|
mov [rsp + 16], rax
|
||||||
mov rdi, [rsp]
|
mov rdi, [rsp]
|
||||||
; memcpy(new_data, old_data, len * vec.item_size);
|
; memcpy(new_data, old_data, len * vec.item_size);
|
||||||
|
|
@ -390,6 +407,7 @@ vec_try_grow:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
|
;; define-fn: fn vec_drop(vec: *mut BlobVec)
|
||||||
vec_drop:
|
vec_drop:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -432,6 +450,7 @@ vec_drop:
|
||||||
;; rsi: poiter to object to find
|
;; rsi: poiter to object to find
|
||||||
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> bool
|
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> bool
|
||||||
;; rcx: compare_fn context
|
;; rcx: compare_fn context
|
||||||
|
;; define-fn: fn vec_find(vec: *mut BlobVec, object: *const (), compare: unsafe extern "C" fn(ctx: *const (), a: *const (), b: *const ()) -> bool, ctx: *const ()) -> usize
|
||||||
vec_find:
|
vec_find:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -483,7 +502,7 @@ vec_find:
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
;; rsi : index
|
;; rsi : index
|
||||||
;; rdx: pointer to data to insert
|
;; rdx: pointer to data to insert
|
||||||
;; fn vec_insert(vec: *mut Vec, index: usize, data: *const T)
|
;; define-fn: fn vec_insert(vec: *mut BlobVec, index: usize, data: *const ())
|
||||||
vec_insert:
|
vec_insert:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -535,7 +554,7 @@ vec_insert:
|
||||||
;; rsi : index
|
;; rsi : index
|
||||||
;; rdx: pointer to data to insert
|
;; rdx: pointer to data to insert
|
||||||
;; rcx: count
|
;; rcx: count
|
||||||
;; define-fn: fn vec_insert_many(vec: *mut BlobVec, index: usize, data: *const u8, count: usize)
|
;; define-fn: fn vec_insert_many(vec: *mut BlobVec, index: usize, data: *const (), count: usize)
|
||||||
vec_insert_many:
|
vec_insert_many:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -595,7 +614,7 @@ vec_insert_many:
|
||||||
;; rsi: pointer to key
|
;; rsi: pointer to key
|
||||||
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32
|
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32
|
||||||
;; rcx: compare_fn context
|
;; rcx: compare_fn context
|
||||||
;;fn vec_binary_search_by(vec: *mut Vec, key: *const T, compare: fn(ctx: *const (), a: *const T, b: *const T) -> i32, ctx: *const ()) -> (usize, bool)
|
;; define-fn: fn vec_binary_search_by(vec: *mut BlobVec, key: *const (), compare: unsafe extern "C" fn(ctx: *const (), a: *const (), b: *const ()) -> i32, ctx: *const ()) -> (usize, bool)
|
||||||
vec_binary_search_by:
|
vec_binary_search_by:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -667,7 +686,7 @@ vec_binary_search_by:
|
||||||
;; rsi: pointer to key
|
;; rsi: pointer to key
|
||||||
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32
|
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32
|
||||||
;; rcx: compare_fn context
|
;; rcx: compare_fn context
|
||||||
;;fn vec_insert_sorted(vec: *mut Vec, key: *const T, compare: fn(ctx: *const (), a: *const T, b: *const T) -> i32, ctx: *const ()) -> (usize, bool)
|
;;define-fn: fn vec_insert_sorted(vec: *mut BlobVec, key: *const (), compare: unsafe extern "C" fn(ctx: *const (), a: *const (), b: *const ()) -> i32, ctx: *const ()) -> (usize, bool)
|
||||||
vec_insert_sorted:
|
vec_insert_sorted:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
@ -694,9 +713,9 @@ vec_insert_sorted:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
;; rdi: *Vec
|
;; rdi: *Vec
|
||||||
;; rsi: *const u8
|
;; rsi: *const ()
|
||||||
;; rdx: number of elements
|
;; rdx: number of elements
|
||||||
;; define-fn: fn vec_extend(vec: *mut BlobVec, elements: *const u8, count: usize) -> ()
|
;; define-fn: fn vec_extend(vec: *mut BlobVec, elements: *const (), count: usize) -> ()
|
||||||
vec_extend:
|
vec_extend:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ def parse_file(path: Path) -> Dict[str, Any]:
|
||||||
def render_rust(function_sigs: List[str], consts: List[Tuple[str, str, str]],
|
def render_rust(function_sigs: List[str], consts: List[Tuple[str, str, str]],
|
||||||
structs: List[Tuple[str, List[str]]], rust_blocks: List[List[str]]) -> str:
|
structs: List[Tuple[str, List[str]]], rust_blocks: List[List[str]]) -> str:
|
||||||
parts: List[str] = []
|
parts: List[str] = []
|
||||||
parts.append('#![allow(non_camel_case_types, dead_code, non_upper_case_globals, improper_ctypes)]')
|
# parts.append('#![allow(non_camel_case_types, dead_code, non_upper_case_globals, improper_ctypes)]')
|
||||||
parts.append('// Auto-generated Rust bindings from assembly source\n')
|
parts.append('// Auto-generated Rust bindings from assembly source\n')
|
||||||
|
|
||||||
# Functions: wrap in single extern "C" block if any
|
# Functions: wrap in single extern "C" block if any
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,7 @@ a = &b;
|
||||||
}",
|
}",
|
||||||
|ast| unsafe { parse_func(ast) },
|
|ast| unsafe { parse_func(ast) },
|
||||||
);
|
);
|
||||||
|
|
||||||
print_ast(
|
print_ast(
|
||||||
b"fn main(a: u32) -> void {
|
b"fn main(a: u32) -> void {
|
||||||
if (a == 0) {
|
if (a == 0) {
|
||||||
|
|
@ -122,4 +123,18 @@ a = &b;
|
||||||
}",
|
}",
|
||||||
|ast| unsafe { parse_func(ast) },
|
|ast| unsafe { parse_func(ast) },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
print_ast(
|
||||||
|
b"fn main(a: u32) -> void {
|
||||||
|
return main(1);
|
||||||
|
}",
|
||||||
|
|ast| unsafe { parse_func(ast) },
|
||||||
|
);
|
||||||
|
|
||||||
|
print_ast(
|
||||||
|
b"fn main(a: u32) -> void {
|
||||||
|
return a as u8;
|
||||||
|
}",
|
||||||
|
|ast| unsafe { parse_func(ast) },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,15 +99,26 @@ fn main() {
|
||||||
// |ast| unsafe { parse_func(ast) },
|
// |ast| unsafe { parse_func(ast) },
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
// print_ast(
|
||||||
|
// b"fn main(a: u32) -> void {
|
||||||
|
// let x: u32 = 10;
|
||||||
|
// if (a == 42) {
|
||||||
|
// x = 7;
|
||||||
|
// } else {
|
||||||
|
// x = 8;
|
||||||
|
// }
|
||||||
|
// return x;
|
||||||
|
// }",
|
||||||
|
// |ast| unsafe { parse_func(ast) },
|
||||||
|
// );
|
||||||
|
|
||||||
print_ast(
|
print_ast(
|
||||||
b"fn main(a: u32) -> void {
|
b"fn main(a: u32) -> void {
|
||||||
let x: u32 = 10;
|
|
||||||
if (a == 42) {
|
if (a == 42) {
|
||||||
x = 7;
|
return main(7);
|
||||||
} else {
|
} else {
|
||||||
x = 8;
|
return a;
|
||||||
}
|
}
|
||||||
return x;
|
|
||||||
}",
|
}",
|
||||||
|ast| unsafe { parse_func(ast) },
|
|ast| unsafe { parse_func(ast) },
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ use super::util;
|
||||||
impl core::fmt::Display for util::defs::AstNode {
|
impl core::fmt::Display for util::defs::AstNode {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
use util::defs::{
|
use util::defs::{
|
||||||
BinaryExpr, AST_ADDRESS_OF, AST_ARG, AST_ASSIGNMENT, AST_BINARY_OP, AST_BLOCK,
|
BinaryExpr, AST_ADDRESS_OF, AST_ARG, AST_AS, AST_ASSIGNMENT, AST_BINARY_OP, AST_BLOCK,
|
||||||
AST_DEREF, AST_FUNCTION, AST_IF, AST_NUMBER, AST_PLACE_TO_VALUE, AST_RETURN_STATEMENT,
|
AST_CALL, AST_DEREF, AST_FUNCTION, AST_IF, AST_NUMBER, AST_PLACE_TO_VALUE,
|
||||||
AST_VALUE_TO_PLACE, AST_VAR_DECL, AST_VAR_REF,
|
AST_RETURN_STATEMENT, AST_VALUE_TO_PLACE, AST_VAR_DECL, AST_VAR_REF,
|
||||||
};
|
};
|
||||||
match self.kind {
|
match self.kind {
|
||||||
AST_NUMBER => {
|
AST_NUMBER => {
|
||||||
|
|
@ -17,6 +17,16 @@ impl core::fmt::Display for util::defs::AstNode {
|
||||||
AST_ADDRESS_OF => {
|
AST_ADDRESS_OF => {
|
||||||
write!(f, "AddressOf(expr: {})", self.data as usize)
|
write!(f, "AddressOf(expr: {})", self.data as usize)
|
||||||
}
|
}
|
||||||
|
AST_CALL => {
|
||||||
|
let call = unsafe { self.data.cast::<util::defs::AstCallExpr>().read() };
|
||||||
|
write!(f, "Call(callee: {}, params: {:?})", call.callee, unsafe {
|
||||||
|
std::slice::from_raw_parts(call.params.cast::<u64>(), call.params_len as usize)
|
||||||
|
},)
|
||||||
|
}
|
||||||
|
AST_AS => {
|
||||||
|
let as_expr = unsafe { self.data.cast::<util::defs::AstAsExpr>().read() };
|
||||||
|
write!(f, "As(expr: {}, target_type: {})", as_expr.expr, as_expr.ty)
|
||||||
|
}
|
||||||
AST_ARG => {
|
AST_ARG => {
|
||||||
let arg = unsafe { self.data.cast::<util::defs::AstArgument>().read() };
|
let arg = unsafe { self.data.cast::<util::defs::AstArgument>().read() };
|
||||||
write!(
|
write!(
|
||||||
|
|
@ -147,6 +157,7 @@ impl core::fmt::Display for util::defs::SymEntry {
|
||||||
util::defs::SYM_KEY_PARENT_SCOPE => "ParentScope",
|
util::defs::SYM_KEY_PARENT_SCOPE => "ParentScope",
|
||||||
util::defs::SYM_KEY_ARG => "Argument",
|
util::defs::SYM_KEY_ARG => "Argument",
|
||||||
util::defs::SYM_KEY_VAR => "Variable",
|
util::defs::SYM_KEY_VAR => "Variable",
|
||||||
|
util::defs::SYM_KEY_FUNCTION => "Function",
|
||||||
_ => "Unknown",
|
_ => "Unknown",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,12 @@
|
||||||
// Auto-generated Rust bindings from assembly source
|
// Auto-generated Rust bindings from assembly source
|
||||||
|
|
||||||
unsafe extern "C" {
|
unsafe extern "C" {
|
||||||
|
pub unsafe fn bump_init();
|
||||||
|
pub unsafe fn bump_alloc(size: usize, alignment: usize) -> *mut u8;
|
||||||
pub unsafe fn parse_func(ast: *mut Ast) -> u64;
|
pub unsafe fn parse_func(ast: *mut Ast) -> u64;
|
||||||
pub unsafe fn parse_args(ast: *mut Ast) -> (*const u64, usize);
|
pub unsafe fn parse_args(ast: *mut Ast) -> (*const u64, usize);
|
||||||
|
pub unsafe fn parse_as_expr(ast: *mut Ast) -> (u64, bool);
|
||||||
|
pub unsafe fn parse_postfix_expr(ast: *mut Ast) -> (u64, bool);
|
||||||
pub unsafe fn parse_primary_expr(ast: *mut Ast) -> (u64, bool);
|
pub unsafe fn parse_primary_expr(ast: *mut Ast) -> (u64, bool);
|
||||||
pub unsafe fn parse_binary_expr(ast: *mut Ast, precedence: u8) -> (u64, bool);
|
pub unsafe fn parse_binary_expr(ast: *mut Ast, precedence: u8) -> (u64, bool);
|
||||||
pub unsafe fn parse_expr(ast: *mut Ast) -> u64;
|
pub unsafe fn parse_expr(ast: *mut Ast) -> u64;
|
||||||
|
|
@ -28,6 +32,7 @@ unsafe extern "C" {
|
||||||
pub unsafe fn codegen_free_operand(ctx: *mut FunctionCtx, operand: *const Operand) -> ();
|
pub unsafe fn codegen_free_operand(ctx: *mut FunctionCtx, operand: *const Operand) -> ();
|
||||||
pub unsafe fn codegen_function(ast: *const CodegenCtx, func_idx: u64) -> ();
|
pub unsafe fn codegen_function(ast: *const CodegenCtx, func_idx: u64) -> ();
|
||||||
pub unsafe fn codegen_push_pop_used_registers(text: *mut Vec<u8>, function_ctx: &FunctionCtx, pop: bool) -> u8;
|
pub unsafe fn codegen_push_pop_used_registers(text: *mut Vec<u8>, function_ctx: &FunctionCtx, pop: bool) -> u8;
|
||||||
|
pub unsafe fn codegen_call_expr(ctx: *const CodegenCtx, function_ctx: &FunctionCtx, call_expr: *const AstCallExpr) -> (u64, bool);
|
||||||
pub unsafe fn codegen_expr(ctx: *const CodegenCtx, function_ctx: &FunctionCtx, expr_idx: u64) -> (u64, bool);
|
pub unsafe fn codegen_expr(ctx: *const CodegenCtx, function_ctx: &FunctionCtx, expr_idx: u64) -> (u64, bool);
|
||||||
pub unsafe fn codegen_binary_op_rm64_rm64(function_ctx: *mut FunctionCtx, text: *mut BlobVec, lhs: *const Operand, rhs: *const Operand, op: [u8; 8], discard_result: bool) -> *const Operand;
|
pub unsafe fn codegen_binary_op_rm64_rm64(function_ctx: *mut FunctionCtx, text: *mut BlobVec, lhs: *const Operand, rhs: *const Operand, op: [u8; 8], discard_result: bool) -> *const Operand;
|
||||||
pub unsafe fn vec_insert_many(vec: *mut BlobVec, index: usize, data: *const u8, count: usize);
|
pub unsafe fn vec_insert_many(vec: *mut BlobVec, index: usize, data: *const u8, count: usize);
|
||||||
|
|
@ -38,9 +43,10 @@ pub const SYM_KEY_SCOPE: u8 = 1;
|
||||||
pub const SYM_KEY_SCOPE_NAME: u8 = 2;
|
pub const SYM_KEY_SCOPE_NAME: u8 = 2;
|
||||||
pub const SYM_KEY_PARENT_SCOPE: u8 = 3;
|
pub const SYM_KEY_PARENT_SCOPE: u8 = 3;
|
||||||
pub const SYM_KEY_START_LOCALS: u8 = 4;
|
pub const SYM_KEY_START_LOCALS: u8 = 4;
|
||||||
pub const SYM_KEY_ARG: u8 = 5;
|
pub const SYM_KEY_FUNCTION: u8 = 5;
|
||||||
pub const SYM_KEY_VAR: u8 = 6;
|
pub const SYM_KEY_ARG: u8 = 6;
|
||||||
pub const SYM_KEY_END_LOCALS: u8 = 7;
|
pub const SYM_KEY_VAR: u8 = 7;
|
||||||
|
pub const SYM_KEY_END_LOCALS: u8 = 8;
|
||||||
pub const AST_FUNCTION: u8 = 1;
|
pub const AST_FUNCTION: u8 = 1;
|
||||||
pub const AST_BLOCK: u8 = 2;
|
pub const AST_BLOCK: u8 = 2;
|
||||||
pub const AST_VARIABLE: u8 = 3;
|
pub const AST_VARIABLE: u8 = 3;
|
||||||
|
|
@ -59,12 +65,23 @@ pub const AST_SWITCH: u8 = 15;
|
||||||
pub const AST_IF: u8 = 16;
|
pub const AST_IF: u8 = 16;
|
||||||
pub const AST_ELSE: u8 = 17;
|
pub const AST_ELSE: u8 = 17;
|
||||||
pub const AST_CALL: u8 = 18;
|
pub const AST_CALL: u8 = 18;
|
||||||
|
pub const AST_AS: u8 = 19;
|
||||||
pub const TYPE_VOID: u8 = 1;
|
pub const TYPE_VOID: u8 = 1;
|
||||||
pub const TYPE_BOOL: u8 = 2;
|
pub const TYPE_BOOL: u8 = 2;
|
||||||
pub const TYPE_I32: u8 = 3;
|
pub const TYPE_U8: u8 = 3;
|
||||||
pub const TYPE_U32: u8 = 4;
|
pub const TYPE_U16: u8 = 4;
|
||||||
pub const TYPE_STR: u8 = 5;
|
pub const TYPE_U32: u8 = 5;
|
||||||
pub const TYPE_POINTER: u8 = 6;
|
pub const TYPE_U64: u8 = 6;
|
||||||
|
pub const TYPE_USIZE: u8 = 7;
|
||||||
|
pub const TYPE_I8: u8 = 8;
|
||||||
|
pub const TYPE_I16: u8 = 9;
|
||||||
|
pub const TYPE_I32: u8 = 10;
|
||||||
|
pub const TYPE_I64: u8 = 11;
|
||||||
|
pub const TYPE_ISIZE: u8 = 12;
|
||||||
|
pub const TYPE_STR: u8 = 13;
|
||||||
|
pub const TYPE_POINTER: u8 = 14;
|
||||||
|
pub const TYPE_F32: u8 = 15;
|
||||||
|
pub const TYPE_F64: u8 = 16;
|
||||||
pub const OPERAND_REGISTER: u32 = 1;
|
pub const OPERAND_REGISTER: u32 = 1;
|
||||||
pub const OPERAND_RBP_VALUE: u32 = 2;
|
pub const OPERAND_RBP_VALUE: u32 = 2;
|
||||||
pub const OPERAND_RBP_PVALUE: u32 = 3;
|
pub const OPERAND_RBP_PVALUE: u32 = 3;
|
||||||
|
|
@ -190,6 +207,21 @@ pub struct AstFunction {
|
||||||
pub body: u64,
|
pub body: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AstAsExpr {
|
||||||
|
pub expr: u64,
|
||||||
|
pub ty: Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AstCallExpr {
|
||||||
|
pub callee: u64,
|
||||||
|
pub params: *const u64,
|
||||||
|
pub params_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AstVarRef {
|
pub struct AstVarRef {
|
||||||
|
|
@ -292,6 +324,8 @@ pub struct Operand {
|
||||||
pub register: u8,
|
pub register: u8,
|
||||||
pub width: u16,
|
pub width: u16,
|
||||||
pub len: u16,
|
pub len: u16,
|
||||||
|
pub align: u8,
|
||||||
|
pub bitset: u8,
|
||||||
pub value: u64,
|
pub value: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -373,26 +373,60 @@ impl<'a, T: core::fmt::Display> core::fmt::Display for DisplaySlice<'a, T> {
|
||||||
|
|
||||||
impl core::fmt::Display for defs::Type {
|
impl core::fmt::Display for defs::Type {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
use defs::{
|
||||||
|
TYPE_BOOL, TYPE_F32, TYPE_F64, TYPE_I16, TYPE_I32, TYPE_I64, TYPE_I8, TYPE_ISIZE,
|
||||||
|
TYPE_POINTER, TYPE_STR, TYPE_U16, TYPE_U32, TYPE_U64, TYPE_U8, TYPE_USIZE, TYPE_VOID,
|
||||||
|
};
|
||||||
match self.kind {
|
match self.kind {
|
||||||
defs::TYPE_VOID => {
|
TYPE_VOID => {
|
||||||
write!(f, "void")
|
write!(f, "void")
|
||||||
}
|
}
|
||||||
defs::TYPE_BOOL => {
|
TYPE_BOOL => {
|
||||||
write!(f, "bool")
|
write!(f, "bool")
|
||||||
}
|
}
|
||||||
defs::TYPE_I32 => {
|
TYPE_I32 => {
|
||||||
write!(f, "i32")
|
write!(f, "i32")
|
||||||
}
|
}
|
||||||
defs::TYPE_U32 => {
|
TYPE_U32 => {
|
||||||
write!(f, "u32")
|
write!(f, "u32")
|
||||||
}
|
}
|
||||||
defs::TYPE_STR => {
|
TYPE_STR => {
|
||||||
write!(f, "str")
|
write!(f, "str")
|
||||||
}
|
}
|
||||||
defs::TYPE_POINTER => {
|
TYPE_POINTER => {
|
||||||
let pointee = unsafe { (self.data as *const defs::Type).read() };
|
let pointee = unsafe { (self.data as *const defs::Type).read() };
|
||||||
write!(f, "*{pointee}",)
|
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")
|
write!(f, "UnknownType")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ mod util;
|
||||||
use util::{ffi::*, vec::Vec, BlobVec};
|
use util::{ffi::*, vec::Vec, BlobVec};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
unsafe {
|
||||||
|
util::defs::bump_init();
|
||||||
|
}
|
||||||
static mut DROPS: usize = 1;
|
static mut DROPS: usize = 1;
|
||||||
fn get_drops() -> usize {
|
fn get_drops() -> usize {
|
||||||
unsafe { (&raw const DROPS).read() }
|
unsafe { (&raw const DROPS).read() }
|
||||||
|
|
|
||||||
7
lang/typeck/Cargo.toml
Normal file
7
lang/typeck/Cargo.toml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
[package]
|
||||||
|
name = "typeck"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libcompiler = { path = "../libcompiler" }
|
||||||
40
lang/typeck/src/lib.rs
Normal file
40
lang/typeck/src/lib.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
fn init() {
|
||||||
|
unsafe {
|
||||||
|
libcompiler::ffi::bump_init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use libcompiler::ffi::Ast;
|
||||||
|
|
||||||
|
use crate::init;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn type_graph() {
|
||||||
|
init();
|
||||||
|
|
||||||
|
let src = b"fn my-fun(a: u32, b: u32) -> void {
|
||||||
|
let x: i64 = a as i64 + b as i64;
|
||||||
|
}";
|
||||||
|
unsafe {
|
||||||
|
libcompiler::ffi::tokeniser_init_buf(src.as_ptr(), src.len());
|
||||||
|
|
||||||
|
let mut ast = Ast {
|
||||||
|
nodes: libcompiler::vec::Vec::default(),
|
||||||
|
};
|
||||||
|
let func_id = libcompiler::ffi::parse_func(&mut ast);
|
||||||
|
let mut symtable = core::mem::MaybeUninit::<libcompiler::ffi::SymbolTable>::uninit();
|
||||||
|
libcompiler::ffi::ast_build_symtable(&mut ast, func_id, &mut symtable);
|
||||||
|
let mut symtable = symtable.assume_init();
|
||||||
|
|
||||||
|
use libcompiler::DisplayedSliceExt;
|
||||||
|
println!(
|
||||||
|
"Symbol Table: {:#?}",
|
||||||
|
symtable.symtable.as_slice().displayed()
|
||||||
|
);
|
||||||
|
|
||||||
|
libcompiler::ffi::ast_resolve_var_refs(&mut ast, &mut symtable, func_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
tools/asm2rust
Symbolic link
1
tools/asm2rust
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../lang/tests/asm_to_rust.py
|
||||||
Loading…
Reference in a new issue