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:
+32
-4
@@ -1,6 +1,34 @@
|
|||||||
;; Output: 0
|
|
||||||
(do
|
(do
|
||||||
(def history (series :float))
|
(def SMA
|
||||||
(push history 0.0)
|
(fn [length]
|
||||||
(history 0)
|
(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
@@ -1,25 +1,24 @@
|
|||||||
(do
|
(do
|
||||||
(def SMA
|
(def SMA
|
||||||
(fn [length]
|
(fn [length]
|
||||||
(do
|
(do
|
||||||
(def history (series :float))
|
(def history (series :float))
|
||||||
(push history 0)
|
(push history 0)
|
||||||
|
|
||||||
(fn [val]
|
(fn [val]
|
||||||
(do
|
(do
|
||||||
(def sum (+ val (history 0)))
|
(def sum (+ val (history 0)))
|
||||||
(push history sum)
|
(push history sum)
|
||||||
(/ sum length)
|
(/ sum length)
|
||||||
(history 0)
|
))
|
||||||
))
|
)))
|
||||||
)))
|
|
||||||
|
(def sma20 (SMA 20))
|
||||||
(def sma20 (SMA 20))
|
|
||||||
|
(def n 100)
|
||||||
(def n 100)
|
(while (> n 0)
|
||||||
(while (> n 0)
|
(do
|
||||||
(do
|
(print "val=" n " sma20=" (sma20 n))
|
||||||
(print "val=" n " sma20=" (sma20 n))
|
(assign n (- n 1))
|
||||||
(assign n (- n 1))
|
))
|
||||||
))
|
|
||||||
)
|
)
|
||||||
@@ -218,19 +218,16 @@ pub trait SeriesMember: Object + Series {
|
|||||||
|
|
||||||
impl SeriesMember for ScalarSeries<f64> {
|
impl SeriesMember for ScalarSeries<f64> {
|
||||||
fn push_value(&self, value: Value, limit: Option<usize>) {
|
fn push_value(&self, value: Value, limit: Option<usize>) {
|
||||||
match value {
|
if let Some(v) = value.as_float() {
|
||||||
Value::Float(v) => self.data.borrow_mut().push(v, limit),
|
self.data.borrow_mut().push(v, limit);
|
||||||
Value::Int(v) => self.data.borrow_mut().push(v as f64, limit),
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SeriesMember for ScalarSeries<i64> {
|
impl SeriesMember for ScalarSeries<i64> {
|
||||||
fn push_value(&self, value: Value, limit: Option<usize>) {
|
fn push_value(&self, value: Value, limit: Option<usize>) {
|
||||||
match value {
|
if let Some(v) = value.as_int() {
|
||||||
Value::Int(v) | Value::DateTime(v) => self.data.borrow_mut().push(v, limit),
|
self.data.borrow_mut().push(v, limit);
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-1
@@ -394,6 +394,12 @@ impl StaticType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match (self, other) {
|
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
|
// Optional(T) is assignable from T or Void
|
||||||
(StaticType::Optional(inner), other) => {
|
(StaticType::Optional(inner), other) => {
|
||||||
matches!(other, StaticType::Void) || inner.is_assignable_from(other)
|
matches!(other, StaticType::Void) || inner.is_assignable_from(other)
|
||||||
@@ -471,7 +477,8 @@ impl StaticType {
|
|||||||
}
|
}
|
||||||
StaticType::FunctionOverloads(sigs) => sigs
|
StaticType::FunctionOverloads(sigs) => sigs
|
||||||
.iter()
|
.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()),
|
.map(|sig| sig.ret.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@@ -490,6 +497,23 @@ impl StaticType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
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 {
|
pub fn is_truthy(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Value::Void => false,
|
Value::Void => false,
|
||||||
|
|||||||
Reference in New Issue
Block a user