1use super::cast::IsAFlags;
2use super::{PrintFlag, Type, TypeRef};
3use crate::{env::Env, typ::format_with_flags};
4use ahash::AHashSet;
5use netidx::publisher::Value;
6use netidx_value::NakedValue;
7use poolshark::local::LPooled;
8use std::fmt;
9
10pub struct TVal<'a> {
12 pub env: &'a Env,
13 pub typ: &'a Type,
14 pub v: &'a Value,
15}
16
17impl<'a> TVal<'a> {
18 fn fmt_int(
19 &self,
20 f: &mut fmt::Formatter<'_>,
21 hist: &mut AHashSet<(usize, usize)>,
22 ) -> fmt::Result {
23 if !self.typ.is_a_with(&self.env, IsAFlags::MatchAbstract.into(), &self.v) {
24 return format_with_flags(PrintFlag::DerefTVars, || {
25 eprintln!("error, type {} does not match value {:?}", self.typ, self.v);
26 write!(f, "{}", NakedValue(self.v))
27 });
28 }
29 match (&self.typ, &self.v) {
30 (
31 Type::Primitive(_)
32 | Type::Abstract { .. }
33 | Type::Bottom
34 | Type::Any
35 | Type::Error(_),
36 v,
37 ) => {
38 write!(f, "{}", NakedValue(v))
39 }
40 (Type::Fn(_), Value::Abstract(v)) => write!(f, "{v:?}"),
41 (Type::Fn(_), v) => write!(f, "{}", NakedValue(v)),
42 (Type::Ref(TypeRef { .. }), v) => {
43 let typ = match self.typ.lookup_ref(&self.env) {
44 Err(e) => return write!(f, "error, {e:?}"),
45 Ok(typ) => typ,
46 };
47 let typ_addr = (&typ as *const Type).addr();
48 let v_addr = (self.v as *const Value).addr();
49 if !hist.contains(&(typ_addr, v_addr)) {
50 hist.insert((typ_addr, v_addr));
51 TVal { typ: &typ, env: self.env, v }.fmt_int(f, hist)?
52 }
53 Ok(())
54 }
55 (Type::Array(et), Value::Array(a)) => {
56 write!(f, "[")?;
57 for (i, v) in a.iter().enumerate() {
58 Self { typ: et, env: self.env, v }.fmt_int(f, hist)?;
59 if i < a.len() - 1 {
60 write!(f, ", ")?
61 }
62 }
63 write!(f, "]")
64 }
65 (Type::Array(_), v) => write!(f, "{}", NakedValue(v)),
66 (Type::Map { key, value }, Value::Map(m)) => {
67 write!(f, "{{")?;
68 for (i, (k, v)) in m.into_iter().enumerate() {
69 Self { typ: key, env: self.env, v: k }.fmt_int(f, hist)?;
70 write!(f, " => ")?;
71 Self { typ: value, env: self.env, v: v }.fmt_int(f, hist)?;
72 if i < m.len() - 1 {
73 write!(f, ", ")?
74 }
75 }
76 write!(f, "}}")
77 }
78 (Type::Map { .. }, v) => write!(f, "{}", NakedValue(v)),
79 (Type::ByRef(_), v) => write!(f, "{}", NakedValue(v)),
80 (Type::Struct(flds), Value::Array(a)) => {
81 write!(f, "{{")?;
82 for (i, ((n, et), v)) in flds.iter().zip(a.iter()).enumerate() {
83 write!(f, "{n}: ")?;
84 match v {
85 Value::Array(a) if a.len() == 2 => {
86 Self { typ: et, env: self.env, v: &a[1] }.fmt_int(f, hist)?
87 }
88 _ => write!(f, "err")?,
89 }
90 if i < flds.len() - 1 {
91 write!(f, ", ")?
92 }
93 }
94 write!(f, "}}")
95 }
96 (Type::Struct(_), v) => write!(f, "{}", NakedValue(v)),
97 (Type::Tuple(flds), Value::Array(a)) => {
98 write!(f, "(")?;
99 for (i, (t, v)) in flds.iter().zip(a.iter()).enumerate() {
100 Self { typ: t, env: self.env, v }.fmt_int(f, hist)?;
101 if i < flds.len() - 1 {
102 write!(f, ", ")?
103 }
104 }
105 write!(f, ")")
106 }
107 (Type::Tuple(_), v) => write!(f, "{}", NakedValue(v)),
108 (Type::TVar(tv), v) => match &*tv.read().typ.read() {
109 None => write!(f, "{}", NakedValue(v)),
110 Some(typ) => TVal { env: self.env, typ, v }.fmt_int(f, hist),
111 },
112 (Type::Variant(n, flds), Value::Array(a)) if a.len() >= 2 => {
113 write!(f, "`{n}(")?;
114 for (i, (t, v)) in flds.iter().zip(a[1..].iter()).enumerate() {
115 Self { typ: t, env: self.env, v }.fmt_int(f, hist)?;
116 if i < flds.len() - 1 {
117 write!(f, ", ")?
118 }
119 }
120 write!(f, ")")
121 }
122 (Type::Variant(_, _), Value::String(s)) => write!(f, "`{s}"),
123 (Type::Variant(_, _), v) => write!(f, "{}", NakedValue(v)),
124 (Type::Set(ts), v) => match ts.iter().find(|t| t.is_a(&self.env, v)) {
125 None => write!(f, "{}", NakedValue(v)),
126 Some(t) => Self { typ: t, env: self.env, v }.fmt_int(f, hist),
127 },
128 }
129 }
130}
131
132impl<'a> fmt::Display for TVal<'a> {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 self.fmt_int(f, &mut LPooled::take())
135 }
136}