BRANCHING (TURING COMPLETE????)
This commit is contained in:
@@ -3,7 +3,7 @@ use std::{collections::HashMap, fmt::Write};
|
||||
use super::{
|
||||
arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, Type, VarID,
|
||||
};
|
||||
use crate::{common::FileSpan, compiler::arch::riscv::Reg, util::Padder};
|
||||
use crate::{compiler::arch::riscv::Reg, util::Padder};
|
||||
|
||||
pub struct IRUFunction {
|
||||
pub name: String,
|
||||
@@ -54,50 +54,64 @@ pub enum IRUInstruction {
|
||||
dest: VarInst,
|
||||
fields: HashMap<String, VarInst>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct IRInstructions {
|
||||
vec: Vec<IRUInstrInst>,
|
||||
}
|
||||
|
||||
impl IRUFunction {
|
||||
pub fn new(name: String, args: Vec<VarID>, ret: Type, instructions: IRInstructions) -> Self {
|
||||
Self {
|
||||
name,
|
||||
ret,
|
||||
args,
|
||||
instructions: instructions.vec,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IRInstructions {
|
||||
pub fn new() -> Self {
|
||||
Self { vec: Vec::new() }
|
||||
}
|
||||
pub fn push(&mut self, i: IRUInstruction, span: FileSpan) {
|
||||
self.vec.push(IRUInstrInst { i, span });
|
||||
}
|
||||
If {
|
||||
cond: VarInst,
|
||||
body: Vec<IRUInstrInst>,
|
||||
},
|
||||
Loop {
|
||||
body: Vec<IRUInstrInst>,
|
||||
},
|
||||
Break,
|
||||
}
|
||||
|
||||
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::LoadSlice { dest, src } => write!(f, "{dest:?} <- &[{src:?}]"),
|
||||
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::LoadSlice { 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(),
|
||||
Self::Construct { dest, fields } => write!(f, "{dest:?} <- {fields:?}"),
|
||||
Self::Access { dest, src, field } => write!(f, "{dest:?} <- {src:?}.{field}"),
|
||||
} => 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()?,
|
||||
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() {
|
||||
f.write_str("{\n ")?;
|
||||
let mut padder = Padder::new(f);
|
||||
for i in body {
|
||||
// they don't expose wrap_buf :grief:
|
||||
padder.write_str(&format!("{i:?};\n"))?;
|
||||
}
|
||||
f.write_char('}')?;
|
||||
} else {
|
||||
f.write_str("{}")?;
|
||||
}
|
||||
}
|
||||
Self::Loop { body } => {
|
||||
write!(f, "loop:")?;
|
||||
if !body.is_empty() {
|
||||
f.write_str("{\n ")?;
|
||||
let mut padder = Padder::new(f);
|
||||
for i in body {
|
||||
// they don't expose wrap_buf :grief:
|
||||
padder.write_str(&format!("{i:?};\n"))?;
|
||||
}
|
||||
f.write_char('}')?;
|
||||
} else {
|
||||
f.write_str("{}")?;
|
||||
}
|
||||
}
|
||||
Self::Break => write!(f, "break")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::Debug,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
use crate::common::FileSpan;
|
||||
@@ -34,9 +33,11 @@ impl IRUProgram {
|
||||
stack: vec![HashMap::new()],
|
||||
}
|
||||
}
|
||||
pub fn push(&mut self) -> NamespaceGuard {
|
||||
pub fn push(&mut self) {
|
||||
self.stack.push(HashMap::new());
|
||||
NamespaceGuard(self)
|
||||
}
|
||||
pub fn pop(&mut self) {
|
||||
self.stack.pop();
|
||||
}
|
||||
pub fn get(&self, name: &str) -> Option<Idents> {
|
||||
for map in self.stack.iter().rev() {
|
||||
@@ -205,27 +206,6 @@ impl IRUProgram {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NamespaceGuard<'a>(&'a mut IRUProgram);
|
||||
|
||||
impl Drop for NamespaceGuard<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.0.stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for NamespaceGuard<'_> {
|
||||
type Target = IRUProgram;
|
||||
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),
|
||||
|
||||
@@ -1,114 +1,140 @@
|
||||
// TODO: move this into ir, not parser
|
||||
use super::{IRUInstruction, IRUProgram, Type};
|
||||
use super::{IRUInstrInst, IRUInstruction, IRUProgram, Type};
|
||||
use crate::common::{CompilerMsg, CompilerOutput};
|
||||
|
||||
impl IRUProgram {
|
||||
pub fn validate(&self) -> CompilerOutput {
|
||||
let mut output = CompilerOutput::new();
|
||||
for (f, fd) in self.fns.iter().flatten().zip(&self.fn_defs) {
|
||||
for i in &f.instructions {
|
||||
match &i.i {
|
||||
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);
|
||||
}
|
||||
IRUInstruction::Ref { dest, src } => todo!(),
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
let Type::Fn { args: argtys, ret } = &f.ty else {
|
||||
todo!()
|
||||
};
|
||||
output.check_assign(self, ret, destty, dest.span);
|
||||
if args.len() != argtys.len() {
|
||||
output.err(CompilerMsg {
|
||||
msg: "Wrong number of arguments to function".to_string(),
|
||||
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);
|
||||
}
|
||||
}
|
||||
IRUInstruction::AsmBlock { instructions, args } => {
|
||||
// TODO
|
||||
}
|
||||
IRUInstruction::Ret { src } => {
|
||||
let srcty = &self.get_var(src.id).ty;
|
||||
output.check_assign(self, srcty, &fd.ret, src.span);
|
||||
}
|
||||
IRUInstruction::Construct { dest, fields } => {
|
||||
let dest_def = self.get_var(dest.id);
|
||||
let tyid = match dest_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);
|
||||
for (name, field) in &def.fields {
|
||||
if let Some(var) = fields.get(name) {
|
||||
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"),
|
||||
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);
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
self.validate_fn(&f.instructions, &fd.ret, &mut output, false);
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
pub fn validate_fn(
|
||||
&self,
|
||||
instructions: &[IRUInstrInst],
|
||||
ret: &Type,
|
||||
output: &mut CompilerOutput,
|
||||
breakable: bool,
|
||||
) {
|
||||
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);
|
||||
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
||||
}
|
||||
IRUInstruction::Ref { dest, src } => todo!(),
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
let Type::Fn { args: argtys, ret } = &f.ty else {
|
||||
todo!()
|
||||
};
|
||||
output.check_assign(self, ret, destty, dest.span);
|
||||
if args.len() != argtys.len() {
|
||||
output.err(CompilerMsg {
|
||||
msg: "Wrong number of arguments to function".to_string(),
|
||||
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);
|
||||
}
|
||||
}
|
||||
IRUInstruction::AsmBlock { instructions, args } => {
|
||||
// TODO
|
||||
}
|
||||
IRUInstruction::Ret { src } => {
|
||||
let srcty = &self.get_var(src.id).ty;
|
||||
output.check_assign(self, srcty, ret, src.span);
|
||||
}
|
||||
IRUInstruction::Construct { dest, fields } => {
|
||||
let dest_def = self.get_var(dest.id);
|
||||
let tyid = match dest_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);
|
||||
for (name, field) in &def.fields {
|
||||
if let Some(var) = fields.get(name) {
|
||||
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"),
|
||||
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);
|
||||
output.check_assign(self, &cond.ty, &Type::Bits(64), i.span);
|
||||
self.validate_fn(body, ret, output, breakable);
|
||||
}
|
||||
IRUInstruction::Loop { body } => {
|
||||
self.validate_fn(body, ret, output, true);
|
||||
}
|
||||
IRUInstruction::Break => {
|
||||
if !breakable {
|
||||
output.err(CompilerMsg {
|
||||
msg: "Can't break here (outside of loop)".to_string(),
|
||||
spans: vec![i.span],
|
||||
});
|
||||
}
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user