Skip to main content

shape_ast/ast/
literals.rs

1//! Literal types for Shape AST
2
3use rust_decimal::Decimal;
4use serde::{Deserialize, Serialize};
5
6use crate::data::Timeframe;
7use crate::int_width::IntWidth;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10pub enum InterpolationMode {
11    Braces,
12    Dollar,
13    Hash,
14}
15
16impl InterpolationMode {
17    pub fn prefix(self) -> &'static str {
18        match self {
19            InterpolationMode::Braces => "f",
20            InterpolationMode::Dollar => "f$",
21            InterpolationMode::Hash => "f#",
22        }
23    }
24
25    pub fn sigil(self) -> Option<char> {
26        match self {
27            InterpolationMode::Braces => None,
28            InterpolationMode::Dollar => Some('$'),
29            InterpolationMode::Hash => Some('#'),
30        }
31    }
32}
33
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
35pub enum Literal {
36    Int(i64),
37    /// Unsigned integer literal > i64::MAX (e.g., 18446744073709551615u64)
38    UInt(u64),
39    /// Explicitly width-typed integer literal (e.g., 42i8, 100u16)
40    TypedInt(i64, IntWidth),
41    Number(f64),
42    /// Decimal type for exact arithmetic (finance, currency)
43    Decimal(Decimal),
44    String(String),
45    /// Formatted string literal (`f"..."`, `f$"..."`, `f#"..."` + triple variants)
46    FormattedString {
47        value: String,
48        mode: InterpolationMode,
49    },
50    /// Content string literal (`c"..."`, `c$"..."`, `c#"..."` + triple variants)
51    ContentString {
52        value: String,
53        mode: InterpolationMode,
54    },
55    Bool(bool),
56    /// Option::None literal (replaces null)
57    None,
58    /// Unit literal `()`
59    Unit,
60    Timeframe(Timeframe),
61}
62
63impl std::fmt::Display for Literal {
64    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65        match self {
66            Literal::Int(i) => write!(f, "{}", i),
67            Literal::UInt(u) => write!(f, "{}u64", u),
68            Literal::TypedInt(v, w) => write!(f, "{}{}", v, w),
69            Literal::Number(n) => {
70                if n.fract() == 0.0 {
71                    write!(f, "{}", *n as i64)
72                } else {
73                    write!(f, "{}", n)
74                }
75            }
76            Literal::Decimal(d) => write!(f, "{}D", d),
77            Literal::String(s) => write!(f, "\"{}\"", s),
78            Literal::FormattedString { value, mode } => write!(f, "{}\"{}\"", mode.prefix(), value),
79            Literal::ContentString { value, mode } => {
80                let prefix = match mode {
81                    InterpolationMode::Braces => "c",
82                    InterpolationMode::Dollar => "c$",
83                    InterpolationMode::Hash => "c#",
84                };
85                write!(f, "{}\"{}\"", prefix, value)
86            }
87            Literal::Bool(b) => write!(f, "{}", b),
88            Literal::None => write!(f, "None"),
89            Literal::Unit => write!(f, "()"),
90            Literal::Timeframe(tf) => write!(f, "{}", tf),
91        }
92    }
93}
94
95impl Literal {
96    /// Convert literal to a JSON value
97    pub fn to_json_value(&self) -> serde_json::Value {
98        match self {
99            Literal::Int(i) => serde_json::json!(*i),
100            Literal::UInt(u) => serde_json::json!(*u),
101            Literal::TypedInt(v, _) => serde_json::json!(*v),
102            Literal::Number(n) => serde_json::json!(*n),
103            Literal::Decimal(d) => serde_json::json!(d.to_string()),
104            Literal::String(s) => serde_json::json!(s),
105            Literal::FormattedString { value, .. } => serde_json::json!(value),
106            Literal::ContentString { value, .. } => serde_json::json!(value),
107            Literal::Bool(b) => serde_json::json!(*b),
108            Literal::None => serde_json::Value::Null,
109            Literal::Unit => serde_json::Value::Null,
110            Literal::Timeframe(t) => serde_json::json!(t.to_string()),
111        }
112    }
113}
114
115#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
116pub struct Duration {
117    pub value: f64,
118    pub unit: DurationUnit,
119}
120
121#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
122pub enum DurationUnit {
123    Seconds,
124    Minutes,
125    Hours,
126    Days,
127    Weeks,
128    Months,
129    Years,
130    Samples,
131}