1use std::collections::BTreeMap;
9use std::fmt;
10use std::path::PathBuf;
11use std::sync::Arc;
12
13use tatara_lisp::Sexp;
14use tatara_nix::derivation::Derivation;
15use tatara_nix::store::StorePath;
16
17use crate::env::Env;
18
19#[derive(Clone)]
23pub enum Value {
24 Nil,
25 Bool(bool),
26 Int(i64),
27 Float(f64),
28 Str(String),
29 Symbol(String),
30 Keyword(String),
31 Path(PathBuf),
32 List(Arc<Vec<Value>>),
33 Attrs(Arc<BTreeMap<String, Value>>),
34 Lambda(Arc<Lambda>),
35 Builtin(Arc<Builtin>),
36 Thunk(Arc<Thunk>),
37 Derivation(Arc<Derivation>),
38 StorePath(StorePath),
39 Quoted(Arc<Sexp>),
41}
42
43impl fmt::Debug for Value {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 match self {
46 Self::Nil => write!(f, "nil"),
47 Self::Bool(b) => write!(f, "{b}"),
48 Self::Int(n) => write!(f, "{n}"),
49 Self::Float(n) => write!(f, "{n}"),
50 Self::Str(s) => write!(f, "{s:?}"),
51 Self::Symbol(s) => write!(f, "sym:{s}"),
52 Self::Keyword(s) => write!(f, ":{s}"),
53 Self::Path(p) => write!(f, "path:{}", p.display()),
54 Self::List(xs) => {
55 write!(f, "(")?;
56 for (i, x) in xs.iter().enumerate() {
57 if i > 0 {
58 write!(f, " ")?;
59 }
60 write!(f, "{x:?}")?;
61 }
62 write!(f, ")")
63 }
64 Self::Attrs(m) => {
65 write!(f, "{{")?;
66 for (i, (k, v)) in m.iter().enumerate() {
67 if i > 0 {
68 write!(f, " ")?;
69 }
70 write!(f, "{k} = {v:?}")?;
71 }
72 write!(f, "}}")
73 }
74 Self::Lambda(l) => write!(f, "<lambda/{}>", l.params.len()),
75 Self::Builtin(b) => write!(f, "<builtin {}>", b.name),
76 Self::Thunk(_) => write!(f, "<thunk>"),
77 Self::Derivation(d) => write!(f, "<deriv {}>", d.name),
78 Self::StorePath(p) => write!(f, "<store-path {p}>"),
79 Self::Quoted(s) => write!(f, "'{s}"),
80 }
81 }
82}
83
84impl fmt::Display for Value {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 match self {
87 Self::Nil => write!(f, ""),
88 Self::Str(s) => write!(f, "{s}"),
89 Self::Int(n) => write!(f, "{n}"),
90 Self::Float(n) => write!(f, "{n}"),
91 Self::Bool(b) => write!(f, "{b}"),
92 Self::Symbol(s) => write!(f, "{s}"),
93 Self::Keyword(s) => write!(f, ":{s}"),
94 Self::Path(p) => write!(f, "{}", p.display()),
95 Self::List(xs) => {
96 write!(f, "(")?;
97 for (i, x) in xs.iter().enumerate() {
98 if i > 0 {
99 write!(f, " ")?;
100 }
101 write!(f, "{x}")?;
102 }
103 write!(f, ")")
104 }
105 other => write!(f, "{other:?}"),
106 }
107 }
108}
109
110impl Value {
111 pub fn type_name(&self) -> &'static str {
112 match self {
113 Self::Nil => "nil",
114 Self::Bool(_) => "bool",
115 Self::Int(_) => "int",
116 Self::Float(_) => "float",
117 Self::Str(_) => "string",
118 Self::Symbol(_) => "symbol",
119 Self::Keyword(_) => "keyword",
120 Self::Path(_) => "path",
121 Self::List(_) => "list",
122 Self::Attrs(_) => "attrs",
123 Self::Lambda(_) => "lambda",
124 Self::Builtin(_) => "builtin",
125 Self::Thunk(_) => "thunk",
126 Self::Derivation(_) => "derivation",
127 Self::StorePath(_) => "store-path",
128 Self::Quoted(_) => "quoted",
129 }
130 }
131
132 pub fn is_truthy(&self) -> bool {
133 !matches!(self, Self::Nil | Self::Bool(false))
134 }
135
136 pub fn as_int(&self) -> Option<i64> {
137 match self {
138 Self::Int(n) => Some(*n),
139 _ => None,
140 }
141 }
142
143 pub fn as_str(&self) -> Option<&str> {
144 match self {
145 Self::Str(s) | Self::Symbol(s) | Self::Keyword(s) => Some(s),
146 _ => None,
147 }
148 }
149
150 pub fn as_list(&self) -> Option<&[Value]> {
151 match self {
152 Self::List(xs) => Some(xs),
153 _ => None,
154 }
155 }
156
157 pub fn as_attrs(&self) -> Option<&BTreeMap<String, Value>> {
158 match self {
159 Self::Attrs(m) => Some(m),
160 _ => None,
161 }
162 }
163
164 pub fn as_derivation(&self) -> Option<&Derivation> {
165 match self {
166 Self::Derivation(d) => Some(d),
167 _ => None,
168 }
169 }
170
171 pub fn as_path(&self) -> Option<&PathBuf> {
172 match self {
173 Self::Path(p) => Some(p),
174 _ => None,
175 }
176 }
177
178 pub fn coerce_to_string(&self) -> Option<String> {
182 match self {
183 Self::Str(s) => Some(s.clone()),
184 Self::Symbol(s) | Self::Keyword(s) => Some(s.clone()),
185 Self::Int(n) => Some(n.to_string()),
186 Self::Float(n) => Some(n.to_string()),
187 Self::Bool(b) => Some(b.to_string()),
188 Self::Path(p) => Some(p.to_string_lossy().into_owned()),
189 Self::StorePath(p) => Some(p.render()),
190 Self::Derivation(d) => Some(d.store_path().render()),
191 _ => None,
192 }
193 }
194}
195
196pub struct Lambda {
200 pub params: Vec<String>,
201 pub rest: Option<String>,
203 pub body: Vec<Sexp>,
204 pub env: Env,
205 pub name: Option<String>,
206}
207
208pub type BuiltinFn = dyn Fn(&[Value]) -> crate::error::Result<Value> + Send + Sync;
212
213pub struct Builtin {
214 pub name: String,
215 pub arity: Arity,
216 pub func: Arc<BuiltinFn>,
217}
218
219#[derive(Clone, Copy, Debug)]
220pub enum Arity {
221 Exact(usize),
222 AtLeast(usize),
223 Any,
224}
225
226impl Arity {
227 pub fn check(&self, got: usize) -> bool {
228 match *self {
229 Self::Exact(n) => got == n,
230 Self::AtLeast(n) => got >= n,
231 Self::Any => true,
232 }
233 }
234
235 pub fn describe(&self) -> String {
236 match *self {
237 Self::Exact(n) => format!("{n}"),
238 Self::AtLeast(n) => format!("at least {n}"),
239 Self::Any => "any".into(),
240 }
241 }
242}
243
244pub struct Thunk {
250 pub cell: std::sync::Mutex<ThunkState>,
251}
252
253pub enum ThunkState {
254 Unevaluated { body: Sexp, env: Env },
255 Evaluating, Forced(Value),
257}
258
259impl Thunk {
260 pub fn new(body: Sexp, env: Env) -> Arc<Self> {
261 Arc::new(Self {
262 cell: std::sync::Mutex::new(ThunkState::Unevaluated { body, env }),
263 })
264 }
265}