use myc::ast::environment::Environment; use myc::ast::types::Value; #[test] fn test_dynamic_call_destructuring_underflow() { let env = Environment::new(); let source = "(do (def call-dynamic (fn [f data] (f data))) (def data [10 [20 30]]) (def x (fn [[a [b c]]] (+ a (+ b c)))) (call-dynamic x data))"; let result = env.run_script(source); if let Err(e) = &result { panic!("Failed: {}", e); } assert_eq!(format!("{}", result.unwrap()), "60"); } #[test] fn test_nested_destructuring_optimization() { let env = Environment::new(); let source_tuple = "((fn [[x y]] (+ x y)) [10 20])"; assert_eq!(format!("{}", env.run_script(source_tuple).unwrap()), "30"); let dump_tuple = env.dump_ast(source_tuple).unwrap(); assert!( dump_tuple.contains("Constant: 30"), "Nested tuple should be folded to 30. Dump:\n{}", dump_tuple ); } #[test] fn test_def_destructuring() { let env = Environment::new(); // 1. Global destructuring let source_global = "(do (def [a b] [1 2]) (+ a b))"; assert_eq!(format!("{}", env.run_script(source_global).unwrap()), "3"); // 2. Local nested destructuring inside a function let source_local = "((fn [x] (do (def [a [[b c] d]] x) (+ a (+ b (+ c d))))) [1 [[2 3] 4]])"; assert_eq!(format!("{}", env.run_script(source_local).unwrap()), "10"); // 3. Verify destructuring result manually let source_check = "(do (def [x y] [7 8]) [x y])"; let res = env.run_script(source_check).unwrap(); if let Value::Tuple(vals) = res { assert_eq!(vals.len(), 2); assert_eq!(format!("{}", vals[0]), "7"); assert_eq!(format!("{}", vals[1]), "8"); } else { panic!("Expected tuple from [x y], got {:?}", res); } } #[test] fn test_assign_destructuring() { // 1. Simple assignment destructuring { let env = Environment::new(); let source_simple = "(do (def a 0) (def b 0) (assign [a b] [10 20]) (+ a b))"; assert_eq!(format!("{}", env.run_script(source_simple).unwrap()), "30"); } // 2. Nested assignment destructuring { let env = Environment::new(); let source_nested = "(do (def a 0) (def b 0) (def c 0) (assign [a [b c]] [1 [2 3]]) (+ a (+ b c)))"; assert_eq!(format!("{}", env.run_script(source_nested).unwrap()), "6"); } // 3. Assignment value check { let env = Environment::new(); let source_return = "(do (def a 0) (def b 0) (assign [a b] [5 6]) [a b])"; let res = env.run_script(source_return).unwrap(); if let Value::Tuple(vals) = res { assert_eq!(vals.len(), 2); assert_eq!(format!("{}", vals[0]), "5"); assert_eq!(format!("{}", vals[1]), "6"); } else { panic!("Expected tuple from [a b], got {:?}", res); } } } #[test] fn test_multi_level_destructuring() { let env = Environment::new(); let source = "(do (def process_data (fn [conf] (do (def [str s] conf) (def [f ss] s) [\"Symbol:\" str \"field:\" f \"id:\" ss] ) ) ) (process_data [\"btc\" [:close \"cls\"]]))"; let res = env.run_script(source).unwrap(); assert_eq!( format!("{}", res), "[\"Symbol:\" \"btc\" \"field:\" :close \"id:\" \"cls\"]" ); } #[test] fn test_captured_slot_destructuring() { let env = Environment::new(); // A closure capturing both slots from a destructuring def must work correctly. let source = r#" (do (def [x y] [10 20]) (def get-sum (fn [] (+ x y))) (get-sum)) "#; assert_eq!(format!("{}", env.run_script(source).unwrap()), "30"); } #[test] fn test_destructuring_capture_mutation() { let env = Environment::new(); // A closure mutating a slot bound via destructuring must see the updated value. let source = r#" (do (def [a b] [1 2]) (def inc! (fn [] (assign a (+ a b)))) (inc!) (inc!) a) "#; // 1+2=3, 3+2=5 assert_eq!(format!("{}", env.run_script(source).unwrap()), "5"); }