fix(runtime::to_value): numbers are always NixFloat

This commit is contained in:
2026-01-03 12:19:43 +08:00
parent add715f560
commit c79eb0951e
3 changed files with 14 additions and 25 deletions

1
.envrc
View File

@@ -1 +1,2 @@
use flake
dotenv

View File

@@ -1,6 +1,7 @@
use std::ptr::NonNull;
use hashbrown::HashMap;
use itertools::Itertools as _;
use string_interner::DefaultStringInterner;
use crate::codegen::{CodegenContext, Compile};
@@ -15,7 +16,7 @@ mod downgrade;
pub struct Context {
irs: Vec<Ir>,
symbols: DefaultStringInterner,
global: NonNull<HashMap<crate::ir::SymId, ExprId>>,
global: NonNull<HashMap<SymId, ExprId>>,
}
impl Drop for Context {
@@ -99,14 +100,7 @@ impl Context {
pub fn eval(&mut self, expr: &str) -> Result<Value> {
let root = rnix::Root::parse(expr);
if !root.errors().is_empty() {
return Err(Error::parse_error(root.errors().iter().fold(
String::new(),
|mut acc, err| {
acc.push_str(&err.to_string());
acc.push_str("; ");
acc
},
)));
return Err(Error::parse_error(root.errors().iter().join("; ")));
}
let root = self
.downgrade_ctx()
@@ -331,11 +325,9 @@ mod test {
#[test]
fn test_builtin_function_map() {
// Test higher-order builtin: builtins.map (x: x * 2) [1 2 3]
// Test higher-order builtin: map (x: x * 2) [1 2 3]
assert_eq!(
Context::new()
.eval("builtins.map (x: x * 2) [1 2 3]")
.unwrap(),
Context::new().eval("map (x: x * 2) [1 2 3]").unwrap(),
Value::List(List::new(vec![
Value::Const(Const::Int(2)),
Value::Const(Const::Int(4)),
@@ -628,6 +620,10 @@ mod test {
ctx.eval("builtins.typeOf 3.14").unwrap(),
Value::String("float".to_string())
);
// literal tests
assert_eq!(ctx.eval("1").unwrap(), Value::Const(Const::Int(1)));
assert_eq!(ctx.eval("1.").unwrap(), Value::Const(Const::Float(1.)))
}
#[test]

View File

@@ -146,16 +146,8 @@ fn to_value<'a, 'b>(val: v8::Local<'a, v8::Value>, ctx: &RuntimeContext<'a, 'b>)
}
_ if val.is_number() => {
let val = val.to_number(scope).unwrap().value();
// Heuristic: convert whole numbers to Int (for backward compatibility and JS interop)
if val.is_finite()
&& val.fract() == 0.0
&& val >= i64::MIN as f64
&& val <= i64::MAX as f64
{
Value::Const(Const::Int(val as i64))
} else {
Value::Const(Const::Float(val))
}
// number is always NixFloat
Value::Const(Const::Float(val))
}
_ if val.is_true() => Value::Const(Const::Bool(true)),
_ if val.is_false() => Value::Const(Const::Bool(false)),
@@ -280,13 +272,13 @@ fn primop_app_name<'a, 'b>(
fn to_value_working() {
assert_eq!(
run("({
test: [1, 9223372036854775807n, true, false, 'hello world!']
test: [1., 9223372036854775807n, true, false, 'hello world!']
})")
.unwrap(),
Value::AttrSet(AttrSet::new(std::collections::BTreeMap::from([(
Symbol::from("test"),
Value::List(List::new(vec![
Value::Const(Const::Int(1)),
Value::Const(Const::Float(1.)),
Value::Const(Const::Int(9223372036854775807)),
Value::Const(Const::Bool(true)),
Value::Const(Const::Bool(false)),