From 853021e4f8e392d6f8bd3e4ef76846fcdf180447 Mon Sep 17 00:00:00 2001 From: NotAFile Date: Wed, 16 Feb 2022 16:37:12 +0100 Subject: [PATCH] add simple const generic eval --- src/frontend.rs | 54 ++++++++++++++++++++++++++++++++----- src/frontend/typed_ir.rs | 4 +-- src/frontend/types.rs | 58 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 103 insertions(+), 13 deletions(-) diff --git a/src/frontend.rs b/src/frontend.rs index 871fc59..c216648 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -121,6 +121,14 @@ impl Context { }) } + fn eval_expression(&self, expr: &typed_ir::Expr) -> Result { + 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() diff --git a/src/frontend/typed_ir.rs b/src/frontend/typed_ir.rs index e72de51..8bcc635 100644 --- a/src/frontend/typed_ir.rs +++ b/src/frontend/typed_ir.rs @@ -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 }, } diff --git a/src/frontend/types.rs b/src/frontend/types.rs index eb0fcde..4c05b83 100644 --- a/src/frontend/types.rs +++ b/src/frontend/types.rs @@ -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), @@ -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 { + // 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) }