aimx/typedef.rs
1//! Type definitions for the AIM expression grammar.
2//!
3//! This module provides type definitions and parsing for the type system used
4//! in the AIM expression language. It includes basic types like Bool, Date,
5//! Number, Task, and Text, as well as array variants and special types like
6//! Closure, Eval, Format, and Node.
7//!
8//! The `Typedef` enum represents the complete type system for AIM expressions,
9//! supporting type checking, casting operations, and function signature validation.
10//! Type definitions are used throughout the expression evaluation system to ensure
11//! type safety and enable automatic type promotion.
12//!
13//! # Supported Types
14//!
15//! ## Basic Types
16//! - `Any` - Any type (wildcard type that matches any value)
17//! - `Bool` - Boolean values (`true`/`false`)
18//! - `Date` - Date and time values
19//! - `Number` - 64-bit floating point numbers
20//! - `Task` - Task primitives with status and text
21//! - `Text` - String values
22//!
23//! ## Array Types
24//! - `Any[]` - Array of any values (heterogeneous)
25//! - `Bool[]` - Arrays of boolean values
26//! - `Date[]` - Arrays of date values
27//! - `Number[]` - Arrays of number values
28//! - `Task[]` - Arrays of task values
29//! - `Text[]` - Arrays of text values
30//!
31//! ## Special Types
32//! - `Closure` - Closure expression type (anonymous functions)
33//! - `Eval` - Evaluation results (inference output)
34//! - `Format` - Formatting instructions (output formatting)
35//! - `Node` - Node references (workflow references)
36//!
37//! # Type Promotion Rules
38//!
39//! AIMX uses an intuitive type promotion strategy where the left operand's type
40//! generally dictates the conversion for the right operand. This allows for
41//! expressive, convenient formulas while preserving type safety.
42//!
43//! # Examples
44//!
45//! ```text
46//! // Type casting examples
47//! (Bool)true // cast to boolean
48//! (Number)"123" // cast to number
49//! (Text[])items // cast to text array
50//!
51//! // Function signature examples
52//! task.done() // requires Typedef::Task
53//! numbers.sum() // requires Typedef::NumberArray
54//! text.upper() // requires Typedef::Text
55//! ```
56//!
57//! # Usage
58//!
59//! Type definitions are primarily used for:
60//! - Type casting operations in expressions
61//! - Function signature validation
62//! - Method dispatch based on receiver type
63//! - Type checking during expression evaluation
64//!
65//! See also: [`parse_typedef`], [`parse_literal_type`], [`Typedef`]
66
67use nom::{
68 IResult,
69 error::Error,
70 Err as NomErr,
71 branch::alt,
72 bytes::complete::tag,
73 combinator::opt,
74 Parser,
75};
76use crate::{
77 Writer,
78 ContextLike,
79 ExpressionLike,
80 Value,
81};
82use std::fmt;
83use anyhow::{anyhow, Result};
84
85/// Represents type definitions in the AIM expression grammar.
86///
87/// The `Typedef` enum provides a complete type system for the AIM expression
88/// language, including basic types, array types, and special-purpose types.
89/// These type definitions are used throughout the expression evaluation system
90/// for type checking, casting operations, function signature validation, and
91/// method dispatch.
92///
93/// # Type Safety and Promotion
94///
95/// AIMX uses a robust type system with automatic type promotion. The system
96/// follows a left-operand-first strategy where the left operand's type determines
97/// how the right operand is promoted. This provides expressive power while
98/// maintaining type safety.
99///
100/// # Variants
101///
102/// ## Basic Types
103/// * `Any` - Wildcard type that matches any value
104/// * `Bool` - Boolean values (`true`/`false`)
105/// * `Date` - Date and time values
106/// * `Number` - 64-bit floating point numbers
107/// * `Task` - Task primitives with status and text
108/// * `Text` - String values
109///
110/// ## Array Types
111/// * `Array` - Array of any values (heterogeneous)
112/// * `BoolArray` - Arrays of boolean values
113/// * `DateArray` - Arrays of date values
114/// * `NumberArray` - Arrays of number values
115/// * `TaskArray` - Arrays of task values
116/// * `TextArray` - Arrays of text values
117///
118/// ## Special Types
119/// * `Closure` - Closure expression type (anonymous functions)
120/// * `Eval` - Evaluation result type (inference output)
121/// * `Format` - Formatting instruction type (output formatting)
122/// * `Node` - Node reference type (workflow references)
123///
124/// # Examples
125///
126/// ```rust
127/// use aimx::typedef::Typedef;
128///
129/// // Basic type checking
130/// assert!(Typedef::Bool.is_bool());
131/// assert!(Typedef::NumberArray.is_array());
132///
133/// // Type conversion
134/// let text_type = Typedef::Text;
135/// assert_eq!(text_type.as_string(), "Text");
136///
137/// // Array type recognition
138/// let number_array = Typedef::NumberArray;
139/// assert!(number_array.is_number());
140/// assert!(number_array.is_array());
141/// ```
142///
143/// See also: [`parse_typedef`], [`parse_literal_type`]
144#[derive(Debug, Clone, PartialEq)]
145pub enum Typedef {
146 /// Any type
147 Any,
148 /// Generic Array
149 Array,
150 /// Boolean type
151 Bool,
152 /// Array of boolean values
153 BoolArray,
154 /// Date and time type
155 Date,
156 /// Array of date values
157 DateArray,
158 /// Number (64-bit float) type
159 Number,
160 /// Array of number values
161 NumberArray,
162 /// Task primitive type
163 Task,
164 /// Array of task values
165 TaskArray,
166 /// Text/string type
167 Text,
168 /// Array of text values
169 TextArray,
170
171 /// Closure expression type
172 Closure,
173 /// Evaluation result type
174 Eval,
175 /// Formatting instruction type
176 Format,
177 /// Node reference type
178 Node,
179}
180
181impl Typedef {
182 /// Check if this type definition represents the Any type.
183 ///
184 /// # Returns
185 ///
186 /// * `bool` - True if this is the Any type, false otherwise
187 pub fn is_any(&self) -> bool {
188 match self {
189 Typedef::Any | Typedef::Array => true,
190 _ => false,
191 }
192 }
193
194 /// Check if this type definition represents the Any Array type.
195 ///
196 /// # Returns
197 ///
198 /// * `bool` - True if this is the Any Array type, false otherwise
199 pub fn is_any_array(&self) -> bool {
200 match self {
201 Typedef::Array => true,
202 _ => false,
203 }
204 }
205
206 /// Check if this type definition represents a Bool or BoolArray type.
207 ///
208 /// # Returns
209 ///
210 /// * `bool` - True if this is a Bool or BoolArray type, false otherwise
211 pub fn is_bool(&self) -> bool {
212 match self {
213 Typedef::Bool | Typedef::BoolArray => true,
214 _ => false,
215 }
216 }
217
218 /// Check if this type definition represents a Date or DateArray type.
219 ///
220 /// # Returns
221 ///
222 /// * `bool` - True if this is a Date or DateArray type, false otherwise
223 pub fn is_date(&self) -> bool {
224 match self {
225 Typedef::Date | Typedef::DateArray => true,
226 _ => false,
227 }
228 }
229
230 /// Check if this type definition represents a Number or NumberArray type.
231 ///
232 /// # Returns
233 ///
234 /// * `bool` - True if this is a Number or NumberArray type, false otherwise
235 pub fn is_number(&self) -> bool {
236 match self {
237 Typedef::Number | Typedef::NumberArray => true,
238 _ => false,
239 }
240 }
241
242 /// Check if this type definition represents a Task or TaskArray type.
243 ///
244 /// # Returns
245 ///
246 /// * `bool` - True if this is a Task or TaskArray type, false otherwise
247 pub fn is_task(&self) -> bool {
248 match self {
249 Typedef::Task | Typedef::TaskArray => true,
250 _ => false,
251 }
252 }
253
254 /// Check if this type definition represents a Text or TextArray type.
255 ///
256 /// # Returns
257 ///
258 /// * `bool` - True if this is a Text or TextArray type, false otherwise
259 pub fn is_text(&self) -> bool {
260 match self {
261 Typedef::Text | Typedef::TextArray => true,
262 _ => false,
263 }
264 }
265
266 /// Check if this type definition represents a Literal type.
267 ///
268 /// Literal types are the basic value types that can be directly represented
269 /// in expressions without requiring complex evaluation.
270 ///
271 /// # Returns
272 ///
273 /// * `bool` - True if this is a Literal type, false otherwise
274 pub fn is_literal(&self) -> bool {
275 match self {
276 Typedef::Bool
277 | Typedef::Number
278 | Typedef::Date
279 | Typedef::Task
280 | Typedef::Text => true,
281 _ => false,
282 }
283 }
284
285 /// Convert this type definition to its corresponding literal type.
286 ///
287 /// This method strips array qualifiers and returns the base literal type.
288 /// For example, `NumberArray` becomes `Number`, `TextArray` becomes `Text`.
289 /// Special types remain unchanged.
290 ///
291 /// # Returns
292 ///
293 /// * `Typedef` - The corresponding literal type
294 ///
295 /// # Examples
296 ///
297 /// ```rust
298 /// use aimx::typedef::Typedef;
299 ///
300 /// assert_eq!(Typedef::NumberArray.as_literal(), Typedef::Number);
301 /// assert_eq!(Typedef::Text.as_literal(), Typedef::Text);
302 /// assert_eq!(Typedef::Closure.as_literal(), Typedef::Closure);
303 /// ```
304 pub fn as_literal(&self) -> Self {
305 match self {
306 Typedef::Any | Typedef::Array => Typedef::Any,
307 Typedef::Bool | Typedef::BoolArray => Typedef::Bool,
308 Typedef::Number | Typedef::NumberArray => Typedef::Number,
309 Typedef::Date | Typedef::DateArray => Typedef::Date,
310 Typedef::Task | Typedef::TaskArray => Typedef::Task,
311 Typedef::Text | Typedef::TextArray => Typedef::Text,
312 Typedef::Closure => Typedef::Closure,
313 Typedef::Eval => Typedef::Eval,
314 Typedef::Format => Typedef::Format,
315 Typedef::Node => Typedef::Node,
316 }
317 }
318
319 /// Check if this type definition represents an array type.
320 ///
321 /// # Returns
322 ///
323 /// * `bool` - True if this is an array type, false otherwise
324 pub fn is_array(&self) -> bool {
325 match self {
326 Typedef::Array
327 | Typedef::BoolArray
328 | Typedef::NumberArray
329 | Typedef::DateArray
330 | Typedef::TaskArray
331 | Typedef::TextArray => true,
332 _ => false,
333 }
334 }
335
336 /// Convert this type definition to its corresponding array type.
337 ///
338 /// This method adds array qualifiers to literal types. For example,
339 /// `Number` becomes `NumberArray`, `Text` becomes `TextArray`.
340 /// Special types remain unchanged.
341 ///
342 /// # Returns
343 ///
344 /// * `Typedef` - The corresponding array type
345 ///
346 /// # Examples
347 ///
348 /// ```rust
349 /// use aimx::typedef::Typedef;
350 ///
351 /// assert_eq!(Typedef::Number.as_array(), Typedef::NumberArray);
352 /// assert_eq!(Typedef::TextArray.as_array(), Typedef::TextArray);
353 /// assert_eq!(Typedef::Closure.as_array(), Typedef::Closure);
354 /// ```
355 pub fn as_array(&self) -> Self {
356 match self {
357 Typedef::Any | Typedef::Array => Typedef::Array,
358 Typedef::Bool | Typedef::BoolArray => Typedef::BoolArray,
359 Typedef::Number | Typedef::NumberArray => Typedef::NumberArray,
360 Typedef::Date | Typedef::DateArray => Typedef::DateArray,
361 Typedef::Task | Typedef::TaskArray => Typedef::TaskArray,
362 Typedef::Text | Typedef::TextArray => Typedef::TextArray,
363 Typedef::Closure => Typedef::Closure,
364 Typedef::Eval => Typedef::Eval,
365 Typedef::Format => Typedef::Format,
366 Typedef::Node => Typedef::Node,
367 }
368 }
369
370 /// Check if this type definition represents the Format type.
371 ///
372 /// # Returns
373 ///
374 /// * `bool` - True if this is the Format type, false otherwise
375 pub fn is_format(&self) -> bool {
376 match self {
377 Typedef::Format => true,
378 _ => false,
379 }
380 }
381
382 /// Check if this type definition represents the Eval type.
383 ///
384 /// # Returns
385 ///
386 /// * `bool` - True if this is the Eval type, false otherwise
387 pub fn is_eval(&self) -> bool {
388 match self {
389 Typedef::Eval => true,
390 _ => false,
391 }
392 }
393
394 /// Check if this type definition represents a Node type.
395 ///
396 /// # Returns
397 ///
398 /// * `bool` - True if this is a Node type, false otherwise
399 pub fn is_node(&self) -> bool {
400 match self {
401 Typedef::Node => true,
402 _ => false,
403 }
404 }
405
406 /// Check if this type definition represents the Closure type.
407 ///
408 /// # Returns
409 ///
410 /// * `bool` - True if this is the Closure type, false otherwise
411 pub fn is_closure(&self) -> bool {
412 match self {
413 Typedef::Closure => true,
414 _ => false,
415 }
416 }
417
418 /// Check if this type definition represents an special type.
419 ///
420 /// Special types are those that don't represent literal values but rather
421 /// serve specific purposes in the expression system.
422 ///
423 /// # Returns
424 ///
425 /// * `bool` - True if this is a Format, Eval, Node or Closure type, false otherwise
426 pub fn is_special(&self) -> bool {
427 match self {
428 Typedef::Closure
429 | Typedef::Format
430 | Typedef::Eval
431 | Typedef::Node => true,
432 _ => false,
433 }
434 }
435
436 /// Get the string representation of this type definition.
437 ///
438 /// Returns the canonical string representation used in AIM expressions.
439 /// This is the same format that would appear in type casting operations.
440 ///
441 /// # Returns
442 ///
443 /// * `&'static str` - The string representation of the type
444 ///
445 /// # Examples
446 ///
447 /// ```rust
448 /// use aimx::typedef::Typedef;
449 ///
450 /// assert_eq!(Typedef::Bool.as_string(), "Bool");
451 /// assert_eq!(Typedef::NumberArray.as_string(), "Number[]");
452 /// assert_eq!(Typedef::Closure.as_string(), "Closure");
453 /// ```
454 pub fn as_string(&self) -> &'static str {
455 match self {
456 Typedef::Any => "Any",
457 Typedef::Array => "Any[]",
458 Typedef::Bool => "Bool",
459 Typedef::BoolArray => "Bool[]",
460 Typedef::Date => "Date",
461 Typedef::DateArray => "Date[]",
462 Typedef::Number => "Number",
463 Typedef::NumberArray => "Number[]",
464 Typedef::Task => "Task",
465 Typedef::TaskArray => "Task[]",
466 Typedef::Text => "Text",
467 Typedef::TextArray => "Text[]",
468
469 Typedef::Closure => "Closure",
470 Typedef::Eval => "Eval",
471 Typedef::Format => "Format",
472 Typedef::Node => "Node",
473 }
474 }
475}
476
477/// Parse a type definition from a string according to the AIM expression grammar syntax.
478///
479/// This function parses type names and array markers to create the appropriate
480/// Typedef variant. It supports both basic types and array types.
481///
482/// # Supported Type Names
483/// - `Any` - Wildcard type that matches any value
484/// - `Bool` - Boolean type
485/// - `Date` - Date type
486/// - `Number` - Number type
487/// - `Task` - Task type
488/// - `Text` - Text type
489///
490/// # Special Types
491/// - `Eval` - Evaluation type
492/// - `Format` - Format type
493/// - `Node` - Node type
494///
495/// # Arguments
496///
497/// * `input` - A string slice containing the type definition to parse
498///
499/// # Returns
500///
501/// * `IResult<&str, Typedef>` - A nom result with remaining input and parsed type definition
502///
503/// # Examples
504///
505/// ```rust
506/// use aimx::typedef::{parse_typedef, Typedef};
507///
508/// assert_eq!(parse_typedef("Bool"), Ok(("", Typedef::Bool)));
509/// assert_eq!(parse_typedef("Number[]"), Ok(("", Typedef::NumberArray)));
510/// assert_eq!(parse_typedef("Text[]"), Ok(("", Typedef::TextArray)));
511/// ```
512pub fn parse_typedef(input: &str) -> IResult<&str, Typedef> {
513
514 // Parse type marker
515 let (input, type_marker) = alt((
516 tag("Any"),
517 tag("Bool"),
518 tag("Date"),
519 tag("Number"),
520 tag("Task"),
521 tag("Text"),
522
523 tag("Closure"),
524 tag("Eval"),
525 tag("Format"),
526 tag("Node"),
527 )).parse(input)?;
528
529 // Parse array marker if present
530 let (input, array_marker) = opt(tag("[]")).parse(input)?;
531 let is_array = array_marker.is_some();
532
533 let typedef = match (type_marker, is_array) {
534 ("Any", false) => Typedef::Any,
535 ("Any", true) => Typedef::Array,
536 ("Bool", false) => Typedef::Bool,
537 ("Bool", true) => Typedef::BoolArray,
538 ("Date", false) => Typedef::Date,
539 ("Date", true) => Typedef::DateArray,
540 ("Number", false) => Typedef::Number,
541 ("Number", true) => Typedef::NumberArray,
542 ("Task", false) => Typedef::Task,
543 ("Task", true) => Typedef::TaskArray,
544 ("Text", false) => Typedef::Text,
545 ("Text", true) => Typedef::TextArray,
546
547 ("Closure", false) => Typedef::Closure,
548 ("Eval", false) => Typedef::Eval,
549 ("Format", false) => Typedef::Format,
550 ("Node", false) => Typedef::Node,
551 _ => return Err(NomErr::Failure(Error::new(input, nom::error::ErrorKind::Fail))),
552 };
553
554 Ok((input, typedef))
555}
556
557/// Parse a literal type definition from a string.
558///
559/// This function is similar to [`parse_typedef`] but only accepts literal types
560/// (Bool, Date, Number, Task, Text) and does not support array types or special types.
561/// It's used in contexts where only basic value types are expected.
562///
563/// # Arguments
564///
565/// * `input` - A string slice containing the literal type definition to parse
566///
567/// # Returns
568///
569/// * `IResult<&str, Typedef>` - A nom result with remaining input and parsed literal type
570///
571/// # Examples
572///
573/// ```rust
574/// use aimx::typedef::{parse_literal_type, Typedef};
575///
576/// assert_eq!(parse_literal_type("Bool"), Ok(("", Typedef::Bool)));
577/// assert_eq!(parse_literal_type("Number"), Ok(("", Typedef::Number)));
578/// assert_eq!(parse_literal_type("Text"), Ok(("", Typedef::Text)));
579/// ```
580pub fn parse_literal_type(input: &str) -> IResult<&str, Typedef> {
581 // Parse type marker
582 let (input, type_marker) = alt((
583 tag("Bool"),
584 tag("Date"),
585 tag("Number"),
586 tag("Task"),
587 tag("Text"),
588 )).parse(input)?;
589 let typedef = match type_marker {
590 "Bool" => Typedef::Bool,
591 "Date" => Typedef::Date,
592 "Number" => Typedef::Number,
593 "Task" => Typedef::Task,
594 "Text" => Typedef::Text,
595 _ => unreachable!(),
596 };
597 Ok((input, typedef))
598}
599
600impl ExpressionLike for Typedef {
601 fn evaluate(&self, _context: &mut dyn ContextLike) -> Result<Value> {
602 Err(anyhow!("Typedef cannot be evaluated"))
603 }
604
605 fn write(&self, writer: &mut Writer) {
606 writer.write_str(self.as_string());
607 }
608 fn to_sanitized(&self) -> String {
609 let mut writer = Writer::sanitizer();
610 writer.write_str(self.as_string());
611 writer.finish()
612 }
613 fn to_formula(&self) -> String {
614 let mut writer = Writer::formulizer();
615 writer.write_str(self.as_string());
616 writer.finish()
617 }
618}
619
620impl fmt::Display for Typedef {
621 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
622 let mut writer = Writer::stringizer();
623 writer.write_str(self.as_string());
624 write!(f, "{}", writer.finish())
625 }
626}
627