Add Stream support for field accessors

The type checker now correctly handles unwrapping `Stream(T)` types for
lambda arguments.
A new `build_map_stream` function has been added to `rtl/streams.rs` to
facilitate field access on streams.
The `create-random-ohlc` function now returns a `Stream` instead of a
`Series`.
Examples have been updated to reflect these changes and demonstrate
stream usage.
This commit is contained in:
Michael Schimmel
2026-03-07 20:47:05 +01:00
parent 2023df2f62
commit f88992da61
6 changed files with 105 additions and 28 deletions
+37 -18
View File
@@ -384,6 +384,12 @@ impl VM {
field.name()
));
}
} else if let Some(sn) = obj.as_any().downcast_ref::<crate::ast::rtl::streams::StreamNode>() {
let mapped = crate::ast::rtl::streams::build_map_stream(sn.inner.clone(), *field);
return Ok(Value::Object(Rc::new(mapped)));
} else if let Some(pn) = obj.as_any().downcast_ref::<crate::ast::rtl::streams::PipelineNode>() {
let mapped = crate::ast::rtl::streams::build_map_stream(pn.stream.clone(), *field);
return Ok(Value::Object(Rc::new(mapped)));
}
// Fallback if it's another type of object that is not a RecordSeries.
@@ -550,26 +556,33 @@ impl VM {
k,
);
return Ok(Value::Object(std::rc::Rc::new(view)));
} else {
} else {
return Err(format!(
"RecordSeries does not have field :{}",
k.name()
));
}
}
return Err(format!(
"Field accessor .{} expects a record or RecordSeries, got {}",
k.name(),
obj.type_name()
));
} else {
return Err(format!(
"Field accessor .{} expects a record or RecordSeries, got {}",
k.name(),
rec
));
}
}
}
} else if let Some(sn) = obj.as_any().downcast_ref::<crate::ast::rtl::streams::StreamNode>() {
let mapped = crate::ast::rtl::streams::build_map_stream(sn.inner.clone(), k);
return Ok(Value::Object(Rc::new(mapped)));
} else if let Some(pn) = obj.as_any().downcast_ref::<crate::ast::rtl::streams::PipelineNode>() {
let mapped = crate::ast::rtl::streams::build_map_stream(pn.stream.clone(), k);
return Ok(Value::Object(Rc::new(mapped)));
}
return Err(format!(
"Field accessor .{} expects a record, RecordSeries or Stream, got {}",
k.name(),
obj.type_name()
));
} else {
return Err(format!(
"Field accessor .{} expects a record, RecordSeries or Stream, got {}",
k.name(),
rec
));
}
}
_ => {
return Err(format!(
"Tail call target is not a function: {}",
@@ -621,16 +634,22 @@ impl VM {
k.name()
))
}
} else if let Some(sn) = obj.as_any().downcast_ref::<crate::ast::rtl::streams::StreamNode>() {
let mapped = crate::ast::rtl::streams::build_map_stream(sn.inner.clone(), *k);
Ok(Value::Object(Rc::new(mapped)))
} else if let Some(pn) = obj.as_any().downcast_ref::<crate::ast::rtl::streams::PipelineNode>() {
let mapped = crate::ast::rtl::streams::build_map_stream(pn.stream.clone(), *k);
Ok(Value::Object(Rc::new(mapped)))
} else {
Err(format!(
"Field accessor .{} expects a record or RecordSeries, got {}",
"Field accessor .{} expects a record, RecordSeries or Stream, got {}",
k.name(),
obj.type_name()
))
}
} else {
Err(format!(
"Field accessor .{} expects a record or RecordSeries, got {}",
"Field accessor .{} expects a record, RecordSeries or Stream, got {}",
k.name(),
rec
))