Skip to main content

graphix_compiler/typ/
tval.rs

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