1use std::collections::{BTreeMap, BTreeSet};
2use std::fmt;
3
4#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
12pub enum Value {
13 Bool(bool),
14 Int(i64),
15 Str(String),
16 Seq(Vec<Value>),
17 Set(BTreeSet<Value>),
18 Record(BTreeMap<String, Value>),
19 Func(BTreeMap<Value, Value>),
20 Infinite(Infinite),
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
25pub enum Infinite {
26 Nat,
27 Int,
28 Strings,
29 Sequences(Box<Value>),
31}
32
33pub(crate) fn count(n: usize) -> i64 {
36 i64::try_from(n).expect("no collection exceeds isize::MAX elements")
37}
38
39impl Value {
40 pub fn set(items: impl IntoIterator<Item = Value>) -> Value {
41 Value::Set(items.into_iter().collect())
42 }
43
44 pub fn string(s: impl Into<String>) -> Value {
45 Value::Str(s.into())
46 }
47
48 pub fn interval(lo: i64, hi: i64) -> Value {
49 Value::Set((lo..=hi).map(Value::Int).collect())
50 }
51
52 pub fn record(fields: impl IntoIterator<Item = (String, Value)>) -> Value {
53 Value::Record(fields.into_iter().collect())
54 }
55
56 pub fn function(entries: BTreeMap<Value, Value>) -> Value {
58 if entries.is_empty() {
59 return Value::Seq(Vec::new());
60 }
61 if entries
62 .keys()
63 .enumerate()
64 .all(|(i, k)| matches!(k, Value::Int(n) if *n == count(i) + 1))
65 {
66 return Value::Seq(entries.into_values().collect());
67 }
68 if entries.keys().all(|k| matches!(k, Value::Str(_))) {
69 return Value::Record(
70 entries
71 .into_iter()
72 .map(|(k, v)| match k {
73 Value::Str(s) => (s, v),
74 _ => unreachable!("keys checked to be strings"),
75 })
76 .collect(),
77 );
78 }
79 Value::Func(entries)
80 }
81
82 pub fn entries(&self) -> Option<BTreeMap<Value, Value>> {
84 match self {
85 Value::Seq(items) => Some(
86 items
87 .iter()
88 .enumerate()
89 .map(|(i, v)| (Value::Int(count(i) + 1), v.clone()))
90 .collect(),
91 ),
92 Value::Record(fields) => Some(
93 fields
94 .iter()
95 .map(|(k, v)| (Value::Str(k.clone()), v.clone()))
96 .collect(),
97 ),
98 Value::Func(map) => Some(map.clone()),
99 _ => None,
100 }
101 }
102
103 pub fn domain(&self) -> Option<BTreeSet<Value>> {
104 match self {
105 Value::Seq(items) => Some((1..=count(items.len())).map(Value::Int).collect()),
106 Value::Record(fields) => Some(fields.keys().cloned().map(Value::Str).collect()),
107 Value::Func(map) => Some(map.keys().cloned().collect()),
108 _ => None,
109 }
110 }
111
112 pub fn apply(&self, key: &Value) -> Option<Value> {
113 match (self, key) {
114 (Value::Seq(items), Value::Int(i)) => usize::try_from(*i)
115 .ok()?
116 .checked_sub(1)
117 .and_then(|i| items.get(i).cloned()),
118 (Value::Record(fields), Value::Str(k)) => fields.get(k).cloned(),
119 (Value::Func(map), k) => map.get(k).cloned(),
120 _ => None,
121 }
122 }
123
124 pub fn type_name(&self) -> &'static str {
125 match self {
126 Value::Bool(_) => "a boolean",
127 Value::Int(_) => "an integer",
128 Value::Str(_) => "a string",
129 Value::Seq(_) => "a sequence",
130 Value::Set(_) | Value::Infinite(_) => "a set",
131 Value::Record(_) => "a record",
132 Value::Func(_) => "a function",
133 }
134 }
135
136 pub fn is_set(&self) -> bool {
137 matches!(self, Value::Set(_) | Value::Infinite(_))
138 }
139}
140
141impl fmt::Display for Value {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 match self {
144 Value::Bool(b) => f.write_str(if *b { "TRUE" } else { "FALSE" }),
145 Value::Int(n) => write!(f, "{n}"),
146 Value::Str(s) => write!(f, "{s:?}"),
147 Value::Seq(items) => write!(f, "<<{}>>", join(items.iter())),
148 Value::Set(items) => write!(f, "{{{}}}", join(items.iter())),
149 Value::Record(fields) => {
150 let body: Vec<String> =
151 fields.iter().map(|(k, v)| format!("{k} |-> {v}")).collect();
152 write!(f, "[{}]", body.join(", "))
153 }
154 Value::Func(map) => {
155 let body: Vec<String> = map.iter().map(|(k, v)| format!("{k} :> {v}")).collect();
156 write!(f, "({})", body.join(" @@ "))
157 }
158 Value::Infinite(Infinite::Nat) => f.write_str("Nat"),
159 Value::Infinite(Infinite::Int) => f.write_str("Int"),
160 Value::Infinite(Infinite::Strings) => f.write_str("STRING"),
161 Value::Infinite(Infinite::Sequences(s)) => write!(f, "Seq({s})"),
162 }
163 }
164}
165
166fn join<'a>(items: impl Iterator<Item = &'a Value>) -> String {
167 items
168 .map(ToString::to_string)
169 .collect::<Vec<_>>()
170 .join(", ")
171}