uni_core/
parser.rs

1// This module converts tokens (from the tokenizer) into Values (our AST/data structures)
2//
3// UNI EXECUTION MODEL:
4// - Numbers (42, 3.14): Push themselves onto the stack
5// - Strings ("hello"): Push themselves onto the stack
6// - Lists ([1 2 +]): Push themselves onto the stack as data (code-as-data)
7// - Atoms (hello, +): Execute by looking up in dictionary
8// - Quoted Atoms ('hello): Push the atom onto the stack without executing
9// - To execute a list: [1 2 +] exec  (push list, then exec executes it)
10//
11// RUST LEARNING NOTES:
12// - We use 'use' statements to import types from other modules
13// - The 'std::rc::Rc' is Rust's reference-counted smart pointer for shared ownership
14// - 'Result<T, E>' is Rust's way of handling errors without exceptions
15// - Pattern matching with 'match' is Rust's equivalent to switch statements but much more powerful
16
17use crate::compat::{Rc, String, Vec, format, ToString};
18use crate::interpreter::Interpreter;
19use crate::tokenizer::{Token, TokenKind, tokenize};
20use crate::value::{RuntimeError, Value};
21use num_bigint::BigInt;
22#[cfg(feature = "complex_numbers")]
23use num_complex::Complex64;
24use num_rational::BigRational;
25
26// RUST CONCEPT: Error types
27// We create our own error type for parser-specific errors
28// #[derive(Debug)] automatically implements Debug trait so we can print errors
29// This is separate from RuntimeError because parsing happens before execution
30#[derive(Debug)]
31pub enum ParseError {
32    UnexpectedToken(String), // Got a token we didn't expect
33    UnexpectedEndOfInput,    // Ran out of tokens when we needed more
34    MismatchedBrackets,      // [ without matching ] or vice versa
35    InvalidPipeNotation,      // Malformed [a | b] pair syntax
36    InvalidNumber(String),   // Number literal that failed to parse
37}
38
39// RUST CONCEPT: Display trait implementation for better error messages
40// This ensures the String field in UnexpectedToken is actually used
41impl crate::compat::fmt::Display for ParseError {
42    fn fmt(&self, f: &mut crate::compat::fmt::Formatter<'_>) -> crate::compat::fmt::Result {
43        match self {
44            ParseError::UnexpectedToken(msg) => write!(f, "{}", msg),
45            ParseError::UnexpectedEndOfInput => write!(f, "Unexpected end of input"),
46            ParseError::MismatchedBrackets => write!(f, "Mismatched brackets"),
47            ParseError::InvalidPipeNotation => write!(f, "Invalid pipe notation"),
48            ParseError::InvalidNumber(msg) => write!(f, "{}", msg),
49        }
50    }
51}
52
53// RUST CONCEPT: From trait
54// This lets us convert ParseError into RuntimeError when needed
55// The ? operator will automatically call this conversion
56impl From<ParseError> for RuntimeError {
57    fn from(err: ParseError) -> Self {
58        RuntimeError::TypeError(format!("Parse error: {:?}", err))
59    }
60}
61
62// RUST CONCEPT: Public functions
63// 'pub fn' makes this function available to other modules
64// This is our main entry point - takes a string, returns parsed Values
65pub fn parse(input: &str, interp: &mut Interpreter) -> Result<Vec<Value>, ParseError> {
66    // RUST CONCEPT: Error propagation
67    // The ? operator here means "if tokenize fails, return that error immediately"
68    // Otherwise, unwrap the Ok value and continue
69    let tokens = tokenize(input)
70        .map_err(|e| ParseError::UnexpectedToken(format!("Tokenize error: {}", e)))?;
71
72    // RUST CONCEPT: Mutable variables
73    // We need 'mut' because we'll be modifying the index as we parse
74    // Rust variables are immutable by default - you must explicitly opt into mutation
75    let mut index = 0;
76
77    // RUST CONCEPT: Vec (growable array)
78    // Vec::new() creates an empty vector that can grow as we add elements
79    // This will hold all the top-level values we parse
80    let mut results = Vec::new();
81
82    // RUST CONCEPT: while loops and slice indexing
83    // tokens.len() gives us the number of tokens
84    // We continue until we've processed all tokens
85    while index < tokens.len() {
86        // RUST CONCEPT: Mutable references
87        // We pass &mut index so parse_value can modify our index variable
88        // This is how the parser keeps track of where it is in the token stream
89        let value = parse_value(&tokens, &mut index, interp)?;
90        results.push(value);
91    }
92
93    // RUST CONCEPT: Return values
94    // Rust functions return the last expression if it doesn't end with semicolon
95    // Ok(results) wraps our successful result in the Result type
96    Ok(results)
97}
98
99// RUST CONCEPT: Function parameters and lifetimes
100// &[Token] is a slice - a view into part of a vector
101// &mut usize means we can modify the index parameter
102// The lifetime is implicit here - Rust infers that the returned Value
103// can't outlive the tokens slice (which is fine since we're cloning data)
104fn parse_value(
105    tokens: &[Token],
106    index: &mut usize,
107    interp: &mut Interpreter,
108) -> Result<Value, ParseError> {
109    // RUST CONCEPT: Bounds checking
110    // .get() returns Option<T> - Some(value) if index exists, None if out of bounds
111    // This is safer than direct indexing which would panic on out-of-bounds
112    match tokens.get(*index) {
113        // RUST CONCEPT: Pattern matching on references
114        // We match on &Token because .get() returns Option<&Token>
115        // The & in the pattern destructures the reference
116        Some(token) if matches!(token.kind, TokenKind::Number(_)) => {
117            if let TokenKind::Number(n) = token.kind {
118                *index += 1; // RUST CONCEPT: Dereferencing - modify the value index points to
119                Ok(Value::Number(n))
120            } else {
121                unreachable!()
122            }
123        }
124
125        Some(token) if matches!(token.kind, TokenKind::Integer(_)) => {
126            if let TokenKind::Integer(s) = &token.kind {
127                *index += 1;
128                // RUST CONCEPT: Try i32 first for embedded-friendly performance
129                // If it fits in i32 range, use Int32; otherwise fall back to BigInt
130                if let Ok(i32_val) = s.parse::<i32>() {
131                    Ok(Value::Int32(i32_val))
132                } else {
133                    match s.parse::<BigInt>() {
134                        Ok(i) => Ok(Value::Integer(i)),
135                        Err(_) => Err(ParseError::InvalidNumber(format!("Invalid integer: {}", s))),
136                    }
137                }
138            } else {
139                unreachable!()
140            }
141        }
142
143        Some(token) if matches!(token.kind, TokenKind::BigInt(_)) => {
144            if let TokenKind::BigInt(s) = &token.kind {
145                *index += 1;
146                match s.parse::<BigInt>() {
147                    Ok(i) => Ok(Value::Integer(i)),
148                    Err(_) => Err(ParseError::InvalidNumber(format!("Invalid BigInt: {}", s))),
149                }
150            } else {
151                unreachable!()
152            }
153        }
154
155        Some(token) if matches!(token.kind, TokenKind::Rational(_, _)) => {
156            if let TokenKind::Rational(numer, denom) = &token.kind {
157                *index += 1;
158                match (numer.parse::<i64>(), denom.parse::<i64>()) {
159                    (Ok(n), Ok(d)) if d != 0 => {
160                        let rational = Value::Rational(BigRational::new(BigInt::from(n), BigInt::from(d)));
161                        Ok(rational.demote())
162                    }
163                    _ => Err(ParseError::InvalidNumber(format!("Invalid rational: {}/{}", numer, denom))),
164                }
165            } else {
166                unreachable!()
167            }
168        }
169
170        #[cfg(feature = "complex_numbers")]
171        Some(token) if matches!(token.kind, TokenKind::GaussianInt(_, _)) => {
172            if let TokenKind::GaussianInt(re, im) = &token.kind {
173                *index += 1;
174                match (re.parse::<i64>(), im.parse::<i64>()) {
175                    (Ok(r), Ok(i)) => Ok(Value::GaussianInt(BigInt::from(r), BigInt::from(i))),
176                    _ => Err(ParseError::InvalidNumber(format!("Invalid Gaussian integer: {}+{}i", re, im))),
177                }
178            } else {
179                unreachable!()
180            }
181        }
182
183        #[cfg(feature = "complex_numbers")]
184        Some(token) if matches!(token.kind, TokenKind::Complex(_, _)) => {
185            if let TokenKind::Complex(re, im) = &token.kind {
186                *index += 1;
187                match (re.parse::<f64>(), im.parse::<f64>()) {
188                    (Ok(r), Ok(i)) => Ok(Value::Complex(Complex64::new(r, i))),
189                    _ => Err(ParseError::InvalidNumber(format!("Invalid complex: {}+{}i", re, im))),
190                }
191            } else {
192                unreachable!()
193            }
194        }
195
196        Some(token) if matches!(token.kind, TokenKind::Atom(_)) => {
197            if let TokenKind::Atom(atom_text) = &token.kind {
198                *index += 1;
199
200                // RUST CONCEPT: Atom interning
201                // Atoms are symbols that get interned (deduplicated) for memory efficiency
202                // The tokenizer has already identified all numeric literals, so anything
203                // here is a true atom (identifier/symbol)
204                let interned_atom = interp.intern_atom(atom_text);
205                Ok(Value::Atom(interned_atom))
206            } else {
207                unreachable!()
208            }
209        }
210
211        Some(token) if matches!(token.kind, TokenKind::String(_)) => {
212            if let TokenKind::String(string_text) = &token.kind {
213                *index += 1;
214                // RUST CONCEPT: Converting String to Rc<str>
215                // .clone() gets an owned String, .into() converts to Rc<str>
216                // Strings are NOT interned - each one gets its own Rc
217                let string_rc: Rc<str> = string_text.clone().into();
218                Ok(Value::String(string_rc))
219            } else {
220                unreachable!()
221            }
222        }
223
224        Some(token) if matches!(token.kind, TokenKind::Boolean(_)) => {
225            if let TokenKind::Boolean(b) = token.kind {
226                *index += 1;
227                // RUST CONCEPT: Boolean literals
228                // Boolean tokens directly create Boolean values
229                Ok(Value::Boolean(b))
230            } else {
231                unreachable!()
232            }
233        }
234
235        Some(token) if matches!(token.kind, TokenKind::Null) => {
236            *index += 1;
237            // RUST CONCEPT: Null literal
238            // Null token creates a Null value
239            Ok(Value::Null)
240        }
241
242        Some(token) if matches!(token.kind, TokenKind::LeftBracket) => {
243            // RUST CONCEPT: Recursive parsing
244            // Lists can contain other lists, so we call parse_list which may call parse_value again
245            parse_list(tokens, index, interp)
246        }
247
248        Some(token) if matches!(token.kind, TokenKind::ArrayLeftBracket) => {
249            parse_array(tokens, index, interp)
250        }
251
252        Some(token) if matches!(token.kind, TokenKind::Quote) => {
253            *index += 1; // Skip the quote token
254
255            // RUST CONCEPT: Validating syntax rules
256            // In Uni, only atoms can be quoted. Lists, numbers, and strings
257            // don't need quotes because they push themselves onto the stack by default
258            match tokens.get(*index) {
259                Some(token) if matches!(token.kind, TokenKind::Atom(_)) => {
260                    if let TokenKind::Atom(atom_text) = &token.kind {
261                        *index += 1; // Consume the atom token
262
263                        // RUST CONCEPT: Creating quoted atoms directly
264                        // Instead of (quote atom) structure, we create a QuotedAtom value
265                        // This directly represents the semantics: push atom without executing
266                        let interned_atom = interp.intern_atom(atom_text);
267                        Ok(Value::QuotedAtom(interned_atom))
268                    } else {
269                        unreachable!()
270                    }
271                }
272                Some(token) if matches!(token.kind, TokenKind::LeftBracket) => {
273                    // RUST CONCEPT: Custom error types for syntax validation
274                    // Lists don't need quotes - they're data by default
275                    Err(ParseError::UnexpectedToken(
276                        "Lists cannot be quoted - they are data by default".to_string(),
277                    ))
278                }
279                Some(token) if matches!(token.kind, TokenKind::String(_)) => {
280                    // Strings don't need quotes - they push themselves onto the stack
281                    Err(ParseError::UnexpectedToken(
282                        "Strings cannot be quoted - they are data by default".to_string(),
283                    ))
284                }
285                Some(token) if matches!(token.kind, TokenKind::Number(_)) => {
286                    // Numbers don't need quotes - they push themselves onto the stack
287                    Err(ParseError::UnexpectedToken(
288                        "Numbers cannot be quoted - they are data by default".to_string(),
289                    ))
290                }
291                Some(token) if matches!(token.kind, TokenKind::Integer(_)) => {
292                    Err(ParseError::UnexpectedToken(
293                        "Numbers cannot be quoted - they are data by default".to_string(),
294                    ))
295                }
296                Some(token) if matches!(token.kind, TokenKind::BigInt(_)) => {
297                    Err(ParseError::UnexpectedToken(
298                        "Numbers cannot be quoted - they are data by default".to_string(),
299                    ))
300                }
301                Some(token) if matches!(token.kind, TokenKind::Rational(_, _)) => {
302                    Err(ParseError::UnexpectedToken(
303                        "Numbers cannot be quoted - they are data by default".to_string(),
304                    ))
305                }
306                #[cfg(feature = "complex_numbers")]
307                Some(token) if matches!(token.kind, TokenKind::GaussianInt(_, _)) => {
308                    Err(ParseError::UnexpectedToken(
309                        "Numbers cannot be quoted - they are data by default".to_string(),
310                    ))
311                }
312                #[cfg(feature = "complex_numbers")]
313                Some(token) if matches!(token.kind, TokenKind::Complex(_, _)) => {
314                    Err(ParseError::UnexpectedToken(
315                        "Numbers cannot be quoted - they are data by default".to_string(),
316                    ))
317                }
318                Some(token) if matches!(token.kind, TokenKind::Boolean(_)) => {
319                    // Booleans don't need quotes - they are data by default
320                    Err(ParseError::UnexpectedToken(
321                        "Booleans cannot be quoted - they are data by default".to_string(),
322                    ))
323                }
324                Some(token) if matches!(token.kind, TokenKind::Null) => {
325                    // Null doesn't need quotes - it is data by default
326                    Err(ParseError::UnexpectedToken(
327                        "Null cannot be quoted - it is data by default".to_string(),
328                    ))
329                }
330                _ => {
331                    // Quote without anything following, or followed by invalid token
332                    Err(ParseError::UnexpectedEndOfInput)
333                }
334            }
335        }
336
337        Some(token) if matches!(token.kind, TokenKind::Pipe) => {
338            // RUST CONCEPT: Error handling
339            // A pipe by itself is invalid - it should only appear in [a | b] notation
340            Err(ParseError::InvalidPipeNotation)
341        }
342
343        Some(token) if matches!(token.kind, TokenKind::RightBracket) => {
344            // RUST CONCEPT: Error types
345            // A closing bracket without a matching opening bracket is an error
346            Err(ParseError::MismatchedBrackets)
347        }
348
349        // RUST CONCEPT: None pattern
350        // This handles the case where we've run out of tokens
351        None => Err(ParseError::UnexpectedEndOfInput),
352
353        // Catch-all for any remaining token types
354        Some(_) => Err(ParseError::UnexpectedToken("Unexpected token".to_string())),
355    }
356}
357
358// RUST CONCEPT: Complex parsing logic
359// This function handles the tricky case of parsing lists, which can be:
360// - [1 2 3] (proper list)
361// - [a . b] (cons pair)
362// - [] (empty list)
363fn parse_list(
364    tokens: &[Token],
365    index: &mut usize,
366    interp: &mut Interpreter,
367) -> Result<Value, ParseError> {
368    // RUST CONCEPT: Assertions and debugging
369    // debug_assert! is removed in release builds but helps catch bugs during development
370    // This ensures we're starting at a LeftBracket token
371    debug_assert!(
372        matches!(tokens.get(*index), Some(token) if matches!(token.kind, TokenKind::LeftBracket))
373    );
374
375    *index += 1; // Skip the opening bracket
376
377    // RUST CONCEPT: Vec for collecting elements
378    // We'll collect list elements here, then convert to cons cells at the end
379    let mut elements = Vec::new();
380
381    // RUST CONCEPT: Loop with pattern matching
382    // We loop until we find the closing bracket or run out of tokens
383    loop {
384        match tokens.get(*index) {
385            Some(token) if matches!(token.kind, TokenKind::RightBracket) => {
386                *index += 1; // Skip the closing bracket
387                break; // RUST CONCEPT: break exits the loop
388            }
389
390            Some(token) if matches!(token.kind, TokenKind::Pipe) => {
391                // RUST CONCEPT: Complex parsing - pipe notation [a | b]
392                // We need at least one element before the pipe, and exactly one after
393                if elements.is_empty() {
394                    return Err(ParseError::InvalidPipeNotation);
395                }
396
397                *index += 1; // Skip the pipe
398
399                // Parse the element after the pipe (the "tail" of the cons cell)
400                let tail = parse_value(tokens, index, interp)?;
401
402                // RUST CONCEPT: Expecting specific tokens
403                // After [a | b], we MUST see a closing bracket
404                match tokens.get(*index) {
405                    Some(token) if matches!(token.kind, TokenKind::RightBracket) => {
406                        *index += 1; // Skip the closing bracket
407
408                        // RUST CONCEPT: Building cons cells manually
409                        // [a b c | d] becomes Pair(a, Pair(b, Pair(c, d)))
410                        // We build this right-to-left using fold
411                        let cons_cell = elements
412                            .into_iter()
413                            .rev() // RUST CONCEPT: Iterator adaptors - reverse the order
414                            .fold(tail, |acc, elem| {
415                                // RUST CONCEPT: Closures (anonymous functions)
416                                // |acc, elem| is the closure parameter list
417                                // We build Pair(elem, acc) for each element
418                                Value::Pair(Rc::new(elem), Rc::new(acc))
419                            });
420
421                        return Ok(cons_cell);
422                    }
423                    _ => return Err(ParseError::MismatchedBrackets),
424                }
425            }
426
427            None => {
428                // RUST CONCEPT: Error cases
429                // We ran out of tokens while looking for the closing bracket
430                return Err(ParseError::UnexpectedEndOfInput);
431            }
432
433            _ => {
434                // RUST CONCEPT: Recursive parsing continues
435                // Parse the next element and add it to our list
436                let element = parse_value(tokens, index, interp)?;
437                elements.push(element);
438            }
439        }
440    }
441
442    // RUST CONCEPT: Converting Vec to linked list
443    // If we get here, we have a proper list [1 2 3] without pipe notation
444    // Convert the Vec<Value> to a linked list of Pair nodes ending in Nil
445    let list = elements
446        .into_iter()
447        .rev() // Reverse so we build right-to-left
448        .fold(Value::Nil, |acc, elem| {
449            // RUST CONCEPT: Fold (reduce) operation
450            // This is like reduce in other languages
451            // We start with Nil and wrap each element: Pair(elem, previous_result)
452            Value::Pair(Rc::new(elem), Rc::new(acc))
453        });
454
455    Ok(list)
456}
457
458fn parse_array(
459    tokens: &[Token],
460    index: &mut usize,
461    interp: &mut Interpreter,
462) -> Result<Value, ParseError> {
463    debug_assert!(
464        matches!(tokens.get(*index), Some(token) if matches!(token.kind, TokenKind::ArrayLeftBracket))
465    );
466
467    *index += 1; // Skip the #[ token
468
469    let mut elements = Vec::new();
470
471    loop {
472        match tokens.get(*index) {
473            Some(token) if matches!(token.kind, TokenKind::RightBracket) => {
474                *index += 1;
475                break;
476            }
477            Some(token) if matches!(token.kind, TokenKind::Pipe) => {
478                return Err(ParseError::UnexpectedToken(
479                    "Arrays do not support pipe notation".to_string(),
480                ));
481            }
482            None => {
483                return Err(ParseError::UnexpectedEndOfInput);
484            }
485            _ => {
486                let element = parse_value(tokens, index, interp)?;
487                elements.push(element);
488            }
489        }
490    }
491
492    Ok(interp.make_array(elements))
493}
494
495// RUST CONCEPT: Conditional compilation and testing
496// #[cfg(test)] means this code only compiles when running tests
497// This keeps test code out of the release binary
498#[cfg(test)]
499mod tests {
500    use super::*; // RUST CONCEPT: Import everything from parent module
501
502    // Test-only helper method for ParseError
503    impl ParseError {
504        fn message(&self) -> String {
505            match self {
506                ParseError::UnexpectedToken(msg) => msg.clone(),
507                ParseError::UnexpectedEndOfInput => "Unexpected end of input".to_string(),
508                ParseError::MismatchedBrackets => "Mismatched brackets".to_string(),
509                ParseError::InvalidPipeNotation => "Invalid pipe notation".to_string(),
510                ParseError::InvalidNumber(msg) => msg.clone(),
511            }
512        }
513    }
514    use super::ParseError; // RUST CONCEPT: Explicit import to help compiler see usage
515
516    // RUST CONCEPT: Test functions
517    // #[test] tells Rust this function is a unit test
518    #[test]
519    fn test_parse_numbers() {
520        // RUST CONCEPT: Creating test data
521        // We need a mutable interpreter for atom interning
522        let mut interp = Interpreter::new();
523
524        // RUST CONCEPT: Unwrap for tests
525        // .unwrap() panics if Result is Err - fine for tests, bad for production
526        let result = parse("42", &mut interp).unwrap();
527
528        // RUST CONCEPT: Assertions
529        // assert_eq! compares two values and panics if they're different
530        assert_eq!(result.len(), 1);
531
532        // RUST CONCEPT: Pattern matching in tests
533        // We destructure the result to check it's the right type
534        // Small integers now use Int32
535        assert!(matches!(&result[0], Value::Int32(42)));
536
537        // Test multiple numbers - mix of integers and floats
538        let result = parse("1 2.5 -3", &mut interp).unwrap();
539        assert_eq!(result.len(), 3);
540
541        // Check mixed types
542        assert!(matches!(&result[0], Value::Int32(1)));
543        assert!(matches!(&result[1], Value::Number(n) if *n == 2.5));
544        assert!(matches!(&result[2], Value::Int32(-3)));
545    }
546
547    #[test]
548    fn test_parse_atoms() {
549        let mut interp = Interpreter::new();
550
551        let result = parse("hello world +", &mut interp).unwrap();
552        assert_eq!(result.len(), 3);
553
554        // RUST CONCEPT: String literals and references
555        // We check that atoms are properly interned
556        let expected_atoms = ["hello", "world", "+"];
557        for (i, expected) in expected_atoms.iter().enumerate() {
558            match &result[i] {
559                Value::Atom(atom) => {
560                    // RUST CONCEPT: Dereferencing Rc
561                    // &**atom dereferences the Rc then takes a reference to the str
562                    assert_eq!(&**atom, *expected);
563                }
564                _ => panic!("Expected atom at position {}", i),
565            }
566        }
567
568        // RUST CONCEPT: Testing interning behavior
569        // Same atoms should share the same Rc (pointer equality)
570        let result2 = parse("hello", &mut interp).unwrap();
571        if let (Value::Atom(atom1), Value::Atom(atom2)) = (&result[0], &result2[0]) {
572            assert!(Rc::ptr_eq(atom1, atom2)); // Same pointer = successful interning
573        }
574    }
575
576    #[test]
577    fn test_parse_strings() {
578        let mut interp = Interpreter::new();
579
580        let result = parse("\"hello world\" \"\"", &mut interp).unwrap();
581        assert_eq!(result.len(), 2);
582
583        match &result[0] {
584            Value::String(s) => assert_eq!(&**s, "hello world"),
585            _ => panic!("Expected string"),
586        }
587
588        match &result[1] {
589            Value::String(s) => assert_eq!(&**s, ""), // Empty string
590            _ => panic!("Expected empty string"),
591        }
592
593        // RUST CONCEPT: Testing non-interning
594        // Strings with same content should NOT share pointers
595        let result2 = parse("\"hello world\"", &mut interp).unwrap();
596        if let (Value::String(s1), Value::String(s2)) = (&result[0], &result2[0]) {
597            assert_eq!(s1, s2); // Same content
598            assert!(!Rc::ptr_eq(s1, s2)); // Different pointers = not interned
599        }
600    }
601
602    #[test]
603    fn test_parse_empty_list() {
604        let mut interp = Interpreter::new();
605
606        let result = parse("[]", &mut interp).unwrap();
607        assert_eq!(result.len(), 1);
608
609        // RUST CONCEPT: Matching specific enum variants
610        match &result[0] {
611            Value::Nil => (), // () is the unit value - like void but it's a real value
612            _ => panic!("Expected empty list (Nil)"),
613        }
614    }
615
616    #[test]
617    fn test_parse_simple_list() {
618        let mut interp = Interpreter::new();
619
620        let result = parse("[1 2 3]", &mut interp).unwrap();
621        assert_eq!(result.len(), 1);
622
623        // RUST CONCEPT: Nested pattern matching
624        // We can destructure complex nested structures in one match
625        match &result[0] {
626            Value::Pair(car1, cdr1) => {
627                // First element should be 1
628                assert!(matches!(**car1, Value::Int32(1)));
629
630                match cdr1.as_ref() {
631                    // RUST CONCEPT: as_ref() converts &Rc<T> to &T
632                    Value::Pair(car2, cdr2) => {
633                        // Second element should be 2
634                        assert!(matches!(**car2, Value::Int32(2)));
635
636                        match cdr2.as_ref() {
637                            Value::Pair(car3, cdr3) => {
638                                // Third element should be 3
639                                assert!(matches!(**car3, Value::Int32(3)));
640                                // End should be Nil
641                                assert!(matches!(**cdr3, Value::Nil));
642                            }
643                            _ => panic!("Expected third pair"),
644                        }
645                    }
646                    _ => panic!("Expected second pair"),
647                }
648            }
649            _ => panic!("Expected list pair"),
650        }
651    }
652
653    #[test]
654    fn test_parse_array_literal() {
655        let mut interp = Interpreter::new();
656
657        let result = parse("#[1 2 3]", &mut interp).unwrap();
658        assert_eq!(result.len(), 1);
659
660        match &result[0] {
661            Value::Array(array_rc) => {
662                let array = array_rc.borrow();
663                assert_eq!(array.len(), 3);
664                assert!(matches!(array[0], Value::Int32(1)));
665                assert!(matches!(array[1], Value::Int32(2)));
666                assert!(matches!(array[2], Value::Int32(3)));
667            }
668            _ => panic!("Expected array value"),
669        }
670    }
671
672    #[test]
673    fn test_parse_array_disallows_pipe() {
674        let mut interp = Interpreter::new();
675
676        let result = parse("#[1 | 2]", &mut interp);
677        assert!(matches!(
678            result,
679            Err(ParseError::UnexpectedToken(msg)) if msg.contains("Arrays do not support pipe notation")
680        ));
681    }
682
683    #[test]
684    fn test_parse_pipe_notation() {
685        let mut interp = Interpreter::new();
686
687        // Test [1 | 2] - a simple cons cell
688        let result = parse("[1 | 2]", &mut interp).unwrap();
689        assert_eq!(result.len(), 1);
690
691        match &result[0] {
692            Value::Pair(car, cdr) => {
693                assert!(matches!(**car, Value::Int32(1)));
694                assert!(matches!(**cdr, Value::Int32(2)));
695            }
696            _ => panic!("Expected pair"),
697        }
698
699        // Test [1 2 | 3] - multiple elements before pipe
700        let result = parse("[1 2 | 3]", &mut interp).unwrap();
701        match &result[0] {
702            Value::Pair(car1, cdr1) => {
703                assert!(matches!(**car1, Value::Int32(1)));
704                match cdr1.as_ref() {
705                    Value::Pair(car2, cdr2) => {
706                        assert!(matches!(**car2, Value::Int32(2)));
707                        assert!(matches!(**cdr2, Value::Int32(3)));
708                    }
709                    _ => panic!("Expected nested pair"),
710                }
711            }
712            _ => panic!("Expected pair"),
713        }
714    }
715
716    #[test]
717    fn test_parse_quoted_values() {
718        let mut interp = Interpreter::new();
719
720        let result = parse("'hello", &mut interp).unwrap();
721        assert_eq!(result.len(), 1);
722
723        // RUST CONCEPT: Testing QuotedAtom parsing
724        // A quoted atom becomes QuotedAtom directly
725        match &result[0] {
726            Value::QuotedAtom(atom) => {
727                assert_eq!(&**atom, "hello");
728            }
729            _ => panic!("Expected QuotedAtom"),
730        }
731    }
732
733    #[test]
734    fn test_parse_nested_lists() {
735        let mut interp = Interpreter::new();
736
737        let result = parse("[[1 2] [3]]", &mut interp).unwrap();
738        assert_eq!(result.len(), 1);
739
740        // RUST CONCEPT: Testing complex data structures
741        // This tests that we can parse nested lists correctly
742        match &result[0] {
743            Value::Pair(first_list, cdr) => {
744                // First list should be [1 2]
745                match first_list.as_ref() {
746                    Value::Pair(one, rest1) => {
747                        assert!(matches!(**one, Value::Int32(1)));
748                        match rest1.as_ref() {
749                            Value::Pair(two, rest2) => {
750                                assert!(matches!(**two, Value::Int32(2)));
751                                assert!(matches!(**rest2, Value::Nil));
752                            }
753                            _ => panic!("Expected [1 2] structure"),
754                        }
755                    }
756                    _ => panic!("Expected first list"),
757                }
758
759                // Rest should be ([3])
760                match cdr.as_ref() {
761                    Value::Pair(second_list, final_cdr) => {
762                        // Second list should be [3]
763                        match second_list.as_ref() {
764                            Value::Pair(three, rest3) => {
765                                assert!(matches!(**three, Value::Int32(3)));
766                                assert!(matches!(**rest3, Value::Nil));
767                            }
768                            _ => panic!("Expected [3] structure"),
769                        }
770                        assert!(matches!(**final_cdr, Value::Nil));
771                    }
772                    _ => panic!("Expected second list pair"),
773                }
774            }
775            _ => panic!("Expected outer list"),
776        }
777    }
778
779    #[test]
780    fn test_parse_errors() {
781        let mut interp = Interpreter::new();
782
783        // RUST CONCEPT: Testing error cases
784        // We use assert!(result.is_err()) to verify we get errors for bad input
785
786        // Mismatched brackets
787        assert!(parse("[1 2", &mut interp).is_err());
788        assert!(parse("1 2]", &mut interp).is_err());
789
790        // Invalid pipe notation
791        assert!(parse("[|]", &mut interp).is_err());
792        assert!(parse("[1 | 2 3]", &mut interp).is_err()); // Too many elements after pipe
793
794        // Standalone pipe
795        assert!(parse("1 | 2", &mut interp).is_err());
796    }
797
798    #[test]
799    fn test_parse_with_comments() {
800        let mut interp = Interpreter::new();
801
802        // RUST CONCEPT: Testing integration
803        // Comments should be stripped by tokenizer, so parser never sees them
804        let result = parse("42 \\ this is a comment\n37", &mut interp).unwrap();
805        assert_eq!(result.len(), 2);
806
807        match (&result[0], &result[1]) {
808            (Value::Int32(42), Value::Int32(37)) => {
809                // Values match expected
810            }
811            _ => panic!("Expected two Int32 values: 42 and 37"),
812        }
813    }
814
815    #[test]
816    fn test_parse_quoted_atoms_only() {
817        let mut interp = Interpreter::new();
818
819        // RUST CONCEPT: Testing valid quote syntax - only atoms can be quoted
820        let result = parse("'hello", &mut interp).unwrap();
821        assert_eq!(result.len(), 1);
822
823        // Should be QuotedAtom("hello")
824        match &result[0] {
825            Value::QuotedAtom(atom) => {
826                assert_eq!(&**atom, "hello");
827            }
828            _ => panic!("Expected QuotedAtom"),
829        }
830
831        // Test multiple quoted atoms
832        let result = parse("'+ '- '*", &mut interp).unwrap();
833        assert_eq!(result.len(), 3);
834
835        for (i, op) in ["+", "-", "*"].iter().enumerate() {
836            match &result[i] {
837                Value::QuotedAtom(atom) => {
838                    assert_eq!(&**atom, *op);
839                }
840                _ => panic!("Expected QuotedAtom at {}", i),
841            }
842        }
843    }
844
845    #[test]
846    fn test_parse_reject_quoted_non_atoms() {
847        let mut interp = Interpreter::new();
848
849        // RUST CONCEPT: Testing syntax restrictions
850        // These should all be rejected because only atoms can be quoted
851
852        // Quoted lists should be rejected
853        assert!(parse("'[1 2 3]", &mut interp).is_err());
854        assert!(parse("'[]", &mut interp).is_err());
855        assert!(parse("'[[nested]]", &mut interp).is_err());
856
857        // Quoted strings should be rejected
858        assert!(parse("'\"hello\"", &mut interp).is_err());
859        assert!(parse("'\"\"", &mut interp).is_err());
860
861        // Quoted float numbers should be rejected (integers become atoms and CAN be quoted)
862        assert!(parse("'3.14", &mut interp).is_err());
863        assert!(parse("'-17.5", &mut interp).is_err());
864        assert!(parse("'1e5", &mut interp).is_err());
865
866        // Verify the error messages are helpful
867        let result = parse("'[1 2]", &mut interp);
868        assert!(result.is_err());
869        let error_msg = format!("{:?}", result.unwrap_err());
870        assert!(error_msg.contains("Lists cannot be quoted"));
871
872        let result = parse("'\"string\"", &mut interp);
873        assert!(result.is_err());
874        let error_msg = format!("{:?}", result.unwrap_err());
875        assert!(error_msg.contains("Strings cannot be quoted"));
876
877        let result = parse("'3.14", &mut interp);
878        assert!(result.is_err());
879        let error_msg = format!("{:?}", result.unwrap_err());
880        assert!(error_msg.contains("Numbers cannot be quoted"));
881    }
882
883    #[test]
884    fn test_parse_mixed_types_in_list() {
885        let mut interp = Interpreter::new();
886
887        let result = parse("[42 hello \"world\" [nested]]", &mut interp).unwrap();
888        assert_eq!(result.len(), 1);
889
890        // RUST CONCEPT: Testing heterogeneous data structures
891        // Uni lists can contain any mix of types
892        match &result[0] {
893            Value::Pair(first, rest1) => {
894                assert!(matches!(first.as_ref(), Value::Int32(42)));
895
896                match rest1.as_ref() {
897                    Value::Pair(second, rest2) => {
898                        assert!(matches!(second.as_ref(), Value::Atom(a) if &**a == "hello"));
899
900                        match rest2.as_ref() {
901                            Value::Pair(third, rest3) => {
902                                assert!(
903                                    matches!(third.as_ref(), Value::String(s) if &**s == "world")
904                                );
905
906                                match rest3.as_ref() {
907                                    Value::Pair(fourth, rest4) => {
908                                        // Fourth should be a nested list
909                                        assert!(matches!(fourth.as_ref(), Value::Pair(_, _)));
910                                        assert!(matches!(rest4.as_ref(), Value::Nil));
911                                    }
912                                    _ => panic!("Expected fourth element"),
913                                }
914                            }
915                            _ => panic!("Expected third element"),
916                        }
917                    }
918                    _ => panic!("Expected second element"),
919                }
920            }
921            _ => panic!("Expected list"),
922        }
923    }
924
925    #[test]
926    fn test_parse_whitespace_handling() {
927        let mut interp = Interpreter::new();
928
929        // RUST CONCEPT: Testing tokenizer integration
930        // Various whitespace should be handled correctly
931        let inputs = [
932            "  1   2   3  ", // Extra spaces
933            "1\n2\t3\r\n4",  // Mixed whitespace
934            "[  1   2  ]",   // Spaces in lists
935            "[ 1 | 2 ]",     // Spaces around pipe
936            "'   hello   ",  // Spaces after quote
937        ];
938
939        let expected_lengths = [3, 4, 1, 1, 1];
940
941        for (input, expected_len) in inputs.iter().zip(expected_lengths.iter()) {
942            let result = parse(input, &mut interp).unwrap();
943            assert_eq!(result.len(), *expected_len, "Failed for input: '{}'", input);
944        }
945    }
946
947    #[test]
948    fn test_parse_deeply_nested_lists() {
949        let mut interp = Interpreter::new();
950
951        // RUST CONCEPT: Testing recursive parsing limits
952        // Deep nesting should work (until stack overflow)
953        let result = parse("[[[[1]]]]", &mut interp).unwrap();
954        assert_eq!(result.len(), 1);
955
956        // Navigate down the nested structure
957        let mut current = &result[0];
958        for _level in 0..4 {
959            match current {
960                Value::Pair(car, cdr) => {
961                    current = car.as_ref();
962                    assert!(matches!(cdr.as_ref(), Value::Nil));
963                }
964                Value::Number(n) if *n == 1.0 => break,
965                _ => panic!("Expected nested structure"),
966            }
967        }
968    }
969
970    #[test]
971    #[cfg(feature = "complex_numbers")]
972    fn test_parse_complex_pipe_cases() {
973        let mut interp = Interpreter::new();
974
975        // RUST CONCEPT: Testing edge cases thoroughly
976
977        // Multiple pipes should fail
978        assert!(parse("[1 | 2 | 3]", &mut interp).is_err());
979
980        // Pipe at beginning should fail
981        assert!(parse("[| 1]", &mut interp).is_err());
982
983        // Multiple elements after pipe should fail
984        assert!(parse("[1 | 2 3]", &mut interp).is_err());
985
986        // Pipe in nested list should work
987        let result = parse("[[1 | 2]]", &mut interp).unwrap();
988        match &result[0] {
989            Value::Pair(inner_list, outer_cdr) => {
990                match inner_list.as_ref() {
991                    Value::Pair(one, two) => {
992                        assert!(matches!(one.as_ref(), Value::Int32(1)));
993                        assert!(matches!(two.as_ref(), Value::Int32(2)));
994                    }
995                    _ => panic!("Expected inner pair"),
996                }
997                assert!(matches!(outer_cdr.as_ref(), Value::Nil));
998            }
999            _ => panic!("Expected outer list"),
1000        }
1001    }
1002
1003    #[test]
1004    fn test_parse_scientific_notation() {
1005        let mut interp = Interpreter::new();
1006
1007        // RUST CONCEPT: Testing tokenizer/parser integration
1008        // Scientific notation should parse as numbers
1009        let result = parse("1e5 2.5e-3 1E10", &mut interp).unwrap();
1010        assert_eq!(result.len(), 3);
1011
1012        let expected = [1e5, 2.5e-3, 1E10];
1013        for (i, expected_val) in expected.iter().enumerate() {
1014            match &result[i] {
1015                Value::Number(n) => assert_eq!(*n, *expected_val),
1016                _ => panic!("Expected number at position {}", i),
1017            }
1018        }
1019    }
1020
1021    #[test]
1022    fn test_parse_empty_input() {
1023        let mut interp = Interpreter::new();
1024
1025        // RUST CONCEPT: Testing boundary conditions
1026        let result = parse("", &mut interp).unwrap();
1027        assert_eq!(result.len(), 0);
1028
1029        let result = parse("   ", &mut interp).unwrap(); // Just whitespace
1030        assert_eq!(result.len(), 0);
1031
1032        let result = parse("\\ just a comment", &mut interp).unwrap();
1033        assert_eq!(result.len(), 0);
1034    }
1035
1036    #[test]
1037    fn test_parse_quote_edge_cases() {
1038        let mut interp = Interpreter::new();
1039
1040        // Quote without following value should fail
1041        assert!(parse("'", &mut interp).is_err());
1042
1043        // RUST CONCEPT: Testing syntax consistency
1044        // Nested quotes like ''hello don't make sense in Uni's execution model
1045        // Quote can only be followed by atoms, not other quote tokens
1046        assert!(parse("''hello", &mut interp).is_err());
1047
1048        // Quote followed by other non-atom tokens should also fail
1049        assert!(parse("'|", &mut interp).is_err());
1050        assert!(parse("']", &mut interp).is_err());
1051
1052        // But quotes followed by atoms should work perfectly
1053        let result = parse("'quote-me", &mut interp).unwrap();
1054        assert_eq!(result.len(), 1);
1055
1056        match &result[0] {
1057            Value::QuotedAtom(atom) => {
1058                assert_eq!(&**atom, "quote-me");
1059            }
1060            _ => panic!("Expected QuotedAtom"),
1061        }
1062    }
1063
1064    #[test]
1065    fn test_parse_error_messages() {
1066        let mut interp = Interpreter::new();
1067
1068        // RUST CONCEPT: Testing error types and messages
1069        let error_cases = [
1070            ("[1 2", "UnexpectedEndOfInput"),
1071            ("1 2]", "MismatchedBrackets"),
1072            ("[|]", "InvalidPipeNotation"),
1073            ("1 | 2", "InvalidPipeNotation"),
1074            ("'[1 2]", "Lists cannot be quoted"),
1075            ("'\"hello\"", "Strings cannot be quoted"),
1076            ("'42.0", "Numbers cannot be quoted"),  // Floats cannot be quoted
1077            ("'", "UnexpectedEndOfInput"), // Quote with nothing following
1078        ];
1079
1080        for (input, expected_error) in error_cases.iter() {
1081            let result = parse(input, &mut interp);
1082            assert!(result.is_err(), "Expected error for input: '{}'", input);
1083
1084            let error_string = format!("{:?}", result.unwrap_err());
1085            // Just check that we get the right error type
1086            assert!(
1087                error_string.contains(expected_error),
1088                "Expected '{}' in error message for '{}', got: {}",
1089                expected_error,
1090                input,
1091                error_string
1092            );
1093        }
1094    }
1095
1096    #[test]
1097    fn test_parse_booleans() {
1098        let mut interp = Interpreter::new();
1099
1100        // Test parsing true
1101        let result = parse("true", &mut interp).unwrap();
1102        assert_eq!(result.len(), 1);
1103        assert!(matches!(result[0], Value::Boolean(true)));
1104
1105        // Test parsing false
1106        let result = parse("false", &mut interp).unwrap();
1107        assert_eq!(result.len(), 1);
1108        assert!(matches!(result[0], Value::Boolean(false)));
1109
1110        // Test mixed with other values
1111        let result = parse("true 42 \"hello\" false", &mut interp).unwrap();
1112        assert_eq!(result.len(), 4);
1113        assert!(matches!(result[0], Value::Boolean(true)));
1114        assert!(matches!(result[1], Value::Int32(42))); // Small integers use Int32
1115        assert!(matches!(result[2], Value::String(_)));
1116        assert!(matches!(result[3], Value::Boolean(false)));
1117    }
1118
1119    #[test]
1120    fn test_parse_null() {
1121        let mut interp = Interpreter::new();
1122
1123        // Test parsing null
1124        let result = parse("null", &mut interp).unwrap();
1125        assert_eq!(result.len(), 1);
1126        assert!(matches!(result[0], Value::Null));
1127
1128        // Test mixed with other values
1129        let result = parse("null 42 true \"test\"", &mut interp).unwrap();
1130        assert_eq!(result.len(), 4);
1131        assert!(matches!(result[0], Value::Null));
1132        assert!(matches!(result[1], Value::Int32(42)));
1133        assert!(matches!(result[2], Value::Boolean(true)));
1134        assert!(matches!(result[3], Value::String(_)));
1135    }
1136
1137    #[test]
1138    fn test_parse_boolean_null_in_lists() {
1139        let mut interp = Interpreter::new();
1140
1141        // Test booleans in list
1142        let result = parse("[true false null 42]", &mut interp).unwrap();
1143        assert_eq!(result.len(), 1);
1144
1145        match &result[0] {
1146            Value::Pair(car1, cdr1) => {
1147                assert!(matches!(car1.as_ref(), Value::Boolean(true)));
1148                match cdr1.as_ref() {
1149                    Value::Pair(car2, cdr2) => {
1150                        assert!(matches!(car2.as_ref(), Value::Boolean(false)));
1151                        match cdr2.as_ref() {
1152                            Value::Pair(car3, cdr3) => {
1153                                assert!(matches!(car3.as_ref(), Value::Null));
1154                                match cdr3.as_ref() {
1155                                    Value::Pair(car4, cdr4) => {
1156                                        assert!(matches!(car4.as_ref(), Value::Int32(42)));
1157                                        assert!(matches!(cdr4.as_ref(), Value::Nil));
1158                                    }
1159                                    _ => panic!("Expected fourth element"),
1160                                }
1161                            }
1162                            _ => panic!("Expected third element"),
1163                        }
1164                    }
1165                    _ => panic!("Expected second element"),
1166                }
1167            }
1168            _ => panic!("Expected list structure"),
1169        }
1170    }
1171
1172    #[test]
1173    fn test_parse_quoted_booleans_null_error() {
1174        let mut interp = Interpreter::new();
1175
1176        // Quoted booleans should be errors - booleans are data by default
1177        let error_cases = vec![
1178            ("'true", "cannot be quoted"),
1179            ("'false", "cannot be quoted"),
1180            ("'null", "cannot be quoted"),
1181        ];
1182
1183        for (input, expected_error) in error_cases.iter() {
1184            let result = parse(input, &mut interp);
1185            assert!(result.is_err(), "Expected error for input: '{}'", input);
1186
1187            let error_string = format!("{:?}", result.unwrap_err());
1188            assert!(
1189                error_string
1190                    .to_lowercase()
1191                    .contains(&expected_error.to_lowercase()),
1192                "Expected '{}' in error message for '{}', got: {}",
1193                expected_error,
1194                input,
1195                error_string
1196            );
1197        }
1198    }
1199
1200    #[test]
1201    fn test_boolean_null_not_atoms() {
1202        let mut interp = Interpreter::new();
1203
1204        // Explicitly verify that true/false/null are NOT parsed as atoms
1205        let result = parse("true false null", &mut interp).unwrap();
1206        assert_eq!(result.len(), 3);
1207
1208        // These should NOT be atoms - they should be their proper types
1209        assert!(
1210            matches!(result[0], Value::Boolean(true)),
1211            "Expected Boolean(true), got: {:?}",
1212            result[0]
1213        );
1214        assert!(
1215            !matches!(result[0], Value::Atom(_)),
1216            "true should NOT be parsed as an atom"
1217        );
1218
1219        assert!(
1220            matches!(result[1], Value::Boolean(false)),
1221            "Expected Boolean(false), got: {:?}",
1222            result[1]
1223        );
1224        assert!(
1225            !matches!(result[1], Value::Atom(_)),
1226            "false should NOT be parsed as an atom"
1227        );
1228
1229        assert!(
1230            matches!(result[2], Value::Null),
1231            "Expected Null, got: {:?}",
1232            result[2]
1233        );
1234        assert!(
1235            !matches!(result[2], Value::Atom(_)),
1236            "null should NOT be parsed as an atom"
1237        );
1238
1239        // Verify similar-looking strings ARE still atoms
1240        let result = parse("TRUE True false-flag NULL nil", &mut interp).unwrap();
1241        assert_eq!(result.len(), 5);
1242
1243        for (i, val) in result.iter().enumerate() {
1244            assert!(
1245                matches!(val, Value::Atom(_)),
1246                "Element {} should be an atom, got: {:?}",
1247                i,
1248                val
1249            );
1250        }
1251    }
1252
1253    #[test]
1254    fn test_parse_error_message_method() {
1255        let mut interp = Interpreter::new();
1256
1257        // Test custom error message for UnexpectedToken
1258        let error = ParseError::UnexpectedToken("Custom error message".to_string());
1259        assert_eq!(error.message(), "Custom error message");
1260
1261        // Test other error types have sensible messages
1262        assert_eq!(
1263            ParseError::UnexpectedEndOfInput.message(),
1264            "Unexpected end of input"
1265        );
1266        assert_eq!(
1267            ParseError::MismatchedBrackets.message(),
1268            "Mismatched brackets"
1269        );
1270        assert_eq!(
1271            ParseError::InvalidPipeNotation.message(),
1272            "Invalid pipe notation"
1273        );
1274
1275        // Test that error messages are accessible from parse results
1276        let result = parse("'", &mut interp);
1277        assert!(result.is_err());
1278        if let Err(error) = result {
1279            let message = error.message();
1280            assert!(!message.is_empty());
1281        }
1282    }
1283
1284    // ========== TESTS FOR NEW NUMBER TYPES ==========
1285
1286    #[test]
1287    fn test_parse_bigint_literals() {
1288        use num_bigint::BigInt;
1289        let mut interp = Interpreter::new();
1290
1291        // Test simple BigInt
1292        let result = parse("123n", &mut interp).unwrap();
1293        assert_eq!(result.len(), 1);
1294        assert!(matches!(result[0], Value::Integer(ref i) if *i == BigInt::from(123)));
1295
1296        // Test negative BigInt
1297        let result = parse("-456n", &mut interp).unwrap();
1298        assert_eq!(result.len(), 1);
1299        assert!(matches!(result[0], Value::Integer(ref i) if *i == BigInt::from(-456)));
1300
1301        // Test large BigInt
1302        let result = parse("123456789012345678901234567890n", &mut interp).unwrap();
1303        assert_eq!(result.len(), 1);
1304        let expected = BigInt::parse_bytes(b"123456789012345678901234567890", 10).unwrap();
1305        assert!(matches!(result[0], Value::Integer(ref i) if *i == expected));
1306
1307        // Test zero BigInt
1308        let result = parse("0n", &mut interp).unwrap();
1309        assert_eq!(result.len(), 1);
1310        assert!(matches!(result[0], Value::Integer(ref i) if *i == BigInt::from(0)));
1311    }
1312
1313    #[test]
1314    fn test_parse_rational_literals() {
1315        use num_bigint::BigInt;
1316        use num_rational::BigRational;
1317        let mut interp = Interpreter::new();
1318
1319        // Test simple fraction
1320        let result = parse("3/4", &mut interp).unwrap();
1321        assert_eq!(result.len(), 1);
1322        let expected = BigRational::new(BigInt::from(3), BigInt::from(4));
1323        assert!(matches!(result[0], Value::Rational(ref r) if *r == expected));
1324
1325        // Test 1/2
1326        let result = parse("1/2", &mut interp).unwrap();
1327        assert_eq!(result.len(), 1);
1328        let expected = BigRational::new(BigInt::from(1), BigInt::from(2));
1329        assert!(matches!(result[0], Value::Rational(ref r) if *r == expected));
1330
1331        // Test negative numerator
1332        let result = parse("-5/8", &mut interp).unwrap();
1333        assert_eq!(result.len(), 1);
1334        let expected = BigRational::new(BigInt::from(-5), BigInt::from(8));
1335        assert!(matches!(result[0], Value::Rational(ref r) if *r == expected));
1336    }
1337
1338    #[test]
1339    #[cfg(feature = "complex_numbers")]
1340    fn test_parse_gaussian_and_complex_literals() {
1341        use num_bigint::BigInt;
1342        use num_complex::Complex64;
1343        let mut interp = Interpreter::new();
1344
1345        // Test standard complex number (integers -> GaussianInt)
1346        let result = parse("3+4i", &mut interp).unwrap();
1347        assert_eq!(result.len(), 1);
1348        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1349            if re == &BigInt::from(3) && im == &BigInt::from(4)));
1350
1351        // Test negative imaginary (integers -> GaussianInt)
1352        let result = parse("5-2i", &mut interp).unwrap();
1353        assert_eq!(result.len(), 1);
1354        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1355            if re == &BigInt::from(5) && im == &BigInt::from(-2)));
1356
1357        // Test pure imaginary (integer -> GaussianInt)
1358        let result = parse("5i", &mut interp).unwrap();
1359        assert_eq!(result.len(), 1);
1360        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1361            if re == &BigInt::from(0) && im == &BigInt::from(5)));
1362
1363        // Test with negative real part (integers -> GaussianInt)
1364        let result = parse("-3+4i", &mut interp).unwrap();
1365        assert_eq!(result.len(), 1);
1366        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1367            if re == &BigInt::from(-3) && im == &BigInt::from(4)));
1368
1369        // Test with decimal parts (decimals -> Complex64)
1370        let result = parse("1.5+2.5i", &mut interp).unwrap();
1371        assert_eq!(result.len(), 1);
1372        assert!(matches!(result[0], Value::Complex(c) if c == Complex64::new(1.5, 2.5)));
1373    }
1374
1375    #[test]
1376    fn test_parse_mixed_number_types() {
1377        use num_bigint::BigInt;
1378        use num_rational::BigRational;
1379        let mut interp = Interpreter::new();
1380
1381        // Test parsing multiple different number types
1382        #[cfg(feature = "complex_numbers")]
1383        {
1384            let result = parse("42 123n 3/4 2+3i", &mut interp).unwrap();
1385            assert_eq!(result.len(), 4);
1386
1387            assert!(matches!(result[0], Value::Int32(42)));
1388            assert!(matches!(result[1], Value::Integer(ref i) if *i == BigInt::from(123)));
1389            assert!(matches!(result[2], Value::Rational(ref r) if *r == BigRational::new(BigInt::from(3), BigInt::from(4))));
1390            assert!(matches!(result[3], Value::GaussianInt(ref re, ref im)
1391                if re == &BigInt::from(2) && im == &BigInt::from(3)));
1392        }
1393
1394        #[cfg(not(feature = "complex_numbers"))]
1395        {
1396            let result = parse("42 123n 3/4", &mut interp).unwrap();
1397            assert_eq!(result.len(), 3);
1398
1399            assert!(matches!(result[0], Value::Int32(42)));
1400            assert!(matches!(result[1], Value::Integer(ref i) if *i == BigInt::from(123)));
1401            assert!(matches!(result[2], Value::Rational(ref r) if *r == BigRational::new(BigInt::from(3), BigInt::from(4))));
1402        }
1403    }
1404
1405    #[test]
1406    fn test_parse_number_types_in_lists() {
1407        use num_bigint::BigInt;
1408        let mut interp = Interpreter::new();
1409
1410        // Test BigInt in list
1411        let result = parse("[1 2n 3]", &mut interp).unwrap();
1412        assert_eq!(result.len(), 1);
1413
1414        // Verify it's a list with proper elements
1415        match &result[0] {
1416            Value::Pair(_, _) => {
1417                // List created correctly
1418            }
1419            _ => panic!("Expected list"),
1420        }
1421
1422        // Test GaussianInt in list (integers -> GaussianInt)
1423        #[cfg(feature = "complex_numbers")]
1424        {
1425            let result = parse("[1+2i 3+4i]", &mut interp).unwrap();
1426            assert_eq!(result.len(), 1);
1427            match &result[0] {
1428                Value::Pair(car, cdr) => {
1429                    assert!(matches!(**car, Value::GaussianInt(ref re, ref im)
1430                        if re == &BigInt::from(1) && im == &BigInt::from(2)));
1431                    match cdr.as_ref() {
1432                        Value::Pair(car2, _) => {
1433                            assert!(matches!(**car2, Value::GaussianInt(ref re, ref im)
1434                                if re == &BigInt::from(3) && im == &BigInt::from(4)));
1435                        }
1436                        _ => panic!("Expected second element"),
1437                    }
1438                }
1439                _ => panic!("Expected list"),
1440            }
1441        }
1442    }
1443
1444    // ========== COMPLEX NUMBER PARSING EDGE CASES ==========
1445
1446    #[test]
1447    #[cfg(feature = "complex_numbers")]
1448    fn test_parse_complex_negative_imaginary() {
1449        use num_bigint::BigInt;
1450        let mut interp = Interpreter::new();
1451
1452        // Test with negative imaginary part: 3-4i (integers -> GaussianInt)
1453        let result = parse("3-4i", &mut interp).unwrap();
1454        assert_eq!(result.len(), 1);
1455        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1456            if re == &BigInt::from(3) && im == &BigInt::from(-4)));
1457
1458        // Test with both negative: -3-4i (integers -> GaussianInt)
1459        let result = parse("-3-4i", &mut interp).unwrap();
1460        assert_eq!(result.len(), 1);
1461        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1462            if re == &BigInt::from(-3) && im == &BigInt::from(-4)));
1463    }
1464
1465    #[test]
1466    #[cfg(feature = "complex_numbers")]
1467    fn test_parse_complex_zero_parts() {
1468        use num_bigint::BigInt;
1469        let mut interp = Interpreter::new();
1470
1471        // Test 0+5i (zero real part) - integers -> GaussianInt
1472        let result = parse("0+5i", &mut interp).unwrap();
1473        assert_eq!(result.len(), 1);
1474        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1475            if re == &BigInt::from(0) && im == &BigInt::from(5)));
1476
1477        // Test 5+0i (zero imaginary part) - integers -> GaussianInt
1478        let result = parse("5+0i", &mut interp).unwrap();
1479        assert_eq!(result.len(), 1);
1480        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1481            if re == &BigInt::from(5) && im == &BigInt::from(0)));
1482
1483        // Test 0+0i (both zero) - integers -> GaussianInt
1484        let result = parse("0+0i", &mut interp).unwrap();
1485        assert_eq!(result.len(), 1);
1486        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1487            if re == &BigInt::from(0) && im == &BigInt::from(0)));
1488    }
1489
1490    #[test]
1491    #[cfg(feature = "complex_numbers")]
1492    fn test_parse_complex_decimal_parts() {
1493        use num_complex::Complex64;
1494        let mut interp = Interpreter::new();
1495
1496        // Test decimals in both parts
1497        let result = parse("1.5+2.5i", &mut interp).unwrap();
1498        assert_eq!(result.len(), 1);
1499        assert!(matches!(result[0], Value::Complex(c) if c == Complex64::new(1.5, 2.5)));
1500
1501        // Test decimal in real only
1502        let result = parse("3.14+2i", &mut interp).unwrap();
1503        assert_eq!(result.len(), 1);
1504        assert!(matches!(result[0], Value::Complex(c) if c == Complex64::new(3.14, 2.0)));
1505
1506        // Test decimal in imaginary only
1507        let result = parse("2+3.14i", &mut interp).unwrap();
1508        assert_eq!(result.len(), 1);
1509        assert!(matches!(result[0], Value::Complex(c) if c == Complex64::new(2.0, 3.14)));
1510
1511        // Test very small decimals
1512        let result = parse("0.1+0.2i", &mut interp).unwrap();
1513        assert_eq!(result.len(), 1);
1514        assert!(matches!(result[0], Value::Complex(c) if (c.re - 0.1).abs() < 0.0001 && (c.im - 0.2).abs() < 0.0001));
1515    }
1516
1517    #[test]
1518    #[cfg(feature = "complex_numbers")]
1519    fn test_parse_complex_pure_imaginary_edge_cases() {
1520        use num_bigint::BigInt;
1521        use num_complex::Complex64;
1522        let mut interp = Interpreter::new();
1523
1524        // Test simple pure imaginary (integer -> GaussianInt)
1525        let result = parse("5i", &mut interp).unwrap();
1526        assert_eq!(result.len(), 1);
1527        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1528            if re == &BigInt::from(0) && im == &BigInt::from(5)));
1529
1530        // Test negative pure imaginary (integer -> GaussianInt)
1531        let result = parse("-5i", &mut interp).unwrap();
1532        assert_eq!(result.len(), 1);
1533        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1534            if re == &BigInt::from(0) && im == &BigInt::from(-5)));
1535
1536        // Test decimal pure imaginary (decimal -> Complex64)
1537        let result = parse("3.5i", &mut interp).unwrap();
1538        assert_eq!(result.len(), 1);
1539        assert!(matches!(result[0], Value::Complex(c) if c == Complex64::new(0.0, 3.5)));
1540
1541        // Test zero pure imaginary (integer -> GaussianInt)
1542        let result = parse("0i", &mut interp).unwrap();
1543        assert_eq!(result.len(), 1);
1544        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1545            if re == &BigInt::from(0) && im == &BigInt::from(0)));
1546    }
1547
1548    #[test]
1549    #[cfg(feature = "complex_numbers")]
1550    fn test_parse_complex_large_numbers() {
1551        use num_bigint::BigInt;
1552        let mut interp = Interpreter::new();
1553
1554        // Test large integer values (integers -> GaussianInt)
1555        let result = parse("1000000+2000000i", &mut interp).unwrap();
1556        assert_eq!(result.len(), 1);
1557        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1558            if re == &BigInt::from(1000000) && im == &BigInt::from(2000000)));
1559
1560        // Test very large decimals (decimals -> Complex64)
1561        let result = parse("123456.789+987654.321i", &mut interp).unwrap();
1562        assert_eq!(result.len(), 1);
1563        match &result[0] {
1564            Value::Complex(c) => {
1565                assert!((c.re - 123456.789).abs() < 0.001);
1566                assert!((c.im - 987654.321).abs() < 0.001);
1567            }
1568            _ => panic!("Expected complex"),
1569        }
1570    }
1571
1572    #[test]
1573    #[cfg(feature = "complex_numbers")]
1574    fn test_parse_complex_with_spaces_fails() {
1575        let mut interp = Interpreter::new();
1576
1577        // In postfix, "3 + 4i" should parse as three separate tokens
1578        // (not a complex number)
1579        let result = parse("3 + 4i", &mut interp).unwrap();
1580        assert_eq!(result.len(), 3); // Three separate values
1581
1582        // Only "3+4i" (no spaces) should be a complex number (GaussianInt since both integers)
1583        let result = parse("3+4i", &mut interp).unwrap();
1584        assert_eq!(result.len(), 1);
1585        assert!(matches!(result[0], Value::GaussianInt(_, _)));
1586    }
1587
1588    #[test]
1589    #[cfg(feature = "complex_numbers")]
1590    fn test_parse_complex_not_confused_with_operators() {
1591        use num_bigint::BigInt;
1592        let mut interp = Interpreter::new();
1593
1594        // "3+4" is not complex (no 'i' suffix)
1595        // It should parse as two separate tokens in postfix
1596        let result = parse("3 4 +", &mut interp).unwrap();
1597        assert_eq!(result.len(), 3);
1598
1599        // But "3+4i" IS complex (has 'i' suffix, integers -> GaussianInt)
1600        let result = parse("3+4i", &mut interp).unwrap();
1601        assert_eq!(result.len(), 1);
1602        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1603            if re == &BigInt::from(3) && im == &BigInt::from(4)));
1604    }
1605
1606    #[test]
1607    #[cfg(feature = "complex_numbers")]
1608    fn test_parse_complex_multiple_signs() {
1609        use num_bigint::BigInt;
1610        let mut interp = Interpreter::new();
1611
1612        // Test multiple complex numbers in sequence (all integers -> GaussianInt)
1613        let result = parse("1+2i 3-4i -5+6i -7-8i", &mut interp).unwrap();
1614        assert_eq!(result.len(), 4);
1615
1616        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1617            if re == &BigInt::from(1) && im == &BigInt::from(2)));
1618        assert!(matches!(result[1], Value::GaussianInt(ref re, ref im)
1619            if re == &BigInt::from(3) && im == &BigInt::from(-4)));
1620        assert!(matches!(result[2], Value::GaussianInt(ref re, ref im)
1621            if re == &BigInt::from(-5) && im == &BigInt::from(6)));
1622        assert!(matches!(result[3], Value::GaussianInt(ref re, ref im)
1623            if re == &BigInt::from(-7) && im == &BigInt::from(-8)));
1624    }
1625
1626    #[test]
1627    #[cfg(feature = "complex_numbers")]
1628    fn test_parse_complex_scientific_notation() {
1629        use num_complex::Complex64;
1630        let mut interp = Interpreter::new();
1631
1632        // Test scientific notation in complex numbers (positive exponents only)
1633        let result = parse("1e2+3e1i", &mut interp).unwrap();
1634        assert_eq!(result.len(), 1);
1635        assert!(matches!(result[0], Value::Complex(c) if c == Complex64::new(100.0, 30.0)));
1636
1637        // Note: Scientific notation with negative exponents (e.g., "1e-2+3e-1i")
1638        // is not supported because the '-' is ambiguous with complex number syntax.
1639        // For such cases, use decimals instead: "0.01+0.3i"
1640    }
1641
1642    #[test]
1643    fn test_parse_rational_edge_cases() {
1644        use num_rational::BigRational;
1645        
1646        let mut interp = Interpreter::new();
1647
1648        // Test 1/1 (whole number as fraction) - should demote to Int32
1649        let result = parse("1/1", &mut interp).unwrap();
1650        assert_eq!(result.len(), 1);
1651        assert!(matches!(result[0], Value::Int32(1)));
1652
1653        // Test 0/1 (zero as fraction) - should demote to Int32(0)
1654        let result = parse("0/1", &mut interp).unwrap();
1655        assert_eq!(result.len(), 1);
1656        assert!(matches!(result[0], Value::Int32(0)));
1657
1658        // Test large numerator and denominator
1659        let result = parse("123456789/987654321", &mut interp).unwrap();
1660        assert_eq!(result.len(), 1);
1661        let expected = BigRational::new(BigInt::from(123456789), BigInt::from(987654321));
1662        assert!(matches!(result[0], Value::Rational(ref r) if *r == expected));
1663    }
1664
1665    #[test]
1666    fn test_parse_bigint_edge_cases() {
1667        use num_bigint::BigInt;
1668        use num_traits::Zero;
1669        let mut interp = Interpreter::new();
1670
1671        // Test 0n
1672        let result = parse("0n", &mut interp).unwrap();
1673        assert_eq!(result.len(), 1);
1674        assert!(matches!(result[0], Value::Integer(ref i) if i.is_zero()));
1675
1676        // Test 1n
1677        let result = parse("1n", &mut interp).unwrap();
1678        assert_eq!(result.len(), 1);
1679        assert!(matches!(result[0], Value::Integer(ref i) if *i == BigInt::from(1)));
1680
1681        // Test negative zero: -0n
1682        let result = parse("-0n", &mut interp).unwrap();
1683        assert_eq!(result.len(), 1);
1684        assert!(matches!(result[0], Value::Integer(ref i) if i.is_zero()));
1685    }
1686
1687    #[test]
1688    fn test_parse_integer_vs_float_literals() {
1689        
1690        let mut interp = Interpreter::new();
1691
1692        // Integers (no decimal point) - small integers use Int32
1693        let result = parse("1", &mut interp).unwrap();
1694        assert_eq!(result.len(), 1);
1695        assert!(matches!(result[0], Value::Int32(1)));
1696
1697        let result = parse("42", &mut interp).unwrap();
1698        assert_eq!(result.len(), 1);
1699        assert!(matches!(result[0], Value::Int32(42)));
1700
1701        let result = parse("-5", &mut interp).unwrap();
1702        assert_eq!(result.len(), 1);
1703        assert!(matches!(result[0], Value::Int32(-5)));
1704
1705        let result = parse("0", &mut interp).unwrap();
1706        assert_eq!(result.len(), 1);
1707        assert!(matches!(result[0], Value::Int32(0)));
1708
1709        // Floats (with decimal point)
1710        let result = parse("1.0", &mut interp).unwrap();
1711        assert_eq!(result.len(), 1);
1712        assert!(matches!(result[0], Value::Number(n) if n == 1.0));
1713
1714        let result = parse("42.0", &mut interp).unwrap();
1715        assert_eq!(result.len(), 1);
1716        assert!(matches!(result[0], Value::Number(n) if n == 42.0));
1717
1718        let result = parse("-5.0", &mut interp).unwrap();
1719        assert_eq!(result.len(), 1);
1720        assert!(matches!(result[0], Value::Number(n) if n == -5.0));
1721
1722        let result = parse("3.14", &mut interp).unwrap();
1723        assert_eq!(result.len(), 1);
1724        assert!(matches!(result[0], Value::Number(n) if n == 3.14));
1725
1726        // Scientific notation (always float)
1727        let result = parse("1e10", &mut interp).unwrap();
1728        assert_eq!(result.len(), 1);
1729        assert!(matches!(result[0], Value::Number(n) if n == 1e10));
1730
1731        let result = parse("1.5e-3", &mut interp).unwrap();
1732        assert_eq!(result.len(), 1);
1733        assert!(matches!(result[0], Value::Number(n) if n == 1.5e-3));
1734    }
1735
1736    #[test]
1737    #[cfg(feature = "complex_numbers")]
1738    fn test_parse_complex_integer_vs_float() {
1739        use num_bigint::BigInt;
1740        use num_complex::Complex64;
1741        let mut interp = Interpreter::new();
1742
1743        // Integer complex (gaussian)
1744        let result = parse("1+2i", &mut interp).unwrap();
1745        assert_eq!(result.len(), 1);
1746        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1747            if re == &BigInt::from(1) && im == &BigInt::from(2)));
1748
1749        let result = parse("3-4i", &mut interp).unwrap();
1750        assert_eq!(result.len(), 1);
1751        assert!(matches!(result[0], Value::GaussianInt(ref re, ref im)
1752            if re == &BigInt::from(3) && im == &BigInt::from(-4)));
1753
1754        // Float complex
1755        let result = parse("1.0+2.0i", &mut interp).unwrap();
1756        assert_eq!(result.len(), 1);
1757        assert!(matches!(result[0], Value::Complex(c) if c == Complex64::new(1.0, 2.0)));
1758
1759        let result = parse("3.0-4.0i", &mut interp).unwrap();
1760        assert_eq!(result.len(), 1);
1761        assert!(matches!(result[0], Value::Complex(c) if c == Complex64::new(3.0, -4.0)));
1762
1763        // Mixed (one has decimal point means Complex)
1764        let result = parse("1.0+2i", &mut interp).unwrap();
1765        assert_eq!(result.len(), 1);
1766        assert!(matches!(result[0], Value::Complex(c) if c == Complex64::new(1.0, 2.0)));
1767
1768        let result = parse("1+2.0i", &mut interp).unwrap();
1769        assert_eq!(result.len(), 1);
1770        assert!(matches!(result[0], Value::Complex(c) if c == Complex64::new(1.0, 2.0)));
1771    }
1772}