Fix: Improve series type handling and coercions

This commit enhances the series type handling in `src/ast/rtl/series.rs`
by introducing helper methods `as_float` and `as_int` in
`src/ast/types.rs` to manage type conversions more robustly.

It also updates the function overload resolution in `src/ast/types.rs`
to prioritize exact parameter matches before falling back to implicit
coercions.

Finally, the example `err.myc` has been updated to reflect a more
accurate implementation of a Simple Moving Average (SMA) calculation.
This commit is contained in:
Michael Schimmel
2026-03-06 16:31:50 +01:00
parent 7e3b000d99
commit 7b6f6e52bd
4 changed files with 83 additions and 35 deletions
+32 -4
View File
@@ -1,6 +1,34 @@
;; Output: 0
(do
(def history (series :float))
(push history 0.0)
(history 0)
(def SMA
(fn [length]
(do
(def history (series :float))
(def sum 0.0)
(fn [val]
(do
(def hist_len (len history))
(if (>= hist_len length)
(assign sum (- sum (history (- hist_len 1))))
...)
(push history val)
(assign sum (+ sum val))
(/ sum (len history))
)))))
(def sma10 (SMA 10))
(sma10 1)
(sma10 2)
(sma10 3)
(sma10 4)
(sma10 5)
(sma10 6)
(sma10 7)
(sma10 8)
(sma10 9)
(sma10 10)
(sma10 11)
)
+22 -23
View File
@@ -1,25 +1,24 @@
(do
(def SMA
(fn [length]
(do
(def history (series :float))
(push history 0)
(fn [val]
(do
(def sum (+ val (history 0)))
(push history sum)
(/ sum length)
(history 0)
))
)))
(def sma20 (SMA 20))
(def n 100)
(while (> n 0)
(do
(print "val=" n " sma20=" (sma20 n))
(assign n (- n 1))
))
(def SMA
(fn [length]
(do
(def history (series :float))
(push history 0)
(fn [val]
(do
(def sum (+ val (history 0)))
(push history sum)
(/ sum length)
))
)))
(def sma20 (SMA 20))
(def n 100)
(while (> n 0)
(do
(print "val=" n " sma20=" (sma20 n))
(assign n (- n 1))
))
)
+4 -7
View File
@@ -218,19 +218,16 @@ pub trait SeriesMember: Object + Series {
impl SeriesMember for ScalarSeries<f64> {
fn push_value(&self, value: Value, limit: Option<usize>) {
match value {
Value::Float(v) => self.data.borrow_mut().push(v, limit),
Value::Int(v) => self.data.borrow_mut().push(v as f64, limit),
_ => {}
if let Some(v) = value.as_float() {
self.data.borrow_mut().push(v, limit);
}
}
}
impl SeriesMember for ScalarSeries<i64> {
fn push_value(&self, value: Value, limit: Option<usize>) {
match value {
Value::Int(v) | Value::DateTime(v) => self.data.borrow_mut().push(v, limit),
_ => {}
if let Some(v) = value.as_int() {
self.data.borrow_mut().push(v, limit);
}
}
}
+25 -1
View File
@@ -394,6 +394,12 @@ impl StaticType {
}
match (self, other) {
// Implicit Coercions
(StaticType::Float, StaticType::Int) => true,
(StaticType::Int, StaticType::Bool) => true,
(StaticType::Int, StaticType::DateTime) => true,
(StaticType::DateTime, StaticType::Int) => true,
// Optional(T) is assignable from T or Void
(StaticType::Optional(inner), other) => {
matches!(other, StaticType::Void) || inner.is_assignable_from(other)
@@ -471,7 +477,8 @@ impl StaticType {
}
StaticType::FunctionOverloads(sigs) => sigs
.iter()
.find(|sig| sig.params.is_assignable_from(args_ty))
.find(|sig| sig.params == *args_ty) // 1. Try exact match first
.or_else(|| sigs.iter().find(|sig| sig.params.is_assignable_from(args_ty))) // 2. Fallback to implicit coercion
.map(|sig| sig.ret.clone()),
_ => None,
}
@@ -490,6 +497,23 @@ impl StaticType {
}
impl Value {
pub fn as_float(&self) -> Option<f64> {
match self {
Value::Float(f) => Some(*f),
Value::Int(i) => Some(*i as f64),
_ => None,
}
}
pub fn as_int(&self) -> Option<i64> {
match self {
Value::Int(i) => Some(*i),
Value::DateTime(d) => Some(*d),
Value::Bool(b) => Some(if *b { 1 } else { 0 }),
_ => None,
}
}
pub fn is_truthy(&self) -> bool {
match self {
Value::Void => false,