feat: C backend module import support, Int/Float.toString, Test.assertEqualMsg
The C backend can now compile programs that import user-defined modules. Module-qualified calls like `mymodule.func(args)` are resolved to prefixed C functions (e.g., `mymodule_func_lux`), with full support for transitive imports and effect-passing. Also adds Int.toString/Float.toString to type system, interpreter, and C backend, and Test.assertEqualMsg for labeled test assertions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -95,6 +95,10 @@ pub enum BuiltinFn {
|
||||
StringLastIndexOf,
|
||||
StringRepeat,
|
||||
|
||||
// Int/Float operations
|
||||
IntToString,
|
||||
FloatToString,
|
||||
|
||||
// JSON operations
|
||||
JsonParse,
|
||||
JsonStringify,
|
||||
@@ -1071,6 +1075,18 @@ impl Interpreter {
|
||||
]));
|
||||
env.define("Math", math_module);
|
||||
|
||||
// Int module
|
||||
let int_module = Value::Record(HashMap::from([
|
||||
("toString".to_string(), Value::Builtin(BuiltinFn::IntToString)),
|
||||
]));
|
||||
env.define("Int", int_module);
|
||||
|
||||
// Float module
|
||||
let float_module = Value::Record(HashMap::from([
|
||||
("toString".to_string(), Value::Builtin(BuiltinFn::FloatToString)),
|
||||
]));
|
||||
env.define("Float", float_module);
|
||||
|
||||
// JSON module
|
||||
let json_module = Value::Record(HashMap::from([
|
||||
("parse".to_string(), Value::Builtin(BuiltinFn::JsonParse)),
|
||||
@@ -2251,6 +2267,26 @@ impl Interpreter {
|
||||
Ok(EvalResult::Value(Value::String(result)))
|
||||
}
|
||||
|
||||
BuiltinFn::IntToString => {
|
||||
if args.len() != 1 {
|
||||
return Err(err("Int.toString requires 1 argument"));
|
||||
}
|
||||
match &args[0] {
|
||||
Value::Int(n) => Ok(EvalResult::Value(Value::String(format!("{}", n)))),
|
||||
v => Ok(EvalResult::Value(Value::String(format!("{}", v)))),
|
||||
}
|
||||
}
|
||||
|
||||
BuiltinFn::FloatToString => {
|
||||
if args.len() != 1 {
|
||||
return Err(err("Float.toString requires 1 argument"));
|
||||
}
|
||||
match &args[0] {
|
||||
Value::Float(f) => Ok(EvalResult::Value(Value::String(format!("{}", f)))),
|
||||
v => Ok(EvalResult::Value(Value::String(format!("{}", v)))),
|
||||
}
|
||||
}
|
||||
|
||||
BuiltinFn::TypeOf => {
|
||||
if args.len() != 1 {
|
||||
return Err(err("typeOf requires 1 argument"));
|
||||
@@ -3856,6 +3892,26 @@ impl Interpreter {
|
||||
}
|
||||
Ok(Value::Unit)
|
||||
}
|
||||
("Test", "assertEqualMsg") => {
|
||||
let expected = request.args.first().cloned().unwrap_or(Value::Unit);
|
||||
let actual = request.args.get(1).cloned().unwrap_or(Value::Unit);
|
||||
let label = match request.args.get(2) {
|
||||
Some(Value::String(s)) => s.clone(),
|
||||
_ => "Values not equal".to_string(),
|
||||
};
|
||||
|
||||
if Value::values_equal(&expected, &actual) {
|
||||
self.test_results.borrow_mut().passed += 1;
|
||||
} else {
|
||||
self.test_results.borrow_mut().failed += 1;
|
||||
self.test_results.borrow_mut().failures.push(TestFailure {
|
||||
message: label,
|
||||
expected: Some(format!("{}", expected)),
|
||||
actual: Some(format!("{}", actual)),
|
||||
});
|
||||
}
|
||||
Ok(Value::Unit)
|
||||
}
|
||||
("Test", "assertNotEqual") => {
|
||||
let a = request.args.first().cloned().unwrap_or(Value::Unit);
|
||||
let b = request.args.get(1).cloned().unwrap_or(Value::Unit);
|
||||
|
||||
Reference in New Issue
Block a user