type checking !?!?
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
use super::{FileSpan, Type};
|
||||
use crate::common::FileSpan;
|
||||
|
||||
use super::Type;
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -23,6 +25,12 @@ pub struct VarDef {
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DataDef {
|
||||
pub ty: Type,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Origin {
|
||||
Builtin,
|
||||
|
||||
19
src/ir/upper/error.rs
Normal file
19
src/ir/upper/error.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
|
||||
|
||||
use super::{IRUProgram, Type};
|
||||
|
||||
impl CompilerOutput {
|
||||
pub fn check_assign(&mut self, p: &IRUProgram, src: &Type, dest: &Type, span: FileSpan) {
|
||||
// TODO: spans
|
||||
if src != dest {
|
||||
self.err(CompilerMsg {
|
||||
msg: format!(
|
||||
"Cannot assign type '{}' to '{}'",
|
||||
p.type_name(src),
|
||||
p.type_name(dest)
|
||||
),
|
||||
spans: vec![span],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +1,51 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
use super::{arch::riscv64::RV64Instruction, DataID, FnID, Len, VarID};
|
||||
use crate::{compiler::arch::riscv64::Reg, util::Padder};
|
||||
use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, VarID};
|
||||
use crate::{common::FileSpan, compiler::arch::riscv64::Reg, util::Padder};
|
||||
|
||||
pub struct IRUFunction {
|
||||
pub name: String,
|
||||
pub args: Vec<VarID>,
|
||||
pub instructions: Vec<IRUInstruction>,
|
||||
pub instructions: Vec<IRUInstrInst>,
|
||||
}
|
||||
|
||||
pub enum IRUInstruction {
|
||||
Mv {
|
||||
dest: VarID,
|
||||
src: VarID,
|
||||
dest: VarInst,
|
||||
src: VarInst,
|
||||
},
|
||||
Ref {
|
||||
dest: VarID,
|
||||
src: VarID,
|
||||
dest: VarInst,
|
||||
src: VarInst,
|
||||
},
|
||||
LoadData {
|
||||
dest: VarID,
|
||||
dest: VarInst,
|
||||
src: DataID,
|
||||
},
|
||||
LoadSlice {
|
||||
dest: VarID,
|
||||
dest: VarInst,
|
||||
src: DataID,
|
||||
len: Len,
|
||||
},
|
||||
LoadFn {
|
||||
dest: VarID,
|
||||
dest: VarInst,
|
||||
src: FnID,
|
||||
},
|
||||
Call {
|
||||
dest: VarID,
|
||||
f: VarID,
|
||||
args: Vec<VarID>,
|
||||
dest: VarInst,
|
||||
f: VarInst,
|
||||
args: Vec<VarInst>,
|
||||
},
|
||||
AsmBlock {
|
||||
instructions: Vec<RV64Instruction>,
|
||||
args: Vec<(Reg, VarID)>,
|
||||
args: Vec<(Reg, VarInst)>,
|
||||
},
|
||||
Ret {
|
||||
src: VarID,
|
||||
src: VarInst,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct IRInstructions {
|
||||
vec: Vec<IRUInstruction>,
|
||||
vec: Vec<IRUInstrInst>,
|
||||
}
|
||||
|
||||
impl IRUFunction {
|
||||
@@ -63,8 +62,8 @@ impl IRInstructions {
|
||||
pub fn new() -> Self {
|
||||
Self { vec: Vec::new() }
|
||||
}
|
||||
pub fn push(&mut self, i: IRUInstruction) {
|
||||
self.vec.push(i);
|
||||
pub fn push(&mut self, i: IRUInstruction, span: FileSpan) {
|
||||
self.vec.push(IRUInstrInst { i, span });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +74,7 @@ impl std::fmt::Debug for IRUInstruction {
|
||||
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::LoadSlice { dest, src, len } => write!(f, "{dest:?} <- &[{src:?}; {len}]"),
|
||||
Self::LoadSlice { dest, src } => write!(f, "{dest:?} <- &[{src:?}]"),
|
||||
Self::Call {
|
||||
dest,
|
||||
f: func,
|
||||
|
||||
27
src/ir/upper/inst.rs
Normal file
27
src/ir/upper/inst.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use crate::{common::FileSpan, ir::VarID};
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::IRUInstruction;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VarInst {
|
||||
pub id: VarID,
|
||||
pub span: FileSpan,
|
||||
}
|
||||
|
||||
pub struct IRUInstrInst {
|
||||
pub i: IRUInstruction,
|
||||
pub span: FileSpan,
|
||||
}
|
||||
|
||||
impl Debug for VarInst {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for IRUInstrInst {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.i)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
mod def;
|
||||
mod func;
|
||||
mod ty;
|
||||
mod namespace;
|
||||
mod program;
|
||||
mod validate;
|
||||
mod error;
|
||||
mod inst;
|
||||
|
||||
use super::*;
|
||||
pub use def::*;
|
||||
pub use func::*;
|
||||
pub use ty::*;
|
||||
pub use namespace::*;
|
||||
pub use program::*;
|
||||
pub use inst::*;
|
||||
|
||||
@@ -4,12 +4,15 @@ use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use crate::common::FileSpan;
|
||||
|
||||
pub struct Namespace {
|
||||
use super::{inst::VarInst, *};
|
||||
|
||||
pub struct IRUProgram {
|
||||
pub fn_defs: Vec<FnDef>,
|
||||
pub var_defs: Vec<VarDef>,
|
||||
pub type_defs: Vec<TypeDef>,
|
||||
pub data_defs: Vec<DataDef>,
|
||||
pub fns: Vec<Option<IRUFunction>>,
|
||||
pub data: Vec<Vec<u8>>,
|
||||
pub fn_map: HashMap<VarID, FnID>,
|
||||
@@ -17,12 +20,13 @@ pub struct Namespace {
|
||||
pub stack: Vec<HashMap<String, Idents>>,
|
||||
}
|
||||
|
||||
impl Namespace {
|
||||
impl IRUProgram {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
fn_defs: Vec::new(),
|
||||
var_defs: Vec::new(),
|
||||
type_defs: Vec::new(),
|
||||
data_defs: Vec::new(),
|
||||
data: Vec::new(),
|
||||
fn_map: HashMap::new(),
|
||||
fns: Vec::new(),
|
||||
@@ -49,6 +53,9 @@ impl Namespace {
|
||||
pub fn get_fn(&self, id: FnID) -> &FnDef {
|
||||
&self.fn_defs[id.0]
|
||||
}
|
||||
pub fn get_data(&self, id: DataID) -> &DataDef {
|
||||
&self.data_defs[id.0]
|
||||
}
|
||||
pub fn get_fn_var(&self, id: VarID) -> Option<&FnDef> {
|
||||
Some(&self.fn_defs[self.fn_map.get(&id)?.0])
|
||||
}
|
||||
@@ -90,17 +97,20 @@ impl Namespace {
|
||||
Type::Unit => 0,
|
||||
})
|
||||
}
|
||||
pub fn size_of_var(&self, var: &VarID) -> Option<Size> {
|
||||
pub fn size_of_var(&self, var: VarID) -> Option<Size> {
|
||||
self.size_of_type(&self.var_defs[var.0].ty)
|
||||
}
|
||||
pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarID {
|
||||
pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarInst {
|
||||
let v = self.def_var(VarDef {
|
||||
name: format!("temp{}", self.temp),
|
||||
origin: super::Origin::File(origin),
|
||||
ty,
|
||||
});
|
||||
self.temp += 1;
|
||||
v
|
||||
VarInst {
|
||||
id: v,
|
||||
span: origin,
|
||||
}
|
||||
}
|
||||
pub fn def_fn(&mut self, def: FnDef) -> FnID {
|
||||
let i = self.fn_defs.len();
|
||||
@@ -128,8 +138,9 @@ impl Namespace {
|
||||
self.type_defs.push(def);
|
||||
id
|
||||
}
|
||||
pub fn def_data(&mut self, bytes: Vec<u8>) -> DataID {
|
||||
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)
|
||||
}
|
||||
@@ -187,18 +198,17 @@ impl Namespace {
|
||||
self.fns[id.0] = Some(f);
|
||||
}
|
||||
pub fn iter_vars(&self) -> impl Iterator<Item = (VarID, &VarDef)> {
|
||||
(0..self.var_defs.len())
|
||||
.map(|i| VarID(i))
|
||||
.zip(self.var_defs.iter())
|
||||
self.var_defs.iter().enumerate().map(|(i, v)| (VarID(i), v))
|
||||
}
|
||||
pub fn iter_fns(&self) -> impl Iterator<Item = (FnID, Option<&IRUFunction>)> {
|
||||
(0..self.fns.len())
|
||||
.map(|i| FnID(i))
|
||||
.zip(self.fns.iter().map(|f| f.as_ref()))
|
||||
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 struct NamespaceGuard<'a>(&'a mut Namespace);
|
||||
pub struct NamespaceGuard<'a>(&'a mut IRUProgram);
|
||||
|
||||
impl Drop for NamespaceGuard<'_> {
|
||||
fn drop(&mut self) {
|
||||
@@ -207,7 +217,7 @@ impl Drop for NamespaceGuard<'_> {
|
||||
}
|
||||
|
||||
impl Deref for NamespaceGuard<'_> {
|
||||
type Target = Namespace;
|
||||
type Target = IRUProgram;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::{Len, TypeID};
|
||||
use super::{IRUInstruction, IRUProgram, Len, TypeID};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Type {
|
||||
Concrete(TypeID),
|
||||
Bits(u32),
|
||||
@@ -25,3 +25,20 @@ impl Type {
|
||||
Self::Slice(Box::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_types(ns: &IRUProgram) {
|
||||
for (i, f) in ns.iter_fns() {
|
||||
for inst in &f.instructions {
|
||||
match &inst.i {
|
||||
IRUInstruction::Mv { dest, src } => todo!(),
|
||||
IRUInstruction::Ref { dest, src } => todo!(),
|
||||
IRUInstruction::LoadData { dest, src } => todo!(),
|
||||
IRUInstruction::LoadSlice { dest, src } => todo!(),
|
||||
IRUInstruction::LoadFn { dest, src } => todo!(),
|
||||
IRUInstruction::Call { dest, f, args } => todo!(),
|
||||
IRUInstruction::AsmBlock { instructions, args } => todo!(),
|
||||
IRUInstruction::Ret { src } => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
52
src/ir/upper/validate.rs
Normal file
52
src/ir/upper/validate.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
// TODO: move this into ir, not parser
|
||||
use super::{IRUProgram, Type};
|
||||
use crate::common::CompilerOutput;
|
||||
|
||||
impl IRUProgram {
|
||||
pub fn validate(&self) -> CompilerOutput {
|
||||
let mut output = CompilerOutput::new();
|
||||
for f in self.fns.iter().flatten() {
|
||||
for i in &f.instructions {
|
||||
match &i.i {
|
||||
super::IRUInstruction::Mv { dest, src } => {
|
||||
let dest = self.get_var(dest.id);
|
||||
let src = self.get_var(src.id);
|
||||
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
||||
}
|
||||
super::IRUInstruction::Ref { dest, src } => todo!(),
|
||||
super::IRUInstruction::LoadData { dest, src } => {
|
||||
let dest = self.get_var(dest.id);
|
||||
let src = self.get_data(*src);
|
||||
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
||||
}
|
||||
super::IRUInstruction::LoadSlice { dest, src } => {
|
||||
let dest = self.get_var(dest.id);
|
||||
let src = self.get_data(*src);
|
||||
let Type::Array(srcty, ..) = &src.ty else {
|
||||
todo!()
|
||||
};
|
||||
output.check_assign(self, &Type::Slice(srcty.clone()), &dest.ty, i.span);
|
||||
}
|
||||
super::IRUInstruction::LoadFn { dest, src } => todo!(),
|
||||
super::IRUInstruction::Call { dest, f, args } => {
|
||||
let destty = &self.get_var(dest.id).ty;
|
||||
let f = self.get_var(f.id);
|
||||
let Type::Fn { args: argtys, ret } = &f.ty else {
|
||||
todo!()
|
||||
};
|
||||
output.check_assign(self, ret, destty, 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);
|
||||
}
|
||||
}
|
||||
super::IRUInstruction::AsmBlock { instructions, args } => {
|
||||
// TODO
|
||||
}
|
||||
super::IRUInstruction::Ret { src } => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user