huge refactor, can now define structs out of order

This commit is contained in:
2025-04-11 01:57:10 -04:00
parent f6a6761262
commit 31c16a263b
24 changed files with 765 additions and 566 deletions

View File

@@ -19,3 +19,4 @@ todo:
- iterators? - iterators?
- borrow checking - borrow checking
- basic optimization: use registers, remove temp var moves - basic optimization: use registers, remove temp var moves
- Cow str

View File

@@ -31,7 +31,7 @@ fn start() {
}; };
println("after"); println("after");
print(tester()); print(tester());
let test = Test { let test: Test = Test {
a: 10, a: 10,
b: 4, b: 4,
c: 0, c: 0,
@@ -59,7 +59,7 @@ fn structer(test: Test) {
print_dec(test.c); print_dec(test.c);
println(""); println("");
let test2 = Test2 { let test2: Test2 = Test2 {
a: 3, a: 3,
b: test, b: test,
c: test, c: test,

View File

@@ -4,7 +4,7 @@ use crate::{
compiler::{arch::riscv::Reg, debug::DebugInfo, UnlinkedFunction, UnlinkedProgram}, compiler::{arch::riscv::Reg, debug::DebugInfo, UnlinkedFunction, UnlinkedProgram},
ir::{ ir::{
arch::riscv64::{RV64Instruction as AI, RegRef}, arch::riscv64::{RV64Instruction as AI, RegRef},
IRLInstruction as IRI, IRLProgram, Len, Size, LInstruction as IRI, LProgram, Len, Size,
}, },
}; };
@@ -47,7 +47,7 @@ fn mov_mem(
} }
} }
pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> { pub fn compile(program: &LProgram) -> UnlinkedProgram<LI> {
let mut fns = Vec::new(); let mut fns = Vec::new();
let mut data = Vec::new(); let mut data = Vec::new();
let mut dbg = DebugInfo::new(program.labels().to_vec()); let mut dbg = DebugInfo::new(program.labels().to_vec());

View File

@@ -7,8 +7,8 @@ mod target;
use arch::riscv; use arch::riscv;
pub use program::*; pub use program::*;
use crate::ir::IRLProgram; use crate::ir::LProgram;
pub fn compile(program: &IRLProgram) -> UnlinkedProgram<riscv::LinkerInstruction> { pub fn compile(program: &LProgram) -> UnlinkedProgram<riscv::LinkerInstruction> {
arch::riscv::compile(program) arch::riscv::compile(program)
} }

View File

@@ -1,46 +1,51 @@
use std::fmt::Debug; use std::{fmt::Debug, marker::PhantomData};
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
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 // I had an idea for why these were different... now I don't
pub type Size = u32; pub type Size = u32;
pub type Len = u32; pub type Len = u32;
impl Debug for VarID { pub struct ID<T>(pub usize, PhantomData<T>);
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "var{}", self.0) impl<T> ID<T> {
pub fn new(i: usize) -> Self {
Self(i, PhantomData)
} }
} }
impl Debug for StructID { pub trait Named {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { const NAME: &str;
write!(f, "ty{}", self.0) }
impl<T> From<usize> for ID<T> {
fn from(value: usize) -> Self {
Self(value, PhantomData)
} }
} }
impl Debug for FnID { impl<K: Named> Debug for ID<K> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "fn{}", self.0) write!(f, "{}{}", K::NAME, self.0)
} }
} }
impl Debug for DataID { impl<T> PartialEq for ID<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn eq(&self, other: &Self) -> bool {
write!(f, "data{}", self.0) self.0 == other.0
} }
} }
impl Debug for FieldID { impl<T> Eq for ID<T> {}
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "field{}", self.0) impl<T> std::hash::Hash for ID<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
} }
} }
impl<T> Clone for ID<T> {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
impl<T> Copy for ID<T> {}

View File

@@ -5,7 +5,7 @@ use std::collections::HashMap;
#[derive(Debug)] #[derive(Debug)]
pub struct IRLFunction { pub struct IRLFunction {
pub instructions: Vec<IRLInstruction>, pub instructions: Vec<LInstruction>,
pub stack: HashMap<VarID, Size>, pub stack: HashMap<VarID, Size>,
pub subvar_map: HashMap<VarID, VarOffset>, pub subvar_map: HashMap<VarID, VarOffset>,
pub args: Vec<(VarID, Size)>, pub args: Vec<(VarID, Size)>,
@@ -14,7 +14,7 @@ pub struct IRLFunction {
} }
#[derive(Debug)] #[derive(Debug)]
pub enum IRLInstruction { pub enum LInstruction {
Mv { Mv {
dest: VarID, dest: VarID,
dest_offset: Size, dest_offset: Size,
@@ -59,7 +59,7 @@ pub enum IRLInstruction {
Mark(Symbol), Mark(Symbol),
} }
impl IRLInstruction { impl LInstruction {
pub fn is_ret(&self) -> bool { pub fn is_ret(&self) -> bool {
matches!(self, Self::Ret { .. }) matches!(self, Self::Ret { .. })
} }

View File

@@ -1,41 +1,38 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::ir::{AsmBlockArgType, IRUFunction, IRUInstrInst, Size, SymbolSpace, VarOffset}; use crate::ir::{AsmBlockArgType, UInstrInst, Size, SymbolSpace, UFunc, VarOffset};
use super::{ use super::{
IRLFunction, IRLInstruction, IRUInstruction, IRUProgram, Len, Symbol, SymbolSpaceBuilder, Type, IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, Type, UInstruction, UProgram,
VarID, VarID,
}; };
pub struct IRLProgram { pub struct LProgram {
sym_space: SymbolSpace, sym_space: SymbolSpace,
entry: Symbol, entry: Symbol,
} }
// NOTE: there are THREE places here where I specify size (8) // NOTE: there are THREE places here where I specify size (8)
impl IRLProgram { impl LProgram {
pub fn create(p: &IRUProgram) -> Result<Self, String> { pub fn create(p: &UProgram) -> Result<Self, String> {
let mut start = None; let start = p
for (i, f) in p.iter_fns() { .names
if f.name == "start" { .lookup::<UFunc>("start")
start = Some(i); .ok_or("no start method found")?;
}
}
let start = start.ok_or("no start method found")?;
let mut ssbuilder = SymbolSpaceBuilder::with_entries(&[start]); let mut ssbuilder = SymbolSpaceBuilder::with_entries(&[start]);
let entry = ssbuilder.func(&start); let entry = ssbuilder.func(&start);
while let Some((sym, i)) = ssbuilder.pop_fn() { while let Some((sym, i)) = ssbuilder.pop_fn() {
let f = p.fns[i.0].as_ref().unwrap(); let f = p.fns[i.0].as_ref().unwrap();
let mut fbuilder = IRLFunctionBuilder::new(p, &mut ssbuilder); let mut fbuilder = LFunctionBuilder::new(p, &mut ssbuilder);
for i in &f.instructions { for i in &f.instructions {
fbuilder.insert_instr(i); fbuilder.insert_instr(i);
} }
if fbuilder.instrs.last().is_none_or(|i| !i.is_ret()) { if fbuilder.instrs.last().is_none_or(|i| !i.is_ret()) {
fbuilder.instrs.push(IRLInstruction::Ret { src: None }); fbuilder.instrs.push(LInstruction::Ret { src: None });
} }
let res = fbuilder.finish(f); let res = fbuilder.finish(f);
ssbuilder.write_fn(sym, res, Some(f.name.clone())); ssbuilder.write_fn(sym, res, Some(p.names.get(i).to_string()));
} }
let sym_space = ssbuilder.finish().expect("we failed the mission"); let sym_space = ssbuilder.finish().expect("we failed the mission");
Ok(Self { sym_space, entry }) Ok(Self { sym_space, entry })
@@ -46,10 +43,10 @@ impl IRLProgram {
} }
} }
pub struct IRLFunctionBuilder<'a> { pub struct LFunctionBuilder<'a> {
program: &'a IRUProgram, program: &'a UProgram,
builder: &'a mut SymbolSpaceBuilder, builder: &'a mut SymbolSpaceBuilder,
instrs: Vec<IRLInstruction>, instrs: Vec<LInstruction>,
stack: HashMap<VarID, Size>, stack: HashMap<VarID, Size>,
subvar_map: HashMap<VarID, VarOffset>, subvar_map: HashMap<VarID, VarOffset>,
makes_call: bool, makes_call: bool,
@@ -62,8 +59,8 @@ pub struct LoopCtx {
bot: Symbol, bot: Symbol,
} }
impl<'a> IRLFunctionBuilder<'a> { impl<'a> LFunctionBuilder<'a> {
pub fn new(program: &'a IRUProgram, builder: &'a mut SymbolSpaceBuilder) -> Self { pub fn new(program: &'a UProgram, builder: &'a mut SymbolSpaceBuilder) -> Self {
Self { Self {
instrs: Vec::new(), instrs: Vec::new(),
stack: HashMap::new(), stack: HashMap::new(),
@@ -92,50 +89,56 @@ impl<'a> IRLFunctionBuilder<'a> {
self.subvar_map.insert(i, off); self.subvar_map.insert(i, off);
} }
} }
pub fn insert_instr(&mut self, i: &IRUInstrInst) -> Option<Option<String>> { pub fn insert_instr(&mut self, i: &UInstrInst) -> Option<Option<String>> {
match &i.i { match &i.i {
IRUInstruction::Mv { dest, src } => { UInstruction::Mv { dest, src } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dest.id)?;
self.map_subvar(src.id); self.map_subvar(src.id);
self.instrs.push(IRLInstruction::Mv { self.instrs.push(LInstruction::Mv {
dest: dest.id, dest: dest.id,
dest_offset: 0, dest_offset: 0,
src: src.id, src: src.id,
src_offset: 0, src_offset: 0,
}); });
} }
IRUInstruction::Ref { dest, src } => { UInstruction::Ref { dest, src } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dest.id)?;
self.map_subvar(src.id); self.map_subvar(src.id);
self.instrs.push(IRLInstruction::Ref { self.instrs.push(LInstruction::Ref {
dest: dest.id, dest: dest.id,
src: src.id, src: src.id,
}); });
} }
IRUInstruction::LoadData { dest, src } => { UInstruction::LoadData { dest, src } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dest.id)?;
let data = &self.program.data[src.0]; let data = self.program.expect(*src);
let ddef = self.program.get_data(*src); let sym = self.builder.ro_data(
let sym = self.builder.ro_data(src, data, Some(ddef.label.clone())); src,
self.instrs.push(IRLInstruction::LoadData { &data.content,
Some(self.program.names.get(dest.id).to_string()),
);
self.instrs.push(LInstruction::LoadData {
dest: dest.id, dest: dest.id,
offset: 0, offset: 0,
len: data.len() as Len, len: data.content.len() as Len,
src: sym, src: sym,
}); });
} }
IRUInstruction::LoadSlice { dest, src } => { UInstruction::LoadSlice { dest, src } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dest.id)?;
let data = &self.program.data[src.0]; let data = self.program.expect(*src);
let def = self.program.get_data(*src); let Type::Array(_, len) = &data.ty else {
let Type::Array(_, len) = &def.ty else {
return Some(Some(format!( return Some(Some(format!(
"tried to load {} as slice", "tried to load {} as slice",
self.program.type_name(&def.ty) self.program.type_name(&data.ty)
))); )));
}; };
let sym = self.builder.ro_data(src, data, Some(def.label.clone())); let sym = self.builder.ro_data(
self.instrs.push(IRLInstruction::LoadAddr { src,
&data.content,
Some(self.program.names.get(dest.id).to_string()),
);
self.instrs.push(LInstruction::LoadAddr {
dest: dest.id, dest: dest.id,
offset: 0, offset: 0,
src: sym, src: sym,
@@ -144,23 +147,23 @@ impl<'a> IRLFunctionBuilder<'a> {
let sym = self let sym = self
.builder .builder
.anon_ro_data(&(*len as u64).to_le_bytes(), Some(format!("len: {}", len))); .anon_ro_data(&(*len as u64).to_le_bytes(), Some(format!("len: {}", len)));
self.instrs.push(IRLInstruction::LoadData { self.instrs.push(LInstruction::LoadData {
dest: dest.id, dest: dest.id,
offset: 8, offset: 8,
len: 8, len: 8,
src: sym, src: sym,
}); });
} }
IRUInstruction::LoadFn { dest, src } => { UInstruction::LoadFn { dest, src } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dest.id)?;
let sym = self.builder.func(src); let sym = self.builder.func(src);
self.instrs.push(IRLInstruction::LoadAddr { self.instrs.push(LInstruction::LoadAddr {
dest: dest.id, dest: dest.id,
offset: 0, offset: 0,
src: sym, src: sym,
}); });
} }
IRUInstruction::Call { dest, f, args } => { UInstruction::Call { dest, f, args } => {
self.alloc_stack(dest.id); self.alloc_stack(dest.id);
self.makes_call = true; self.makes_call = true;
let fid = &self.program.fn_map[&f.id]; let fid = &self.program.fn_map[&f.id];
@@ -171,7 +174,7 @@ impl<'a> IRLFunctionBuilder<'a> {
} else { } else {
None None
}; };
let call = IRLInstruction::Call { let call = LInstruction::Call {
dest, dest,
f: sym, f: sym,
args: args args: args
@@ -184,7 +187,7 @@ impl<'a> IRLFunctionBuilder<'a> {
}; };
self.instrs.push(call); self.instrs.push(call);
} }
IRUInstruction::AsmBlock { instructions, args } => { UInstruction::AsmBlock { instructions, args } => {
let mut inputs = Vec::new(); let mut inputs = Vec::new();
let mut outputs = Vec::new(); let mut outputs = Vec::new();
for a in args { for a in args {
@@ -199,15 +202,15 @@ impl<'a> IRLFunctionBuilder<'a> {
} }
} }
} }
self.instrs.push(IRLInstruction::AsmBlock { self.instrs.push(LInstruction::AsmBlock {
instructions: instructions.clone(), instructions: instructions.clone(),
inputs, inputs,
outputs, outputs,
}) })
} }
IRUInstruction::Ret { src } => { UInstruction::Ret { src } => {
self.map_subvar(src.id); self.map_subvar(src.id);
self.instrs.push(IRLInstruction::Ret { self.instrs.push(LInstruction::Ret {
src: if self.program.size_of_var(src.id).expect("unsized var") == 0 { src: if self.program.size_of_var(src.id).expect("unsized var") == 0 {
None None
} else { } else {
@@ -215,9 +218,9 @@ impl<'a> IRLFunctionBuilder<'a> {
}, },
}) })
} }
IRUInstruction::Construct { dest, fields } => { UInstruction::Construct { dest, fields } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dest.id)?;
let ty = &self.program.get_var(dest.id).ty; let ty = &self.program.expect(dest.id).ty;
let &Type::Struct { id, ref args } = ty else { let &Type::Struct { id, ref args } = ty else {
return Some(Some(format!( return Some(Some(format!(
"Failed to contruct type {}", "Failed to contruct type {}",
@@ -226,7 +229,7 @@ impl<'a> IRLFunctionBuilder<'a> {
}; };
for (&fid, var) in fields { for (&fid, var) in fields {
self.map_subvar(var.id); self.map_subvar(var.id);
self.instrs.push(IRLInstruction::Mv { self.instrs.push(LInstruction::Mv {
dest: dest.id, dest: dest.id,
src: var.id, src: var.id,
dest_offset: self.program.field_offset(id, fid).expect("field offset"), dest_offset: self.program.field_offset(id, fid).expect("field offset"),
@@ -234,19 +237,19 @@ impl<'a> IRLFunctionBuilder<'a> {
}) })
} }
} }
IRUInstruction::If { cond, body } => { UInstruction::If { cond, body } => {
self.map_subvar(cond.id); self.map_subvar(cond.id);
let sym = self.builder.reserve(); let sym = self.builder.reserve();
self.instrs.push(IRLInstruction::Branch { self.instrs.push(LInstruction::Branch {
to: *sym, to: *sym,
cond: cond.id, cond: cond.id,
}); });
for i in body { for i in body {
self.insert_instr(i); self.insert_instr(i);
} }
self.instrs.push(IRLInstruction::Mark(*sym)); self.instrs.push(LInstruction::Mark(*sym));
} }
IRUInstruction::Loop { body } => { UInstruction::Loop { body } => {
let top = self.builder.reserve(); let top = self.builder.reserve();
let bot = self.builder.reserve(); let bot = self.builder.reserve();
let old = self.loopp; let old = self.loopp;
@@ -254,21 +257,21 @@ impl<'a> IRLFunctionBuilder<'a> {
bot: *bot, bot: *bot,
top: *top, top: *top,
}); });
self.instrs.push(IRLInstruction::Mark(*top)); self.instrs.push(LInstruction::Mark(*top));
for i in body { for i in body {
self.insert_instr(i); self.insert_instr(i);
} }
self.instrs.push(IRLInstruction::Jump(*top)); self.instrs.push(LInstruction::Jump(*top));
self.instrs.push(IRLInstruction::Mark(*bot)); self.instrs.push(LInstruction::Mark(*bot));
self.loopp = old; self.loopp = old;
} }
IRUInstruction::Break => { UInstruction::Break => {
self.instrs.push(IRLInstruction::Jump( self.instrs.push(LInstruction::Jump(
self.loopp.expect("Tried to break outside of loop").bot, self.loopp.expect("Tried to break outside of loop").bot,
)); ));
} }
IRUInstruction::Continue => { UInstruction::Continue => {
self.instrs.push(IRLInstruction::Jump( self.instrs.push(LInstruction::Jump(
self.loopp.expect("Tried to break outside of loop").top, self.loopp.expect("Tried to break outside of loop").top,
)); ));
} }
@@ -276,7 +279,7 @@ impl<'a> IRLFunctionBuilder<'a> {
Some(None) Some(None)
} }
pub fn finish(self, f: &IRUFunction) -> IRLFunction { pub fn finish(self, f: &UFunc) -> IRLFunction {
IRLFunction { IRLFunction {
instructions: self.instrs, instructions: self.instrs,
makes_call: self.makes_call, makes_call: self.makes_call,
@@ -292,7 +295,7 @@ impl<'a> IRLFunctionBuilder<'a> {
} }
} }
impl std::ops::Deref for IRLProgram { impl std::ops::Deref for LProgram {
type Target = SymbolSpace; type Target = SymbolSpace;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {

View File

@@ -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))
}
}

View File

@@ -1,9 +1,9 @@
use crate::common::{CompilerMsg, CompilerOutput, FileSpan}; use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
use super::{IRUProgram, Type}; use super::{Type, UProgram};
impl CompilerOutput { 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 // TODO: spans
if src != dest { if src != dest {
self.err(CompilerMsg { self.err(CompilerMsg {
@@ -14,6 +14,9 @@ impl CompilerOutput {
), ),
spans: vec![span], spans: vec![span],
}); });
true
} else {
false
} }
} }
} }

View File

@@ -1,7 +1,7 @@
use crate::{common::FileSpan, ir::VarID}; use crate::{common::FileSpan, ir::VarID};
use std::fmt::Debug; use std::fmt::Debug;
use super::IRUInstruction; use super::UInstruction;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct VarInst { pub struct VarInst {
@@ -9,8 +9,8 @@ pub struct VarInst {
pub span: FileSpan, pub span: FileSpan,
} }
pub struct IRUInstrInst { pub struct UInstrInst {
pub i: IRUInstruction, pub i: UInstruction,
pub span: FileSpan, 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.i) write!(f, "{:?}", self.i)
} }

View File

@@ -1,18 +1,9 @@
use std::{collections::HashMap, fmt::Write}; use std::{collections::HashMap, fmt::Write};
use super::{ use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, UInstrInst, UFunc};
arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, Type, VarID,
};
use crate::{compiler::arch::riscv::Reg, ir::FieldID, util::Padder}; use crate::{compiler::arch::riscv::Reg, ir::FieldID, util::Padder};
pub struct IRUFunction { pub enum UInstruction {
pub name: String,
pub args: Vec<VarID>,
pub ret: Type,
pub instructions: Vec<IRUInstrInst>,
}
pub enum IRUInstruction {
Mv { Mv {
dest: VarInst, dest: VarInst,
src: VarInst, src: VarInst,
@@ -51,10 +42,10 @@ pub enum IRUInstruction {
}, },
If { If {
cond: VarInst, cond: VarInst,
body: Vec<IRUInstrInst>, body: Vec<UInstrInst>,
}, },
Loop { Loop {
body: Vec<IRUInstrInst>, body: Vec<UInstrInst>,
}, },
Break, Break,
Continue, Continue,
@@ -73,7 +64,7 @@ pub enum AsmBlockArgType {
Out, Out,
} }
impl std::fmt::Debug for IRUInstruction { impl std::fmt::Debug for UInstruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::Mv { dest, src } => write!(f, "{dest:?} <- {src:?}")?, Self::Mv { dest, src } => write!(f, "{dest:?} <- {src:?}")?,
@@ -86,9 +77,7 @@ impl std::fmt::Debug for IRUInstruction {
f: func, f: func,
args, args,
} => write!(f, "{dest:?} <- {func:?}({args:?})")?, } => write!(f, "{dest:?} <- {func:?}({args:?})")?,
Self::AsmBlock { args, instructions } => { Self::AsmBlock { args, instructions } => write!(f, "asm {args:?} {instructions:#?}")?,
write!(f, "asm {args:?} {instructions:#?}")?
}
Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish()?, Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish()?,
Self::Construct { dest, fields } => write!(f, "{dest:?} <- {fields:?}")?, Self::Construct { dest, fields } => write!(f, "{dest:?} <- {fields:?}")?,
Self::If { cond, body } => { 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 { 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() { if !self.instructions.is_empty() {
f.write_str("{\n ")?; f.write_str("{\n ")?;
let mut padder = Padder::new(f); let mut padder = Padder::new(f);

160
src/ir/upper/kind.rs Normal file
View 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;
}

View File

@@ -1,5 +1,5 @@
mod def; mod kind;
mod func; mod instr;
mod ty; mod ty;
mod program; mod program;
mod validate; mod validate;
@@ -7,8 +7,8 @@ mod error;
mod inst; mod inst;
use super::*; use super::*;
pub use def::*; pub use kind::*;
pub use func::*; pub use instr::*;
pub use ty::*; pub use ty::*;
pub use program::*; pub use program::*;
pub use inst::*; pub use inst::*;

View File

@@ -2,40 +2,67 @@ use std::{collections::HashMap, fmt::Debug};
use super::{inst::VarInst, *}; use super::{inst::VarInst, *};
pub struct IRUProgram { pub struct UProgram {
pub fn_defs: Vec<FnDef>, pub fns: Vec<Option<UFunc>>,
pub var_defs: Vec<VarDef>, pub vars: Vec<Option<UVar>>,
pub struct_defs: Vec<StructDef>, pub structs: Vec<Option<UStruct>>,
pub data_defs: Vec<DataDef>, pub data: Vec<Option<UData>>,
pub fns: Vec<Option<IRUFunction>>, pub start: Option<FnID>,
pub data: Vec<Vec<u8>>, pub names: NameMap,
// todo: these feel weird raw
pub fn_map: HashMap<VarID, FnID>, pub fn_map: HashMap<VarID, FnID>,
pub inv_fn_map: Vec<VarID>,
pub temp: usize, 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 { pub fn new() -> Self {
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(), 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, temp: 0,
stack: vec![HashMap::new()], name_stack: vec![HashMap::new()],
} }
} }
pub fn push(&mut self) { pub fn push(&mut self) {
self.stack.push(HashMap::new()); self.name_stack.push(HashMap::new());
} }
pub fn pop(&mut self) { pub fn pop(&mut self) {
self.stack.pop(); self.name_stack.pop();
} }
pub fn get(&self, name: &str) -> Option<Idents> { pub fn get_idents(&self, name: &str) -> Option<Idents> {
for map in self.stack.iter().rev() { for map in self.name_stack.iter().rev() {
let res = map.get(name); let res = map.get(name);
if res.is_some() { if res.is_some() {
return res.cloned(); return res.cloned();
@@ -43,43 +70,29 @@ impl IRUProgram {
} }
None None
} }
pub fn get_var(&self, id: VarID) -> &VarDef { pub fn get<K: Kind>(&self, id: ID<K>) -> Option<&K> {
&self.var_defs[id.0] K::from_program(self)[id.0].as_ref()
} }
pub fn get_fn(&self, id: FnID) -> &FnDef { pub fn get_mut<K: Kind>(&mut self, id: ID<K>) -> Option<&mut K> {
&self.fn_defs[id.0] K::from_program_mut(self)[id.0].as_mut()
} }
pub fn get_data(&self, id: DataID) -> &DataDef { pub fn expect<K: Kind + Named>(&self, id: ID<K>) -> &K {
&self.data_defs[id.0] self.get(id)
.unwrap_or_else(|| panic!("{id:?} not defined yet!"))
} }
pub fn get_fn_var(&self, id: VarID) -> Option<&FnDef> { pub fn expect_mut<K: Kind + Named>(&mut self, id: ID<K>) -> &mut K {
Some(&self.fn_defs[self.fn_map.get(&id)?.0]) self.get_mut(id)
.unwrap_or_else(|| panic!("{id:?} not defined yet!"))
} }
pub fn get_struct(&self, id: StructID) -> &StructDef { pub fn get_fn_var(&self, id: VarID) -> Option<&UFunc> {
&self.struct_defs[id.0] self.fns[self.fn_map.get(&id)?.0].as_ref()
}
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 size_of_type(&self, ty: &Type) -> Option<Size> { pub fn size_of_type(&self, ty: &Type) -> Option<Size> {
// TODO: target matters // TODO: target matters
Some(match ty { Some(match ty {
Type::Bits(b) => *b, Type::Bits(b) => *b,
Type::Struct { id, args } => self.struct_defs[id.0] Type::Struct { id, args } => self.structs[id.0]
.as_ref()?
.fields .fields
.iter() .iter()
.try_fold(0, |sum, f| Some(sum + self.size_of_type(&f.ty)?))?, .try_fold(0, |sum, f| Some(sum + self.size_of_type(&f.ty)?))?,
@@ -92,9 +105,8 @@ impl IRUProgram {
Type::Unit => 0, Type::Unit => 0,
}) })
} }
pub fn struct_layout() {}
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) self.size_of_type(&self.get(var)?.ty)
} }
pub fn temp_subvar(&mut self, origin: Origin, ty: Type, parent: FieldRef) -> VarInst { pub fn temp_subvar(&mut self, origin: Origin, ty: Type, parent: FieldRef) -> VarInst {
self.temp_var_inner(origin, ty, Some(parent)) 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 { fn temp_var_inner(&mut self, origin: Origin, ty: Type, parent: Option<FieldRef>) -> VarInst {
let v = self.def_var(VarDef { let v = self.def(
name: format!("temp{}", self.temp), format!("temp{}", self.temp),
parent, Some(UVar { parent, origin, ty }),
origin, );
ty,
});
self.temp += 1; self.temp += 1;
VarInst { VarInst {
id: v, id: v,
@@ -117,44 +127,29 @@ impl IRUProgram {
} }
} }
pub fn def_fn(&mut self, def: FnDef) -> FnID { pub fn write<K: Kind>(&mut self, id: ID<K>, k: K) {
let i = self.fn_defs.len(); K::from_program_mut(self)[id.0] = Some(k);
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 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 id
} }
pub fn def_struct(&mut self, def: StructDef) -> StructID {
let i = self.struct_defs.len(); pub fn def_searchable<K: Kind>(&mut self, name: String, k: Option<K>) -> ID<K> {
let id = StructID(i); let id = self.def(name.clone(), k);
self.insert(&def.name, Ident::Type(id)); self.name_on_stack(id, name);
self.struct_defs.push(def);
id 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 { pub fn type_name(&self, ty: &Type) -> String {
let mut str = String::new(); let mut str = String::new();
match ty { match ty {
Type::Struct { id: base, args } => { Type::Struct { id: base, args } => {
str += &self.get_struct(*base).name; str += self.names.get(*base);
if let Some(arg) = args.first() { if let Some(arg) = args.first() {
str = str + "<" + &self.type_name(arg); str = str + "<" + &self.type_name(arg);
} }
@@ -188,81 +183,82 @@ impl IRUProgram {
} }
str str
} }
fn insert(&mut self, name: &str, id: Ident) { fn name_on_stack<K: Kind>(&mut self, id: ID<K>, name: String) {
let idx = self.stack.len() - 1; let idx = self.name_stack.len() - 1;
let last = &mut self.stack[idx]; let last = &mut self.name_stack[idx];
if let Some(l) = last.get_mut(name) { if let Some(l) = last.get_mut(&name) {
l.insert(id); l.insert(id.into());
} else { } 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> { pub fn var_offset(&self, var: VarID) -> Option<VarOffset> {
let mut current = VarOffset { id: var, offset: 0 }; 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.id = parent.var;
current.offset += self.field_offset(parent.struc, parent.field)?; current.offset += self.field_offset(parent.struc, parent.field)?;
} }
Some(current) Some(current)
} }
pub fn field_offset(&self, struct_id: StructID, field: FieldID) -> Option<Len> { 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; let mut offset = 0;
for i in 0..field.0 { for i in 0..field.0 {
offset += self.size_of_type(&struc.fields[i].ty)?; offset += self.size_of_type(&struc.fields[i].ty)?;
} }
Some(offset) 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)] #[derive(Debug, Clone, Copy)]
pub enum Ident { pub struct Ident {
Var(VarID), id: usize,
Fn(FnID), kind: usize,
Type(StructID), }
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)] #[derive(Debug, Clone, Copy)]
pub struct Idents { pub struct Idents {
pub latest: Ident, pub latest: Ident,
pub var: Option<VarID>, pub kinds: [Option<usize>; NAMED_KINDS],
pub func: Option<FnID>,
pub struc: Option<StructID>,
} }
impl Idents { impl Idents {
fn new(latest: Ident) -> Self { fn new(latest: Ident) -> Self {
let mut s = Self { let mut s = Self {
latest, latest,
var: None, kinds: [None; NAMED_KINDS],
func: None,
struc: None,
}; };
s.insert(latest); s.insert(latest);
s s
} }
fn insert(&mut self, i: Ident) { fn insert(&mut self, i: Ident) {
self.latest = i; self.latest = i;
match i { self.kinds[i.kind] = Some(i.id);
Ident::Var(v) => {
self.var = Some(v);
}
Ident::Fn(f) => {
self.func = Some(f);
}
Ident::Type(t) => self.struc = Some(t),
} }
pub fn get<K: Kind>(&self) -> Option<ID<K>> {
self.kinds[K::INDEX].map(|i| i.into())
} }
} }

View File

@@ -1,4 +1,6 @@
use super::{IRUProgram, Len, StructID}; use crate::common::CompilerOutput;
use super::{Len, StructID, UInstruction, UProgram, UVar};
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum Type { pub enum Type {
@@ -25,13 +27,121 @@ impl Type {
} }
} }
// should impl instead impl UProgram {
pub fn resolve_types(ns: &IRUProgram) { pub fn resolve_types(&mut self) {
for (i, f) in ns.iter_fns() { // I LOVE RUST
for inst in &f.instructions { let mut vars = self.vars.clone();
match &inst.i { for f in self.fns.iter().flatten() {
_ => todo!(), 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,
} }
} }

View File

@@ -1,26 +1,27 @@
// TODO: move this into ir, not parser // 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}; use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
impl IRUProgram { impl UProgram {
pub fn validate(&self) -> CompilerOutput { pub fn validate(&self) -> CompilerOutput {
let mut output = CompilerOutput::new(); let mut output = CompilerOutput::new();
for (f, fd) in self.fns.iter().flatten().zip(&self.fn_defs) { for f in self.fns.iter().flatten() {
self.validate_fn( self.validate_fn(&f.instructions, f.origin, &f.ret, &mut output, true, false);
&f.instructions, }
fd.origin, for (id, var) in self.iter_vars() {
&fd.ret, if var.ty == Type::Error {
&mut output, output.err(CompilerMsg {
true, msg: format!("Var {:?} is error type!", id),
false, spans: vec![var.origin],
); });
}
} }
output output
} }
pub fn validate_fn( pub fn validate_fn(
&self, &self,
instructions: &[IRUInstrInst], instructions: &[UInstrInst],
origin: FileSpan, origin: FileSpan,
ret: &Type, ret: &Type,
output: &mut CompilerOutput, output: &mut CompilerOutput,
@@ -30,31 +31,31 @@ impl IRUProgram {
let mut no_ret = true; let mut no_ret = true;
for i in instructions { for i in instructions {
match &i.i { match &i.i {
IRUInstruction::Mv { dest, src } => { UInstruction::Mv { dest, src } => {
let dest = self.get_var(dest.id); let dest = self.expect(dest.id);
let src = self.get_var(src.id); let src = self.expect(src.id);
output.check_assign(self, &src.ty, &dest.ty, i.span); output.check_assign(self, &src.ty, &dest.ty, i.span);
} }
IRUInstruction::Ref { dest, src } => { UInstruction::Ref { dest, src } => {
// TODO // TODO
} }
IRUInstruction::LoadData { dest, src } => { UInstruction::LoadData { dest, src } => {
let dest = self.get_var(dest.id); let dest = self.expect(dest.id);
let src = self.get_data(*src); let src = self.expect(*src);
output.check_assign(self, &src.ty, &dest.ty, i.span); output.check_assign(self, &src.ty, &dest.ty, i.span);
} }
IRUInstruction::LoadSlice { dest, src } => { UInstruction::LoadSlice { dest, src } => {
let dest = self.get_var(dest.id); let dest = self.expect(dest.id);
let src = self.get_data(*src); let src = self.expect(*src);
let Type::Array(srcty, ..) = &src.ty else { let Type::Array(srcty, ..) = &src.ty else {
todo!() todo!()
}; };
output.check_assign(self, &Type::Slice(srcty.clone()), &dest.ty, i.span); output.check_assign(self, &Type::Slice(srcty.clone()), &dest.ty, i.span);
} }
IRUInstruction::LoadFn { dest, src } => todo!(), UInstruction::LoadFn { dest, src } => todo!(),
IRUInstruction::Call { dest, f, args } => { UInstruction::Call { dest, f, args } => {
let destty = &self.get_var(dest.id).ty; let destty = &self.expect(dest.id).ty;
let f = self.get_var(f.id); let f = self.expect(f.id);
let Type::Fn { args: argtys, ret } = &f.ty else { let Type::Fn { args: argtys, ret } = &f.ty else {
todo!() todo!()
}; };
@@ -65,21 +66,21 @@ impl IRUProgram {
spans: vec![dest.span], spans: vec![dest.span],
}); });
} }
for (argv, argt) in args.iter().zip(argtys) { for (dst_ty, src) in argtys.iter().zip(args) {
let dest = self.get_var(argv.id); let src_var = self.expect(src.id);
output.check_assign(self, argt, &dest.ty, argv.span); output.check_assign(self, &src_var.ty, dst_ty, src.span);
} }
} }
IRUInstruction::AsmBlock { instructions, args } => { UInstruction::AsmBlock { instructions, args } => {
// TODO // TODO
} }
IRUInstruction::Ret { src } => { UInstruction::Ret { src } => {
let srcty = &self.get_var(src.id).ty; let srcty = &self.expect(src.id).ty;
output.check_assign(self, srcty, ret, src.span); output.check_assign(self, srcty, ret, src.span);
no_ret = false; no_ret = false;
} }
IRUInstruction::Construct { dest, fields } => { UInstruction::Construct { dest, fields } => {
let dest_def = self.get_var(dest.id); let dest_def = self.expect(dest.id);
let tyid = match &dest_def.ty { let tyid = match &dest_def.ty {
Type::Struct { id, args } => *id, Type::Struct { id, args } => *id,
_ => { _ => {
@@ -90,10 +91,10 @@ impl IRUProgram {
continue; continue;
} }
}; };
let def = self.get_struct(tyid); let def = self.expect(tyid);
for (id, field) in def.iter_fields() { for (id, field) in def.iter_fields() {
if let Some(var) = fields.get(&id) { 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); output.check_assign(self, &field.ty, ety, var.span);
} else { } else {
output.err(CompilerMsg { output.err(CompilerMsg {
@@ -103,15 +104,15 @@ impl IRUProgram {
} }
} }
} }
IRUInstruction::If { cond, body } => { UInstruction::If { cond, body } => {
let cond = self.get_var(cond.id); let cond = self.expect(cond.id);
output.check_assign(self, &cond.ty, &Type::Bits(64), i.span); output.check_assign(self, &cond.ty, &Type::Bits(64), i.span);
self.validate_fn(body, origin, ret, output, false, breakable); self.validate_fn(body, origin, ret, output, false, breakable);
} }
IRUInstruction::Loop { body } => { UInstruction::Loop { body } => {
self.validate_fn(body, origin, ret, output, false, true); self.validate_fn(body, origin, ret, output, false, true);
} }
IRUInstruction::Break => { UInstruction::Break => {
if !breakable { if !breakable {
output.err(CompilerMsg { output.err(CompilerMsg {
msg: "Can't break here (outside of loop)".to_string(), msg: "Can't break here (outside of loop)".to_string(),
@@ -120,7 +121,7 @@ impl IRUProgram {
} }
// TODO // TODO
} }
IRUInstruction::Continue => { UInstruction::Continue => {
if !breakable { if !breakable {
output.err(CompilerMsg { output.err(CompilerMsg {
msg: "Can't continue here (outside of loop)".to_string(), msg: "Can't continue here (outside of loop)".to_string(),

View File

@@ -5,8 +5,9 @@
// dawg what // dawg what
#![feature(str_as_str)] #![feature(str_as_str)]
use ir::{IRLProgram, IRUProgram}; use ir::{LProgram, UProgram};
use parser::{NodeParsable, PModule, PStatement, ParserCtx}; use parser::{NodeParsable, PModule, PStatement, ParserCtx};
use util::Labelable;
use std::{ use std::{
fs::{create_dir_all, OpenOptions}, fs::{create_dir_all, OpenOptions},
io::{stdout, BufRead, BufReader}, io::{stdout, BufRead, BufReader},
@@ -37,24 +38,35 @@ fn main() {
fn run_file(file: &str, gdb: bool, asm: bool) { fn run_file(file: &str, gdb: bool, asm: bool) {
let mut ctx = ParserCtx::from(file); let mut ctx = ParserCtx::from(file);
let res = PModule::parse_node(&mut ctx); let res = PModule::parse_node(&mut ctx);
if ctx.output.errs.is_empty() { let mut output = ctx.output;
println!("Parsed:"); 'outer: {
println!("{:#?}", res.node); if !output.errs.is_empty() {
if let Some(module) = res.node.as_ref() { break 'outer;
let mut program = IRUProgram::new(); }
module.lower(&mut program, &mut ctx.output); // println!("Parsed:");
if ctx.output.errs.is_empty() { // println!("{:#?}", res.node);
let Some(module) = res.node.as_ref() else {
break 'outer;
};
let mut program = UProgram::new();
module.lower(&mut program, &mut output);
if !output.errs.is_empty() {
break 'outer;
}
program.resolve_types();
// println!("vars:"); // println!("vars:");
// for (id, def) in namespace.iter_vars() { // for (id, def) in program.iter_vars() {
// println!(" {id:?} = {}: {}", def.name, namespace.type_name(&def.ty)); // println!(" {id:?} = {}: {}", program.names.get(id), program.type_name(&def.ty));
// } // }
// for (id, f) in namespace.iter_fns() { // for (id, f) in program.iter_fns() {
// println!("{id:?} = {:#?}", f.unwrap()); // println!("{}:{id:?} = {:#?}", program.names.get(id), f);
// } // }
let output = program.validate(); output = program.validate();
if !output.errs.is_empty() {
break 'outer;
}
output.write_for(&mut stdout(), file); output.write_for(&mut stdout(), file);
if output.errs.is_empty() { let program = LProgram::create(&program).expect("morir");
let program = IRLProgram::create(&program).expect("morir");
let unlinked = compiler::compile(&program); let unlinked = compiler::compile(&program);
if asm { if asm {
println!("{:?}", unlinked); println!("{:?}", unlinked);
@@ -64,10 +76,7 @@ fn run_file(file: &str, gdb: bool, asm: bool) {
save_run(&bin, gdb); save_run(&bin, gdb);
} }
} }
} output.write_for(&mut stdout(), file);
}
}
ctx.output.write_for(&mut stdout(), file);
} }
fn save_run(binary: &[u8], run_gdb: bool) { fn save_run(binary: &[u8], run_gdb: bool) {

View File

@@ -1,7 +1,7 @@
use crate::{ use crate::{
compiler::arch::riscv::Reg, compiler::arch::riscv::Reg,
ir::{ ir::{
arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, IRUInstruction, Type, VarInst, arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, UInstruction, Type, VarInst,
}, },
parser::PAsmBlockArg, parser::PAsmBlockArg,
}; };
@@ -48,7 +48,7 @@ impl FnLowerable for PAsmBlock {
} }
} }
} }
let block = IRUInstruction::AsmBlock { let block = UInstruction::AsmBlock {
instructions: { instructions: {
let mut v = Vec::new(); let mut v = Vec::new();
for i in &self.instructions { for i in &self.instructions {

View File

@@ -1,4 +1,4 @@
use crate::ir::{IRUInstruction, Type, VarInst}; use crate::ir::{Type, UInstruction, VarInst};
use super::{FnLowerCtx, FnLowerable, PBlock, PStatement}; use super::{FnLowerCtx, FnLowerable, PBlock, PStatement};
@@ -23,17 +23,20 @@ impl FnLowerable for PStatement {
let def = def.lower(ctx.program, ctx.output)?; let def = def.lower(ctx.program, ctx.output)?;
let res = e.lower(ctx); let res = e.lower(ctx);
if let Some(res) = res { if let Some(res) = res {
ctx.program.name_var(&def, res.id); ctx.push(UInstruction::Mv {
dest: def,
src: res,
});
} }
None None
} }
super::PStatement::Return(e) => { super::PStatement::Return(e) => {
if let Some(e) = e { if let Some(e) = e {
let src = e.lower(ctx)?; let src = e.lower(ctx)?;
ctx.push_at(IRUInstruction::Ret { src }, src.span); ctx.push_at(UInstruction::Ret { src }, src.span);
} else { } else {
let src = ctx.temp(Type::Unit); let src = ctx.temp(Type::Unit);
ctx.push_at(IRUInstruction::Ret { src }, src.span); ctx.push_at(UInstruction::Ret { src }, src.span);
} }
None None
} }

View File

@@ -1,26 +1,35 @@
use crate::ir::{IRUProgram, Origin, Type, VarDef}; use crate::ir::{Type, UProgram, UStruct, UVar, VarInst};
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType, PVarDef}; use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType, PVarDef};
impl Node<PVarDef> { impl Node<PVarDef> {
pub fn lower(&self, program: &mut IRUProgram, output: &mut CompilerOutput) -> Option<VarDef> { pub fn lower(&self, program: &mut UProgram, output: &mut CompilerOutput) -> Option<VarInst> {
let s = self.as_ref()?; let s = self.as_ref()?;
let name = s.name.as_ref()?.to_string(); let name = s
.name
.as_ref()
.map(|n| n.to_string())
.unwrap_or("{error}".to_string());
let ty = match &s.ty { let ty = match &s.ty {
Some(ty) => ty.lower(program, output), Some(ty) => ty.lower(program, output),
None => Type::Infer, None => Type::Infer,
}; };
Some(VarDef { Some(VarInst {
id: program.def_searchable(
name, name,
Some(UVar {
ty, ty,
parent: None, parent: None,
origin: self.span, origin: self.span,
}),
),
span: self.span,
}) })
} }
} }
impl Node<PType> { impl Node<PType> {
pub fn lower(&self, namespace: &mut IRUProgram, output: &mut CompilerOutput) -> Type { pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> Type {
self.as_ref() self.as_ref()
.map(|t| t.lower(namespace, output, self.span)) .map(|t| t.lower(namespace, output, self.span))
.unwrap_or(Type::Error) .unwrap_or(Type::Error)
@@ -30,14 +39,17 @@ impl Node<PType> {
impl PType { impl PType {
pub fn lower( pub fn lower(
&self, &self,
namespace: &mut IRUProgram, namespace: &mut UProgram,
output: &mut CompilerOutput, output: &mut CompilerOutput,
span: FileSpan, span: FileSpan,
) -> Type { ) -> Type {
let Some(name) = self.name.as_ref() else { let Some(name) = self.name.as_ref() else {
return Type::Error; return Type::Error;
}; };
match namespace.get(&name).and_then(|ids| ids.struc) { match namespace
.get_idents(name)
.and_then(|ids| ids.get::<UStruct>())
{
Some(id) => { Some(id) => {
let args = self let args = self
.args .args

View File

@@ -1,6 +1,6 @@
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp}; use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
use crate::{ use crate::{
ir::{DataDef, FieldRef, IRUInstruction, Type, VarInst}, ir::{FieldRef, Type, UData, UInstruction, VarInst},
parser::PInfixOp, parser::PInfixOp,
}; };
@@ -12,55 +12,53 @@ impl FnLowerable for PExpr {
super::PLiteral::String(s) => { super::PLiteral::String(s) => {
let dest = ctx.program.temp_var(l.span, Type::Bits(8).slice()); let dest = ctx.program.temp_var(l.span, Type::Bits(8).slice());
let data = s.as_bytes().to_vec(); let data = s.as_bytes().to_vec();
let src = ctx.program.def_data( let src = ctx.program.def(
DataDef { format!("string \"{}\"", s.replace("\n", "\\n")),
Some(UData {
ty: Type::Bits(8).arr(data.len() as u32), ty: Type::Bits(8).arr(data.len() as u32),
origin: l.span, origin: l.span,
label: format!("string \"{}\"", s.replace("\n", "\\n")), content: data,
}, }),
data,
); );
ctx.push(IRUInstruction::LoadSlice { dest, src }); ctx.push(UInstruction::LoadSlice { dest, src });
dest dest
} }
super::PLiteral::Char(c) => { super::PLiteral::Char(c) => {
let ty = Type::Bits(8); let ty = Type::Bits(8);
let dest = ctx.program.temp_var(l.span, ty.clone()); let dest = ctx.program.temp_var(l.span, ty.clone());
let src = ctx.program.def_data( let src = ctx.program.def(
DataDef { format!("char '{c}'"),
Some(UData {
ty, ty,
origin: l.span, origin: l.span,
label: format!("char '{c}'"), content: c.to_string().as_bytes().to_vec(),
}, }),
c.to_string().as_bytes().to_vec(),
); );
ctx.push(IRUInstruction::LoadData { dest, src }); ctx.push(UInstruction::LoadData { dest, src });
dest dest
} }
super::PLiteral::Number(n) => { super::PLiteral::Number(n) => {
// TODO: temp // TODO: temp
let ty = Type::Bits(64); let ty = Type::Bits(64);
let dest = ctx.program.temp_var(l.span, Type::Bits(64)); let dest = ctx.program.temp_var(l.span, Type::Bits(64));
let src = ctx.program.def_data( let src = ctx.program.def(
DataDef { format!("num {n:?}"),
Some(UData {
ty, ty,
origin: l.span, origin: l.span,
label: format!("num {n:?}"), content: n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
}, }),
n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
); );
ctx.push(IRUInstruction::LoadData { dest, src }); ctx.push(UInstruction::LoadData { dest, src });
dest dest
} }
super::PLiteral::Unit => { super::PLiteral::Unit => ctx.program.temp_var(l.span, Type::Unit),
todo!();
}
}, },
PExpr::Ident(i) => ctx.get_var(i)?, PExpr::Ident(i) => ctx.get_var(i)?,
PExpr::BinaryOp(op, e1, e2) => { PExpr::BinaryOp(op, e1, e2) => {
let res1 = e1.lower(ctx)?; let res1 = e1.lower(ctx)?;
if *op == PInfixOp::Access { if *op == PInfixOp::Access {
let sty = &ctx.program.get_var(res1.id).ty; let sty = &ctx.program.expect(res1.id).ty;
let Type::Struct { let Type::Struct {
id: struct_id, id: struct_id,
args, args,
@@ -72,7 +70,7 @@ impl FnLowerable for PExpr {
)); ));
return None; return None;
}; };
let struc = ctx.program.get_struct(*struct_id); let struc = ctx.program.expect(*struct_id);
let Some(box PExpr::Ident(ident)) = &e2.inner else { let Some(box PExpr::Ident(ident)) = &e2.inner else {
ctx.err("Field accesses must be identifiers".to_string()); ctx.err("Field accesses must be identifiers".to_string());
return None; return None;
@@ -102,7 +100,7 @@ impl FnLowerable for PExpr {
PInfixOp::GreaterThan => todo!(), PInfixOp::GreaterThan => todo!(),
PInfixOp::Access => todo!(), PInfixOp::Access => todo!(),
PInfixOp::Assign => { PInfixOp::Assign => {
ctx.push(IRUInstruction::Mv { ctx.push(UInstruction::Mv {
dest: res1, dest: res1,
src: res2, src: res2,
}); });
@@ -115,15 +113,15 @@ impl FnLowerable for PExpr {
let res = e.lower(ctx)?; let res = e.lower(ctx)?;
match op { match op {
UnaryOp::Ref => { UnaryOp::Ref => {
let temp = ctx.temp(ctx.program.get_var(res.id).ty.clone().rf()); let temp = ctx.temp(ctx.program.expect(res.id).ty.clone().rf());
ctx.push(IRUInstruction::Ref { ctx.push(UInstruction::Ref {
dest: temp, dest: temp,
src: res, src: res,
}); });
temp temp
} }
UnaryOp::Deref => { UnaryOp::Deref => {
let t = &ctx.program.get_var(res.id).ty; let t = &ctx.program.expect(res.id).ty;
let Type::Ref(inner) = t else { let Type::Ref(inner) = t else {
ctx.err(format!( ctx.err(format!(
"Cannot dereference type {:?}", "Cannot dereference type {:?}",
@@ -145,22 +143,13 @@ impl FnLowerable for PExpr {
let arg = arg.lower(ctx)?; let arg = arg.lower(ctx)?;
nargs.push(arg); nargs.push(arg);
} }
let def = ctx.program.get_fn_var(fe.id); let ty = ctx
let ty = match def { .program
Some(def) => def.ret.clone(), .get_fn_var(fe.id)
None => { .map(|f| f.ret.clone())
ctx.err_at( .unwrap_or(Type::Error);
e.span,
format!(
"Expected function, found {}",
ctx.program.type_name(&ctx.program.get_var(fe.id).ty)
),
);
Type::Error
}
};
let temp = ctx.temp(ty); let temp = ctx.temp(ty);
ctx.push(IRUInstruction::Call { ctx.push(UInstruction::Call {
dest: temp, dest: temp,
f: fe, f: fe,
args: nargs, args: nargs,
@@ -176,7 +165,7 @@ impl FnLowerable for PExpr {
body.lower(&mut body_ctx); body.lower(&mut body_ctx);
let body = body_ctx.instructions; let body = body_ctx.instructions;
ctx.program.pop(); ctx.program.pop();
ctx.push(IRUInstruction::If { cond, body }); ctx.push(UInstruction::If { cond, body });
return None; return None;
} }
PExpr::Loop(body) => { PExpr::Loop(body) => {
@@ -185,15 +174,15 @@ impl FnLowerable for PExpr {
body.lower(&mut body_ctx); body.lower(&mut body_ctx);
let body = body_ctx.instructions; let body = body_ctx.instructions;
ctx.program.pop(); ctx.program.pop();
ctx.push(IRUInstruction::Loop { body }); ctx.push(UInstruction::Loop { body });
return None; return None;
} }
PExpr::Break => { PExpr::Break => {
ctx.push(IRUInstruction::Break); ctx.push(UInstruction::Break);
return None; return None;
} }
PExpr::Continue => { PExpr::Continue => {
ctx.push(IRUInstruction::Continue); ctx.push(UInstruction::Continue);
return None; return None;
} }
}) })

View File

@@ -1,110 +1,102 @@
use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction}; use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction};
use crate::{ use crate::{
ir::{ ir::{FieldRef, FnID, Idents, Type, UFunc, UInstrInst, UInstruction, UProgram, UVar, VarInst},
FnDef, FnID, IRUFunction, IRUInstrInst, IRUInstruction, IRUProgram, Idents, Type, VarDef,
VarInst, FieldRef,
},
parser, parser,
}; };
impl Node<PFunction> { impl Node<PFunction> {
pub fn lower_header(&self, map: &mut IRUProgram, output: &mut CompilerOutput) -> Option<FnID> { pub fn lower_name(&self, p: &mut UProgram) -> Option<FnID> {
self.as_ref()?.lower_header(map, output) Some(self.as_ref()?.lower_name(p)?)
}
pub fn lower(&self, id: FnID, p: &mut UProgram, output: &mut CompilerOutput) {
if let Some(s) = self.as_ref() {
s.lower(id, p, output)
} }
pub fn lower_body(
&self,
id: FnID,
map: &mut IRUProgram,
output: &mut CompilerOutput,
) -> Option<IRUFunction> {
Some(self.as_ref()?.lower_body(id, map, output))
} }
} }
impl PFunction { impl PFunction {
pub fn lower_header(&self, map: &mut IRUProgram, output: &mut CompilerOutput) -> Option<FnID> { pub fn lower_name(&self, p: &mut UProgram) -> Option<FnID> {
let header = self.header.as_ref()?; let header = self.header.as_ref()?;
let name = header.name.as_ref()?; let name = header.name.as_ref()?;
let args = header let id = p.def_searchable(name.to_string(), None);
.args let var = p.def_searchable(
.iter() name.to_string(),
.map(|a| { Some(UVar {
a.lower(map, output).unwrap_or(VarDef {
name: "{error}".to_string(),
origin: a.span,
parent: None, parent: None,
ty: Type::Error, ty: Type::Error,
})
})
.collect();
let ret = match &header.ret {
Some(ty) => ty.lower(map, output),
None => Type::Unit,
};
Some(map.def_fn(FnDef {
name: name.to_string(),
origin: self.header.span, origin: self.header.span,
args, }),
ret, );
})) p.fn_map.insert(var, id);
p.inv_fn_map.push(var);
Some(id)
} }
pub fn lower_body( pub fn lower(&self, id: FnID, p: &mut UProgram, output: &mut CompilerOutput) {
&self, let (args, ret) = if let Some(header) = self.header.as_ref() {
id: FnID, (
map: &mut IRUProgram, header
output: &mut CompilerOutput, .args
) -> IRUFunction { .iter()
let def = map.get_fn(id).clone(); .flat_map(|a| Some(a.lower(p, output)?.id))
let args = def.args.iter().map(|a| map.named_var(a.clone())).collect(); .collect(),
match &header.ret {
Some(ty) => ty.lower(p, output),
None => Type::Unit,
},
)
} else {
(Vec::new(), Type::Error)
};
let mut ctx = FnLowerCtx { let mut ctx = FnLowerCtx {
instructions: Vec::new(), instructions: Vec::new(),
program: map, program: p,
output, output,
span: self.body.span, span: self.body.span,
}; };
if let Some(src) = self.body.lower(&mut ctx) { if let Some(src) = self.body.lower(&mut ctx) {
ctx.instructions.push(IRUInstrInst { ctx.instructions.push(UInstrInst {
i: IRUInstruction::Ret { src }, i: UInstruction::Ret { src },
span: src.span, span: src.span,
}); });
} }
IRUFunction { let origin = self.header.span;
name: def.name.clone(), let f = UFunc {
origin,
args, args,
ret: def.ret, ret,
instructions: ctx.instructions, instructions: ctx.instructions,
} };
p.expect_mut(p.inv_fn_map[id.0]).ty = f.ty(p);
p.write(id, f)
} }
} }
pub struct FnLowerCtx<'a> { pub struct FnLowerCtx<'a> {
pub program: &'a mut IRUProgram, pub program: &'a mut UProgram,
pub instructions: Vec<IRUInstrInst>, pub instructions: Vec<UInstrInst>,
pub output: &'a mut CompilerOutput, pub output: &'a mut CompilerOutput,
pub span: FileSpan, pub span: FileSpan,
} }
impl FnLowerCtx<'_> { impl FnLowerCtx<'_> {
pub fn get(&mut self, node: &Node<parser::PIdent>) -> Option<Idents> { pub fn get_idents(&mut self, node: &Node<parser::PIdent>) -> Option<Idents> {
let name = node.inner.as_ref()?; let name = node.inner.as_ref()?;
let res = self.program.get(name); let res = self.program.get_idents(name);
if res.is_none() { if res.is_none() {
self.err_at(node.span, format!("Identifier '{}' not found", name)); self.err_at(node.span, format!("Identifier '{}' not found", name));
} }
res res
} }
pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> Option<VarInst> { pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> Option<VarInst> {
let ids = self.get(node)?; let ids = self.get_idents(node)?;
if ids.var.is_none() { if ids.get::<UVar>().is_none() {
self.err_at( self.err_at(
node.span, node.span,
format!( format!("Variable '{}' not found", node.inner.as_ref()?),
"Variable '{}' not found; Type found but cannot be used here",
node.inner.as_ref()?
),
); );
} }
ids.var.map(|id| VarInst { ids.get::<UVar>().map(|id| VarInst {
id, id,
span: node.span, span: node.span,
}) })
@@ -121,11 +113,11 @@ impl FnLowerCtx<'_> {
pub fn temp_subvar(&mut self, ty: Type, parent: FieldRef) -> VarInst { pub fn temp_subvar(&mut self, ty: Type, parent: FieldRef) -> VarInst {
self.program.temp_subvar(self.span, ty, parent) self.program.temp_subvar(self.span, ty, parent)
} }
pub fn push(&mut self, i: IRUInstruction) { pub fn push(&mut self, i: UInstruction) {
self.instructions.push(IRUInstrInst { i, span: self.span }); self.instructions.push(UInstrInst { i, span: self.span });
} }
pub fn push_at(&mut self, i: IRUInstruction, span: FileSpan) { pub fn push_at(&mut self, i: UInstruction, span: FileSpan) {
self.instructions.push(IRUInstrInst { i, span }); self.instructions.push(UInstrInst { i, span });
} }
pub fn branch<'a>(&'a mut self) -> FnLowerCtx<'a> { pub fn branch<'a>(&'a mut self) -> FnLowerCtx<'a> {
FnLowerCtx { FnLowerCtx {

View File

@@ -1,25 +1,25 @@
use crate::ir::IRUProgram; use crate::ir::UProgram;
use super::{PModule, CompilerOutput}; use super::{CompilerOutput, PModule};
impl PModule { impl PModule {
pub fn lower(&self, p: &mut IRUProgram, output: &mut CompilerOutput) { pub fn lower(&self, p: &mut UProgram, output: &mut CompilerOutput) {
let mut structs = Vec::new();
for s in &self.structs { for s in &self.structs {
s.lower(p, output); structs.push(s.lower_name(p));
}
for (s, id) in self.structs.iter().zip(structs) {
if let Some(id) = id {
s.lower(id, p, output);
}
} }
let mut fns = Vec::new(); let mut fns = Vec::new();
for f in &self.functions { for f in &self.functions {
if let Some(id) = f.lower_header(p, output) { fns.push(f.lower_name(p));
fns.push(Some(id));
} else {
fns.push(None)
}
} }
for (f, id) in self.functions.iter().zip(fns) { for (f, id) in self.functions.iter().zip(fns) {
if let Some(id) = id { if let Some(id) = id {
if let Some(res) = f.lower_body(id, p, output) { f.lower(id, p, output)
p.write_fn(id, res);
}
} }
} }
} }

View File

@@ -2,7 +2,7 @@ use std::collections::HashMap;
use crate::{ use crate::{
common::{CompilerOutput, FileSpan}, common::{CompilerOutput, FileSpan},
ir::{FieldID, IRUInstruction, IRUProgram, StructDef, StructField, Type, VarInst}, ir::{FieldID, StructField, StructID, Type, UInstruction, UProgram, UStruct, VarInst},
parser::{Node, PConstruct, PConstructFields, PStruct, PStructFields}, parser::{Node, PConstruct, PConstructFields, PStruct, PStructFields},
}; };
@@ -13,7 +13,7 @@ impl FnLowerable for PConstruct {
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
let ty = self.name.lower(ctx.program, ctx.output); let ty = self.name.lower(ctx.program, ctx.output);
let field_map = match ty { let field_map = match ty {
Type::Struct { id, .. } => ctx.program.get_struct(id), Type::Struct { id, .. } => ctx.program.expect(id),
_ => { _ => {
ctx.err(format!( ctx.err(format!(
"Type {} cannot be constructed", "Type {} cannot be constructed",
@@ -62,7 +62,7 @@ impl FnLowerable for PConstruct {
PConstructFields::None => Default::default(), PConstructFields::None => Default::default(),
}; };
let id = ctx.temp(ty); let id = ctx.temp(ty);
ctx.push(IRUInstruction::Construct { dest: id, fields }); ctx.push(UInstruction::Construct { dest: id, fields });
Some(id) Some(id)
} }
} }
@@ -70,7 +70,8 @@ impl FnLowerable for PConstruct {
impl PStruct { impl PStruct {
pub fn lower( pub fn lower(
&self, &self,
p: &mut IRUProgram, id: StructID,
p: &mut UProgram,
output: &mut CompilerOutput, output: &mut CompilerOutput,
span: FileSpan, span: FileSpan,
) -> Option<()> { ) -> Option<()> {
@@ -99,23 +100,30 @@ impl PStruct {
.into_iter() .into_iter()
.enumerate() .enumerate()
.map(|(i, (name, ty))| { .map(|(i, (name, ty))| {
let id = FieldID(i); let id = FieldID::new(i);
field_map.insert(name.clone(), id); field_map.insert(name.clone(), id);
StructField { name, ty } StructField { name, ty }
}) })
.collect(); .collect();
p.def_struct(StructDef { p.write(
name: self.name.as_ref()?.to_string(), id,
UStruct {
origin: span, origin: span,
field_map, field_map,
fields, fields,
}); },
);
Some(()) Some(())
} }
} }
impl Node<PStruct> { impl Node<PStruct> {
pub fn lower(&self, p: &mut IRUProgram, output: &mut CompilerOutput) { pub fn lower_name(&self, p: &mut UProgram) -> Option<StructID> {
self.as_ref().map(|i| i.lower(p, output, self.span)); let name = self.as_ref()?.name.as_ref()?.to_string();
let id = p.def_searchable(name.to_string(), None);
Some(id)
}
pub fn lower(&self, id: StructID, p: &mut UProgram, output: &mut CompilerOutput) {
self.as_ref().map(|i| i.lower(id, p, output, self.span));
} }
} }