1pub mod ast;
49pub mod builtins;
50pub mod error;
51pub mod interpreter;
52pub mod lexer;
53pub mod parser;
54
55use indexmap::IndexMap;
56
57pub use ast::{Expression, Program, Statement};
59pub use builtins::BuiltinFn;
60pub use error::{FiddlerError, LexError, ParseError, RuntimeError};
61pub use interpreter::Interpreter;
62pub use lexer::{Lexer, Token};
63pub use parser::Parser;
64
65#[derive(Debug, Clone)]
67pub enum Value {
68 Integer(i64),
70 Float(f64),
72 String(String),
74 Boolean(bool),
76 Bytes(Vec<u8>),
78 Array(Vec<Value>),
80 Dictionary(IndexMap<String, Value>),
82 Null,
84}
85
86impl PartialEq for Value {
88 fn eq(&self, other: &Self) -> bool {
89 match (self, other) {
90 (Value::Integer(a), Value::Integer(b)) => a == b,
91 (Value::Float(a), Value::Float(b)) => a == b, (Value::Integer(a), Value::Float(b)) => (*a as f64) == *b,
93 (Value::Float(a), Value::Integer(b)) => *a == (*b as f64),
94 (Value::String(a), Value::String(b)) => a == b,
95 (Value::Boolean(a), Value::Boolean(b)) => a == b,
96 (Value::Bytes(a), Value::Bytes(b)) => a == b,
97 (Value::Array(a), Value::Array(b)) => a == b,
98 (Value::Dictionary(a), Value::Dictionary(b)) => a == b,
99 (Value::Null, Value::Null) => true,
100 _ => false,
101 }
102 }
103}
104
105impl std::fmt::Display for Value {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 match self {
108 Value::Integer(n) => write!(f, "{}", n),
109 Value::Float(fl) => {
110 if fl.is_nan() {
111 write!(f, "NaN")
112 } else if fl.is_infinite() {
113 if fl.is_sign_positive() {
114 write!(f, "Infinity")
115 } else {
116 write!(f, "-Infinity")
117 }
118 } else if fl.fract() == 0.0 && fl.abs() < 1e15 {
119 write!(f, "{:.1}", fl)
121 } else {
122 let s = format!("{:.10}", fl);
124 let s = s.trim_end_matches('0').trim_end_matches('.');
125 write!(f, "{}", s)
126 }
127 }
128 Value::String(s) => write!(f, "{}", s),
129 Value::Boolean(b) => write!(f, "{}", b),
130 Value::Bytes(bytes) => write!(f, "<bytes: {} bytes>", bytes.len()),
131 Value::Array(arr) => {
132 write!(f, "[")?;
133 let mut first = true;
134 for v in arr {
135 if !first {
136 write!(f, ", ")?;
137 }
138 write!(f, "{}", v)?;
139 first = false;
140 }
141 write!(f, "]")
142 }
143 Value::Dictionary(dict) => {
144 write!(f, "{{")?;
145 let mut first = true;
146 for (k, v) in dict {
147 if !first {
148 write!(f, ", ")?;
149 }
150 write!(f, "{}: {}", k, v)?;
151 first = false;
152 }
153 write!(f, "}}")
154 }
155 Value::Null => write!(f, "null"),
156 }
157 }
158}
159
160impl Value {
161 pub fn to_bytes(&self) -> Vec<u8> {
163 match self {
164 Value::Integer(n) => n.to_string().into_bytes(),
165 Value::Float(f) => f.to_string().into_bytes(),
166 Value::String(s) => s.as_bytes().to_vec(),
167 Value::Boolean(b) => b.to_string().into_bytes(),
168 Value::Bytes(bytes) => bytes.clone(),
169 Value::Array(_) | Value::Dictionary(_) => self.to_string().into_bytes(),
170 Value::Null => Vec::new(),
171 }
172 }
173
174 pub fn is_number(&self) -> bool {
176 matches!(self, Value::Integer(_) | Value::Float(_))
177 }
178
179 pub fn as_f64(&self) -> Option<f64> {
181 match self {
182 Value::Integer(n) => Some(*n as f64),
183 Value::Float(f) => Some(*f),
184 _ => None,
185 }
186 }
187
188 pub fn as_i64(&self) -> Option<i64> {
190 match self {
191 Value::Integer(n) => Some(*n),
192 Value::Float(f) => Some(*f as i64),
193 _ => None,
194 }
195 }
196
197 pub fn from_bytes(bytes: Vec<u8>) -> Self {
199 Value::Bytes(bytes)
200 }
201
202 pub fn as_string_lossy(&self) -> Result<String, RuntimeError> {
208 match self {
209 Value::String(s) => Ok(s.clone()),
210 Value::Bytes(b) => Ok(String::from_utf8_lossy(b).into_owned()),
211 _ => Err(RuntimeError::invalid_argument(
212 "Expected string or bytes value",
213 )),
214 }
215 }
216
217 pub fn is_array(&self) -> bool {
219 matches!(self, Value::Array(_))
220 }
221
222 pub fn is_dictionary(&self) -> bool {
224 matches!(self, Value::Dictionary(_))
225 }
226
227 pub fn as_array(&self) -> Option<&Vec<Value>> {
229 match self {
230 Value::Array(arr) => Some(arr),
231 _ => None,
232 }
233 }
234
235 pub fn as_dictionary(&self) -> Option<&IndexMap<String, Value>> {
237 match self {
238 Value::Dictionary(dict) => Some(dict),
239 _ => None,
240 }
241 }
242}