aimx/aim/
typedef.rs

1//! Internal type identifiers and parsers used by the AIMX expression engine.
2//! Focused on type annotations, casts, function signatures, and runtime checks.
3//! Primary items: [`Typedef`], [`parse_typedef`], [`parse_literal_type`]
4
5use crate::aim::{Writer, WriterLike};
6use nom::{
7    Err as NomErr, IResult, Parser, branch::alt, bytes::complete::tag, combinator::opt,
8    error::Error,
9};
10use std::fmt;
11
12/// AIMX type identifiers for annotations, casts, signatures, and internal control.
13/// Variants include scalar, array, collection, and special engine-only types.
14/// Primary parser: [`parse_typedef`].
15#[derive(Debug, Clone, PartialEq)]
16pub enum Typedef {
17    /// Any type
18    Any,
19    /// Generic Array
20    Array,
21    /// Collection
22    Collection,
23    /// Boolean type
24    Bool,
25    /// Array of boolean values
26    BoolArray,
27    /// Date and time type
28    Date,
29    /// Array of date values
30    DateArray,
31    /// Number (64-bit float) type
32    Number,
33    /// Array of number values
34    NumberArray,
35    /// Task primitive type
36    Task,
37    /// Array of task values
38    TaskArray,
39    /// Text/string type
40    Text,
41    /// Array of text values
42    TextArray,
43
44    /// Branch state transition type
45    Branch,
46    /// Closure expression type
47    Closure,
48    /// Evaluation result type
49    Eval,
50    /// Formatting instruction type
51    Format,
52    /// Context instance type
53    Instance,
54    /// Node reference type
55    Node,
56    /// Retry inference loop
57    Retry,
58}
59
60impl Typedef {
61    pub fn convert(input: &str) -> Self {
62        match parse_typedef(input) {
63            Ok((_, typedef)) => typedef,
64            _ => Typedef::Any,
65        }
66    }
67
68    /// Returns true if this is `Any` or `Array`.
69    pub fn is_any(&self) -> bool {
70        match self {
71            Typedef::Any | Typedef::Array => true,
72            _ => false,
73        }
74    }
75
76    /// Returns true if this is `Array`.
77    pub fn is_any_array(&self) -> bool {
78        match self {
79            Typedef::Array => true,
80            _ => false,
81        }
82    }
83
84    /// Returns true if this is `Collection`.
85    pub fn is_collection(&self) -> bool {
86        match self {
87            Typedef::Collection => true,
88            _ => false,
89        }
90    }
91
92    /// Returns true if this is a boolean scalar or array type.
93    pub fn is_bool(&self) -> bool {
94        match self {
95            Typedef::Bool | Typedef::BoolArray => true,
96            _ => false,
97        }
98    }
99
100    /// Returns true if this is a date scalar or array type.
101    pub fn is_date(&self) -> bool {
102        match self {
103            Typedef::Date | Typedef::DateArray => true,
104            _ => false,
105        }
106    }
107
108    /// Returns true if this is a numeric scalar or array type.
109    pub fn is_number(&self) -> bool {
110        match self {
111            Typedef::Number | Typedef::NumberArray => true,
112            _ => false,
113        }
114    }
115
116    /// Returns true if this is a task scalar or array type.
117    pub fn is_task(&self) -> bool {
118        match self {
119            Typedef::Task | Typedef::TaskArray => true,
120            _ => false,
121        }
122    }
123
124    /// Returns true if this is a text scalar or array type.
125    pub fn is_text(&self) -> bool {
126        match self {
127            Typedef::Text | Typedef::TextArray => true,
128            _ => false,
129        }
130    }
131
132    /// Returns true if this is a literal scalar type (no arrays or specials).
133    pub fn is_literal(&self) -> bool {
134        match self {
135            Typedef::Bool | Typedef::Number | Typedef::Date | Typedef::Task | Typedef::Text => true,
136            _ => false,
137        }
138    }
139
140    /// Return the corresponding base literal type (arrays mapped to scalar, specials unchanged).
141    pub fn as_literal(&self) -> Self {
142        match self {
143            Typedef::Any | Typedef::Array | Typedef::Collection => Typedef::Any,
144            Typedef::Bool | Typedef::BoolArray => Typedef::Bool,
145            Typedef::Number | Typedef::NumberArray => Typedef::Number,
146            Typedef::Date | Typedef::DateArray => Typedef::Date,
147            Typedef::Task | Typedef::TaskArray => Typedef::Task,
148            Typedef::Text | Typedef::TextArray => Typedef::Text,
149            Typedef::Branch => Typedef::Branch,
150            Typedef::Closure => Typedef::Closure,
151            Typedef::Eval => Typedef::Eval,
152            Typedef::Format => Typedef::Format,
153            Typedef::Instance => Typedef::Instance,
154            Typedef::Node => Typedef::Node,
155            Typedef::Retry => Typedef::Retry,
156        }
157    }
158
159    /// Returns true if this is any array variant.
160    pub fn is_array(&self) -> bool {
161        match self {
162            Typedef::Array
163            | Typedef::BoolArray
164            | Typedef::NumberArray
165            | Typedef::DateArray
166            | Typedef::TaskArray
167            | Typedef::TextArray => true,
168            _ => false,
169        }
170    }
171
172    /// Return the corresponding array type for this definition (scalars mapped to array, specials unchanged).
173    pub fn as_array(&self) -> Self {
174        match self {
175            Typedef::Any | Typedef::Array | Typedef::Collection => Typedef::Array,
176            Typedef::Bool | Typedef::BoolArray => Typedef::BoolArray,
177            Typedef::Number | Typedef::NumberArray => Typedef::NumberArray,
178            Typedef::Date | Typedef::DateArray => Typedef::DateArray,
179            Typedef::Task | Typedef::TaskArray => Typedef::TaskArray,
180            Typedef::Text | Typedef::TextArray => Typedef::TextArray,
181            Typedef::Branch => Typedef::Branch,
182            Typedef::Closure => Typedef::Closure,
183            Typedef::Eval => Typedef::Eval,
184            Typedef::Format => Typedef::Format,
185            Typedef::Instance => Typedef::Instance,
186            Typedef::Node => Typedef::Node,
187            Typedef::Retry => Typedef::Retry,
188        }
189    }
190
191    /// Returns true if this is `Branch`.
192    pub fn is_branch(&self) -> bool {
193        match self {
194            Typedef::Branch => true,
195            _ => false,
196        }
197    }
198
199    /// Returns true if this is `Closure`.
200    pub fn is_closure(&self) -> bool {
201        match self {
202            Typedef::Closure => true,
203            _ => false,
204        }
205    }
206
207    /// Returns true if this is `Eval`.
208    pub fn is_eval(&self) -> bool {
209        match self {
210            Typedef::Eval => true,
211            _ => false,
212        }
213    }
214
215    /// Returns true if this is `Format`.
216    pub fn is_format(&self) -> bool {
217        match self {
218            Typedef::Format => true,
219            _ => false,
220        }
221    }
222
223    /// Returns true if this is `Instance`.
224    pub fn is_instance(&self) -> bool {
225        match self {
226            Typedef::Instance => true,
227            _ => false,
228        }
229    }
230
231    /// Returns true if this is `Node`.
232    pub fn is_node(&self) -> bool {
233        match self {
234            Typedef::Node => true,
235            _ => false,
236        }
237    }
238
239    /// Returns true if this is `Retry`.
240    pub fn is_retry(&self) -> bool {
241        match self {
242            Typedef::Retry => true,
243            _ => false,
244        }
245    }
246
247    /// Returns true if this is a special control/inference type.
248    pub fn is_special(&self) -> bool {
249        match self {
250            Typedef::Branch
251            | Typedef::Closure
252            | Typedef::Format
253            | Typedef::Eval
254            | Typedef::Node
255            | Typedef::Retry => true,
256            _ => false,
257        }
258    }
259
260    /// Get the string representation of this type definition.
261    ///
262    /// Returns the canonical string representation used in AIM expressions.
263    /// This is the same format that would appear in type casting operations.
264    ///
265    /// # Returns
266    ///
267    /// * `&'static str` - The string representation of the type
268    pub fn as_str(&self) -> &'static str {
269        match self {
270            Typedef::Any => "Any",
271            Typedef::Array => "Any[]",
272            Typedef::Collection => "Collection",
273
274            Typedef::Bool => "Bool",
275            Typedef::BoolArray => "Bool[]",
276            Typedef::Date => "Date",
277            Typedef::DateArray => "Date[]",
278            Typedef::Number => "Number",
279            Typedef::NumberArray => "Number[]",
280            Typedef::Task => "Task",
281            Typedef::TaskArray => "Task[]",
282            Typedef::Text => "Text",
283            Typedef::TextArray => "Text[]",
284
285            Typedef::Branch => "Branch",
286            Typedef::Closure => "Closure",
287            Typedef::Eval => "Eval",
288            Typedef::Format => "Format",
289            Typedef::Instance => "Instance",
290            Typedef::Node => "Node",
291            Typedef::Retry => "Retry",
292        }
293    }
294
295    pub fn print(&self, writer: &mut Writer) {
296        writer.write_str(self.as_str());
297    }
298
299    pub fn to_formula(&self) -> String {
300        let mut writer = Writer::formulizer();
301        writer.write_str(self.as_str());
302        writer.finish()
303    }
304}
305
306impl WriterLike for Typedef {
307    fn write(&self, writer: &mut Writer) {
308        self.print(writer);
309    }
310}
311
312impl fmt::Display for Typedef {
313    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
314        write!(f, "{}", self.to_stringized())
315    }
316}
317
318/// Parse a type identifier from `input` (supports scalar, array, collection, and specials).
319
320pub fn parse_typedef(input: &str) -> IResult<&str, Typedef> {
321    // Parse type marker
322    let (input, type_marker) = alt((
323        tag("Any"),
324        tag("Bool"),
325        tag("Date"),
326        tag("Number"),
327        tag("Task"),
328        tag("Text"),
329        tag("Collection"),
330        tag("Branch"),
331        tag("Closure"),
332        tag("Eval"),
333        tag("Format"),
334        tag("Instance"),
335        tag("Node"),
336        tag("Retry"),
337    ))
338    .parse(input)?;
339
340    // Parse array marker if present
341    let (input, array_marker) = opt(tag("[]")).parse(input)?;
342    let is_array = array_marker.is_some();
343
344    let typedef = match (type_marker, is_array) {
345        ("Any", false) => Typedef::Any,
346        ("Any", true) => Typedef::Array,
347        ("Bool", false) => Typedef::Bool,
348        ("Bool", true) => Typedef::BoolArray,
349        ("Date", false) => Typedef::Date,
350        ("Date", true) => Typedef::DateArray,
351        ("Number", false) => Typedef::Number,
352        ("Number", true) => Typedef::NumberArray,
353        ("Task", false) => Typedef::Task,
354        ("Task", true) => Typedef::TaskArray,
355        ("Text", false) => Typedef::Text,
356        ("Text", true) => Typedef::TextArray,
357
358        ("Collection", false) => Typedef::Collection,
359
360        ("Branch", false) => Typedef::Branch,
361        ("Closure", false) => Typedef::Closure,
362        ("Eval", false) => Typedef::Eval,
363        ("Format", false) => Typedef::Format,
364        ("Instance", false) => Typedef::Instance,
365        ("Node", false) => Typedef::Node,
366        ("Retry", false) => Typedef::Retry,
367        _ => {
368            return Err(NomErr::Failure(Error::new(
369                input,
370                nom::error::ErrorKind::Fail,
371            )));
372        }
373    };
374
375    Ok((input, typedef))
376}
377
378/// Parse a literal (non-array, non-special) scalar type identifier from `input`.
379
380pub fn parse_literal_type(input: &str) -> IResult<&str, Typedef> {
381    // Parse type marker
382    let (input, type_marker) = alt((
383        tag("Bool"),
384        tag("Date"),
385        tag("Number"),
386        tag("Task"),
387        tag("Text"),
388    ))
389    .parse(input)?;
390    let typedef = match type_marker {
391        "Bool" => Typedef::Bool,
392        "Date" => Typedef::Date,
393        "Number" => Typedef::Number,
394        "Task" => Typedef::Task,
395        "Text" => Typedef::Text,
396        _ => unreachable!(),
397    };
398    Ok((input, typedef))
399}