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, PartialEq)]
299pub struct LambdaDef {
300    pub name: Option<String>,
301    pub args: Vec<LambdaArg>,
302    pub body: SpannedExpr,
303    pub scope: HashMap<String, Value>,
304    /// The source code string that the body's spans refer to (shared via Rc for efficiency)
305    pub source: Rc<str>,
306}
307
308impl LambdaDef {
309    pub fn set_name(&mut self, name: String, _value: Value) {
310        self.name = Some(name.clone());
311    }
312
313    pub fn get_arity(&self) -> FunctionArity {
314        let has_rest = self.args.iter().any(|arg| arg.is_rest());
315        let min = self.args.iter().filter(|arg| arg.is_required()).count();
316        let max = self.args.len();
317
318        if has_rest {
319            FunctionArity::AtLeast(min)
320        } else if min == max {
321            FunctionArity::Exact(min)
322        } else {
323            FunctionArity::Between(min, max)
324        }
325    }
326}
327
328impl PartialOrd for LambdaDef {
329    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
330        if self.args > other.args {
331            Some(std::cmp::Ordering::Greater)
332        } else if self.args < other.args {
333            Some(std::cmp::Ordering::Less)
334        } else {
335            Some(std::cmp::Ordering::Equal)
336        }
337    }
338}
339
340#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
341pub struct SerializableLambdaDef {
342    pub name: Option<String>,
343    pub args: Vec<LambdaArg>,
344    pub body: String,
345    pub scope: Option<IndexMap<String, SerializableValue>>,
346}
347
348pub struct WithHeap<'h, T> {
349    pub value: &'h T,
350    pub heap: Rc<RefCell<Heap>>,
351}
352
353#[derive(Debug, Copy, Clone, PartialEq)]
354pub enum ReifiedIterableValue<'h> {
355    List(&'h Vec<Value>),
356    String(&'h String),
357    Record(&'h IndexMap<String, Value>),
358}
359
360#[derive(Debug, Clone, PartialEq)]
361pub enum ReifiedIterableValueType {
362    List,
363    String,
364    Record,
365}
366
367impl<'h> ReifiedIterableValue<'h> {
368    pub fn with_heap(&'h self, heap: Rc<RefCell<Heap>>) -> WithHeap<'h, ReifiedIterableValue<'h>> {
369        WithHeap { value: self, heap }
370    }
371
372    pub fn get_type(&self) -> ReifiedIterableValueType {
373        match self {
374            ReifiedIterableValue::List(_) => ReifiedIterableValueType::List,
375            ReifiedIterableValue::String(_) => ReifiedIterableValueType::String,
376            ReifiedIterableValue::Record(_) => ReifiedIterableValueType::Record,
377        }
378    }
379}
380
381impl<'h> IntoIterator for WithHeap<'h, ReifiedIterableValue<'h>> {
382    type Item = Value;
383    type IntoIter = std::vec::IntoIter<Self::Item>;
384
385    fn into_iter(self) -> Self::IntoIter {
386        match self.value {
387            // Yields an iterator over the values in the list.
388            ReifiedIterableValue::List(l) => (*l).clone().into_iter(),
389            // Yields an iterator over the characters in the string.
390            ReifiedIterableValue::String(s) => s
391                .chars()
392                .map(|c| self.heap.borrow_mut().insert_string(c.to_string()))
393                .collect::<Vec<Value>>()
394                .into_iter(),
395            // Yields an iterator over the [key, value] pairs of the record.
396            ReifiedIterableValue::Record(r) => r
397                .into_iter()
398                .map(|(k, v)| {
399                    let list = vec![self.heap.borrow_mut().insert_string(k.to_string()), *v];
400                    self.heap.borrow_mut().insert_list(list)
401                })
402                .collect::<Vec<Value>>()
403                .into_iter(),
404        }
405    }
406}
407
408impl<'h> IntoIterator for WithHeap<'h, ReifiedValue<'h>> {
409    type Item = Value;
410    type IntoIter = std::vec::IntoIter<Self::Item>;
411
412    fn into_iter(self) -> Self::IntoIter {
413        match self.value {
414            ReifiedValue::Spread(iterable, _) => iterable.with_heap(self.heap).into_iter(),
415            _ => vec![(*self.value).into()].into_iter(),
416        }
417    }
418}
419
420#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
421pub enum ValueType {
422    Number,
423    List,
424    Spread,
425    Bool,
426    Lambda,
427    BuiltIn,
428    String,
429    Record,
430    Null,
431}
432
433impl Display for ValueType {
434    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
435        match self {
436            ValueType::Number => write!(f, "number"),
437            ValueType::List => write!(f, "list"),
438            ValueType::Spread => write!(f, "spread"),
439            ValueType::Bool => write!(f, "boolean"),
440            ValueType::Lambda => write!(f, "function"),
441            ValueType::BuiltIn => write!(f, "built-in function"),
442            ValueType::String => write!(f, "string"),
443            ValueType::Record => write!(f, "record"),
444            ValueType::Null => write!(f, "null"),
445        }
446    }
447}
448
449/// A value, after it has been "reified" (borrowed) from a pointer.
450#[derive(Debug, Copy, Clone, PartialEq)]
451pub enum ReifiedValue<'h> {
452    /// A number is a floating-point value.
453    Number(f64),
454    /// A boolean value is either true or false.
455    Bool(bool),
456    /// A null value represents the absence of a value.
457    Null,
458    /// A list is a sequence of values.
459    List(&'h Vec<Value>, ListPointer),
460    /// A string is a sequence of characters.
461    String(&'h str, StringPointer),
462    /// A record is a collection of key-value pairs.
463    Record(&'h IndexMap<String, Value>, RecordPointer),
464    /// A lambda is a function definition.
465    Lambda(&'h LambdaDef, LambdaPointer),
466    /// A spread value is "spread" into its container when it is used in a list, record, or function call. (internal only)
467    Spread(ReifiedIterableValue<'h>, IterablePointer),
468    /// A built-in function is a function that is implemented in Rust.
469    BuiltIn(BuiltInFunction),
470}
471
472impl<'h> ReifiedValue<'h> {
473    pub fn with_heap(&'h self, heap: Rc<RefCell<Heap>>) -> WithHeap<'h, ReifiedValue<'h>> {
474        WithHeap { value: self, heap }
475    }
476}
477
478impl From<ReifiedValue<'_>> for Value {
479    fn from(value: ReifiedValue) -> Self {
480        match value {
481            ReifiedValue::Number(n) => Value::Number(n),
482            ReifiedValue::Bool(b) => Value::Bool(b),
483            ReifiedValue::Null => Value::Null,
484            ReifiedValue::List(_, p) => Value::List(p),
485            ReifiedValue::String(_, p) => Value::String(p),
486            ReifiedValue::Record(_, p) => Value::Record(p),
487            ReifiedValue::Lambda(_, p) => Value::Lambda(p),
488            ReifiedValue::Spread(_, p) => Value::Spread(p),
489            ReifiedValue::BuiltIn(id) => Value::BuiltIn(id),
490        }
491    }
492}
493
494#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
495pub enum SerializableIterableValue {
496    List(Vec<SerializableValue>),
497    String(String),
498    Record(IndexMap<String, SerializableValue>),
499}
500
501#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
502pub enum SerializableValue {
503    Number(f64),
504    Bool(bool),
505    Null,
506    List(Vec<SerializableValue>),
507    String(String),
508    Record(IndexMap<String, SerializableValue>),
509    Lambda(SerializableLambdaDef),
510    BuiltIn(String),
511}
512
513impl SerializableValue {
514    /// Convert from serde_json::Value to SerializableValue
515    pub fn from_json(value: &serde_json::Value) -> SerializableValue {
516        match value {
517            serde_json::Value::Number(n) => SerializableValue::Number(n.as_f64().unwrap_or(0.0)),
518            serde_json::Value::Bool(b) => SerializableValue::Bool(*b),
519            serde_json::Value::Null => SerializableValue::Null,
520            serde_json::Value::String(s) => SerializableValue::String(s.clone()),
521            serde_json::Value::Array(arr) => {
522                SerializableValue::List(arr.iter().map(Self::from_json).collect())
523            }
524            serde_json::Value::Object(obj) => {
525                // Check if this is a function object
526                if let Some(func_value) = obj.get("__blots_function")
527                    && let Some(func_str) = func_value.as_str()
528                {
529                    // Try to parse as a built-in function first (just a name)
530                    if crate::functions::BuiltInFunction::from_ident(func_str).is_some() {
531                        return SerializableValue::BuiltIn(func_str.to_string());
532                    }
533
534                    // Otherwise, parse as a lambda function
535                    // We need to parse the function source and convert it to a SerializableLambdaDef
536                    if let Ok(lambda_def) = Self::parse_function_source(func_str) {
537                        return SerializableValue::Lambda(lambda_def);
538                    }
539                }
540
541                // Regular record
542                let map: IndexMap<String, SerializableValue> = obj
543                    .iter()
544                    .map(|(k, v)| (k.clone(), Self::from_json(v)))
545                    .collect();
546                SerializableValue::Record(map)
547            }
548        }
549    }
550
551    /// Parse a function source string into a SerializableLambdaDef
552    fn parse_function_source(source: &str) -> Result<SerializableLambdaDef> {
553        use crate::expressions::pairs_to_expr;
554        use crate::parser::get_pairs;
555
556        // Parse the source as an expression
557        let pairs = get_pairs(source)?;
558
559        // Extract the lambda expression from the parsed pairs
560        for pair in pairs {
561            if let crate::parser::Rule::statement = pair.as_rule()
562                && let Some(inner_pair) = pair.into_inner().next()
563                && let crate::parser::Rule::expression = inner_pair.as_rule()
564            {
565                // Parse the expression to get an AST
566                let expr = pairs_to_expr(inner_pair.into_inner())?;
567
568                // Check if it's a lambda
569                if let crate::ast::Expr::Lambda { args, body } = expr.node {
570                    // Since the function is already inlined (no scope needed),
571                    // we create a SerializableLambdaDef with the source as the body
572                    return Ok(SerializableLambdaDef {
573                        name: None,
574                        args,
575                        body: crate::ast_to_source::expr_to_source(&body),
576                        scope: None, // Functions from JSON have no scope - they're already inlined
577                    });
578                }
579            }
580        }
581
582        Err(anyhow!("Failed to parse function source: {}", source))
583    }
584
585    /// Convert SerializableValue to clean serde_json::Value
586    pub fn to_json(&self) -> serde_json::Value {
587        match self {
588            SerializableValue::Number(n) => serde_json::Value::Number(
589                serde_json::Number::from_f64(*n).unwrap_or_else(|| serde_json::Number::from(0)),
590            ),
591            SerializableValue::Bool(b) => serde_json::Value::Bool(*b),
592            SerializableValue::Null => serde_json::Value::Null,
593            SerializableValue::String(s) => serde_json::Value::String(s.clone()),
594            SerializableValue::List(items) => {
595                serde_json::Value::Array(items.iter().map(|v| v.to_json()).collect())
596            }
597            SerializableValue::Record(fields) => {
598                let map: serde_json::Map<String, serde_json::Value> = fields
599                    .iter()
600                    .map(|(k, v)| (k.clone(), v.to_json()))
601                    .collect();
602                serde_json::Value::Object(map)
603            }
604            SerializableValue::Lambda(lambda_def) => {
605                // We can't inline scope values from SerializableLambdaDef because the body is already a string
606                // For now, output the function as a JSON object with the source code
607                let mut map = serde_json::Map::new();
608
609                // Build the function source with arguments
610                let args_str: Vec<String> = lambda_def
611                    .args
612                    .iter()
613                    .map(|arg| match arg {
614                        LambdaArg::Required(name) => name.clone(),
615                        LambdaArg::Optional(name) => format!("{}?", name),
616                        LambdaArg::Rest(name) => format!("...{}", name),
617                    })
618                    .collect();
619
620                let function_source = format!("({}) => {}", args_str.join(", "), lambda_def.body);
621
622                map.insert(
623                    "__blots_function".to_string(),
624                    serde_json::Value::String(function_source),
625                );
626                serde_json::Value::Object(map)
627            }
628            SerializableValue::BuiltIn(name) => {
629                // Output built-in functions in the same format as lambdas
630                let mut map = serde_json::Map::new();
631                map.insert(
632                    "__blots_function".to_string(),
633                    serde_json::Value::String(name.clone()),
634                );
635                serde_json::Value::Object(map)
636            }
637        }
638    }
639
640    pub fn from_value(value: &Value, heap: &Heap) -> Result<SerializableValue> {
641        match value {
642            Value::Number(n) => Ok(SerializableValue::Number(*n)),
643            Value::Bool(b) => Ok(SerializableValue::Bool(*b)),
644            Value::Null => Ok(SerializableValue::Null),
645            Value::List(p) => {
646                let list = p.reify(heap).as_list()?;
647                let serialized_list = list
648                    .iter()
649                    .map(|v| SerializableValue::from_value(v, heap))
650                    .collect::<Result<Vec<SerializableValue>>>()?;
651                Ok(SerializableValue::List(serialized_list))
652            }
653            Value::String(p) => {
654                let string = p.reify(heap).as_string()?;
655                Ok(SerializableValue::String(string.to_string()))
656            }
657            Value::Record(p) => {
658                let record = p.reify(heap).as_record()?;
659                let serialized_record = record
660                    .iter()
661                    .map(|(k, v)| Ok((k.to_string(), SerializableValue::from_value(v, heap)?)))
662                    .collect::<Result<IndexMap<String, SerializableValue>>>()?;
663                Ok(SerializableValue::Record(serialized_record))
664            }
665            Value::Lambda(p) => {
666                let lambda = p.reify(heap).as_lambda()?;
667
668                // Convert the scope to SerializableValues
669                let serializable_scope: IndexMap<String, SerializableValue> = lambda
670                    .scope
671                    .clone()
672                    .into_iter()
673                    .map(|(k, v)| SerializableValue::from_value(&v, heap).map(|sv| (k, sv)))
674                    .collect::<Result<IndexMap<String, SerializableValue>>>()?;
675
676                // Generate the body with inlined scope values
677                let body_with_inlined_scope = crate::ast_to_source::expr_to_source_with_scope(
678                    &lambda.body,
679                    &serializable_scope,
680                );
681
682                Ok(SerializableValue::Lambda(SerializableLambdaDef {
683                    name: lambda.name.clone(),
684                    args: lambda.args.clone(),
685                    body: body_with_inlined_scope,
686                    scope: Some(serializable_scope),
687                }))
688            }
689            Value::BuiltIn(built_in) => Ok(SerializableValue::BuiltIn(built_in.name().to_string())),
690            Value::Spread(_) => Err(anyhow!("cannot serialize a spread value")),
691        }
692    }
693
694    pub fn to_value(&self, heap: &mut Heap) -> Result<Value> {
695        match self {
696            SerializableValue::Number(n) => Ok(Value::Number(*n)),
697            SerializableValue::Bool(b) => Ok(Value::Bool(*b)),
698            SerializableValue::Null => Ok(Value::Null),
699            SerializableValue::List(list) => {
700                let deserialized_list = list
701                    .iter()
702                    .map(|v| SerializableValue::to_value(v, heap))
703                    .collect::<Result<Vec<Value>>>()?;
704
705                Ok(heap.insert_list(deserialized_list))
706            }
707            SerializableValue::String(s) => Ok(heap.insert_string(s.to_string())),
708            SerializableValue::Record(record) => {
709                let deserialized_record = record
710                    .iter()
711                    .map(|(k, v)| Ok((k.to_string(), SerializableValue::to_value(v, heap)?)))
712                    .collect::<Result<IndexMap<String, Value>>>()?;
713                Ok(heap.insert_record(deserialized_record))
714            }
715            SerializableValue::Lambda(s_lambda) => {
716                let scope = if let Some(scope) = s_lambda.scope.clone() {
717                    scope
718                        .iter()
719                        .map(|(k, v)| Ok((k.to_string(), SerializableValue::to_value(v, heap)?)))
720                        .collect::<Result<HashMap<String, Value>>>()?
721                } else {
722                    HashMap::new()
723                };
724
725                // For now, parse the body string back to AST
726                // In a real implementation, we'd want to serialize/deserialize the AST properly
727                let body_ast = crate::expressions::pairs_to_expr(
728                    crate::parser::get_pairs(&s_lambda.body)?
729                        .next()
730                        .unwrap()
731                        .into_inner(),
732                )?;
733
734                let lambda = LambdaDef {
735                    name: s_lambda.name.clone(),
736                    args: s_lambda.args.clone(),
737                    body: body_ast,
738                    scope,
739                    source: Rc::from(""), // Deserialized lambdas don't have original source
740                };
741
742                Ok(heap.insert_lambda(lambda))
743            }
744            SerializableValue::BuiltIn(ident) => BuiltInFunction::from_ident(ident)
745                .ok_or(anyhow!("built-in function with ident {} not found", ident))
746                .map(Value::BuiltIn),
747        }
748    }
749}
750
751#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
752pub enum PrimitiveValue {
753    Number(f64),
754    Bool(bool),
755    Null,
756}
757
758impl From<PrimitiveValue> for Value {
759    fn from(val: PrimitiveValue) -> Self {
760        match val {
761            PrimitiveValue::Number(n) => Value::Number(n),
762            PrimitiveValue::Bool(b) => Value::Bool(b),
763            PrimitiveValue::Null => Value::Null,
764        }
765    }
766}
767
768impl From<PrimitiveValue> for SerializableValue {
769    fn from(val: PrimitiveValue) -> Self {
770        match val {
771            PrimitiveValue::Number(n) => SerializableValue::Number(n),
772            PrimitiveValue::Bool(b) => SerializableValue::Bool(b),
773            PrimitiveValue::Null => SerializableValue::Null,
774        }
775    }
776}
777
778#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
779pub enum Value {
780    /// A number is a floating-point value.
781    Number(f64),
782    /// A boolean value is either true or false.
783    Bool(bool),
784    /// A null value represents the absence of a value.
785    Null,
786    /// A list is a sequence of values.
787    List(ListPointer),
788    /// A string is a sequence of characters.
789    String(StringPointer),
790    /// A record is a collection of key-value pairs.
791    Record(RecordPointer),
792    /// A lambda is a function definition.
793    Lambda(LambdaPointer),
794    /// A spread value is "spread" into its container when it is used in a list, record, or function call. (internal only)
795    Spread(IterablePointer),
796    /// A built-in function is a function that is implemented in Rust.
797    BuiltIn(BuiltInFunction),
798}
799
800impl Value {
801    /// Compare two values for equality by their actual content, not by reference
802    pub fn equals(&self, other: &Value, heap: &Heap) -> Result<bool> {
803        match (self, other) {
804            // Primitive types - compare directly
805            (Value::Number(a), Value::Number(b)) => Ok(a == b),
806            (Value::Bool(a), Value::Bool(b)) => Ok(a == b),
807            (Value::Null, Value::Null) => Ok(true),
808
809            // String comparison - compare content
810            (Value::String(a_ptr), Value::String(b_ptr)) => {
811                let a_str = a_ptr.reify(heap).as_string()?;
812                let b_str = b_ptr.reify(heap).as_string()?;
813                Ok(a_str == b_str)
814            }
815
816            // List comparison - compare elements recursively
817            (Value::List(a_ptr), Value::List(b_ptr)) => {
818                let a_list = a_ptr.reify(heap).as_list()?;
819                let b_list = b_ptr.reify(heap).as_list()?;
820
821                if a_list.len() != b_list.len() {
822                    return Ok(false);
823                }
824
825                for (a_elem, b_elem) in a_list.iter().zip(b_list.iter()) {
826                    if !a_elem.equals(b_elem, heap)? {
827                        return Ok(false);
828                    }
829                }
830                Ok(true)
831            }
832
833            // Record comparison - compare keys and values
834            (Value::Record(a_ptr), Value::Record(b_ptr)) => {
835                let a_record = a_ptr.reify(heap).as_record()?;
836                let b_record = b_ptr.reify(heap).as_record()?;
837
838                if a_record.len() != b_record.len() {
839                    return Ok(false);
840                }
841
842                for (key, a_value) in a_record.iter() {
843                    match b_record.get(key) {
844                        Some(b_value) => {
845                            if !a_value.equals(b_value, heap)? {
846                                return Ok(false);
847                            }
848                        }
849                        None => return Ok(false),
850                    }
851                }
852                Ok(true)
853            }
854
855            // Lambda comparison - compare by structure (AST equality)
856            (Value::Lambda(a_ptr), Value::Lambda(b_ptr)) => {
857                let a_lambda = a_ptr.reify(heap).as_lambda()?;
858                let b_lambda = b_ptr.reify(heap).as_lambda()?;
859
860                // Compare argument lists
861                if a_lambda.args != b_lambda.args {
862                    return Ok(false);
863                }
864
865                // Compare AST bodies
866                if a_lambda.body != b_lambda.body {
867                    return Ok(false);
868                }
869
870                // Note: We don't compare scopes because two functions with the same
871                // definition but different closures would have different behavior
872                // For now, we only compare structure, not captured variables
873                Ok(true)
874            }
875
876            // Built-in functions - compare by ID
877            (Value::BuiltIn(a), Value::BuiltIn(b)) => Ok(a == b),
878
879            // Spread values - compare the underlying iterable
880            (Value::Spread(a_ptr), Value::Spread(b_ptr)) => match (a_ptr, b_ptr) {
881                (IterablePointer::List(a), IterablePointer::List(b)) => {
882                    Value::List(*a).equals(&Value::List(*b), heap)
883                }
884                (IterablePointer::String(a), IterablePointer::String(b)) => {
885                    Value::String(*a).equals(&Value::String(*b), heap)
886                }
887                (IterablePointer::Record(a), IterablePointer::Record(b)) => {
888                    Value::Record(*a).equals(&Value::Record(*b), heap)
889                }
890                _ => Ok(false),
891            },
892
893            // Different types are never equal
894            _ => Ok(false),
895        }
896    }
897
898    /// Compare two values for ordering
899    pub fn compare(&self, other: &Value, heap: &Heap) -> Result<Option<std::cmp::Ordering>> {
900        match (self, other) {
901            // Numbers have natural ordering
902            (Value::Number(a), Value::Number(b)) => Ok(a.partial_cmp(b)),
903
904            // Booleans: false < true
905            (Value::Bool(a), Value::Bool(b)) => Ok(a.partial_cmp(b)),
906
907            // Strings compare lexicographically
908            (Value::String(a_ptr), Value::String(b_ptr)) => {
909                let a_str = a_ptr.reify(heap).as_string()?;
910                let b_str = b_ptr.reify(heap).as_string()?;
911                Ok(a_str.partial_cmp(b_str))
912            }
913
914            // Lists compare lexicographically
915            (Value::List(a_ptr), Value::List(b_ptr)) => {
916                let a_list = a_ptr.reify(heap).as_list()?;
917                let b_list = b_ptr.reify(heap).as_list()?;
918
919                for (a_elem, b_elem) in a_list.iter().zip(b_list.iter()) {
920                    match a_elem.compare(b_elem, heap)? {
921                        Some(std::cmp::Ordering::Equal) => continue,
922                        other => return Ok(other),
923                    }
924                }
925
926                // If all compared elements are equal, compare lengths
927                Ok(a_list.len().partial_cmp(&b_list.len()))
928            }
929
930            // Other types don't have a natural ordering
931            _ => Ok(None),
932        }
933    }
934
935    pub fn get_type(&self) -> ValueType {
936        match self {
937            Value::Number(_) => ValueType::Number,
938            Value::List(_) => ValueType::List,
939            Value::Spread(_) => ValueType::Spread,
940            Value::Bool(_) => ValueType::Bool,
941            Value::Lambda(_) => ValueType::Lambda,
942            Value::String(_) => ValueType::String,
943            Value::Null => ValueType::Null,
944            Value::BuiltIn(_) => ValueType::BuiltIn,
945            Value::Record(_) => ValueType::Record,
946        }
947    }
948
949    pub fn is_number(&self) -> bool {
950        matches!(self, Value::Number(_))
951    }
952
953    pub fn is_list(&self) -> bool {
954        matches!(self, Value::List(_))
955    }
956
957    pub fn is_spread(&self) -> bool {
958        matches!(self, Value::Spread(_))
959    }
960
961    pub fn is_bool(&self) -> bool {
962        matches!(self, Value::Bool(_))
963    }
964
965    pub fn is_lambda(&self) -> bool {
966        matches!(self, Value::Lambda(_))
967    }
968
969    pub fn is_string(&self) -> bool {
970        matches!(self, Value::String(_))
971    }
972
973    pub fn is_null(&self) -> bool {
974        matches!(self, Value::Null)
975    }
976
977    pub fn is_built_in(&self) -> bool {
978        matches!(self, Value::BuiltIn(_))
979    }
980
981    pub fn is_callable(&self) -> bool {
982        matches!(self, Value::BuiltIn(_) | Value::Lambda(_))
983    }
984
985    pub fn as_number(&self) -> Result<f64> {
986        match self {
987            Value::Number(n) => Ok(*n),
988            _ => Err(anyhow!("expected a number, but got a {}", self.get_type())),
989        }
990    }
991
992    pub fn as_list<'h>(&self, heap: &'h Heap) -> Result<&'h Vec<Value>> {
993        match self {
994            Value::List(l) => l.reify(heap).as_list(),
995            _ => Err(anyhow!("expected a list, but got a {}", self.get_type())),
996        }
997    }
998
999    pub fn as_spread<'h>(&self, heap: &'h Heap) -> Result<&'h HeapValue> {
1000        match self {
1001            Value::Spread(v) => Ok(v.reify(heap)),
1002            _ => Err(anyhow!("expected a spread, but got a {}", self.get_type())),
1003        }
1004    }
1005
1006    pub fn as_bool(&self) -> Result<bool> {
1007        match self {
1008            Value::Bool(b) => Ok(*b),
1009            _ => Err(anyhow!("expected a boolean, but got a {}", self.get_type())),
1010        }
1011    }
1012
1013    pub fn as_lambda<'h>(&self, heap: &'h Heap) -> Result<&'h LambdaDef> {
1014        match self {
1015            Value::Lambda(l) => l.reify(heap).as_lambda(),
1016            _ => Err(anyhow!("expected a lambda, but got a {}", self.get_type())),
1017        }
1018    }
1019
1020    pub fn as_string<'h>(&self, heap: &'h Heap) -> Result<&'h str> {
1021        match self {
1022            Value::String(p) => p.reify(heap).as_string(),
1023            _ => Err(anyhow!("expected a string, but got a {}", self.get_type())),
1024        }
1025    }
1026
1027    pub fn as_null(&self) -> Result<()> {
1028        match self {
1029            Value::Null => Ok(()),
1030            _ => Err(anyhow!("expected a null, but got a {}", self.get_type())),
1031        }
1032    }
1033
1034    pub fn as_built_in(&self) -> Result<&str> {
1035        match self {
1036            Value::BuiltIn(built_in) => Ok(built_in.name()),
1037            _ => Err(anyhow!(
1038                "expected a built-in function, but got a {}",
1039                self.get_type()
1040            )),
1041        }
1042    }
1043
1044    pub fn as_record<'h>(&self, heap: &'h Heap) -> Result<&'h IndexMap<String, Value>> {
1045        match self {
1046            Value::Record(r) => r.reify(heap).as_record(),
1047            _ => Err(anyhow!("expected a record, but got a {}", self.get_type())),
1048        }
1049    }
1050
1051    pub fn as_list_pointer(&self) -> Result<ListPointer> {
1052        match self {
1053            Value::List(p) => Ok(*p),
1054            _ => Err(anyhow!("expected a list, but got a {}", self.get_type())),
1055        }
1056    }
1057
1058    pub fn as_string_pointer(&self) -> Result<StringPointer> {
1059        match self {
1060            Value::String(p) => Ok(*p),
1061            _ => Err(anyhow!("expected a string, but got a {}", self.get_type())),
1062        }
1063    }
1064
1065    pub fn as_record_pointer(&self) -> Result<RecordPointer> {
1066        match self {
1067            Value::Record(p) => Ok(*p),
1068            _ => Err(anyhow!("expected a record, but got a {}", self.get_type())),
1069        }
1070    }
1071
1072    pub fn as_lambda_pointer(&self) -> Result<LambdaPointer> {
1073        match self {
1074            Value::Lambda(p) => Ok(*p),
1075            _ => Err(anyhow!("expected a lambda, but got a {}", self.get_type())),
1076        }
1077    }
1078
1079    pub fn as_iterable_pointer(&self) -> Result<IterablePointer> {
1080        match self {
1081            Value::Spread(p) => Ok(*p),
1082            _ => Err(anyhow!("expected a spread, but got a {}", self.get_type())),
1083        }
1084    }
1085
1086    pub fn to_serializable_value(&self, heap: &Heap) -> Result<SerializableValue> {
1087        SerializableValue::from_value(self, heap)
1088    }
1089
1090    pub fn reify<'h>(&self, heap: &'h Heap) -> Result<ReifiedValue<'h>> {
1091        match self {
1092            Value::Number(n) => Ok(ReifiedValue::Number(*n)),
1093            Value::List(p) => Ok(ReifiedValue::List(p.reify(heap).as_list()?, *p)),
1094            Value::Spread(p) => Ok(ReifiedValue::Spread(p.reify(heap).as_iterable()?, *p)),
1095            Value::Bool(b) => Ok(ReifiedValue::Bool(*b)),
1096            Value::Lambda(p) => Ok(ReifiedValue::Lambda(p.reify(heap).as_lambda()?, *p)),
1097            Value::String(p) => Ok(ReifiedValue::String(p.reify(heap).as_string()?, *p)),
1098            Value::Null => Ok(ReifiedValue::Null),
1099            Value::BuiltIn(id) => Ok(ReifiedValue::BuiltIn(*id)),
1100            Value::Record(p) => Ok(ReifiedValue::Record(p.reify(heap).as_record()?, *p)),
1101        }
1102    }
1103
1104    /// Stringify the value. Returns the same thing as stringify, except for
1105    /// Value::String, which is returned without wrapping quotes. Use this for string
1106    /// concatenation, formatting, etc. Don't use this for displaying values to the user.
1107    pub fn stringify_internal(&self, heap: &Heap) -> String {
1108        self.stringify(heap, false, false)
1109    }
1110
1111    pub fn stringify_external(&self, heap: &Heap) -> String {
1112        self.stringify(heap, true, false)
1113    }
1114
1115    /// Stringify the value with display formatting (thousand separators, scientific notation).
1116    /// Use this for user-facing output like the format() function.
1117    pub fn stringify_for_display(&self, heap: &Heap) -> String {
1118        self.stringify(heap, false, true)
1119    }
1120
1121    fn stringify(&self, heap: &Heap, wrap_strings: bool, display_format: bool) -> String {
1122        match self {
1123            Value::String(p) => p
1124                .reify(heap)
1125                .as_string()
1126                .map(|s| {
1127                    if wrap_strings {
1128                        format!("\"{}\"", s)
1129                    } else {
1130                        s.to_string()
1131                    }
1132                })
1133                .unwrap(),
1134            Value::List(p) => {
1135                let mut result = String::from("[");
1136                let list = p.reify(heap).as_list().unwrap();
1137
1138                for (i, value) in list.iter().enumerate() {
1139                    result.push_str(&value.stringify(heap, wrap_strings, display_format));
1140                    if i < list.len() - 1 {
1141                        result.push_str(", ");
1142                    }
1143                }
1144                result.push(']');
1145                result
1146            }
1147            Value::Record(p) => {
1148                let mut result = String::from("{");
1149                let record = p.reify(heap).as_record().unwrap();
1150
1151                for (i, (key, value)) in record.iter().enumerate() {
1152                    result.push_str(&format!(
1153                        "{}: {}",
1154                        key,
1155                        value.stringify(heap, wrap_strings, display_format)
1156                    ));
1157                    if i < record.len() - 1 {
1158                        result.push_str(", ");
1159                    }
1160                }
1161                result.push('}');
1162                result
1163            }
1164            Value::Lambda(p) => {
1165                let lambda = p.reify(heap).as_lambda().unwrap();
1166                let mut result = String::from("(");
1167                for (i, arg) in lambda.args.iter().enumerate() {
1168                    result.push_str(&arg.to_string());
1169                    if i < lambda.args.len() - 1 {
1170                        result.push_str(", ");
1171                    }
1172                }
1173                result.push_str(") => ");
1174
1175                // Convert scope to SerializableValues and inline them
1176                let serializable_scope: IndexMap<String, SerializableValue> = lambda
1177                    .scope
1178                    .iter()
1179                    .filter_map(|(k, v)| {
1180                        SerializableValue::from_value(v, heap)
1181                            .ok()
1182                            .map(|sv| (k.clone(), sv))
1183                    })
1184                    .collect();
1185
1186                result.push_str(&crate::ast_to_source::expr_to_source_with_scope(
1187                    &lambda.body,
1188                    &serializable_scope,
1189                ));
1190                result
1191            }
1192            Value::BuiltIn(built_in) => {
1193                format!("{} (built-in)", built_in.name())
1194            }
1195            Value::Spread(p) => match p {
1196                IterablePointer::List(l) => {
1197                    let list = l.reify(heap).as_list().unwrap();
1198                    let mut result = String::from("...");
1199                    result.push_str(
1200                        &list
1201                            .iter()
1202                            .map(|v| v.stringify(heap, wrap_strings, display_format))
1203                            .collect::<String>(),
1204                    );
1205                    result
1206                }
1207                IterablePointer::String(s) => {
1208                    let string = s.reify(heap).as_string().unwrap();
1209                    format!("...{}", string)
1210                }
1211                IterablePointer::Record(r) => {
1212                    let record = r.reify(heap).as_record().unwrap();
1213                    let mut result = String::from("...");
1214                    result.push('{');
1215                    for (i, (key, value)) in record.iter().enumerate() {
1216                        result.push_str(&format!(
1217                            "{}: {}",
1218                            key,
1219                            value.stringify(heap, wrap_strings, display_format)
1220                        ));
1221                        if i < record.len() - 1 {
1222                            result.push_str(", ");
1223                        }
1224                    }
1225                    result.push('}');
1226                    result
1227                }
1228            },
1229            Value::Number(n) => {
1230                if display_format {
1231                    format_display_number(*n)
1232                } else {
1233                    n.to_string()
1234                }
1235            }
1236            Value::Bool(b) => b.to_string(),
1237            Value::Null => "null".to_string(),
1238        }
1239    }
1240}
1241
1242impl Display for Value {
1243    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1244        match self {
1245            Value::Number(n) => write!(f, "{}", format_display_number(*n)),
1246            Value::List(p) => write!(f, "{}", p),
1247            Value::Spread(p) => write!(f, "...{}", p),
1248            Value::Bool(b) => write!(f, "{}", b),
1249            Value::Lambda(p) => write!(f, "{}", p),
1250            Value::String(p) => write!(f, "{}", p),
1251            Value::Null => write!(f, "null"),
1252            Value::BuiltIn(built_in) => write!(f, "{} (built-in)", built_in.name()),
1253            Value::Record(p) => write!(f, "{}", p),
1254        }
1255    }
1256}
1257
1258#[cfg(test)]
1259mod tests {
1260    use super::*;
1261
1262    #[test]
1263    fn test_format_display_number_zero() {
1264        assert_eq!(format_display_number(0.0), "0");
1265        assert_eq!(format_display_number(-0.0), "-0"); // -0 is preserved
1266    }
1267
1268    #[test]
1269    fn test_format_display_number_integers() {
1270        assert_eq!(format_display_number(1.0), "1");
1271        assert_eq!(format_display_number(123.0), "123");
1272        assert_eq!(format_display_number(1234.0), "1,234");
1273        assert_eq!(format_display_number(1234567.0), "1,234,567");
1274        assert_eq!(format_display_number(-1234567.0), "-1,234,567");
1275    }
1276
1277    #[test]
1278    fn test_format_display_number_large_integers() {
1279        assert_eq!(
1280            format_display_number(999999999999999.0),
1281            "999,999,999,999,999"
1282        );
1283        assert_eq!(
1284            format_display_number(100000000000000.0),
1285            "100,000,000,000,000"
1286        );
1287    }
1288
1289    #[test]
1290    fn test_format_display_number_decimals() {
1291        assert_eq!(format_display_number(3.14159), "3.14159");
1292        assert_eq!(format_display_number(1234.56), "1,234.56");
1293        assert_eq!(format_display_number(0.5), "0.5");
1294        assert_eq!(format_display_number(0.0001), "0.0001");
1295    }
1296
1297    #[test]
1298    fn test_format_display_number_scientific_small() {
1299        // Numbers < 0.0001 should use scientific notation
1300        assert_eq!(format_display_number(0.00001), "1e-5");
1301        assert_eq!(format_display_number(0.00001234), "1.234e-5");
1302        assert_eq!(format_display_number(1e-10), "1e-10");
1303    }
1304
1305    #[test]
1306    fn test_format_display_number_scientific_large() {
1307        // Numbers >= 1e15 should use scientific notation
1308        assert_eq!(format_display_number(1e15), "1e15");
1309        assert_eq!(format_display_number(1.5e15), "1.5e15");
1310        assert_eq!(format_display_number(1e20), "1e20");
1311    }
1312
1313    #[test]
1314    fn test_format_display_number_special_values() {
1315        assert_eq!(format_display_number(f64::NAN), "NaN");
1316        assert_eq!(format_display_number(f64::INFINITY), "Infinity");
1317        assert_eq!(format_display_number(f64::NEG_INFINITY), "-Infinity");
1318    }
1319
1320    #[test]
1321    fn test_format_display_number_negative() {
1322        assert_eq!(format_display_number(-3.14), "-3.14");
1323        assert_eq!(format_display_number(-1234.56), "-1,234.56");
1324        assert_eq!(format_display_number(-0.00001), "-1e-5");
1325        assert_eq!(format_display_number(-1e15), "-1e15");
1326    }
1327
1328    #[test]
1329    fn test_stringify_internal_vs_display() {
1330        use crate::heap::Heap;
1331
1332        let heap = Heap::new();
1333        let value = Value::Number(1234567.89);
1334
1335        // stringify_internal uses plain formatting (for to_string)
1336        assert_eq!(value.stringify_internal(&heap), "1234567.89");
1337
1338        // stringify_for_display uses fancy formatting (for format)
1339        assert_eq!(value.stringify_for_display(&heap), "1,234,567.89");
1340    }
1341
1342    #[test]
1343    fn test_stringify_negative_zero() {
1344        use crate::heap::Heap;
1345
1346        let heap = Heap::new();
1347        let neg_zero = Value::Number(-0.0);
1348
1349        // Both stringify methods should preserve -0
1350        assert_eq!(neg_zero.stringify_internal(&heap), "-0");
1351        assert_eq!(neg_zero.stringify_for_display(&heap), "-0");
1352    }
1353}