|
| 1 | +//! This module defines the abstract syntax tree (AST) for the filter expressions. |
| 2 | +//! Parsing module will convert the input string into this AST structure. |
| 3 | +//! This AST is then traversed and interpreted by the evaluation module (via helpers::evaluate) to determine the result of the filter expression. |
| 4 | +//! |
| 5 | +//! The AST is designed to be a direct representation of the parsed filter expression, capturing it's structure, operators and literal values. |
| 6 | +//! Lifetime annotations (`'a`) are used to ensure that the references to string literals are valid for the duration of the expression evaluation. |
| 7 | +
|
| 8 | +/// Represents the possible literal values that can be used in filter expressions. |
| 9 | +/// The `LiteralValue` enum captures the different constant values that are used on the right side of a condition (RHS). |
| 10 | +#[derive(Debug, Clone, PartialEq, Eq)] |
| 11 | +pub enum LiteralValue<'a> { |
| 12 | + /// A boolean literal value. |
| 13 | + Bool(bool), |
| 14 | + /// A string literal value. Includes both single-quoted and unquoted strings, includes hexadecimal strings. |
| 15 | + /// e.g., "abc", 'abc', '0x123ABC' |
| 16 | + Str(&'a str), |
| 17 | + /// A numeric literal value. e.g., "123", "-123.456", "0x123" or hexadecimal |
| 18 | + /// Store as string slice to preserve original form until evaluation phase. |
| 19 | + /// Conversion to specific type is done within chain context during evaluation. |
| 20 | + Number(&'a str), |
| 21 | +} |
| 22 | + |
| 23 | +/// Represents the possible comparison operators that can be used in filter expressions. |
| 24 | +#[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 25 | +pub enum ComparisonOperator { |
| 26 | + /// Equality operator (==) |
| 27 | + Eq, |
| 28 | + /// Inequality operator (!=) |
| 29 | + Ne, |
| 30 | + /// Greater than operator (>) |
| 31 | + Gt, |
| 32 | + /// Greater than or equal to operator (>=) |
| 33 | + Gte, |
| 34 | + /// Less than operator (<) |
| 35 | + Lt, |
| 36 | + /// Less than or equal to operator (<=) |
| 37 | + Lte, |
| 38 | + /// String/collection comparison operators: |
| 39 | + /// - StartsWith: Checks if the string/collection starts with a given item. |
| 40 | + StartsWith, |
| 41 | + /// - EndsWith: Checks if the string/collection ends with a given item. |
| 42 | + EndsWith, |
| 43 | + /// - Contains: Checks if the string/collection contains a given item. |
| 44 | + Contains, |
| 45 | +} |
| 46 | + |
| 47 | +/// Represents the possible logical operators that can be used in filter expressions. |
| 48 | +#[derive(Debug, Clone, PartialEq, Eq)] |
| 49 | +pub enum LogicalOperator { |
| 50 | + /// Logical AND operator (&&) |
| 51 | + And, |
| 52 | + /// Logical OR operator (||) |
| 53 | + Or, |
| 54 | +} |
| 55 | + |
| 56 | +/// Represents the possible accessors that can be used in filter expressions. |
| 57 | +/// Accessors are used to access elements in collections or properties in objects. |
| 58 | +#[derive(Debug, Clone, PartialEq, Eq)] |
| 59 | +pub enum Accessor<'a> { |
| 60 | + /// Accessor for a collection index (e.g., [0], [1], etc.) |
| 61 | + Index(usize), |
| 62 | + /// Accessor for a property name (e.g., .name, .age, etc.) |
| 63 | + Key(&'a str), |
| 64 | +} |
| 65 | + |
| 66 | +#[derive(Debug, Clone, PartialEq, Eq)] |
| 67 | +pub struct VariablePath<'a> { |
| 68 | + pub base: &'a str, |
| 69 | + pub accessors: Vec<Accessor<'a>>, |
| 70 | +} |
| 71 | + |
| 72 | +/// Represents the left side of a condition (LHS) in a filter expression. |
| 73 | +/// The left side can either be a simple variable name or a path to a variable. |
| 74 | +#[derive(Debug, Clone, PartialEq, Eq)] |
| 75 | +pub enum ConditionLeft<'a> { |
| 76 | + /// A simple variable name (e.g., "name", "age", etc.) |
| 77 | + /// This is a direct reference to a variable in the data structure. |
| 78 | + Simple(&'a str), |
| 79 | + /// A sequence of accessors that form a path to a variable (e.g., "person.name", "person[0].age", etc.) |
| 80 | + Path(VariablePath<'a>), |
| 81 | +} |
| 82 | + |
| 83 | +impl<'a> ConditionLeft<'a> { |
| 84 | + /// Helper method get the base name of the variable or path. |
| 85 | + pub fn base_name(&self) -> &'a str { |
| 86 | + match self { |
| 87 | + ConditionLeft::Simple(name) => name, |
| 88 | + ConditionLeft::Path(path) => path.base, |
| 89 | + } |
| 90 | + } |
| 91 | + |
| 92 | + /// Helper method to get the accessors of the variable path. |
| 93 | + /// If ConditionLeft is a simple variable, it returns an empty slice. |
| 94 | + /// If it is a path, it returns the accessors of that path. |
| 95 | + /// Used during evaluation to traverse nested structures. |
| 96 | + pub fn accessors(&self) -> &[Accessor] { |
| 97 | + match self { |
| 98 | + ConditionLeft::Simple(_) => &[], |
| 99 | + ConditionLeft::Path(path) => &path.accessors, |
| 100 | + } |
| 101 | + } |
| 102 | +} |
| 103 | + |
| 104 | +/// Represents a condition in a filter expression. |
| 105 | +/// A condition consists of a left side (LHS), an operator, and a right side (RHS). |
| 106 | +#[derive(Debug, Clone, PartialEq, Eq)] |
| 107 | +pub struct Condition<'a> { |
| 108 | + /// The left side of the condition (LHS). |
| 109 | + /// This can be a simple variable name or a path to a variable. |
| 110 | + pub left: ConditionLeft<'a>, |
| 111 | + /// The operator used in the condition (e.g., ==, !=, >, <, etc.) |
| 112 | + pub operator: ComparisonOperator, |
| 113 | + /// The right side of the condition (RHS). |
| 114 | + pub right: LiteralValue<'a>, |
| 115 | +} |
| 116 | + |
| 117 | +/// Represents a complete filter expression. |
| 118 | +/// An expression can be a single condition or a logical combination of multiple conditions. |
| 119 | +#[derive(Debug, Clone, PartialEq, Eq)] |
| 120 | +pub enum Expression<'a> { |
| 121 | + /// A simple condition (e.g., "age > 30") |
| 122 | + Condition(Condition<'a>), |
| 123 | + /// A logical combination of two expressions (e.g., "age > 30 && name == 'John'") |
| 124 | + /// `Box` is used to avoid infinite type recursion, as `Expression` can contain other `Expression`s. |
| 125 | + Logical { |
| 126 | + /// The left side sub-expression. |
| 127 | + left: Box<Expression<'a>>, |
| 128 | + /// The logical operator used to combine the two expressions: AND or OR. |
| 129 | + operator: LogicalOperator, |
| 130 | + /// The right side sub-expression. |
| 131 | + right: Box<Expression<'a>>, |
| 132 | + }, |
| 133 | +} |
0 commit comments