aimx/expressions/primary.rs
1//! Primary expression parsing and evaluation for the AIMX grammar.
2//!
3//! This module provides the infrastructure for parsing and evaluating **primary expressions**,
4//! which form the foundation of the AIMX (Agentic Inference Markup Expressions) language.
5//! Primary expressions represent the most fundamental building blocks that all other
6//! expressions are built upon, including literals, variable references, and parenthesized
7//! expressions.
8//!
9//! Primary expressions have the highest precedence in the AIMX grammar hierarchy and are
10//! the first expressions parsed when building the abstract syntax tree (AST).
11//!
12//! # Primary Expression Types
13//!
14//! - **Literals** - Boolean, Date, Number, Task, and Text values
15//! - **References** - Variable and field references using dot notation
16//! - **Parentheses** - Grouped expressions `(expression)` that override precedence
17//!
18//! # Examples
19//!
20//! ```text
21//! 42 // number literal
22//! "hello" // text literal
23//! true // boolean literal
24//! foo // simple variable reference
25//! data.items // chained field reference
26//! (1 + 2) * 3 // parenthesized expression
27//! ```
28//!
29//! # AST Flattening Optimization
30//!
31//! The `Primary` enum includes variants for all higher-level expression types as part of an
32//! AST flattening optimization. This allows expressions that consist solely of primary
33//! components to be evaluated more efficiently without deep recursion through the expression
34//! hierarchy.
35//!
36//! # Usage
37//!
38//! Primary expressions are typically used internally by the AIMX parser but can also be
39//! used directly for parsing simple expressions or when working with literals and references
40//! in isolation.
41//!
42//! ```rust
43//! use aimx::{Primary};
44//! use aimx::expressions::{parse_primary};
45//! use aimx::Literal;
46//!
47//! // Parse a simple literal
48//! let (remaining, primary) = parse_primary("42").unwrap();
49//! assert_eq!(remaining, "");
50//! assert!(matches!(primary, Primary::Literal(Literal::Number(_))));
51//!
52//! // Parse a reference
53//! let (remaining, primary) = parse_primary("variable_name").unwrap();
54//! assert_eq!(remaining, "");
55//! assert!(matches!(primary, Primary::Reference(_)));
56//! ```
57
58use nom::{
59 IResult,
60 Parser,
61 branch::alt,
62 character::complete::{char, multispace0},
63 combinator::map,
64};
65use crate::{
66 ContextLike,
67 Expression,
68 ExpressionLike,
69 parse_expression,
70 expressions::{
71 Additive,
72 Closure,
73 Conditional,
74 Equality,
75 LogicalAnd,
76 LogicalOr,
77 Multiplicative,
78 Postfix,
79 parse_reference,
80 Relational,
81 Unary,
82 },
83 Literal,
84 parse_literal,
85 Reference,
86 Value,
87 Writer,
88};
89use std::fmt;
90use anyhow::Result;
91
92/// Represents a primary expression in the AIMX grammar.
93///
94/// Primary expressions are the fundamental building blocks of expressions in
95/// the AIMX language. They include literal values, variable references, and
96/// parenthesized expressions. Primary expressions form the base of the
97/// expression hierarchy, with other expression types building upon them.
98///
99/// The `Primary` enum uses AST flattening optimization, where it includes
100/// variants for all higher-level expression types. This allows expressions
101/// that consist solely of primary components to be evaluated more efficiently
102/// without deep recursion through the expression hierarchy.
103///
104/// # Variants
105///
106/// - [`Literal`](Primary::Literal) - A literal value (Bool, Date, Number, Task, Text, or Empty)
107/// - [`Reference`](Primary::Reference) - A variable or field reference
108/// - [`Parentheses`](Primary::Parentheses) - A parenthesized expression
109/// - [`Postfix`](Primary::Postfix) - Postfix operations (method calls, indexing, function calls)
110/// - [`Unary`](Primary::Unary) - Unary operations (logical NOT, arithmetic negation, casts)
111/// - [`Multiplicative`](Primary::Multiplicative) - Multiplicative operations (`*`, `/`, `%`)
112/// - [`Additive`](Primary::Additive) - Additive operations (`+`, `-`)
113/// - [`Relational`](Primary::Relational) - Relational operations (`<`, `<=`, `>`, `>=`)
114/// - [`Equality`](Primary::Equality) - Equality operations (`=`, `!=`)
115/// - [`LogicalAnd`](Primary::LogicalAnd) - Logical AND operations (`&`, `&&`)
116/// - [`LogicalOr`](Primary::LogicalOr) - Logical OR operations (`|`, `||`)
117/// - [`Conditional`](Primary::Conditional) - Conditional operations (`?`, `:`)
118/// - [`Closure`](Primary::Closure) - Closure operations (`=>`)
119///
120/// # AST Flattening
121///
122/// The flattened variants (Postfix through Closure) are populated during parsing
123/// when an expression contains higher-level operators but can be represented
124/// efficiently within the `Primary` enum. This optimization reduces AST depth
125/// and improves evaluation performance.
126///
127/// # Examples
128///
129/// ```rust
130/// use aimx::{Primary};
131/// use aimx::expressions::{parse_primary};
132/// use aimx::Literal;
133///
134/// // Parse a literal expression
135/// let (_, primary) = parse_primary("42").unwrap();
136/// assert!(matches!(primary, Primary::Literal(Literal::Number(_))));
137///
138/// // Parse a reference expression
139/// let (_, primary) = parse_primary("variable_name").unwrap();
140/// assert!(matches!(primary, Primary::Reference(_)));
141///
142/// // Parse a parenthesized expression
143/// let (_, primary) = parse_primary("(1 + 2)").unwrap();
144/// assert!(matches!(primary, Primary::Parentheses(_)));
145/// ```
146///
147/// # See Also
148///
149/// - [`crate::expressions::parse_primary`] - Function to parse primary expressions from text
150/// - [`ExpressionLike`] - Trait for expression evaluation
151/// - [`Literal`] - Literal value representation
152/// - [`Reference`] - Variable reference representation
153#[derive(Debug, Clone, PartialEq)]
154pub enum Primary {
155 /// A literal value such as a number, text string, boolean, date, or task
156 Literal(Literal),
157 /// A variable or field reference
158 Reference(Reference),
159 /// A parenthesized expression
160 Parentheses(Expression),
161
162 // Flattened abstract syntax tree
163 Postfix(Postfix),
164 Unary(Unary),
165 Multiplicative(Multiplicative),
166 Additive(Additive),
167 Relational(Relational),
168 Equality(Equality),
169 LogicalAnd(LogicalAnd),
170 LogicalOr(LogicalOr),
171 Conditional(Conditional),
172 Closure(Closure),
173}
174
175impl Primary {
176 /// Check if this primary expression is a literal value.
177 ///
178 /// Returns `true` if this `Primary` variant is [`Literal`](Primary::Literal),
179 /// `false` otherwise.
180 ///
181 /// # Examples
182 ///
183 /// ```rust
184 /// use aimx::{Primary};
185 /// use aimx::expressions::{parse_primary};
186 /// use aimx::Literal;
187 ///
188 /// let (_, literal) = parse_primary("42").unwrap();
189 /// assert!(literal.is_literal());
190 ///
191 /// let (_, reference) = parse_primary("variable").unwrap();
192 /// assert!(!reference.is_literal());
193 /// ```
194 pub fn is_literal(&self) -> bool {
195 match self {
196 Primary::Literal(_) => true,
197 _ => false,
198 }
199 }
200
201 /// Check if this primary expression is a variable or field reference.
202 ///
203 /// Returns `true` if this `Primary` variant is [`Reference`](Primary::Reference),
204 /// `false` otherwise.
205 ///
206 /// # Examples
207 ///
208 /// ```rust
209 /// use aimx::{Primary};
210 /// use aimx::expressions::{parse_primary};
211 ///
212 /// let (_, reference) = parse_primary("variable").unwrap();
213 /// assert!(reference.is_reference());
214 ///
215 /// let (_, literal) = parse_primary("42").unwrap();
216 /// assert!(!literal.is_reference());
217 /// ```
218 pub fn is_reference(&self) -> bool {
219 match self {
220 Primary::Reference(_) => true,
221 _ => false,
222 }
223 }
224}
225
226/// Parse a primary expression from text input.
227///
228/// This function parses the fundamental building blocks of expressions in the
229/// AIMX grammar, including literal values, references, and parenthesized expressions.
230/// It serves as the base parser for the expression grammar hierarchy and is used
231/// internally by higher-level parsers to handle the highest precedence expressions.
232///
233/// # Arguments
234///
235/// * `input` - A string slice containing the primary expression to parse
236///
237/// # Returns
238///
239/// Returns an [`IResult<&str, Primary>`] containing:
240/// - The remaining unparsed input
241/// - A parsed [`Primary`] expression
242///
243/// # Grammar
244///
245/// The primary expression grammar follows:
246/// ```text
247/// primary = literal | reference | '(' expression ')'
248/// ```
249///
250/// Where:
251/// - `literal` represents any valid literal value (number, text, boolean, date, task)
252/// - `reference` represents a variable or field reference
253/// - `expression` represents any valid AIMX expression
254///
255/// # Examples
256///
257/// ```rust
258/// use aimx::{Primary};
259/// use aimx::expressions::{parse_primary};
260/// use aimx::Literal;
261///
262/// // Parse a number literal
263/// let (remaining, primary) = parse_primary("42").unwrap();
264/// assert_eq!(remaining, "");
265/// assert!(matches!(primary, Primary::Literal(Literal::Number(_))));
266///
267/// // Parse a text literal
268/// let (remaining, primary) = parse_primary("\"hello\"").unwrap();
269/// assert_eq!(remaining, "");
270/// assert!(matches!(primary, Primary::Literal(Literal::Text(_))));
271///
272/// // Parse a variable reference
273/// let (remaining, primary) = parse_primary("variable_name").unwrap();
274/// assert_eq!(remaining, "");
275/// assert!(matches!(primary, Primary::Reference(_)));
276///
277/// // Parse a parenthesized expression
278/// let (remaining, primary) = parse_primary("(1 + 2)").unwrap();
279/// assert_eq!(remaining, "");
280/// assert!(matches!(primary, Primary::Parentheses(_)));
281/// ```
282///
283/// # See Also
284///
285/// - [`crate::expressions::parse_parentheses`] - Function for parsing parenthesized expressions
286/// - [`crate::literal::parse_literal`] - Function for parsing literal values
287/// - [`crate::expressions::reference::parse_reference`] - Function for parsing references
288pub fn parse_primary(input: &str) -> IResult<&str, Primary> {
289 alt((
290 map(parse_literal, Primary::Literal),
291 map(parse_reference, Primary::Reference),
292 map(parse_parentheses, |expression| Primary::Parentheses(expression)),
293 )).parse(input)
294}
295
296/// Parse a parenthesized expression.
297///
298/// This function parses expressions enclosed in parentheses, which are used
299/// to override operator precedence or group subexpressions. Parentheses allow
300/// explicit control over the evaluation order of complex expressions.
301///
302/// # Arguments
303///
304/// * `input` - A string slice containing the parenthesized expression to parse
305///
306/// # Returns
307///
308/// Returns an [`IResult<&str, Expression>`] containing:
309/// - The remaining unparsed input
310/// - A parsed [`Expression`] representing the parenthesized content
311///
312/// # Grammar
313///
314/// The parenthesized expression grammar follows:
315/// ```text
316/// parentheses = '(' S? expression S? ')'
317/// ```
318///
319/// Where `expression` represents any valid AIMX expression. Empty parentheses
320/// `()` are parsed as [`Expression::Empty`].
321///
322/// # Examples
323///
324/// ```rust
325/// use aimx::{Primary};
326/// use aimx::expressions::{parse_parentheses};
327/// use aimx::{Expression, Literal};
328///
329/// // Parse empty parentheses
330/// let (remaining, expr) = parse_parentheses("()").unwrap();
331/// assert_eq!(remaining, "");
332/// assert!(matches!(expr, Expression::Empty));
333///
334/// // Parse a simple parenthesized literal
335/// let (remaining, expr) = parse_parentheses("(42)").unwrap();
336/// assert_eq!(remaining, "");
337/// // The result will depend on how the inner expression "42" is parsed
338/// // It could be Expression::Primary(_) for simple literals
339///
340/// // Parse a complex parenthesized expression
341/// let (remaining, expr) = parse_parentheses("(1 + 2 * 3)").unwrap();
342/// assert_eq!(remaining, "");
343/// // The result depends on the specific expression parsed
344/// ```
345///
346/// # Implementation Details
347///
348/// This function handles:
349/// - Empty parentheses `()` by returning [`Expression::Empty`]
350/// - Whitespace around the parentheses
351/// - Recursive parsing of the inner expression
352/// - Proper error handling for mismatched parentheses
353///
354/// # See Also
355///
356/// - [`crate::expression::parse_expression`] - Function for parsing the inner expression
357/// - [`Expression::Empty`] - The variant returned for empty parentheses
358/// - [`Primary::Parentheses`] - The variant used when parenthesized expressions are parsed as primary expressions
359pub fn parse_parentheses(input: &str) -> IResult<&str, Expression> {
360 let (input, _) = char('(').parse(input)?;
361 let (input, _) = multispace0.parse(input)?;
362 if input.starts_with(')') {
363 let (input, _) = char(')').parse(input)?;
364 return Ok((input, Expression::Empty));
365 }
366 let (input, expression) = parse_expression(input)?;
367 let (input, _) = char(')').parse(input)?;
368 Ok((input, expression))
369}
370
371impl ExpressionLike for Primary {
372 /// Evaluate this primary expression within the given context.
373 ///
374 /// This method recursively evaluates the primary expression, delegating
375 /// to the appropriate evaluation methods for each variant. The evaluation
376 /// follows the AST flattening optimization where higher-level expression
377 /// variants are evaluated directly without recursion through the expression
378 /// hierarchy.
379 ///
380 /// # Arguments
381 ///
382 /// * `context` - The evaluation context providing variable values and function implementations
383 ///
384 /// # Returns
385 ///
386 /// Returns a [`Result<Value>`] containing the evaluated value if successful,
387 /// or an error if evaluation fails.
388 ///
389 /// # Evaluation Strategy
390 ///
391 /// - [`Literal`](Primary::Literal) expressions return their literal value
392 /// - [`Reference`](Primary::Reference) expressions look up the variable in the context
393 /// - [`Parentheses`](Primary::Parentheses) expressions evaluate the inner expression
394 /// - Flattened variants delegate to their respective evaluation methods
395 ///
396 /// # Examples
397 ///
398 /// ```rust
399 /// use aimx::{Primary};
400 /// use aimx::expressions::{parse_primary};
401 /// use aimx::{ContextLike, ExpressionLike, Literal};
402 ///
403 /// let mut context = aimx::Context::new();
404 ///
405 /// // Evaluate a literal
406 /// let primary = Primary::Literal(Literal::Number(42.0));
407 /// let result = primary.evaluate(&mut context).unwrap();
408 /// assert_eq!(result.to_string(), "42");
409 /// ```
410 ///
411 /// # See Also
412 ///
413 /// - [`ExpressionLike`] - The trait being implemented
414 /// - [`Value`] - The result type returned by evaluation
415 /// - [`ContextLike`] - The context trait for evaluation
416 fn evaluate(&self, context: &mut dyn ContextLike) -> Result<Value> {
417 match self {
418 Primary::Literal(literal) => {
419 if literal.is_empty() {
420 Ok(Value::Empty)
421 }
422 else {
423 Ok(Value::Literal(literal.clone()))
424 }
425 }
426 Primary::Reference(reference) => reference.evaluate(context),
427 Primary::Parentheses(expression) => expression.evaluate(context),
428
429 Primary::Postfix(postfix) => postfix.evaluate(context),
430 Primary::Unary(unary) => unary.evaluate(context),
431 Primary::Multiplicative(multiplicative) => multiplicative.evaluate(context),
432 Primary::Additive(additive) => additive.evaluate(context),
433 Primary::Relational(relational) => relational.evaluate(context),
434 Primary::Equality(equality) => equality.evaluate(context),
435 Primary::LogicalAnd(logical_and) => logical_and.evaluate(context),
436 Primary::LogicalOr(logical_or) => logical_or.evaluate(context),
437 Primary::Conditional(conditional) => conditional.evaluate(context),
438 Primary::Closure(closure) => closure.evaluate(context),
439 }
440 }
441
442 /// Write this primary expression to a [`Writer`] for formatting.
443 ///
444 /// This method recursively writes the primary expression to the provided
445 /// writer, producing a formatted representation suitable for display
446 /// or serialization.
447 ///
448 /// # Arguments
449 ///
450 /// * `writer` - The writer to write the formatted expression to
451 ///
452 /// # Writing Strategy
453 ///
454 /// - [`Literal`](Primary::Literal) expressions write their literal representation
455 /// - [`Reference`](Primary::Reference) expressions write the reference path
456 /// - [`Parentheses`](Primary::Parentheses) expressions write parentheses around the inner expression
457 /// - Flattened variants delegate to their respective write methods
458 fn write(&self, writer: &mut Writer) {
459 match self {
460 Primary::Literal(literal) => literal.write(writer),
461 Primary::Reference(reference) => reference.write(writer),
462 Primary::Parentheses(expression) => {
463 writer.write_char('(');
464 expression.write(writer);
465 writer.write_char(')');
466 },
467
468 Primary::Postfix(postfix) => postfix.write(writer),
469 Primary::Unary(unary) => unary.write(writer),
470 Primary::Multiplicative(multiplicative) => multiplicative.write(writer),
471 Primary::Additive(additive) => additive.write(writer),
472 Primary::Relational(relational) => relational.write(writer),
473 Primary::Equality(equality) => equality.write(writer),
474 Primary::LogicalAnd(logical_and) => logical_and.write(writer),
475 Primary::LogicalOr(logical_or) => logical_or.write(writer),
476 Primary::Conditional(conditional) => conditional.write(writer),
477 Primary::Closure(closure) => closure.write(writer),
478 }
479 }
480
481 /// Convert this primary expression to a sanitized string representation.
482 ///
483 /// Sanitized expressions are suitable for display purposes and may
484 /// omit certain implementation details or sensitive information.
485 ///
486 /// # Returns
487 ///
488 /// Returns a [`String`] containing the sanitized expression representation.
489 fn to_sanitized(&self) -> String {
490 let mut writer = Writer::sanitizer();
491 self.write(&mut writer);
492 writer.finish()
493 }
494
495 /// Convert this primary expression to its original formula representation.
496 ///
497 /// The formula representation attempts to reconstruct the original
498 /// expression text as it was parsed, suitable for use in formulas
499 /// or serialization.
500 ///
501 /// # Returns
502 ///
503 /// Returns a [`String`] containing the formula representation.
504 fn to_formula(&self) -> String {
505 let mut writer = Writer::formulizer();
506 self.write(&mut writer);
507 writer.finish()
508 }
509}
510
511impl fmt::Display for Primary {
512 /// Format this primary expression as a string.
513 ///
514 /// This implementation delegates to the [`write`](ExpressionLike::write) method
515 /// using a string-based writer, producing a human-readable representation
516 /// of the expression.
517 ///
518 /// # Arguments
519 ///
520 /// * `f` - The formatter to write the string representation to
521 ///
522 /// # Returns
523 ///
524 /// Returns [`fmt::Result`] indicating success or failure of formatting.
525 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
526 let mut writer = Writer::stringizer();
527 self.write(&mut writer);
528 write!(f, "{}", writer.finish())
529 }
530}