add pretty printing for typed IR

main
NotAFile 2022-02-15 23:56:52 +01:00
parent faa7a06aa2
commit 0daa49874e
6 changed files with 118 additions and 30 deletions

View File

@ -4,4 +4,5 @@ comb reduce_or (
a: Logic
)
-> Logic<1> {
}

View File

@ -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::<Result<Vec<_>, 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(())
}
}

View File

@ -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 {

View File

@ -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"),
}

View File

@ -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 {

View File

@ -15,9 +15,9 @@ pub fn typename(input: TokenSpan) -> IResult<TokenSpan, TypeName> {
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<TokenSpan, TypeName> {
#[derive(Debug)]
pub struct TypeName<'a> {
pub name: Span<'a>,
pub generics: (),
pub generics: Option<Expression<'a>>,
}
#[derive(Debug)]