use lutra_bin::ident;
use crate::pr;
use crate::printer::common::{PrintSourceExt, Separated};
use crate::printer::{PrintSource, Printer};
impl PrintSource for pr::Ty {
#[tracing::instrument(name = "t", skip_all)]
fn print<'c>(&self, p: &mut Printer<'c>) -> Option<()> {
tracing::trace!("ty {}", self.kind.as_ref());
match &self.kind {
pr::TyKind::Ident(ident) => p.push(ident.to_string())?,
pr::TyKind::Primitive(prim) => p.push(prim.to_string())?,
pr::TyKind::Tuple(fields) => {
return Separated {
nodes: fields,
sep_inline: ", ",
sep_line_end: ",",
}
.between("{", "}", self.span)
.single_line_end(",")
.print(p);
}
pr::TyKind::Array(item) => {
return item.as_ref().between("[", "]", self.span).print(p);
}
pr::TyKind::Option(inner) => {
inner.print(p)?;
p.push("?")?;
}
pr::TyKind::Enum(variants) => {
p.push("enum ")?;
Separated {
nodes: variants,
sep_inline: ", ",
sep_line_end: ",",
}
.between("{", "}", self.span)
.single_line_end(",")
.print(p)?;
}
pr::TyKind::Func(func) => return print_ty_func(func, None, p),
pr::TyKind::TupleComprehension(comp) => {
p.push("{for ")?;
p.push(ident::display(&comp.variable_name))?;
p.push(": ")?;
p.push(ident::display(&comp.variable_ty))?;
p.push(" in ")?;
comp.tuple.print(p)?;
p.push(" do ")?;
if let Some(name) = &comp.body_name {
p.push(ident::display(name))?;
p.push(": ")?;
}
comp.body_ty.print(p)?;
p.push("}")?;
}
};
Some(())
}
fn span(&self) -> Option<crate::Span> {
self.span
}
}
pub(super) fn print_ty_func<'c>(
func: &pr::TyFunc,
name: Option<&str>,
p: &mut Printer<'c>,
) -> Option<()> {
p.push("func ")?;
if let Some(name) = name {
p.push(ident::display(name))?;
}
Separated {
nodes: &func.params,
sep_inline: ", ",
sep_line_end: ",",
}
.between("(", ")", None)
.print(p)?;
if let Some(return_ty) = &func.body {
p.push(": ")?;
return_ty.print(p)?;
}
if !func.ty_params.is_empty() {
p.new_line();
p.push("where ")?;
p.indent();
Separated {
nodes: &func.ty_params,
sep_inline: ", ",
sep_line_end: ",",
}
.print(p)?;
p.dedent();
}
Some(())
}
impl PrintSource for pr::TyFuncParam {
fn print<'c>(&self, p: &mut Printer<'c>) -> Option<()> {
if self.constant {
p.push("const ")?;
}
if let Some(label) = &self.label {
p.push(ident::display(label))?;
p.push(": ")?;
}
if let Some(ty) = &self.ty {
ty.print(p)?;
}
Some(())
}
fn span(&self) -> Option<crate::Span> {
self.ty.as_ref().and_then(|t| t.span)
}
}
impl PrintSource for pr::TyTupleField {
fn print<'c>(&self, p: &mut Printer<'c>) -> Option<()> {
if let Some(name) = &self.name {
p.push(ident::display(name))?;
p.push(": ")?;
}
if self.unpack {
p.push("..")?;
}
self.ty.print(p)
}
fn span(&self) -> Option<crate::Span> {
self.ty.span
}
}
impl PrintSource for pr::TyEnumVariant {
fn print<'c>(&self, p: &mut Printer<'c>) -> Option<()> {
p.push(ident::display(&self.name))?;
let is_unit = self.ty.kind.as_tuple().is_some_and(|f| f.is_empty());
if is_unit {
return Some(());
}
p.push(": ")?;
self.ty.print(p)
}
fn span(&self) -> Option<crate::Span> {
self.ty.span
}
}
impl PrintSource for pr::TyParam {
fn print<'c>(&self, p: &mut Printer<'c>) -> Option<()> {
p.push(ident::display(&self.name))?;
match &self.domain {
pr::TyDomain::Open => {}
pr::TyDomain::OneOf(tys) => {
p.push(": ")?;
for (i, ty) in tys.iter().enumerate() {
if i > 0 {
p.push(" | ")?;
}
ty.print(p)?;
}
}
pr::TyDomain::TupleHasFields(fields) => {
p.push(": {")?;
for (i, field) in fields.iter().enumerate() {
match &field.location {
pr::Lookup::Name(name) => {
p.push(ident::display(name))?;
p.push(": ")?;
}
pr::Lookup::Position(p) => {
assert_eq!(i, *p as usize); }
}
field.ty.print(p)?;
p.push(", ")?;
}
p.push("..}")?;
}
pr::TyDomain::TupleLen { n } => {
p.push(": {.. ")?;
p.push(n.to_string())?;
p.push(" ..}")?;
}
pr::TyDomain::EnumVariants(variants) => {
p.push(": enum {")?;
for (i, variant) in variants.iter().enumerate() {
if i > 0 {
p.push(", ")?;
}
p.push(ident::display(&variant.name))?;
if variant.ty.kind.as_tuple().is_some_and(|f| f.is_empty()) {
p.push(": ")?;
variant.ty.print(p)?;
}
}
p.push(", ..}")?;
}
}
Some(())
}
fn span(&self) -> Option<crate::Span> {
self.span
}
}