INITIAL GENERICS IMPL
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -6,6 +6,7 @@ mod expr;
|
||||
mod func;
|
||||
mod module;
|
||||
mod struc;
|
||||
mod ty;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {})))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user