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    /// Unicode scalar value char literal (`'a'`, `'\n'`, `'\u{1F600}'`)
46    Char(char),
47    /// Formatted string literal (`f"..."`, `f$"..."`, `f#"..."` + triple variants)
48    FormattedString {
49        value: String,
50        mode: InterpolationMode,
51    },
52    /// Content string literal (`c"..."`, `c$"..."`, `c#"..."` + triple variants)
53    ContentString {
54        value: String,
55        mode: InterpolationMode,
56    },
57    Bool(bool),
58    /// Option::None literal (replaces null)
59    None,
60    /// Unit literal `()`
61    Unit,
62    Timeframe(Timeframe),
63}
64
65impl std::fmt::Display for Literal {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        match self {
68            Literal::Int(i) => write!(f, "{}", i),
69            Literal::UInt(u) => write!(f, "{}u64", u),
70            Literal::TypedInt(v, w) => write!(f, "{}{}", v, w),
71            Literal::Number(n) => {
72                if n.fract() == 0.0 {
73                    write!(f, "{}", *n as i64)
74                } else {
75                    write!(f, "{}", n)
76                }
77            }
78            Literal::Decimal(d) => write!(f, "{}D", d),
79            Literal::String(s) => write!(f, "\"{}\"", s),
80            Literal::Char(c) => write!(f, "'{}'", c.escape_default()),
81            Literal::FormattedString { value, mode } => write!(f, "{}\"{}\"", mode.prefix(), value),
82            Literal::ContentString { value, mode } => {
83                let prefix = match mode {
84                    InterpolationMode::Braces => "c",
85                    InterpolationMode::Dollar => "c$",
86                    InterpolationMode::Hash => "c#",
87                };
88                write!(f, "{}\"{}\"", prefix, value)
89            }
90            Literal::Bool(b) => write!(f, "{}", b),
91            Literal::None => write!(f, "None"),
92            Literal::Unit => write!(f, "()"),
93            Literal::Timeframe(tf) => write!(f, "{}", tf),
94        }
95    }
96}
97
98impl Literal {
99    /// Convert literal to a JSON value
100    pub fn to_json_value(&self) -> serde_json::Value {
101        match self {
102            Literal::Int(i) => serde_json::json!(*i),
103            Literal::UInt(u) => serde_json::json!(*u),
104            Literal::TypedInt(v, _) => serde_json::json!(*v),
105            Literal::Number(n) => serde_json::json!(*n),
106            Literal::Decimal(d) => serde_json::json!(d.to_string()),
107            Literal::String(s) => serde_json::json!(s),
108            Literal::Char(c) => serde_json::json!(c.to_string()),
109            Literal::FormattedString { value, .. } => serde_json::json!(value),
110            Literal::ContentString { value, .. } => serde_json::json!(value),
111            Literal::Bool(b) => serde_json::json!(*b),
112            Literal::None => serde_json::Value::Null,
113            Literal::Unit => serde_json::Value::Null,
114            Literal::Timeframe(t) => serde_json::json!(t.to_string()),
115        }
116    }
117}
118
119#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
120pub struct Duration {
121    pub value: f64,
122    pub unit: DurationUnit,
123}
124
125#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
126pub enum DurationUnit {
127    Seconds,
128    Minutes,
129    Hours,
130    Days,
131    Weeks,
132    Months,
133    Years,
134    Samples,
135}