diff --git a/examples/pipeline_script_ticker.myc b/examples/pipeline_script_ticker.myc index 6eb2a42..5d510d2 100644 --- a/examples/pipeline_script_ticker.myc +++ b/examples/pipeline_script_ticker.myc @@ -1,10 +1,10 @@ -;; Benchmark: 2.0us -;; Benchmark-Repeat: 1015 +;; Benchmark: 3.0us +;; Benchmark-Repeat: 593 ;; Output: PipelineNode[last: Some(110.45243843391206)] (do ;; Set the random seed to match the existing test output exactly - (seed! 42) + (def random (make-random 42)) ;; Use our new generic create-ticker to pulse 3 times (def cnt 3) diff --git a/src/ast/environment.rs b/src/ast/environment.rs index 980eb08..7788df8 100644 --- a/src/ast/environment.rs +++ b/src/ast/environment.rs @@ -28,7 +28,6 @@ pub struct Environment { pub global_types: Rc>>, pub global_purity: Rc>>, pub global_values: Rc>>, - pub prng: Rc>, pub function_registry: Rc>>, pub typed_function_registry: Rc>>, pub monomorph_cache: Rc>, @@ -102,7 +101,6 @@ impl Environment { global_types: Rc::new(RefCell::new(HashMap::new())), global_purity: Rc::new(RefCell::new(HashMap::new())), global_values: Rc::new(RefCell::new(Vec::new())), - prng: Rc::new(RefCell::new(fastrand::Rng::new())), function_registry: Rc::new(RefCell::new(HashMap::new())), typed_function_registry: Rc::new(RefCell::new(HashMap::new())), monomorph_cache: Rc::new(RefCell::new(HashMap::new())), diff --git a/src/ast/rtl/math.rs b/src/ast/rtl/math.rs index 0efc319..d76e978 100644 --- a/src/ast/rtl/math.rs +++ b/src/ast/rtl/math.rs @@ -135,27 +135,39 @@ pub fn register(env: &Environment) { best }); - // Random - let random_ty = StaticType::Function(Box::new(Signature { + // 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)), + }, + ]); - let prng = env.prng.clone(); - env.register_native_fn("random", random_ty, Purity::SideEffectFree, move |_| { - Value::Float(prng.borrow_mut().f64()) - }); - - let seed_ty = StaticType::Function(Box::new(Signature { - params: StaticType::Tuple(vec![StaticType::Int]), - ret: StaticType::Void, - })); - - let prng_seed = env.prng.clone(); - env.register_native_fn("seed!", seed_ty, Purity::Impure, move |args| { - if let Value::Int(s) = args[0] { - prng_seed.borrow_mut().seed(s as u64); - } - Value::Void + 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, + })) }); } diff --git a/src/integration_test.rs b/src/integration_test.rs index 222a6cf..e9d751d 100644 --- a/src/integration_test.rs +++ b/src/integration_test.rs @@ -175,12 +175,13 @@ mod tests { let env1 = Environment::new(); let env2 = Environment::new(); - // 1. Seed env1 - env1.run_script("(seed! 123)").unwrap(); - let val1_a = env1.run_script("(random)").unwrap(); + // 1. Create a seeded generator in env1 + env1.run_script("(def rand (make-random 123))").unwrap(); + let val1_a = env1.run_script("(rand)").unwrap(); - // 2. env2 should have its own default seed state - let val2_a = env2.run_script("(random)").unwrap(); + // 2. env2 should have its own default seed state for its generators + env2.run_script("(def rand (make-random))").unwrap(); + let val2_a = env2.run_script("(rand)").unwrap(); // They are highly unlikely to be equal by default, // and seeding env1 MUST not have seeded env2. @@ -189,9 +190,9 @@ mod tests { "Environments must have isolated PRNG states" ); - // 3. Seed env2 differently - env2.run_script("(seed! 123)").unwrap(); - let val2_b = env2.run_script("(random)").unwrap(); + // 3. Create another generator in env2 with the same seed + env2.run_script("(def rand-same (make-random 123))").unwrap(); + let val2_b = env2.run_script("(rand-same)").unwrap(); // After same seeding, they should match (isolated but identical seed) assert_eq!( @@ -205,12 +206,12 @@ mod tests { let env = Environment::new(); // 1. First run with seed 42 - env.run_script("(seed! 42)").unwrap(); - let val1 = env.run_script("(random)").unwrap(); + env.run_script("(def rand1 (make-random 42))").unwrap(); + let val1 = env.run_script("(rand1)").unwrap(); // 2. Second run with same seed 42 - env.run_script("(seed! 42)").unwrap(); - let val2 = env.run_script("(random)").unwrap(); + env.run_script("(def rand2 (make-random 42))").unwrap(); + let val2 = env.run_script("(rand2)").unwrap(); assert_eq!( val1, val2, @@ -218,8 +219,8 @@ mod tests { ); // 3. Third run with different seed - env.run_script("(seed! 123)").unwrap(); - let val3 = env.run_script("(random)").unwrap(); + env.run_script("(def rand3 (make-random 123))").unwrap(); + let val3 = env.run_script("(rand3)").unwrap(); assert_ne!(val1, val3, "Random results must differ for different seeds"); }