blots_core/
values.rs

1use anyhow::{Result, anyhow};
2use indexmap::IndexMap;
3use serde::{Deserialize, Serialize};
4use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc};
5
6use crate::{
7    ast::SpannedExpr,
8    functions::BuiltInFunction,
9    heap::{
10        Heap, HeapPointer, HeapValue, IterablePointer, LambdaPointer, ListPointer, RecordPointer,
11        StringPointer,
12    },
13};
14
15/// Format a number for display output, matching the JS displayNumber function:
16/// - Very small values (< 0.0001) or extremely large values (>= 1e15) use scientific notation
17/// - Standard numbers preserve up to 15 significant digits with thousand separators
18pub fn format_display_number(value: f64) -> String {
19    // Handle special values
20    if value.is_nan() {
21        return "NaN".to_string();
22    }
23    if value.is_infinite() {
24        return if value.is_sign_positive() {
25            "Infinity".to_string()
26        } else {
27            "-Infinity".to_string()
28        };
29    }
30    // Handle zero specially to avoid "0e0" from scientific notation path
31    if value == 0.0 {
32        return value.to_string();
33    }
34
35    let abs_value = value.abs();
36
37    // Very small values (< 0.0001) or extremely large values (>= 1e15) -> Scientific notation
38    if !(0.0001..1e15).contains(&abs_value) {
39        return format_scientific(value);
40    }
41
42    // Standard numbers - preserve 15 digits of precision with thousand separators
43    format_standard(value)
44}
45
46/// Format a number in scientific notation with up to 15 significant digits
47fn format_scientific(value: f64) -> String {
48    // Format with up to 15 significant digits in scientific notation
49    let formatted = format!("{:.14e}", value);
50
51    // Parse and clean up the result
52    if let Some((mantissa_str, exp_str)) = formatted.split_once('e') {
53        let mantissa: f64 = mantissa_str.parse().unwrap_or(value);
54        let exp: i32 = exp_str.parse().unwrap_or(0);
55
56        // Format mantissa, removing trailing zeros
57        let mantissa_formatted = format_mantissa(mantissa);
58
59        format!("{}e{}", mantissa_formatted, exp)
60    } else {
61        formatted
62    }
63}
64
65/// Format the mantissa part, removing unnecessary trailing zeros
66fn format_mantissa(mantissa: f64) -> String {
67    // Format with enough precision
68    let s = format!("{:.14}", mantissa);
69
70    // Remove trailing zeros after decimal point
71    let s = s.trim_end_matches('0');
72    // Remove trailing decimal point if no decimals left
73    let s = s.trim_end_matches('.');
74
75    s.to_string()
76}
77
78/// Format a standard number with thousand separators and up to 15 significant digits
79fn format_standard(value: f64) -> String {
80    // For integers that fit in i64 range, handle them directly without float rounding
81    // This avoids floating point precision issues with large integers
82    if value.fract() == 0.0 && value.abs() < 9007199254740992.0 {
83        // Can be exactly represented as i64
84        let int_val = value as i64;
85        return format_integer_with_separators(int_val);
86    }
87
88    // Round to 15 significant figures for non-integers
89    let rounded = round_to_significant_figures(value, 15);
90
91    // Format the number, preserving significant digits
92    let formatted = format_float_significant(rounded, 15);
93
94    // Add thousand separators to the integer part
95    add_thousand_separators(&formatted)
96}
97
98/// Round a number to n significant figures
99fn round_to_significant_figures(value: f64, sig_figs: u32) -> f64 {
100    if value == 0.0 {
101        return 0.0;
102    }
103
104    let magnitude = value.abs().log10().floor() as i32;
105    let scale = 10_f64.powi(sig_figs as i32 - 1 - magnitude);
106    (value * scale).round() / scale
107}
108
109/// Format a float with up to n significant figures, removing trailing zeros
110fn format_float_significant(value: f64, max_sig_figs: usize) -> String {
111    // Determine how many decimal places we need
112    let abs_value = value.abs();
113    let magnitude = if abs_value >= 1.0 {
114        abs_value.log10().floor() as i32 + 1
115    } else {
116        // For numbers < 1, count leading zeros
117        -(abs_value.log10().floor() as i32)
118    };
119
120    // Calculate decimal places needed for significant figures
121    let decimal_places = if abs_value >= 1.0 {
122        (max_sig_figs as i32 - magnitude).max(0) as usize
123    } else {
124        // For numbers < 1, we need more decimal places
125        (max_sig_figs as i32 + magnitude - 1).max(0) as usize
126    };
127
128    let formatted = format!("{:.prec$}", value, prec = decimal_places);
129
130    // Remove trailing zeros after decimal point, but keep at least one decimal if there is a decimal point
131    if formatted.contains('.') {
132        let trimmed = formatted.trim_end_matches('0');
133        if trimmed.ends_with('.') {
134            trimmed.trim_end_matches('.').to_string()
135        } else {
136            trimmed.to_string()
137        }
138    } else {
139        formatted
140    }
141}
142
143/// Format an integer with thousand separators (commas)
144fn format_integer_with_separators(value: i64) -> String {
145    let is_negative = value < 0;
146    let abs_str = value.abs().to_string();
147
148    let with_commas: String = abs_str
149        .chars()
150        .rev()
151        .enumerate()
152        .flat_map(|(i, c)| {
153            if i > 0 && i % 3 == 0 {
154                vec![',', c]
155            } else {
156                vec![c]
157            }
158        })
159        .collect::<Vec<_>>()
160        .into_iter()
161        .rev()
162        .collect();
163
164    if is_negative {
165        format!("-{}", with_commas)
166    } else {
167        with_commas
168    }
169}
170
171/// Add thousand separators to the integer part of a formatted float string
172fn add_thousand_separators(s: &str) -> String {
173    let is_negative = s.starts_with('-');
174    let s = if is_negative { &s[1..] } else { s };
175
176    let (int_part, dec_part) = if let Some(dot_pos) = s.find('.') {
177        (&s[..dot_pos], Some(&s[dot_pos..]))
178    } else {
179        (s, None)
180    };
181
182    // Add commas to integer part
183    let int_with_commas: String = int_part
184        .chars()
185        .rev()
186        .enumerate()
187        .flat_map(|(i, c)| {
188            if i > 0 && i % 3 == 0 {
189                vec![',', c]
190            } else {
191                vec![c]
192            }
193        })
194        .collect::<Vec<_>>()
195        .into_iter()
196        .rev()
197        .collect();
198
199    let result = if let Some(dec) = dec_part {
200        format!("{}{}", int_with_commas, dec)
201    } else {
202        int_with_commas
203    };
204
205    if is_negative {
206        format!("-{}", result)
207    } else {
208        result
209    }
210}
211
212#[derive(Debug)]
213pub enum FunctionArity {
214    Exact(usize),
215    AtLeast(usize),
216    Between(usize, usize),
217}
218
219impl FunctionArity {
220    pub fn can_accept(&self, n: usize) -> bool {
221        match self {
222            FunctionArity::Exact(expected) => n == *expected,
223            FunctionArity::Between(min, max) => n >= *min && n <= *max,
224            FunctionArity::AtLeast(min) => n >= *min,
225        }
226    }
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)]
230pub enum LambdaArg {
231    Required(String),
232    Optional(String),
233    Rest(String),
234}
235
236impl LambdaArg {
237    pub fn get_name(&self) -> &str {
238        match self {
239            LambdaArg::Required(name) => name,
240            LambdaArg::Optional(name) => name,
241            LambdaArg::Rest(name) => name,
242        }
243    }
244
245    pub fn is_required(&self) -> bool {
246        matches!(self, LambdaArg::Required(_))
247    }
248
249    pub fn is_optional(&self) -> bool {
250        matches!(self, LambdaArg::Optional(_))
251    }
252
253    pub fn is_rest(&self) -> bool {
254        matches!(self, LambdaArg::Rest(_))
255    }
256
257    pub fn as_required(&self) -> Result<&str> {
258        match self {
259            LambdaArg::Required(name) => Ok(name),
260            _ => Err(anyhow!(
261                "expected a required argument, but got a {} one",
262                self.get_name()
263            )),
264        }
265    }
266
267    pub fn as_optional(&self) -> Result<&str> {
268        match self {
269            LambdaArg::Optional(name) => Ok(name),
270            _ => Err(anyhow!(
271                "expected an optional argument, but got a {} one",
272                self.get_name()
273            )),
274        }
275    }
276
277    pub fn as_rest(&self) -> Result<&str> {
278        match self {
279            LambdaArg::Rest(name) => Ok(name),
280            _ => Err(anyhow!(
281                "expected a rest argument, but got a {} one",
282                self.get_name()
283            )),
284        }
285    }
286}
287
288impl Display for LambdaArg {
289    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290        match self {
291            LambdaArg::Required(name) => write!(f, "{}", name),
292            LambdaArg::Optional(name) => write!(f, "{}?", name),
293            LambdaArg::Rest(name) => write!(f, "...{}", name),
294        }
295    }
296}
297
298#[derive(Debug, Clone, Default, PartialEq)]
299pub struct CapturedScope(Rc<HashMap<String, Value>>);
300
301impl CapturedScope {
302    pub fn new(map: HashMap<String, Value>) -> Self {
303        Self(Rc::new(map))
304    }
305
306    pub fn is_empty(&self) -> bool {
307        self.0.is_empty()
308    }
309
310    pub fn len(&self) -> usize {
311        self.0.len()
312    }
313
314    pub fn contains_key(&self, key: &str) -> bool {
315        self.0.contains_key(key)
316    }
317
318    pub fn get(&self, key: &str) -> Option<Value> {
319        self.0.get(key).copied()
320    }
321
322    pub fn iter(&self) -> impl Iterator<Item = (&String, &Value)> {
323        self.0.iter()
324    }
325
326    pub fn as_rc(&self) -> Rc<HashMap<String, Value>> {
327        Rc::clone(&self.0)
328    }
329}
330
331#[derive(Debug, Clone, PartialEq)]
332pub struct LambdaDef {
333    pub name: Option<String>,
334    pub args: Vec<LambdaArg>,
335    pub body: SpannedExpr,
336    pub scope: CapturedScope,
337    /// The source code string that the body's spans refer to (shared via Rc for efficiency)
338    pub source: Rc<str>,
339}
340
341impl LambdaDef {
342    pub fn set_name(&mut self, name: String, _value: Value) {
343        self.name = Some(name.clone());
344    }
345
346    pub fn get_arity(&self) -> FunctionArity {
347        let has_rest = self.args.iter().any(|arg| arg.is_rest());
348        let min = self.args.iter().filter(|arg| arg.is_required()).count();
349        let max = self.args.len();
350
351        if has_rest {
352            FunctionArity::AtLeast(min)
353        } else if min == max {
354            FunctionArity::Exact(min)
355        } else {
356            FunctionArity::Between(min, max)
357        }
358    }
359}
360
361impl PartialOrd for LambdaDef {
362    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
363        if self.args > other.args {
364            Some(std::cmp::Ordering::Greater)
365        } else if self.args < other.args {
366            Some(std::cmp::Ordering::Less)
367        } else {
368            Some(std::cmp::Ordering::Equal)
369        }
370    }
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
374pub struct SerializableLambdaDef {
375    pub name: Option<String>,
376    pub args: Vec<LambdaArg>,
377    pub body: String,
378    pub scope: Option<IndexMap<String, SerializableValue>>,
379}
380
381pub struct WithHeap<'h, T> {
382    pub value: &'h T,
383    pub heap: Rc<RefCell<Heap>>,
384}
385
386#[derive(Debug, Copy, Clone, PartialEq)]
387pub enum ReifiedIterableValue<'h> {
388    List(&'h Vec<Value>),
389    String(&'h String),
390    Record(&'h IndexMap<String, Value>),
391}
392
393#[derive(Debug, Clone, PartialEq)]
394pub enum ReifiedIterableValueType {
395    List,
396    String,
397    Record,
398}
399
400impl<'h> ReifiedIterableValue<'h> {
401    pub fn with_heap(&'h self, heap: Rc<RefCell<Heap>>) -> WithHeap<'h, ReifiedIterableValue<'h>> {
402        WithHeap { value: self, heap }
403    }
404
405    pub fn get_type(&self) -> ReifiedIterableValueType {
406        match self {
407            ReifiedIterableValue::List(_) => ReifiedIterableValueType::List,
408            ReifiedIterableValue::String(_) => ReifiedIterableValueType::String,
409            ReifiedIterableValue::Record(_) => ReifiedIterableValueType::Record,
410        }
411    }
412}
413
414impl<'h> IntoIterator for WithHeap<'h, ReifiedIterableValue<'h>> {
415    type Item = Value;
416    type IntoIter = std::vec::IntoIter<Self::Item>;
417
418    fn into_iter(self) -> Self::IntoIter {
419        match self.value {
420            // Yields an iterator over the values in the list.
421            ReifiedIterableValue::List(l) => (*l).clone().into_iter(),
422            // Yields an iterator over the characters in the string.
423            ReifiedIterableValue::String(s) => s
424                .chars()
425                .map(|c| self.heap.borrow_mut().insert_string(c.to_string()))
426                .collect::<Vec<Value>>()
427                .into_iter(),
428            // Yields an iterator over the [key, value] pairs of the record.
429            ReifiedIterableValue::Record(r) => r
430                .into_iter()
431                .map(|(k, v)| {
432                    let list = vec![self.heap.borrow_mut().insert_string(k.to_string()), *v];
433                    self.heap.borrow_mut().insert_list(list)
434                })
435                .collect::<Vec<Value>>()
436                .into_iter(),
437        }
438    }
439}
440
441impl<'h> IntoIterator for WithHeap<'h, ReifiedValue<'h>> {
442    type Item = Value;
443    type IntoIter = std::vec::IntoIter<Self::Item>;
444
445    fn into_iter(self) -> Self::IntoIter {
446        match self.value {
447            ReifiedValue::Spread(iterable, _) => iterable.with_heap(self.heap).into_iter(),
448            _ => vec![(*self.value).into()].into_iter(),
449        }
450    }
451}
452
453#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
454pub enum ValueType {
455    Number,
456    List,
457    Spread,
458    Bool,
459    Lambda,
460    BuiltIn,
461    String,
462    Record,
463    Null,
464}
465
466impl Display for ValueType {
467    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
468        match self {
469            ValueType::Number => write!(f, "number"),
470            ValueType::List => write!(f, "list"),
471            ValueType::Spread => write!(f, "spread"),
472            ValueType::Bool => write!(f, "boolean"),
473            ValueType::Lambda => write!(f, "function"),
474            ValueType::BuiltIn => write!(f, "built-in function"),
475            ValueType::String => write!(f, "string"),
476            ValueType::Record => write!(f, "record"),
477            ValueType::Null => write!(f, "null"),
478        }
479    }
480}
481
482/// A value, after it has been "reified" (borrowed) from a pointer.
483#[derive(Debug, Copy, Clone, PartialEq)]
484pub enum ReifiedValue<'h> {
485    /// A number is a floating-point value.
486    Number(f64),
487    /// A boolean value is either true or false.
488    Bool(bool),
489    /// A null value represents the absence of a value.
490    Null,
491    /// A list is a sequence of values.
492    List(&'h Vec<Value>, ListPointer),
493    /// A string is a sequence of characters.
494    String(&'h str, StringPointer),
495    /// A record is a collection of key-value pairs.
496    Record(&'h IndexMap<String, Value>, RecordPointer),
497    /// A lambda is a function definition.
498    Lambda(&'h LambdaDef, LambdaPointer),
499    /// A spread value is "spread" into its container when it is used in a list, record, or function call. (internal only)
500    Spread(ReifiedIterableValue<'h>, IterablePointer),
501    /// A built-in function is a function that is implemented in Rust.
502    BuiltIn(BuiltInFunction),
503}
504
505impl<'h> ReifiedValue<'h> {
506    pub fn with_heap(&'h self, heap: Rc<RefCell<Heap>>) -> WithHeap<'h, ReifiedValue<'h>> {
507        WithHeap { value: self, heap }
508    }
509}
510
511impl From<ReifiedValue<'_>> for Value {
512    fn from(value: ReifiedValue) -> Self {
513        match value {
514            ReifiedValue::Number(n) => Value::Number(n),
515            ReifiedValue::Bool(b) => Value::Bool(b),
516            ReifiedValue::Null => Value::Null,
517            ReifiedValue::List(_, p) => Value::List(p),
518            ReifiedValue::String(_, p) => Value::String(p),
519            ReifiedValue::Record(_, p) => Value::Record(p),
520            ReifiedValue::Lambda(_, p) => Value::Lambda(p),
521            ReifiedValue::Spread(_, p) => Value::Spread(p),
522            ReifiedValue::BuiltIn(id) => Value::BuiltIn(id),
523        }
524    }
525}
526
527#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
528pub enum SerializableIterableValue {
529    List(Vec<SerializableValue>),
530    String(String),
531    Record(IndexMap<String, SerializableValue>),
532}
533
534#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
535pub enum SerializableValue {
536    Number(f64),
537    Bool(bool),
538    Null,
539    List(Vec<SerializableValue>),
540    String(String),
541    Record(IndexMap<String, SerializableValue>),
542    Lambda(SerializableLambdaDef),
543    BuiltIn(String),
544}
545
546impl SerializableValue {
547    /// Convert from serde_json::Value to SerializableValue
548    pub fn from_json(value: &serde_json::Value) -> SerializableValue {
549        match value {
550            serde_json::Value::Number(n) => SerializableValue::Number(n.as_f64().unwrap_or(0.0)),
551            serde_json::Value::Bool(b) => SerializableValue::Bool(*b),
552            serde_json::Value::Null => SerializableValue::Null,
553            serde_json::Value::String(s) => SerializableValue::String(s.clone()),
554            serde_json::Value::Array(arr) => {
555                SerializableValue::List(arr.iter().map(Self::from_json).collect())
556            }
557            serde_json::Value::Object(obj) => {
558                // Check if this is a function object
559                if let Some(func_value) = obj.get("__blots_function")
560                    && let Some(func_str) = func_value.as_str()
561                {
562                    // Try to parse as a built-in function first (just a name)
563                    if crate::functions::BuiltInFunction::from_ident(func_str).is_some() {
564                        return SerializableValue::BuiltIn(func_str.to_string());
565                    }
566
567                    // Otherwise, parse as a lambda function
568                    // We need to parse the function source and convert it to a SerializableLambdaDef
569                    if let Ok(lambda_def) = Self::parse_function_source(func_str) {
570                        return SerializableValue::Lambda(lambda_def);
571                    }
572                }
573
574                // Regular record
575                let map: IndexMap<String, SerializableValue> = obj
576                    .iter()
577                    .map(|(k, v)| (k.clone(), Self::from_json(v)))
578                    .collect();
579                SerializableValue::Record(map)
580            }
581        }
582    }
583
584    /// Parse a function source string into a SerializableLambdaDef
585    fn parse_function_source(source: &str) -> Result<SerializableLambdaDef> {
586        use crate::expressions::pairs_to_expr;
587        use crate::parser::get_pairs;
588
589        // Parse the source as an expression
590        let pairs = get_pairs(source)?;
591
592        // Extract the lambda expression from the parsed pairs
593        for pair in pairs {
594            if let crate::parser::Rule::statement = pair.as_rule()
595                && let Some(inner_pair) = pair.into_inner().next()
596                && let crate::parser::Rule::expression = inner_pair.as_rule()
597            {
598                // Parse the expression to get an AST
599                let expr = pairs_to_expr(inner_pair.into_inner())?;
600
601                // Check if it's a lambda
602                if let crate::ast::Expr::Lambda { args, body } = expr.node {
603                    // Since the function is already inlined (no scope needed),
604                    // we create a SerializableLambdaDef with the source as the body
605                    return Ok(SerializableLambdaDef {
606                        name: None,
607                        args,
608                        body: crate::ast_to_source::expr_to_source(&body),
609                        scope: None, // Functions from JSON have no scope - they're already inlined
610                    });
611                }
612            }
613        }
614
615        Err(anyhow!("Failed to parse function source: {}", source))
616    }
617
618    /// Convert SerializableValue to clean serde_json::Value
619    pub fn to_json(&self) -> serde_json::Value {
620        match self {
621            SerializableValue::Number(n) => serde_json::Value::Number(
622                serde_json::Number::from_f64(*n).unwrap_or_else(|| serde_json::Number::from(0)),
623            ),
624            SerializableValue::Bool(b) => serde_json::Value::Bool(*b),
625            SerializableValue::Null => serde_json::Value::Null,
626            SerializableValue::String(s) => serde_json::Value::String(s.clone()),
627            SerializableValue::List(items) => {
628                serde_json::Value::Array(items.iter().map(|v| v.to_json()).collect())
629            }
630            SerializableValue::Record(fields) => {
631                let map: serde_json::Map<String, serde_json::Value> = fields
632                    .iter()
633                    .map(|(k, v)| (k.clone(), v.to_json()))
634                    .collect();
635                serde_json::Value::Object(map)
636            }
637            SerializableValue::Lambda(lambda_def) => {
638                // We can't inline scope values from SerializableLambdaDef because the body is already a string
639                // For now, output the function as a JSON object with the source code
640                let mut map = serde_json::Map::new();
641
642                // Build the function source with arguments
643                let args_str: Vec<String> = lambda_def
644                    .args
645                    .iter()
646                    .map(|arg| match arg {
647                        LambdaArg::Required(name) => name.clone(),
648                        LambdaArg::Optional(name) => format!("{}?", name),
649                        LambdaArg::Rest(name) => format!("...{}", name),
650                    })
651                    .collect();
652
653                let function_source = format!("({}) => {}", args_str.join(", "), lambda_def.body);
654
655                map.insert(
656                    "__blots_function".to_string(),
657                    serde_json::Value::String(function_source),
658                );
659                serde_json::Value::Object(map)
660            }
661            SerializableValue::BuiltIn(name) => {
662                // Output built-in functions in the same format as lambdas
663                let mut map = serde_json::Map::new();
664                map.insert(
665                    "__blots_function".to_string(),
666                    serde_json::Value::String(name.clone()),
667                );
668                serde_json::Value::Object(map)
669            }
670        }
671    }
672
673    pub fn from_value(value: &Value, heap: &Heap) -> Result<SerializableValue> {
674        match value {
675            Value::Number(n) => Ok(SerializableValue::Number(*n)),
676            Value::Bool(b) => Ok(SerializableValue::Bool(*b)),
677            Value::Null => Ok(SerializableValue::Null),
678            Value::List(p) => {
679                let list = p.reify(heap).as_list()?;
680                let serialized_list = list
681                    .iter()
682                    .map(|v| SerializableValue::from_value(v, heap))
683                    .collect::<Result<Vec<SerializableValue>>>()?;
684                Ok(SerializableValue::List(serialized_list))
685            }
686            Value::String(p) => {
687                let string = p.reify(heap).as_string()?;
688                Ok(SerializableValue::String(string.to_string()))
689            }
690            Value::Record(p) => {
691                let record = p.reify(heap).as_record()?;
692                let serialized_record = record
693                    .iter()
694                    .map(|(k, v)| Ok((k.to_string(), SerializableValue::from_value(v, heap)?)))
695                    .collect::<Result<IndexMap<String, SerializableValue>>>()?;
696                Ok(SerializableValue::Record(serialized_record))
697            }
698            Value::Lambda(p) => {
699                let lambda = p.reify(heap).as_lambda()?;
700
701                // Convert the scope to SerializableValues
702                let serializable_scope: IndexMap<String, SerializableValue> = lambda
703                    .scope
704                    .iter()
705                    .map(|(k, v)| SerializableValue::from_value(v, heap).map(|sv| (k.clone(), sv)))
706                    .collect::<Result<IndexMap<String, SerializableValue>>>()?;
707
708                // Generate the body with inlined scope values
709                let body_with_inlined_scope = crate::ast_to_source::expr_to_source_with_scope(
710                    &lambda.body,
711                    &serializable_scope,
712                );
713
714                Ok(SerializableValue::Lambda(SerializableLambdaDef {
715                    name: lambda.name.clone(),
716                    args: lambda.args.clone(),
717                    body: body_with_inlined_scope,
718                    scope: Some(serializable_scope),
719                }))
720            }
721            Value::BuiltIn(built_in) => Ok(SerializableValue::BuiltIn(built_in.name().to_string())),
722            Value::Spread(_) => Err(anyhow!("cannot serialize a spread value")),
723        }
724    }
725
726    pub fn to_value(&self, heap: &mut Heap) -> Result<Value> {
727        match self {
728            SerializableValue::Number(n) => Ok(Value::Number(*n)),
729            SerializableValue::Bool(b) => Ok(Value::Bool(*b)),
730            SerializableValue::Null => Ok(Value::Null),
731            SerializableValue::List(list) => {
732                let deserialized_list = list
733                    .iter()
734                    .map(|v| SerializableValue::to_value(v, heap))
735                    .collect::<Result<Vec<Value>>>()?;
736
737                Ok(heap.insert_list(deserialized_list))
738            }
739            SerializableValue::String(s) => Ok(heap.insert_string(s.to_string())),
740            SerializableValue::Record(record) => {
741                let deserialized_record = record
742                    .iter()
743                    .map(|(k, v)| Ok((k.to_string(), SerializableValue::to_value(v, heap)?)))
744                    .collect::<Result<IndexMap<String, Value>>>()?;
745                Ok(heap.insert_record(deserialized_record))
746            }
747            SerializableValue::Lambda(s_lambda) => {
748                let scope = if let Some(scope) = s_lambda.scope.as_ref() {
749                    scope
750                        .iter()
751                        .map(|(k, v)| Ok((k.to_string(), SerializableValue::to_value(v, heap)?)))
752                        .collect::<Result<HashMap<String, Value>>>()?
753                } else {
754                    HashMap::new()
755                };
756
757                // For now, parse the body string back to AST
758                // In a real implementation, we'd want to serialize/deserialize the AST properly
759                let body_ast = crate::expressions::pairs_to_expr(
760                    crate::parser::get_pairs(&s_lambda.body)?
761                        .next()
762                        .unwrap()
763                        .into_inner(),
764                )?;
765
766                let lambda = LambdaDef {
767                    name: s_lambda.name.clone(),
768                    args: s_lambda.args.clone(),
769                    body: body_ast,
770                    scope: CapturedScope::new(scope),
771                    source: Rc::from(""), // Deserialized lambdas don't have original source
772                };
773
774                Ok(heap.insert_lambda(lambda))
775            }
776            SerializableValue::BuiltIn(ident) => BuiltInFunction::from_ident(ident)
777                .ok_or(anyhow!("built-in function with ident {} not found", ident))
778                .map(Value::BuiltIn),
779        }
780    }
781}
782
783#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
784pub enum PrimitiveValue {
785    Number(f64),
786    Bool(bool),
787    Null,
788}
789
790impl From<PrimitiveValue> for Value {
791    fn from(val: PrimitiveValue) -> Self {
792        match val {
793            PrimitiveValue::Number(n) => Value::Number(n),
794            PrimitiveValue::Bool(b) => Value::Bool(b),
795            PrimitiveValue::Null => Value::Null,
796        }
797    }
798}
799
800impl From<PrimitiveValue> for SerializableValue {
801    fn from(val: PrimitiveValue) -> Self {
802        match val {
803            PrimitiveValue::Number(n) => SerializableValue::Number(n),
804            PrimitiveValue::Bool(b) => SerializableValue::Bool(b),
805            PrimitiveValue::Null => SerializableValue::Null,
806        }
807    }
808}
809
810#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
811pub enum Value {
812    /// A number is a floating-point value.
813    Number(f64),
814    /// A boolean value is either true or false.
815    Bool(bool),
816    /// A null value represents the absence of a value.
817    Null,
818    /// A list is a sequence of values.
819    List(ListPointer),
820    /// A string is a sequence of characters.
821    String(StringPointer),
822    /// A record is a collection of key-value pairs.
823    Record(RecordPointer),
824    /// A lambda is a function definition.
825    Lambda(LambdaPointer),
826    /// A spread value is "spread" into its container when it is used in a list, record, or function call. (internal only)
827    Spread(IterablePointer),
828    /// A built-in function is a function that is implemented in Rust.
829    BuiltIn(BuiltInFunction),
830}
831
832impl Value {
833    /// Compare two values for equality by their actual content, not by reference
834    pub fn equals(&self, other: &Value, heap: &Heap) -> Result<bool> {
835        match (self, other) {
836            // Primitive types - compare directly
837            (Value::Number(a), Value::Number(b)) => Ok(a == b),
838            (Value::Bool(a), Value::Bool(b)) => Ok(a == b),
839            (Value::Null, Value::Null) => Ok(true),
840
841            // String comparison - compare content
842            (Value::String(a_ptr), Value::String(b_ptr)) => {
843                let a_str = a_ptr.reify(heap).as_string()?;
844                let b_str = b_ptr.reify(heap).as_string()?;
845                Ok(a_str == b_str)
846            }
847
848            // List comparison - compare elements recursively
849            (Value::List(a_ptr), Value::List(b_ptr)) => {
850                let a_list = a_ptr.reify(heap).as_list()?;
851                let b_list = b_ptr.reify(heap).as_list()?;
852
853                if a_list.len() != b_list.len() {
854                    return Ok(false);
855                }
856
857                for (a_elem, b_elem) in a_list.iter().zip(b_list.iter()) {
858                    if !a_elem.equals(b_elem, heap)? {
859                        return Ok(false);
860                    }
861                }
862                Ok(true)
863            }
864
865            // Record comparison - compare keys and values
866            (Value::Record(a_ptr), Value::Record(b_ptr)) => {
867                let a_record = a_ptr.reify(heap).as_record()?;
868                let b_record = b_ptr.reify(heap).as_record()?;
869
870                if a_record.len() != b_record.len() {
871                    return Ok(false);
872                }
873
874                for (key, a_value) in a_record.iter() {
875                    match b_record.get(key) {
876                        Some(b_value) => {
877                            if !a_value.equals(b_value, heap)? {
878                                return Ok(false);
879                            }
880                        }
881                        None => return Ok(false),
882                    }
883                }
884                Ok(true)
885            }
886
887            // Lambda comparison - compare by structure (AST equality)
888            (Value::Lambda(a_ptr), Value::Lambda(b_ptr)) => {
889                let a_lambda = a_ptr.reify(heap).as_lambda()?;
890                let b_lambda = b_ptr.reify(heap).as_lambda()?;
891
892                // Compare argument lists
893                if a_lambda.args != b_lambda.args {
894                    return Ok(false);
895                }
896
897                // Compare AST bodies
898                if a_lambda.body != b_lambda.body {
899                    return Ok(false);
900                }
901
902                // Note: We don't compare scopes because two functions with the same
903                // definition but different closures would have different behavior
904                // For now, we only compare structure, not captured variables
905                Ok(true)
906            }
907
908            // Built-in functions - compare by ID
909            (Value::BuiltIn(a), Value::BuiltIn(b)) => Ok(a == b),
910
911            // Spread values - compare the underlying iterable
912            (Value::Spread(a_ptr), Value::Spread(b_ptr)) => match (a_ptr, b_ptr) {
913                (IterablePointer::List(a), IterablePointer::List(b)) => {
914                    Value::List(*a).equals(&Value::List(*b), heap)
915                }
916                (IterablePointer::String(a), IterablePointer::String(b)) => {
917                    Value::String(*a).equals(&Value::String(*b), heap)
918                }
919                (IterablePointer::Record(a), IterablePointer::Record(b)) => {
920                    Value::Record(*a).equals(&Value::Record(*b), heap)
921                }
922                _ => Ok(false),
923            },
924
925            // Different types are never equal
926            _ => Ok(false),
927        }
928    }
929
930    /// Compare two values for ordering
931    pub fn compare(&self, other: &Value, heap: &Heap) -> Result<Option<std::cmp::Ordering>> {
932        match (self, other) {
933            // Numbers have natural ordering
934            (Value::Number(a), Value::Number(b)) => Ok(a.partial_cmp(b)),
935
936            // Booleans: false < true
937            (Value::Bool(a), Value::Bool(b)) => Ok(a.partial_cmp(b)),
938
939            // Strings compare lexicographically
940            (Value::String(a_ptr), Value::String(b_ptr)) => {
941                let a_str = a_ptr.reify(heap).as_string()?;
942                let b_str = b_ptr.reify(heap).as_string()?;
943                Ok(a_str.partial_cmp(b_str))
944            }
945
946            // Lists compare lexicographically
947            (Value::List(a_ptr), Value::List(b_ptr)) => {
948                let a_list = a_ptr.reify(heap).as_list()?;
949                let b_list = b_ptr.reify(heap).as_list()?;
950
951                for (a_elem, b_elem) in a_list.iter().zip(b_list.iter()) {
952                    match a_elem.compare(b_elem, heap)? {
953                        Some(std::cmp::Ordering::Equal) => continue,
954                        other => return Ok(other),
955                    }
956                }
957
958                // If all compared elements are equal, compare lengths
959                Ok(a_list.len().partial_cmp(&b_list.len()))
960            }
961
962            // Other types don't have a natural ordering
963            _ => Ok(None),
964        }
965    }
966
967    pub fn get_type(&self) -> ValueType {
968        match self {
969            Value::Number(_) => ValueType::Number,
970            Value::List(_) => ValueType::List,
971            Value::Spread(_) => ValueType::Spread,
972            Value::Bool(_) => ValueType::Bool,
973            Value::Lambda(_) => ValueType::Lambda,
974            Value::String(_) => ValueType::String,
975            Value::Null => ValueType::Null,
976            Value::BuiltIn(_) => ValueType::BuiltIn,
977            Value::Record(_) => ValueType::Record,
978        }
979    }
980
981    pub fn is_number(&self) -> bool {
982        matches!(self, Value::Number(_))
983    }
984
985    pub fn is_list(&self) -> bool {
986        matches!(self, Value::List(_))
987    }
988
989    pub fn is_spread(&self) -> bool {
990        matches!(self, Value::Spread(_))
991    }
992
993    pub fn is_bool(&self) -> bool {
994        matches!(self, Value::Bool(_))
995    }
996
997    pub fn is_lambda(&self) -> bool {
998        matches!(self, Value::Lambda(_))
999    }
1000
1001    pub fn is_string(&self) -> bool {
1002        matches!(self, Value::String(_))
1003    }
1004
1005    pub fn is_null(&self) -> bool {
1006        matches!(self, Value::Null)
1007    }
1008
1009    pub fn is_built_in(&self) -> bool {
1010        matches!(self, Value::BuiltIn(_))
1011    }
1012
1013    pub fn is_callable(&self) -> bool {
1014        matches!(self, Value::BuiltIn(_) | Value::Lambda(_))
1015    }
1016
1017    pub fn as_number(&self) -> Result<f64> {
1018        match self {
1019            Value::Number(n) => Ok(*n),
1020            _ => Err(anyhow!("expected a number, but got a {}", self.get_type())),
1021        }
1022    }
1023
1024    pub fn as_list<'h>(&self, heap: &'h Heap) -> Result<&'h Vec<Value>> {
1025        match self {
1026            Value::List(l) => l.reify(heap).as_list(),
1027            _ => Err(anyhow!("expected a list, but got a {}", self.get_type())),
1028        }
1029    }
1030
1031    pub fn as_spread<'h>(&self, heap: &'h Heap) -> Result<&'h HeapValue> {
1032        match self {
1033            Value::Spread(v) => Ok(v.reify(heap)),
1034            _ => Err(anyhow!("expected a spread, but got a {}", self.get_type())),
1035        }
1036    }
1037
1038    pub fn as_bool(&self) -> Result<bool> {
1039        match self {
1040            Value::Bool(b) => Ok(*b),
1041            _ => Err(anyhow!("expected a boolean, but got a {}", self.get_type())),
1042        }
1043    }
1044
1045    pub fn as_lambda<'h>(&self, heap: &'h Heap) -> Result<&'h LambdaDef> {
1046        match self {
1047            Value::Lambda(l) => l.reify(heap).as_lambda(),
1048            _ => Err(anyhow!("expected a lambda, but got a {}", self.get_type())),
1049        }
1050    }
1051
1052    pub fn as_string<'h>(&self, heap: &'h Heap) -> Result<&'h str> {
1053        match self {
1054            Value::String(p) => p.reify(heap).as_string(),
1055            _ => Err(anyhow!("expected a string, but got a {}", self.get_type())),
1056        }
1057    }
1058
1059    pub fn as_null(&self) -> Result<()> {
1060        match self {
1061            Value::Null => Ok(()),
1062            _ => Err(anyhow!("expected a null, but got a {}", self.get_type())),
1063        }
1064    }
1065
1066    pub fn as_built_in(&self) -> Result<&str> {
1067        match self {
1068            Value::BuiltIn(built_in) => Ok(built_in.name()),
1069            _ => Err(anyhow!(
1070                "expected a built-in function, but got a {}",
1071                self.get_type()
1072            )),
1073        }
1074    }
1075
1076    pub fn as_record<'h>(&self, heap: &'h Heap) -> Result<&'h IndexMap<String, Value>> {
1077        match self {
1078            Value::Record(r) => r.reify(heap).as_record(),
1079            _ => Err(anyhow!("expected a record, but got a {}", self.get_type())),
1080        }
1081    }
1082
1083    pub fn as_list_pointer(&self) -> Result<ListPointer> {
1084        match self {
1085            Value::List(p) => Ok(*p),
1086            _ => Err(anyhow!("expected a list, but got a {}", self.get_type())),
1087        }
1088    }
1089
1090    pub fn as_string_pointer(&self) -> Result<StringPointer> {
1091        match self {
1092            Value::String(p) => Ok(*p),
1093            _ => Err(anyhow!("expected a string, but got a {}", self.get_type())),
1094        }
1095    }
1096
1097    pub fn as_record_pointer(&self) -> Result<RecordPointer> {
1098        match self {
1099            Value::Record(p) => Ok(*p),
1100            _ => Err(anyhow!("expected a record, but got a {}", self.get_type())),
1101        }
1102    }
1103
1104    pub fn as_lambda_pointer(&self) -> Result<LambdaPointer> {
1105        match self {
1106            Value::Lambda(p) => Ok(*p),
1107            _ => Err(anyhow!("expected a lambda, but got a {}", self.get_type())),
1108        }
1109    }
1110
1111    pub fn as_iterable_pointer(&self) -> Result<IterablePointer> {
1112        match self {
1113            Value::Spread(p) => Ok(*p),
1114            _ => Err(anyhow!("expected a spread, but got a {}", self.get_type())),
1115        }
1116    }
1117
1118    pub fn to_serializable_value(&self, heap: &Heap) -> Result<SerializableValue> {
1119        SerializableValue::from_value(self, heap)
1120    }
1121
1122    pub fn reify<'h>(&self, heap: &'h Heap) -> Result<ReifiedValue<'h>> {
1123        match self {
1124            Value::Number(n) => Ok(ReifiedValue::Number(*n)),
1125            Value::List(p) => Ok(ReifiedValue::List(p.reify(heap).as_list()?, *p)),
1126            Value::Spread(p) => Ok(ReifiedValue::Spread(p.reify(heap).as_iterable()?, *p)),
1127            Value::Bool(b) => Ok(ReifiedValue::Bool(*b)),
1128            Value::Lambda(p) => Ok(ReifiedValue::Lambda(p.reify(heap).as_lambda()?, *p)),
1129            Value::String(p) => Ok(ReifiedValue::String(p.reify(heap).as_string()?, *p)),
1130            Value::Null => Ok(ReifiedValue::Null),
1131            Value::BuiltIn(id) => Ok(ReifiedValue::BuiltIn(*id)),
1132            Value::Record(p) => Ok(ReifiedValue::Record(p.reify(heap).as_record()?, *p)),
1133        }
1134    }
1135
1136    /// Stringify the value. Returns the same thing as stringify, except for
1137    /// Value::String, which is returned without wrapping quotes. Use this for string
1138    /// concatenation, formatting, etc. Don't use this for displaying values to the user.
1139    pub fn stringify_internal(&self, heap: &Heap) -> String {
1140        self.stringify(heap, false, false)
1141    }
1142
1143    pub fn stringify_external(&self, heap: &Heap) -> String {
1144        self.stringify(heap, true, false)
1145    }
1146
1147    /// Stringify the value with display formatting (thousand separators, scientific notation).
1148    /// Use this for user-facing output like the format() function.
1149    pub fn stringify_for_display(&self, heap: &Heap) -> String {
1150        self.stringify(heap, false, true)
1151    }
1152
1153    fn stringify(&self, heap: &Heap, wrap_strings: bool, display_format: bool) -> String {
1154        match self {
1155            Value::String(p) => p
1156                .reify(heap)
1157                .as_string()
1158                .map(|s| {
1159                    if wrap_strings {
1160                        format!("\"{}\"", s)
1161                    } else {
1162                        s.to_string()
1163                    }
1164                })
1165                .unwrap(),
1166            Value::List(p) => {
1167                let mut result = String::from("[");
1168                let list = p.reify(heap).as_list().unwrap();
1169
1170                for (i, value) in list.iter().enumerate() {
1171                    result.push_str(&value.stringify(heap, wrap_strings, display_format));
1172                    if i < list.len() - 1 {
1173                        result.push_str(", ");
1174                    }
1175                }
1176                result.push(']');
1177                result
1178            }
1179            Value::Record(p) => {
1180                let mut result = String::from("{");
1181                let record = p.reify(heap).as_record().unwrap();
1182
1183                for (i, (key, value)) in record.iter().enumerate() {
1184                    result.push_str(&format!(
1185                        "{}: {}",
1186                        key,
1187                        value.stringify(heap, wrap_strings, display_format)
1188                    ));
1189                    if i < record.len() - 1 {
1190                        result.push_str(", ");
1191                    }
1192                }
1193                result.push('}');
1194                result
1195            }
1196            Value::Lambda(p) => {
1197                let lambda = p.reify(heap).as_lambda().unwrap();
1198                let mut result = String::from("(");
1199                for (i, arg) in lambda.args.iter().enumerate() {
1200                    result.push_str(&arg.to_string());
1201                    if i < lambda.args.len() - 1 {
1202                        result.push_str(", ");
1203                    }
1204                }
1205                result.push_str(") => ");
1206
1207                // Convert scope to SerializableValues and inline them
1208                let serializable_scope: IndexMap<String, SerializableValue> = lambda
1209                    .scope
1210                    .iter()
1211                    .filter_map(|(k, v)| {
1212                        SerializableValue::from_value(v, heap)
1213                            .ok()
1214                            .map(|sv| (k.clone(), sv))
1215                    })
1216                    .collect();
1217
1218                result.push_str(&crate::ast_to_source::expr_to_source_with_scope(
1219                    &lambda.body,
1220                    &serializable_scope,
1221                ));
1222                result
1223            }
1224            Value::BuiltIn(built_in) => {
1225                format!("{} (built-in)", built_in.name())
1226            }
1227            Value::Spread(p) => match p {
1228                IterablePointer::List(l) => {
1229                    let list = l.reify(heap).as_list().unwrap();
1230                    let mut result = String::from("...");
1231                    result.push_str(
1232                        &list
1233                            .iter()
1234                            .map(|v| v.stringify(heap, wrap_strings, display_format))
1235                            .collect::<String>(),
1236                    );
1237                    result
1238                }
1239                IterablePointer::String(s) => {
1240                    let string = s.reify(heap).as_string().unwrap();
1241                    format!("...{}", string)
1242                }
1243                IterablePointer::Record(r) => {
1244                    let record = r.reify(heap).as_record().unwrap();
1245                    let mut result = String::from("...");
1246                    result.push('{');
1247                    for (i, (key, value)) in record.iter().enumerate() {
1248                        result.push_str(&format!(
1249                            "{}: {}",
1250                            key,
1251                            value.stringify(heap, wrap_strings, display_format)
1252                        ));
1253                        if i < record.len() - 1 {
1254                            result.push_str(", ");
1255                        }
1256                    }
1257                    result.push('}');
1258                    result
1259                }
1260            },
1261            Value::Number(n) => {
1262                if display_format {
1263                    format_display_number(*n)
1264                } else {
1265                    n.to_string()
1266                }
1267            }
1268            Value::Bool(b) => b.to_string(),
1269            Value::Null => "null".to_string(),
1270        }
1271    }
1272}
1273
1274impl Display for Value {
1275    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1276        match self {
1277            Value::Number(n) => write!(f, "{}", format_display_number(*n)),
1278            Value::List(p) => write!(f, "{}", p),
1279            Value::Spread(p) => write!(f, "...{}", p),
1280            Value::Bool(b) => write!(f, "{}", b),
1281            Value::Lambda(p) => write!(f, "{}", p),
1282            Value::String(p) => write!(f, "{}", p),
1283            Value::Null => write!(f, "null"),
1284            Value::BuiltIn(built_in) => write!(f, "{} (built-in)", built_in.name()),
1285            Value::Record(p) => write!(f, "{}", p),
1286        }
1287    }
1288}
1289
1290#[cfg(test)]
1291mod tests {
1292    use super::*;
1293
1294    #[test]
1295    fn test_format_display_number_zero() {
1296        assert_eq!(format_display_number(0.0), "0");
1297        assert_eq!(format_display_number(-0.0), "-0"); // -0 is preserved
1298    }
1299
1300    #[test]
1301    fn test_format_display_number_integers() {
1302        assert_eq!(format_display_number(1.0), "1");
1303        assert_eq!(format_display_number(123.0), "123");
1304        assert_eq!(format_display_number(1234.0), "1,234");
1305        assert_eq!(format_display_number(1234567.0), "1,234,567");
1306        assert_eq!(format_display_number(-1234567.0), "-1,234,567");
1307    }
1308
1309    #[test]
1310    fn test_format_display_number_large_integers() {
1311        assert_eq!(
1312            format_display_number(999999999999999.0),
1313            "999,999,999,999,999"
1314        );
1315        assert_eq!(
1316            format_display_number(100000000000000.0),
1317            "100,000,000,000,000"
1318        );
1319    }
1320
1321    #[test]
1322    fn test_format_display_number_decimals() {
1323        assert_eq!(format_display_number(3.7432), "3.7432");
1324        assert_eq!(format_display_number(1234.56), "1,234.56");
1325        assert_eq!(format_display_number(0.5), "0.5");
1326        assert_eq!(format_display_number(0.0001), "0.0001");
1327    }
1328
1329    #[test]
1330    fn test_format_display_number_scientific_small() {
1331        // Numbers < 0.0001 should use scientific notation
1332        assert_eq!(format_display_number(0.00001), "1e-5");
1333        assert_eq!(format_display_number(0.00001234), "1.234e-5");
1334        assert_eq!(format_display_number(1e-10), "1e-10");
1335    }
1336
1337    #[test]
1338    fn test_format_display_number_scientific_large() {
1339        // Numbers >= 1e15 should use scientific notation
1340        assert_eq!(format_display_number(1e15), "1e15");
1341        assert_eq!(format_display_number(1.5e15), "1.5e15");
1342        assert_eq!(format_display_number(1e20), "1e20");
1343    }
1344
1345    #[test]
1346    fn test_format_display_number_special_values() {
1347        assert_eq!(format_display_number(f64::NAN), "NaN");
1348        assert_eq!(format_display_number(f64::INFINITY), "Infinity");
1349        assert_eq!(format_display_number(f64::NEG_INFINITY), "-Infinity");
1350    }
1351
1352    #[test]
1353    fn test_format_display_number_negative() {
1354        assert_eq!(format_display_number(-3.7432), "-3.7432");
1355        assert_eq!(format_display_number(-1234.56), "-1,234.56");
1356        assert_eq!(format_display_number(-0.00001), "-1e-5");
1357        assert_eq!(format_display_number(-1e15), "-1e15");
1358    }
1359
1360    #[test]
1361    fn test_stringify_internal_vs_display() {
1362        use crate::heap::Heap;
1363
1364        let heap = Heap::new();
1365        let value = Value::Number(1234567.89);
1366
1367        // stringify_internal uses plain formatting (for to_string)
1368        assert_eq!(value.stringify_internal(&heap), "1234567.89");
1369
1370        // stringify_for_display uses fancy formatting (for format)
1371        assert_eq!(value.stringify_for_display(&heap), "1,234,567.89");
1372    }
1373
1374    #[test]
1375    fn test_stringify_negative_zero() {
1376        use crate::heap::Heap;
1377
1378        let heap = Heap::new();
1379        let neg_zero = Value::Number(-0.0);
1380
1381        // Both stringify methods should preserve -0
1382        assert_eq!(neg_zero.stringify_internal(&heap), "-0");
1383        assert_eq!(neg_zero.stringify_for_display(&heap), "-0");
1384    }
1385}