From 0daa49874e981ec59ef5f175ace21e6cd612c306 Mon Sep 17 00:00:00 2001 From: NotAFile Date: Tue, 15 Feb 2022 23:56:52 +0100 Subject: [PATCH] add pretty printing for typed IR --- lib/builtins/main.hyd | 1 + src/frontend.rs | 63 ++++++++++++++++++++++++++++++--------- src/frontend/typed_ir.rs | 17 +++++++++-- src/frontend/types.rs | 52 +++++++++++++++++++++++++------- src/main.rs | 9 +++++- src/parser/declaration.rs | 6 ++-- 6 files changed, 118 insertions(+), 30 deletions(-) diff --git a/lib/builtins/main.hyd b/lib/builtins/main.hyd index fc1b56b..2050b8a 100644 --- a/lib/builtins/main.hyd +++ b/lib/builtins/main.hyd @@ -4,4 +4,5 @@ comb reduce_or ( a: Logic ) -> Logic<1> { + } diff --git a/src/frontend.rs b/src/frontend.rs index 26b4002..871fc59 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -1,5 +1,6 @@ use std::cell::Cell; use std::collections::BTreeMap; +use std::fmt::Write; use super::parser; use crate::rtlil; @@ -93,7 +94,11 @@ impl Context { callables: BTreeMap::new(), signals: BTreeMap::new(), types: TypingContext::new(), - typenames: [("Logic".to_string(), tcx.primitives.logic)].into(), + typenames: [ + ("Logic".to_string(), tcx.primitives.logic), + ("Num".to_string(), tcx.primitives.elabnum), + ] + .into(), ids: Counter::new(), } } @@ -141,7 +146,7 @@ impl Context { called: typed_ir::DefId(99), args: vec![a, b], }, - typ: self.types.primitives.elabnum, + typ: self.types.primitives.infer, } } Expression::Call(call) => { @@ -156,7 +161,7 @@ impl Context { called: typed_ir::DefId(99), args: args_resolved, }, - typ: self.types.primitives.elabnum, + typ: self.types.primitives.infer, } } }; @@ -182,20 +187,11 @@ impl Context { } let ret_typename = &comb.ret.name; - let ret_type = self.try_get_type(ret_typename.fragment())?; + let _ret_type = self.try_get_type(ret_typename.fragment())?; + // TODO: use ret type let root_expr = self.type_expression(&comb.expr)?; - // TODO: more sophisticated type compat check - if root_expr.typ != ret_type { - let expected = ret_type; - let found = root_expr.typ; - return Err(CompileError::new(CompileErrorKind::TypeError { - expected, - found, - })); - } - Ok(typed_ir::Block { signals, expr: root_expr, @@ -215,4 +211,43 @@ impl Context { "no blocks in module".to_string(), ))) } + + pub fn pretty_typed_block( + &self, + w: &mut dyn std::fmt::Write, + block: &typed_ir::Block, + ) -> std::fmt::Result { + 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)? + } + self.pretty_typed_expr(w, &block.expr)?; + Ok(()) + } + + pub fn pretty_typed_expr( + &self, + w: &mut dyn std::fmt::Write, + 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::Call { called, args } => { + let args = args + .iter() + .map(|arg| { + self.pretty_typed_expr(w, arg)?; + Ok(format!("_{}", arg.id.0)) + }) + .collect::, std::fmt::Error>>()?; + format!("_{}({})", called.0, args.join(", ")) + } + }; + let mut type_pretty = String::new(); + self.types.pretty_type(&mut type_pretty, expr.typ)?; + writeln!(w, "let _{}: {} = {}", expr.id.0, type_pretty, expr_pretty)?; + Ok(()) + } } diff --git a/src/frontend/typed_ir.rs b/src/frontend/typed_ir.rs index 8284bbb..e72de51 100644 --- a/src/frontend/typed_ir.rs +++ b/src/frontend/typed_ir.rs @@ -1,11 +1,24 @@ use super::types::Type; +use std::fmt::Debug; /// ID of a definition (e.g. variable, block, function) -#[derive(Debug, Clone, Copy)] +#[derive(Clone, Copy)] pub struct DefId(pub u32); -#[derive(Debug, Clone, Copy)] +#[derive(Clone, Copy)] pub struct ExprId(pub u32); +// more compact Debug impl +impl Debug for DefId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "DefId({})", self.0) + } +} +impl Debug for ExprId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "ExprId({})", self.0) + } +} + /// an abstract element that performs some kind of computation on inputs #[derive(Debug, Clone)] pub struct Expr { diff --git a/src/frontend/types.rs b/src/frontend/types.rs index c6a5f72..eb0fcde 100644 --- a/src/frontend/types.rs +++ b/src/frontend/types.rs @@ -4,9 +4,16 @@ use std::fmt::Debug; /// easier pub type Type = InternedType; -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub struct InternedType(usize); +impl Debug for InternedType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Type({})", self.0) + } +} + +#[derive(Debug)] pub struct TypeStruct { kind: TypeKind, } @@ -21,10 +28,12 @@ enum TypeKind { UInt(ElabData), /// Callable Callable, + /// A type that was not given and needs to be inferred + Infer, } #[derive(Debug)] -struct ElabData { +pub struct ElabData { typ: Type, value: ElabValue, } @@ -53,6 +62,7 @@ enum ElabKind { pub struct PrimitiveTypes { pub elabnum: Type, pub logic: Type, + pub infer: Type, } pub struct TypingContext { @@ -65,14 +75,23 @@ impl TypingContext { let primitives = PrimitiveTypes { elabnum: InternedType(0), logic: InternedType(1), + infer: InternedType(2), }; Self { - types: vec![TypeStruct { - kind: TypeKind::Logic(ElabData { - typ: primitives.elabnum, - value: ElabValue::Infer, - }), - }], + types: vec![ + TypeStruct { + kind: TypeKind::ElabType(ElabKind::Num), + }, + TypeStruct { + kind: TypeKind::Logic(ElabData { + typ: primitives.elabnum, + value: ElabValue::Infer, + }), + }, + TypeStruct { + kind: TypeKind::Infer, + }, + ], primitives, } } @@ -87,10 +106,23 @@ impl TypingContext { &self.types[typ.0] } + pub fn pretty_value(&self, w: &mut dyn std::fmt::Write, data: &ElabData) -> std::fmt::Result { + match data.value { + ElabValue::Infer => write!(w, "?: ")?, + ElabValue::Concrete(_) => todo!("concrete type value"), + } + self.pretty_type(w, data.typ) + } + pub fn pretty_type(&self, w: &mut dyn std::fmt::Write, typ: Type) -> std::fmt::Result { match &self.get(typ).kind { - TypeKind::ElabType(val) => write!(w, "{{{:?}}}", val), - TypeKind::Logic(_) => todo!("print logic"), + TypeKind::ElabType(val) => write!(w, "{:?}", val), + TypeKind::Logic(val) => { + let mut width = String::new(); + self.pretty_value(&mut width, val)?; + write!(w, "Logic<{}>", width) + } + TypeKind::Infer => write!(w, "?"), TypeKind::UInt(_) => todo!("print uint"), TypeKind::Callable => todo!("print callable"), } diff --git a/src/main.rs b/src/main.rs index dc6ca3f..523f106 100644 --- a/src/main.rs +++ b/src/main.rs @@ -61,7 +61,14 @@ fn main() { let mut frontendcontext = crate::frontend::Context::new(); let typed = frontendcontext.type_module(res.1); if opt.debug { - println!("{:#?}", typed); + println!("{:#?}", &typed); + let mut pretty_block = String::new(); + if let Ok(block) = typed { + frontendcontext + .pretty_typed_block(&mut pretty_block, &block) + .unwrap(); + } + println!("{}", &pretty_block); } /* match lowered { diff --git a/src/parser/declaration.rs b/src/parser/declaration.rs index dca1de8..f3dbc2b 100644 --- a/src/parser/declaration.rs +++ b/src/parser/declaration.rs @@ -15,9 +15,9 @@ pub fn typename(input: TokenSpan) -> IResult { token(tk::Ident), opt(delimited(token(tk::LAngle), expression, token(tk::RAngle))), )), - |(ident, _)| TypeName { + |(ident, params)| TypeName { name: ident.span(), - generics: (), + generics: params, }, )(input) } @@ -25,7 +25,7 @@ pub fn typename(input: TokenSpan) -> IResult { #[derive(Debug)] pub struct TypeName<'a> { pub name: Span<'a>, - pub generics: (), + pub generics: Option>, } #[derive(Debug)]