Formatting
This commit is contained in:
+176
-173
@@ -1,173 +1,176 @@
|
||||
use crate::ast::environment::Environment;
|
||||
use crate::ast::types::{Purity, Signature, StaticType, Value};
|
||||
use std::f64::consts;
|
||||
|
||||
pub fn register(env: &Environment) {
|
||||
// Constants
|
||||
env.register_constant("PI", StaticType::Float, Value::Float(consts::PI));
|
||||
env.register_constant("E", StaticType::Float, Value::Float(consts::E));
|
||||
|
||||
// Helper to get f64 from Value (Int or Float)
|
||||
fn to_f64(v: &Value) -> Option<f64> {
|
||||
match v {
|
||||
Value::Float(f) => Some(*f),
|
||||
Value::Int(i) => Some(*i as f64),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// Unary functions (float -> float)
|
||||
let register_unary = |name: &'static str, f: fn(f64) -> f64| {
|
||||
let ty = StaticType::Function(Box::new(Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Float]),
|
||||
ret: StaticType::Float,
|
||||
}));
|
||||
env.register_native_fn(name, ty, Purity::Pure, move |args| {
|
||||
if let Some(x) = to_f64(&args[0]) {
|
||||
Value::Float(f(x))
|
||||
} else {
|
||||
Value::Void
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Unary functions (float -> int)
|
||||
let register_to_int = |name: &'static str, f: fn(f64) -> f64| {
|
||||
let ty = StaticType::Function(Box::new(Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Float]),
|
||||
ret: StaticType::Int,
|
||||
}));
|
||||
env.register_native_fn(name, ty, Purity::Pure, move |args| {
|
||||
if let Some(x) = to_f64(&args[0]) {
|
||||
Value::Int(f(x) as i64)
|
||||
} else {
|
||||
Value::Void
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
register_unary("sqrt", f64::sqrt);
|
||||
register_unary("sin", f64::sin);
|
||||
register_unary("cos", f64::cos);
|
||||
register_unary("tan", f64::tan);
|
||||
register_unary("asin", f64::asin);
|
||||
register_unary("acos", f64::acos);
|
||||
register_unary("atan", f64::atan);
|
||||
register_unary("exp", f64::exp);
|
||||
register_unary("ln", f64::ln);
|
||||
register_unary("log10", f64::log10);
|
||||
register_unary("fract", f64::fract);
|
||||
|
||||
// Rounding functions returning Int
|
||||
register_to_int("round", f64::round);
|
||||
register_to_int("floor", f64::floor);
|
||||
register_to_int("ceil", f64::ceil);
|
||||
register_to_int("trunc", f64::trunc);
|
||||
|
||||
// Binary functions (float, float -> float)
|
||||
let register_binary = |name: &'static str, f: fn(f64, f64) -> f64| {
|
||||
let ty = StaticType::Function(Box::new(Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Float, StaticType::Float]),
|
||||
ret: StaticType::Float,
|
||||
}));
|
||||
env.register_native_fn(name, ty, Purity::Pure, move |args| {
|
||||
if let (Some(a), Some(b)) = (to_f64(&args[0]), to_f64(&args[1])) {
|
||||
Value::Float(f(a, b))
|
||||
} else {
|
||||
Value::Void
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
register_binary("atan2", f64::atan2);
|
||||
register_binary("pow", f64::powf);
|
||||
register_binary("log", f64::log);
|
||||
|
||||
// Specialized abs to handle Int -> Int, Float -> Float
|
||||
let abs_ty = StaticType::Function(Box::new(Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Any]),
|
||||
ret: StaticType::Any,
|
||||
}));
|
||||
env.register_native_fn("abs", abs_ty, Purity::Pure, |args| {
|
||||
if args.len() != 1 {
|
||||
return Value::Void;
|
||||
}
|
||||
match args[0] {
|
||||
Value::Int(i) => Value::Int(i.abs()),
|
||||
Value::Float(f) => Value::Float(f.abs()),
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// Variadic min / max
|
||||
let variadic_ty = StaticType::Function(Box::new(Signature {
|
||||
params: StaticType::Any,
|
||||
ret: StaticType::Any,
|
||||
}));
|
||||
|
||||
env.register_native_fn("min", variadic_ty.clone(), Purity::Pure, |args| {
|
||||
if args.is_empty() {
|
||||
return Value::Void;
|
||||
}
|
||||
let mut best = args[0].clone();
|
||||
for arg in &args[1..] {
|
||||
if let Some(ord) = arg.partial_cmp(&best)
|
||||
&& ord == std::cmp::Ordering::Less
|
||||
{
|
||||
best = arg.clone();
|
||||
}
|
||||
}
|
||||
best
|
||||
});
|
||||
|
||||
env.register_native_fn("max", variadic_ty, Purity::Pure, |args| {
|
||||
if args.is_empty() {
|
||||
return Value::Void;
|
||||
}
|
||||
let mut best = args[0].clone();
|
||||
for arg in &args[1..] {
|
||||
if let Some(ord) = arg.partial_cmp(&best)
|
||||
&& ord == std::cmp::Ordering::Greater
|
||||
{
|
||||
best = arg.clone();
|
||||
}
|
||||
}
|
||||
best
|
||||
});
|
||||
|
||||
// Random generator factory (Closure-based)
|
||||
let generator_sig = Signature {
|
||||
params: StaticType::Tuple(vec![]),
|
||||
ret: StaticType::Float,
|
||||
};
|
||||
|
||||
let make_random_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![]),
|
||||
ret: StaticType::Function(Box::new(generator_sig.clone())),
|
||||
},
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Int]),
|
||||
ret: StaticType::Function(Box::new(generator_sig)),
|
||||
},
|
||||
]);
|
||||
|
||||
env.register_native_fn("make-random", make_random_ty, Purity::SideEffectFree, |args| {
|
||||
let rng = if args.is_empty() {
|
||||
fastrand::Rng::new()
|
||||
} else if let Value::Int(s) = args[0] {
|
||||
fastrand::Rng::with_seed(s as u64)
|
||||
} else {
|
||||
fastrand::Rng::new()
|
||||
};
|
||||
|
||||
let prng = std::rc::Rc::new(std::cell::RefCell::new(rng));
|
||||
|
||||
Value::Function(std::rc::Rc::new(crate::ast::types::NativeFunction {
|
||||
func: std::rc::Rc::new(move |_| {
|
||||
Value::Float(prng.borrow_mut().f64())
|
||||
}),
|
||||
purity: Purity::Impure,
|
||||
}))
|
||||
});
|
||||
}
|
||||
use crate::ast::environment::Environment;
|
||||
use crate::ast::types::{Purity, Signature, StaticType, Value};
|
||||
use std::f64::consts;
|
||||
|
||||
pub fn register(env: &Environment) {
|
||||
// Constants
|
||||
env.register_constant("PI", StaticType::Float, Value::Float(consts::PI));
|
||||
env.register_constant("E", StaticType::Float, Value::Float(consts::E));
|
||||
|
||||
// Helper to get f64 from Value (Int or Float)
|
||||
fn to_f64(v: &Value) -> Option<f64> {
|
||||
match v {
|
||||
Value::Float(f) => Some(*f),
|
||||
Value::Int(i) => Some(*i as f64),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// Unary functions (float -> float)
|
||||
let register_unary = |name: &'static str, f: fn(f64) -> f64| {
|
||||
let ty = StaticType::Function(Box::new(Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Float]),
|
||||
ret: StaticType::Float,
|
||||
}));
|
||||
env.register_native_fn(name, ty, Purity::Pure, move |args| {
|
||||
if let Some(x) = to_f64(&args[0]) {
|
||||
Value::Float(f(x))
|
||||
} else {
|
||||
Value::Void
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Unary functions (float -> int)
|
||||
let register_to_int = |name: &'static str, f: fn(f64) -> f64| {
|
||||
let ty = StaticType::Function(Box::new(Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Float]),
|
||||
ret: StaticType::Int,
|
||||
}));
|
||||
env.register_native_fn(name, ty, Purity::Pure, move |args| {
|
||||
if let Some(x) = to_f64(&args[0]) {
|
||||
Value::Int(f(x) as i64)
|
||||
} else {
|
||||
Value::Void
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
register_unary("sqrt", f64::sqrt);
|
||||
register_unary("sin", f64::sin);
|
||||
register_unary("cos", f64::cos);
|
||||
register_unary("tan", f64::tan);
|
||||
register_unary("asin", f64::asin);
|
||||
register_unary("acos", f64::acos);
|
||||
register_unary("atan", f64::atan);
|
||||
register_unary("exp", f64::exp);
|
||||
register_unary("ln", f64::ln);
|
||||
register_unary("log10", f64::log10);
|
||||
register_unary("fract", f64::fract);
|
||||
|
||||
// Rounding functions returning Int
|
||||
register_to_int("round", f64::round);
|
||||
register_to_int("floor", f64::floor);
|
||||
register_to_int("ceil", f64::ceil);
|
||||
register_to_int("trunc", f64::trunc);
|
||||
|
||||
// Binary functions (float, float -> float)
|
||||
let register_binary = |name: &'static str, f: fn(f64, f64) -> f64| {
|
||||
let ty = StaticType::Function(Box::new(Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Float, StaticType::Float]),
|
||||
ret: StaticType::Float,
|
||||
}));
|
||||
env.register_native_fn(name, ty, Purity::Pure, move |args| {
|
||||
if let (Some(a), Some(b)) = (to_f64(&args[0]), to_f64(&args[1])) {
|
||||
Value::Float(f(a, b))
|
||||
} else {
|
||||
Value::Void
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
register_binary("atan2", f64::atan2);
|
||||
register_binary("pow", f64::powf);
|
||||
register_binary("log", f64::log);
|
||||
|
||||
// Specialized abs to handle Int -> Int, Float -> Float
|
||||
let abs_ty = StaticType::Function(Box::new(Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Any]),
|
||||
ret: StaticType::Any,
|
||||
}));
|
||||
env.register_native_fn("abs", abs_ty, Purity::Pure, |args| {
|
||||
if args.len() != 1 {
|
||||
return Value::Void;
|
||||
}
|
||||
match args[0] {
|
||||
Value::Int(i) => Value::Int(i.abs()),
|
||||
Value::Float(f) => Value::Float(f.abs()),
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// Variadic min / max
|
||||
let variadic_ty = StaticType::Function(Box::new(Signature {
|
||||
params: StaticType::Any,
|
||||
ret: StaticType::Any,
|
||||
}));
|
||||
|
||||
env.register_native_fn("min", variadic_ty.clone(), Purity::Pure, |args| {
|
||||
if args.is_empty() {
|
||||
return Value::Void;
|
||||
}
|
||||
let mut best = args[0].clone();
|
||||
for arg in &args[1..] {
|
||||
if let Some(ord) = arg.partial_cmp(&best)
|
||||
&& ord == std::cmp::Ordering::Less
|
||||
{
|
||||
best = arg.clone();
|
||||
}
|
||||
}
|
||||
best
|
||||
});
|
||||
|
||||
env.register_native_fn("max", variadic_ty, Purity::Pure, |args| {
|
||||
if args.is_empty() {
|
||||
return Value::Void;
|
||||
}
|
||||
let mut best = args[0].clone();
|
||||
for arg in &args[1..] {
|
||||
if let Some(ord) = arg.partial_cmp(&best)
|
||||
&& ord == std::cmp::Ordering::Greater
|
||||
{
|
||||
best = arg.clone();
|
||||
}
|
||||
}
|
||||
best
|
||||
});
|
||||
|
||||
// Random generator factory (Closure-based)
|
||||
let generator_sig = Signature {
|
||||
params: StaticType::Tuple(vec![]),
|
||||
ret: StaticType::Float,
|
||||
};
|
||||
|
||||
let make_random_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![]),
|
||||
ret: StaticType::Function(Box::new(generator_sig.clone())),
|
||||
},
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Int]),
|
||||
ret: StaticType::Function(Box::new(generator_sig)),
|
||||
},
|
||||
]);
|
||||
|
||||
env.register_native_fn(
|
||||
"make-random",
|
||||
make_random_ty,
|
||||
Purity::SideEffectFree,
|
||||
|args| {
|
||||
let rng = if args.is_empty() {
|
||||
fastrand::Rng::new()
|
||||
} else if let Value::Int(s) = args[0] {
|
||||
fastrand::Rng::with_seed(s as u64)
|
||||
} else {
|
||||
fastrand::Rng::new()
|
||||
};
|
||||
|
||||
let prng = std::rc::Rc::new(std::cell::RefCell::new(rng));
|
||||
|
||||
Value::Function(std::rc::Rc::new(crate::ast::types::NativeFunction {
|
||||
func: std::rc::Rc::new(move |_| Value::Float(prng.borrow_mut().f64())),
|
||||
purity: Purity::Impure,
|
||||
}))
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,4 +14,4 @@ pub fn register(env: &Environment) {
|
||||
math::register(env);
|
||||
series::register(env);
|
||||
streams::register(env);
|
||||
}
|
||||
}
|
||||
|
||||
+558
-530
File diff suppressed because it is too large
Load Diff
+641
-593
File diff suppressed because it is too large
Load Diff
@@ -202,7 +202,12 @@ mod tests {
|
||||
// Check static type
|
||||
let st = TypeRegistry::resolve_type::<Person>(®istry);
|
||||
if let StaticType::Record(layout) = st {
|
||||
assert!(layout.fields.iter().any(|(k, _)| *k == Keyword::intern("greet")));
|
||||
assert!(
|
||||
layout
|
||||
.fields
|
||||
.iter()
|
||||
.any(|(k, _)| *k == Keyword::intern("greet"))
|
||||
);
|
||||
} else {
|
||||
panic!("Expected Record type");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user