getting closer

This commit is contained in:
2025-05-04 14:21:27 -04:00
parent 6583d47ef8
commit 9368d6dcd0
16 changed files with 423 additions and 327 deletions

View File

@@ -1,10 +1,10 @@
use crate::{compiler::arch::riscv::*, ir::VarInst};
use crate::{compiler::arch::riscv::*, ir::UIdent};
pub type RV64Instruction = LinkerInstruction<RegRef, VarInst>;
pub type RV64Instruction = LinkerInstruction<RegRef, UIdent>;
#[derive(Copy, Clone)]
pub enum RegRef {
Var(VarInst),
Var(UIdent),
Reg(Reg),
}

View File

@@ -1,7 +1,7 @@
use std::collections::HashMap;
use crate::ir::{AsmBlockArgType, Size, StructTy, SymbolSpace, Type, UFunc, UInstrInst, VarOffset};
StructTy
use crate::ir::{AsmBlockArgType, Size, LStructInst, SymbolSpace, Type, UFunc, UInstrInst, VarOffset};
LStructInst
use super::{
IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, UInstruction, UProgram, VarID,
};
@@ -42,14 +42,14 @@ impl LProgram {
}
}
pub struct StructInst {
pub struct LStructInst {
offsets: Vec<Len>,
types: Vec<Type>,
order: HashMap<String, usize>,
size: Size,
}
impl StructInst {
impl LStructInst {
pub fn offset(&self, name: &str) -> Option<Len> {
Some(self.offsets[*self.order.get(name)?])
}
@@ -82,7 +82,7 @@ pub struct LFunctionBuilderData<'a> {
instrs: Vec<LInstruction>,
stack: HashMap<VarID, Size>,
subvar_map: HashMap<VarID, VarOffset>,
struct_insts: HashMap<StructInst, StructInst>,
struct_insts: HashMap<LStructInst, LStructInst>,
makes_call: bool,
loopp: Option<LoopCtx>,
}
@@ -376,10 +376,10 @@ impl LFunctionBuilderData<'_> {
pub fn addr_size(&self) -> Size {
64StructTy
}
pub fn struct_inst(&mut self, p: &UProgram, ty: &StructTy) -> &StructInst {
pub fn struct_inst(&mut self, p: &UProgram, ty: &LStructInst) -> &LStructInst {
// normally I'd let Some(..) here and return, but polonius does not exist :grief:
if self.struct_insts.get(ty).is_none() {
let StructInst { id, args } = ty;
let LStructInst { id, args } = ty;
let struc = p.expect(*id);
let mut types = Vec::new();
let mut sizes = struc
@@ -412,7 +412,7 @@ impl LFunctionBuilderData<'_> {
}
self.struct_insts.insert(
ty.clone(),
StructInst {
LStructInst {
offsets,
order,
types,
@@ -423,7 +423,7 @@ impl LFunctionBuilderData<'_> {
self.struct_insts.get(ty).unwrap()
}
pub fn field_offset(&mut self, p: &UProgram, sty: &StructInst, field: &str) -> Option<Len> {
pub fn field_offset(&mut self, p: &UProgram, sty: &LStructInst, field: &str) -> Option<Len> {
let inst = self.struct_inst(p, sty);
Some(inst.offset(field)?)
}

View File

@@ -3,7 +3,7 @@ use crate::{
ir::ID,
};
use super::{KindTy, Origin, StructID, TypeID, UProgram};
use super::{KindTy, Origin, Res, StructID, TypeID, UProgram};
pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec<ResErr>) {
for err in errs {
@@ -82,18 +82,18 @@ pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec<ResErr>)
origin,
found,
expected,
id,
} => output.err(CompilerMsg::new(
{
let name = match found {
KindTy::Type => &p.type_name(ID::new(id)),
KindTy::Var => &p.vars[id].name,
KindTy::Struct => &p.structs[id].name,
let name = match &found {
Res::Fn(fty) => &p.fns[fty.id].name,
Res::Type(id) => &p.type_name(id),
Res::Var(id) => &p.vars[id].name,
Res::Struct(sty) => &p.structs[sty.id].name,
};
format!(
"Expected {}, found {} '{}'",
expected.str(),
found.str(),
found.kind_str(),
name
)
},
@@ -106,12 +106,20 @@ pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec<ResErr>)
}
}
#[derive(Debug, Clone)]
pub enum ResErr {
UnknownModule {
origin: Origin,
name: String,
},
UnknownMember {
origin: Origin,
name: String,
},
KindMismatch {
origin: Origin,
expected: KindTy,
found: KindTy,
id: usize,
found: Res,
},
UnexpectedField {
origin: Origin,
@@ -158,6 +166,7 @@ pub enum ResErr {
},
}
#[derive(Debug, Clone)]
pub enum ControlFlowOp {
Break,
Continue,
@@ -172,6 +181,7 @@ impl ControlFlowOp {
}
}
#[derive(Debug, Clone)]
pub struct TypeMismatch {
pub dst: TypeID,
pub src: TypeID,

View File

@@ -1,53 +1,53 @@
use std::{collections::HashMap, fmt::Write};
use super::{arch::riscv64::RV64Instruction, DataID, FnID, Origin, UFunc, VarInst, VarInstID};
use super::{arch::riscv64::RV64Instruction, DataID, FnID, Origin, UFunc, UIdent, IdentID};
use crate::{compiler::arch::riscv::Reg, util::Padder};
#[derive(Clone)]
pub enum UInstruction {
Mv {
dst: VarInstID,
src: VarInstID,
dst: IdentID,
src: IdentID,
},
Ref {
dst: VarInstID,
src: VarInstID,
dst: IdentID,
src: IdentID,
},
Deref {
dst: VarInstID,
src: VarInstID,
dst: IdentID,
src: IdentID,
},
LoadData {
dst: VarInstID,
dst: IdentID,
src: DataID,
},
LoadSlice {
dst: VarInstID,
dst: IdentID,
src: DataID,
},
LoadFn {
dst: VarInstID,
dst: IdentID,
src: FnID,
},
Call {
dst: VarInstID,
f: VarInstID,
args: Vec<VarInstID>,
dst: IdentID,
f: IdentID,
args: Vec<IdentID>,
},
AsmBlock {
instructions: Vec<RV64Instruction>,
args: Vec<AsmBlockArg>,
},
Ret {
src: VarInstID,
src: IdentID,
},
Construct {
dst: VarInstID,
struc: VarInstID,
fields: HashMap<String, VarInstID>,
dst: IdentID,
struc: IdentID,
fields: HashMap<String, IdentID>,
},
If {
cond: VarInstID,
cond: IdentID,
body: Vec<UInstrInst>,
},
Loop {
@@ -71,7 +71,7 @@ impl std::fmt::Debug for UInstrInst {
#[derive(Debug, Clone)]
pub struct AsmBlockArg {
pub var: VarInstID,
pub var: IdentID,
pub reg: Reg,
pub ty: AsmBlockArgType,
}

View File

@@ -1,4 +1,4 @@
use super::{Type, UInstrInst, UInstruction};
use super::{FnInst, ResErr, StructInst, Type, UInstrInst, UInstruction};
use crate::{
common::FileSpan,
ir::{Len, ID},
@@ -7,57 +7,9 @@ use std::{collections::HashMap, fmt::Debug};
pub type NamePath = Vec<String>;
// "effective" (externally visible) kinds
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KindTy {
Type,
Var,
Struct,
Fn,
}
impl KindTy {
pub fn str(&self) -> &'static str {
match self {
KindTy::Type => "type",
KindTy::Var => "variable",
KindTy::Fn => "function",
KindTy::Struct => "struct",
}
}
}
pub trait Kind {
fn ty() -> KindTy;
}
impl Kind for UFunc {
fn ty() -> KindTy {
KindTy::Fn
}
}
impl Kind for UVar {
fn ty() -> KindTy {
KindTy::Var
}
}
impl Kind for UStruct {
fn ty() -> KindTy {
KindTy::Struct
}
}
impl Kind for Type {
fn ty() -> KindTy {
KindTy::Type
}
}
pub type FnID = ID<UFunc>;
pub type VarID = ID<UVar>;
pub type VarInstID = ID<VarInst>;
pub type IdentID = ID<UIdent>;
pub type TypeID = ID<Type>;
pub type GenericID = ID<UGeneric>;
pub type StructID = ID<UStruct>;
@@ -99,31 +51,33 @@ pub struct UVar {
pub origin: Origin,
pub ty: TypeID,
pub parent: Option<VarID>,
pub children: Vec<VarID>,
pub children: HashMap<String, VarID>,
}
/// these are more like "expressions", need to find good name
/// eg. a::b::c::<T,U>.d.e
#[derive(Clone, Debug)]
pub struct VarInst {
pub status: VarStatus,
pub struct UIdent {
pub status: IdentStatus,
pub origin: Origin,
}
#[derive(Clone, Debug)]
pub enum VarStatus {
pub enum IdentStatus {
Var(VarID),
Struct(StructID, Vec<TypeID>),
Struct(StructInst),
Fn(FnInst),
Type(TypeID),
Unres {
path: ModPath,
name: String,
mem: MemberID,
gargs: Vec<TypeID>,
fields: Vec<MemberID>,
},
Partial {
v: VarID,
PartialVar {
id: VarID,
fields: Vec<MemberID>,
},
Failed(ResErr),
Cooked,
}
@@ -209,13 +163,3 @@ impl<'a> Iterator for InstrIter<'a> {
}
}
impl VarInst {
pub fn id(&self) -> Option<VarID> {
match &self.status {
VarStatus::Var(id) => Some(*id),
VarStatus::Unres { .. } => None,
VarStatus::Partial { .. } => None,
VarStatus::Cooked => None,
}
}
}

View File

@@ -12,3 +12,4 @@ pub use kind::*;
pub use program::*;
pub use ty::*;
pub use error::*;
pub use resolve::*;

View File

@@ -11,7 +11,7 @@ pub struct UProgram {
pub data: Vec<UData>,
pub generics: Vec<UGeneric>,
pub vars: Vec<UVar>,
pub vars_insts: Vec<VarInst>,
pub idents: Vec<UIdent>,
pub types: Vec<Type>,
pub vfmap: HashMap<VarID, FnID>,
@@ -39,7 +39,7 @@ impl UProgram {
Self {
fns: Vec::new(),
vars: Vec::new(),
vars_insts: Vec::new(),
idents: Vec::new(),
structs: Vec::new(),
types: Vec::new(),
generics: Vec::new(),
@@ -66,8 +66,8 @@ impl UProgram {
push_id(&mut self.types, t)
}
pub fn def_var_inst(&mut self, i: VarInst) -> VarInstID {
push_id(&mut self.vars_insts, i)
pub fn def_var_inst(&mut self, i: UIdent) -> IdentID {
push_id(&mut self.idents, i)
}
pub fn def_generic(&mut self, g: UGeneric) -> GenericID {
@@ -85,12 +85,12 @@ impl UProgram {
pub fn type_name(&self, ty: impl Typed) -> String {
match ty.ty(self) {
Type::Struct(ty) => {
format!("{}{}", self.structs[ty.id].name, self.gparams_str(&ty.args))
format!("{}{}", self.structs[ty.id].name, self.gparams_str(&ty.gargs))
}
Type::FnRef(ty) => {
format!(
"fn{}({}) -> {}",
&self.gparams_str(&ty.args),
&self.gparams_str(&ty.gargs),
&self.type_list_str(self.fns[ty.id].args.iter().map(|v| self.vars[v].ty)),
&self.type_name(self.fns[ty.id].ret)
)
@@ -146,21 +146,21 @@ impl<'a> UModuleBuilder<'a> {
temp: 0,
}
}
pub fn temp_var(&mut self, origin: Origin, ty: impl Typable) -> VarInstID {
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) -> VarInstID {
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: Vec::new(),
children: HashMap::new(),
};
let id = self.p.def_var(var);
self.temp += 1;
self.def_var_inst(VarInst {
status: VarStatus::Var(id),
self.def_var_inst(UIdent {
status: IdentStatus::Var(id),
origin,
})
}

View File

@@ -1,9 +1,11 @@
use super::{
report_errs, ControlFlowOp, DataID, Kind, MemberTy, Origin, ResErr, Type, TypeID, TypeMismatch, UData, UFunc, UGeneric, UInstrInst, UInstruction, UModule, UProgram, UStruct, UVar, VarID, VarInst, VarInstID, VarStatus
inst_fn_ty, inst_struct_ty, report_errs, ControlFlowOp, DataID, FnInst, IdentID, IdentStatus,
MemberTy, Origin, ResErr, StructInst, Type, TypeID, TypeMismatch, UData, UFunc, UGeneric,
UIdent, UInstrInst, UInstruction, UModule, UProgram, UStruct, UVar, VarID,
};
use crate::{
common::{CompilerMsg, CompilerOutput},
ir::{inst_fn_var, inst_struct_ty, KindTy, ID},
ir::{inst_fn_var, ID},
};
use std::{
collections::HashSet,
@@ -21,7 +23,7 @@ impl UProgram {
changed: false,
types: &mut self.types,
s: Sources {
insts: &mut self.vars_insts,
idents: &mut self.idents,
vars: &mut self.vars,
fns: &self.fns,
structs: &self.structs,
@@ -44,13 +46,12 @@ impl UProgram {
}
// this currently works bc expressions create temporary variables
// although you can't do things like loop {return 3} (need to analyze control flow)
if !matches!(data.types[f.ret], Type::Unit) {
if f.instructions
if !matches!(data.types[f.ret], Type::Unit)
&& f.instructions
.last()
.is_none_or(|i| !matches!(i.i, UInstruction::Ret { .. }))
{
data.errs.push(ResErr::NoReturn { fid });
}
{
data.errs.push(ResErr::NoReturn { fid });
}
}
while !data.unfinished.is_empty() && data.changed {
@@ -60,7 +61,23 @@ impl UProgram {
resolve_instr(&mut data, ctx);
}
}
let errs = data.errs;
let mut 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);
for var in &self.vars {
match &self.types[var.ty] {
@@ -93,13 +110,8 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
let mut res = InstrRes::Finished;
match &ctx.i.i {
UInstruction::Call { dst, f, args } => {
let fty = data.res_id(f, ctx)?;
let Type::FnRef(ftyy) = data.types[fty].clone() else {
let origin = f.origin(data);
data.errs.push(ResErr::NotCallable { origin, ty: fty });
return None;
};
let f = &data.s.fns[ftyy.id];
let fi = data.res_id::<UFunc>(f, ctx)?;
let f = &data.s.fns[fi.id];
for (src, dest) in args.iter().zip(&f.args) {
res |= data.match_types(dest, src, src);
}
@@ -109,14 +121,14 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
res |= data.match_types(dst, src, src);
}
UInstruction::Ref { dst, src } => {
let dstid = data.res_id(dst, ctx)?;
let dstid = data.res_ty_id::<UVar>(dst, ctx)?;
let Type::Ref(dest_ty) = data.types[dstid] else {
compiler_error()
};
res |= data.match_types(dest_ty, src, src);
}
UInstruction::Deref { dst, src } => {
let srcid = data.res_id(src, ctx)?;
let srcid = data.res_ty_id::<UVar>(src, ctx)?;
let Type::Ref(src_ty) = data.types[srcid] else {
let origin = src.origin(data);
data.errs.push(ResErr::CannotDeref { origin, ty: srcid });
@@ -148,11 +160,8 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
res |= data.match_types(ctx.ret, src, src);
}
UInstruction::Construct { dst, struc, fields } => {
let id = data.res_id(dst, ctx, KindTy::Struct)?;
let Type::Struct(sty) = &data.types[id] else {
return None;
};
let sid = sty.id;
let si = data.res_id::<UStruct>(dst, ctx)?;
let sid = si.id;
let st = &data.s.structs[sid];
let mut used = HashSet::new();
for (name, field) in &st.fields {
@@ -180,7 +189,7 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
}
}
UInstruction::If { cond, body } => {
if let Some(id) = data.res_id(cond, ctx, KindTy::Var) {
if let Some(id) = data.res_ty_id::<UVar>(cond, ctx) {
if !matches!(data.types[id], Type::Bits(64)) {
let origin = cond.origin(data);
data.errs.push(ResErr::CondType { origin, ty: id });
@@ -262,7 +271,7 @@ pub fn match_types(data: &mut TypeResData, dst: impl TypeIDed, src: impl TypeIDe
if dest.id != src.id {
return error();
}
match_all(data, dest.args.iter().cloned(), src.args.iter().cloned())
match_all(data, dest.gargs.iter().cloned(), src.gargs.iter().cloned())
}
// (
// Type::Fn {
@@ -327,7 +336,7 @@ fn match_all(
}
struct Sources<'a> {
insts: &'a mut [VarInst],
idents: &'a mut [UIdent],
vars: &'a mut Vec<UVar>,
fns: &'a [UFunc],
structs: &'a [UStruct],
@@ -353,12 +362,12 @@ struct TypeResData<'a> {
impl<'a> ResData<'a> {
pub fn match_types(
&mut self,
dst: impl ResID<Type>,
src: impl ResID<Type>,
dst: impl Resolvable<Type>,
src: impl Resolvable<Type>,
origin: impl HasOrigin,
) -> InstrRes {
let dst = dst.try_id(&mut self.s, self.types, &mut self.errs, KindTy::Type)?;
let src = src.try_id(&mut self.s, self.types, &mut self.errs, KindTy::Type)?;
let dst = dst.try_res(&mut self.s, self.types, &mut self.errs)?;
let src = src.try_res(&mut self.s, self.types, &mut self.errs)?;
let res = match_types(
&mut TypeResData {
changed: &mut self.changed,
@@ -382,15 +391,24 @@ impl<'a> ResData<'a> {
}
}
}
pub fn try_res_id<K>(&mut self, x: impl ResID) -> Result<ID<K>, InstrRes> {
x.try_id(&mut self.s, &mut self.types, &mut self.errs)
.map(|id| resolve_refs(self.types, id))
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)
}
pub fn res_id<'b: 'a, K>(
pub fn res_ty_id<'b: 'a, K: ResKind>(
&mut self,
x: impl ResID<K>,
x: impl Resolvable<K>,
ctx: ResolveCtx<'b>,
) -> Option<ID<K>> {
) -> Option<TypeID>
where
K::Res: TypeIDed,
{
self.res_id::<K>(x, ctx).map(|i| i.type_id(&self.s))
}
pub fn res_id<'b: 'a, K: ResKind>(
&mut self,
x: impl Resolvable<K>,
ctx: ResolveCtx<'b>,
) -> Option<K::Res> {
match self.try_res_id(x) {
Ok(id) => return Some(id),
Err(InstrRes::Unfinished) => self.unfinished.push(ctx),
@@ -433,166 +451,293 @@ impl FromResidual<Option<Infallible>> for InstrRes {
}
}
trait ResID<K> {
fn try_id(
trait Resolvable<K: ResKind> {
fn try_res(
&self,
s: &mut Sources,
types: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
) -> Result<ID<K>, InstrRes>;
) -> Result<K::Res, InstrRes>;
}
impl<T: TypeIDed> ResID<Type> for T {
fn try_id(
impl<T: TypeIDed> Resolvable<Type> for T {
fn try_res(
&self,
s: &mut Sources,
_: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
kind: KindTy,
) -> Result<TypeID, InstrRes> {
Ok(self.type_id(s))
}
}
impl VarInst {
pub fn resolve(&mut self, s: &mut Sources) {
match &self.status {
VarStatus::Var(id) => self.status = VarStatus::Cooked,
VarStatus::Struct(id, ids) => todo!(),
VarStatus::Unres { path, name, gargs, fields } => todo!(),
VarStatus::Partial { v, fields } => todo!(),
VarStatus::Cooked => todo!(),
}
}
}
impl<K: Kind> ResID<K> for VarInstID {
fn try_id(
&self,
s: &mut Sources,
types: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
) -> Result<ID<K>, InstrRes> {
let kind = K::ty();
let inst = &mut s.insts[self];
let (id, fields) = match &mut inst.status {
VarStatus::Var(id) => {
return Ok(s.vars[id].ty)
},
VarStatus::Unres {
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,
name,
mem,
gargs,
fields,
} => {
let mut mid = path.id;
let mut depth = 0;
let mut count = 0;
for mem in &path.path {
let Some(&child) = s.modules[mid].children.get(&mem.name) else {
break;
};
depth += 1;
count += 1;
mid = child;
}
path.path.drain(0..depth);
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(name) else {
let Some(mem) = s.modules[mid].members.get(&mem.name) else {
return Err(InstrRes::Unfinished);
};
let vid = match mem.id {
match mem.id {
MemberTy::Fn(id) => {
if kind == KindTy::Fn {
return Ok(id.0.into());
}
if !matches!(kind, KindTy::Var | KindTy::Fn) {
errs.push(ResErr::KindMismatch {
origin: inst.origin,
expected: kind,
found: KindTy::Fn,
id: id.0,
if fields.len() > 0 {
ident.status = IdentStatus::Failed(ResErr::UnexpectedField {
origin: ident.origin,
});
return Err(InstrRes::Finished);
}
inst_fn_var(
let fty = FnInst {
id,
s.fns,
gargs,
inst.origin,
s.vars,
types,
s.generics,
errs,
)
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 !matches!(kind, KindTy::Var | KindTy::Any) {
errs.push(ResErr::KindMismatch {
origin: inst.origin,
expected: kind,
found: KindTy::Var,
id: id.0,
});
return Err(InstrRes::Finished);
}
if !gargs.is_empty() {
errs.push(ResErr::GenericCount {
origin: inst.origin,
ident.status = IdentStatus::Failed(ResErr::GenericCount {
origin: ident.origin,
expected: 0,
found: gargs.len(),
});
}
id
}
MemberTy::Struct(id) => {
if !matches!(kind, KindTy::Struct | KindTy::Type | KindTy::Any) {
errs.push(ResErr::KindMismatch {
origin: inst.origin,
expected: kind,
found: KindTy::Struct,
id: id.0,
});
return Err(InstrRes::Finished);
}
if fields.len() > 0 {
errs.push(ResErr::UnexpectedField {
origin: inst.origin,
});
return Err(InstrRes::Finished);
}
return Ok(inst_struct_ty(
id, s.structs, gargs, types, s.generics, errs,
));
ident.status = IdentStatus::PartialVar {
id,
fields: fields.clone(),
};
return self.resolve(s);
}
};
if fields.len() > 0 {
inst.status = VarStatus::Partial{v: vid, fields}
}
}
VarStatus::Partial { v, fields } => (*v, fields),
VarStatus::Cooked => return Err(InstrRes::Finished),
};
// I feel like this clone is not necessary but idk how
inst.status = VarStatus::Partial {
v: id,
fields: fields.clone(),
};
// let VarStatus::Partial { v, fields } = inst.status
todo!()
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> ResID<K> for &VarInstID {
fn try_id(
impl<K: ResKind> Resolvable<K> for IdentID {
fn try_res(
&self,
s: &mut Sources,
types: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
kind: KindTy,
) -> Result<ID<K>, InstrRes> {
(*self).try_id(s, types, errs, kind)
) -> Result<K::Res, InstrRes> {
let origin = s.idents[self].origin;
let res = self.resolve(s)?;
match K::from_res(res.clone(), types, s, origin, errs) {
Some(res) => Ok(res),
None => {
errs.push(ResErr::KindMismatch {
origin,
expected: K::ty(),
found: res,
});
Err(InstrRes::Finished)
}
}
}
}
// "effective" (externally visible) kinds
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KindTy {
Type,
Var,
Struct,
Fn,
}
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)]
pub enum Res {
Var(VarID),
Fn(FnInst),
Struct(StructInst),
Type(TypeID),
}
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,
}
}
pub fn kind_str(&self) -> &'static str {
self.kind().str()
}
}
pub trait ResKind {
type Res;
fn ty() -> KindTy;
fn from_res(
res: Res,
types: &mut Vec<Type>,
s: &mut Sources,
origin: Origin,
errs: &mut Vec<ResErr>,
) -> Option<Self::Res>;
}
impl ResKind for UFunc {
type Res = FnInst;
fn ty() -> KindTy {
KindTy::Fn
}
fn from_res(
res: Res,
_: &mut Vec<Type>,
_: &mut Sources,
_: Origin,
_: &mut Vec<ResErr>,
) -> Option<Self::Res> {
match res {
Res::Fn(fi) => Some(fi),
_ => None,
}
}
}
impl ResKind for UVar {
type Res = VarID;
fn ty() -> KindTy {
KindTy::Var
}
fn from_res(
res: Res,
types: &mut Vec<Type>,
s: &mut Sources,
origin: Origin,
errs: &mut Vec<ResErr>,
) -> Option<Self::Res> {
Some(match res {
Res::Fn(fty) => inst_fn_var(&fty, s.fns, origin, s.vars, types, s.generics, errs),
Res::Var(id) => id,
Res::Struct(_) => return None,
Res::Type(_) => return None,
})
}
}
impl ResKind for UStruct {
type Res = StructInst;
fn ty() -> KindTy {
KindTy::Struct
}
fn from_res(
res: Res,
_: &mut Vec<Type>,
_: &mut Sources,
_: Origin,
_: &mut Vec<ResErr>,
) -> Option<Self::Res> {
match res {
Res::Struct(si) => Some(si),
_ => None,
}
}
}
impl ResKind for Type {
type Res = TypeID;
fn ty() -> KindTy {
KindTy::Type
}
fn from_res(
res: Res,
types: &mut Vec<Type>,
s: &mut Sources,
_: Origin,
errs: &mut Vec<ResErr>,
) -> Option<Self::Res> {
Some(match res {
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,
})
}
}
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)
}
}
@@ -637,8 +782,8 @@ trait HasOrigin {
fn origin(&self, data: &ResData) -> Origin;
}
impl HasOrigin for &VarInstID {
impl HasOrigin for &IdentID {
fn origin(&self, data: &ResData) -> Origin {
data.s.insts[*self].origin
data.s.idents[*self].origin
}
}

View File

@@ -1,8 +1,8 @@
use std::collections::HashMap;
use super::{
push_id, FnID, GenericID, Len, ModPath, Origin, ResErr, StructID, TypeCache, TypeID, UFunc,
UGeneric, UProgram, UStruct, UVar, VarID,
push_id, FnID, GenericID, Len, ModPath, Origin, ResErr, StructID, TypeID, UFunc, UGeneric,
UProgram, UStruct, UVar, VarID,
};
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
@@ -11,23 +11,23 @@ pub struct FieldRef {
pub name: String,
}
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct StructTy {
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct StructInst {
pub id: StructID,
pub args: Vec<TypeID>,
pub gargs: Vec<TypeID>,
}
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct FnTy {
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct FnInst {
pub id: FnID,
pub args: Vec<TypeID>,
pub gargs: Vec<TypeID>,
}
#[derive(Clone)]
pub enum Type {
Bits(u32),
Struct(StructTy),
FnRef(FnTy),
Struct(StructInst),
FnRef(FnInst),
// this can be added for constraints later (F: fn(...) -> ...)
// Fn { args: Vec<TypeID>, ret: TypeID },
Ref(TypeID),
@@ -79,17 +79,16 @@ impl Type {
}
pub fn inst_fn_var(
id: FnID,
fi: &FnInst,
fns: &[UFunc],
gargs: &[TypeID],
origin: Origin,
vars: &mut Vec<UVar>,
types: &mut Vec<Type>,
generics: &[UGeneric],
errs: &mut Vec<ResErr>,
) -> VarID {
let ty = inst_fn_ty(id, fns, gargs, types, generics, errs);
let name = fns[id].name.clone();
let ty = inst_fn_ty(fi, fns, types, generics, errs);
let name = fns[fi.id].name.clone();
push_id(
vars,
UVar {
@@ -97,39 +96,37 @@ pub fn inst_fn_var(
origin,
ty,
parent: None,
children: Vec::new(),
children: HashMap::new(),
},
)
}
pub fn inst_fn_ty(
id: FnID,
fi: &FnInst,
fns: &[UFunc],
gargs: &[TypeID],
types: &mut Vec<Type>,
generics: &[UGeneric],
errs: &mut Vec<ResErr>,
) -> TypeID {
let f = &fns[id];
let ty = Type::FnRef(FnTy {
id,
args: inst_generics(&f.gargs, gargs, types, generics, errs),
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(
id: StructID,
si: &StructInst,
structs: &[UStruct],
gargs: &[TypeID],
origin: Origin,
vars: &mut Vec<UVar>,
types: &mut Vec<Type>,
generics: &[UGeneric],
errs: &mut Vec<ResErr>,
) -> VarID {
let ty = inst_struct_ty(id, structs, gargs, types, generics, errs);
let name = structs[id].name.clone();
let ty = inst_struct_ty(si, structs, types, generics, errs);
let name = structs[si.id].name.clone();
push_id(
vars,
UVar {
@@ -137,23 +134,22 @@ pub fn inst_struct_var(
origin,
ty,
parent: None,
children: Vec::new(),
children: HashMap::new(),
},
)
}
pub fn inst_struct_ty(
id: StructID,
si: &StructInst,
structs: &[UStruct],
gargs: &[TypeID],
types: &mut Vec<Type>,
generics: &[UGeneric],
errs: &mut Vec<ResErr>,
) -> TypeID {
let s = &structs[id];
let ty = Type::Struct(StructTy {
id,
args: inst_generics(&s.gargs, gargs, types, generics, errs),
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)
}
@@ -204,18 +200,18 @@ pub fn inst_type_ins(
) -> TypeID {
let ty = match types[id].clone() {
Type::Bits(_) => return id,
Type::Struct(struct_ty) => Type::Struct(StructTy {
Type::Struct(struct_ty) => Type::Struct(StructInst {
id: struct_ty.id,
args: struct_ty
.args
gargs: struct_ty
.gargs
.iter()
.map(|id| inst_type(*id, types, gmap))
.collect(),
}),
Type::FnRef(fn_ty) => Type::FnRef(FnTy {
Type::FnRef(fn_ty) => Type::FnRef(FnInst {
id: fn_ty.id,
args: fn_ty
.args
gargs: fn_ty
.gargs
.iter()
.map(|id| inst_type(*id, types, gmap))
.collect(),

View File

@@ -3,7 +3,7 @@ use crate::{
compiler::arch::riscv::*,
ir::{
arch::riscv64::{RV64Instruction, RegRef},
VarInst,
UIdent,
},
};
@@ -166,7 +166,7 @@ impl RV64Instruction {
}
}
pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarInst> {
pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<UIdent> {
let PAsmArg::Ref(node) = node.inner.as_ref()? else {
ctx.err_at(
node.origin,

View File

@@ -1,15 +1,15 @@
use crate::{
compiler::arch::riscv::Reg,
ir::{
arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, Type, UInstruction, VarInst,
VarInstID,
arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, Type, UInstruction, UIdent,
IdentID,
},
parser::PAsmBlockArg,
};
use super::{FnLowerCtx, FnLowerable, PAsmBlock, PInstruction, PUAsmBlockArg};
type PLAsmBlockArg = PAsmBlockArg<Reg, VarInstID>;
type PLAsmBlockArg = PAsmBlockArg<Reg, IdentID>;
impl FnLowerable for PInstruction {
type Output = RV64Instruction;
@@ -20,7 +20,7 @@ impl FnLowerable for PInstruction {
}
impl FnLowerable for PAsmBlock {
type Output = VarInstID;
type Output = IdentID;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
let mut args = Vec::new();

View File

@@ -1,13 +1,13 @@
use crate::{
ir::{Type, UInstruction, UVar, VarInst, VarInstID},
ir::{Type, UInstruction, UVar, UIdent, IdentID},
parser::{PConstStatement, PStatementLike},
};
use super::{FnLowerCtx, FnLowerable, Import, PBlock, PStatement};
impl FnLowerable for PBlock {
type Output = VarInstID;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInstID> {
type Output = IdentID;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<IdentID> {
let mut last = None;
let mut statements = Vec::new();
let mut fn_nodes = Vec::new();
@@ -74,8 +74,8 @@ impl FnLowerable for PBlock {
}
impl FnLowerable for PStatement {
type Output = VarInst;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
type Output = UIdent;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<UIdent> {
match self {
PStatement::Let(def, e) => {
let def = def.lower(ctx.b, ctx.output)?;

View File

@@ -1,4 +1,4 @@
use crate::ir::{UProgram, UVar, VarID, VarInst};
use crate::ir::{UProgram, UVar, VarID, UIdent};
use super::{CompilerOutput, Node, PVarDef};
@@ -10,7 +10,7 @@ impl Node<PVarDef> {
Some(ty) => ty.lower(program, output),
None => program.infer(self.origin),
};
Some(VarInst {
Some(UIdent {
id: program.def_searchable(name, Some(UVar { ty }), self.origin),
origin: self.origin,
})

View File

@@ -1,12 +1,12 @@
use super::{func::FnLowerCtx, FnLowerable, PExpr, PostfixOp};
use crate::{
ir::{Type, UData, UInstruction, VarInst, VarInstID},
ir::{Type, UData, UInstruction, UIdent, IdentID},
parser::InfixOp,
};
impl FnLowerable for PExpr {
type Output = VarInstID;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInstID> {
type Output = IdentID;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<IdentID> {
let mut e = self;
let mut path = Vec::new();
while let PExpr::Member(node, ident) = e {

View File

@@ -7,7 +7,7 @@ use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Imports, Node, P
use crate::{
ir::{
FnID, GenericID, ModPath, Origin, Typable, Type, UFunc, UInstrInst, UInstruction,
UModuleBuilder, VarID, VarInst, VarInstID, VarStatus,
UModuleBuilder, VarID, UIdent, IdentID, IdentStatus,
},
parser,
util::NameStack,
@@ -68,7 +68,7 @@ impl PFunction {
let res = self.body.lower(&mut ctx);
let mut instructions = ctx.instructions;
if let Some(src) = res {
let origin = b.vars_insts[src].origin;
let origin = b.idents[src].origin;
instructions.push(UInstrInst {
origin,
i: UInstruction::Ret { src },
@@ -99,13 +99,13 @@ pub struct FnLowerCtx<'a, 'b> {
}
impl<'a, 'b> FnLowerCtx<'a, 'b> {
pub fn var(&mut self, node: &Node<parser::PIdent>) -> VarInstID {
let inst = VarInst {
pub fn var(&mut self, node: &Node<parser::PIdent>) -> IdentID {
let inst = UIdent {
status: if let Some(n) = node.as_ref() {
if let Some(&var) = self.var_stack.search(&n.0) {
VarStatus::Var(var)
IdentStatus::Var(var)
} else {
VarStatus::Unres {
IdentStatus::Unres {
path: ModPath {
id: self.b.module,
path: Vec::new(),
@@ -116,7 +116,7 @@ impl<'a, 'b> FnLowerCtx<'a, 'b> {
}
}
} else {
VarStatus::Cooked
IdentStatus::Cooked
},
origin: node.origin,
};
@@ -128,7 +128,7 @@ impl<'a, 'b> FnLowerCtx<'a, 'b> {
pub fn err_at(&mut self, span: FileSpan, msg: String) {
self.output.err(CompilerMsg::new(msg, span))
}
pub fn temp<T: Typable>(&mut self, ty: T) -> VarInstID {
pub fn temp<T: Typable>(&mut self, ty: T) -> IdentID {
self.b.temp_var(self.origin, ty)
}
pub fn push(&mut self, i: UInstruction) {

View File

@@ -1,11 +1,11 @@
use std::collections::HashMap;
use crate::{ir::VarInstID, parser::PMap};
use crate::{ir::IdentID, parser::PMap};
use super::{FnLowerCtx, FnLowerable};
impl FnLowerable for PMap {
type Output = HashMap<String, VarInstID>;
type Output = HashMap<String, IdentID>;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
Some(
self.0