tenda_runtime/
value.rs

1use std::cell::RefCell;
2use std::fmt;
3use std::fmt::Display;
4use std::rc::Rc;
5use tenda_scanner::Literal;
6
7use crate::associative_array::{AssociativeArray, AssociativeArrayKey};
8use crate::date::Date;
9use crate::function::Function;
10
11#[derive(Debug, Clone, PartialEq)]
12pub enum Value {
13    Number(f64),
14    Boolean(bool),
15    String(String),
16    Function(Function),
17    List(Rc<RefCell<Vec<Value>>>),
18    Range(usize, usize),
19    AssociativeArray(Rc<RefCell<AssociativeArray>>),
20    Date(Date),
21    Nil,
22}
23
24impl Value {
25    pub fn kind(&self) -> ValueType {
26        use Value::*;
27
28        match self {
29            Number(_) => ValueType::Number,
30            Boolean(_) => ValueType::Boolean,
31            String(_) => ValueType::String,
32            Function(_) => ValueType::Function,
33            List(_) => ValueType::List,
34            Range(_, _) => ValueType::Range,
35            Nil => ValueType::Nil,
36            AssociativeArray(_) => ValueType::AssociativeArray,
37            Date(_) => ValueType::Date,
38        }
39    }
40
41    pub fn to_bool(&self) -> bool {
42        match self {
43            Value::Number(value) => *value != 0.0,
44            Value::Boolean(value) => *value,
45            Value::String(_) => true,
46            Value::Function(_) => true,
47            Value::List(_) => true,
48            Value::Range(_, _) => true,
49            Value::Nil => false,
50            Value::AssociativeArray(_) => true,
51            Value::Date(_) => true,
52        }
53    }
54
55    pub fn is_iterable(&self) -> bool {
56        matches!(self, Value::List(_) | Value::Range(_, _))
57    }
58}
59
60impl Display for Value {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        use Value::*;
63
64        write!(
65            f,
66            "{}",
67            match self {
68                Number(value) => match value {
69                    v if v.is_infinite() => {
70                        if v.is_sign_positive() {
71                            Literal::POSITIVE_INFINITY_LITERAL.to_string()
72                        } else {
73                            Literal::NEGATIVE_INFINITY_LITERAL.to_string()
74                        }
75                    }
76                    v if v.is_nan() => Literal::NAN_LITERAL.to_string(),
77                    _ => value.to_string(),
78                },
79                Boolean(value) => match *value {
80                    true => Literal::TRUE_LITERAL.to_string(),
81                    false => Literal::FALSE_LITERAL.to_string(),
82                },
83                String(value) => format!("\"{}\"", value),
84                Function(value) => format!("<função {:#x}>", value.id),
85                List(value) => format!(
86                    "[{}]",
87                    value
88                        .borrow()
89                        .iter()
90                        .map(|v| match v {
91                            Value::String(s) => format!("\"{}\"", escape_special_chars(s)),
92                            _ => v.to_string(),
93                        })
94                        .collect::<Vec<_>>()
95                        .join(", ")
96                ),
97                Range(start, end) => format!("{} até {}", start, end),
98                Nil => Literal::NIL_LITERAL.to_string(),
99                AssociativeArray(value) => format!(
100                    "{{ {} }}",
101                    value
102                        .borrow()
103                        .iter()
104                        .map(|(k, v)| match v {
105                            Value::String(s) => (k, format!("\"{}\"", escape_special_chars(s))),
106                            _ => (k, v.to_string()),
107                        })
108                        .map(|(k, v)| match k {
109                            AssociativeArrayKey::String(key) => format!("\"{}\": {}", key, v),
110                            AssociativeArrayKey::Number(key) => format!("{}: {}", key, v),
111                        })
112                        .collect::<Vec<_>>()
113                        .join(", ")
114                ),
115                Date(value) => value.to_iso_string(),
116            }
117        )
118    }
119}
120
121impl From<Literal> for Value {
122    fn from(literal: Literal) -> Self {
123        use Literal::*;
124
125        match literal {
126            Number(value) => Value::Number(value),
127            String(value) => Value::String(value),
128            Boolean(value) => Value::Boolean(value),
129            Nil => Value::Nil,
130        }
131    }
132}
133
134impl IntoIterator for Value {
135    type Item = Value;
136    type IntoIter = std::vec::IntoIter<Value>;
137
138    fn into_iter(self) -> Self::IntoIter {
139        if !self.is_iterable() {
140            panic!("value is not iterable");
141        }
142
143        match self {
144            Value::List(list) => list.borrow_mut().clone().into_iter(),
145            Value::Range(start, end) => (start..=end)
146                .map(|i| Value::Number(i as f64))
147                .collect::<Vec<_>>()
148                .into_iter(),
149            _ => unreachable!(),
150        }
151    }
152}
153
154#[derive(Debug, PartialEq, Clone)]
155pub enum ValueType {
156    Number,
157    Boolean,
158    String,
159    Function,
160    List,
161    Range,
162    Nil,
163    AssociativeArray,
164    Date,
165}
166
167impl From<Value> for ValueType {
168    fn from(value: Value) -> Self {
169        value.kind()
170    }
171}
172
173impl Display for ValueType {
174    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175        use ValueType::*;
176
177        let str = match self {
178            Number => "número".to_string(),
179            Boolean => "lógico".to_string(),
180            String => "texto".to_string(),
181            Function => "função".to_string(),
182            List => "lista".to_string(),
183            Range => "intervalo".to_string(),
184            AssociativeArray => "dicionário".to_string(),
185            Date => "data".to_string(),
186            Nil => "Nada".to_string(),
187        };
188
189        write!(f, "{}", str)
190    }
191}
192
193pub fn escape_special_chars(s: &str) -> String {
194    let mut result = String::with_capacity(s.len());
195
196    for c in s.chars() {
197        match c {
198            '\0' => result.push_str("\\0"),
199            '\x07' => result.push_str("\\a"),
200            '\x08' => result.push_str("\\b"),
201            '\x0C' => result.push_str("\\f"),
202            '\x0B' => result.push_str("\\v"),
203            '\x1B' => result.push_str("\\e"),
204            '\r' => result.push_str("\\r"),
205            '\n' => result.push_str("\\n"),
206            '\t' => result.push_str("\\t"),
207            '\\' => result.push_str("\\\\"),
208            '"' => result.push_str("\\\""),
209            '\'' => result.push_str("\\\'"),
210
211            c if c.is_control() => {
212                let byte = c as u32;
213                result.push_str(&format!("\\x{byte:02X}"));
214            }
215
216            _ => result.push(c),
217        }
218    }
219
220    result
221}
222
223pub fn escape_value(value: &Value) -> String {
224    match value {
225        Value::String(s) => format!("\"{}\"", escape_special_chars(s)),
226        _ => value.to_string(),
227    }
228}