trudging through the snow

This commit is contained in:
2025-05-06 23:27:30 -04:00
parent 9368d6dcd0
commit 0016ede873
29 changed files with 1375 additions and 1085 deletions

40
ideas
View File

@@ -1,21 +1,27 @@
struct move names into separate vec with origins
make struct fields a vec, resolve into index
Type inner values that auto generate map function:
structinst enum Thing<inner T> {
bits A(T),
B(T, T),
but type is already typeinst? C
}
for each var, create list of constraints on type or
then just need to iterate through constraints to determine type #[derive(Map(T))]
keep doing passes for vars that depend on the type of other vars enum Thing<T> { ... }
really need to make subvar for each field of struct var so 2 different "a.b" refer to same thing
makes borrow checking easier
do dependency cycles exist?
for global vars yes, in functions no
but if function returns are inferrable (even if just "impl Trait"), then needed in functions?
every kind has an origin, should make separate like names?
{([<
std::Option:(u32)::Some(3)
func:(u32)("hello", test, 3);
std::Option:[u32]::Some(3)
func:[T]("hello", test, 3);
std::Option::<u32>::Some(3)
func::<u32>(3)
std.Option.[u32].Some(3)
func.[T]("hello", test, 3);
std::Option:<u32>::Some(3)
func:<u32>(3)
TYPE IDS!!!!! MY SAVIOR!!! MY GOAT!!!

View File

@@ -68,6 +68,83 @@ pub enum LinkerInstruction<R = Reg, S = Symbol> {
imm: i32, imm: i32,
}, },
} }
impl<R, S> LinkerInstruction<R, S> {
pub fn map<R2, S2>(&self, r: impl Fn(&R) -> R2) -> LinkerInstruction<R2, S2> {
self.try_map(|v| Some(r(v))).unwrap()
}
pub fn try_map<R2, S2>(&self, r: impl Fn(&R) -> Option<R2>) -> Option<LinkerInstruction<R2, S2>> {
use LinkerInstruction as I;
Some(match self {
Self::ECall => I::ECall,
Self::EBreak => I::EBreak,
&Self::Li { ref dest, imm } => I::Li { dest: r(dest)?, imm },
Self::Mv { ref dest, src } => I::Mv {
dest: r(dest)?,
src: r(src)?,
},
Self::La { .. } => todo!(),
&Self::Load {
width,
ref dest,
ref base,
offset,
} => I::Load {
width,
dest: r(dest)?,
offset,
base: r(base)?,
},
&Self::Store {
width,
ref src,
ref base,
offset,
} => I::Store {
width,
src: r(src)?,
offset,
base: r(base)?,
},
&Self::Op {
op,
funct,
ref dest,
ref src1,
ref src2,
} => I::Op {
op,
funct,
dest: r(dest)?,
src1: r(src1)?,
src2: r(src2)?,
},
&Self::OpImm { op, ref dest, ref src, imm } => I::OpImm {
op,
dest: r(dest)?,
src: r(src)?,
imm,
},
&Self::OpImmF7 {
op,
funct,
ref dest,
ref src,
imm,
} => I::OpImmF7 {
op,
funct,
dest: r(dest)?,
src: r(src)?,
imm,
},
Self::Ret => I::Ret,
Self::Call(..) => todo!(),
Self::Jal { .. } => todo!(),
Self::J(..) => todo!(),
Self::Branch { .. } => todo!(),
})
}
}
pub fn addi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> RawInstruction { pub fn addi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> RawInstruction {
opi(op32i::ADD, dest, src, imm.to_u()) opi(op32i::ADD, dest, src, imm.to_u())

View File

@@ -2,10 +2,7 @@ use std::collections::HashMap;
use crate::{ use crate::{
compiler::{arch::riscv::Reg, debug::DebugInfo, UnlinkedFunction, UnlinkedProgram}, compiler::{arch::riscv::Reg, debug::DebugInfo, UnlinkedFunction, UnlinkedProgram},
ir::{ ir::{arch::riscv64::RegRef, LInstruction as IRI, LProgram, Len, Size, VarID},
arch::riscv64::{RV64Instruction as AI, RegRef},
LInstruction as IRI, LProgram, Len, Size,
},
}; };
use super::{LinkerInstruction as LI, *}; use super::{LinkerInstruction as LI, *};
@@ -103,8 +100,8 @@ pub fn compile(program: &LProgram) -> UnlinkedProgram<LI> {
irli.push((v.len(), format!("{i:?}"))); irli.push((v.len(), format!("{i:?}")));
match i { match i {
IRI::Mv { IRI::Mv {
dest, dst: dest,
dest_offset, dst_offset: dest_offset,
src, src,
src_offset, src_offset,
} => { } => {
@@ -119,11 +116,15 @@ pub fn compile(program: &LProgram) -> UnlinkedProgram<LI> {
s, s,
); );
} }
IRI::Ref { dest, src } => { IRI::Ref { dst: dest, src } => {
v.push(LI::addi(t0, sp, stack[src])); v.push(LI::addi(t0, sp, stack[src]));
v.push(LI::sd(t0, stack[dest], sp)); v.push(LI::sd(t0, stack[dest], sp));
} }
IRI::LoadAddr { dest, offset, src } => { IRI::LoadAddr {
dst: dest,
offset,
src,
} => {
v.extend([ v.extend([
LI::La { LI::La {
dest: t0, dest: t0,
@@ -133,7 +134,7 @@ pub fn compile(program: &LProgram) -> UnlinkedProgram<LI> {
]); ]);
} }
IRI::LoadData { IRI::LoadData {
dest, dst: dest,
offset, offset,
src, src,
len, len,
@@ -144,7 +145,7 @@ pub fn compile(program: &LProgram) -> UnlinkedProgram<LI> {
}); });
mov_mem(&mut v, t0, 0, sp, stack[dest] + *offset as i32, t1, *len); mov_mem(&mut v, t0, 0, sp, stack[dest] + *offset as i32, t1, *len);
} }
IRI::Call { dest, f, args } => { IRI::Call { dst: dest, f, args } => {
let mut offset = 0; let mut offset = 0;
if let Some((dest, s)) = dest { if let Some((dest, s)) = dest {
offset -= align(s); offset -= align(s);
@@ -166,82 +167,14 @@ pub fn compile(program: &LProgram) -> UnlinkedProgram<LI> {
for (reg, var) in inputs { for (reg, var) in inputs {
v.push(LI::ld(*reg, stack[var], sp)); v.push(LI::ld(*reg, stack[var], sp));
} }
fn r(rr: RegRef) -> Reg { fn r(rr: &RegRef<VarID>) -> Reg {
match rr { match rr {
RegRef::Var(..) => todo!(), RegRef::Var(..) => todo!(),
RegRef::Reg(reg) => reg, RegRef::Reg(reg) => *reg,
} }
} }
for i in instructions { for i in instructions {
match *i { v.push(i.map(|v| r(v)));
AI::ECall => v.push(LI::ECall),
AI::EBreak => v.push(LI::EBreak),
AI::Li { dest, imm } => v.push(LI::Li { dest: r(dest), imm }),
AI::Mv { dest, src } => v.push(LI::Mv {
dest: r(dest),
src: r(src),
}),
AI::La { .. } => todo!(),
AI::Load {
width,
dest,
base,
offset,
} => v.push(LI::Load {
width,
dest: r(dest),
offset,
base: r(base),
}),
AI::Store {
width,
src,
base,
offset,
} => v.push(LI::Store {
width,
src: r(src),
offset,
base: r(base),
}),
AI::Op {
op,
funct,
dest,
src1,
src2,
} => v.push(LI::Op {
op,
funct,
dest: r(dest),
src1: r(src1),
src2: r(src2),
}),
AI::OpImm { op, dest, src, imm } => v.push(LI::OpImm {
op,
dest: r(dest),
src: r(src),
imm,
}),
AI::OpImmF7 {
op,
funct,
dest,
src,
imm,
} => v.push(LI::OpImmF7 {
op,
funct,
dest: r(dest),
src: r(src),
imm,
}),
AI::Ret => v.push(LI::Ret),
AI::Call(..) => todo!(),
AI::Jal { .. } => todo!(),
AI::J(..) => todo!(),
AI::Branch { .. } => todo!(),
}
} }
for (reg, var) in outputs { for (reg, var) in outputs {
v.push(LI::sd(*reg, stack[var], sp)); v.push(LI::sd(*reg, stack[var], sp));

View File

@@ -1,14 +1,16 @@
use crate::{compiler::arch::riscv::*, ir::UIdent}; use std::fmt::Debug;
pub type RV64Instruction = LinkerInstruction<RegRef, UIdent>; use crate::{compiler::arch::riscv::*, ir::IdentID};
pub type RV64Instruction<V = IdentID> = LinkerInstruction<RegRef<V>, V>;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum RegRef { pub enum RegRef<V = IdentID, R = Reg> {
Var(UIdent), Var(V),
Reg(Reg), Reg(R),
} }
impl std::fmt::Debug for RegRef { impl<V: Debug, R: Debug> Debug for RegRef<V, R> {
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::Var(v) => write!(f, "{{{:?}}}", v), Self::Var(v) => write!(f, "{{{:?}}}", v),
@@ -16,4 +18,3 @@ impl std::fmt::Debug for RegRef {
} }
} }
} }

View File

@@ -1,16 +1,7 @@
use crate::compiler::arch::riscv::Reg; use super::{arch::riscv64::RegRef, IdentID};
use super::VarID;
#[derive(Clone)] #[derive(Clone)]
pub struct IRAsmInstruction { pub struct IRAsmInstruction {
op: String, op: String,
args: Vec<RegRef>, args: Vec<RegRef<IdentID, String>>,
} }
#[derive(Clone)]
pub enum RegRef {
Var(VarID),
Reg(String),
}

View File

@@ -1,5 +1,5 @@
use super::*; use super::*;
use crate::compiler::arch::riscv::Reg; use crate::{compiler::arch::riscv::Reg, ir::arch::riscv64::RegRef};
use arch::riscv64::RV64Instruction; use arch::riscv64::RV64Instruction;
use std::collections::HashMap; use std::collections::HashMap;
@@ -16,33 +16,33 @@ pub struct IRLFunction {
#[derive(Debug)] #[derive(Debug)]
pub enum LInstruction { pub enum LInstruction {
Mv { Mv {
dest: VarID, dst: VarID,
dest_offset: Size, dst_offset: Size,
src: VarID, src: VarID,
src_offset: Size, src_offset: Size,
}, },
Ref { Ref {
dest: VarID, dst: VarID,
src: VarID, src: VarID,
}, },
LoadAddr { LoadAddr {
dest: VarID, dst: VarID,
offset: Size, offset: Size,
src: Symbol, src: Symbol,
}, },
LoadData { LoadData {
dest: VarID, dst: VarID,
offset: Size, offset: Size,
src: Symbol, src: Symbol,
len: Len, len: Len,
}, },
Call { Call {
dest: Option<(VarID, Size)>, dst: Option<(VarID, Size)>,
f: Symbol, f: Symbol,
args: Vec<(VarID, Size)>, args: Vec<(VarID, Size)>,
}, },
AsmBlock { AsmBlock {
instructions: Vec<RV64Instruction>, instructions: Vec<RV64Instruction<VarID>>,
inputs: Vec<(Reg, VarID)>, inputs: Vec<(Reg, VarID)>,
outputs: Vec<(Reg, VarID)>, outputs: Vec<(Reg, VarID)>,
}, },

View File

@@ -1,6 +1,7 @@
mod func; mod func;
mod program; mod program;
mod symbol; mod symbol;
mod res;
pub use func::*; pub use func::*;
pub use program::*; pub use program::*;

View File

@@ -1,10 +1,11 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::ir::{AsmBlockArgType, Size, LStructInst, SymbolSpace, Type, UFunc, UInstrInst, VarOffset};
LStructInst
use super::{ use super::{
IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, UInstruction, UProgram, VarID, IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, UInstruction, UProgram, VarID,
}; };
use crate::ir::{
AsmBlockArgType, Size, StructInst, SymbolSpace, Type, TypeID, UFunc, UInstrInst, VarOffset,
};
pub struct LProgram { pub struct LProgram {
sym_space: SymbolSpace, sym_space: SymbolSpace,
@@ -22,7 +23,7 @@ impl LProgram {
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];
let mut fbuilder = LFunctionBuilder::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);
@@ -31,7 +32,7 @@ impl LProgram {
fbuilder.instrs.push(LInstruction::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(p.names.path(i).to_string())); ssbuilder.write_fn(sym, res, Some(f.name.clone()));
} }
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 })
@@ -82,7 +83,7 @@ pub struct LFunctionBuilderData<'a> {
instrs: Vec<LInstruction>, instrs: Vec<LInstruction>,
stack: HashMap<VarID, Size>, stack: HashMap<VarID, Size>,
subvar_map: HashMap<VarID, VarOffset>, subvar_map: HashMap<VarID, VarOffset>,
struct_insts: HashMap<LStructInst, LStructInst>, struct_insts: HashMap<StructInst, LStructInst>,
makes_call: bool, makes_call: bool,
loopp: Option<LoopCtx>, loopp: Option<LoopCtx>,
} }
@@ -127,44 +128,48 @@ impl<'a> LFunctionBuilder<'a> {
} }
} }
pub fn insert_instr(&mut self, i: &UInstrInst) -> Option<Option<String>> { pub fn insert_instr(&mut self, i: &UInstrInst) -> Option<Option<String>> {
match &i.i { match i
UInstruction::Mv { dst: dest, src } => { .i
self.alloc_stack(dest.id)?; .resolve(self.program)
self.map_subvar(src.id); .expect("failed to resolve during lowering")
{
UInstruction::Mv { dst, src } => {
self.alloc_stack(dst)?;
self.map_subvar(src);
self.instrs.push(LInstruction::Mv { self.instrs.push(LInstruction::Mv {
dest: dest.id, dst,
dest_offset: 0, dst_offset: 0,
src: src.id, src,
src_offset: 0, src_offset: 0,
}); });
} }
UInstruction::Ref { dst: dest, src } => { UInstruction::Ref { dst, src } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dst)?;
self.map_subvar(src.id); self.map_subvar(src);
self.instrs.push(LInstruction::Ref { self.instrs.push(LInstruction::Ref { dst, src });
dest: dest.id,
src: src.id,
});
} }
UInstruction::LoadData { dst: dest, src } => { UInstruction::Deref { dst, src } => {
self.alloc_stack(dest.id)?; todo!()
let data = self.program.expect(*src); }
UInstruction::LoadData { dst, src } => {
self.alloc_stack(dst)?;
let data = &self.program.data[src];
let sym = self.data.builder.ro_data( let sym = self.data.builder.ro_data(
src, src,
&data.content, &data.content,
Some(self.program.names.path(dest.id).to_string()), Some(&self.program.data[src].name),
); );
self.instrs.push(LInstruction::LoadData { self.instrs.push(LInstruction::LoadData {
dest: dest.id, dst,
offset: 0, offset: 0,
len: data.content.len() as Len, len: data.content.len() as Len,
src: sym, src: sym,
}); });
} }
UInstruction::LoadSlice { dst: dest, src } => { UInstruction::LoadSlice { dst, src } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dst)?;
let data = self.program.expect(*src); let data = &self.program.data[src];
let Type::Array(_, len) = &data.ty else { let Type::Array(_, len) = &self.program.types[data.ty] else {
return Some(Some(format!( return Some(Some(format!(
"tried to load {} as slice", "tried to load {} as slice",
self.program.type_name(&data.ty) self.program.type_name(&data.ty)
@@ -173,10 +178,10 @@ impl<'a> LFunctionBuilder<'a> {
let sym = self.data.builder.ro_data( let sym = self.data.builder.ro_data(
src, src,
&data.content, &data.content,
Some(self.program.names.path(dest.id).to_string()), Some(&self.program.data[src].name),
); );
self.instrs.push(LInstruction::LoadAddr { self.instrs.push(LInstruction::LoadAddr {
dest: dest.id, dst,
offset: 0, offset: 0,
src: sym, src: sym,
}); });
@@ -185,46 +190,36 @@ impl<'a> LFunctionBuilder<'a> {
.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(LInstruction::LoadData { self.instrs.push(LInstruction::LoadData {
dest: dest.id, dst,
offset: 8, offset: 8,
len: 8, len: 8,
src: sym, src: sym,
}); });
} }
UInstruction::LoadFn { dst: dest, src } => { UInstruction::Call { dst, f, args } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dst);
let sym = self.builder.func(src);
self.instrs.push(LInstruction::LoadAddr {
dest: dest.id,
offset: 0,
src: sym,
});
}
UInstruction::Call { dst: dest, f, args } => {
self.alloc_stack(dest.id);
self.makes_call = true; self.makes_call = true;
let fid = &self.program.fn_var.fun(f.id).expect("a"); let sym = self.builder.func(f.id);
let sym = self.builder.func(fid);
let ret_size = self let ret_size = self
.data .data
.size_of_var(self.program, dest.id) .size_of_var(self.program, dst)
.expect("unsized type"); .expect("unsized type");
let dest = if ret_size > 0 { let dst = if ret_size > 0 {
Some((dest.id, ret_size)) Some((dst, ret_size))
} else { } else {
None None
}; };
let call = LInstruction::Call { let call = LInstruction::Call {
dest, dst,
f: sym, f: sym,
args: args args: args
.iter() .into_iter()
.map(|a| { .map(|id| {
self.map_subvar(a.id); self.map_subvar(id);
( (
a.id, id,
self.data self.data
.size_of_var(self.program, a.id) .size_of_var(self.program, id)
.expect("unsized type"), .expect("unsized type"),
) )
}) })
@@ -238,12 +233,12 @@ impl<'a> LFunctionBuilder<'a> {
for a in args { for a in args {
match a.ty { match a.ty {
AsmBlockArgType::In => { AsmBlockArgType::In => {
self.map_subvar(a.var.id); self.map_subvar(a.var);
inputs.push((a.reg, a.var.id)) inputs.push((a.reg, a.var))
} }
AsmBlockArgType::Out => { AsmBlockArgType::Out => {
self.alloc_stack(a.var.id)?; self.alloc_stack(a.var)?;
outputs.push((a.reg, a.var.id)); outputs.push((a.reg, a.var));
} }
} }
} }
@@ -254,33 +249,33 @@ impl<'a> LFunctionBuilder<'a> {
}) })
} }
UInstruction::Ret { src } => { UInstruction::Ret { src } => {
self.map_subvar(src.id); self.map_subvar(src);
let src = if self let src = if self
.data .data
.size_of_var(self.program, src.id) .size_of_var(self.program, src)
.expect("unsized var") .expect("unsized var")
== 0 == 0
{ {
None None
} else { } else {
Some(src.id) Some(src)
}; };
self.data.instrs.push(LInstruction::Ret { src }) self.data.instrs.push(LInstruction::Ret { src })
} }
UInstruction::Construct { dst: dest, fields } => { UInstruction::Construct {
let sty = &self.program.expect_type(dest.id); dst,
let Type::Struct(sty) = sty else { ref struc,
panic!("bruh htis aint' a struct"); ref fields,
}; } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dst)?;
for (field, var) in fields { for (field, &src) in fields {
self.map_subvar(var.id); self.map_subvar(src);
let i = LInstruction::Mv { let i = LInstruction::Mv {
dest: dest.id, dst,
src: var.id, src,
dest_offset: self dst_offset: self
.data .data
.field_offset(self.program, sty, field) .field_offset(self.program, struc, field)
.expect("field offset"), .expect("field offset"),
src_offset: 0, src_offset: 0,
}; };
@@ -288,14 +283,11 @@ impl<'a> LFunctionBuilder<'a> {
} }
} }
UInstruction::If { cond, body } => { UInstruction::If { cond, body } => {
self.map_subvar(cond.id); self.map_subvar(cond);
let sym = self.builder.reserve(); let sym = self.builder.reserve();
self.instrs.push(LInstruction::Branch { self.instrs.push(LInstruction::Branch { to: *sym, cond });
to: *sym,
cond: cond.id,
});
for i in body { for i in body {
self.insert_instr(i); self.insert_instr(&i);
} }
self.instrs.push(LInstruction::Mark(*sym)); self.instrs.push(LInstruction::Mark(*sym));
} }
@@ -374,9 +366,9 @@ impl LFunctionBuilderData<'_> {
Some(VarOffset { id: var, offset }) Some(VarOffset { id: var, offset })
} }
pub fn addr_size(&self) -> Size { pub fn addr_size(&self) -> Size {
64StructTy 64
} }
pub fn struct_inst(&mut self, p: &UProgram, ty: &LStructInst) -> &LStructInst { pub fn struct_inst(&mut self, p: &UProgram, ty: &StructInst) -> &LStructInst {
// normally I'd let Some(..) here and return, but polonius does not exist :grief: // normally I'd let Some(..) here and return, but polonius does not exist :grief:
if self.struct_insts.get(ty).is_none() { if self.struct_insts.get(ty).is_none() {
let LStructInst { id, args } = ty; let LStructInst { id, args } = ty;
@@ -423,18 +415,20 @@ impl LFunctionBuilderData<'_> {
self.struct_insts.get(ty).unwrap() self.struct_insts.get(ty).unwrap()
} }
pub fn field_offset(&mut self, p: &UProgram, sty: &LStructInst, field: &str) -> Option<Len> { pub fn field_offset(&mut self, p: &UProgram, sty: &StructInst, field: &str) -> Option<Len> {
let inst = self.struct_inst(p, sty); let inst = self.struct_inst(p, sty);
Some(inst.offset(field)?) Some(inst.offset(field)?)
} }
pub fn size_of_type(&mut self, p: &UProgram, ty: &Type) -> Option<Size> { pub fn size_of_type(&mut self, p: &UProgram, ty: &TypeID) -> Option<Size> {
// TODO: target matters // TODO: target matters
Some(match p.follow_type(ty)? { Some(match &p.types[ty] {
Type::Bits(b) => *b, Type::Bits(b) => *b,
Type::Struct(ty) => self.struct_inst(p, ty).size, Type::Struct(ty) => self.struct_inst(p, ty).size,
Type::Generic { id } => return None, Type::Generic(id) => return None,
Type::Fn { args, ret } => todo!(), // function references are resolved at compile time into direct calls,
// so they don't have any size as arguments
Type::FnRef(fi) => 0,
Type::Ref(_) => self.addr_size(), Type::Ref(_) => self.addr_size(),
Type::Array(ty, len) => self.size_of_type(p, ty)? * len, Type::Array(ty, len) => self.size_of_type(p, ty)? * len,
Type::Slice(_) => self.addr_size() * 2, Type::Slice(_) => self.addr_size() * 2,

92
src/ir/lower/res.rs Normal file
View File

@@ -0,0 +1,92 @@
use crate::ir::{
arch::riscv64::{RV64Instruction, RegRef},
AsmBlockArg, Resolved, UInstrInst, UInstruction, UProgram, VarID,
};
impl UInstrInst {
pub fn resolve<'a>(&'a self, p: &'a UProgram) -> Option<UInstrInst<Resolved>> {
Some(UInstrInst {
i: self.i.resolve(p)?,
origin: self.origin,
})
}
}
impl UInstruction {
pub fn resolve<'a>(&'a self, p: &'a UProgram) -> Option<UInstruction<Resolved>> {
use UInstruction as I;
Some(match self {
I::Mv { dst, src } => I::Mv {
dst: dst.var(p)?,
src: src.var(p)?,
},
I::Ref { dst, src } => I::Ref {
dst: dst.var(p)?,
src: src.var(p)?,
},
I::Deref { dst, src } => I::Deref {
dst: dst.var(p)?,
src: src.var(p)?,
},
I::LoadData { dst, src } => I::LoadData {
dst: dst.var(p)?,
src: *src,
},
I::LoadSlice { dst, src } => I::LoadSlice {
dst: dst.var(p)?,
src: *src,
},
I::Call { dst, f, args } => I::Call {
dst: dst.var(p)?,
f: f.fun(p)?.clone(),
args: args.iter().map(|i| i.var(p)).try_collect()?,
},
I::AsmBlock { instructions, args } => I::AsmBlock {
instructions: instructions
.iter()
.map(|i| i.resolve(p))
.collect::<Option<_>>()?,
args: args.iter().map(|a| a.resolve(p)).try_collect()?,
},
I::Ret { src } => I::Ret { src: src.var(p)? },
I::Construct { dst, struc, fields } => I::Construct {
dst: dst.var(p)?,
struc: struc.struc(p)?.clone(),
fields: fields
.iter()
.map(|(name, ident)| ident.var(p).map(|i| (name.clone(), i)))
.collect::<Option<_>>()?,
},
I::If { cond, body } => I::If {
cond: cond.var(p)?,
body: body.iter().map(|i| i.resolve(p)).try_collect()?,
},
I::Loop { body } => I::Loop {
body: body.iter().map(|i| i.resolve(p)).try_collect()?,
},
I::Break => I::Break,
I::Continue => I::Continue,
})
}
}
impl AsmBlockArg {
pub fn resolve(&self, p: &UProgram) -> Option<AsmBlockArg<VarID>> {
Some(AsmBlockArg {
var: self.var.var(p)?,
reg: self.reg,
ty: self.ty,
})
}
}
impl RV64Instruction {
pub fn resolve(&self, p: &UProgram) -> Option<RV64Instruction<VarID>> {
self.try_map(|i| {
Some(match i {
RegRef::Var(v) => RegRef::Var(v.var(p)?),
RegRef::Reg(r) => RegRef::Reg(*r),
})
})
}
}

View File

@@ -62,7 +62,7 @@ impl SymbolSpaceBuilder {
pub fn with_entries(entries: &[FnID]) -> SymbolSpaceBuilder { pub fn with_entries(entries: &[FnID]) -> SymbolSpaceBuilder {
let mut s = Self::new(); let mut s = Self::new();
for e in entries { for e in entries {
s.func(e); s.func(*e);
} }
s s
} }
@@ -73,24 +73,24 @@ impl SymbolSpaceBuilder {
let sym = self.reserve(); let sym = self.reserve();
self.write_ro_data(sym, data.to_vec(), label) self.write_ro_data(sym, data.to_vec(), label)
} }
pub fn ro_data(&mut self, id: &DataID, data: &[u8], label: Option<String>) -> Symbol { pub fn ro_data(&mut self, id: DataID, data: &[u8], label: Option<&str>) -> Symbol {
match self.data_map.get(id) { match self.data_map.get(&id) {
Some(s) => *s, Some(s) => *s,
None => { None => {
let sym = self.reserve(); let sym = self.reserve();
self.data_map.insert(*id, *sym); self.data_map.insert(id, *sym);
self.write_ro_data(sym, data.to_vec(), label) self.write_ro_data(sym, data.to_vec(), label.map(|l| l.to_string()))
} }
} }
} }
pub fn func(&mut self, id: &FnID) -> Symbol { pub fn func(&mut self, id: FnID) -> Symbol {
match self.fn_map.get(id) { match self.fn_map.get(&id) {
Some(s) => *s, Some(s) => *s,
None => { None => {
let wsym = self.reserve(); let wsym = self.reserve();
let sym = *wsym; let sym = *wsym;
self.unwritten_fns.push((wsym, *id)); self.unwritten_fns.push((wsym, id));
self.fn_map.insert(*id, sym); self.fn_map.insert(id, sym);
sym sym
} }
} }

View File

@@ -1,3 +1,9 @@
//! the IR is split into 2 layers: upper and lower
//! upper handles all of the main language features like types,
//! and the lower is a very concrete format that can be easily
//! translated to assembly and will probably also include
//! the majority of optimization, but not sure
mod upper; mod upper;
mod lower; mod lower;
mod id; mod id;
@@ -7,3 +13,4 @@ pub mod arch;
pub use upper::*; pub use upper::*;
pub use lower::*; pub use lower::*;
pub use id::*; pub use id::*;

View File

@@ -1,11 +1,25 @@
use crate::{ use crate::common::{CompilerMsg, CompilerOutput};
common::{CompilerMsg, CompilerOutput},
ir::ID, use super::{
IdentStatus, KindTy, MemRes, MemberTy, Origin, Res, ResBase, StructID, Type, TypeID, UProgram
}; };
use super::{KindTy, Origin, Res, StructID, TypeID, UProgram}; pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, mut errs: Vec<ResErr>) {
for ident in &p.idents {
pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec<ResErr>) { match &ident.status {
IdentStatus::Unres { path, base } => {
let mem = path.last().unwrap();
errs.push(ResErr::UnknownMember {
ty: mem.ty,
name: mem.name.clone(),
origin: mem.origin,
parent: base.clone(),
})
}
IdentStatus::Failed(err) => errs.push(err.clone()),
_ => (),
}
}
for err in errs { for err in errs {
match err { match err {
ResErr::Type { ResErr::Type {
@@ -56,7 +70,7 @@ pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec<ResErr>)
origin, origin,
)); ));
} }
ResErr::UnknownField { origin, id, name } => { ResErr::UnknownStructField { origin, id, name } => {
output.err(CompilerMsg::new( output.err(CompilerMsg::new(
format!("Unknown field '{name}' in struct '{}'", p.structs[id].name), format!("Unknown field '{name}' in struct '{}'", p.structs[id].name),
origin, origin,
@@ -83,47 +97,48 @@ pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec<ResErr>)
found, found,
expected, expected,
} => output.err(CompilerMsg::new( } => output.err(CompilerMsg::new(
{ format!("Expected {expected}, found {}", found.display_str(p)),
let name = match &found { origin,
Res::Fn(fty) => &p.fns[fty.id].name, )),
Res::Type(id) => &p.type_name(id), ResErr::UnknownMember {
Res::Var(id) => &p.vars[id].name, origin,
Res::Struct(sty) => &p.structs[sty.id].name, ty,
}; name,
format!( parent,
"Expected {}, found {} '{}'", } => output.err(CompilerMsg::new(
expected.str(), format!("Unknown {ty} {name} of {}", parent.display_str(p)),
found.kind_str(),
name
)
},
origin, origin,
)), )),
ResErr::UnexpectedField { origin } => {
output.err(CompilerMsg::new(format!("Unexpected fields here"), origin))
} }
} }
for var in &p.vars {
match &p.types[var.ty] {
Type::Error => output.err(CompilerMsg::new(
format!("Var {:?} is error type!", var.name),
var.origin,
)),
Type::Infer => output.err(CompilerMsg::new(
format!("Type of {:?} cannot be inferred", var.name),
var.origin,
)),
_ => (),
}
} }
} }
#[derive(Debug, Clone)] #[derive(Clone)]
pub enum ResErr { pub enum ResErr {
UnknownModule {
origin: Origin,
name: String,
},
UnknownMember { UnknownMember {
origin: Origin, origin: Origin,
ty: MemberTy,
name: String, name: String,
parent: ResBase,
}, },
KindMismatch { KindMismatch {
origin: Origin, origin: Origin,
expected: KindTy, expected: KindTy,
found: Res, found: Res,
}, },
UnexpectedField {
origin: Origin,
},
GenericCount { GenericCount {
origin: Origin, origin: Origin,
expected: usize, expected: usize,
@@ -153,7 +168,7 @@ pub enum ResErr {
id: StructID, id: StructID,
name: String, name: String,
}, },
UnknownField { UnknownStructField {
origin: Origin, origin: Origin,
id: StructID, id: StructID,
name: String, name: String,

View File

@@ -1,153 +1,71 @@
use std::{collections::HashMap, fmt::Write}; use std::collections::HashMap;
use super::{arch::riscv64::RV64Instruction, DataID, FnID, Origin, UFunc, UIdent, IdentID}; use super::{arch::riscv64::RV64Instruction, DataID, IdentID, Origin, ResStage, Unresolved};
use crate::{compiler::arch::riscv::Reg, util::Padder}; use crate::compiler::arch::riscv::Reg;
#[derive(Clone)] pub enum UInstruction<S: ResStage = Unresolved> {
pub enum UInstruction {
Mv { Mv {
dst: IdentID, dst: S::Var,
src: IdentID, src: S::Var,
}, },
Ref { Ref {
dst: IdentID, dst: S::Var,
src: IdentID, src: S::Var,
}, },
Deref { Deref {
dst: IdentID, dst: S::Var,
src: IdentID, src: S::Var,
}, },
LoadData { LoadData {
dst: IdentID, dst: S::Var,
src: DataID, src: DataID,
}, },
LoadSlice { LoadSlice {
dst: IdentID, dst: S::Var,
src: DataID, src: DataID,
}, },
LoadFn {
dst: IdentID,
src: FnID,
},
Call { Call {
dst: IdentID, dst: S::Var,
f: IdentID, f: S::Func,
args: Vec<IdentID>, args: Vec<S::Var>,
}, },
AsmBlock { AsmBlock {
instructions: Vec<RV64Instruction>, instructions: Vec<RV64Instruction<S::Var>>,
args: Vec<AsmBlockArg>, args: Vec<AsmBlockArg<S::Var>>,
}, },
Ret { Ret {
src: IdentID, src: S::Var,
}, },
Construct { Construct {
dst: IdentID, dst: S::Var,
struc: IdentID, struc: S::Struct,
fields: HashMap<String, IdentID>, fields: HashMap<String, S::Var>,
}, },
If { If {
cond: IdentID, cond: S::Var,
body: Vec<UInstrInst>, body: Vec<UInstrInst<S>>,
}, },
Loop { Loop {
body: Vec<UInstrInst>, body: Vec<UInstrInst<S>>,
}, },
Break, Break,
Continue, Continue,
} }
#[derive(Clone)] pub struct UInstrInst<S: ResStage = Unresolved> {
pub struct UInstrInst { pub i: UInstruction<S>,
pub i: UInstruction,
pub origin: Origin, pub origin: Origin,
} }
impl std::fmt::Debug for UInstrInst {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.i)
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct AsmBlockArg { pub struct AsmBlockArg<V = IdentID> {
pub var: IdentID, pub var: V,
pub reg: Reg, pub reg: Reg,
pub ty: AsmBlockArgType, pub ty: AsmBlockArgType,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub enum AsmBlockArgType { pub enum AsmBlockArgType {
In, In,
Out, Out,
} }
impl std::fmt::Debug for UInstruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Mv { dst: dest, src } => write!(f, "{dest:?} <- {src:?}")?,
Self::Ref { dst: dest, src } => write!(f, "{dest:?} <- {src:?}&")?,
Self::Deref { dst: dest, src } => write!(f, "{dest:?} <- {src:?}^")?,
Self::LoadData { dst: dest, src } => write!(f, "{dest:?} <- {src:?}")?,
Self::LoadFn { dst: dest, src } => write!(f, "{dest:?} <- {src:?}")?,
Self::LoadSlice { dst: dest, src } => write!(f, "{dest:?} <- &[{src:?}]")?,
Self::Call {
dst: dest,
f: func,
args,
} => write!(f, "{dest:?} <- {func:?}({args:?})")?,
Self::AsmBlock { args, instructions } => write!(f, "asm {args:?} {instructions:#?}")?,
Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish()?,
Self::Construct { dst: dest, struc, fields } => write!(f, "{dest:?} <- {struc:?}{fields:?}")?,
Self::If { cond, body } => {
write!(f, "if {cond:?}:")?;
if !body.is_empty() {
f.write_str("{\n ")?;
let mut padder = Padder::new(f);
for i in body {
// they don't expose wrap_buf :grief:
padder.write_str(&format!("{i:?};\n"))?;
}
f.write_char('}')?;
} else {
f.write_str("{}")?;
}
}
Self::Loop { body } => {
write!(f, "loop:")?;
if !body.is_empty() {
f.write_str("{\n ")?;
let mut padder = Padder::new(f);
for i in body {
// they don't expose wrap_buf :grief:
padder.write_str(&format!("{i:?};\n"))?;
}
f.write_char('}')?;
} else {
f.write_str("{}")?;
}
}
Self::Break => write!(f, "break")?,
Self::Continue => write!(f, "continue")?,
}
Ok(())
}
}
impl std::fmt::Debug for UFunc {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.args)?;
if !self.instructions.is_empty() {
f.write_str("{\n ")?;
let mut padder = Padder::new(f);
for i in &self.instructions {
// they don't expose wrap_buf :grief:
padder.write_str(&format!("{i:?};\n"))?;
}
f.write_char('}')?;
} else {
f.write_str("{}")?;
}
Ok(())
}
}

View File

@@ -1,9 +1,37 @@
use super::{FnInst, ResErr, StructInst, Type, UInstrInst, UInstruction}; //! all main IR Upper data structures stored in UProgram
use super::{FnInst, ResErr, StructInst, Type, UInstrInst, UInstruction, UProgram};
use crate::{ use crate::{
common::FileSpan, common::FileSpan,
ir::{Len, ID}, ir::{Len, ID},
}; };
use std::{collections::HashMap, fmt::Debug}; use std::{
collections::HashMap,
fmt::{Debug, Display},
};
pub trait ResStage {
type Var;
type Func;
type Struct;
type Type;
}
pub struct Unresolved;
impl ResStage for Unresolved {
type Var = IdentID;
type Func = IdentID;
type Struct = IdentID;
type Type = IdentID;
}
pub struct Resolved;
impl ResStage for Resolved {
type Var = VarID;
type Func = FnInst;
type Struct = StructInst;
type Type = TypeID;
}
pub type NamePath = Vec<String>; pub type NamePath = Vec<String>;
@@ -16,7 +44,6 @@ pub type StructID = ID<UStruct>;
pub type DataID = ID<UData>; pub type DataID = ID<UData>;
pub type ModID = ID<UModule>; pub type ModID = ID<UModule>;
#[derive(Clone)]
pub struct UFunc { pub struct UFunc {
pub name: String, pub name: String,
pub origin: Origin, pub origin: Origin,
@@ -26,12 +53,12 @@ pub struct UFunc {
pub instructions: Vec<UInstrInst>, pub instructions: Vec<UInstrInst>,
} }
#[derive(Clone)]
pub struct StructField { pub struct StructField {
pub ty: TypeID, pub ty: TypeID,
pub origin: Origin,
// pub vis: Visibility
} }
#[derive(Clone)]
pub struct UStruct { pub struct UStruct {
pub name: String, pub name: String,
pub origin: Origin, pub origin: Origin,
@@ -39,13 +66,11 @@ pub struct UStruct {
pub gargs: Vec<GenericID>, pub gargs: Vec<GenericID>,
} }
#[derive(Clone)]
pub struct UGeneric { pub struct UGeneric {
pub name: String, pub name: String,
pub origin: Origin, pub origin: Origin,
} }
#[derive(Clone)]
pub struct UVar { pub struct UVar {
pub name: String, pub name: String,
pub origin: Origin, pub origin: Origin,
@@ -54,43 +79,53 @@ pub struct UVar {
pub children: HashMap<String, VarID>, pub children: HashMap<String, VarID>,
} }
/// eg. a::b::c::<T,U>.d.e /// a generic identifier for all (identifiable) kinds
#[derive(Clone, Debug)] /// eg. a::b::c.d.e
/// or a::Result<T,_>
pub struct UIdent { pub struct UIdent {
pub status: IdentStatus, pub status: IdentStatus,
pub origin: Origin, pub origin: Origin,
} }
#[derive(Clone, Debug)]
pub enum IdentStatus { pub enum IdentStatus {
Var(VarID), Res(Res),
Struct(StructInst),
Fn(FnInst),
Type(TypeID),
Unres { Unres {
path: ModPath, base: ResBase,
mem: MemberID, path: Vec<MemberIdent>,
gargs: Vec<TypeID>,
fields: Vec<MemberID>,
}, },
PartialVar { Failed(Option<ResErr>),
id: VarID,
fields: Vec<MemberID>,
},
Failed(ResErr),
Cooked, Cooked,
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct MemberIdent {
pub struct MemberID { pub ty: MemberTy,
pub name: String, pub name: String,
pub gargs: Vec<TypeID>,
pub origin: Origin, pub origin: Origin,
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Clone, Copy)]
pub struct ModPath { pub enum MemberTy {
pub id: ModID, Member,
pub path: Vec<MemberID>, Field,
}
impl MemberTy {
pub fn sep(&self) -> &'static str {
match self {
MemberTy::Member => "::",
MemberTy::Field => ".",
}
}
}
impl Display for MemberTy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
MemberTy::Member => "member",
MemberTy::Field => "field",
})
}
} }
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
@@ -110,25 +145,163 @@ pub struct UData {
pub struct UModule { pub struct UModule {
pub name: String, pub name: String,
pub members: HashMap<String, Member>, pub members: HashMap<String, Member>,
pub children: HashMap<String, ModID>,
pub parent: Option<ModID>, pub parent: Option<ModID>,
pub func: FnID,
} }
#[derive(Clone)] #[derive(Clone)]
pub struct Member { pub struct Member {
pub id: MemberTy, pub id: MemberID,
// pub visibility: Visibility // pub visibility: Visibility
} }
#[derive(Clone)] #[derive(Clone)]
pub enum MemberTy { pub enum MemberID {
Fn(FnID), Fn(FnID),
Struct(StructID), Struct(StructID),
Var(VarID), Var(VarID),
Module(ModID),
Type(TypeDef),
}
#[derive(Clone)]
pub struct TypeDef {
pub gargs: Vec<GenericID>,
pub ty: TypeID,
}
impl MemberID {
pub fn kind(&self) -> KindTy {
match self {
MemberID::Fn(_) => KindTy::Fn,
MemberID::Struct(_) => KindTy::Struct,
MemberID::Var(_) => KindTy::Var,
MemberID::Module(_) => KindTy::Module,
MemberID::Type(_) => KindTy::Type,
}
}
pub fn display_str(&self, p: &UProgram) -> String {
let name = match self {
MemberID::Var(id) => &p.vars[id].name,
MemberID::Fn(id) => &p.fns[id].name,
MemberID::Struct(id) => &p.structs[id].name,
MemberID::Module(id) => &p.modules[id].name,
MemberID::Type(id) => &p.type_name(id),
};
format!("{} '{}'", self.kind(), name)
}
} }
pub type Origin = FileSpan; pub type Origin = FileSpan;
// "effective" (externally visible) kinds
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KindTy {
Type,
Var,
Struct,
Fn,
Module,
Generic,
}
impl Display for KindTy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
KindTy::Type => "type",
KindTy::Var => "variable",
KindTy::Fn => "function",
KindTy::Struct => "struct",
KindTy::Module => "module",
KindTy::Generic => "generic",
})
}
}
#[derive(Debug, Clone)]
pub enum Res {
Var(VarID),
Fn(FnInst),
Struct(StructInst),
Type(TypeID),
Generic(GenericID),
Module(ModID),
}
impl Res {
pub fn kind(&self) -> KindTy {
match self {
Res::Var(..) => KindTy::Var,
Res::Fn(..) => KindTy::Fn,
Res::Struct(..) => KindTy::Struct,
Res::Type(..) => KindTy::Type,
Res::Module(..) => KindTy::Module,
Res::Generic(..) => KindTy::Generic,
}
}
pub fn display_str(&self, p: &UProgram) -> String {
let name = match self {
Res::Var(id) => &p.vars[id].name,
Res::Fn(fi) => &p.fns[fi.id].name,
Res::Struct(si) => &p.structs[si.id].name,
Res::Type(id) => &p.type_name(id),
Res::Generic(id) => &p.generics[id].name,
Res::Module(id) => &p.modules[id].name,
};
format!("{} '{}'", self.kind(), name)
}
}
#[derive(Clone)]
pub enum ResBase {
Unvalidated(MemRes),
Validated(Res),
}
impl ResBase {
pub fn display_str(&self, p: &UProgram) -> String {
match self {
ResBase::Unvalidated(uv) => uv.display_str(p),
ResBase::Validated(res) => res.display_str(p),
}
}
}
#[derive(Clone)]
pub struct MemRes {
pub mem: Member,
pub origin: Origin,
pub gargs: Vec<TypeID>,
}
impl MemRes {
pub fn display_str(&self, p: &UProgram) -> String {
self.mem.id.display_str(p)
}
}
impl IdentID {
pub fn var(&self, p: &UProgram) -> Option<VarID> {
match p.idents[self].status {
IdentStatus::Res(Res::Var(id)) => Some(id),
_ => None,
}
}
pub fn fun<'a>(&self, p: &'a UProgram) -> Option<&'a FnInst> {
match &p.idents[self].status {
IdentStatus::Res(Res::Fn(i)) => Some(&i),
_ => None,
}
}
pub fn struc<'a>(&self, p: &'a UProgram) -> Option<&'a StructInst> {
match &p.idents[self].status {
IdentStatus::Res(Res::Struct(i)) => Some(&i),
_ => None,
}
}
}
impl UFunc { impl UFunc {
pub fn flat_iter(&self) -> impl Iterator<Item = &UInstrInst> { pub fn flat_iter(&self) -> impl Iterator<Item = &UInstrInst> {
InstrIter::new(self.instructions.iter()) InstrIter::new(self.instructions.iter())
@@ -162,4 +335,3 @@ impl<'a> Iterator for InstrIter<'a> {
Some(next) Some(next)
} }
} }

View File

@@ -1,8 +1,5 @@
use super::*; use super::*;
use std::{ use std::collections::HashMap;
collections::HashMap,
ops::{Deref, DerefMut},
};
pub struct UProgram { pub struct UProgram {
pub fns: Vec<UFunc>, pub fns: Vec<UFunc>,
@@ -23,12 +20,6 @@ pub struct TypeCache {
pub error: TypeID, pub error: TypeID,
} }
pub struct UModuleBuilder<'a> {
pub p: &'a mut UProgram,
pub module: ModID,
pub temp: usize,
}
impl UProgram { impl UProgram {
pub fn new() -> Self { pub fn new() -> Self {
let mut types = Vec::new(); let mut types = Vec::new();
@@ -66,7 +57,7 @@ impl UProgram {
push_id(&mut self.types, t) push_id(&mut self.types, t)
} }
pub fn def_var_inst(&mut self, i: UIdent) -> IdentID { pub fn def_ident(&mut self, i: UIdent) -> IdentID {
push_id(&mut self.idents, i) push_id(&mut self.idents, i)
} }
@@ -82,10 +73,18 @@ impl UProgram {
push_id(&mut self.structs, s) push_id(&mut self.structs, s)
} }
pub fn def_module(&mut self, m: UModule) -> ModID {
push_id(&mut self.modules, m)
}
pub fn type_name(&self, ty: impl Typed) -> String { pub fn type_name(&self, ty: impl Typed) -> String {
match ty.ty(self) { match ty.ty(self) {
Type::Struct(ty) => { Type::Struct(ty) => {
format!("{}{}", self.structs[ty.id].name, self.gparams_str(&ty.gargs)) format!(
"{}{}",
self.structs[ty.id].name,
self.gparams_str(&ty.gargs)
)
} }
Type::FnRef(ty) => { Type::FnRef(ty) => {
format!( format!(
@@ -97,13 +96,13 @@ impl UProgram {
} }
Type::Ref(t) => format!("{}&", self.type_name(t)), Type::Ref(t) => format!("{}&", self.type_name(t)),
Type::Deref(t) => format!("{}^", self.type_name(t)), Type::Deref(t) => format!("{}^", self.type_name(t)),
Type::Unres(_) => "{unresolved}".to_string(),
Type::Bits(size) => format!("b{}", size), Type::Bits(size) => format!("b{}", size),
Type::Array(t, len) => format!("[{}; {len}]", self.type_name(t)), Type::Array(t, len) => format!("[{}; {len}]", self.type_name(t)),
Type::Unit => "()".to_string(), Type::Unit => "()".to_string(),
Type::Slice(t) => format!("&[{}]", self.type_name(t)), Type::Slice(t) => format!("&[{}]", self.type_name(t)),
Type::Error => "{error}".to_string(), Type::Error => "{error}".to_string(),
Type::Infer => "{inferred}".to_string(), Type::Infer => "{inferred}".to_string(),
Type::Unres(_) => "{unresolved}".to_string(),
Type::Generic(id) => self.generics[id].name.clone(), Type::Generic(id) => self.generics[id].name.clone(),
} }
} }
@@ -138,34 +137,6 @@ pub fn push_id<T>(v: &mut Vec<T>, t: T) -> ID<T> {
id id
} }
impl<'a> UModuleBuilder<'a> {
pub fn new(program: &'a mut UProgram, id: ModID) -> Self {
Self {
p: program,
module: id,
temp: 0,
}
}
pub fn temp_var(&mut self, origin: Origin, ty: impl Typable) -> IdentID {
self.temp_var_inner(origin, ty)
}
fn temp_var_inner(&mut self, origin: Origin, ty: impl Typable) -> IdentID {
let var = UVar {
name: format!("temp{}", self.temp),
ty: ty.ty(self),
origin,
parent: None,
children: HashMap::new(),
};
let id = self.p.def_var(var);
self.temp += 1;
self.def_var_inst(UIdent {
status: IdentStatus::Var(id),
origin,
})
}
}
// I'm done with names... // I'm done with names...
pub trait Typed { pub trait Typed {
fn ty<'a>(&'a self, p: &'a UProgram) -> &'a Type; fn ty<'a>(&'a self, p: &'a UProgram) -> &'a Type;
@@ -194,33 +165,3 @@ impl Typed for &Box<Type> {
&**self &**self
} }
} }
pub trait Typable {
fn ty(self, p: &mut UProgram) -> TypeID;
}
impl Typable for Type {
fn ty(self, p: &mut UProgram) -> TypeID {
p.def_ty(self)
}
}
impl Typable for TypeID {
fn ty(self, p: &mut UProgram) -> TypeID {
self
}
}
impl Deref for UModuleBuilder<'_> {
type Target = UProgram;
fn deref(&self) -> &Self::Target {
self.p
}
}
impl DerefMut for UModuleBuilder<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.p
}
}

View File

@@ -1,11 +1,9 @@
use super::{ use super::{
inst_fn_ty, inst_struct_ty, report_errs, ControlFlowOp, DataID, FnInst, IdentID, IdentStatus, inst_fn_var, inst_type, inst_typedef, inst_var, push_id, report_errs, resolve_refs, validate_gargs, ControlFlowOp, DataID, FnInst, IdentID, IdentStatus, KindTy, MemberID, MemberTy, Origin, Res, ResBase, ResErr, StructInst, Type, TypeID, TypeMismatch, UData, UFunc, UGeneric, UIdent, UInstrInst, UInstruction, UModule, UProgram, UStruct, UVar, VarID
MemberTy, Origin, ResErr, StructInst, Type, TypeID, TypeMismatch, UData, UFunc, UGeneric,
UIdent, UInstrInst, UInstruction, UModule, UProgram, UStruct, UVar, VarID,
}; };
use crate::{ use crate::{
common::{CompilerMsg, CompilerOutput}, common::CompilerOutput,
ir::{inst_fn_var, ID}, ir::{MemRes, Member},
}; };
use std::{ use std::{
collections::HashSet, collections::HashSet,
@@ -14,6 +12,7 @@ use std::{
}; };
// dawg this file is way too long // dawg this file is way too long
// this is the omega file tho that's super cool
impl UProgram { impl UProgram {
pub fn resolve(&mut self, output: &mut CompilerOutput) { pub fn resolve(&mut self, output: &mut CompilerOutput) {
@@ -61,41 +60,8 @@ impl UProgram {
resolve_instr(&mut data, ctx); resolve_instr(&mut data, ctx);
} }
} }
let mut errs = data.errs; let errs = data.errs;
for ident in &self.idents {
match &ident.status {
IdentStatus::Unres {
path,
mem,
gargs,
fields,
} => errs.push(ResErr::UnknownModule {
origin: path.path[0].origin,
name: path.path[0].name.clone(),
}),
IdentStatus::PartialVar { id, fields } => todo!(),
IdentStatus::Failed(err) => errs.push(err.clone()),
_ => (),
}
}
report_errs(self, output, errs); report_errs(self, output, errs);
for var in &self.vars {
match &self.types[var.ty] {
Type::Error => output.err(CompilerMsg::new(
format!("Var {:?} is error type!", var.name),
var.origin,
)),
Type::Infer => output.err(CompilerMsg::new(
format!("Type of {:?} cannot be inferred", var.name),
var.origin,
)),
Type::Unres(_) => output.err(CompilerMsg::new(
format!("Var {:?} type still unresolved!", var.name),
var.origin,
)),
_ => (),
}
}
} }
} }
@@ -112,36 +78,37 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
UInstruction::Call { dst, f, args } => { UInstruction::Call { dst, f, args } => {
let fi = data.res_id::<UFunc>(f, ctx)?; let fi = data.res_id::<UFunc>(f, ctx)?;
let f = &data.s.fns[fi.id]; let f = &data.s.fns[fi.id];
for (src, dest) in args.iter().zip(&f.args) { for (src, &dest) in args.iter().zip(&f.args) {
res |= data.match_types(dest, src, src); res |= data.match_types::<UVar, UVar>(dest, src, src);
} }
res |= data.match_types(dst, f.ret, dst); res |= data.match_types::<UVar, Type>(dst, f.ret, dst);
} }
UInstruction::Mv { dst, src } => { UInstruction::Mv { dst, src } => {
res |= data.match_types(dst, src, src); res |= data.match_types::<UVar, UVar>(dst, src, src);
} }
UInstruction::Ref { dst, src } => { UInstruction::Ref { dst, src } => {
let dstid = data.res_ty_id::<UVar>(dst, ctx)?; let dstid = data.res_var_ty(dst, ctx)?;
let Type::Ref(dest_ty) = data.types[dstid] else { let Type::Ref(dest_ty) = data.types[dstid] else {
compiler_error() compiler_error()
}; };
res |= data.match_types(dest_ty, src, src); res |= data.match_types::<Type, UVar>(dest_ty, src, src);
} }
UInstruction::Deref { dst, src } => { UInstruction::Deref { dst, src } => {
let srcid = data.res_ty_id::<UVar>(src, ctx)?; let srcid = data.res_var_ty(src, ctx)?;
let Type::Ref(src_ty) = data.types[srcid] else { let Type::Ref(src_ty) = data.types[srcid] else {
let origin = src.origin(data); let origin = src.origin(data);
data.errs.push(ResErr::CannotDeref { origin, ty: srcid }); data.errs.push(ResErr::CannotDeref { origin, ty: srcid });
return None; return None;
}; };
res |= data.match_types(dst, src_ty, src); res |= data.match_types::<UVar, Type>(dst, src_ty, src);
} }
UInstruction::LoadData { dst, src } => { UInstruction::LoadData { dst, src } => {
res |= data.match_types(dst, src, dst); let srcid = src.type_id(&data.s);
res |= data.match_types::<UVar, Type>(dst, srcid, dst);
} }
UInstruction::LoadSlice { dst, src } => { UInstruction::LoadSlice { dst, src } => {
let dstid = data.res_id(src, ctx)?; let dstid = data.res_var_ty(dst, ctx)?;
let srcid = data.res_id(src, ctx)?; let srcid = src.type_id(&data.s);
let Type::Slice(dstty) = data.types[dstid] else { let Type::Slice(dstty) = data.types[dstid] else {
compiler_error() compiler_error()
}; };
@@ -150,14 +117,11 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
}; };
res |= data.match_types(dstty, srcty, dst); res |= data.match_types(dstty, srcty, dst);
} }
UInstruction::LoadFn { dst, src } => {
// TODO: validate size with enabled targets
}
UInstruction::AsmBlock { instructions, args } => { UInstruction::AsmBlock { instructions, args } => {
// TODO // TODO
} }
UInstruction::Ret { src } => { UInstruction::Ret { src } => {
res |= data.match_types(ctx.ret, src, src); res |= data.match_types::<Type, UVar>(ctx.ret, src, src);
} }
UInstruction::Construct { dst, struc, fields } => { UInstruction::Construct { dst, struc, fields } => {
let si = data.res_id::<UStruct>(dst, ctx)?; let si = data.res_id::<UStruct>(dst, ctx)?;
@@ -167,7 +131,7 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
for (name, field) in &st.fields { for (name, field) in &st.fields {
if let Some(src) = fields.get(name) { if let Some(src) = fields.get(name) {
used.insert(name); used.insert(name);
res |= data.match_types(field.ty, src, src); res |= data.match_types::<Type, UVar>(field.ty, src, src);
} else { } else {
let origin = dst.origin(data); let origin = dst.origin(data);
data.errs.push(ResErr::MissingField { data.errs.push(ResErr::MissingField {
@@ -180,7 +144,7 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
for (name, _) in fields { for (name, _) in fields {
if !used.contains(name) { if !used.contains(name) {
let origin = dst.origin(data); let origin = dst.origin(data);
data.errs.push(ResErr::UnknownField { data.errs.push(ResErr::UnknownStructField {
origin, origin,
id: sid, id: sid,
name: name.clone(), name: name.clone(),
@@ -189,7 +153,7 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
} }
} }
UInstruction::If { cond, body } => { UInstruction::If { cond, body } => {
if let Some(id) = data.res_ty_id::<UVar>(cond, ctx) { if let Some(id) = data.res_var_ty(cond, ctx) {
if !matches!(data.types[id], Type::Bits(64)) { if !matches!(data.types[id], Type::Bits(64)) {
let origin = cond.origin(data); let origin = cond.origin(data);
data.errs.push(ResErr::CondType { origin, ty: id }); data.errs.push(ResErr::CondType { origin, ty: id });
@@ -247,24 +211,31 @@ fn compiler_error() -> ! {
panic!("how could this happen to me (you)"); panic!("how could this happen to me (you)");
} }
pub fn match_types(data: &mut TypeResData, dst: impl TypeIDed, src: impl TypeIDed) -> MatchRes { pub fn match_types(data: &mut ResData, dst: impl TypeIDed, src: impl TypeIDed) -> MatchRes {
let dst = data.res_id(dst); let dstid = data.res_ty(&dst)?;
let src = data.res_id(src); let srcid = data.res_ty(&src)?;
if dst == src { if dstid == srcid {
return MatchRes::Finished; return MatchRes::Finished;
} }
let error = || MatchRes::Error(vec![TypeMismatch { dst, src }]); let error = || {
match (data.types[dst].clone(), data.types[src].clone()) { MatchRes::Error(vec![TypeMismatch {
dst: dstid,
src: srcid,
}])
};
match (data.types[dstid].clone(), data.types[srcid].clone()) {
(Type::Error, _) | (_, Type::Error) => MatchRes::Finished, (Type::Error, _) | (_, Type::Error) => MatchRes::Finished,
(Type::Infer, Type::Infer) => MatchRes::Unfinished, (Type::Infer, Type::Infer) => MatchRes::Unfinished,
(Type::Infer, x) => { (Type::Infer, x) => {
*data.changed = true; data.changed = true;
data.types[dst] = x; data.types[dstid] = x;
dst.finish(&mut data.s, data.types);
MatchRes::Finished MatchRes::Finished
} }
(x, Type::Infer) => { (x, Type::Infer) => {
*data.changed = true; data.changed = true;
data.types[src] = x; data.types[srcid] = x;
src.finish(&mut data.s, data.types);
MatchRes::Finished MatchRes::Finished
} }
(Type::Struct(dest), Type::Struct(src)) => { (Type::Struct(dest), Type::Struct(src)) => {
@@ -300,18 +271,8 @@ pub fn match_types(data: &mut TypeResData, dst: impl TypeIDed, src: impl TypeIDe
} }
} }
pub fn resolve_refs(types: &[Type], id: TypeID) -> TypeID {
if let Type::Deref(rid) = types[id]
&& let Type::Ref(nid) = types[rid]
{
nid
} else {
id
}
}
fn match_all( fn match_all(
data: &mut TypeResData, data: &mut ResData,
dst: impl Iterator<Item = TypeID>, dst: impl Iterator<Item = TypeID>,
src: impl Iterator<Item = TypeID>, src: impl Iterator<Item = TypeID>,
) -> MatchRes { ) -> MatchRes {
@@ -353,30 +314,24 @@ struct ResData<'a> {
errs: Vec<ResErr>, errs: Vec<ResErr>,
} }
struct TypeResData<'a> {
changed: &'a mut bool,
types: &'a mut [Type],
sources: &'a Sources<'a>,
}
impl<'a> ResData<'a> { impl<'a> ResData<'a> {
pub fn match_types( pub fn match_types<Dst: ResKind, Src: ResKind>(
&mut self, &mut self,
dst: impl Resolvable<Type>, dst: impl Resolvable<Dst>,
src: impl Resolvable<Type>, src: impl Resolvable<Src>,
origin: impl HasOrigin, origin: impl HasOrigin,
) -> InstrRes { ) -> InstrRes
let dst = dst.try_res(&mut self.s, self.types, &mut self.errs)?; where
let src = src.try_res(&mut self.s, self.types, &mut self.errs)?; Dst::Res: TypeIDed,
let res = match_types( Src::Res: TypeIDed,
&mut TypeResData { {
changed: &mut self.changed, let dst = dst
types: self.types, .try_res(&mut self.s, self.types, &mut self.errs, &mut self.changed)?
sources: &self.s, .type_id(&self.s);
}, let src = src
dst, .try_res(&mut self.s, self.types, &mut self.errs, &mut self.changed)?
src, .type_id(&self.s);
); let res = match_types(self, dst, src);
match res { match res {
MatchRes::Unfinished => InstrRes::Unfinished, MatchRes::Unfinished => InstrRes::Unfinished,
MatchRes::Finished => InstrRes::Finished, MatchRes::Finished => InstrRes::Finished,
@@ -392,17 +347,19 @@ impl<'a> ResData<'a> {
} }
} }
pub fn try_res_id<K: ResKind>(&mut self, x: impl Resolvable<K>) -> Result<K::Res, InstrRes> { pub fn try_res_id<K: ResKind>(&mut self, x: impl Resolvable<K>) -> Result<K::Res, InstrRes> {
x.try_res(&mut self.s, &mut self.types, &mut self.errs) x.try_res(
&mut self.s,
&mut self.types,
&mut self.errs,
&mut self.changed,
)
} }
pub fn res_ty_id<'b: 'a, K: ResKind>( pub fn res_var_ty<'b: 'a>(
&mut self, &mut self,
x: impl Resolvable<K>, x: impl Resolvable<UVar>,
ctx: ResolveCtx<'b>, ctx: ResolveCtx<'b>,
) -> Option<TypeID> ) -> Option<TypeID> {
where self.res_id::<UVar>(x, ctx).map(|i| i.type_id(&self.s))
K::Res: TypeIDed,
{
self.res_id::<K>(x, ctx).map(|i| i.type_id(&self.s))
} }
pub fn res_id<'b: 'a, K: ResKind>( pub fn res_id<'b: 'a, K: ResKind>(
&mut self, &mut self,
@@ -416,11 +373,22 @@ impl<'a> ResData<'a> {
} }
None None
} }
}
impl TypeResData<'_> { pub fn res_ty(&mut self, x: &impl TypeIDed) -> Result<TypeID, InstrRes> {
pub fn res_id(&self, x: impl TypeIDed) -> TypeID { let id = resolve_refs(self.types, x.type_id(&self.s));
resolve_refs(self.types, x.type_id(self.sources)) Ok(if let Type::Unres(ident) = self.types[id] {
match self.try_res_id::<Type>(ident) {
Ok(nid) => {
// this does NOT feel good lmao
self.types[id] = self.types[nid].clone();
x.finish(&mut self.s, self.types);
nid
}
Err(res) => return Err(res),
}
} else {
id
})
} }
} }
@@ -436,6 +404,155 @@ pub enum InstrRes {
Unfinished, Unfinished,
} }
impl MemRes {
pub fn validate(
&self,
fns: &[UFunc],
structs: &[UStruct],
generics: &[UGeneric],
types: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
) -> Result<Res, Option<ResErr>> {
let no_gargs = || {
if self.gargs.len() > 0 {
Err(ResErr::GenericCount {
origin: self.origin,
expected: 0,
found: self.gargs.len(),
})
} else {
Ok(())
}
};
Ok(match &self.mem.id {
&MemberID::Fn(id) => {
validate_gargs(
&fns[id].gargs,
&self.gargs,
generics,
types,
errs,
self.origin,
)?;
Res::Fn(FnInst {
id,
gargs: self.gargs.clone(),
})
}
&MemberID::Struct(id) => {
validate_gargs(
&structs[id].gargs,
&self.gargs,
generics,
types,
errs,
self.origin,
)?;
Res::Struct(StructInst {
id,
gargs: self.gargs.clone(),
})
}
&MemberID::Var(id) => {
no_gargs()?;
Res::Var(id)
}
&MemberID::Module(id) => {
no_gargs()?;
Res::Module(id)
}
MemberID::Type(def) => {
validate_gargs(&def.gargs, &self.gargs, generics, types, errs, self.origin)?;
inst_typedef(def, &self.gargs, types);
Res::Type(def.ty)
}
})
}
}
impl IdentID {
pub fn resolve(
self,
s: &mut Sources,
types: &mut Vec<Type>,
changed: &mut bool,
errs: &mut Vec<ResErr>,
) -> Result<Res, InstrRes> {
let status = &mut s.idents[self].status;
// TOOD: there are some clones here that shouldn't be needed
Ok(match status {
IdentStatus::Res(r) => r.clone(),
IdentStatus::Unres { path, base } => {
while let Some(mem) = path.pop() {
let res = match base {
ResBase::Unvalidated(u) => {
match u.validate(s.fns, s.structs, s.generics, types, errs) {
Ok(res) => res,
Err(err) => {
*status = IdentStatus::Failed(err);
return Err(InstrRes::Finished);
}
}
}
ResBase::Validated(res) => res.clone(),
};
*base = match (res, mem.ty) {
(Res::Module(id), MemberTy::Member) => {
let Some(m) = s.modules[id].members.get(&mem.name) else {
return Err(InstrRes::Unfinished);
};
ResBase::Unvalidated(MemRes {
mem: m.clone(),
origin: mem.origin,
gargs: mem.gargs,
})
}
(Res::Var(id), MemberTy::Field) => {
// trait resolution here
let Some(&child) = s.vars[id].children.get(&mem.name) else {
return Err(InstrRes::Unfinished);
};
ResBase::Unvalidated(MemRes {
mem: Member {
id: MemberID::Var(child),
},
origin: mem.origin,
gargs: mem.gargs,
})
}
_ => {
*status = IdentStatus::Failed(Some(ResErr::UnknownMember {
origin: mem.origin,
ty: mem.ty,
name: mem.name.clone(),
parent: base.clone(),
}));
return Err(InstrRes::Finished);
}
};
}
let res = match base {
ResBase::Unvalidated(u) => {
match u.validate(s.fns, s.structs, s.generics, types, errs) {
Ok(res) => res,
Err(err) => {
*status = IdentStatus::Failed(err);
return Err(InstrRes::Finished);
}
}
}
ResBase::Validated(res) => res.clone(),
};
*status = IdentStatus::Res(res.clone());
*changed = true;
res
}
IdentStatus::Cooked => return Err(InstrRes::Finished),
IdentStatus::Failed(_) => return Err(InstrRes::Finished),
})
}
}
impl BitOrAssign for InstrRes { impl BitOrAssign for InstrRes {
fn bitor_assign(&mut self, rhs: Self) { fn bitor_assign(&mut self, rhs: Self) {
match rhs { match rhs {
@@ -457,134 +574,23 @@ trait Resolvable<K: ResKind> {
s: &mut Sources, s: &mut Sources,
types: &mut Vec<Type>, types: &mut Vec<Type>,
errs: &mut Vec<ResErr>, errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> Result<K::Res, InstrRes>; ) -> Result<K::Res, InstrRes>;
} }
impl<T: TypeIDed> Resolvable<Type> for T {
fn try_res(
&self,
s: &mut Sources,
_: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
) -> Result<TypeID, InstrRes> {
Ok(self.type_id(s))
}
}
impl IdentID {
pub fn resolve(self, s: &mut Sources) -> Result<Res, InstrRes> {
let ident = &mut s.idents[self];
Ok(match &mut ident.status {
IdentStatus::Var(id) => Res::Var(*id),
IdentStatus::Struct(sty) => Res::Struct(sty.clone()),
IdentStatus::Fn(fty) => Res::Fn(fty.clone()),
IdentStatus::Type(ty) => Res::Type(*ty),
IdentStatus::Unres {
path,
mem,
gargs,
fields,
} => {
let mut mid = path.id;
let mut count = 0;
for mem in &path.path {
let Some(&child) = s.modules[mid].children.get(&mem.name) else {
break;
};
count += 1;
mid = child;
}
path.path.drain(0..count);
path.id = mid;
if path.path.len() != 0 {
return Err(InstrRes::Unfinished);
}
let Some(mem) = s.modules[mid].members.get(&mem.name) else {
return Err(InstrRes::Unfinished);
};
match mem.id {
MemberTy::Fn(id) => {
if fields.len() > 0 {
ident.status = IdentStatus::Failed(ResErr::UnexpectedField {
origin: ident.origin,
});
return Err(InstrRes::Finished);
}
let fty = FnInst {
id,
gargs: gargs.clone(),
};
ident.status = IdentStatus::Fn(fty.clone());
Res::Fn(fty)
}
MemberTy::Struct(id) => {
if fields.len() > 0 {
ident.status = IdentStatus::Failed(ResErr::UnexpectedField {
origin: ident.origin,
});
return Err(InstrRes::Finished);
}
let sty = StructInst {
id,
gargs: gargs.clone(),
};
ident.status = IdentStatus::Struct(sty.clone());
Res::Struct(sty)
}
MemberTy::Var(id) => {
if !gargs.is_empty() {
ident.status = IdentStatus::Failed(ResErr::GenericCount {
origin: ident.origin,
expected: 0,
found: gargs.len(),
});
return Err(InstrRes::Finished);
}
ident.status = IdentStatus::PartialVar {
id,
fields: fields.clone(),
};
return self.resolve(s);
}
}
}
IdentStatus::PartialVar { id, fields } => {
let mut fiter = fields.iter();
let mut next = fiter.next();
let mut count = 0;
while let Some(mem) = next
&& let Some(&cid) = s.vars[*id].children.get(&mem.name)
{
*id = cid;
next = fiter.next();
count += 1;
}
fields.drain(0..count);
if fields.len() != 0 {
return Err(InstrRes::Unfinished);
}
let id = *id;
ident.status = IdentStatus::Var(id);
Res::Var(id)
}
IdentStatus::Cooked => return Err(InstrRes::Finished),
IdentStatus::Failed(_) => return Err(InstrRes::Finished),
})
}
}
impl<K: ResKind> Resolvable<K> for IdentID { impl<K: ResKind> Resolvable<K> for IdentID {
fn try_res( fn try_res(
&self, &self,
s: &mut Sources, s: &mut Sources,
types: &mut Vec<Type>, types: &mut Vec<Type>,
errs: &mut Vec<ResErr>, errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> Result<K::Res, InstrRes> { ) -> Result<K::Res, InstrRes> {
let origin = s.idents[self].origin; let origin = s.idents[self].origin;
let res = self.resolve(s)?; let res = self.resolve(s, types, changed, errs)?;
match K::from_res(res.clone(), types, s, origin, errs) { match K::from_res(res, types, s, origin) {
Some(res) => Ok(res), Ok(res) => Ok(res),
None => { Err(res) => {
errs.push(ResErr::KindMismatch { errs.push(ResErr::KindMismatch {
origin, origin,
expected: K::ty(), expected: K::ty(),
@@ -596,45 +602,39 @@ impl<K: ResKind> Resolvable<K> for IdentID {
} }
} }
// "effective" (externally visible) kinds impl<K: ResKind> Resolvable<K> for &IdentID {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] fn try_res(
pub enum KindTy { &self,
Type, s: &mut Sources,
Var, types: &mut Vec<Type>,
Struct, errs: &mut Vec<ResErr>,
Fn, changed: &mut bool,
} ) -> Result<K::Res, InstrRes> {
Resolvable::<K>::try_res(*self, s, types, errs, changed)
impl KindTy {
pub fn str(&self) -> &'static str {
match self {
KindTy::Type => "type",
KindTy::Var => "variable",
KindTy::Fn => "function",
KindTy::Struct => "struct",
}
} }
} }
#[derive(Debug, Clone)] impl Resolvable<UVar> for VarID {
pub enum Res { fn try_res(
Var(VarID), &self,
Fn(FnInst), s: &mut Sources,
Struct(StructInst), types: &mut Vec<Type>,
Type(TypeID), errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> Result<<UVar as ResKind>::Res, InstrRes> {
Ok(*self)
}
} }
impl Res { impl Resolvable<Type> for TypeID {
pub fn kind(&self) -> KindTy { fn try_res(
match self { &self,
Res::Var(..) => KindTy::Var, s: &mut Sources,
Res::Fn(..) => KindTy::Fn, types: &mut Vec<Type>,
Res::Struct(..) => KindTy::Struct, errs: &mut Vec<ResErr>,
Res::Type(..) => KindTy::Type, changed: &mut bool,
} ) -> Result<<Type as ResKind>::Res, InstrRes> {
} Ok(*self)
pub fn kind_str(&self) -> &'static str {
self.kind().str()
} }
} }
@@ -646,8 +646,7 @@ pub trait ResKind {
types: &mut Vec<Type>, types: &mut Vec<Type>,
s: &mut Sources, s: &mut Sources,
origin: Origin, origin: Origin,
errs: &mut Vec<ResErr>, ) -> Result<Self::Res, Res>;
) -> Option<Self::Res>;
} }
impl ResKind for UFunc { impl ResKind for UFunc {
@@ -655,16 +654,10 @@ impl ResKind for UFunc {
fn ty() -> KindTy { fn ty() -> KindTy {
KindTy::Fn KindTy::Fn
} }
fn from_res( fn from_res(res: Res, _: &mut Vec<Type>, _: &mut Sources, _: Origin) -> Result<Self::Res, Res> {
res: Res,
_: &mut Vec<Type>,
_: &mut Sources,
_: Origin,
_: &mut Vec<ResErr>,
) -> Option<Self::Res> {
match res { match res {
Res::Fn(fi) => Some(fi), Res::Fn(fi) => Ok(fi),
_ => None, _ => Err(res),
} }
} }
} }
@@ -679,13 +672,11 @@ impl ResKind for UVar {
types: &mut Vec<Type>, types: &mut Vec<Type>,
s: &mut Sources, s: &mut Sources,
origin: Origin, origin: Origin,
errs: &mut Vec<ResErr>, ) -> Result<Self::Res, Res> {
) -> Option<Self::Res> { Ok(match res {
Some(match res { Res::Fn(fty) => inst_fn_var(fty, s.fns, origin, s.vars, types),
Res::Fn(fty) => inst_fn_var(&fty, s.fns, origin, s.vars, types, s.generics, errs),
Res::Var(id) => id, Res::Var(id) => id,
Res::Struct(_) => return None, _ => return Err(res),
Res::Type(_) => return None,
}) })
} }
} }
@@ -695,16 +686,10 @@ impl ResKind for UStruct {
fn ty() -> KindTy { fn ty() -> KindTy {
KindTy::Struct KindTy::Struct
} }
fn from_res( fn from_res(res: Res, _: &mut Vec<Type>, _: &mut Sources, _: Origin) -> Result<Self::Res, Res> {
res: Res,
_: &mut Vec<Type>,
_: &mut Sources,
_: Origin,
_: &mut Vec<ResErr>,
) -> Option<Self::Res> {
match res { match res {
Res::Struct(si) => Some(si), Res::Struct(si) => Ok(si),
_ => None, _ => Err(res),
} }
} }
} }
@@ -719,30 +704,18 @@ impl ResKind for Type {
types: &mut Vec<Type>, types: &mut Vec<Type>,
s: &mut Sources, s: &mut Sources,
_: Origin, _: Origin,
errs: &mut Vec<ResErr>, ) -> Result<Self::Res, Res> {
) -> Option<Self::Res> { Ok(match res {
Some(match res { Res::Struct(si) => push_id(types, Type::Struct(si)),
Res::Fn(fty) => inst_fn_ty(&fty, s.fns, types, s.generics, errs),
Res::Var(id) => id.type_id(s),
Res::Struct(si) => inst_struct_ty(&si, s.structs, types, s.generics, errs),
Res::Type(id) => id, Res::Type(id) => id,
_ => return Err(res),
}) })
} }
} }
impl<K: ResKind> Resolvable<K> for &IdentID {
fn try_res(
&self,
s: &mut Sources,
types: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
) -> Result<K::Res, InstrRes> {
Resolvable::<K>::try_res(*self, s, types, errs)
}
}
pub trait TypeIDed { pub trait TypeIDed {
fn type_id(&self, s: &Sources) -> TypeID; fn type_id(&self, s: &Sources) -> TypeID;
fn finish(&self, s: &mut Sources, types: &mut Vec<Type>) {}
} }
impl TypeIDed for TypeID { impl TypeIDed for TypeID {
@@ -755,6 +728,9 @@ impl TypeIDed for VarID {
fn type_id(&self, s: &Sources) -> TypeID { fn type_id(&self, s: &Sources) -> TypeID {
s.vars[self].ty s.vars[self].ty
} }
fn finish(&self, s: &mut Sources, types: &mut Vec<Type>) {
inst_var(s.vars, s.structs, *self, types);
}
} }
impl TypeIDed for DataID { impl TypeIDed for DataID {
@@ -769,8 +745,8 @@ impl<T: TypeIDed> TypeIDed for &T {
} }
} }
impl FromResidual<std::result::Result<std::convert::Infallible, InstrRes>> for InstrRes { impl FromResidual<Result<Infallible, InstrRes>> for InstrRes {
fn from_residual(residual: std::result::Result<std::convert::Infallible, InstrRes>) -> Self { fn from_residual(residual: Result<Infallible, InstrRes>) -> Self {
match residual { match residual {
Ok(_) => unreachable!(), Ok(_) => unreachable!(),
Err(r) => r, Err(r) => r,
@@ -787,3 +763,11 @@ impl HasOrigin for &IdentID {
data.s.idents[*self].origin data.s.idents[*self].origin
} }
} }
impl FromResidual<Result<Infallible, MatchRes>> for MatchRes {
fn from_residual(residual: Result<Infallible, MatchRes>) -> Self {
match residual {
Ok(_) => unreachable!(),
Err(r) => r,
}
}
}

View File

@@ -1,8 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use super::{ use super::{
push_id, FnID, GenericID, Len, ModPath, Origin, ResErr, StructID, TypeID, UFunc, UGeneric, push_id, FnID, GenericID, IdentID, Len, Origin, ResErr, StructID, TypeDef, TypeID, UFunc,
UProgram, UStruct, UVar, VarID, UGeneric, UProgram, UStruct, UVar, VarID,
}; };
#[derive(Debug, Clone, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Hash, Eq, PartialEq)]
@@ -14,12 +14,14 @@ pub struct FieldRef {
#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct StructInst { pub struct StructInst {
pub id: StructID, pub id: StructID,
/// assumed to be valid
pub gargs: Vec<TypeID>, pub gargs: Vec<TypeID>,
} }
#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct FnInst { pub struct FnInst {
pub id: FnID, pub id: FnID,
/// assumed to be valid
pub gargs: Vec<TypeID>, pub gargs: Vec<TypeID>,
} }
@@ -36,7 +38,7 @@ pub enum Type {
Array(TypeID, Len), Array(TypeID, Len),
Unit, Unit,
// "fake" types // "fake" types
Unres(ModPath), Unres(IdentID),
Generic(GenericID), Generic(GenericID),
Infer, Infer,
Error, Error,
@@ -79,16 +81,14 @@ impl Type {
} }
pub fn inst_fn_var( pub fn inst_fn_var(
fi: &FnInst, fi: FnInst,
fns: &[UFunc], fns: &[UFunc],
origin: Origin, origin: Origin,
vars: &mut Vec<UVar>, vars: &mut Vec<UVar>,
types: &mut Vec<Type>, types: &mut Vec<Type>,
generics: &[UGeneric],
errs: &mut Vec<ResErr>,
) -> VarID { ) -> VarID {
let ty = inst_fn_ty(fi, fns, types, generics, errs);
let name = fns[fi.id].name.clone(); let name = fns[fi.id].name.clone();
let ty = push_id(types, Type::FnRef(fi));
push_id( push_id(
vars, vars,
UVar { UVar {
@@ -101,33 +101,16 @@ pub fn inst_fn_var(
) )
} }
pub fn inst_fn_ty(
fi: &FnInst,
fns: &[UFunc],
types: &mut Vec<Type>,
generics: &[UGeneric],
errs: &mut Vec<ResErr>,
) -> TypeID {
let f = &fns[fi.id];
let ty = Type::FnRef(FnInst {
id: fi.id,
gargs: inst_generics(&f.gargs, &fi.gargs, types, generics, errs),
});
push_id(types, ty)
}
pub fn inst_struct_var( pub fn inst_struct_var(
si: &StructInst, si: StructInst,
structs: &[UStruct], structs: &[UStruct],
origin: Origin, origin: Origin,
vars: &mut Vec<UVar>, vars: &mut Vec<UVar>,
types: &mut Vec<Type>, types: &mut Vec<Type>,
generics: &[UGeneric],
errs: &mut Vec<ResErr>,
) -> VarID { ) -> VarID {
let ty = inst_struct_ty(si, structs, types, generics, errs);
let name = structs[si.id].name.clone(); let name = structs[si.id].name.clone();
push_id( let ty = push_id(types, Type::Struct(si));
let id = push_id(
vars, vars,
UVar { UVar {
name, name,
@@ -136,68 +119,91 @@ pub fn inst_struct_var(
parent: None, parent: None,
children: HashMap::new(), children: HashMap::new(),
}, },
)
}
pub fn inst_struct_ty(
si: &StructInst,
structs: &[UStruct],
types: &mut Vec<Type>,
generics: &[UGeneric],
errs: &mut Vec<ResErr>,
) -> TypeID {
let s = &structs[si.id];
let ty = Type::Struct(StructInst {
id: si.id,
gargs: inst_generics(&s.gargs, &si.gargs, types, generics, errs),
});
push_id(types, ty)
}
pub fn inst_generics(
source: &[GenericID],
args: &[TypeID],
types: &mut Vec<Type>,
// will be needed when constraints are added
_generics: &[UGeneric],
errs: &mut Vec<ResErr>,
) -> Vec<TypeID> {
if source.len() != args.len() {
// don't want unequal lengths to be inferred further
return source.iter().map(|_| push_id(types, Type::Error)).collect();
}
let mut gargs = Vec::new();
let mut gmap = HashMap::new();
for &gid in source {
let id = push_id(types, Type::Error);
gmap.insert(gid, id);
gargs.push(id);
}
for (gid, &ty) in source.iter().zip(args) {
inst_type_ins(
|types, ty| {
let id = gmap[gid];
types[id] = ty;
id
},
ty,
types,
&gmap,
); );
inst_var(vars, structs, id, types);
id
}
pub fn inst_var(vars: &mut Vec<UVar>, structs: &[UStruct], id: VarID, types: &mut Vec<Type>) {
match &types[resolve_refs(types, vars[id].ty)] {
Type::Struct(si) => {
let fields = &structs[si.id].fields;
let s_gargs = &structs[si.id].gargs;
let gmap = inst_gmap(s_gargs, &si.gargs);
let children = fields
.iter()
.map(|(name, f)| {
(name.clone(), {
let ty = inst_type(f.ty, types, &gmap);
let fid = push_id(
vars,
UVar {
name: name.clone(),
origin: f.origin,
ty,
parent: Some(id),
children: HashMap::new(),
},
);
inst_var(vars, structs, fid, types);
fid
})
})
.collect();
vars[id].children = children;
} }
gargs _ => (),
}
}
pub fn resolve_refs(types: &[Type], id: TypeID) -> TypeID {
if let Type::Deref(rid) = types[id]
&& let Type::Ref(nid) = types[rid]
{
nid
} else {
id
}
}
pub fn validate_gargs(
dst: &[GenericID],
src: &[TypeID],
generics: &[UGeneric],
types: &[Type],
errs: &mut Vec<ResErr>,
origin: Origin,
) -> Result<(), Option<ResErr>> {
if dst.len() != src.len() {
return Err(Some(ResErr::GenericCount {
origin,
expected: dst.len(),
found: src.len(),
}));
}
for (dst, src) in dst.iter().zip(src.iter()) {
let g = &generics[dst];
let t = &types[src];
// TODO: validate trait constraints
}
Ok(())
}
/// gargs assumed to be valid
pub fn inst_typedef(def: &TypeDef, gargs: &[TypeID], types: &mut Vec<Type>) -> TypeID {
let gmap = inst_gmap(&def.gargs, &gargs);
inst_type(def.ty, types, &gmap)
}
pub fn inst_gmap(dst: &[GenericID], src: &[TypeID]) -> HashMap<GenericID, TypeID> {
let mut gmap = HashMap::new();
for (&gid, &tid) in dst.iter().zip(src) {
gmap.insert(gid, tid);
}
gmap
} }
pub fn inst_type(id: TypeID, types: &mut Vec<Type>, gmap: &HashMap<GenericID, TypeID>) -> TypeID { pub fn inst_type(id: TypeID, types: &mut Vec<Type>, gmap: &HashMap<GenericID, TypeID>) -> TypeID {
inst_type_ins(push_id, id, types, gmap)
}
pub fn inst_type_ins(
insert: impl Fn(&mut Vec<Type>, Type) -> TypeID,
id: TypeID,
types: &mut Vec<Type>,
gmap: &HashMap<GenericID, TypeID>,
) -> TypeID {
let ty = match types[id].clone() { let ty = match types[id].clone() {
Type::Bits(_) => return id, Type::Bits(_) => return id,
Type::Struct(struct_ty) => Type::Struct(StructInst { Type::Struct(struct_ty) => Type::Struct(StructInst {
@@ -226,5 +232,7 @@ pub fn inst_type_ins(
Type::Infer => Type::Infer, Type::Infer => Type::Infer,
Type::Error => Type::Error, Type::Error => Type::Error,
}; };
insert(types, ty) push_id(types, ty)
} }
// type Test<T, U> = (&T, &U)

View File

@@ -2,6 +2,7 @@
#![feature(try_trait_v2)] #![feature(try_trait_v2)]
#![feature(trait_alias)] #![feature(trait_alias)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(iterator_try_collect)]
// dawg what // dawg what
#![feature(str_as_str)] #![feature(str_as_str)]

View File

@@ -12,7 +12,7 @@ impl RV64Instruction {
let args = &inst.args[..]; let args = &inst.args[..];
let opstr = &**inst.op.inner.as_ref()?; let opstr = &**inst.op.inner.as_ref()?;
// TODO: surely this can be abstracted... // TODO: surely this can be abstracted...
let opi = |ctx: &mut FnLowerCtx<'_>, op: Funct3| -> Option<Self> { let opi = |ctx: &mut FnLowerCtx<'_, '_, '_>, op: Funct3| -> Option<Self> {
let [dest, src, imm] = args else { let [dest, src, imm] = args else {
ctx.err(format!("{opstr} requires 3 arguments")); ctx.err(format!("{opstr} requires 3 arguments"));
return None; return None;
@@ -22,7 +22,7 @@ impl RV64Instruction {
let imm = i32_from_arg(imm, ctx)?; let imm = i32_from_arg(imm, ctx)?;
Some(Self::OpImm { op, dest, src, imm }) Some(Self::OpImm { op, dest, src, imm })
}; };
let op = |ctx: &mut FnLowerCtx<'_>, op: Funct3, funct: Funct7| -> Option<Self> { let op = |ctx: &mut FnLowerCtx<'_, '_, '_>, op: Funct3, funct: Funct7| -> Option<Self> {
let [dest, src1, src2] = args else { let [dest, src1, src2] = args else {
ctx.err(format!("{opstr} requires 3 arguments")); ctx.err(format!("{opstr} requires 3 arguments"));
return None; return None;
@@ -174,7 +174,7 @@ pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<UIdent>
); );
return None; return None;
}; };
ctx.var(node) ctx.ident(node)
} }
impl RegRef { impl RegRef {
@@ -184,7 +184,7 @@ impl RegRef {
let reg = Reg::from_ident(node, ctx)?; let reg = Reg::from_ident(node, ctx)?;
Self::Reg(reg) Self::Reg(reg)
} }
PAsmArg::Ref(node) => Self::Var(ctx.var(node)?), PAsmArg::Ref(node) => Self::Var(ctx.ident(node)?),
}) })
} }
} }

View File

@@ -1,8 +1,7 @@
use crate::{ use crate::{
compiler::arch::riscv::Reg, compiler::arch::riscv::Reg,
ir::{ ir::{
arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, Type, UInstruction, UIdent, arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, IdentID, Type, UInstruction,
IdentID,
}, },
parser::PAsmBlockArg, parser::PAsmBlockArg,
}; };

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
ir::{Type, UInstruction, UVar, UIdent, IdentID}, ir::{IdentID, Type, UIdent, UInstruction, UVar},
parser::{PConstStatement, PStatementLike}, parser::{PConstStatement, PStatementLike},
}; };
@@ -8,6 +8,7 @@ use super::{FnLowerCtx, FnLowerable, Import, PBlock, PStatement};
impl FnLowerable for PBlock { impl FnLowerable for PBlock {
type Output = IdentID; type Output = IdentID;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<IdentID> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<IdentID> {
ctx.ident_stack.push();
let mut last = None; let mut last = None;
let mut statements = Vec::new(); let mut statements = Vec::new();
let mut fn_nodes = Vec::new(); let mut fn_nodes = Vec::new();
@@ -27,64 +28,58 @@ impl FnLowerable for PBlock {
}, },
} }
} }
ctx.b.push();
// then lower imports // then lower imports
for i_n in &import_nodes { for i_n in &import_nodes {
if let Some(i) = i_n.as_ref() { if let Some(i) = i_n.as_ref() {
let name = &i.0; let name = &i.0;
let path = ctx.b.path_for(name); let path = ctx.path_for(name);
let import = Import(path.clone()); let import = Import(path.clone());
if ctx.imports.insert(import) { if ctx.imports.insert(import) {
ctx.b.def_searchable::<UVar>( ctx.def_var(UVar {
name, name: name.clone(),
Some(UVar {
ty: Type::Module(path), ty: Type::Module(path),
}), origin: i_n.origin,
i_n.origin, });
);
} }
} }
} }
// then lower const things // then lower const things
let mut structs = Vec::new(); let mut structs = Vec::new();
for s in &struct_nodes { for s in &struct_nodes {
structs.push(s.lower_name(ctx.b)); structs.push(s.lower(ctx.ctx));
} }
for (s, id) in struct_nodes.iter().zip(structs) { for (s, id) in struct_nodes.iter().zip(structs) {
if let Some(id) = id { if let Some(id) = id {
s.lower(id, ctx.b, ctx.output); s.lower(ctx.ctx);
} }
} }
let mut fns = Vec::new(); let mut fns = Vec::new();
for f in &fn_nodes { for f in &fn_nodes {
fns.push(f.lower_name(ctx.b)); fns.push(f.lower(ctx.ctx));
} }
for (f, id) in fn_nodes.iter().zip(fns) { for (f, id) in fn_nodes.iter().zip(fns) {
if let Some(id) = id { if let Some(id) = id {
f.lower(id, ctx.b, ctx.imports, ctx.output) f.lower(ctx.ctx);
} }
} }
// then lower statements // then lower statements
for s in statements { for s in statements {
last = s.lower(ctx); last = s.lower(ctx);
} }
ctx.b.pop(); ctx.ident_stack.pop();
last last
} }
} }
impl FnLowerable for PStatement { impl FnLowerable for PStatement {
type Output = UIdent; type Output = IdentID;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<UIdent> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<IdentID> {
match self { match self {
PStatement::Let(def, e) => { PStatement::Let(def, e) => {
let def = def.lower(ctx.b, ctx.output)?; let def = def.lower(ctx.ctx)?;
let res = e.lower(ctx); let res = e.lower(ctx);
if let Some(res) = res { if let Some(res) = res {
ctx.push(UInstruction::Mv { ctx.push(UInstruction::Mv { dst: def, src: res });
dst: def,
src: res,
});
} }
None None
} }

View File

@@ -1,18 +1,23 @@
use crate::ir::{UProgram, UVar, VarID, UIdent}; use std::collections::HashMap;
use super::{CompilerOutput, Node, PVarDef}; use crate::ir::{UVar, VarID};
use super::{ModuleLowerCtx, Node, PVarDef};
impl Node<PVarDef> { impl Node<PVarDef> {
pub fn lower(&self, program: &mut UProgram, output: &mut CompilerOutput) -> Option<VarID> { pub fn lower(&self, ctx: &mut ModuleLowerCtx) -> Option<VarID> {
let s = self.as_ref()?; let s = self.as_ref()?;
let name = s.name.as_ref().map_or("{error}", |v| v); let name = s.name.as_ref().map_or("{error}", |v| v).to_string();
let ty = match &s.ty { let ty = match &s.ty {
Some(ty) => ty.lower(program, output), Some(ty) => ty.lower(ctx),
None => program.infer(self.origin), None => ctx.infer(),
}; };
Some(UIdent { Some(ctx.def_var(UVar {
id: program.def_searchable(name, Some(UVar { ty }), self.origin), name,
ty,
origin: self.origin, origin: self.origin,
}) parent: None,
children: HashMap::new(),
}))
} }
} }

View File

@@ -1,6 +1,6 @@
use super::{func::FnLowerCtx, FnLowerable, PExpr, PostfixOp}; use super::{func::FnLowerCtx, FnLowerable, PExpr, PostfixOp};
use crate::{ use crate::{
ir::{Type, UData, UInstruction, UIdent, IdentID}, ir::{IdentID, IdentStatus, MemRes, Member, MemberID, MemberIdent, Type, UData, UInstruction},
parser::InfixOp, parser::InfixOp,
}; };
@@ -9,22 +9,49 @@ impl FnLowerable for PExpr {
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<IdentID> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<IdentID> {
let mut e = self; let mut e = self;
let mut path = Vec::new(); let mut path = Vec::new();
while let PExpr::Member(node, ident) = e { let mut gargs = None;
loop {
match e {
PExpr::Member(node, ty, ident) => {
e = if let Some(t) = node.as_ref() { e = if let Some(t) = node.as_ref() {
path.push(ident); ctx.origin = node.origin;
path.push((ty, ident, gargs.unwrap_or_default()));
&**t &**t
} else { } else {
return None; return None;
}; };
} }
PExpr::Generic(node, nodes) => match gargs {
None => gargs = Some(nodes.iter().map(|t| t.lower(ctx)).collect::<Vec<_>>()),
Some(_) => {
// this should cover the more specific area of ::<...>
// but too lazy rn
ctx.err("Cannot specify generics here".to_string());
return None;
}
},
_ => break,
}
}
while let PExpr::Member(node, ty, ident) = e {}
if path.len() > 0 {
// UIdent {
// origin: ctx.origin,
// status: IdentStatus::Unres { base: (), path: () },
// }
}
let origin = ctx.origin;
Some(match e { Some(match e {
PExpr::Lit(l) => match l { PExpr::Lit(l) => match l {
super::PLiteral::String(s) => { super::PLiteral::String(s) => {
let dst = ctx.temp_var(ctx.origin, Type::Bits(8).slice(ctx.p)); let sty = Type::Bits(8).slice(ctx.p);
let dst = ctx.temp_var(origin, sty);
let data = s.as_bytes().to_vec(); let data = s.as_bytes().to_vec();
let dty = Type::Bits(8).arr(ctx.ctx.p, data.len() as u32);
let dty = ctx.def_ty(dty);
let src = ctx.def_data(UData { let src = ctx.def_data(UData {
name: format!("string \"{}\"", s.replace("\n", "\\n")), name: format!("string \"{}\"", s.replace("\n", "\\n")),
ty: ctx.def_ty(Type::Bits(8).arr(ctx.b.p, data.len() as u32)), ty: dty,
content: data, content: data,
}); });
ctx.push(UInstruction::LoadSlice { dst, src }); ctx.push(UInstruction::LoadSlice { dst, src });
@@ -32,7 +59,7 @@ impl FnLowerable for PExpr {
} }
super::PLiteral::Char(c) => { super::PLiteral::Char(c) => {
let ty = ctx.def_ty(Type::Bits(8)); let ty = ctx.def_ty(Type::Bits(8));
let dst = ctx.temp_var(ctx.origin, ty.clone()); let dst = ctx.temp_var(origin, ty.clone());
let src = ctx.def_data(UData { let src = ctx.def_data(UData {
name: format!("char '{c}'"), name: format!("char '{c}'"),
ty, ty,
@@ -44,7 +71,7 @@ impl FnLowerable for PExpr {
super::PLiteral::Number(n) => { super::PLiteral::Number(n) => {
// TODO: temp // TODO: temp
let ty = ctx.def_ty(Type::Bits(64)); let ty = ctx.def_ty(Type::Bits(64));
let dst = ctx.temp_var(ctx.origin, ty.clone()); let dst = ctx.temp_var(origin, ty.clone());
let src = ctx.def_data(UData { let src = ctx.def_data(UData {
name: format!("num {n:?}"), name: format!("num {n:?}"),
ty, ty,
@@ -53,9 +80,9 @@ impl FnLowerable for PExpr {
ctx.push(UInstruction::LoadData { dst, src }); ctx.push(UInstruction::LoadData { dst, src });
dst dst
} }
super::PLiteral::Unit => ctx.temp_var(ctx.origin, Type::Unit), super::PLiteral::Unit => ctx.temp_var(origin, Type::Unit),
}, },
PExpr::Ident(i) => ctx.var(i), PExpr::Ident(i) => ctx.ident(i),
PExpr::BinaryOp(op, e1, e2) => match op { PExpr::BinaryOp(op, e1, e2) => match op {
InfixOp::Add => todo!(), InfixOp::Add => todo!(),
InfixOp::Sub => todo!(), InfixOp::Sub => todo!(),
@@ -77,7 +104,7 @@ impl FnLowerable for PExpr {
let res = e.lower(ctx)?; let res = e.lower(ctx)?;
match op { match op {
PostfixOp::Ref => { PostfixOp::Ref => {
let ty = Type::Ref(ctx.b.infer()); let ty = Type::Ref(ctx.ctx.infer());
let dest = ctx.temp(ty); let dest = ctx.temp(ty);
ctx.push(UInstruction::Ref { ctx.push(UInstruction::Ref {
dst: dest, dst: dest,
@@ -86,7 +113,7 @@ impl FnLowerable for PExpr {
dest dest
} }
PostfixOp::Deref => { PostfixOp::Deref => {
let ty = Type::Deref(ctx.b.infer()); let ty = Type::Deref(ctx.ctx.infer());
let dst = ctx.temp(ty); let dst = ctx.temp(ty);
ctx.push(UInstruction::Deref { dst, src: res }); ctx.push(UInstruction::Deref { dst, src: res });
dst dst
@@ -121,20 +148,20 @@ impl FnLowerable for PExpr {
} }
PExpr::If(cond, body) => { PExpr::If(cond, body) => {
let cond = cond.lower(ctx)?; let cond = cond.lower(ctx)?;
ctx.var_stack.push(); ctx.ident_stack.push();
let mut body_ctx = ctx.branch(); let mut body_ctx = ctx.branch();
body.lower(&mut body_ctx); body.lower(&mut body_ctx);
let body = body_ctx.instructions; let body = body_ctx.instructions;
ctx.var_stack.pop(); ctx.ident_stack.pop();
ctx.push(UInstruction::If { cond, body }); ctx.push(UInstruction::If { cond, body });
return None; return None;
} }
PExpr::Loop(body) => { PExpr::Loop(body) => {
ctx.var_stack.push(); ctx.ident_stack.push();
let mut body_ctx = ctx.branch(); let mut body_ctx = ctx.branch();
body.lower(&mut body_ctx); body.lower(&mut body_ctx);
let body = body_ctx.instructions; let body = body_ctx.instructions;
ctx.var_stack.pop(); ctx.ident_stack.pop();
ctx.push(UInstruction::Loop { body }); ctx.push(UInstruction::Loop { body });
return None; return None;
} }
@@ -146,12 +173,33 @@ impl FnLowerable for PExpr {
ctx.push(UInstruction::Continue); ctx.push(UInstruction::Continue);
return None; return None;
} }
PExpr::Member(e, name) => { PExpr::Member(e, ty, name) => {
ctx.err("Can't access a member here".to_string()); let id = e.lower(ctx)?;
return None; let name_str = name.as_ref()?.0;
let cur = &mut ctx.p.idents[id];
match cur.status {
IdentStatus::Res(res) => {
cur.status = IdentStatus::Unres {
base: MemRes {
mem: Member {
id: MemberID
},
origin: (),
gargs: (),
},
path: (),
} }
PExpr::Field(e, name) => { }
todo!() IdentStatus::Unres { base, path } => path.push(MemberIdent {
ty: *ty,
name: name_str,
origin: name.origin,
gargs: Vec::new(),
}),
IdentStatus::Failed(res_err) => return None,
IdentStatus::Cooked => return None,
}
return None;
} }
}) })
} }

View File

@@ -1,74 +1,68 @@
use std::{ use std::ops::{Deref, DerefMut};
collections::HashMap,
ops::{Deref, DerefMut},
};
use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Imports, Node, PFunction}; use super::{CompilerMsg, FileSpan, ModuleLowerCtx, Node, PFunction, Typable};
use crate::{ use crate::{
ir::{ ir::{
FnID, GenericID, ModPath, Origin, Typable, Type, UFunc, UInstrInst, UInstruction, FnID, IdentID, IdentStatus, MemRes, Member, MemberID, MemberIdent, MemberPath, MemberTy,
UModuleBuilder, VarID, UIdent, IdentID, IdentStatus, Origin, Res, Type, UFunc, UIdent, UInstrInst, UInstruction,
}, },
parser, parser,
util::NameStack,
}; };
impl Node<PFunction> { impl Node<PFunction> {
pub fn lower( pub fn lower(&self, ctx: &mut ModuleLowerCtx) -> Option<FnID> {
&self, self.as_ref().map(|s| s.lower(ctx, self.origin)).flatten()
b: &mut UModuleBuilder,
imports: &mut Imports,
output: &mut CompilerOutput,
) -> Option<FnID> {
self.as_ref()
.map(|s| s.lower(b, imports, output, self.origin))
.flatten()
} }
} }
impl PFunction { impl PFunction {
pub fn lower( pub fn lower(&self, ctx: &mut ModuleLowerCtx, origin: Origin) -> Option<FnID> {
&self,
b: &mut UModuleBuilder,
imports: &mut Imports,
output: &mut CompilerOutput,
origin: Origin,
) -> Option<FnID> {
let header = self.header.as_ref()?; let header = self.header.as_ref()?;
let name = header.name.as_ref()?.0.clone(); let name = header.name.as_ref()?.0.clone();
let (generics, args, ret) = if let Some(header) = self.header.as_ref() { let (generics, args, ret) = if let Some(header) = self.header.as_ref() {
( (
header.gargs.iter().flat_map(|a| a.lower(b)).collect(), header
.gargs
.iter()
.flat_map(|a| a.lower(ctx).map(|g| (g.0, g.1, a.origin)))
.collect(),
header header
.args .args
.iter() .iter()
.flat_map(|a| Some(a.lower(b, output)?)) .flat_map(|a| Some(a.lower(ctx)?))
.collect(), .collect(),
match &header.ret { match &header.ret {
Some(ty) => ty.lower(b, output), Some(ty) => ty.lower(ctx),
None => b.def_ty(Type::Unit), None => ctx.def_ty(Type::Unit),
}, },
) )
} else { } else {
(Vec::new(), Vec::new(), b.tc.error) (Vec::new(), Vec::new(), ctx.tc.error)
}; };
let gargs = generics.iter().map(|g| g.1).collect(); let gargs = generics.iter().map(|g| g.1).collect();
let generics = generics.into_iter().collect(); let generics = generics
.into_iter()
.map(|g| {
(
g.0,
ctx.def_ident(UIdent {
status: IdentStatus::Res(Res::Generic(g.1)),
origin: g.2,
}),
)
})
.collect::<Vec<_>>();
ctx.ident_stack.extend(generics.into_iter());
let instructions = { let instructions = {
let mut var_stack = NameStack::new(); let mut fctx = FnLowerCtx {
let mut ctx = FnLowerCtx {
instructions: Vec::new(), instructions: Vec::new(),
var_stack: &mut var_stack, ctx,
b,
output,
origin: self.body.origin, origin: self.body.origin,
generics: &generics,
imports,
}; };
let res = self.body.lower(&mut ctx); let res = self.body.lower(&mut fctx);
let mut instructions = ctx.instructions; let mut instructions = fctx.instructions;
if let Some(src) = res { if let Some(src) = res {
let origin = b.idents[src].origin; let origin = ctx.idents[src].origin;
instructions.push(UInstrInst { instructions.push(UInstrInst {
origin, origin,
i: UInstruction::Ret { src }, i: UInstruction::Ret { src },
@@ -84,35 +78,37 @@ impl PFunction {
ret, ret,
instructions, instructions,
}; };
Some(b.def_fn(f)) Some(ctx.def_fn(f))
} }
} }
pub struct FnLowerCtx<'a, 'b> { pub struct FnLowerCtx<'a, 'b> {
pub b: &'a mut UModuleBuilder<'b>, pub ctx: &'a mut ModuleLowerCtx<'b>,
pub instructions: Vec<UInstrInst>, pub instructions: Vec<UInstrInst>,
pub output: &'a mut CompilerOutput,
pub origin: FileSpan, pub origin: FileSpan,
pub imports: &'a mut Imports,
pub var_stack: &'a mut NameStack<VarID>,
pub generics: &'a HashMap<String, GenericID>,
} }
impl<'a, 'b> FnLowerCtx<'a, 'b> { impl<'a, 'b> FnLowerCtx<'a, 'b> {
pub fn var(&mut self, node: &Node<parser::PIdent>) -> IdentID { pub fn ident(&mut self, node: &Node<parser::PIdent>) -> IdentID {
let inst = UIdent { let inst = UIdent {
status: if let Some(n) = node.as_ref() { status: if let Some(n) = node.as_ref() {
if let Some(&var) = self.var_stack.search(&n.0) { if let Some(&res) = self.ident_stack.search(&n.0) {
IdentStatus::Var(var) return res;
} else { } else {
IdentStatus::Unres { IdentStatus::Unres {
path: ModPath { path: vec![MemberIdent {
id: self.b.module, ty: MemberTy::Member,
path: Vec::new(),
},
name: n.0.clone(), name: n.0.clone(),
origin: node.origin,
gargs: Vec::new(), gargs: Vec::new(),
fields: Vec::new(), }],
base: MemRes {
mem: Member {
id: MemberID::Module(self.module),
},
origin: self.origin,
gargs: Vec::new(),
},
} }
} }
} else { } else {
@@ -120,16 +116,17 @@ impl<'a, 'b> FnLowerCtx<'a, 'b> {
}, },
origin: node.origin, origin: node.origin,
}; };
self.def_var_inst(inst) self.def_ident(inst)
} }
pub fn err(&mut self, msg: String) { pub fn err(&mut self, msg: String) {
self.output.err(CompilerMsg::new(msg, self.origin)) let origin = self.origin;
self.output.err(CompilerMsg::new(msg, origin))
} }
pub fn err_at(&mut self, span: FileSpan, msg: String) { pub fn err_at(&mut self, span: FileSpan, msg: String) {
self.output.err(CompilerMsg::new(msg, span)) self.output.err(CompilerMsg::new(msg, span))
} }
pub fn temp<T: Typable>(&mut self, ty: T) -> IdentID { pub fn temp<T: Typable>(&mut self, ty: T) -> IdentID {
self.b.temp_var(self.origin, ty) self.ctx.temp_var(self.origin, ty)
} }
pub fn push(&mut self, i: UInstruction) { pub fn push(&mut self, i: UInstruction) {
self.push_at(i, self.origin); self.push_at(i, self.origin);
@@ -139,27 +136,46 @@ impl<'a, 'b> FnLowerCtx<'a, 'b> {
} }
pub fn branch<'c>(&'c mut self) -> FnLowerCtx<'c, 'b> { pub fn branch<'c>(&'c mut self) -> FnLowerCtx<'c, 'b> {
FnLowerCtx { FnLowerCtx {
b: self.b, ctx: self.ctx,
instructions: Vec::new(), instructions: Vec::new(),
generics: self.generics,
var_stack: self.var_stack,
output: self.output,
origin: self.origin, origin: self.origin,
imports: self.imports,
} }
} }
} }
impl<'b> Deref for FnLowerCtx<'_, 'b> { impl<'b> Deref for FnLowerCtx<'_, 'b> {
type Target = UModuleBuilder<'b>; type Target = ModuleLowerCtx<'b>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
self.b self.ctx
} }
} }
impl DerefMut for FnLowerCtx<'_, '_> { impl DerefMut for FnLowerCtx<'_, '_> {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
self.b self.ctx
}
}
pub trait FnLowerable {
type Output;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output>;
}
impl<T: FnLowerable> FnLowerable for Node<T> {
type Output = T::Output;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<T::Output> {
let old_span = ctx.origin;
ctx.origin = self.origin;
let res = self.as_ref()?.lower(ctx);
ctx.origin = old_span;
res
}
}
impl<T: FnLowerable> FnLowerable for Box<T> {
type Output = T::Output;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<T::Output> {
self.as_ref().lower(ctx)
} }
} }

View File

@@ -4,65 +4,131 @@ mod block;
mod def; mod def;
mod expr; mod expr;
mod func; mod func;
mod map;
mod struc; mod struc;
mod ty; mod ty;
mod map;
use std::{
collections::HashMap,
ops::{Deref, DerefMut},
};
use super::*; use super::*;
use crate::ir::{Type, UFunc, UModuleBuilder}; use crate::{
ir::{
IdentID, IdentStatus, ModID, Origin, Res, Type, TypeID, UFunc, UIdent, UModule, UProgram,
UVar,
},
util::NameStack,
};
pub use func::{FnLowerCtx, FnLowerable};
impl PModule { impl PModule {
pub fn lower( pub fn lower(
&self, &self,
path: Vec<String>, path: Vec<String>,
p: &mut UModuleBuilder, p: &mut UProgram,
imports: &mut Imports, imports: &mut Imports,
output: &mut CompilerOutput, output: &mut CompilerOutput,
) { ) -> ModID {
let name = path.last().unwrap().clone(); let name = path.last().unwrap().clone();
p.set_module(path); let f = UFunc {
let fid = p.def_searchable(&name, None, self.block.origin); name: name.clone(),
p.push_name(&name); args: Vec::new(),
let mut fctx = FnLowerCtx { instructions: Vec::new(),
b: p, gargs: Vec::new(),
ret: p.def_ty(Type::Unit),
origin: self.block.origin,
};
let fid = p.def_fn(f);
let mid = p.def_module(UModule {
name,
members: HashMap::new(),
parent: None,
func: fid,
});
let mut ctx = ModuleLowerCtx {
p,
output,
module: mid,
temp: 0,
ident_stack: NameStack::new(),
};
let mut fctx = FnLowerCtx {
ctx: &mut ctx,
instructions: Vec::new(), instructions: Vec::new(),
output,
origin: self.block.origin, origin: self.block.origin,
imports,
}; };
self.block.lower(&mut fctx); self.block.lower(&mut fctx);
let f = UFunc { p.fns[fid].instructions = fctx.instructions;
args: Vec::new(), mid
instructions: fctx.instructions, }
ret: Type::Unit, }
pub struct ModuleLowerCtx<'a> {
pub p: &'a mut UProgram,
pub output: &'a mut CompilerOutput,
pub module: ModID,
pub temp: usize,
pub ident_stack: NameStack<IdentID>,
}
impl<'a> ModuleLowerCtx<'a> {
pub fn new(program: &'a mut UProgram, output: &'a mut CompilerOutput, id: ModID) -> Self {
Self {
p: program,
output,
module: id,
temp: 0,
ident_stack: NameStack::new(),
}
}
pub fn temp_var(&mut self, origin: Origin, ty: impl Typable) -> IdentID {
self.temp_var_inner(origin, ty)
}
fn temp_var_inner(&mut self, origin: Origin, ty: impl Typable) -> IdentID {
let var = UVar {
name: format!("temp{}", self.temp),
ty: ty.ty(self),
origin,
parent: None,
children: HashMap::new(),
}; };
p.write(fid, f); let id = self.p.def_var(var);
p.pop_name(); self.temp += 1;
self.def_ident(UIdent {
status: IdentStatus::Res(Res::Var(id)),
origin,
})
} }
} }
pub use func::FnLowerCtx; pub trait Typable {
use import::Imports; fn ty(self, p: &mut UProgram) -> TypeID;
pub trait FnLowerable {
type Output;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output>;
} }
impl<T: FnLowerable> FnLowerable for Node<T> { impl Typable for Type {
type Output = T::Output; fn ty(self, p: &mut UProgram) -> TypeID {
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<T::Output> { p.def_ty(self)
let old_span = ctx.origin;
ctx.origin = self.origin;
let res = self.as_ref()?.lower(ctx);
ctx.origin = old_span;
res
} }
} }
impl<T: FnLowerable> FnLowerable for Box<T> { impl Typable for TypeID {
type Output = T::Output; fn ty(self, p: &mut UProgram) -> TypeID {
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<T::Output> { self
self.as_ref().lower(ctx) }
}
impl Deref for ModuleLowerCtx<'_> {
type Target = UProgram;
fn deref(&self) -> &Self::Target {
self.p
}
}
impl DerefMut for ModuleLowerCtx<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.p
} }
} }

View File

@@ -1,18 +1,16 @@
use crate::{ use crate::{
common::{CompilerOutput, FileSpan}, common::FileSpan,
ir::{StructField, StructID, UModuleBuilder, UProgram, UStruct}, ir::{StructField, StructID, UStruct},
parser::{Node, PStruct, PStructFields}, parser::{PStruct, PStructFields},
}; };
use super::ModuleLowerCtx;
impl PStruct { impl PStruct {
pub fn lower( pub fn lower(&self, ctx: &mut ModuleLowerCtx, span: FileSpan) -> Option<StructID> {
&self, ctx.ident_stack.push();
id: StructID, let gmap: Vec<_> = self.generics.iter().flat_map(|a| a.lower(ctx)).collect();
b: &mut UModuleBuilder, let gargs = gmap.iter().map(|(_, id)| *id).collect();
output: &mut CompilerOutput,
span: FileSpan,
) -> Option<()> {
let generics = self.generics.iter().flat_map(|a| a.lower(b)).collect();
let fields = match &self.fields { let fields = match &self.fields {
PStructFields::Named(nodes) => nodes PStructFields::Named(nodes) => nodes
.iter() .iter()
@@ -20,7 +18,7 @@ impl PStruct {
let def = n.as_ref()?; let def = n.as_ref()?;
let name = def.name.as_ref()?.to_string(); let name = def.name.as_ref()?.to_string();
let tynode = def.ty.as_ref()?; let tynode = def.ty.as_ref()?;
let ty = tynode.lower(b, output); let ty = tynode.lower(ctx);
Some((name, ty)) Some((name, ty))
}) })
.collect(), .collect(),
@@ -28,7 +26,7 @@ impl PStruct {
.iter() .iter()
.enumerate() .enumerate()
.flat_map(|(i, n)| { .flat_map(|(i, n)| {
let ty = n.as_ref()?.lower(b, output, span); let ty = n.as_ref()?.lower(ctx, span);
Some((format!("{i}"), ty)) Some((format!("{i}"), ty))
}) })
.collect(), .collect(),
@@ -38,21 +36,12 @@ impl PStruct {
.map(|(name, ty)| (name, StructField { ty })) .map(|(name, ty)| (name, StructField { ty }))
.collect(); .collect();
let name = self.name.as_ref()?.to_string(); let name = self.name.as_ref()?.to_string();
b.def_data(UStruct { ctx.ident_stack.pop();
Some(ctx.def_struct(UStruct {
name, name,
gargs: generics, gargs,
fields, fields,
origin: span, origin: span,
}); }))
Some(())
}
}
impl Node<PStruct> {
pub fn lower(&self, id: StructID, p: &mut UProgram, output: &mut CompilerOutput) -> Option<()> {
let s = self.as_ref()?;
let name = s.name.as_ref()?;
s.lower(id, p, output, self.origin);
Some(())
} }
} }

View File

@@ -1,76 +1,76 @@
use crate::{ use crate::{
ir::{GenericID, MemberID, ModPath, Type, TypeID, UGeneric, UModuleBuilder, UProgram}, ir::{GenericID, MemberIdent, MemberPath, Type, TypeID, UGeneric, UProgram},
parser::PGenericDef, parser::PGenericDef,
}; };
use super::{CompilerOutput, FileSpan, Node, PType}; use super::{FileSpan, ModuleLowerCtx, Node, PType};
impl Node<Box<PType>> { impl Node<Box<PType>> {
pub fn lower(&self, p: &mut UModuleBuilder, output: &mut CompilerOutput) -> TypeID { pub fn lower(&self, ctx: &mut ModuleLowerCtx) -> TypeID {
self.as_ref() self.as_ref()
.map(|t| t.lower(p, output, self.origin)) .map(|t| t.lower(ctx, self.origin))
.unwrap_or(p.error) .unwrap_or(ctx.tc.error)
} }
} }
impl Node<PType> { impl Node<PType> {
pub fn lower(&self, p: &mut UModuleBuilder, output: &mut CompilerOutput) -> TypeID { pub fn lower(&self, ctx: &mut ModuleLowerCtx) -> TypeID {
self.as_ref() self.as_ref()
.map(|t| t.lower(p, output, self.origin)) .map(|t| t.lower(ctx, self.origin))
.unwrap_or(p.error) .unwrap_or(ctx.tc.error)
} }
} }
fn test() {}
impl PType { impl PType {
pub fn lower( pub fn lower(&self, ctx: &mut ModuleLowerCtx, mut origin: FileSpan) -> TypeID {
&self,
p: &mut UModuleBuilder,
output: &mut CompilerOutput,
mut origin: FileSpan,
) -> TypeID {
let mut ty = self; let mut ty = self;
let mut path = Vec::new(); let mut path = Vec::new();
while let PType::Member(node, ident) = ty { while let PType::Member(node, ident) = ty {
ty = if let Some(t) = node.as_ref() { ty = if let Some(t) = node.as_ref() {
let Some(name) = ident.as_ref() else { let Some(name) = ident.as_ref() else {
return p.error; return ctx.tc.error;
}; };
origin = node.origin; origin = node.origin;
path.push(MemberID { path.push(MemberIdent {
name: name.0.clone(), name: name.0.clone(),
origin: ident.origin, origin: ident.origin,
}); });
&**t &**t
} else { } else {
return p.error; return ctx.tc.error;
}; };
} }
if !path.is_empty() { if !path.is_empty() {
let PType::Ident(id) = ty else { let PType::Ident(id) = ty else {
return p.error; return ctx.tc.error;
}; };
path.push(MemberID { path.push(MemberIdent {
name: id.0.clone(), name: id.0.clone(),
origin, origin,
}); });
let ty = Type::Unres(ModPath { id: p.module, path }); path.reverse();
return p.def_ty(ty); let ty = Type::Unres(MemberPath {
id: ctx.module,
path,
});
return ctx.def_ty(ty);
} }
let ty = match ty { let ty = match ty {
PType::Member(_, _) => unreachable!(), PType::Member(_, _) => unreachable!(),
PType::Ident(node) => { PType::Ident(node) => {
path.push(MemberID { path.push(MemberIdent {
name: node.0.clone(), name: node.0.clone(),
origin, origin,
}); });
path.reverse(); path.reverse();
Type::Unres(ModPath { id: p.module, path }) Type::Unres(MemberPath {
id: ctx.module,
path,
})
} }
PType::Ref(node) => node.lower(p, output).rf(), PType::Ref(node) => node.lower(ctx).rf(),
PType::Generic(node, nodes) => todo!(), PType::Generic(node, nodes) => todo!(),
}; };
p.def_ty(ty) ctx.def_ty(ty)
} }
} }

View File

@@ -1,12 +1,12 @@
use std::fmt::{Debug, Write}; use std::fmt::{Debug, Write};
use crate::{common::FilePos, parser::NodeParsableWith}; use crate::{common::FilePos, ir::MemberTy, parser::NodeParsableWith};
use super::{ use super::{
op::{InfixOp, PostfixOp}, op::{InfixOp, PostfixOp},
util::parse_list, util::parse_list,
CompilerMsg, Keyword, Node, PAsmBlock, PBlock, PIdent, PLiteral, PMap, Parsable, ParseResult, CompilerMsg, Keyword, Node, PAsmBlock, PBlock, PIdent, PLiteral, PMap, PType, Parsable,
ParserCtx, Symbol, ParseResult, ParserCtx, Symbol,
}; };
type BoxNode = Node<Box<PExpr>>; type BoxNode = Node<Box<PExpr>>;
@@ -19,8 +19,8 @@ pub enum PExpr {
Block(Node<PBlock>), Block(Node<PBlock>),
Call(BoxNode, Vec<Node<PExpr>>), Call(BoxNode, Vec<Node<PExpr>>),
Group(BoxNode), Group(BoxNode),
Field(BoxNode, Node<PIdent>), Member(BoxNode, MemberTy, Node<PIdent>),
Member(BoxNode, Node<PIdent>), Generic(BoxNode, Vec<Node<PType>>),
AsmBlock(Node<PAsmBlock>), AsmBlock(Node<PAsmBlock>),
Construct(BoxNode, Node<PMap>), Construct(BoxNode, Node<PMap>),
If(BoxNode, BoxNode), If(BoxNode, BoxNode),
@@ -65,16 +65,25 @@ impl PExpr {
e1 = Self::Call(Node::new(e1, span).bx(), args); e1 = Self::Call(Node::new(e1, span).bx(), args);
continue; continue;
} else if next.is_symbol(Symbol::OpenCurly) { } else if next.is_symbol(Symbol::OpenCurly) {
ctx.next();
let map = ctx.parse()?; let map = ctx.parse()?;
e1 = Self::Construct(Node::new(e1, span).bx(), map); e1 = Self::Construct(Node::new(e1, span).bx(), map);
continue; continue;
} else if next.is_symbol(Symbol::Dot) { } else if next.is_symbol(Symbol::Dot) {
ctx.next();
let field = ctx.parse()?; let field = ctx.parse()?;
e1 = Self::Field(Node::new(e1, span).bx(), field); e1 = Self::Member(Node::new(e1, span).bx(), MemberTy::Field, field);
continue; continue;
} else if next.is_symbol(Symbol::DoubleColon) { } else if next.is_symbol(Symbol::DoubleColon) {
ctx.next();
if ctx.peek().is_some_and(|i| i.is_symbol(Symbol::OpenAngle)) {
ctx.next();
let gargs = parse_list(ctx, Symbol::CloseAngle)?;
e1 = Self::Generic(Node::new(e1, span).bx(), gargs);
} else {
let field = ctx.parse()?; let field = ctx.parse()?;
e1 = Self::Member(Node::new(e1, span).bx(), field); e1 = Self::Member(Node::new(e1, span).bx(), MemberTy::Member, field);
}
continue; continue;
} else if let Some(op) = PostfixOp::from_token(next) { } else if let Some(op) = PostfixOp::from_token(next) {
ctx.next(); ctx.next();
@@ -185,13 +194,13 @@ impl Debug for PExpr {
PExpr::PostfixOp(e, op) => write!(f, "({:?}{})", e, op.str())?, PExpr::PostfixOp(e, op) => write!(f, "({:?}{})", e, op.str())?,
PExpr::Group(inner) => inner.fmt(f)?, PExpr::Group(inner) => inner.fmt(f)?,
PExpr::AsmBlock(inner) => inner.fmt(f)?, PExpr::AsmBlock(inner) => inner.fmt(f)?,
PExpr::Construct(node, inner) => inner.fmt(f)?, PExpr::Construct(node, inner) => write!(f, "{:?}{:?}", node, inner)?,
PExpr::If(cond, res) => write!(f, "if {cond:?} then {res:?}")?, PExpr::If(cond, res) => write!(f, "if {cond:?} then {res:?}")?,
PExpr::Loop(res) => write!(f, "loop -> {res:?}")?, PExpr::Loop(res) => write!(f, "loop -> {res:?}")?,
PExpr::Break => write!(f, "break")?, PExpr::Break => write!(f, "break")?,
PExpr::Continue => write!(f, "continue")?, PExpr::Continue => write!(f, "continue")?,
PExpr::Field(e1, name) => write!(f, "{:?}.{:?}", e1, name)?, PExpr::Member(e1, ty, name) => write!(f, "{:?}{}{:?}", e1, ty.sep(), name)?,
PExpr::Member(e1, name) => write!(f, "{:?}::{:?}", e1, name)?, PExpr::Generic(e1, gargs) => write!(f, "{:?}<{:?}>", e1, gargs)?,
} }
Ok(()) Ok(())
} }

View File

@@ -1,23 +1,45 @@
use std::collections::HashMap; use std::collections::HashMap;
pub struct NameStack<T>(Vec<HashMap<String, T>>); pub struct NameStack<T> {
base: HashMap<String, T>,
levels: Vec<HashMap<String, T>>,
}
impl<T> NameStack<T> { impl<T> NameStack<T> {
pub fn new() -> Self { pub fn new() -> Self {
Self(vec![HashMap::new()]) Self {
base: HashMap::new(),
levels: Vec::new(),
}
} }
pub fn search(&self, name: &str) -> Option<&T> { pub fn search(&self, name: &str) -> Option<&T> {
for level in self.0.iter().rev() { for level in self.levels.iter().rev() {
if let Some(v) = level.get(name) { if let Some(v) = level.get(name) {
return Some(v); return Some(v);
} }
} }
None self.base.get(name)
} }
pub fn push(&mut self) { pub fn push(&mut self) {
self.0.push(HashMap::new()); self.levels.push(HashMap::new());
} }
pub fn pop(&mut self) { pub fn pop(&mut self) {
self.0.pop(); self.levels.pop();
}
fn cur(&mut self) -> &mut HashMap<String, T> {
self.levels.last_mut().unwrap_or(&mut self.base)
}
pub fn insert(&mut self, name: String, v: T) -> bool {
let cur = self.cur();
if cur.contains_key(&name) {
return true;
}
cur.insert(name, v);
false
}
pub fn extend(&mut self, iter: impl Iterator<Item = (String, T)>) {
for (name, v) in iter {
self.insert(name, v);
}
} }
} }