huge refactor, can now define structs out of order
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
57
src/ir/id.rs
57
src/ir/id.rs
@@ -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> {}
|
||||||
|
|||||||
@@ -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 { .. })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
common::FileSpan,
|
|
||||||
ir::{FieldID, Len, StructID, VarID},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::Type;
|
|
||||||
use std::{collections::HashMap, fmt::Debug};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct FnDef {
|
|
||||||
pub name: String,
|
|
||||||
pub args: Vec<VarDef>,
|
|
||||||
pub ret: Type,
|
|
||||||
pub origin: Origin,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct StructField {
|
|
||||||
pub name: String,
|
|
||||||
pub ty: Type,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct StructDef {
|
|
||||||
pub name: String,
|
|
||||||
pub fields: Vec<StructField>,
|
|
||||||
pub field_map: HashMap<String, FieldID>,
|
|
||||||
pub origin: Origin,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct VarDef {
|
|
||||||
pub name: String,
|
|
||||||
pub parent: Option<FieldRef>,
|
|
||||||
pub ty: Type,
|
|
||||||
pub origin: Origin,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
|
||||||
pub struct VarOffset {
|
|
||||||
pub id: VarID,
|
|
||||||
pub offset: Len,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
|
||||||
pub struct FieldRef {
|
|
||||||
pub var: VarID,
|
|
||||||
// this is technically redundant bc you can get it from the var...
|
|
||||||
// but it makes things a lot easier, and you'd have to recheck the fields anyways
|
|
||||||
pub struc: StructID,
|
|
||||||
pub field: FieldID,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct DataDef {
|
|
||||||
pub ty: Type,
|
|
||||||
pub origin: Origin,
|
|
||||||
pub label: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Origin = FileSpan;
|
|
||||||
|
|
||||||
impl FnDef {
|
|
||||||
pub fn ty(&self) -> Type {
|
|
||||||
Type::Fn {
|
|
||||||
args: self.args.iter().map(|a| a.ty.clone()).collect(),
|
|
||||||
ret: Box::new(self.ret.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StructDef {
|
|
||||||
pub fn field(&self, id: FieldID) -> &StructField {
|
|
||||||
&self.fields[id.0]
|
|
||||||
}
|
|
||||||
pub fn get_field(&self, name: &str) -> Option<&StructField> {
|
|
||||||
self.field_map.get(name).map(|id| self.field(*id))
|
|
||||||
}
|
|
||||||
pub fn iter_fields(&self) -> impl Iterator<Item = (FieldID, &StructField)> {
|
|
||||||
self.fields.iter().enumerate().map(|(i, f)| (FieldID(i), f))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
|
use 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
160
src/ir/upper/kind.rs
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
use crate::{
|
||||||
|
common::FileSpan,
|
||||||
|
ir::{Len, Named, ID},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{Type, UInstrInst, UProgram};
|
||||||
|
use std::{collections::HashMap, fmt::Debug};
|
||||||
|
|
||||||
|
pub const NAMED_KINDS: usize = 4;
|
||||||
|
|
||||||
|
pub struct UFunc {
|
||||||
|
pub args: Vec<VarID>,
|
||||||
|
pub ret: Type,
|
||||||
|
pub origin: Origin,
|
||||||
|
pub instructions: Vec<UInstrInst>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct StructField {
|
||||||
|
pub name: String,
|
||||||
|
pub ty: Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct UStruct {
|
||||||
|
pub fields: Vec<StructField>,
|
||||||
|
pub field_map: HashMap<String, FieldID>,
|
||||||
|
pub origin: Origin,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct UVar {
|
||||||
|
pub parent: Option<FieldRef>,
|
||||||
|
pub ty: Type,
|
||||||
|
pub origin: Origin,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
|
pub struct VarOffset {
|
||||||
|
pub id: VarID,
|
||||||
|
pub offset: Len,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
|
pub struct FieldRef {
|
||||||
|
pub var: VarID,
|
||||||
|
// this is technically redundant bc you can get it from the var...
|
||||||
|
// but it makes things a lot easier, and you'd have to recheck the fields anyways
|
||||||
|
pub struc: StructID,
|
||||||
|
pub field: FieldID,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct UData {
|
||||||
|
pub ty: Type,
|
||||||
|
pub origin: Origin,
|
||||||
|
pub content: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Origin = FileSpan;
|
||||||
|
|
||||||
|
impl UFunc {
|
||||||
|
pub fn ty(&self, program: &UProgram) -> Type {
|
||||||
|
Type::Fn {
|
||||||
|
args: self
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.map(|a| program.expect(*a).ty.clone())
|
||||||
|
.collect(),
|
||||||
|
ret: Box::new(self.ret.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UStruct {
|
||||||
|
pub fn field(&self, id: FieldID) -> &StructField {
|
||||||
|
&self.fields[id.0]
|
||||||
|
}
|
||||||
|
pub fn get_field(&self, name: &str) -> Option<&StructField> {
|
||||||
|
self.field_map.get(name).map(|id| self.field(*id))
|
||||||
|
}
|
||||||
|
pub fn iter_fields(&self) -> impl Iterator<Item = (FieldID, &StructField)> {
|
||||||
|
self.fields
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, f)| (FieldID::new(i), f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type StructID = ID<UStruct>;
|
||||||
|
pub type VarID = ID<UVar>;
|
||||||
|
pub type DataID = ID<UData>;
|
||||||
|
pub type FieldID = ID<StructField>;
|
||||||
|
pub type FnID = ID<UFunc>;
|
||||||
|
|
||||||
|
impl Kind for UFunc {
|
||||||
|
const INDEX: usize = 0;
|
||||||
|
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||||
|
&mut program.fns
|
||||||
|
}
|
||||||
|
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||||
|
&program.fns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Named for UFunc {
|
||||||
|
const NAME: &str = "func";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kind for UVar {
|
||||||
|
const INDEX: usize = 1;
|
||||||
|
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||||
|
&mut program.vars
|
||||||
|
}
|
||||||
|
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||||
|
&program.vars
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Named for UVar {
|
||||||
|
const NAME: &str = "var";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kind for UStruct {
|
||||||
|
const INDEX: usize = 2;
|
||||||
|
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||||
|
&mut program.structs
|
||||||
|
}
|
||||||
|
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||||
|
&program.structs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Named for UStruct {
|
||||||
|
const NAME: &str = "struct";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kind for UData {
|
||||||
|
const INDEX: usize = 3;
|
||||||
|
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||||
|
&mut program.data
|
||||||
|
}
|
||||||
|
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||||
|
&program.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Named for UData {
|
||||||
|
const NAME: &str = "data";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Named for StructField {
|
||||||
|
const NAME: &str = "field";
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Kind {
|
||||||
|
const INDEX: usize;
|
||||||
|
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
fn from_program(program: &UProgram) -> &Vec<Option<Self>>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
mod def;
|
mod 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::*;
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
47
src/main.rs
47
src/main.rs
@@ -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) {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user