fix(runtime::to_value): numbers are always NixFloat
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -146,17 +146,9 @@ 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 {
|
||||
// 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)),
|
||||
_ if val.is_null() => Value::Const(Const::Null),
|
||||
@@ -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)),
|
||||
|
||||
Reference in New Issue
Block a user