Refactor: Replace Object with StreamStorage for streams
The `Object` trait is too generic and has been causing confusion. This commit introduces `StreamStorage` as a dedicated trait for reactive stream types. This change involves: - Renaming `Object` to `StreamStorage` in relevant places. - Updating the `Value::Object` enum variant to `Value::Stream`. - Modifying how streams are handled in the compiler, VM, and tests to use the new `StreamStorage` trait. - Adjusting example scripts and tests to reflect the change in type representation. - The `StreamNode` struct now explicitly holds its `element_type`.
This commit is contained in:
+53
-3
@@ -43,6 +43,56 @@ fn test_pipe_infers_lambda_params_from_tuple_inputs() {
|
||||
assert!(res.is_ok(), "Script failed: {:?}", res.err());
|
||||
}
|
||||
|
||||
/// Verifies that PipeHook::finalize replaces the `pipe` identifier with a
|
||||
/// pre-configured factory Constant — mirroring the SeriesHook pattern.
|
||||
/// FAILS before PipeHook is implemented (callee is still `Identifier: pipe`).
|
||||
#[test]
|
||||
fn test_pipe_callee_is_factory_after_finalize() {
|
||||
let env = Environment::new();
|
||||
let dump = env.dump_ast("(do
|
||||
(def ohlc (create-random-ohlc 42 5))
|
||||
(pipe ohlc (fn [bar] (.close bar)))
|
||||
)").expect("dump_ast failed");
|
||||
|
||||
assert!(
|
||||
!dump.contains("Identifier: pipe"),
|
||||
"PipeHook::finalize should replace `pipe` with a pre-configured factory Constant.\nDump:\n{dump}"
|
||||
);
|
||||
}
|
||||
|
||||
/// Field accessor on unknown field in pipe lambda must be a compile-time error.
|
||||
/// The lambda param is inferred as the concrete Record type (not Any),
|
||||
/// so the compiler can validate field names.
|
||||
#[test]
|
||||
fn test_pipe_field_typo_is_compile_error() {
|
||||
let env = Environment::new();
|
||||
let valid = "(do (def ohlc (create-random-ohlc 42 5)) (pipe ohlc (fn [bar] (.close bar))))";
|
||||
assert!(env.run_script(valid).is_ok(), "Valid pipe should compile");
|
||||
|
||||
let typo = "(do (def ohlc (create-random-ohlc 42 5)) (pipe ohlc (fn [bar] (.nonexistent bar))))";
|
||||
assert!(
|
||||
env.run_script(typo).is_err(),
|
||||
"Field typo in pipe lambda must be a compile error"
|
||||
);
|
||||
}
|
||||
|
||||
/// A chained pipe (output feeds another pipe) must preserve concrete Stream types.
|
||||
#[test]
|
||||
fn test_pipe_chain_preserves_concrete_types() {
|
||||
let env = Environment::new();
|
||||
let source = "(do
|
||||
(def ohlc (create-random-ohlc 42 5))
|
||||
(def closes (pipe ohlc (fn [bar] (.close bar))))
|
||||
(pipe closes (fn [c] (* c 2.0)))
|
||||
)";
|
||||
let dump = env.dump_ast(source).expect("dump_ast failed");
|
||||
assert!(
|
||||
dump.contains("Stream(Float)"),
|
||||
"Both pipe stages should yield Stream(Float).\nDump:\n{dump}"
|
||||
);
|
||||
assert!(env.run_script(source).is_ok(), "Chained pipe failed at runtime");
|
||||
}
|
||||
|
||||
/// Verifies that pipe with Optional return (filter pattern) still produces Stream(Float).
|
||||
#[test]
|
||||
fn test_pipeline_optional_type() {
|
||||
@@ -69,9 +119,9 @@ fn test_pipeline_optional_type() {
|
||||
}
|
||||
|
||||
let val = res.unwrap();
|
||||
if let Value::Object(obj) = val {
|
||||
assert_eq!(obj.type_name(), "StreamNode");
|
||||
if let Value::Stream(s) = val {
|
||||
assert_eq!(s.stream_type_name(), "stream");
|
||||
} else {
|
||||
panic!("Expected an Object(StreamNode)");
|
||||
panic!("Expected a Stream(StreamNode)");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user