add pretty printing for typed IR

This commit is contained in:
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 a: Logic
) )
-> Logic<1> { -> Logic<1> {
} }

View File

@ -1,5 +1,6 @@
use std::cell::Cell; use std::cell::Cell;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt::Write;
use super::parser; use super::parser;
use crate::rtlil; use crate::rtlil;
@ -93,7 +94,11 @@ impl Context {
callables: BTreeMap::new(), callables: BTreeMap::new(),
signals: BTreeMap::new(), signals: BTreeMap::new(),
types: TypingContext::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(), ids: Counter::new(),
} }
} }
@ -141,7 +146,7 @@ impl Context {
called: typed_ir::DefId(99), called: typed_ir::DefId(99),
args: vec![a, b], args: vec![a, b],
}, },
typ: self.types.primitives.elabnum, typ: self.types.primitives.infer,
} }
} }
Expression::Call(call) => { Expression::Call(call) => {
@ -156,7 +161,7 @@ impl Context {
called: typed_ir::DefId(99), called: typed_ir::DefId(99),
args: args_resolved, 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_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)?; 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 { Ok(typed_ir::Block {
signals, signals,
expr: root_expr, expr: root_expr,
@ -215,4 +211,43 @@ impl Context {
"no blocks in module".to_string(), "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 super::types::Type;
use std::fmt::Debug;
/// ID of a definition (e.g. variable, block, function) /// ID of a definition (e.g. variable, block, function)
#[derive(Debug, Clone, Copy)] #[derive(Clone, Copy)]
pub struct DefId(pub u32); pub struct DefId(pub u32);
#[derive(Debug, Clone, Copy)] #[derive(Clone, Copy)]
pub struct ExprId(pub u32); 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 /// an abstract element that performs some kind of computation on inputs
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Expr { pub struct Expr {

View File

@ -4,9 +4,16 @@ use std::fmt::Debug;
/// easier /// easier
pub type Type = InternedType; pub type Type = InternedType;
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
pub struct InternedType(usize); 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 { pub struct TypeStruct {
kind: TypeKind, kind: TypeKind,
} }
@ -21,10 +28,12 @@ enum TypeKind {
UInt(ElabData), UInt(ElabData),
/// Callable /// Callable
Callable, Callable,
/// A type that was not given and needs to be inferred
Infer,
} }
#[derive(Debug)] #[derive(Debug)]
struct ElabData { pub struct ElabData {
typ: Type, typ: Type,
value: ElabValue, value: ElabValue,
} }
@ -53,6 +62,7 @@ enum ElabKind {
pub struct PrimitiveTypes { pub struct PrimitiveTypes {
pub elabnum: Type, pub elabnum: Type,
pub logic: Type, pub logic: Type,
pub infer: Type,
} }
pub struct TypingContext { pub struct TypingContext {
@ -65,14 +75,23 @@ impl TypingContext {
let primitives = PrimitiveTypes { let primitives = PrimitiveTypes {
elabnum: InternedType(0), elabnum: InternedType(0),
logic: InternedType(1), logic: InternedType(1),
infer: InternedType(2),
}; };
Self { Self {
types: vec![TypeStruct { types: vec![
TypeStruct {
kind: TypeKind::ElabType(ElabKind::Num),
},
TypeStruct {
kind: TypeKind::Logic(ElabData { kind: TypeKind::Logic(ElabData {
typ: primitives.elabnum, typ: primitives.elabnum,
value: ElabValue::Infer, value: ElabValue::Infer,
}), }),
}], },
TypeStruct {
kind: TypeKind::Infer,
},
],
primitives, primitives,
} }
} }
@ -87,10 +106,23 @@ impl TypingContext {
&self.types[typ.0] &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 { pub fn pretty_type(&self, w: &mut dyn std::fmt::Write, typ: Type) -> std::fmt::Result {
match &self.get(typ).kind { match &self.get(typ).kind {
TypeKind::ElabType(val) => write!(w, "{{{:?}}}", val), TypeKind::ElabType(val) => write!(w, "{:?}", val),
TypeKind::Logic(_) => todo!("print logic"), 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::UInt(_) => todo!("print uint"),
TypeKind::Callable => todo!("print callable"), TypeKind::Callable => todo!("print callable"),
} }

View File

@ -61,7 +61,14 @@ fn main() {
let mut frontendcontext = crate::frontend::Context::new(); let mut frontendcontext = crate::frontend::Context::new();
let typed = frontendcontext.type_module(res.1); let typed = frontendcontext.type_module(res.1);
if opt.debug { 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 { match lowered {

View File

@ -15,9 +15,9 @@ pub fn typename(input: TokenSpan) -> IResult<TokenSpan, TypeName> {
token(tk::Ident), token(tk::Ident),
opt(delimited(token(tk::LAngle), expression, token(tk::RAngle))), opt(delimited(token(tk::LAngle), expression, token(tk::RAngle))),
)), )),
|(ident, _)| TypeName { |(ident, params)| TypeName {
name: ident.span(), name: ident.span(),
generics: (), generics: params,
}, },
)(input) )(input)
} }
@ -25,7 +25,7 @@ pub fn typename(input: TokenSpan) -> IResult<TokenSpan, TypeName> {
#[derive(Debug)] #[derive(Debug)]
pub struct TypeName<'a> { pub struct TypeName<'a> {
pub name: Span<'a>, pub name: Span<'a>,
pub generics: (), pub generics: Option<Expression<'a>>,
} }
#[derive(Debug)] #[derive(Debug)]