synthphonia/expr/ops/mod.rs
1use enum_dispatch::enum_dispatch;
2
3use super::*;
4use crate::parser::config::Config;
5use crate::{value::Value, expr};
6use std::future::Future;
7use std::path::Display;
8
9pub mod str;
10use self::context::Context;
11pub use self::str::*;
12
13use crate::text::parsing::*;
14use crate::text::formatting::*;
15pub mod base;
16pub use self::base::*;
17
18pub mod int;
19pub use self::int::*;
20pub mod float;
21pub use self::float::*;
22
23pub mod list;
24pub use self::list::*;
25
26
27pub mod date;
28pub use date::*;
29pub mod bv;
30pub use bv::*;
31pub mod macros;
32
33#[enum_dispatch]
34/// Defines a trait for unary operations that supports cloning and formatting.
35///
36/// This trait requires implementing a method to determine the operation's cost and another to attempt evaluation on a single input value.
37/// The `cost` method returns the computational expense of the operation as a `usize`, providing a way to assess the relative resource consumption.
38/// The `try_eval` method takes a single argument, `a1`, of type `Value`, and returns a tuple, where the first element is a boolean indicating success or failure of the evaluation, and the second element contains the resulting `Value`.
39/// This trait layout allows for flexibility and modularity when defining unary operations within the string synthesis framework.
40///
41///
42pub trait Op1: Clone + std::fmt::Display {
43 fn cost(&self) -> usize;
44 fn try_eval(&self, a1: Value) -> (bool, Value);
45}
46
47impl Op1Enum {
48 /// Evaluates a unary operation on a given value and returns the result.
49 ///
50 /// This function takes a reference to self as an `Op1Enum` instance and a `Value` representing the operand for the unary operation.
51 /// It attempts to evaluate the operation by calling the `try_eval` method with the provided argument and returns the second element of the resulting tuple, which is the computed `Value`.
52 /// This method assumes that the operation is successfully executed, as it directly takes the result part of the tuple from `try_eval`.
53 ///
54 pub fn eval(&self, a1: Value) -> Value {
55
56 self.try_eval(a1).1
57 }
58}
59
60#[enum_dispatch]
61/// Defines a trait for binary operations in the string synthesis framework.
62///
63///
64/// The trait requires implementors to include methods for calculating the cost associated with executing the operation and attempting evaluation with two input values, returning a tuple with a boolean indicating success or failure and the resultant value.
65/// It also requires implementors to derive clone and display functionalities, ensuring that all binary operations can be easily duplicated and formatted to strings for display purposes.
66pub trait Op2 : Clone + std::fmt::Display {
67 fn cost(&self) -> usize;
68 fn try_eval(&self, a1: Value, a2: Value) -> (bool, Value);
69}
70
71impl Op2Enum {
72 /// Evaluates a binary operation encapsulated by the `Op2Enum`.
73 ///
74 /// It takes two arguments, both of type `Value`, and returns the result of attempting the operation.
75 /// The method utilizes the `try_eval` function internally, discarding the primary component of its result and only retaining the secondary element, which represents the successfully evaluated output.
76 /// This signifies that while the `try_eval` function may return additional diagnostic information or status, this method focuses solely on obtaining the computed value from the operation.
77 ///
78 pub fn eval(&self, a1: Value, a2: Value) -> Value { self.try_eval(a1, a2).1 }
79}
80
81#[enum_dispatch]
82/// A trait defining a ternary operation.
83///
84/// It represents operations that take three argument values and provides methods to evaluate and determine the cost of performing the operation.
85/// Implementations of this trait must provide a `cost` method that returns the operation's cost as an unsigned size.
86/// The `try_eval` method attempts to evaluate the operation with three input values, returning a tuple where the first element indicates success as a boolean and the second element contains the resultant value.
87/// This trait requires its implementers to be clonable and displayable, facilitating duplication and formatted output of operation instances.
88///
89pub trait Op3 : Clone + std::fmt::Display {
90 fn cost(&self) -> usize;
91 fn try_eval(&self, a1: Value, a2: Value, a3: Value) -> (bool, Value);
92}
93
94impl Op3Enum {
95 /// Provides an evaluation method for the `Op3Enum` operations.
96 ///
97 /// Invokes the `try_eval` method with three provided `Value` arguments and returns the second element of the tuple resulting from the `try_eval` call.
98 /// This method abstracts the direct invocation of operation logic encapsulated in `try_eval`, emphasizing the resultant value of the operation within ternary operation contexts.
99 ///
100 pub fn eval(&self, a1: Value, a2: Value, a3: Value) -> Value { self.try_eval(a1, a2, a3).1 }
101}
102
103#[enum_dispatch(Op1)]
104#[derive(Debug, Clone, PartialEq, Eq, Hash)]
105/// An enum that defines unary operations for expressions within the string synthesis framework.
106///
107/// This enumeration, `Op1Enum`, includes a wide array of operations that can be applied to a single operand.
108/// The operations cover a diverse set of functionalities such as conversions between data types (e.g., `ToInt`, `ToStr`, `IntToFloat`, `FloatToInt`, `StrToFloat`), string manipulations like changing case (`Uppercase`, `Lowercase`) and retaining specific character types (`RetainLl`, `RetainLc`, `RetainN`, `RetainL`, `RetainLN`).
109///
110///
111/// Additionally, the enum supports various mathematical and logical checks (`IsPos`, `IsZero`, `IsNatural`, `FIsPos`, `FIsZero`, `FNotNeg`), numerical operations (`Neg`, `FNeg`, `FAbs`, `FExp10`), formatting (`FormatInt`, `FormatFloat`, `FormatTime`, `FormatMonth`, `FormatWeekday`), and parsing (`ParseTime`, `ParseDate`, `ParseInt`, `ParseMonth`, `ParseWeekday`, `ParseFloat`).
112/// It also includes utilities like `Len` for measuring length and several date-related transformations (`AsMonth`, `AsDay`, `AsYear`, `AsWeekDay`).
113/// This diverse suite of operations enables flexible and efficient manipulation of data types required for string synthesis challenges.
114pub enum Op1Enum {
115 Len,
116 ToInt,
117 ToStr,
118 Neg,
119 IsPos,
120 IsZero,
121 IsNatural,
122 RetainLl,
123 RetainLc,
124 RetainN,
125 RetainL,
126 RetainLN,
127 Map,
128 Filter,
129 Uppercase,
130 Lowercase,
131 AsMonth,
132 AsDay,
133 AsYear,
134 AsWeekDay,
135 ParseTime,
136 ParseDate,
137 ParseInt,
138 ParseMonth,
139 ParseWeekday,
140 ParseFloat,
141 FormatInt,
142 FormatFloat,
143 FormatTime,
144 FormatMonth,
145 FormatWeekday,
146 FNeg,
147 FAbs,
148 FIsPos,
149 FExp10,
150 IntToFloat,
151 FloatToInt,
152 StrToFloat,
153 FIsZero,
154 FNotNeg,
155 FLen,
156 BvNot,
157 BvNeg
158}
159impl std::fmt::Display for Op1Enum {
160 /// Formats the operation represented by `Op1Enum` for printing.
161 ///
162 /// This implementation attempts to match the enum variant of the `Op1Enum` and writes its argument to the provided formatter.
163 /// The macro `crate::for_all_op1!()` is used to iterate over all possible unary operation variants, facilitating the matching process.
164 /// If an appropriate match is found, it writes the associated argument to the formatter.
165 /// If no match is found using the macro, it completes without any action.
166 /// This approach enables a concise and consistent output for each variant when formatted.
167 ///
168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 macro_rules! _do { ($($op:ident)*) => {
170 $(
171 if let Self::$op(a) = self {
172 return write!(f, "{a}");
173 }
174 )*
175 }}
176 crate::for_all_op1!();
177 Ok(())
178 }
179}
180
181impl Op1Enum {
182 /// Implements a method to create an instance of the enumeration from a string identifier.
183 ///
184 /// This method takes a string `name` representing the desired operation and a `config` reference, which helps configure certain operational aspects, to return the corresponding `Op1Enum` variant.
185 /// Internally, it uses a macro, `_do`, to iterate over potential operations and check if their names match the given string identifier.
186 /// If a match is found, it returns the operation configured with the supplied configuration.
187 /// For specific operations like "str.len", "str.from_int", and "str.to_int", direct matches that do not utilize the macro are provided for convenience.
188 /// If no operation matches the given string name, the method panics with an "Unknown Operator" error message.
189 ///
190 pub fn from_name(name: &str, config: &Config) -> Self {
191 macro_rules! _do { ($($op:ident)*) => {
192 $(
193 if $op::name() == name {
194 return $op::from_config(config).into();
195 }
196 )*
197 }}
198 crate::for_all_op1!();
199 match name {
200 "str.len" => Len::from_config(config).into(),
201 "str.from_int" => ToStr::from_config(config).into(),
202 "str.to_int" => ToInt::from_config(config).into(),
203 _ => panic!("Unknown Operator {}", name),
204 }
205 }
206 /// Provides a method to retrieve the name of a unary operation as a static string.
207 ///
208 /// The method uses a macro to match the current instance of the enumeration against all possible variants of unary operations defined by `Op1Enum`.
209 /// If the current instance matches one of these variants, it returns the corresponding name by invoking the `name()` method of the matched operation.
210 /// It leverages a macro named `for_all_op1!` to iterate through all operation variants, ensuring extensibility and maintainability when new operations are introduced.
211 /// If no match is found, the method panics, indicating an unexpected state or missing variant handling.
212 ///
213 pub fn name(&self) -> &'static str {
214 macro_rules! _do { ($($op:ident)*) => {
215 $(
216 if let Self::$op(_) = self {
217 return $op::name();
218 }
219 )*
220 }}
221 crate::for_all_op1!();
222 panic!()
223 }
224}
225
226#[enum_dispatch(Op2)]
227#[derive(Clone, PartialEq, Eq, Hash)]
228/// An enum representing binary operations used in the expression manipulation framework.
229///
230/// This enumeration includes a diverse set of operations applicable to strings, numbers, lists, and time-related data.
231/// Typical operations include string manipulations such as `Concat`, `PrefixOf`, and `Contains`, which allow for constructing and checking properties of strings.
232/// There are also numerical operations like `Add`, `Sub`, alongside floating-point specific operations like `FAdd`, `FSub`, and rounding techniques such as `Floor`, `Round`, and `Ceil`.
233///
234/// Moreover, the enum encapsulates list operations such as `Head`, `Tail`, and `Filter`, indicating capabilities to manipulate and traverse lists.
235/// Time-based operations like `TimeFloor`, `TimeAdd`, and `TimeMul` are included, reflecting tasks related to temporal data.
236/// `Split` and `Join` manage compound string or list structures, and `StrAt` and `At` facilitate index-based access in strings or lists.
237/// The enumeration is designed to accommodate various contexts and operations necessary for a comprehensive synthesis framework, supporting diverse data types and manipulation techniques.
238pub enum Op2Enum {
239 Concat,
240 Eq,
241 At,
242 PrefixOf,
243 SuffixOf,
244 Contains,
245 Split,
246 Join,
247 Count,
248 Add,
249 Sub,
250 Head,
251 Tail,
252 TimeFloor,
253 TimeAdd,
254 Floor, Round, Ceil,
255 FAdd, FSub, FFloor, FRound, FCeil, FCount, FShl10, TimeMul, StrAt,
256 BvAdd, BvSub, BvMul, BvUDiv, BvURem, BvSDiv, BvSRem, BvOr, BvAnd, BvXor, BvShl, BvAShr, BvLShr
257}
258
259impl std::fmt::Display for Op2Enum {
260 /// Provides a formatting implementation for the `Op2Enum` type, utilizing the Rust standard library's `fmt` trait.
261 ///
262 /// This method employs a macro to streamline the process of matching against all possible `Op2Enum` variants, applying the formatting operation uniformly.
263 /// Within the macro `_do`, each variant is checked using pattern matching, and upon a match, it writes the variant's name to the provided formatter.
264 /// The macro ultimately integrates with a custom crate-level macro `crate::for_all_op2!()` to encompass all operations within `Op2Enum`, ensuring the method comprehensively formats each operation, returning a `Result` to indicate success or failure of the formatting operation.
265 ///
266 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267 macro_rules! _do { ($($op:ident)*) => {
268 $(
269 if let Self::$op(a) = self {
270 return write!(f, "{a}");
271 }
272 )*
273 }}
274 crate::for_all_op2!();
275 Ok(())
276 }
277}
278
279impl Op2Enum {
280 /// Converts a string name into an `Op2Enum` variant by matching the provided name with known operation names and configurations.
281 ///
282 /// The function utilizes a macro to iterate through all defined binary operations (`Op2`) and checks if the operation's name matches the input string.
283 /// If a match is found, it retrieves the operation with the given configuration and converts it into the `Op2Enum` type.
284 /// For specific operators like `"+"` and `"-"`, the function directly constructs their corresponding `Add` or `Sub` variants, respectively.
285 /// If no matching operation is found, it raises a panic with an error message indicating the unknown operator name.
286 ///
287 pub fn from_name(name: &str, config: &Config) -> Self {
288 macro_rules! _do { ($($op:ident)*) => {
289 $(
290 if $op::name() == name {
291 return $op::from_config(config).into();
292 }
293 )*
294 }}
295 crate::for_all_op2!();
296 match name {
297 "+" => Add::from_config(config).into(),
298 "-" => Sub::from_config(config).into(),
299 _ => panic!("Unknown Operator: {}", name),
300 }
301 }
302 /// Returns the name of the operation represented by the given instance of the enumeration.
303 ///
304 /// This implementation utilizes a macro to iterate over possible operation variants defined in the enumeration, invoking the `name` method on each.
305 /// The `name` method of a specific operation is called, and its result is returned if the instance matches one of the variants.
306 /// If no match is found, the function will trigger a panic, indicating that the instance does not correspond to a recognized operation variant.
307 /// This design aims to streamline name retrieval across multiple operation types within the `Op2Enum`.
308 ///
309 pub fn name(&self) -> &'static str {
310 macro_rules! _do { ($($op:ident)*) => {
311 $(
312 if let Self::$op(_) = self {
313 return $op::name();
314 }
315 )*
316 }}
317 crate::for_all_op2!();
318 panic!()
319 }
320}
321
322#[enum_dispatch(Op3)]
323#[derive(Clone, PartialEq, Eq, Hash)]
324/// An enum representing ternary operations in the string synthesis framework.
325///
326/// This enum includes operations such as `Replace`, which substitutes a part of a string with another substring, and `Ite` (if-then-else), which selects between two expressions based on a condition.
327/// It also includes `SubStr`, which extracts a portion of a string specified by a starting index and length, and `IndexOf`, which determines the index of a substring within another string.
328/// These operations are essential for manipulating strings in complex synthesis tasks.
329///
330pub enum Op3Enum {
331 Replace,
332 Ite,
333 SubStr,
334 IndexOf,
335}
336
337impl std::fmt::Display for Op3Enum {
338 /// Formats an `Op3Enum` variant into a string.
339 ///
340 /// The functionality uses a macro to match the variant of `Op3Enum` and writes its value (`a`) to the given formatter.
341 /// If the variant matches, the function returns the result of the formatted write operation.
342 /// If none of the variants match, it defaults to resolving successfully with an `Ok(())`.
343 /// The macro `crate::for_all_op3!()` is employed to handle all possible variants of `Op3Enum`, allowing concise and reusable code patterns for formatting each operation in the enumeration.
344 ///
345 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
346 macro_rules! _do { ($($op:ident)*) => {
347 $(
348 if let Self::$op(a) = self {
349 return write!(f, "{a}");
350 }
351 )*
352 }}
353 crate::for_all_op3!();
354 Ok(())
355 }
356}
357
358impl Op3Enum {
359 /// Provides a method for creating an instance of an operation from its name and a specified configuration.
360 ///
361 /// The `from_name` function takes a string slice representing the name of the operation and a reference to a `Config` object.
362 /// Utilizing a macro named `_do`, it iterates over all possible operations within the `Op3Enum` by dynamically executing each operation's name comparison.
363 /// If a match is found, it returns the corresponding operator configured via the `from_config` method.
364 /// In case no matching operation name is found, the function will terminate execution and issue a panic with an error message indicating the unknown operator.
365 /// This method ensures that each operation can be instantiated from a configuration while providing runtime safety against undefined operations.
366 ///
367 pub fn from_name(name: &str, config: &Config) -> Self {
368 macro_rules! _do { ($($op:ident)*) => {
369 $(
370 if $op::name() == name {
371 return $op::from_config(config).into();
372 }
373 )*
374 }}
375 crate::for_all_op3!();
376 panic!("Unknown Operator: {}", name);
377 }
378 /// Provides an implementation to retrieve the name of an operation represented by this item.
379 ///
380 /// This is achieved using a macro to iterate over a series of operations associated with the item, checking if the current instance matches any of these operations and returning its name via a helper function defined for each operation.
381 /// The logic ensures that for any valid instance of this item, the correct associated name is returned.
382 /// If none of the operations match, it results in a panic, indicating an unexpected state.
383 ///
384 pub fn name(&self) -> &'static str {
385 macro_rules! _do { ($($op:ident)*) => {
386 $(
387 if let Self::$op(_) = self {
388 return $op::name();
389 }
390 )*
391 }}
392 crate::for_all_op3!();
393 panic!()
394 }
395}
396
397pub mod op_impl;