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