Skip to main content

radixdb_sql/
precedence.rs

1// Copyright 2026 RadixDB Contributors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Operator precedence levels for the Pratt parser
16
17/// Precedence levels (higher number = higher precedence)
18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
19#[repr(u8)]
20#[derive(Default)]
21pub enum Precedence {
22    /// Lowest precedence
23    #[default]
24    Lowest = 1,
25    /// Logical operators (OR)
26    Or = 2,
27    /// Logical operators (AND)
28    And = 3,
29    /// NOT operator
30    Not = 4,
31    /// Comparison operators (=, <>, !=, IS, LIKE, IN, BETWEEN)
32    Equals = 5,
33    /// Comparison operators (<, >, <=, >=)
34    LessGreater = 6,
35    /// Bitwise OR (|)
36    BitwiseOr = 7,
37    /// Bitwise XOR (^)
38    BitwiseXor = 8,
39    /// Bitwise AND (&)
40    BitwiseAnd = 9,
41    /// Bitwise shift (<<, >>)
42    BitwiseShift = 10,
43    /// Addition and subtraction (+, -, ||)
44    Sum = 11,
45    /// Multiplication and division (*, /, %)
46    Product = 12,
47    /// Prefix operators (-, +, NOT, ~)
48    Prefix = 13,
49    /// Function calls
50    Call = 14,
51    /// Array/JSON index access ([])
52    Index = 15,
53    /// Dot notation (table.column)
54    Dot = 16,
55}
56
57impl Precedence {
58    /// Get precedence for an operator string
59    pub fn for_operator(op: &str) -> Precedence {
60        match op.to_uppercase().as_str() {
61            // Logical
62            "OR" => Precedence::Or,
63            "XOR" => Precedence::Or, // XOR has same precedence as OR
64            "AND" => Precedence::And,
65            "NOT" => Precedence::Not,
66
67            // Comparison
68            "=" | "<>" | "!=" | "IS" | "LIKE" | "ILIKE" | "GLOB" | "REGEXP" | "RLIKE" | "IN"
69            | "BETWEEN" => Precedence::Equals,
70            "<" | ">" | "<=" | ">=" | "<=>" | "&&" | "@>" | "<@" => Precedence::LessGreater,
71
72            // Bitwise operators (lower to higher precedence)
73            "|" => Precedence::BitwiseOr,
74            "^" => Precedence::BitwiseXor,
75            "&" => Precedence::BitwiseAnd,
76            "<<" | ">>" => Precedence::BitwiseShift,
77
78            // Arithmetic
79            "+" | "-" | "||" => Precedence::Sum,
80            "*" | "/" | "%" => Precedence::Product,
81
82            // Access
83            "." => Precedence::Dot,
84            "(" => Precedence::Call,
85            "[" => Precedence::Index,
86
87            // JSON operators
88            "->" | "->>" => Precedence::Index,
89
90            _ => Precedence::Lowest,
91        }
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[test]
100    fn test_precedence_ordering() {
101        assert!(Precedence::Product > Precedence::Sum);
102        assert!(Precedence::Sum > Precedence::LessGreater);
103        assert!(Precedence::LessGreater > Precedence::Equals);
104        assert!(Precedence::And > Precedence::Or);
105        assert!(Precedence::Dot > Precedence::Call);
106    }
107
108    #[test]
109    fn test_operator_precedence() {
110        assert_eq!(Precedence::for_operator("+"), Precedence::Sum);
111        assert_eq!(Precedence::for_operator("*"), Precedence::Product);
112        assert_eq!(Precedence::for_operator("AND"), Precedence::And);
113        assert_eq!(Precedence::for_operator("OR"), Precedence::Or);
114        assert_eq!(Precedence::for_operator("="), Precedence::Equals);
115        assert_eq!(Precedence::for_operator("."), Precedence::Dot);
116    }
117}