add simple const generic eval
This commit is contained in:
parent
0daa49874e
commit
853021e4f8
|
@ -121,6 +121,14 @@ impl Context {
|
|||
})
|
||||
}
|
||||
|
||||
fn eval_expression(&self, expr: &typed_ir::Expr) -> Result<types::ElabData, CompileError> {
|
||||
match &expr.kind {
|
||||
typed_ir::ExprKind::Literal(lit) => Ok(lit.clone()),
|
||||
typed_ir::ExprKind::Path(_) => todo!("evaluate path"),
|
||||
typed_ir::ExprKind::Call { called, args } => todo!("evaluate call"),
|
||||
}
|
||||
}
|
||||
|
||||
fn type_expression(
|
||||
&self,
|
||||
expr: &parser::expression::Expression,
|
||||
|
@ -136,8 +144,32 @@ impl Context {
|
|||
typ: signal.typ,
|
||||
}
|
||||
}
|
||||
Expression::Literal(_) => todo!("type literal"),
|
||||
Expression::UnOp(op) => self.type_expression(&op.a)?,
|
||||
Expression::Literal(lit) => {
|
||||
// TODO: make this a proper enum instead of having to match on everything
|
||||
let data = match lit.kind() {
|
||||
parser::tokens::TokenKind::Number => {
|
||||
let num = lit.span().fragment().parse().unwrap();
|
||||
self.types.make_elabnum_u32(num)
|
||||
}
|
||||
_ => unreachable!("non-literal token in literal?"),
|
||||
};
|
||||
typed_ir::Expr {
|
||||
id,
|
||||
kind: typed_ir::ExprKind::Literal(data),
|
||||
typ: self.types.primitives.infer,
|
||||
}
|
||||
}
|
||||
Expression::UnOp(op) => {
|
||||
let a = self.type_expression(&op.a)?;
|
||||
typed_ir::Expr {
|
||||
id,
|
||||
kind: typed_ir::ExprKind::Call {
|
||||
called: typed_ir::DefId(99),
|
||||
args: vec![a],
|
||||
},
|
||||
typ: self.types.primitives.infer,
|
||||
}
|
||||
}
|
||||
Expression::BinOp(op) => {
|
||||
let (a, b) = (self.type_expression(&op.a)?, self.type_expression(&op.b)?);
|
||||
typed_ir::Expr {
|
||||
|
@ -176,8 +208,18 @@ impl Context {
|
|||
|
||||
for port in comb.ports.iter() {
|
||||
let sig_id = self.ids.next();
|
||||
|
||||
let sig_typename = &port.net.typ;
|
||||
let sig_type = self.try_get_type(sig_typename.name.fragment())?;
|
||||
let mut sig_type = self.try_get_type(sig_typename.name.fragment())?;
|
||||
if let Some(arg) = &sig_typename.generics {
|
||||
let elab_expr = self.type_expression(arg)?;
|
||||
let elab_val = self.eval_expression(&elab_expr)?;
|
||||
sig_type = self
|
||||
.types
|
||||
.parameterize(sig_type, &[types::GenericArg::Elab(elab_val)])
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let sig = typed_ir::Signal {
|
||||
id: typed_ir::DefId(sig_id as u32),
|
||||
typ: sig_type,
|
||||
|
@ -220,7 +262,7 @@ impl Context {
|
|||
for sig in &block.signals {
|
||||
let mut typ_pretty = String::new();
|
||||
self.types.pretty_type(&mut typ_pretty, sig.typ)?;
|
||||
writeln!(w, "_{}: {}", sig.id.0, typ_pretty)?
|
||||
writeln!(w, "sig_{}: {}", sig.id.0, typ_pretty)?
|
||||
}
|
||||
self.pretty_typed_expr(w, &block.expr)?;
|
||||
Ok(())
|
||||
|
@ -232,8 +274,8 @@ impl Context {
|
|||
expr: &typed_ir::Expr,
|
||||
) -> std::fmt::Result {
|
||||
let expr_pretty = match &expr.kind {
|
||||
typed_ir::ExprKind::Literal => todo!(),
|
||||
typed_ir::ExprKind::Path(path) => format!("_{}", path.0),
|
||||
typed_ir::ExprKind::Literal(_) => todo!(),
|
||||
typed_ir::ExprKind::Path(path) => format!("sig_{}", path.0),
|
||||
typed_ir::ExprKind::Call { called, args } => {
|
||||
let args = args
|
||||
.iter()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::types::Type;
|
||||
use super::types::{ElabData, Type};
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// ID of a definition (e.g. variable, block, function)
|
||||
|
@ -29,7 +29,7 @@ pub struct Expr {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ExprKind {
|
||||
Literal,
|
||||
Literal(ElabData),
|
||||
Path(DefId),
|
||||
Call { called: DefId, args: Vec<Expr> },
|
||||
}
|
||||
|
|
|
@ -32,13 +32,13 @@ enum TypeKind {
|
|||
Infer,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ElabData {
|
||||
typ: Type,
|
||||
value: ElabValue,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
enum ElabValue {
|
||||
/// the value is not given and has to be inferred
|
||||
Infer,
|
||||
|
@ -46,7 +46,7 @@ enum ElabValue {
|
|||
Concrete(ElabValueData),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
enum ElabValueData {
|
||||
U32(u32),
|
||||
Bytes(Vec<u8>),
|
||||
|
@ -59,6 +59,12 @@ enum ElabKind {
|
|||
Num,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GenericArg {
|
||||
Elab(ElabData),
|
||||
Type(Type),
|
||||
}
|
||||
|
||||
pub struct PrimitiveTypes {
|
||||
pub elabnum: Type,
|
||||
pub logic: Type,
|
||||
|
@ -106,10 +112,52 @@ impl TypingContext {
|
|||
&self.types[typ.0]
|
||||
}
|
||||
|
||||
pub fn make_elabnum_u32(&self, num: u32) -> ElabData {
|
||||
ElabData {
|
||||
typ: self.primitives.elabnum,
|
||||
value: ElabValue::Concrete(ElabValueData::U32(num)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parameterize(&mut self, typ: Type, params: &[GenericArg]) -> Option<Type> {
|
||||
// TODO: return proper error type here
|
||||
match &self.get(typ).kind {
|
||||
// Elab types have no params yet
|
||||
TypeKind::ElabType(_) => None,
|
||||
TypeKind::Logic(_) => {
|
||||
if params.len() != 1 {
|
||||
// invalid number of typeargs
|
||||
return None;
|
||||
};
|
||||
let param = ¶ms[0];
|
||||
if let GenericArg::Elab(data) = param {
|
||||
if data.typ == self.primitives.elabnum {
|
||||
Some(self.add(TypeStruct {
|
||||
kind: TypeKind::Logic(data.clone()),
|
||||
}))
|
||||
} else {
|
||||
// arg must be elabnum
|
||||
None
|
||||
}
|
||||
} else {
|
||||
// arg must be an elab value
|
||||
None
|
||||
}
|
||||
}
|
||||
TypeKind::UInt(_) => todo!(),
|
||||
TypeKind::Callable => todo!("callable generic params"),
|
||||
// need to know what the type is to parameterize it
|
||||
TypeKind::Infer => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pretty_value(&self, w: &mut dyn std::fmt::Write, data: &ElabData) -> std::fmt::Result {
|
||||
match data.value {
|
||||
match &data.value {
|
||||
ElabValue::Infer => write!(w, "?: ")?,
|
||||
ElabValue::Concrete(_) => todo!("concrete type value"),
|
||||
ElabValue::Concrete(val) => match val {
|
||||
ElabValueData::U32(val) => write!(w, "{:?}: ", val)?,
|
||||
ElabValueData::Bytes(val) => write!(w, "{:?}: ", val)?,
|
||||
},
|
||||
}
|
||||
self.pretty_type(w, data.typ)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue