trudging through the snow
This commit is contained in:
40
ideas
40
ideas
@@ -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!!!
|
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)>,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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::*;
|
||||||
|
|||||||
@@ -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
92
src/ir/lower/res.rs
Normal 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),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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::*;
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
gargs
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|
||||||
|
|||||||
@@ -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)?),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user