graphix_compiler/typ/
tval.rs

1use super::{PrintFlag, Type};
2use crate::{env::Env, typ::format_with_flags, Rt, UserEvent};
3use fxhash::FxHashSet;
4use netidx::publisher::Value;
5use netidx_value::NakedValue;
6use std::{cell::RefCell, collections::HashSet, fmt};
7
8/// A value with it's type, used for formatting
9pub struct TVal<'a, R: Rt, E: UserEvent> {
10    pub env: &'a Env<R, E>,
11    pub typ: &'a Type,
12    pub v: &'a Value,
13}
14
15impl<'a, R: Rt, E: UserEvent> TVal<'a, R, E> {
16    fn fmt_int(
17        &self,
18        f: &mut fmt::Formatter<'_>,
19        hist: &mut FxHashSet<(usize, usize)>,
20    ) -> fmt::Result {
21        if !self.typ.is_a(&self.env, &self.v) {
22            return format_with_flags(PrintFlag::DerefTVars, || {
23                write!(
24                    f,
25                    "error, type {} does not match value {}",
26                    self.typ,
27                    NakedValue(self.v)
28                )
29            });
30        }
31        match (&self.typ, &self.v) {
32            (Type::Primitive(_) | Type::Bottom | Type::Any | Type::Fn(_), v) => {
33                write!(f, "{}", NakedValue(v))
34            }
35            (Type::Ref { .. }, v) => match self.typ.lookup_ref(&self.env) {
36                Err(e) => write!(f, "error, {e:?}"),
37                Ok(typ) => {
38                    let typ_addr = (typ as *const Type).addr();
39                    let v_addr = (self.v as *const Value).addr();
40                    if !hist.contains(&(typ_addr, v_addr)) {
41                        hist.insert((typ_addr, v_addr));
42                        Self { typ, env: self.env, v }.fmt_int(f, hist)?
43                    }
44                    Ok(())
45                }
46            },
47            (Type::Array(et), Value::Array(a)) => {
48                write!(f, "[")?;
49                for (i, v) in a.iter().enumerate() {
50                    Self { typ: et, env: self.env, v }.fmt_int(f, hist)?;
51                    if i < a.len() - 1 {
52                        write!(f, ", ")?
53                    }
54                }
55                write!(f, "]")
56            }
57            (Type::Array(_), v) => write!(f, "{}", NakedValue(v)),
58            (Type::ByRef(_), v) => write!(f, "{}", NakedValue(v)),
59            (Type::Struct(flds), Value::Array(a)) => {
60                write!(f, "{{")?;
61                for (i, ((n, et), v)) in flds.iter().zip(a.iter()).enumerate() {
62                    write!(f, "{n}: ")?;
63                    match v {
64                        Value::Array(a) if a.len() == 2 => {
65                            Self { typ: et, env: self.env, v: &a[1] }.fmt_int(f, hist)?
66                        }
67                        _ => write!(f, "err")?,
68                    }
69                    if i < flds.len() - 1 {
70                        write!(f, ", ")?
71                    }
72                }
73                write!(f, "}}")
74            }
75            (Type::Struct(_), v) => write!(f, "{}", NakedValue(v)),
76            (Type::Tuple(flds), Value::Array(a)) => {
77                write!(f, "(")?;
78                for (i, (t, v)) in flds.iter().zip(a.iter()).enumerate() {
79                    Self { typ: t, env: self.env, v }.fmt_int(f, hist)?;
80                    if i < flds.len() - 1 {
81                        write!(f, ", ")?
82                    }
83                }
84                write!(f, ")")
85            }
86            (Type::Tuple(_), v) => write!(f, "{}", NakedValue(v)),
87            (Type::TVar(tv), v) => match &*tv.read().typ.read() {
88                None => write!(f, "{}", NakedValue(v)),
89                Some(typ) => TVal { env: self.env, typ, v }.fmt_int(f, hist),
90            },
91            (Type::Variant(n, flds), Value::Array(a)) if a.len() >= 2 => {
92                write!(f, "`{n}(")?;
93                for (i, (t, v)) in flds.iter().zip(a[1..].iter()).enumerate() {
94                    Self { typ: t, env: self.env, v }.fmt_int(f, hist)?;
95                    if i < flds.len() - 1 {
96                        write!(f, ", ")?
97                    }
98                }
99                write!(f, ")")
100            }
101            (Type::Variant(_, _), Value::String(s)) => write!(f, "`{s}"),
102            (Type::Variant(_, _), v) => write!(f, "{}", NakedValue(v)),
103            (Type::Set(ts), v) => match ts.iter().find(|t| t.is_a(&self.env, v)) {
104                None => write!(f, "{}", NakedValue(v)),
105                Some(t) => Self { typ: t, env: self.env, v }.fmt_int(f, hist),
106            },
107        }
108    }
109}
110
111impl<'a, R: Rt, E: UserEvent> fmt::Display for TVal<'a, R, E> {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        thread_local! {
114            static HIST: RefCell<FxHashSet<(usize, usize)>> = RefCell::new(HashSet::default());
115        }
116        HIST.with_borrow_mut(|hist| {
117            hist.clear();
118            self.fmt_int(f, hist)
119        })
120    }
121}