actually compiles and does stuff now
This commit is contained in:
39
src/ir/upper/def.rs
Normal file
39
src/ir/upper/def.rs
Normal 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
82
src/ir/upper/func.rs
Normal 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
10
src/ir/upper/mod.rs
Normal 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
233
src/ir/upper/namespace.rs
Normal 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
53
src/ir/upper/ty.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user