The commit changes the interpreter and related code to use the new `BaeValue` and `Number` types, moving away from direct floats. The main changes include: - Replace LiteralValue with BaeValue across the codebase - Add Number enum for type-safe numeric values - Move AST definitions to common module - Update operators to handle new numeric types - Add 'is' token type and parser support Switch to common base_value library for value types This commit represents a significant refactoring to switch the interpreter to use a new shared base value type system. The main changes include: 1. Move value types to a new common/base_value.rs module 2. Add richer numeric type support with promotion rules 3. Update interpreter to use new BaseValue enum 4. Move AST types to common module for sharing 5. Consolidate value operations like Add, Sub etc 6. Add proper test coverage for numeric operations The commit improves type safety and adds more robust numeric handling while keeping the interpreter's core logic clean.
188 lines
5.0 KiB
Rust
188 lines
5.0 KiB
Rust
use rlox::common::base_value::{BaseValue, Number};
|
|
|
|
#[test]
|
|
fn test_number_addition_with_type_promotion() {
|
|
// Test float + int -> both become F64
|
|
let float_num = Number::F64(3.5);
|
|
let int_num = Number::I32(2);
|
|
let result = float_num.add(int_num);
|
|
match result {
|
|
Number::F64(val) => assert_eq!(val, 5.5),
|
|
_ => panic!("Expected F64 result from float + int"),
|
|
}
|
|
|
|
// Test int + unsigned -> both become I64
|
|
let int_num = Number::I32(-5);
|
|
let unsigned_num = Number::U32(10);
|
|
let result = int_num.add(unsigned_num);
|
|
match result {
|
|
Number::I64(val) => assert_eq!(val, 5),
|
|
_ => panic!("Expected I64 result from int + unsigned"),
|
|
}
|
|
|
|
// Test float + unsigned -> both become F64
|
|
let float_num = Number::F32(2.5);
|
|
let unsigned_num = Number::U64(3);
|
|
let result = float_num.add(unsigned_num);
|
|
match result {
|
|
Number::F64(val) => assert_eq!(val, 5.5),
|
|
_ => panic!("Expected F64 result from float + unsigned"),
|
|
}
|
|
|
|
// Test unsigned + unsigned -> both stay U128
|
|
let unsigned1 = Number::U32(100);
|
|
let unsigned2 = Number::U64(200);
|
|
let result = unsigned1.add(unsigned2);
|
|
match result {
|
|
Number::U128(val) => assert_eq!(val, 300),
|
|
_ => panic!("Expected U128 result from unsigned + unsigned"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_number_subtraction() {
|
|
let a = Number::F64(10.5);
|
|
let b = Number::I32(5);
|
|
let result = a.sub(b);
|
|
match result {
|
|
Number::F64(val) => assert_eq!(val, 5.5),
|
|
_ => panic!("Expected F64 result"),
|
|
}
|
|
|
|
let a = Number::I32(10);
|
|
let b = Number::U32(3);
|
|
let result = a.sub(b);
|
|
match result {
|
|
Number::I64(val) => assert_eq!(val, 7),
|
|
_ => panic!("Expected I64 result"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_number_multiplication() {
|
|
let a = Number::F64(2.5);
|
|
let b = Number::I32(4);
|
|
let result = a.mul(b);
|
|
match result {
|
|
Number::F64(val) => assert_eq!(val, 10.0),
|
|
_ => panic!("Expected F64 result"),
|
|
}
|
|
|
|
let a = Number::U32(5);
|
|
let b = Number::U32(6);
|
|
let result = a.mul(b);
|
|
match result {
|
|
Number::U128(val) => assert_eq!(val, 30),
|
|
_ => panic!("Expected U128 result"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_number_division() {
|
|
let a = Number::F64(10.0);
|
|
let b = Number::I32(4);
|
|
let result = a.div(b).unwrap();
|
|
match result {
|
|
Number::F64(val) => assert_eq!(val, 2.5),
|
|
_ => panic!("Expected F64 result"),
|
|
}
|
|
|
|
// Test division by zero
|
|
let a = Number::I32(10);
|
|
let b = Number::I32(0);
|
|
assert!(a.div(b).is_none());
|
|
|
|
let a = Number::F64(10.0);
|
|
let b = Number::F64(0.0);
|
|
assert!(a.div(b).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn test_number_remainder() {
|
|
let a = Number::I32(10);
|
|
let b = Number::I32(3);
|
|
let result = a.rem(b).unwrap();
|
|
match result {
|
|
Number::I64(val) => assert_eq!(val, 1),
|
|
_ => panic!("Expected I64 result"),
|
|
}
|
|
|
|
let a = Number::F64(10.5);
|
|
let b = Number::F64(3.0);
|
|
let result = a.rem(b).unwrap();
|
|
match result {
|
|
Number::F64(val) => assert_eq!(val, 1.5),
|
|
_ => panic!("Expected F64 result"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_number_negation() {
|
|
let num = Number::I32(5);
|
|
let result = num.neg();
|
|
match result {
|
|
Number::I32(val) => assert_eq!(val, -5),
|
|
_ => panic!("Expected I32 result"),
|
|
}
|
|
|
|
let num = Number::U32(5);
|
|
let result = num.neg();
|
|
match result {
|
|
Number::I64(val) => assert_eq!(val, -5),
|
|
_ => panic!("Expected I64 result for negated unsigned"),
|
|
}
|
|
|
|
let num = Number::F64(3.5);
|
|
let result = num.neg();
|
|
match result {
|
|
Number::F64(val) => assert_eq!(val, -3.5),
|
|
_ => panic!("Expected F64 result"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_number_comparison() {
|
|
let a = Number::I32(5);
|
|
let b = Number::F64(5.0);
|
|
assert_eq!(a.partial_cmp(&b), Some(std::cmp::Ordering::Equal));
|
|
|
|
let a = Number::I32(5);
|
|
let b = Number::F64(6.0);
|
|
assert_eq!(a.partial_cmp(&b), Some(std::cmp::Ordering::Less));
|
|
|
|
let a = Number::U32(10);
|
|
let b = Number::I32(5);
|
|
assert_eq!(a.partial_cmp(&b), Some(std::cmp::Ordering::Greater));
|
|
}
|
|
|
|
#[test]
|
|
fn test_baevalue_operations() {
|
|
// Test BaseValue addition
|
|
let a = BaseValue::Number(Number::I32(5));
|
|
let b = BaseValue::Number(Number::F64(3.5));
|
|
let result = (a + b).unwrap();
|
|
match result {
|
|
BaseValue::Number(Number::F64(val)) => assert_eq!(val, 8.5),
|
|
_ => panic!("Expected Number(F64) result"),
|
|
}
|
|
|
|
// Test string concatenation
|
|
let a = BaseValue::String("Hello ".to_string());
|
|
let b = BaseValue::String("World".to_string());
|
|
let result = (a + b).unwrap();
|
|
match result {
|
|
BaseValue::String(s) => assert_eq!(s, "Hello World"),
|
|
_ => panic!("Expected String result"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_is_zero() {
|
|
assert!(Number::I32(0).is_zero());
|
|
assert!(Number::F64(0.0).is_zero());
|
|
assert!(Number::U32(0).is_zero());
|
|
assert!(!Number::I32(1).is_zero());
|
|
assert!(!Number::F64(0.1).is_zero());
|
|
assert!(!Number::U32(1).is_zero());
|
|
}
|