structs r a lot more sane in code, can now actually assign & stuff
This commit is contained in:
13
src/ir/id.rs
13
src/ir/id.rs
@@ -1,14 +1,17 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub struct TypeID(pub usize);
|
||||
pub struct StructID(pub usize);
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub struct VarID(pub usize);
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub struct FnID(pub usize);
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub struct DataID(pub usize);
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub struct FieldID(pub usize);
|
||||
|
||||
// I had an idea for why these were different... now I don't
|
||||
pub type Size = u32;
|
||||
pub type Len = u32;
|
||||
|
||||
@@ -18,7 +21,7 @@ impl Debug for VarID {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for TypeID {
|
||||
impl Debug for StructID {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "ty{}", self.0)
|
||||
}
|
||||
@@ -35,3 +38,9 @@ impl Debug for DataID {
|
||||
write!(f, "data{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for FieldID {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "field{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use std::collections::HashMap;
|
||||
pub struct IRLFunction {
|
||||
pub instructions: Vec<IRLInstruction>,
|
||||
pub stack: HashMap<VarID, Size>,
|
||||
pub subvar_map: HashMap<VarID, VarOffset>,
|
||||
pub args: Vec<(VarID, Size)>,
|
||||
pub ret_size: Size,
|
||||
pub makes_call: bool,
|
||||
@@ -46,7 +47,7 @@ pub enum IRLInstruction {
|
||||
outputs: Vec<(Reg, VarID)>,
|
||||
},
|
||||
Ret {
|
||||
src: VarID,
|
||||
src: Option<VarID>,
|
||||
},
|
||||
// TODO I feel like this should be turned into control flow instructions, maybe...
|
||||
// not sure but LLVM has them so might be right play; seems optimal for optimization
|
||||
@@ -58,3 +59,11 @@ pub enum IRLInstruction {
|
||||
Mark(Symbol),
|
||||
}
|
||||
|
||||
impl IRLInstruction {
|
||||
pub fn is_ret(&self) -> bool {
|
||||
match self {
|
||||
Self::Ret { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::ir::{AsmBlockArgType, IRUFunction, IRUInstrInst, Size, SymbolSpace};
|
||||
use crate::ir::{AsmBlockArgType, IRUFunction, IRUInstrInst, Size, SymbolSpace, VarOffset};
|
||||
|
||||
use super::{
|
||||
IRLFunction, IRLInstruction, IRUInstruction, IRUProgram, Len, Symbol, SymbolSpaceBuilder, Type,
|
||||
@@ -31,6 +31,9 @@ impl IRLProgram {
|
||||
for i in &f.instructions {
|
||||
fbuilder.insert_instr(i);
|
||||
}
|
||||
if fbuilder.instrs.last().is_none_or(|i| !i.is_ret()) {
|
||||
fbuilder.instrs.push(IRLInstruction::Ret { src: None });
|
||||
}
|
||||
let res = fbuilder.finish(f);
|
||||
ssbuilder.write_fn(sym, res, Some(f.name.clone()));
|
||||
}
|
||||
@@ -48,8 +51,15 @@ pub struct IRLFunctionBuilder<'a> {
|
||||
builder: &'a mut SymbolSpaceBuilder,
|
||||
instrs: Vec<IRLInstruction>,
|
||||
stack: HashMap<VarID, Size>,
|
||||
subvar_map: HashMap<VarID, VarOffset>,
|
||||
makes_call: bool,
|
||||
outer: Option<Symbol>,
|
||||
loopp: Option<LoopCtx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct LoopCtx {
|
||||
top: Symbol,
|
||||
bot: Symbol,
|
||||
}
|
||||
|
||||
impl<'a> IRLFunctionBuilder<'a> {
|
||||
@@ -57,27 +67,36 @@ impl<'a> IRLFunctionBuilder<'a> {
|
||||
Self {
|
||||
instrs: Vec::new(),
|
||||
stack: HashMap::new(),
|
||||
subvar_map: HashMap::new(),
|
||||
makes_call: false,
|
||||
program,
|
||||
builder,
|
||||
outer: None,
|
||||
loopp: None,
|
||||
}
|
||||
}
|
||||
pub fn alloc_stack(&mut self, i: VarID) -> Option<()> {
|
||||
let size = *self
|
||||
if self.program.size_of_var(i).expect("unsized type") == 0 {
|
||||
return None;
|
||||
};
|
||||
self.map_subvar(i);
|
||||
let var = self.program.var_offset(i).expect("var offset");
|
||||
*self
|
||||
.stack
|
||||
.entry(i)
|
||||
.or_insert(self.program.size_of_var(i).expect("unsized type"));
|
||||
if size == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(())
|
||||
.entry(var.id)
|
||||
.or_insert(self.program.size_of_var(var.id).expect("unsized type"));
|
||||
Some(())
|
||||
}
|
||||
pub fn map_subvar(&mut self, i: VarID) {
|
||||
let off = self.program.var_offset(i).expect("var offset");
|
||||
if off.id != i {
|
||||
self.subvar_map.insert(i, off);
|
||||
}
|
||||
}
|
||||
pub fn insert_instr(&mut self, i: &IRUInstrInst) -> Option<Option<String>> {
|
||||
match &i.i {
|
||||
IRUInstruction::Mv { dest, src } => {
|
||||
self.alloc_stack(dest.id)?;
|
||||
self.map_subvar(src.id);
|
||||
self.instrs.push(IRLInstruction::Mv {
|
||||
dest: dest.id,
|
||||
dest_offset: 0,
|
||||
@@ -87,6 +106,7 @@ impl<'a> IRLFunctionBuilder<'a> {
|
||||
}
|
||||
IRUInstruction::Ref { dest, src } => {
|
||||
self.alloc_stack(dest.id)?;
|
||||
self.map_subvar(src.id);
|
||||
self.instrs.push(IRLInstruction::Ref {
|
||||
dest: dest.id,
|
||||
src: src.id,
|
||||
@@ -151,21 +171,28 @@ impl<'a> IRLFunctionBuilder<'a> {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.instrs.push(IRLInstruction::Call {
|
||||
let call = IRLInstruction::Call {
|
||||
dest,
|
||||
f: sym,
|
||||
args: args
|
||||
.iter()
|
||||
.map(|a| (a.id, self.program.size_of_var(a.id).expect("unsized type")))
|
||||
.map(|a| {
|
||||
self.map_subvar(a.id);
|
||||
(a.id, self.program.size_of_var(a.id).expect("unsized type"))
|
||||
})
|
||||
.collect(),
|
||||
});
|
||||
};
|
||||
self.instrs.push(call);
|
||||
}
|
||||
IRUInstruction::AsmBlock { instructions, args } => {
|
||||
let mut inputs = Vec::new();
|
||||
let mut outputs = Vec::new();
|
||||
for a in args {
|
||||
match a.ty {
|
||||
AsmBlockArgType::In => inputs.push((a.reg, a.var.id)),
|
||||
AsmBlockArgType::In => {
|
||||
self.map_subvar(a.var.id);
|
||||
inputs.push((a.reg, a.var.id))
|
||||
}
|
||||
AsmBlockArgType::Out => {
|
||||
self.alloc_stack(a.var.id)?;
|
||||
outputs.push((a.reg, a.var.id));
|
||||
@@ -178,50 +205,37 @@ impl<'a> IRLFunctionBuilder<'a> {
|
||||
outputs,
|
||||
})
|
||||
}
|
||||
IRUInstruction::Ret { src } => self.instrs.push(IRLInstruction::Ret { src: src.id }),
|
||||
IRUInstruction::Ret { src } => {
|
||||
self.map_subvar(src.id);
|
||||
self.instrs.push(IRLInstruction::Ret {
|
||||
src: if self.program.size_of_var(src.id).expect("unsized var") == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(src.id)
|
||||
},
|
||||
})
|
||||
}
|
||||
IRUInstruction::Construct { dest, fields } => {
|
||||
self.alloc_stack(dest.id)?;
|
||||
let ty = &self.program.get_var(dest.id).ty;
|
||||
let Type::Concrete(id) = ty else {
|
||||
let &Type::Struct { id, ref args } = ty else {
|
||||
return Some(Some(format!(
|
||||
"Failed to contruct type {}",
|
||||
self.program.type_name(ty)
|
||||
)));
|
||||
};
|
||||
let struc = self.program.get_struct(*id);
|
||||
for (name, var) in fields {
|
||||
for (&fid, var) in fields {
|
||||
self.map_subvar(var.id);
|
||||
self.instrs.push(IRLInstruction::Mv {
|
||||
dest: dest.id,
|
||||
src: var.id,
|
||||
dest_offset: struc.fields[name].offset,
|
||||
dest_offset: self.program.field_offset(id, fid).expect("field offset"),
|
||||
src_offset: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
IRUInstruction::Access { dest, src, field } => {
|
||||
self.alloc_stack(dest.id)?;
|
||||
let ty = &self.program.get_var(src.id).ty;
|
||||
let Type::Concrete(id) = ty else {
|
||||
return Some(Some(format!(
|
||||
"Failed to access field of struct {}",
|
||||
self.program.type_name(ty)
|
||||
)));
|
||||
};
|
||||
let struc = self.program.get_struct(*id);
|
||||
let Some(field) = struc.fields.get(field) else {
|
||||
return Some(Some(format!(
|
||||
"No field {field} in struct {}",
|
||||
self.program.type_name(ty)
|
||||
)));
|
||||
};
|
||||
self.instrs.push(IRLInstruction::Mv {
|
||||
dest: dest.id,
|
||||
src: src.id,
|
||||
src_offset: field.offset,
|
||||
dest_offset: 0,
|
||||
})
|
||||
}
|
||||
IRUInstruction::If { cond, body } => {
|
||||
self.map_subvar(cond.id);
|
||||
let sym = self.builder.reserve();
|
||||
self.instrs.push(IRLInstruction::Branch {
|
||||
to: *sym,
|
||||
@@ -235,19 +249,27 @@ impl<'a> IRLFunctionBuilder<'a> {
|
||||
IRUInstruction::Loop { body } => {
|
||||
let top = self.builder.reserve();
|
||||
let bot = self.builder.reserve();
|
||||
let old = self.outer;
|
||||
self.outer = Some(*bot);
|
||||
let old = self.loopp;
|
||||
self.loopp = Some(LoopCtx {
|
||||
bot: *bot,
|
||||
top: *top,
|
||||
});
|
||||
self.instrs.push(IRLInstruction::Mark(*top));
|
||||
for i in body {
|
||||
self.insert_instr(i);
|
||||
}
|
||||
self.instrs.push(IRLInstruction::Jump(*top));
|
||||
self.instrs.push(IRLInstruction::Mark(*bot));
|
||||
self.outer = old;
|
||||
self.loopp = old;
|
||||
}
|
||||
IRUInstruction::Break => {
|
||||
self.instrs.push(IRLInstruction::Jump(
|
||||
self.outer.expect("Tried to break outside of loop"),
|
||||
self.loopp.expect("Tried to break outside of loop").bot,
|
||||
));
|
||||
}
|
||||
IRUInstruction::Continue => {
|
||||
self.instrs.push(IRLInstruction::Jump(
|
||||
self.loopp.expect("Tried to break outside of loop").top,
|
||||
));
|
||||
}
|
||||
};
|
||||
@@ -265,6 +287,7 @@ impl<'a> IRLFunctionBuilder<'a> {
|
||||
.collect(),
|
||||
ret_size: self.program.size_of_type(&f.ret).expect("unsized type"),
|
||||
stack: self.stack,
|
||||
subvar_map: self.subvar_map,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::{common::FileSpan, ir::{Len, Size}};
|
||||
use crate::{
|
||||
common::FileSpan,
|
||||
ir::{FieldID, Len, StructID, VarID},
|
||||
};
|
||||
|
||||
use super::Type;
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
@@ -13,25 +16,41 @@ pub struct FnDef {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StructField {
|
||||
pub name: String,
|
||||
pub ty: Type,
|
||||
pub offset: Len,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StructDef {
|
||||
pub name: String,
|
||||
pub fields: HashMap<String, StructField>,
|
||||
pub size: Size,
|
||||
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,
|
||||
@@ -49,3 +68,15 @@ impl FnDef {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::{collections::HashMap, fmt::Write};
|
||||
use super::{
|
||||
arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, Type, VarID,
|
||||
};
|
||||
use crate::{compiler::arch::riscv::Reg, util::Padder};
|
||||
use crate::{compiler::arch::riscv::Reg, ir::FieldID, util::Padder};
|
||||
|
||||
pub struct IRUFunction {
|
||||
pub name: String,
|
||||
@@ -33,11 +33,6 @@ pub enum IRUInstruction {
|
||||
dest: VarInst,
|
||||
src: FnID,
|
||||
},
|
||||
Access {
|
||||
dest: VarInst,
|
||||
src: VarInst,
|
||||
field: String,
|
||||
},
|
||||
Call {
|
||||
dest: VarInst,
|
||||
f: VarInst,
|
||||
@@ -52,7 +47,7 @@ pub enum IRUInstruction {
|
||||
},
|
||||
Construct {
|
||||
dest: VarInst,
|
||||
fields: HashMap<String, VarInst>,
|
||||
fields: HashMap<FieldID, VarInst>,
|
||||
},
|
||||
If {
|
||||
cond: VarInst,
|
||||
@@ -62,6 +57,7 @@ pub enum IRUInstruction {
|
||||
body: Vec<IRUInstrInst>,
|
||||
},
|
||||
Break,
|
||||
Continue,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -95,7 +91,6 @@ impl std::fmt::Debug for IRUInstruction {
|
||||
}
|
||||
Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish()?,
|
||||
Self::Construct { dest, fields } => write!(f, "{dest:?} <- {fields:?}")?,
|
||||
Self::Access { dest, src, field } => write!(f, "{dest:?} <- {src:?}.{field}")?,
|
||||
Self::If { cond, body } => {
|
||||
write!(f, "if {cond:?}:")?;
|
||||
if !body.is_empty() {
|
||||
@@ -125,6 +120,7 @@ impl std::fmt::Debug for IRUInstruction {
|
||||
}
|
||||
}
|
||||
Self::Break => write!(f, "break")?,
|
||||
Self::Continue => write!(f, "continue")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
use crate::common::FileSpan;
|
||||
|
||||
use super::{inst::VarInst, *};
|
||||
|
||||
pub struct IRUProgram {
|
||||
pub fn_defs: Vec<FnDef>,
|
||||
pub var_defs: Vec<VarDef>,
|
||||
pub type_defs: Vec<StructDef>,
|
||||
pub struct_defs: Vec<StructDef>,
|
||||
pub data_defs: Vec<DataDef>,
|
||||
pub fns: Vec<Option<IRUFunction>>,
|
||||
pub data: Vec<Vec<u8>>,
|
||||
@@ -21,7 +19,7 @@ impl IRUProgram {
|
||||
Self {
|
||||
fn_defs: Vec::new(),
|
||||
var_defs: Vec::new(),
|
||||
type_defs: Vec::new(),
|
||||
struct_defs: Vec::new(),
|
||||
data_defs: Vec::new(),
|
||||
data: Vec::new(),
|
||||
fn_map: HashMap::new(),
|
||||
@@ -57,8 +55,8 @@ impl IRUProgram {
|
||||
pub fn get_fn_var(&self, id: VarID) -> Option<&FnDef> {
|
||||
Some(&self.fn_defs[self.fn_map.get(&id)?.0])
|
||||
}
|
||||
pub fn get_struct(&self, id: TypeID) -> &StructDef {
|
||||
&self.type_defs[id.0]
|
||||
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));
|
||||
@@ -80,9 +78,11 @@ impl IRUProgram {
|
||||
pub fn size_of_type(&self, ty: &Type) -> Option<Size> {
|
||||
// TODO: target matters
|
||||
Some(match ty {
|
||||
Type::Concrete(id) => self.type_defs[id.0].size,
|
||||
Type::Bits(b) => *b,
|
||||
Type::Generic { base, args } => todo!(),
|
||||
Type::Struct { id, args } => self.struct_defs[id.0]
|
||||
.fields
|
||||
.iter()
|
||||
.try_fold(0, |sum, f| Some(sum + self.size_of_type(&f.ty)?))?,
|
||||
Type::Fn { args, ret } => todo!(),
|
||||
Type::Ref(_) => 64,
|
||||
Type::Array(ty, len) => self.size_of_type(ty)? * len,
|
||||
@@ -92,12 +92,21 @@ 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)
|
||||
}
|
||||
pub fn temp_subvar(&mut self, origin: Origin, ty: Type, parent: FieldRef) -> VarInst {
|
||||
self.temp_var_inner(origin, ty, Some(parent))
|
||||
}
|
||||
pub fn temp_var(&mut self, origin: Origin, ty: Type) -> VarInst {
|
||||
self.temp_var_inner(origin, ty, None)
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
@@ -107,11 +116,13 @@ impl IRUProgram {
|
||||
span: origin,
|
||||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
};
|
||||
@@ -126,11 +137,11 @@ impl IRUProgram {
|
||||
|
||||
id
|
||||
}
|
||||
pub fn def_type(&mut self, def: StructDef) -> TypeID {
|
||||
let i = self.type_defs.len();
|
||||
let id = TypeID(i);
|
||||
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.type_defs.push(def);
|
||||
self.struct_defs.push(def);
|
||||
id
|
||||
}
|
||||
pub fn def_data(&mut self, def: DataDef, bytes: Vec<u8>) -> DataID {
|
||||
@@ -142,10 +153,7 @@ impl IRUProgram {
|
||||
pub fn type_name(&self, ty: &Type) -> String {
|
||||
let mut str = String::new();
|
||||
match ty {
|
||||
Type::Concrete(t) => {
|
||||
str += &self.get_struct(*t).name;
|
||||
}
|
||||
Type::Generic { base, args } => {
|
||||
Type::Struct { id: base, args } => {
|
||||
str += &self.get_struct(*base).name;
|
||||
if let Some(arg) = args.first() {
|
||||
str = str + "<" + &self.type_name(arg);
|
||||
@@ -201,13 +209,29 @@ impl IRUProgram {
|
||||
.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 {
|
||||
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 mut offset = 0;
|
||||
for i in 0..field.0 {
|
||||
offset += self.size_of_type(&struc.fields[i].ty)?;
|
||||
}
|
||||
Some(offset)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Ident {
|
||||
Var(VarID),
|
||||
Fn(FnID),
|
||||
Type(TypeID),
|
||||
Type(StructID),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@@ -215,7 +239,7 @@ pub struct Idents {
|
||||
pub latest: Ident,
|
||||
pub var: Option<VarID>,
|
||||
pub func: Option<FnID>,
|
||||
pub ty: Option<TypeID>,
|
||||
pub struc: Option<StructID>,
|
||||
}
|
||||
|
||||
impl Idents {
|
||||
@@ -224,7 +248,7 @@ impl Idents {
|
||||
latest,
|
||||
var: None,
|
||||
func: None,
|
||||
ty: None,
|
||||
struc: None,
|
||||
};
|
||||
s.insert(latest);
|
||||
s
|
||||
@@ -238,7 +262,7 @@ impl Idents {
|
||||
Ident::Fn(f) => {
|
||||
self.func = Some(f);
|
||||
}
|
||||
Ident::Type(t) => self.ty = Some(t),
|
||||
Ident::Type(t) => self.struc = Some(t),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use super::{IRUProgram, Len, TypeID};
|
||||
use super::{IRUProgram, Len, StructID};
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Type {
|
||||
Concrete(TypeID),
|
||||
Bits(u32),
|
||||
Generic { base: TypeID, args: Vec<Type> },
|
||||
Struct { id: StructID, args: Vec<Type> },
|
||||
Fn { args: Vec<Type>, ret: Box<Type> },
|
||||
Ref(Box<Type>),
|
||||
Slice(Box<Type>),
|
||||
@@ -26,6 +25,7 @@ impl Type {
|
||||
}
|
||||
}
|
||||
|
||||
// should impl instead
|
||||
pub fn resolve_types(ns: &IRUProgram) {
|
||||
for (i, f) in ns.iter_fns() {
|
||||
for inst in &f.instructions {
|
||||
|
||||
@@ -80,8 +80,8 @@ impl IRUProgram {
|
||||
}
|
||||
IRUInstruction::Construct { dest, fields } => {
|
||||
let dest_def = self.get_var(dest.id);
|
||||
let tyid = match dest_def.ty {
|
||||
Type::Concrete(id) => id,
|
||||
let tyid = match &dest_def.ty {
|
||||
Type::Struct { id, args } => *id,
|
||||
_ => {
|
||||
output.err(CompilerMsg {
|
||||
msg: "uhh type is not struct".to_string(),
|
||||
@@ -91,44 +91,17 @@ impl IRUProgram {
|
||||
}
|
||||
};
|
||||
let def = self.get_struct(tyid);
|
||||
for (name, field) in &def.fields {
|
||||
if let Some(var) = fields.get(name) {
|
||||
for (id, field) in def.iter_fields() {
|
||||
if let Some(var) = fields.get(&id) {
|
||||
let ety = &self.get_var(var.id).ty;
|
||||
output.check_assign(self, &field.ty, ety, var.span);
|
||||
} else {
|
||||
output.err(CompilerMsg {
|
||||
msg: format!("field '{name}' missing from struct"),
|
||||
msg: format!("field '{}' missing from struct", field.name),
|
||||
spans: vec![dest.span],
|
||||
});
|
||||
}
|
||||
}
|
||||
for name in fields.keys() {
|
||||
if !def.fields.contains_key(name) {
|
||||
output.err(CompilerMsg {
|
||||
msg: format!("field '{name}' not in struct"),
|
||||
spans: vec![dest.span],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
IRUInstruction::Access { dest, src, field } => {
|
||||
let dest_def = self.get_var(dest.id);
|
||||
let src_def = self.get_var(src.id);
|
||||
let tyid = match src_def.ty {
|
||||
Type::Concrete(id) => id,
|
||||
_ => {
|
||||
output.err(CompilerMsg {
|
||||
msg: "uhh type is not struct".to_string(),
|
||||
spans: vec![dest.span],
|
||||
});
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let def = self.get_struct(tyid);
|
||||
let field = def.fields.get(field).expect(
|
||||
"already validated during parse lowering... probably shouldn't be?",
|
||||
);
|
||||
output.check_assign(self, &field.ty, &dest_def.ty, i.span);
|
||||
}
|
||||
IRUInstruction::If { cond, body } => {
|
||||
let cond = self.get_var(cond.id);
|
||||
@@ -147,6 +120,15 @@ impl IRUProgram {
|
||||
}
|
||||
// TODO
|
||||
}
|
||||
IRUInstruction::Continue => {
|
||||
if !breakable {
|
||||
output.err(CompilerMsg {
|
||||
msg: "Can't continue here (outside of loop)".to_string(),
|
||||
spans: vec![i.span],
|
||||
});
|
||||
}
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
if needs_ret && no_ret && *ret != Type::Unit {
|
||||
|
||||
Reference in New Issue
Block a user