huge refactor, can now define structs out of order
This commit is contained in:
@@ -1,82 +0,0 @@
|
||||
use crate::{
|
||||
common::FileSpan,
|
||||
ir::{FieldID, Len, StructID, VarID},
|
||||
};
|
||||
|
||||
use super::Type;
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FnDef {
|
||||
pub name: String,
|
||||
pub args: Vec<VarDef>,
|
||||
pub ret: Type,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StructField {
|
||||
pub name: String,
|
||||
pub ty: Type,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StructDef {
|
||||
pub name: String,
|
||||
pub fields: Vec<StructField>,
|
||||
pub field_map: HashMap<String, FieldID>,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VarDef {
|
||||
pub name: String,
|
||||
pub parent: Option<FieldRef>,
|
||||
pub ty: Type,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
pub struct VarOffset {
|
||||
pub id: VarID,
|
||||
pub offset: Len,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
pub struct FieldRef {
|
||||
pub var: VarID,
|
||||
// this is technically redundant bc you can get it from the var...
|
||||
// but it makes things a lot easier, and you'd have to recheck the fields anyways
|
||||
pub struc: StructID,
|
||||
pub field: FieldID,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DataDef {
|
||||
pub ty: Type,
|
||||
pub origin: Origin,
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
pub type Origin = 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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StructDef {
|
||||
pub fn field(&self, id: FieldID) -> &StructField {
|
||||
&self.fields[id.0]
|
||||
}
|
||||
pub fn get_field(&self, name: &str) -> Option<&StructField> {
|
||||
self.field_map.get(name).map(|id| self.field(*id))
|
||||
}
|
||||
pub fn iter_fields(&self) -> impl Iterator<Item = (FieldID, &StructField)> {
|
||||
self.fields.iter().enumerate().map(|(i, f)| (FieldID(i), f))
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
|
||||
|
||||
use super::{IRUProgram, Type};
|
||||
use super::{Type, UProgram};
|
||||
|
||||
impl CompilerOutput {
|
||||
pub fn check_assign(&mut self, p: &IRUProgram, src: &Type, dest: &Type, span: FileSpan) {
|
||||
pub fn check_assign(&mut self, p: &UProgram, src: &Type, dest: &Type, span: FileSpan) -> bool {
|
||||
// TODO: spans
|
||||
if src != dest {
|
||||
self.err(CompilerMsg {
|
||||
@@ -14,6 +14,9 @@ impl CompilerOutput {
|
||||
),
|
||||
spans: vec![span],
|
||||
});
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{common::FileSpan, ir::VarID};
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::IRUInstruction;
|
||||
use super::UInstruction;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VarInst {
|
||||
@@ -9,8 +9,8 @@ pub struct VarInst {
|
||||
pub span: FileSpan,
|
||||
}
|
||||
|
||||
pub struct IRUInstrInst {
|
||||
pub i: IRUInstruction,
|
||||
pub struct UInstrInst {
|
||||
pub i: UInstruction,
|
||||
pub span: FileSpan,
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ impl Debug for VarInst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for IRUInstrInst {
|
||||
impl Debug for UInstrInst {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.i)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
use std::{collections::HashMap, fmt::Write};
|
||||
|
||||
use super::{
|
||||
arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, Type, VarID,
|
||||
};
|
||||
use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, UInstrInst, UFunc};
|
||||
use crate::{compiler::arch::riscv::Reg, ir::FieldID, util::Padder};
|
||||
|
||||
pub struct IRUFunction {
|
||||
pub name: String,
|
||||
pub args: Vec<VarID>,
|
||||
pub ret: Type,
|
||||
pub instructions: Vec<IRUInstrInst>,
|
||||
}
|
||||
|
||||
pub enum IRUInstruction {
|
||||
pub enum UInstruction {
|
||||
Mv {
|
||||
dest: VarInst,
|
||||
src: VarInst,
|
||||
@@ -51,10 +42,10 @@ pub enum IRUInstruction {
|
||||
},
|
||||
If {
|
||||
cond: VarInst,
|
||||
body: Vec<IRUInstrInst>,
|
||||
body: Vec<UInstrInst>,
|
||||
},
|
||||
Loop {
|
||||
body: Vec<IRUInstrInst>,
|
||||
body: Vec<UInstrInst>,
|
||||
},
|
||||
Break,
|
||||
Continue,
|
||||
@@ -73,7 +64,7 @@ pub enum AsmBlockArgType {
|
||||
Out,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for IRUInstruction {
|
||||
impl std::fmt::Debug for UInstruction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Mv { dest, src } => write!(f, "{dest:?} <- {src:?}")?,
|
||||
@@ -86,9 +77,7 @@ impl std::fmt::Debug for IRUInstruction {
|
||||
f: func,
|
||||
args,
|
||||
} => write!(f, "{dest:?} <- {func:?}({args:?})")?,
|
||||
Self::AsmBlock { args, instructions } => {
|
||||
write!(f, "asm {args:?} {instructions:#?}")?
|
||||
}
|
||||
Self::AsmBlock { args, instructions } => write!(f, "asm {args:?} {instructions:#?}")?,
|
||||
Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish()?,
|
||||
Self::Construct { dest, fields } => write!(f, "{dest:?} <- {fields:?}")?,
|
||||
Self::If { cond, body } => {
|
||||
@@ -126,9 +115,9 @@ impl std::fmt::Debug for IRUInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for IRUFunction {
|
||||
impl std::fmt::Debug for UFunc {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}{:?}", &self.name, self.args)?;
|
||||
write!(f, "{:?}", self.args)?;
|
||||
if !self.instructions.is_empty() {
|
||||
f.write_str("{\n ")?;
|
||||
let mut padder = Padder::new(f);
|
||||
160
src/ir/upper/kind.rs
Normal file
160
src/ir/upper/kind.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
use crate::{
|
||||
common::FileSpan,
|
||||
ir::{Len, Named, ID},
|
||||
};
|
||||
|
||||
use super::{Type, UInstrInst, UProgram};
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
pub const NAMED_KINDS: usize = 4;
|
||||
|
||||
pub struct UFunc {
|
||||
pub args: Vec<VarID>,
|
||||
pub ret: Type,
|
||||
pub origin: Origin,
|
||||
pub instructions: Vec<UInstrInst>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StructField {
|
||||
pub name: String,
|
||||
pub ty: Type,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UStruct {
|
||||
pub fields: Vec<StructField>,
|
||||
pub field_map: HashMap<String, FieldID>,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UVar {
|
||||
pub parent: Option<FieldRef>,
|
||||
pub ty: Type,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
pub struct VarOffset {
|
||||
pub id: VarID,
|
||||
pub offset: Len,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
pub struct FieldRef {
|
||||
pub var: VarID,
|
||||
// this is technically redundant bc you can get it from the var...
|
||||
// but it makes things a lot easier, and you'd have to recheck the fields anyways
|
||||
pub struc: StructID,
|
||||
pub field: FieldID,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UData {
|
||||
pub ty: Type,
|
||||
pub origin: Origin,
|
||||
pub content: Vec<u8>,
|
||||
}
|
||||
|
||||
pub type Origin = FileSpan;
|
||||
|
||||
impl UFunc {
|
||||
pub fn ty(&self, program: &UProgram) -> Type {
|
||||
Type::Fn {
|
||||
args: self
|
||||
.args
|
||||
.iter()
|
||||
.map(|a| program.expect(*a).ty.clone())
|
||||
.collect(),
|
||||
ret: Box::new(self.ret.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UStruct {
|
||||
pub fn field(&self, id: FieldID) -> &StructField {
|
||||
&self.fields[id.0]
|
||||
}
|
||||
pub fn get_field(&self, name: &str) -> Option<&StructField> {
|
||||
self.field_map.get(name).map(|id| self.field(*id))
|
||||
}
|
||||
pub fn iter_fields(&self) -> impl Iterator<Item = (FieldID, &StructField)> {
|
||||
self.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, f)| (FieldID::new(i), f))
|
||||
}
|
||||
}
|
||||
|
||||
pub type StructID = ID<UStruct>;
|
||||
pub type VarID = ID<UVar>;
|
||||
pub type DataID = ID<UData>;
|
||||
pub type FieldID = ID<StructField>;
|
||||
pub type FnID = ID<UFunc>;
|
||||
|
||||
impl Kind for UFunc {
|
||||
const INDEX: usize = 0;
|
||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||
&mut program.fns
|
||||
}
|
||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||
&program.fns
|
||||
}
|
||||
}
|
||||
impl Named for UFunc {
|
||||
const NAME: &str = "func";
|
||||
}
|
||||
|
||||
impl Kind for UVar {
|
||||
const INDEX: usize = 1;
|
||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||
&mut program.vars
|
||||
}
|
||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||
&program.vars
|
||||
}
|
||||
}
|
||||
impl Named for UVar {
|
||||
const NAME: &str = "var";
|
||||
}
|
||||
|
||||
impl Kind for UStruct {
|
||||
const INDEX: usize = 2;
|
||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||
&mut program.structs
|
||||
}
|
||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||
&program.structs
|
||||
}
|
||||
}
|
||||
impl Named for UStruct {
|
||||
const NAME: &str = "struct";
|
||||
}
|
||||
|
||||
impl Kind for UData {
|
||||
const INDEX: usize = 3;
|
||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||
&mut program.data
|
||||
}
|
||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||
&program.data
|
||||
}
|
||||
}
|
||||
impl Named for UData {
|
||||
const NAME: &str = "data";
|
||||
}
|
||||
|
||||
impl Named for StructField {
|
||||
const NAME: &str = "field";
|
||||
}
|
||||
|
||||
pub trait Kind {
|
||||
const INDEX: usize;
|
||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>>
|
||||
where
|
||||
Self: Sized;
|
||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
mod def;
|
||||
mod func;
|
||||
mod kind;
|
||||
mod instr;
|
||||
mod ty;
|
||||
mod program;
|
||||
mod validate;
|
||||
@@ -7,8 +7,8 @@ mod error;
|
||||
mod inst;
|
||||
|
||||
use super::*;
|
||||
pub use def::*;
|
||||
pub use func::*;
|
||||
pub use kind::*;
|
||||
pub use instr::*;
|
||||
pub use ty::*;
|
||||
pub use program::*;
|
||||
pub use inst::*;
|
||||
|
||||
@@ -2,40 +2,67 @@ use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
use super::{inst::VarInst, *};
|
||||
|
||||
pub struct IRUProgram {
|
||||
pub fn_defs: Vec<FnDef>,
|
||||
pub var_defs: Vec<VarDef>,
|
||||
pub struct_defs: Vec<StructDef>,
|
||||
pub data_defs: Vec<DataDef>,
|
||||
pub fns: Vec<Option<IRUFunction>>,
|
||||
pub data: Vec<Vec<u8>>,
|
||||
pub struct UProgram {
|
||||
pub fns: Vec<Option<UFunc>>,
|
||||
pub vars: Vec<Option<UVar>>,
|
||||
pub structs: Vec<Option<UStruct>>,
|
||||
pub data: Vec<Option<UData>>,
|
||||
pub start: Option<FnID>,
|
||||
pub names: NameMap,
|
||||
// todo: these feel weird raw
|
||||
pub fn_map: HashMap<VarID, FnID>,
|
||||
pub inv_fn_map: Vec<VarID>,
|
||||
pub temp: usize,
|
||||
pub stack: Vec<HashMap<String, Idents>>,
|
||||
pub name_stack: Vec<HashMap<String, Idents>>,
|
||||
}
|
||||
|
||||
impl IRUProgram {
|
||||
pub struct NameMap {
|
||||
names: [Vec<String>; NAMED_KINDS],
|
||||
inv_names: [HashMap<String, usize>; NAMED_KINDS],
|
||||
}
|
||||
|
||||
impl NameMap {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
names: core::array::from_fn(|_| Vec::new()),
|
||||
inv_names: core::array::from_fn(|_| HashMap::new()),
|
||||
}
|
||||
}
|
||||
pub fn get<K: Kind>(&self, id: ID<K>) -> &str {
|
||||
&self.names[K::INDEX][id.0]
|
||||
}
|
||||
pub fn lookup<K: Kind>(&self, name: &str) -> Option<ID<K>> {
|
||||
Some(ID::new(*self.inv_names[K::INDEX].get(name)?))
|
||||
}
|
||||
pub fn push<K: Kind>(&mut self, name: String) {
|
||||
self.inv_names[K::INDEX].insert(name.clone(), self.names[K::INDEX].len());
|
||||
self.names[K::INDEX].push(name);
|
||||
}
|
||||
}
|
||||
|
||||
impl UProgram {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
fn_defs: Vec::new(),
|
||||
var_defs: Vec::new(),
|
||||
struct_defs: Vec::new(),
|
||||
data_defs: Vec::new(),
|
||||
data: Vec::new(),
|
||||
fn_map: HashMap::new(),
|
||||
fns: Vec::new(),
|
||||
vars: Vec::new(),
|
||||
structs: Vec::new(),
|
||||
data: Vec::new(),
|
||||
start: None,
|
||||
names: NameMap::new(),
|
||||
fn_map: HashMap::new(),
|
||||
inv_fn_map: Vec::new(),
|
||||
temp: 0,
|
||||
stack: vec![HashMap::new()],
|
||||
name_stack: vec![HashMap::new()],
|
||||
}
|
||||
}
|
||||
pub fn push(&mut self) {
|
||||
self.stack.push(HashMap::new());
|
||||
self.name_stack.push(HashMap::new());
|
||||
}
|
||||
pub fn pop(&mut self) {
|
||||
self.stack.pop();
|
||||
self.name_stack.pop();
|
||||
}
|
||||
pub fn get(&self, name: &str) -> Option<Idents> {
|
||||
for map in self.stack.iter().rev() {
|
||||
pub fn get_idents(&self, name: &str) -> Option<Idents> {
|
||||
for map in self.name_stack.iter().rev() {
|
||||
let res = map.get(name);
|
||||
if res.is_some() {
|
||||
return res.cloned();
|
||||
@@ -43,43 +70,29 @@ impl IRUProgram {
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn get_var(&self, id: VarID) -> &VarDef {
|
||||
&self.var_defs[id.0]
|
||||
pub fn get<K: Kind>(&self, id: ID<K>) -> Option<&K> {
|
||||
K::from_program(self)[id.0].as_ref()
|
||||
}
|
||||
pub fn get_fn(&self, id: FnID) -> &FnDef {
|
||||
&self.fn_defs[id.0]
|
||||
pub fn get_mut<K: Kind>(&mut self, id: ID<K>) -> Option<&mut K> {
|
||||
K::from_program_mut(self)[id.0].as_mut()
|
||||
}
|
||||
pub fn get_data(&self, id: DataID) -> &DataDef {
|
||||
&self.data_defs[id.0]
|
||||
pub fn expect<K: Kind + Named>(&self, id: ID<K>) -> &K {
|
||||
self.get(id)
|
||||
.unwrap_or_else(|| panic!("{id:?} not defined yet!"))
|
||||
}
|
||||
pub fn get_fn_var(&self, id: VarID) -> Option<&FnDef> {
|
||||
Some(&self.fn_defs[self.fn_map.get(&id)?.0])
|
||||
pub fn expect_mut<K: Kind + Named>(&mut self, id: ID<K>) -> &mut K {
|
||||
self.get_mut(id)
|
||||
.unwrap_or_else(|| panic!("{id:?} not defined yet!"))
|
||||
}
|
||||
pub fn get_struct(&self, id: StructID) -> &StructDef {
|
||||
&self.struct_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 get_fn_var(&self, id: VarID) -> Option<&UFunc> {
|
||||
self.fns[self.fn_map.get(&id)?.0].as_ref()
|
||||
}
|
||||
pub fn size_of_type(&self, ty: &Type) -> Option<Size> {
|
||||
// TODO: target matters
|
||||
Some(match ty {
|
||||
Type::Bits(b) => *b,
|
||||
Type::Struct { id, args } => self.struct_defs[id.0]
|
||||
Type::Struct { id, args } => self.structs[id.0]
|
||||
.as_ref()?
|
||||
.fields
|
||||
.iter()
|
||||
.try_fold(0, |sum, f| Some(sum + self.size_of_type(&f.ty)?))?,
|
||||
@@ -92,9 +105,8 @@ impl IRUProgram {
|
||||
Type::Unit => 0,
|
||||
})
|
||||
}
|
||||
pub fn struct_layout() {}
|
||||
pub fn size_of_var(&self, var: VarID) -> Option<Size> {
|
||||
self.size_of_type(&self.var_defs[var.0].ty)
|
||||
self.size_of_type(&self.get(var)?.ty)
|
||||
}
|
||||
pub fn temp_subvar(&mut self, origin: Origin, ty: Type, parent: FieldRef) -> VarInst {
|
||||
self.temp_var_inner(origin, ty, Some(parent))
|
||||
@@ -104,12 +116,10 @@ impl IRUProgram {
|
||||
}
|
||||
|
||||
fn temp_var_inner(&mut self, origin: Origin, ty: Type, parent: Option<FieldRef>) -> VarInst {
|
||||
let v = self.def_var(VarDef {
|
||||
name: format!("temp{}", self.temp),
|
||||
parent,
|
||||
origin,
|
||||
ty,
|
||||
});
|
||||
let v = self.def(
|
||||
format!("temp{}", self.temp),
|
||||
Some(UVar { parent, origin, ty }),
|
||||
);
|
||||
self.temp += 1;
|
||||
VarInst {
|
||||
id: v,
|
||||
@@ -117,44 +127,29 @@ impl IRUProgram {
|
||||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
parent: None,
|
||||
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);
|
||||
pub fn write<K: Kind>(&mut self, id: ID<K>, k: K) {
|
||||
K::from_program_mut(self)[id.0] = Some(k);
|
||||
}
|
||||
|
||||
pub fn def<K: Kind>(&mut self, name: String, k: Option<K>) -> ID<K> {
|
||||
self.names.push::<K>(name);
|
||||
let vec = K::from_program_mut(self);
|
||||
let id = ID::new(vec.len());
|
||||
vec.push(k);
|
||||
id
|
||||
}
|
||||
pub fn def_struct(&mut self, def: StructDef) -> StructID {
|
||||
let i = self.struct_defs.len();
|
||||
let id = StructID(i);
|
||||
self.insert(&def.name, Ident::Type(id));
|
||||
self.struct_defs.push(def);
|
||||
|
||||
pub fn def_searchable<K: Kind>(&mut self, name: String, k: Option<K>) -> ID<K> {
|
||||
let id = self.def(name.clone(), k);
|
||||
self.name_on_stack(id, name);
|
||||
id
|
||||
}
|
||||
pub fn def_data(&mut self, def: DataDef, bytes: Vec<u8>) -> DataID {
|
||||
let i = self.data.len();
|
||||
self.data_defs.push(def);
|
||||
self.data.push(bytes);
|
||||
DataID(i)
|
||||
}
|
||||
|
||||
pub fn type_name(&self, ty: &Type) -> String {
|
||||
let mut str = String::new();
|
||||
match ty {
|
||||
Type::Struct { id: base, args } => {
|
||||
str += &self.get_struct(*base).name;
|
||||
str += self.names.get(*base);
|
||||
if let Some(arg) = args.first() {
|
||||
str = str + "<" + &self.type_name(arg);
|
||||
}
|
||||
@@ -188,81 +183,82 @@ impl IRUProgram {
|
||||
}
|
||||
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);
|
||||
fn name_on_stack<K: Kind>(&mut self, id: ID<K>, name: String) {
|
||||
let idx = self.name_stack.len() - 1;
|
||||
let last = &mut self.name_stack[idx];
|
||||
if let Some(l) = last.get_mut(&name) {
|
||||
l.insert(id.into());
|
||||
} else {
|
||||
last.insert(name.to_string(), Idents::new(id));
|
||||
last.insert(name, Idents::new(id.into()));
|
||||
}
|
||||
}
|
||||
pub fn write_fn(&mut self, id: FnID, f: IRUFunction) {
|
||||
self.fns[id.0] = Some(f);
|
||||
}
|
||||
pub fn iter_vars(&self) -> impl Iterator<Item = (VarID, &VarDef)> {
|
||||
self.var_defs.iter().enumerate().map(|(i, v)| (VarID(i), v))
|
||||
}
|
||||
pub fn iter_fns(&self) -> impl Iterator<Item = (FnID, &IRUFunction)> {
|
||||
self.fns
|
||||
.iter()
|
||||
.enumerate()
|
||||
.flat_map(|(i, f)| Some((FnID(i), f.as_ref()?)))
|
||||
}
|
||||
pub fn var_offset(&self, var: VarID) -> Option<VarOffset> {
|
||||
let mut current = VarOffset { id: var, offset: 0 };
|
||||
while let Some(parent) = self.var_defs[current.id.0].parent {
|
||||
while let Some(parent) = self.get(current.id)?.parent {
|
||||
current.id = parent.var;
|
||||
current.offset += self.field_offset(parent.struc, parent.field)?;
|
||||
}
|
||||
Some(current)
|
||||
}
|
||||
pub fn field_offset(&self, struct_id: StructID, field: FieldID) -> Option<Len> {
|
||||
let struc = self.get_struct(struct_id);
|
||||
let struc = self.get(struct_id)?;
|
||||
let mut offset = 0;
|
||||
for i in 0..field.0 {
|
||||
offset += self.size_of_type(&struc.fields[i].ty)?;
|
||||
}
|
||||
Some(offset)
|
||||
}
|
||||
pub fn iter_vars(&self) -> impl Iterator<Item = (VarID, &UVar)> {
|
||||
self.vars
|
||||
.iter()
|
||||
.flatten()
|
||||
.enumerate()
|
||||
.map(|(i, x)| (ID::new(i), x))
|
||||
}
|
||||
pub fn iter_fns(&self) -> impl Iterator<Item = (FnID, &UFunc)> {
|
||||
self.fns
|
||||
.iter()
|
||||
.flatten()
|
||||
.enumerate()
|
||||
.map(|(i, x)| (ID::new(i), x))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Ident {
|
||||
Var(VarID),
|
||||
Fn(FnID),
|
||||
Type(StructID),
|
||||
pub struct Ident {
|
||||
id: usize,
|
||||
kind: usize,
|
||||
}
|
||||
|
||||
impl<K: Kind> From<ID<K>> for Ident {
|
||||
fn from(id: ID<K>) -> Self {
|
||||
Self {
|
||||
id: id.0,
|
||||
kind: K::INDEX,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Idents {
|
||||
pub latest: Ident,
|
||||
pub var: Option<VarID>,
|
||||
pub func: Option<FnID>,
|
||||
pub struc: Option<StructID>,
|
||||
pub kinds: [Option<usize>; NAMED_KINDS],
|
||||
}
|
||||
|
||||
impl Idents {
|
||||
fn new(latest: Ident) -> Self {
|
||||
let mut s = Self {
|
||||
latest,
|
||||
var: None,
|
||||
func: None,
|
||||
struc: None,
|
||||
kinds: [None; NAMED_KINDS],
|
||||
};
|
||||
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.struc = Some(t),
|
||||
}
|
||||
self.kinds[i.kind] = Some(i.id);
|
||||
}
|
||||
pub fn get<K: Kind>(&self) -> Option<ID<K>> {
|
||||
self.kinds[K::INDEX].map(|i| i.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use super::{IRUProgram, Len, StructID};
|
||||
use crate::common::CompilerOutput;
|
||||
|
||||
use super::{Len, StructID, UInstruction, UProgram, UVar};
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Type {
|
||||
@@ -25,13 +27,121 @@ impl Type {
|
||||
}
|
||||
}
|
||||
|
||||
// should impl instead
|
||||
pub fn resolve_types(ns: &IRUProgram) {
|
||||
for (i, f) in ns.iter_fns() {
|
||||
for inst in &f.instructions {
|
||||
match &inst.i {
|
||||
_ => todo!(),
|
||||
impl UProgram {
|
||||
pub fn resolve_types(&mut self) {
|
||||
// I LOVE RUST
|
||||
let mut vars = self.vars.clone();
|
||||
for f in self.fns.iter().flatten() {
|
||||
for i in &f.instructions {
|
||||
self.resolve_instr_types(&mut vars, &i.i);
|
||||
}
|
||||
}
|
||||
self.vars = vars;
|
||||
}
|
||||
|
||||
pub fn resolve_instr_types(&self, vars: &mut Vec<Option<UVar>>, i: &UInstruction) {
|
||||
match &i {
|
||||
UInstruction::Call { dest, f, args } => {
|
||||
let ret = self.get_fn_var(f.id).expect("bruh").ret.clone();
|
||||
vars[dest.id.0].as_mut().expect("bruh").ty = ret;
|
||||
}
|
||||
UInstruction::Mv { dest, src } => {
|
||||
let dest_ty = &vars[dest.id.0].as_ref().unwrap().ty;
|
||||
let src_ty = &vars[src.id.0].as_ref().unwrap().ty;
|
||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||
vars[dest.id.0]
|
||||
.as_mut()
|
||||
.expect("PARTIAL BORROWING WOULD BE REALLY COOL")
|
||||
.ty = ty.clone();
|
||||
vars[src.id.0]
|
||||
.as_mut()
|
||||
.expect("PARTIAL BORROWING WOULD BE REALLY COOL")
|
||||
.ty = ty;
|
||||
}
|
||||
}
|
||||
UInstruction::Ref { dest, src } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::LoadData { dest, src } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::LoadSlice { dest, src } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::LoadFn { dest, src } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::AsmBlock { instructions, args } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::Ret { .. } => {}
|
||||
UInstruction::Construct { dest, fields } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::If { cond, body } => {
|
||||
for i in body {
|
||||
self.resolve_instr_types(vars, &i.i);
|
||||
}
|
||||
}
|
||||
UInstruction::Loop { body } => {
|
||||
for i in body {
|
||||
self.resolve_instr_types(vars, &i.i);
|
||||
}
|
||||
}
|
||||
UInstruction::Break => {}
|
||||
UInstruction::Continue => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_types(dest: &Type, src: &Type) -> Option<Type> {
|
||||
if dest == src {
|
||||
return None;
|
||||
}
|
||||
match (dest, src) {
|
||||
(Type::Error, x) | (x, Type::Error) => None,
|
||||
(Type::Infer, x) | (x, Type::Infer) => Some(x.clone()),
|
||||
(
|
||||
Type::Struct {
|
||||
id: dest_id,
|
||||
args: dest_args,
|
||||
},
|
||||
Type::Struct {
|
||||
id: src_id,
|
||||
args: src_args,
|
||||
},
|
||||
) => {
|
||||
if dest_id != src_id {
|
||||
return None;
|
||||
}
|
||||
None
|
||||
// TODO
|
||||
// let mut args = Vec::new();
|
||||
// for (darg, sarg) in dest_args.iter().zip(src_args) {
|
||||
// }
|
||||
// Some(Type::Struct { id: *dest_id, args })
|
||||
}
|
||||
(
|
||||
Type::Fn {
|
||||
args: dest_args,
|
||||
ret: dest_ret,
|
||||
},
|
||||
Type::Fn {
|
||||
args: src_args,
|
||||
ret: src_ret,
|
||||
},
|
||||
) => {
|
||||
// TODO
|
||||
None
|
||||
}
|
||||
(Type::Ref(dest), Type::Ref(src)) => Some(match_types(dest, src)?),
|
||||
(Type::Slice(dest), Type::Slice(src)) => Some(match_types(dest, src)?),
|
||||
(Type::Array(dest, dlen), Type::Array(src, slen)) => {
|
||||
if dlen != slen {
|
||||
return None;
|
||||
}
|
||||
match_types(dest, src)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
// TODO: move this into ir, not parser
|
||||
use super::{IRUInstrInst, IRUInstruction, IRUProgram, Type};
|
||||
use super::{Type, UInstrInst, UInstruction, UProgram};
|
||||
use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
|
||||
|
||||
impl IRUProgram {
|
||||
impl UProgram {
|
||||
pub fn validate(&self) -> CompilerOutput {
|
||||
let mut output = CompilerOutput::new();
|
||||
for (f, fd) in self.fns.iter().flatten().zip(&self.fn_defs) {
|
||||
self.validate_fn(
|
||||
&f.instructions,
|
||||
fd.origin,
|
||||
&fd.ret,
|
||||
&mut output,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
for f in self.fns.iter().flatten() {
|
||||
self.validate_fn(&f.instructions, f.origin, &f.ret, &mut output, true, false);
|
||||
}
|
||||
for (id, var) in self.iter_vars() {
|
||||
if var.ty == Type::Error {
|
||||
output.err(CompilerMsg {
|
||||
msg: format!("Var {:?} is error type!", id),
|
||||
spans: vec![var.origin],
|
||||
});
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
pub fn validate_fn(
|
||||
&self,
|
||||
instructions: &[IRUInstrInst],
|
||||
instructions: &[UInstrInst],
|
||||
origin: FileSpan,
|
||||
ret: &Type,
|
||||
output: &mut CompilerOutput,
|
||||
@@ -30,31 +31,31 @@ impl IRUProgram {
|
||||
let mut no_ret = true;
|
||||
for i in instructions {
|
||||
match &i.i {
|
||||
IRUInstruction::Mv { dest, src } => {
|
||||
let dest = self.get_var(dest.id);
|
||||
let src = self.get_var(src.id);
|
||||
UInstruction::Mv { dest, src } => {
|
||||
let dest = self.expect(dest.id);
|
||||
let src = self.expect(src.id);
|
||||
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
||||
}
|
||||
IRUInstruction::Ref { dest, src } => {
|
||||
UInstruction::Ref { dest, src } => {
|
||||
// TODO
|
||||
}
|
||||
IRUInstruction::LoadData { dest, src } => {
|
||||
let dest = self.get_var(dest.id);
|
||||
let src = self.get_data(*src);
|
||||
UInstruction::LoadData { dest, src } => {
|
||||
let dest = self.expect(dest.id);
|
||||
let src = self.expect(*src);
|
||||
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
||||
}
|
||||
IRUInstruction::LoadSlice { dest, src } => {
|
||||
let dest = self.get_var(dest.id);
|
||||
let src = self.get_data(*src);
|
||||
UInstruction::LoadSlice { dest, src } => {
|
||||
let dest = self.expect(dest.id);
|
||||
let src = self.expect(*src);
|
||||
let Type::Array(srcty, ..) = &src.ty else {
|
||||
todo!()
|
||||
};
|
||||
output.check_assign(self, &Type::Slice(srcty.clone()), &dest.ty, i.span);
|
||||
}
|
||||
IRUInstruction::LoadFn { dest, src } => todo!(),
|
||||
IRUInstruction::Call { dest, f, args } => {
|
||||
let destty = &self.get_var(dest.id).ty;
|
||||
let f = self.get_var(f.id);
|
||||
UInstruction::LoadFn { dest, src } => todo!(),
|
||||
UInstruction::Call { dest, f, args } => {
|
||||
let destty = &self.expect(dest.id).ty;
|
||||
let f = self.expect(f.id);
|
||||
let Type::Fn { args: argtys, ret } = &f.ty else {
|
||||
todo!()
|
||||
};
|
||||
@@ -65,21 +66,21 @@ impl IRUProgram {
|
||||
spans: vec![dest.span],
|
||||
});
|
||||
}
|
||||
for (argv, argt) in args.iter().zip(argtys) {
|
||||
let dest = self.get_var(argv.id);
|
||||
output.check_assign(self, argt, &dest.ty, argv.span);
|
||||
for (dst_ty, src) in argtys.iter().zip(args) {
|
||||
let src_var = self.expect(src.id);
|
||||
output.check_assign(self, &src_var.ty, dst_ty, src.span);
|
||||
}
|
||||
}
|
||||
IRUInstruction::AsmBlock { instructions, args } => {
|
||||
UInstruction::AsmBlock { instructions, args } => {
|
||||
// TODO
|
||||
}
|
||||
IRUInstruction::Ret { src } => {
|
||||
let srcty = &self.get_var(src.id).ty;
|
||||
UInstruction::Ret { src } => {
|
||||
let srcty = &self.expect(src.id).ty;
|
||||
output.check_assign(self, srcty, ret, src.span);
|
||||
no_ret = false;
|
||||
}
|
||||
IRUInstruction::Construct { dest, fields } => {
|
||||
let dest_def = self.get_var(dest.id);
|
||||
UInstruction::Construct { dest, fields } => {
|
||||
let dest_def = self.expect(dest.id);
|
||||
let tyid = match &dest_def.ty {
|
||||
Type::Struct { id, args } => *id,
|
||||
_ => {
|
||||
@@ -90,10 +91,10 @@ impl IRUProgram {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let def = self.get_struct(tyid);
|
||||
let def = self.expect(tyid);
|
||||
for (id, field) in def.iter_fields() {
|
||||
if let Some(var) = fields.get(&id) {
|
||||
let ety = &self.get_var(var.id).ty;
|
||||
let ety = &self.expect(var.id).ty;
|
||||
output.check_assign(self, &field.ty, ety, var.span);
|
||||
} else {
|
||||
output.err(CompilerMsg {
|
||||
@@ -103,15 +104,15 @@ impl IRUProgram {
|
||||
}
|
||||
}
|
||||
}
|
||||
IRUInstruction::If { cond, body } => {
|
||||
let cond = self.get_var(cond.id);
|
||||
UInstruction::If { cond, body } => {
|
||||
let cond = self.expect(cond.id);
|
||||
output.check_assign(self, &cond.ty, &Type::Bits(64), i.span);
|
||||
self.validate_fn(body, origin, ret, output, false, breakable);
|
||||
}
|
||||
IRUInstruction::Loop { body } => {
|
||||
UInstruction::Loop { body } => {
|
||||
self.validate_fn(body, origin, ret, output, false, true);
|
||||
}
|
||||
IRUInstruction::Break => {
|
||||
UInstruction::Break => {
|
||||
if !breakable {
|
||||
output.err(CompilerMsg {
|
||||
msg: "Can't break here (outside of loop)".to_string(),
|
||||
@@ -120,7 +121,7 @@ impl IRUProgram {
|
||||
}
|
||||
// TODO
|
||||
}
|
||||
IRUInstruction::Continue => {
|
||||
UInstruction::Continue => {
|
||||
if !breakable {
|
||||
output.err(CompilerMsg {
|
||||
msg: "Can't continue here (outside of loop)".to_string(),
|
||||
|
||||
Reference in New Issue
Block a user