add pretty printing for typed IR
This commit is contained in:
parent
faa7a06aa2
commit
0daa49874e
|
@ -4,4 +4,5 @@ comb reduce_or (
|
|||
a: Logic
|
||||
)
|
||||
-> Logic<1> {
|
||||
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
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"),
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)]
|
||||
|
|
Loading…
Reference in New Issue