kotoba_jsonnet/
value.rs

1//! Jsonnet value representation
2
3use crate::ast::Expr;
4use crate::error::{JsonnetError, Result};
5use std::collections::HashMap;
6use std::fmt;
7
8/// Jsonnet value types
9#[derive(Debug, Clone, PartialEq)]
10#[derive(Default)]
11pub enum JsonnetValue {
12    /// Null value
13    #[default]
14    Null,
15    /// Boolean value
16    Boolean(bool),
17    /// Number value (f64)
18    Number(f64),
19    /// String value
20    String(String),
21    /// Array value
22    Array(Vec<JsonnetValue>),
23    /// Object value
24    Object(HashMap<String, JsonnetValue>),
25    /// Function value
26    Function(JsonnetFunction),
27    /// Builtin function value
28    Builtin(JsonnetBuiltin),
29}
30
31impl JsonnetValue {
32    /// Create a null value
33    pub fn null() -> Self {
34        JsonnetValue::Null
35    }
36
37    /// Create a boolean value
38    pub fn boolean(b: bool) -> Self {
39        JsonnetValue::Boolean(b)
40    }
41
42    /// Create a number value
43    pub fn number(n: f64) -> Self {
44        JsonnetValue::Number(n)
45    }
46
47    /// Create a string value
48    pub fn string(s: impl Into<String>) -> Self {
49        JsonnetValue::String(s.into())
50    }
51
52    /// Create an array value
53    pub fn array(values: Vec<JsonnetValue>) -> Self {
54        JsonnetValue::Array(values)
55    }
56
57    /// Create an object value
58    pub fn object(fields: HashMap<String, JsonnetValue>) -> Self {
59        JsonnetValue::Object(fields)
60    }
61
62    /// Check if the value is truthy
63    pub fn is_truthy(&self) -> bool {
64        match self {
65            JsonnetValue::Null => false,
66            JsonnetValue::Boolean(b) => *b,
67            JsonnetValue::Number(n) => *n != 0.0,
68            JsonnetValue::String(s) => !s.is_empty(),
69            JsonnetValue::Array(a) => !a.is_empty(),
70            JsonnetValue::Object(o) => !o.is_empty(),
71            JsonnetValue::Function(_) => true,
72            JsonnetValue::Builtin(_) => true,
73        }
74    }
75
76    /// Get the type name of this value
77    pub fn type_name(&self) -> &'static str {
78        match self {
79            JsonnetValue::Null => "null",
80            JsonnetValue::Boolean(_) => "boolean",
81            JsonnetValue::Number(_) => "number",
82            JsonnetValue::String(_) => "string",
83            JsonnetValue::Array(_) => "array",
84            JsonnetValue::Object(_) => "object",
85            JsonnetValue::Function(_) => "function",
86            JsonnetValue::Builtin(_) => "function",
87        }
88    }
89
90    /// Convert to serde_json::Value for serialization
91    pub fn to_json_value(&self) -> serde_json::Value {
92        match self {
93            JsonnetValue::Null => serde_json::Value::Null,
94            JsonnetValue::Boolean(b) => serde_json::Value::Bool(*b),
95            JsonnetValue::Number(n) => serde_json::json!(*n),
96            JsonnetValue::String(s) => serde_json::Value::String(s.clone()),
97            JsonnetValue::Array(arr) => {
98                let json_arr: Vec<serde_json::Value> = arr.iter().map(|v| v.to_json_value()).collect();
99                serde_json::Value::Array(json_arr)
100            }
101            JsonnetValue::Object(obj) => {
102                let mut json_obj = serde_json::Map::new();
103                for (k, v) in obj {
104                    json_obj.insert(k.clone(), v.to_json_value());
105                }
106                serde_json::Value::Object(json_obj)
107            }
108            JsonnetValue::Function(_) => {
109                serde_json::Value::Null
110            }
111            JsonnetValue::Builtin(_) => {
112                // Functions cannot be serialized to JSON
113                serde_json::Value::String("<function>".to_string())
114            }
115        }
116    }
117
118    /// Try to convert to a string
119    pub fn as_string(&self) -> Result<&str> {
120        match self {
121            JsonnetValue::String(s) => Ok(s),
122            _ => Err(JsonnetError::type_error(format!("Expected string, got {}", self.type_name()))),
123        }
124    }
125
126    /// Try to convert to a number
127    pub fn as_number(&self) -> Result<f64> {
128        match self {
129            JsonnetValue::Number(n) => Ok(*n),
130            _ => Err(JsonnetError::type_error(format!("Expected number, got {}", self.type_name()))),
131        }
132    }
133
134    /// Try to convert to a boolean
135    pub fn as_boolean(&self) -> Result<bool> {
136        match self {
137            JsonnetValue::Boolean(b) => Ok(*b),
138            _ => Err(JsonnetError::type_error(format!("Expected boolean, got {}", self.type_name()))),
139        }
140    }
141
142    /// Try to convert to an array
143    pub fn as_array(&self) -> Result<&Vec<JsonnetValue>> {
144        match self {
145            JsonnetValue::Array(arr) => Ok(arr),
146            _ => Err(JsonnetError::type_error(format!("Expected array, got {}", self.type_name()))),
147        }
148    }
149
150    /// Try to convert to an object
151    pub fn as_object(&self) -> Result<&HashMap<String, JsonnetValue>> {
152        match self {
153            JsonnetValue::Object(obj) => Ok(obj),
154            _ => Err(JsonnetError::type_error(format!("Expected object, got {}", self.type_name()))),
155        }
156    }
157
158    /// Get a field from an object
159    pub fn get_field(&self, field: &str) -> Result<&JsonnetValue> {
160        match self {
161            JsonnetValue::Object(obj) => {
162                obj.get(field)
163                    .ok_or_else(|| JsonnetError::undefined_field(field.to_string()))
164            }
165            _ => Err(JsonnetError::type_error(format!("Expected object, got {}", self.type_name()))),
166        }
167    }
168
169    /// Get an element from an array by index
170    pub fn get_index(&self, index: i64) -> Result<&JsonnetValue> {
171        match self {
172            JsonnetValue::Array(arr) => {
173                let idx = if index < 0 {
174                    (arr.len() as i64 + index) as usize
175                } else {
176                    index as usize
177                };
178
179                arr.get(idx)
180                    .ok_or_else(|| JsonnetError::index_out_of_bounds(index))
181            }
182            _ => Err(JsonnetError::type_error(format!("Expected array, got {}", self.type_name()))),
183        }
184    }
185
186    /// Check if two values are equal
187    pub fn equals(&self, other: &JsonnetValue) -> bool {
188        match (self, other) {
189            (JsonnetValue::Null, JsonnetValue::Null) => true,
190            (JsonnetValue::Boolean(a), JsonnetValue::Boolean(b)) => a == b,
191            (JsonnetValue::Number(a), JsonnetValue::Number(b)) => (a - b).abs() < f64::EPSILON,
192            (JsonnetValue::String(a), JsonnetValue::String(b)) => a == b,
193            (JsonnetValue::Array(a), JsonnetValue::Array(b)) => {
194                a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.equals(y))
195            }
196            (JsonnetValue::Object(a), JsonnetValue::Object(b)) => {
197                a.len() == b.len() && a.iter().all(|(k, v)| {
198                    b.get(k).is_some_and(|bv| v.equals(bv))
199                })
200            }
201            _ => false,
202        }
203    }
204
205    // Binary operations
206    pub fn add(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
207        match (self, other) {
208            (JsonnetValue::Number(a), JsonnetValue::Number(b)) => Ok(JsonnetValue::number(a + b)),
209            (JsonnetValue::String(a), JsonnetValue::String(b)) => Ok(JsonnetValue::string(format!("{}{}", a, b))),
210            (JsonnetValue::Array(a), JsonnetValue::Array(b)) => {
211                let mut result = a.clone();
212                result.extend(b.clone());
213                Ok(JsonnetValue::Array(result))
214            }
215            _ => Err(JsonnetError::runtime_error("Cannot add these types")),
216        }
217    }
218
219    pub fn sub(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
220        match (self, other) {
221            (JsonnetValue::Number(a), JsonnetValue::Number(b)) => Ok(JsonnetValue::number(a - b)),
222            _ => Err(JsonnetError::runtime_error("Cannot subtract these types")),
223        }
224    }
225
226    pub fn mul(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
227        match (self, other) {
228            (JsonnetValue::Number(a), JsonnetValue::Number(b)) => Ok(JsonnetValue::number(a * b)),
229            _ => Err(JsonnetError::runtime_error("Cannot multiply these types")),
230        }
231    }
232
233    pub fn div(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
234        match (self, other) {
235            (JsonnetValue::Number(a), JsonnetValue::Number(b)) => {
236                if *b == 0.0 {
237                    Err(JsonnetError::runtime_error("Division by zero"))
238                } else {
239                    Ok(JsonnetValue::number(a / b))
240                }
241            }
242            _ => Err(JsonnetError::runtime_error("Cannot divide these types")),
243        }
244    }
245
246    pub fn modulo(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
247        match (self, other) {
248            (JsonnetValue::Number(a), JsonnetValue::Number(b)) => {
249                if *b == 0.0 {
250                    Err(JsonnetError::runtime_error("Modulo by zero"))
251                } else {
252                    Ok(JsonnetValue::number(a % b))
253                }
254            }
255            _ => Err(JsonnetError::runtime_error("Cannot modulo these types")),
256        }
257    }
258
259    // Comparison operations
260    pub fn lt(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
261        match (self, other) {
262            (JsonnetValue::Number(a), JsonnetValue::Number(b)) => Ok(JsonnetValue::boolean(a < b)),
263            (JsonnetValue::String(a), JsonnetValue::String(b)) => Ok(JsonnetValue::boolean(a < b)),
264            _ => Err(JsonnetError::runtime_error("Cannot compare these types")),
265        }
266    }
267
268    pub fn le(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
269        match (self, other) {
270            (JsonnetValue::Number(a), JsonnetValue::Number(b)) => Ok(JsonnetValue::boolean(a <= b)),
271            (JsonnetValue::String(a), JsonnetValue::String(b)) => Ok(JsonnetValue::boolean(a <= b)),
272            _ => Err(JsonnetError::runtime_error("Cannot compare these types")),
273        }
274    }
275
276    pub fn gt(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
277        match (self, other) {
278            (JsonnetValue::Number(a), JsonnetValue::Number(b)) => Ok(JsonnetValue::boolean(a > b)),
279            (JsonnetValue::String(a), JsonnetValue::String(b)) => Ok(JsonnetValue::boolean(a > b)),
280            _ => Err(JsonnetError::runtime_error("Cannot compare these types")),
281        }
282    }
283
284    pub fn ge(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
285        match (self, other) {
286            (JsonnetValue::Number(a), JsonnetValue::Number(b)) => Ok(JsonnetValue::boolean(a >= b)),
287            (JsonnetValue::String(a), JsonnetValue::String(b)) => Ok(JsonnetValue::boolean(a >= b)),
288            _ => Err(JsonnetError::runtime_error("Cannot compare these types")),
289        }
290    }
291
292    pub fn eq(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
293        Ok(JsonnetValue::boolean(self.equals(other)))
294    }
295
296    pub fn ne(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
297        Ok(JsonnetValue::boolean(!self.equals(other)))
298    }
299
300    // Logical operations
301    pub fn and(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
302        if self.is_truthy() {
303            Ok(other.clone())
304        } else {
305            Ok(self.clone())
306        }
307    }
308
309    pub fn or(&self, other: &JsonnetValue) -> Result<JsonnetValue> {
310        if self.is_truthy() {
311            Ok(self.clone())
312        } else {
313            Ok(other.clone())
314        }
315    }
316
317    // Unary operations
318    pub fn not(&self) -> Result<JsonnetValue> {
319        Ok(JsonnetValue::boolean(!self.is_truthy()))
320    }
321
322    pub fn neg(&self) -> Result<JsonnetValue> {
323        match self {
324            JsonnetValue::Number(n) => Ok(JsonnetValue::number(-n)),
325            _ => Err(JsonnetError::runtime_error("Cannot negate this type")),
326        }
327    }
328}
329
330impl fmt::Display for JsonnetValue {
331    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
332        match self {
333            JsonnetValue::Null => write!(f, "null"),
334            JsonnetValue::Boolean(b) => write!(f, "{}", b),
335            JsonnetValue::Number(n) => write!(f, "{}", n),
336            JsonnetValue::String(s) => write!(f, "{:?}", s),
337            JsonnetValue::Array(arr) => {
338                write!(f, "[")?;
339                for (i, item) in arr.iter().enumerate() {
340                    if i > 0 {
341                        write!(f, ", ")?;
342                    }
343                    write!(f, "{}", item)?;
344                }
345                write!(f, "]")
346            }
347            JsonnetValue::Object(obj) => {
348                write!(f, "{{")?;
349                for (i, (key, value)) in obj.iter().enumerate() {
350                    if i > 0 {
351                        write!(f, ", ")?;
352                    }
353                    write!(f, "{}: {}", key, value)?;
354                }
355                write!(f, "}}")
356            }
357            JsonnetValue::Function(_) => write!(f, "<function>"),
358            JsonnetValue::Builtin(_) => write!(f, "<builtin>"),
359        }
360    }
361}
362
363
364/// Jsonnet builtin function types
365#[derive(Debug, Clone, PartialEq)]
366pub enum JsonnetBuiltin {
367    Length,
368    StdLibFunction(String),
369    // Add more builtins as needed
370}
371
372impl JsonnetBuiltin {
373    pub fn call(&self, args: Vec<JsonnetValue>) -> Result<JsonnetValue> {
374        match self {
375            JsonnetBuiltin::Length => crate::stdlib::StdLib::length(args),
376            JsonnetBuiltin::StdLibFunction(func_name) => crate::stdlib::StdLib::call_function(func_name, args),
377        }
378    }
379}
380
381/// Jsonnet function representation
382#[derive(Debug, Clone)]
383pub struct JsonnetFunction {
384    pub parameters: Vec<String>,
385    pub body: Box<Expr>,
386    pub environment: HashMap<String, JsonnetValue>,
387}
388
389impl PartialEq for JsonnetFunction {
390    fn eq(&self, _other: &JsonnetFunction) -> bool {
391        // Functions are never equal for comparison purposes
392        false
393    }
394}
395
396impl JsonnetFunction {
397    /// Create a new function
398    pub fn new(parameters: Vec<String>, body: Box<Expr>, environment: HashMap<String, JsonnetValue>) -> Self {
399        JsonnetFunction {
400            parameters,
401            body,
402            environment,
403        }
404    }
405
406    /// Call the function with arguments
407    pub fn call(&self, args: Vec<JsonnetValue>) -> Result<JsonnetValue> {
408        if args.len() != self.parameters.len() {
409            return Err(JsonnetError::invalid_function_call(format!(
410                "Expected {} arguments, got {}",
411                self.parameters.len(),
412                args.len()
413            )));
414        }
415
416        // Create function environment
417        let mut env = self.environment.clone();
418        for (param, arg) in self.parameters.iter().zip(args) {
419            env.insert(param.clone(), arg);
420        }
421
422        // Evaluate function body
423        // This would need access to the evaluator
424        // For now, return a placeholder
425        Err(JsonnetError::runtime_error("Function evaluation not yet implemented"))
426    }
427}
428