actually compiles and does stuff now

This commit is contained in:
2024-12-06 19:44:33 -05:00
parent 31c197e991
commit 620c4557e9
67 changed files with 1931 additions and 1287 deletions

39
src/ir/upper/def.rs Normal file
View File

@@ -0,0 +1,39 @@
use super::{FileSpan, Type};
use std::fmt::Debug;
#[derive(Clone)]
pub struct FnDef {
pub name: String,
pub args: Vec<VarDef>,
pub ret: Type,
pub origin: Origin,
}
#[derive(Clone)]
pub struct TypeDef {
pub name: String,
pub args: usize,
pub origin: Origin,
}
#[derive(Clone)]
pub struct VarDef {
pub name: String,
pub ty: Type,
pub origin: Origin,
}
#[derive(Debug, Clone, Copy)]
pub enum Origin {
Builtin,
File(FileSpan),
}
impl FnDef {
pub fn ty(&self) -> Type {
Type::Fn {
args: self.args.iter().map(|a| a.ty.clone()).collect(),
ret: Box::new(self.ret.clone()),
}
}
}

82
src/ir/upper/func.rs Normal file
View File

@@ -0,0 +1,82 @@
use crate::compiler::arch::riscv64::Reg;
use super::{arch::riscv64::RV64Instruction, DataID, FnID, VarID};
#[derive(Debug)]
pub struct IRUFunction {
pub name: String,
pub args: Vec<VarID>,
pub instructions: Vec<IRUInstruction>,
}
pub enum IRUInstruction {
Mv {
dest: VarID,
src: VarID,
},
Ref {
dest: VarID,
src: VarID,
},
LoadData {
dest: VarID,
src: DataID,
},
LoadFn {
dest: VarID,
src: FnID,
},
Call {
dest: VarID,
f: VarID,
args: Vec<VarID>,
},
AsmBlock {
instructions: Vec<RV64Instruction>,
args: Vec<(Reg, VarID)>,
},
Ret {
src: VarID,
},
}
pub struct IRInstructions {
vec: Vec<IRUInstruction>,
}
impl IRUFunction {
pub fn new(name: String, args: Vec<VarID>, instructions: IRInstructions) -> Self {
Self {
name,
args,
instructions: instructions.vec,
}
}
}
impl IRInstructions {
pub fn new() -> Self {
Self { vec: Vec::new() }
}
pub fn push(&mut self, i: IRUInstruction) {
self.vec.push(i);
}
}
impl std::fmt::Debug for IRUInstruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Mv { dest, src } => write!(f, "{dest:?} <- {src:?}"),
Self::Ref { dest, src } => write!(f, "{dest:?} <- &{src:?}"),
Self::LoadData { dest, src } => write!(f, "{dest:?} <- {src:?}"),
Self::LoadFn { dest, src } => write!(f, "{dest:?} <- {src:?}"),
Self::Call {
dest,
f: func,
args,
} => write!(f, "{dest:?} <- {func:?}({args:?})"),
Self::AsmBlock { args, instructions } => write!(f, "asm {args:?} {instructions:#?}"),
Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish(),
}
}
}

10
src/ir/upper/mod.rs Normal file
View File

@@ -0,0 +1,10 @@
mod def;
mod func;
mod ty;
mod namespace;
use super::*;
pub use def::*;
pub use func::*;
pub use ty::*;
pub use namespace::*;

233
src/ir/upper/namespace.rs Normal file
View File

@@ -0,0 +1,233 @@
use std::{
collections::HashMap,
fmt::Debug,
ops::{Deref, DerefMut},
};
use super::*;
pub struct Namespace {
pub fn_defs: Vec<FnDef>,
pub var_defs: Vec<VarDef>,
pub type_defs: Vec<TypeDef>,
pub fns: Vec<Option<IRUFunction>>,
pub data: Vec<Vec<u8>>,
pub fn_map: HashMap<VarID, FnID>,
pub temp: usize,
pub stack: Vec<HashMap<String, Idents>>,
}
impl Namespace {
pub fn new() -> Self {
let mut s = Self {
fn_defs: Vec::new(),
var_defs: Vec::new(),
type_defs: Vec::new(),
data: Vec::new(),
fn_map: HashMap::new(),
fns: Vec::new(),
temp: 0,
stack: vec![HashMap::new()],
};
for b in BuiltinType::enumerate() {
s.def_type(b.def());
}
s
}
pub fn push(&mut self) -> NamespaceGuard {
self.stack.push(HashMap::new());
NamespaceGuard(self)
}
pub fn get(&self, name: &str) -> Option<Idents> {
for map in self.stack.iter().rev() {
let res = map.get(name);
if res.is_some() {
return res.cloned();
}
}
None
}
pub fn get_var(&self, id: VarID) -> &VarDef {
&self.var_defs[id.0]
}
pub fn get_fn(&self, id: FnID) -> &FnDef {
&self.fn_defs[id.0]
}
pub fn get_fn_var(&self, id: VarID) -> &FnDef {
&self.fn_defs[self.fn_map[&id].0]
}
pub fn get_type(&self, id: TypeID) -> &TypeDef {
&self.type_defs[id.0]
}
pub fn alias_fn(&mut self, name: &str, id: FnID) {
self.insert(name, Ident::Fn(id));
}
pub fn named_var(&mut self, def: VarDef) -> VarID {
// TODO: this is stupid
let id = self.def_var(def.clone());
self.name_var(&def, id);
id
}
pub fn name_var(&mut self, def: &VarDef, var: VarID) {
self.insert(&def.name, Ident::Var(var));
}
pub fn def_var(&mut self, var: VarDef) -> VarID {
let i = self.var_defs.len();
self.var_defs.push(var);
VarID(i)
}
pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarID {
let v = self.def_var(VarDef {
name: format!("temp{}", self.temp),
origin: super::Origin::File(origin),
ty,
});
self.temp += 1;
v
}
pub fn def_fn(&mut self, def: FnDef) -> FnID {
let i = self.fn_defs.len();
let id = FnID(i);
let var_def = VarDef {
name: def.name.clone(),
origin: def.origin,
ty: def.ty(),
};
let vid = self.def_var(var_def);
self.insert(&def.name, Ident::Var(vid));
self.fn_map.insert(vid, id);
self.insert(&def.name, Ident::Fn(id));
self.fn_defs.push(def);
self.fns.push(None);
id
}
pub fn def_type(&mut self, def: TypeDef) -> TypeID {
let i = self.type_defs.len();
let id = TypeID(i);
self.insert(&def.name, Ident::Type(id));
self.type_defs.push(def);
id
}
pub fn def_data(&mut self, bytes: Vec<u8>) -> DataID {
let i = self.data.len();
self.data.push(bytes);
DataID(i)
}
pub fn type_name(&self, ty: &Type) -> String {
let mut str = String::new();
match ty {
Type::Concrete(t) => {
str += &self.get_type(*t).name;
}
Type::Generic { base, args } => {
str += &self.get_type(*base).name;
if let Some(arg) = args.first() {
str = str + "<" + &self.type_name(arg);
}
for arg in args.iter().skip(1) {
str = str + ", " + &self.type_name(arg);
}
if !args.is_empty() {
str += ">";
}
}
Type::Fn { args, ret } => {
str += "fn(";
if let Some(arg) = args.first() {
str += &self.type_name(arg);
}
for arg in args.iter().skip(1) {
str = str + ", " + &self.type_name(arg);
}
str += ") -> ";
str += &self.type_name(ret);
}
Type::Ref(t) => {
str = str + "&" + &self.type_name(t);
}
Type::Error => str += "{error}",
Type::Infer => str += "{inferred}",
Type::Bits(size) => str += &format!("b{}", size),
Type::Array(t) => str += &format!("[{}]", self.type_name(t)),
}
str
}
fn insert(&mut self, name: &str, id: Ident) {
let idx = self.stack.len() - 1;
let last = &mut self.stack[idx];
if let Some(l) = last.get_mut(name) {
l.insert(id);
} else {
last.insert(name.to_string(), Idents::new(id));
}
}
pub fn write_fn(&mut self, id: FnID, f: IRUFunction) {
self.fns[id.0] = Some(f);
}
}
pub struct NamespaceGuard<'a>(&'a mut Namespace);
impl Drop for NamespaceGuard<'_> {
fn drop(&mut self) {
self.0.stack.pop();
}
}
impl Deref for NamespaceGuard<'_> {
type Target = Namespace;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl DerefMut for NamespaceGuard<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0
}
}
#[derive(Debug, Clone, Copy)]
pub enum Ident {
Var(VarID),
Fn(FnID),
Type(TypeID),
}
#[derive(Debug, Clone, Copy)]
pub struct Idents {
pub latest: Ident,
pub var: Option<VarID>,
pub func: Option<FnID>,
pub ty: Option<TypeID>,
}
impl Idents {
fn new(latest: Ident) -> Self {
let mut s = Self {
latest,
var: None,
func: None,
ty: None,
};
s.insert(latest);
s
}
fn insert(&mut self, i: Ident) {
self.latest = i;
match i {
Ident::Var(v) => {
self.var = Some(v);
}
Ident::Fn(f) => {
self.func = Some(f);
}
Ident::Type(t) => self.ty = Some(t),
}
}
}

53
src/ir/upper/ty.rs Normal file
View File

@@ -0,0 +1,53 @@
use super::{Origin, TypeDef, TypeID};
#[derive(Clone)]
pub enum Type {
Concrete(TypeID),
Bits(u32),
Generic { base: TypeID, args: Vec<Type> },
Fn { args: Vec<Type>, ret: Box<Type> },
Ref(Box<Type>),
Array(Box<Type>),
Infer,
Error,
}
impl Type {
pub fn rf(self) -> Self {
Self::Ref(Box::new(self))
}
pub fn arr(self) -> Self {
Self::Array(Box::new(self))
}
}
#[repr(usize)]
#[derive(Debug, Clone, Copy)]
pub enum BuiltinType {
Unit,
}
impl BuiltinType {
pub fn enumerate() -> &'static [Self; 1] {
&[Self::Unit]
}
pub fn def(&self) -> TypeDef {
match self {
BuiltinType::Unit => TypeDef {
name: "()".to_string(),
args: 0,
origin: Origin::Builtin,
},
}
}
pub fn id(&self) -> TypeID {
TypeID::builtin(self)
}
}
impl TypeID {
pub fn builtin(ty: &BuiltinType) -> Self {
Self(*ty as usize)
}
}