INITIAL GENERICS IMPL

This commit is contained in:
2025-04-15 03:21:57 -04:00
parent 993458f4be
commit 329b1d86ac
18 changed files with 607 additions and 381 deletions
+2 -53
View File
@@ -1,6 +1,6 @@
use crate::ir::{Type, UProgram, UStruct, UVar, VarInst};
use crate::ir::{Type, UProgram, UVar, VarInst};
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType, PVarDef};
use super::{CompilerOutput, Node, PVarDef};
impl Node<PVarDef> {
pub fn lower(&self, program: &mut UProgram, output: &mut CompilerOutput) -> Option<VarInst> {
@@ -27,54 +27,3 @@ impl Node<PVarDef> {
})
}
}
impl Node<PType> {
pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> Type {
self.as_ref()
.map(|t| t.lower(namespace, output, self.span))
.unwrap_or(Type::Error)
}
}
impl PType {
pub fn lower(
&self,
namespace: &mut UProgram,
output: &mut CompilerOutput,
span: FileSpan,
) -> Type {
let Some(name) = self.name.as_ref() else {
return Type::Error;
};
match namespace
.get_idents(name)
.and_then(|ids| ids.get::<UStruct>())
{
Some(id) => {
let args = self
.args
.iter()
.map(|n| n.lower(namespace, output))
.collect();
Type::Struct { id, args }
}
None => {
if let Ok(num) = name.parse::<u32>() {
Type::Bits(num)
} else {
match name.as_str() {
"slice" => {
let inner = self.args[0].lower(namespace, output);
Type::Slice(Box::new(inner))
}
"_" => Type::Infer,
_ => {
output.err(CompilerMsg::from_span(span, "Type not found".to_string()));
Type::Error
}
}
}
}
}
}
}
+5 -24
View File
@@ -58,35 +58,16 @@ impl FnLowerable for PExpr {
PExpr::BinaryOp(op, e1, e2) => {
let res1 = e1.lower(ctx)?;
if *op == PInfixOp::Access {
let sty = &ctx.program.expect(res1.id).ty;
let Type::Struct {
id: struct_id,
args,
} = sty
else {
ctx.err(format!(
"Type {:?} has no fields",
ctx.program.type_name(sty)
));
return None;
};
let struc = ctx.program.expect(*struct_id);
let Some(box PExpr::Ident(ident)) = &e2.inner else {
ctx.err("Field accesses must be identifiers".to_string());
ctx.err("Field accessors must be identifiers".to_string());
return None;
};
let fname = &ident.as_ref()?.0;
let Some(&field) = struc.field_map.get(fname) else {
ctx.err(format!("Field '{fname}' not in struct"));
return None;
};
let fdef = struc.field(field);
let fname = ident.as_ref()?.0.clone();
ctx.temp_subvar(
fdef.ty.clone(),
Type::Placeholder,
FieldRef {
var: res1.id,
struc: *struct_id,
field,
field: fname,
},
)
} else {
@@ -147,7 +128,7 @@ impl FnLowerable for PExpr {
.program
.get_fn_var(fe.id)
.map(|f| f.ret.clone())
.unwrap_or(Type::Error);
.unwrap_or(Type::Placeholder);
let temp = ctx.temp(ty);
ctx.push(UInstruction::Call {
dest: temp,
+8 -5
View File
@@ -1,6 +1,9 @@
use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction};
use crate::{
ir::{FieldRef, FnID, Idents, Type, UFunc, UInstrInst, UInstruction, UProgram, UVar, VarInst},
ir::{
FieldRef, FnID, Idents, InstrIter, Type, UFunc, UInstrInst, UInstruction, UProgram, UVar,
VarInst,
},
parser,
};
@@ -24,8 +27,7 @@ impl PFunction {
name.to_string(),
Some(UVar {
parent: None,
// this gets replaced with the correct type later
ty: Type::Error,
ty: Type::Placeholder,
origin: self.header.span,
}),
);
@@ -62,11 +64,12 @@ impl PFunction {
});
}
let origin = self.header.span;
let instructions = ctx.instructions;
let f = UFunc {
origin,
args,
ret,
instructions: ctx.instructions,
instructions,
};
p.expect_mut(p.inv_fn_map[id.0]).ty = f.ty(p);
p.write(id, f)
@@ -115,7 +118,7 @@ impl FnLowerCtx<'_> {
self.program.temp_subvar(self.span, ty, parent)
}
pub fn push(&mut self, i: UInstruction) {
self.instructions.push(UInstrInst { i, span: self.span });
self.push_at(i, self.span);
}
pub fn push_at(&mut self, i: UInstruction, span: FileSpan) {
self.instructions.push(UInstrInst { i, span });
+1
View File
@@ -6,6 +6,7 @@ mod expr;
mod func;
mod module;
mod struc;
mod ty;
use super::*;
+12 -41
View File
@@ -1,8 +1,6 @@
use std::collections::HashMap;
use crate::{
common::{CompilerOutput, FileSpan},
ir::{FieldID, StructField, StructID, Type, UInstruction, UProgram, UStruct, VarInst},
ir::{StructField, StructID, UInstruction, UProgram, UStruct, VarInst},
parser::{Node, PConstruct, PConstructFields, PStruct, PStructFields},
};
@@ -12,18 +10,6 @@ impl FnLowerable for PConstruct {
type Output = VarInst;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
let ty = self.name.lower(ctx.program, ctx.output);
let field_map = match ty {
Type::Struct { id, .. } => ctx.program.expect(id),
_ => {
ctx.err(format!(
"Type {} cannot be constructed",
ctx.program.type_name(&ty)
));
return None;
}
}
.field_map
.clone();
let fields = match &self.fields {
PConstructFields::Named(nodes) => nodes
.iter()
@@ -31,15 +17,7 @@ impl FnLowerable for PConstruct {
let def = n.as_ref()?;
let name = def.name.as_ref()?.to_string();
let expr = def.val.as_ref()?.lower(ctx)?;
let Some(&field) = field_map.get(&name) else {
ctx.err(format!(
"Struct {} has no field {}",
ctx.program.type_name(&ty),
name
));
return None;
};
Some((field, expr))
Some((name, expr))
})
.collect(),
PConstructFields::Tuple(nodes) => nodes
@@ -48,15 +26,7 @@ impl FnLowerable for PConstruct {
.flat_map(|(i, n)| {
let expr = n.as_ref()?.lower(ctx)?;
let name = format!("{i}");
let Some(&field) = field_map.get(&name) else {
ctx.err(format!(
"Struct {} has no field {}",
ctx.program.type_name(&ty),
name
));
return None;
};
Some((field, expr))
Some((name, expr))
})
.collect(),
PConstructFields::None => Default::default(),
@@ -75,7 +45,12 @@ impl PStruct {
output: &mut CompilerOutput,
span: FileSpan,
) -> Option<()> {
let mut field_map = HashMap::new();
p.push();
let generics = self
.generics
.iter()
.flat_map(|a| a.as_ref()?.lower(p))
.collect();
let fields = match &self.fields {
PStructFields::Named(nodes) => nodes
.iter()
@@ -98,21 +73,17 @@ impl PStruct {
PStructFields::None => vec![],
}
.into_iter()
.enumerate()
.map(|(i, (name, ty))| {
let id = FieldID::new(i);
field_map.insert(name.clone(), id);
StructField { name, ty }
})
.map(|(name, ty)| (name, StructField { ty }))
.collect();
p.write(
id,
UStruct {
origin: span,
field_map,
generics,
fields,
},
);
p.pop();
Some(())
}
}
+53
View File
@@ -0,0 +1,53 @@
use crate::{
ir::{GenericID, Type, UGeneric, UProgram, UStruct},
parser::PGenericDef,
};
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType};
impl Node<PType> {
pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> Type {
self.as_ref()
.map(|t| t.lower(namespace, output, self.span))
.unwrap_or(Type::Error)
}
}
impl PType {
pub fn lower(&self, p: &mut UProgram, output: &mut CompilerOutput, span: FileSpan) -> Type {
let Some(name) = self.name.as_ref() else {
return Type::Error;
};
let ids = p.get_idents(name);
// TODO: should generics always take precedence?
if let Some(id) = ids.and_then(|ids| ids.get::<UGeneric>()) {
Type::Generic { id }
} else if let Some(id) = ids.and_then(|ids| ids.get::<UStruct>()) {
let args = self.args.iter().map(|n| n.lower(p, output)).collect();
Type::Struct { id, args }
} else if let Ok(num) = name.parse::<u32>() {
Type::Bits(num)
} else {
match name.as_str() {
"slice" => {
let inner = self.args[0].lower(p, output);
Type::Slice(Box::new(inner))
}
"_" => Type::Infer,
_ => {
output.err(CompilerMsg::from_span(span, "Type not found".to_string()));
Type::Error
}
}
}
}
}
impl PGenericDef {
pub fn lower(&self, p: &mut UProgram) -> Option<GenericID> {
let Some(name) = self.name.as_ref() else {
return None;
};
Some(p.def_searchable(name.to_string(), Some(UGeneric {})))
}
}