Introduce Value::Cell for mutable upvalues, allowing closures to
modify captured variables. Implement `capture_upvalue` and `get_value`/`set_value` methods in the `VM` to handle these mutable upvalues. Refactor number parsing to support integers and floats Separate the `TokenKind::Number` into `TokenKind::Integer` and `TokenKind::Float`. Update the lexer to distinguish between integer and float literals. Update the parser to correctly map these new token kinds to their respective `Value` types. Add integration tests for parsing integers and floats, and for closure modification of captured variables.
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::{Arc, Mutex};
|
||||
use crate::ast::parser::Parser;
|
||||
use crate::ast::compiler::binder::Binder;
|
||||
use crate::ast::vm::VM;
|
||||
use crate::ast::types::Value;
|
||||
|
||||
use crate::ast::nodes::UntypedKind;
|
||||
|
||||
#[test]
|
||||
fn test_parse_integer_constant() {
|
||||
let source = "123";
|
||||
let mut parser = Parser::new(source).expect("Failed to create parser");
|
||||
let ast = parser.parse_expression().expect("Failed to parse");
|
||||
|
||||
if let UntypedKind::Constant(Value::Int(val)) = ast.kind {
|
||||
assert_eq!(val, 123);
|
||||
} else {
|
||||
panic!("Expected Integer constant, got {:?}", ast.kind);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_negative_integer() {
|
||||
let source = "-42";
|
||||
let mut parser = Parser::new(source).expect("Failed to create parser");
|
||||
let ast = parser.parse_expression().expect("Failed to parse");
|
||||
|
||||
if let UntypedKind::Constant(Value::Int(val)) = ast.kind {
|
||||
assert_eq!(val, -42);
|
||||
} else {
|
||||
panic!("Expected Integer constant, got {:?}", ast.kind);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_float_constant() {
|
||||
let source = "123.45";
|
||||
let mut parser = Parser::new(source).expect("Failed to create parser");
|
||||
let ast = parser.parse_expression().expect("Failed to parse");
|
||||
|
||||
if let UntypedKind::Constant(Value::Float(val)) = ast.kind {
|
||||
assert_eq!(val, 123.45);
|
||||
} else {
|
||||
panic!("Expected Float constant, got {:?}", ast.kind);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_negative_float() {
|
||||
let source = "-10.5";
|
||||
let mut parser = Parser::new(source).expect("Failed to create parser");
|
||||
let ast = parser.parse_expression().expect("Failed to parse");
|
||||
|
||||
if let UntypedKind::Constant(Value::Float(val)) = ast.kind {
|
||||
assert_eq!(val, -10.5);
|
||||
} else {
|
||||
panic!("Expected Float constant, got {:?}", ast.kind);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_closure_modification_from_source() {
|
||||
let source = r#"
|
||||
(do
|
||||
(def x 10)
|
||||
(def f (fn [] (assign x 20)))
|
||||
(f)
|
||||
x
|
||||
)
|
||||
"#;
|
||||
|
||||
let mut parser = Parser::new(source).expect("Failed to create parser");
|
||||
let ast = parser.parse_expression().expect("Failed to parse");
|
||||
|
||||
let globals = Arc::new(Mutex::new(std::collections::HashMap::new()));
|
||||
let mut binder = Binder::new(globals.clone());
|
||||
let bound_ast = binder.bind(&ast).expect("Failed to bind");
|
||||
|
||||
let vm_globals = Arc::new(Mutex::new(Vec::new()));
|
||||
let mut vm = VM::new(vm_globals);
|
||||
let result = vm.run(&bound_ast);
|
||||
|
||||
match result {
|
||||
Ok(Value::Int(val)) => assert_eq!(val, 20, "Closure should modify outer variable"),
|
||||
Ok(val) => panic!("Expected Int(20), got {:?}", val),
|
||||
Err(e) => panic!("VM Error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user