aimx/
parser.rs

1//! Main parsing interface for AIMX expressions.
2//!
3//! This module provides the primary entry point for parsing AIM Expressions (AIMX)
4//! strings into evaluatable abstract syntax trees. It serves as a wrapper around the
5//! internal parsing logic with enhanced error handling and validation.
6//!
7//! The parser transforms AIMX source code into an [`Expression`] AST that can be
8//! evaluated within a [`Context`](crate::context::Context). It handles the complete AIMX
9//! grammar including arrays, closures, conditionals, and all operator precedence rules.
10
11use crate::{
12    Expression, parse_expression,
13    values::Errata,
14};
15
16/// Parse an AIMX expression string into an Abstract Syntax Tree (AST).
17///
18/// This is the main entry point for parsing AIM Expressions. It transforms a string
19/// representation of an expression into an [`Expression`] AST that can be evaluated
20/// within a [`Context`](crate::context::Context). The parser handles the complete AIMX grammar
21/// including operator precedence, type annotations, arrays, closures, and conditional expressions.
22///
23/// # Arguments
24///
25/// * `input` - A string slice containing the AIMX expression to parse
26///
27/// # Returns
28///
29/// Returns an [`Expression`] representing the parsed abstract syntax tree. If parsing
30/// succeeds, the returned expression can be evaluated to produce a [`Value`](crate::value::Value).
31/// If parsing fails, the returned expression will contain error information wrapped
32/// in an [`Errata`] variant.
33///
34/// # Grammar Coverage
35///
36/// The parser supports the complete AIMX grammar including:
37/// - Arithmetic expressions: `2 + 3 * 4`
38/// - Boolean logic: `true & false | !flag`
39/// - Conditional expressions: `5 > 3 ? "yes" : "no"`
40/// - Function calls: `sqrt(16) + abs(-5)`
41/// - Array expressions: `(1, 2, 3).sum()`
42/// - Closures: `x => x * 2`
43/// - Type annotations: `(Number) "42"`
44/// - Task definitions: `[x] "Completed task"`
45/// - Variable references: `employee.salary * 0.15`
46///
47/// # Error Handling
48///
49/// The parser returns an [`Expression`] that may contain error information in the
50/// following scenarios:
51///
52/// - **Syntax Errors**: Malformed expressions that violate AIMX grammar rules
53/// - **Incomplete Expressions**: Input that ends before a complete expression is parsed
54/// - **Unexpected Input**: Valid expressions followed by additional unparsed text
55///
56/// Errors are represented as [`Errata`] variants within the returned [`Expression`],
57/// allowing the calling code to handle parsing failures gracefully.
58///
59/// # Examples
60///
61/// Basic usage for parsing and evaluating expressions:
62///
63/// ```rust
64/// use aimx::{aimx_parse, ExpressionLike, Context};
65///
66/// // Parse a simple arithmetic expression
67/// let expression = aimx_parse("2 + 3 * 4");
68/// let mut context = Context::new();
69/// let result = expression.evaluate(&mut context).unwrap();
70/// assert_eq!(result.to_string(), "14");
71///
72/// // Parse a complex expression with functions and arrays
73/// let expression = aimx_parse("sqrt(pow(2, 2) + max((1, 3))).round_to(5)");
74/// let result = expression.evaluate(&mut context).unwrap();
75/// assert_eq!(result.to_string(), "2.64575");
76///
77/// // Or use a simpler example:
78/// let expression = aimx_parse("sqrt(16)");
79/// let result = expression.evaluate(&mut context).unwrap();
80/// assert_eq!(result.to_string(), "4");
81///
82/// // Handle parsing errors gracefully
83/// let expression = aimx_parse("2 + * 3"); // Invalid syntax
84/// if expression.has_error() {
85///     println!("Parsing failed: {}", expression);
86/// }
87/// ```
88///
89/// # Implementation Details
90///
91/// The parser uses a recursive descent approach built on the [`nom`](https://docs.rs/nom) parser combinator
92/// library. It handles operator precedence through a hierarchy of expression types,
93/// with the highest precedence operators being parsed first. The parser is designed
94/// to be efficient and handle the complete AIMX grammar without backtracking.
95///
96/// After successful parsing, the function validates that no input remains unparsed.
97/// If additional text follows a valid expression, it is treated as an error to
98/// prevent ambiguity in expression boundaries.
99///
100/// # Panics
101///
102/// This function does not panic. All parsing errors are captured and returned
103/// as [`Errata`] variants within the [`Expression`] result.
104///
105/// # See Also
106///
107/// - [`Expression`] - The abstract syntax tree returned by the parser
108/// - [`ExpressionLike`](crate::evaluate::ExpressionLike) - Trait for evaluating expressions
109/// - [`Context`](crate::context::Context) - Evaluation context for expression evaluation
110/// - [`Value`](crate::value::Value) - Runtime values produced by expression evaluation
111/// - [`Errata`] - Error information wrapper
112pub fn aimx_parse(input: &str) -> Expression {
113    match parse_expression(input) {
114        Ok((remaining, expression)) => {
115            if remaining.is_empty() {
116                expression
117            } else {
118                // Unexpected input remaining that wasn't parsed
119                Errata::new_reason_expression_location(
120                    "Unexpected Input Remaining".to_owned(),
121                    input.to_string(),
122                    remaining.to_string()
123                )
124            }
125        }
126        Err(nom::Err::Incomplete(_)) => {
127            Errata::new_reason_expression(
128                "Incomplete Expression".to_owned(),
129                input.to_string()
130            )
131        }
132        Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => {
133            Errata::new_reason_expression_location(
134                format!("Syntax Error ({})", e),
135                input.to_string(),
136                e.input.to_string()
137            )
138        }
139    }
140}