1use std::fmt;
4use synoema_parser::{Pat, Expr, Equation};
5
6#[derive(Debug, Clone)]
8pub enum Value {
9 Int(i64),
10 Float(f64),
11 Bool(bool),
12 Str(String),
13 Char(char),
14 List(Vec<Value>),
16 Con(String, Vec<Value>),
18 Closure {
20 params: Vec<Pat>,
21 body: Expr,
22 env: Env,
23 },
24 Func {
26 name: String,
27 equations: Vec<Equation>,
28 env: Env,
29 },
30 Builtin(String, usize), PartialBuiltin(String, usize, Vec<Value>), Record(Vec<(String, Value)>),
36 Unit,
38}
39
40impl PartialEq for Value {
41 fn eq(&self, other: &Self) -> bool {
42 match (self, other) {
43 (Value::Int(a), Value::Int(b)) => a == b,
44 (Value::Float(a), Value::Float(b)) => a == b,
45 (Value::Bool(a), Value::Bool(b)) => a == b,
46 (Value::Str(a), Value::Str(b)) => a == b,
47 (Value::Char(a), Value::Char(b)) => a == b,
48 (Value::List(a), Value::List(b)) => a == b,
49 (Value::Con(na, fa), Value::Con(nb, fb)) => na == nb && fa == fb,
50 (Value::Record(a), Value::Record(b)) => a == b,
51 (Value::Unit, Value::Unit) => true,
52 _ => false,
53 }
54 }
55}
56
57impl PartialOrd for Value {
58 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
59 match (self, other) {
60 (Value::Int(a), Value::Int(b)) => a.partial_cmp(b),
61 (Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
62 (Value::Str(a), Value::Str(b)) => a.partial_cmp(b),
63 (Value::Char(a), Value::Char(b)) => a.partial_cmp(b),
64 (Value::Bool(a), Value::Bool(b)) => a.partial_cmp(b),
65 _ => None,
66 }
67 }
68}
69
70impl fmt::Display for Value {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 match self {
73 Value::Int(n) => write!(f, "{}", n),
74 Value::Float(n) => {
75 if *n == (*n as i64) as f64 {
76 write!(f, "{:.1}", n)
77 } else {
78 write!(f, "{}", n)
79 }
80 }
81 Value::Bool(b) => write!(f, "{}", b),
82 Value::Str(s) => write!(f, "{}", s),
83 Value::Char(c) => write!(f, "{}", c),
84 Value::List(elems) => {
85 write!(f, "[")?;
86 for (i, e) in elems.iter().enumerate() {
87 if i > 0 { write!(f, " ")?; }
88 write!(f, "{}", e)?;
89 }
90 write!(f, "]")
91 }
92 Value::Con(name, fields) => {
93 write!(f, "{}", name)?;
94 for fld in fields {
95 write!(f, " ")?;
96 match fld {
97 Value::Con(_, fs) if !fs.is_empty() => write!(f, "({})", fld)?,
98 _ => write!(f, "{}", fld)?,
99 }
100 }
101 Ok(())
102 }
103 Value::Record(fields) => {
104 write!(f, "{{")?;
105 for (i, (name, val)) in fields.iter().enumerate() {
106 if i > 0 { write!(f, ", ")?; }
107 write!(f, "{} = {}", name, val)?;
108 }
109 write!(f, "}}")
110 }
111 Value::Closure { .. } => write!(f, "<closure>"),
112 Value::Func { name, .. } => write!(f, "<fn {}>", name),
113 Value::Builtin(name, _) => write!(f, "<builtin {}>", name),
114 Value::PartialBuiltin(name, _, _) => write!(f, "<partial {}>", name),
115 Value::Unit => write!(f, "()"),
116 }
117 }
118}
119
120#[derive(Debug, Clone)]
122pub struct Env {
123 frames: Vec<std::collections::HashMap<String, Value>>,
124}
125
126impl Env {
127 pub fn new() -> Self {
128 Env { frames: vec![std::collections::HashMap::new()] }
129 }
130
131 pub fn lookup(&self, name: &str) -> Option<&Value> {
132 for frame in self.frames.iter().rev() {
133 if let Some(v) = frame.get(name) {
134 return Some(v);
135 }
136 }
137 None
138 }
139
140 pub fn insert(&mut self, name: String, val: Value) {
141 if let Some(frame) = self.frames.last_mut() {
142 frame.insert(name, val);
143 }
144 }
145
146 pub fn push_scope(&mut self) {
147 self.frames.push(std::collections::HashMap::new());
148 }
149
150 pub fn pop_scope(&mut self) {
151 if self.frames.len() > 1 {
152 self.frames.pop();
153 }
154 }
155
156 pub fn child(&self) -> Self {
158 let mut e = self.clone();
159 e.push_scope();
160 e
161 }
162
163 pub fn iter_all(&self) -> Vec<(String, Value)> {
165 let mut seen = std::collections::HashSet::new();
166 let mut result = Vec::new();
167 for frame in self.frames.iter().rev() {
168 for (k, v) in frame {
169 if seen.insert(k.clone()) {
170 result.push((k.clone(), v.clone()));
171 }
172 }
173 }
174 result
175 }
176}