aimx/aim/
rule.rs

1//! AIM rule representation and parsing.
2//!
3//! A `Rule` models a single AIM entry: identifier, typedef, expression, and value.
4//! Identifiers classify rules:
5//! - UPPERCASE → modifier
6//! - lowercase → assignment
7//! - other/mixed → general evaluation.
8
9use crate::{
10    aim::{ContextLike, Typedef, Writer, WriterLike, parse_typedef},
11    expressions::{
12        Expression, ExpressionLike, parse_arc_identifier, parse_branch, parse_closure, parse_expression, parse_retry, statically_evaluate
13    },
14    values::{Errata, Instance, Node, Value, parse_eval, parse_format, parse_instance, parse_node, parse_value},
15};
16use anyhow::{Result, anyhow};
17use bitflags::bitflags;
18use nom::{
19    Finish, IResult, Parser, 
20    character::complete::{char, multispace0}, 
21    sequence::{delimited},
22    error::{Error, ErrorKind}
23};
24use std::{
25    fmt,
26    sync::Arc,
27};
28
29// ----- FLAGS -----
30
31bitflags! {
32    /// Internal rule state flags derived from identifier and evaluation.
33    #[derive(Debug, Clone, PartialEq)]
34    struct Flags: usize {
35        /// Rule identifier is all uppercase (modifier rule)
36        const IS_MODIFIER   = 0b1;
37        /// Rule identifier is all lowercase (assignment rule)
38        const IS_ASSIGNMENT = 0b10;
39        /// Expression has been statically evaluated to constant value
40        const IS_STATIC     = 0b100;
41    }
42}
43
44/// Check if a string contains only uppercase characters.
45pub fn is_uppercase(s: &str) -> bool {
46    s.chars().all(|c| !c.is_alphabetic() || c.is_uppercase())
47}
48
49/// Check if a string contains only lowercase characters.
50pub fn is_lowercase(s: &str) -> bool {
51    s.chars().all(|c| !c.is_alphabetic() || c.is_lowercase())
52}
53
54/// Test if an identifier should be considered a modifier rule.
55pub fn test_for_modifier(identifier: &str) -> bool {
56    if is_uppercase(identifier) {
57        true
58    } else {
59        false
60    }
61}
62
63/// Test if an identifier should be considered an assignment rule.
64pub fn test_for_assignment(identifier: &str) -> bool {
65    if is_lowercase(identifier) {
66        true
67    } else {
68        false
69    }
70}
71
72/// Initialize rule flags based on an identifier.
73fn init_flags(identifier: &str) -> Flags {
74    let mut flags = Flags::empty();
75    if test_for_modifier(&identifier) {
76        flags.insert(Flags::IS_MODIFIER);
77    }
78    if test_for_assignment(&identifier) {
79        flags.insert(Flags::IS_ASSIGNMENT);
80    }
81    flags
82}
83
84// ----- RULE -----
85
86/// Single AIM rule: identifier, typedef, expression, and value.
87///
88/// Constructors perform identifier-based classification and optional
89/// static folding of constant expressions into `value`.
90#[derive(Debug, Clone, PartialEq)]
91pub struct Rule {
92    /// Rule identifier
93    identifier: Arc<str>,
94    /// Rule type definition
95    typedef: Typedef,
96    /// Rule expression
97    expression: Expression,
98    /// Rule value
99    value: Arc<Value>,
100    /// Internal flags
101    flags: Flags,
102}
103
104impl Rule {
105    /// Create a new Rule with the given components
106    ///
107    /// # Parameters
108    /// - `identifier`: The rule's unique identifier
109    /// - `typedef`: The type definition for the rule
110    /// - `expression`: The expression that computes the rule's value
111    /// - `value`: The initial value of the rule
112    ///
113    /// # Returns
114    /// A new Rule instance with appropriate flags set based on the identifier
115    ///
116    /// # Notes
117    /// - Automatically performs static evaluation of expressions when possible
118    /// - Sets flags based on identifier format (modifier/assignment)
119    pub fn new(identifier: Arc<str>, typedef: Typedef, expression: Expression, value: Arc<Value>) -> Self {
120        let mut flags = init_flags(&identifier);
121        if expression.is_empty() || expression.is_branch() || expression.is_retry() {
122            Self {
123                identifier,
124                typedef,
125                expression,
126                value,
127                flags,
128            }
129        } else {
130            let (static_exp, static_val) = match statically_evaluate(&expression) {
131                Ok(value) => {
132                    flags.insert(Flags::IS_STATIC);
133                    (Expression::Empty, value)
134                }
135                _ => (expression, Value::empty()),
136            };
137            Self {
138                identifier,
139                typedef,
140                expression: static_exp,
141                value: static_val,
142                flags,
143            }
144        }
145    }
146
147    pub fn convert(identifier: Arc<str>, typedef: Arc<str>, formula: Arc<str>, value: Arc<str>) -> Self {
148        Self::new(
149            identifier,
150            Typedef::convert(&typedef),
151            Expression::convert(&formula),
152            Value::convert(value)
153        )
154    }
155
156    /// Create a new Rule by parsing operands from a string
157    ///
158    /// This constructor parses the expression/value portion of a rule definition
159    /// based on the rule's type definition and assignment status.
160    ///
161    /// # Parameters
162    /// - `input`: The string containing the rule's operands
163    /// - `identifier`: The rule's identifier
164    /// - `typedef`: The rule's type definition
165    /// - `is_assignment`: Whether this is an assignment rule
166    ///
167    /// # Returns
168    /// A new Rule instance with parsed expression and value
169    ///
170    /// # Errors
171    /// Returns error expressions for incomplete or malformed input
172    pub fn parse(&self, input: &str) -> Self {
173        let identifier = self.identifier.clone();
174        let typedef = self.typedef.clone();
175        match parse_rule_operands(input, &self.typedef) {
176            Ok((_, (expression, value))) => Self::new(identifier, typedef, expression, value),
177            Err(nom::Err::Incomplete(_)) => {
178                let expression = Errata::new_expression(
179                    Arc::from("Incomplete Expression"),
180                    Arc::from(input),
181                );
182                Self::new(identifier, typedef, expression, Value::empty())
183            }
184            Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => {
185                let expression = Errata::new_expression_location(
186                    Arc::from(format!("Syntax Error ({})", e)),
187                    Arc::from(input),
188                    Arc::from(e.input),
189                );
190                Self::new(identifier, typedef, expression, Value::empty())
191            }
192        }
193    }
194
195    /// Check if the rule is completely empty (no expression and no value)
196    pub fn is_empty(&self) -> bool {
197        if self.expression.is_empty() && self.value.is_empty() {
198            true
199        } else {
200            false
201        }
202    }
203
204    /// Check if the rule contains any errors
205    pub fn is_error(&self) -> bool {
206        self.value.is_error() | self.expression.is_error()
207    }
208
209    /// Check if the rule has a non-empty expression
210    pub fn has_expression(&self) -> bool {
211        match &self.expression {
212            Expression::Empty | Expression::Errata { .. } => false,
213            _ => true,
214        }
215    }
216
217    /// Get the rule's identifier
218    pub fn identifier(&self) -> Arc<str> {
219        self.identifier.clone()
220    }
221
222    /// Get the uppercase form of the identifier.
223    ///
224    /// Non-alphabetic characters (such as `_` or digits) are preserved; only
225    /// alphabetic characters are converted to uppercase.
226    pub fn ucid(&self) -> Arc<str> {
227        Arc::from(self.identifier.to_uppercase())
228    }
229
230    /// Get the lowercase form of the identifier.
231    ///
232    /// Non-alphabetic characters (such as `_` or digits) are preserved; only
233    /// alphabetic characters are converted to lowercase.
234    pub fn lcid(&self) -> Arc<str> {
235        Arc::from(self.identifier.to_lowercase())
236    }
237
238    /// Set a new identifier for the rule
239    ///
240    /// Updates the identifier and automatically adjusts flags based on the new identifier format
241    pub fn set_identifier(&mut self, identifier: Arc<str>) -> bool {
242        // Updating the identifier potentially changes a lot of flags
243        if self.identifier != identifier {
244            // Update flags
245            if test_for_modifier(&identifier) {
246                self.flags.insert(Flags::IS_MODIFIER);
247            } else {
248                self.flags.remove(Flags::IS_MODIFIER);
249            }
250            if test_for_assignment(&identifier) {
251                self.flags.insert(Flags::IS_ASSIGNMENT);
252            } else {
253                self.flags.remove(Flags::IS_ASSIGNMENT);
254            }
255            self.identifier = identifier;
256            true
257        } else {
258            false
259        }
260    }
261
262    /// Check if this is a modifier rule (all uppercase identifier)
263    pub fn is_modifier(&self) -> bool {
264        self.flags.contains(Flags::IS_MODIFIER)
265    }
266
267    /// Check if this is an assignment rule (identifier starts with underscore)
268    pub fn is_assignment(&self) -> bool {
269        self.flags.contains(Flags::IS_ASSIGNMENT)
270    }
271
272    /// Get the rule's type definition
273    pub fn typedef(&self) -> &Typedef {
274        &self.typedef
275    }
276
277    /// Set a new type definition for the rule
278    ///
279    /// Resets the value to empty and marks the rule as touched
280    /// 
281    /// # Returns
282    /// `true` if the rule changed, else `false` 
283    pub fn set_typedef(&mut self, typedef: Typedef) -> bool {
284        if self.typedef != typedef {
285            match self.value.clone().to_type(&typedef) {
286                Ok(value) => self.value = value,
287                _ => self.value = Value::empty(),
288            }
289            self.typedef = typedef;
290            true
291        } else {
292            false
293        }
294    }
295
296    /// Get the rule's expression
297    pub fn expression(&self) -> &Expression {
298        &self.expression
299    }
300
301    /// Set a new expression for the rule
302    ///
303    /// Marks the rule as touched if the expression differs from the current one
304    /// 
305    /// # Returns
306    /// `true` if the rule changed, else `false` 
307    pub fn set_expression(&mut self, expression: Expression) -> bool {
308        if self.expression.to_formula() != expression.to_formula() {
309            self.expression = expression;
310            true
311        } else {
312            false
313        }
314    }
315
316    /// Get the rule's current value
317    pub fn value(&self) -> Arc<Value> {
318        self.value.clone()
319    }
320
321    /// Set the rule's value
322    ///
323    /// # Parameters
324    /// The value to set. Must match `typedef` unless empty or error.
325    /// 
326    /// This function does not set special typedef values.
327    ///
328    /// # Returns
329    /// `Ok(())` if the value matches the rule's type, `Err` otherwise
330    pub fn set_value(&mut self, value: Arc<Value>) -> Result<()> {
331        if !self.typedef.is_special() && (value.is_empty() || value.is_error() || value.is_of_type(&self.typedef)) {
332            self.value = value;
333            Ok(())
334        } else {
335            Err(anyhow!(
336                "Type mismatch, expecting {} found {}",
337                self.typedef.as_str(),
338                value.type_as_string()
339            ))
340        }
341    }
342
343    pub fn rename_node(&self, identifier: Arc<str>) -> Result<Self> {
344        // Update the node's reference if it's a node-typed rule
345        if self.is_node() {
346            if let Some(old_node) = self.get_node() {
347                // Rename the reference with the updated identifier
348                let old_reference = old_node.reference()?;
349                let new_reference = Arc::new(old_reference.rename_child(identifier.clone()));
350                // Create a new unloaded node
351                let new_node = Node::init_new(new_reference, old_node.inference());
352                // Create the new rule value
353                let value = Arc::new(Value::Node(new_node));
354                // Create a new rule
355                Ok(Rule::new(identifier, self.typedef.clone(), Expression::Empty, value))
356            } else {
357                Err(anyhow!("Node missing from Rule {}", self.identifier))
358            }
359        } else {
360            Err(anyhow!("Type mismatch, expecting Node found {}", self.typedef.as_str()))
361        }
362    }
363    /// Check if this is a format rule
364    pub fn is_format(&self) -> bool {
365        self.typedef.is_format() && self.value.is_format()
366    }
367
368    /// Check if this is an evaluation rule
369    pub fn is_eval(&self) -> bool {
370        self.typedef.is_eval() && self.value.is_eval()
371    }
372
373    /// Mark an evaluation rule as passing
374    ///
375    /// Only affects rules with Eval type definitions
376    /// 
377    /// # Returns
378    /// `true` if the rule changed, else `false` 
379    pub fn set_pass(&mut self) -> Result<()> {
380        let value = self.value.to_pass()?;
381        self.set_value(Arc::new(value))
382    }
383
384    /// Mark an evaluation rule as failing
385    ///
386    /// Only affects rules with Eval type definitions
387    /// 
388    /// # Returns
389    /// `true` if the rule changed, else `false` 
390    pub fn set_fail(&mut self) -> Result<()> {
391        let value = self.value.to_fail()?;
392        self.set_value(Arc::new(value))
393    }
394
395    /// Check if this is a node rule
396    pub fn is_node(&self) -> bool {
397        self.typedef.is_node() && self.value.is_node()
398    }
399
400    /// Get the node from this rule if it is a node rule
401    ///
402    /// # Returns
403    /// `Some(Node)` if this is a node rule with a node value, `None` otherwise
404    pub fn get_node(&self) -> Option<Node> {
405        self.value.get_node()
406    }
407
408    pub fn get_instance(&self) -> Option<Instance> {
409        self.value.get_instance()
410    }
411
412    /// Write the rule's complete definition to a writer
413    ///
414    /// Outputs the rule in AIM format: `identifier: typedef = expression $value`
415    pub fn print(&self, writer: &mut Writer) {
416        writer.write_str(&self.identifier);
417        writer.write_str(": ");
418        self.typedef.print(writer);
419        writer.write_str(" = ");
420        if self.expression.is_empty() {
421            if self.value.is_constant() {
422                writer.write_char('$');
423            }
424            self.value.print(writer);
425        } else {
426            self.expression.print(writer);
427            if self.value.is_constant() {
428                writer.write_str(" $");
429                self.value.print(writer);
430            }
431        }
432    }
433
434}
435
436/// Parse a rule from a single AIM line.
437
438pub fn parse_rule(input: &str) -> Result<Rule> {
439    match parse_rule_elements(input).finish() {
440        Ok((_, rule)) => Ok(rule),
441        Err(e) => Err(anyhow!("Parse error: {}", e)),
442    }
443}
444
445/// Parse the raw elements of a rule line.
446
447fn parse_rule_elements(input: &str) -> IResult<&str, Rule> {
448    let (input, (_, identifier, _, typedef, _)) = (
449        multispace0,
450        parse_arc_identifier,
451        delimited(multispace0, char(':'), multispace0),
452        parse_typedef,
453        delimited(multispace0, char('='), multispace0),
454    ).parse(input)?;
455    let (input, (expression, value)) = parse_rule_operands(input, &typedef)?;
456    
457    Ok((input, Rule::new(identifier, typedef, expression, value)))
458}
459
460/// Parse the expression and value operands of a rule.
461fn parse_rule_operands<'a>(
462    input: &'a str,
463    typedef: &Typedef,
464) -> IResult<&'a str, (Expression, Arc<Value>)> {
465    // Parse expression `$` value
466    let input = input.trim(); // S?
467
468    // The parsing strategy depends on the typedef:
469    let (input, value) = if input.is_empty() {
470        // - Empty input results in `Expression::Empty`
471        if typedef.is_format() || typedef.is_instance() {
472            // Format and instance should never be empty
473            return Err(nom::Err::Error(Error::new(input, ErrorKind::Fail)));
474        } else if typedef.is_node() {
475            // Node types should create a default node when empty
476            let node = Node::default();
477            (input, Arc::new(Value::Node(node)))
478        } else {
479            (input, Value::empty())
480        }
481    } else if input.starts_with('$') {
482        // - Constant values are from statically evaluated expressions
483        let (input, _) = char('$')(input)?;
484        let (input, value) = parse_value(input)?;
485        (input, value)
486    } else if typedef.is_closure() {
487        // - Closure types are parsed as args => expression
488        let (input, closure) = parse_closure(input)?;
489        (input, Arc::new(Value::Closure(Arc::new(closure))))
490    } else if typedef.is_eval() {
491        // - Eval types are parsed as ratio, score, count
492        let (input, eval) = parse_eval(input)?;
493        (input, Arc::new(Value::Eval(eval)))
494    } else if typedef.is_format() {
495        // - Format types are parsed as "Instruction" <format> "Example", "Example", "Example"...
496        let (input, format) = parse_format(input)?;
497        (input, Arc::new(Value::Format(format)))
498    } else if typedef.is_instance() {
499        // - Instance types are parsed as source, target
500        let (input, instance) = parse_instance(input)?;
501        (input, Arc::new(Value::Instance(instance)))
502    } else if typedef.is_node() {
503        // - Node types are parsed as pattern, model
504        let (input, node) = parse_node(input)?;
505        (input, Arc::new(Value::Node(node)))
506    } else {
507        // - Expression types are parsed as normal
508        let (input, expression) = if typedef.is_branch() {
509            let (input, branch) = parse_branch(input)?;
510            (input, Expression::Branch(branch))
511        } else if typedef.is_retry() {
512            let (input, retry) = parse_retry(input)?;
513            (input, Expression::Retry(retry))
514        } else {
515            // Parse expression
516            parse_expression(input)?
517        };
518        let (input, _) = multispace0(input)?; // S?
519        let (input, value) = if input.starts_with('$') {
520            let (input, _) = char('$')(input)?;
521            let (input, value) = parse_value(input)?;
522            (input, value)
523        } else {
524            (input, Value::empty())
525        };
526        return Ok((input, (expression, value)));
527    };
528    Ok((input, (Expression::Empty, value)))
529}
530
531impl ExpressionLike for Rule {
532    /// Evaluate the rule's expression and return a [`Value`], handling errors
533    /// gracefully, or if empty, return the rule's value.
534    ///
535    /// - If `expression` is non-empty, this evaluates the expression.
536    /// - If `expression` is empty, this returns a clone of the stored `value`.
537    ///
538    /// This method evaluates the rule expression in the given context.
539    ///
540    /// - If the expression is empty, returns the stored value.
541    /// - If the expression is non-empty, delegates to the underlying
542    ///   [`ExpressionLike::evaluate`] implementation.
543    ///
544    /// # Arguments
545    ///
546    /// * `context` - The evaluation context providing variable values and function implementations
547    ///
548    /// # Returns
549    ///
550    /// Returns a [`Value`] representing the result of evaluation. If evaluation
551    /// succeeds, returns the computed value. If evaluation fails, returns an
552    /// [`Errata`] value containing error information.
553    ///
554    /// # See Also
555    ///
556    /// - [`ExpressionLike::evaluate`] - The underlying evaluation method that returns [`Result`]
557    /// - [`Value`] - The result type returned by evaluation
558    fn evaluate(&self, context: &mut dyn ContextLike) -> Result<Arc<Value>> {
559        if self.expression.is_empty() {
560            Ok(self.value.clone())
561        } else {
562            self.expression.evaluate(context)
563        }
564    }
565
566    /// Return the formula-string representation (round-trippable by the parser).
567    fn to_formula(&self) -> String {
568        let mut writer = Writer::formulizer();
569        self.print(&mut writer);
570        writer.finish()
571    }
572}
573
574impl WriterLike for Rule {
575    fn write(&self, writer: &mut Writer) {
576        self.print(writer);
577    }
578}
579
580impl fmt::Display for Rule {
581    /// Display the rule's content (expression or value) for user-facing output
582    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
583        let mut writer = Writer::formulizer();
584        if self.value.is_empty() {
585            self.expression.print(&mut writer);
586        } else {
587            self.value.print(&mut writer);
588        }
589        write!(f, "{}", writer.finish())
590    }
591}