sqlexpr-congo-rust
This project provides a parser and evaluator for boolean expressions written in a SQL-like language. The language leverages SQL's simplicity and wide adoption, and is especially well-suited to represent end-user conditional logic, such as user-defined email routing or message queue selection. No SQL database is required.
The project contains a Rust parser and evaluator for SQL-like selector expressions, generated from a CongoCC grammar. The parser handles relational, comparison, and arithmetic expressions with SQL keywords (AND, OR, NOT, BETWEEN, LIKE, IN, IS NULL, etc.). The evaluator binds runtime values to variables in boolean expressions and then evaluates those expressions as either true or false.
Originally derived from an Apache ActiveMQ JMS message selector parser, the Rust code was generated from the CongoCC grammar file SqlExprParser.ccc using CongoCC's prototype Rust target support.
Related Project Catalog
The project is a part of a suite of production-ready and experimental projects that provide SQL-based boolean expression parsers and evaluators that use different technologies in their construction and output. Below is a summary of these projects.
| Project Name | Description |
|---|---|
| >>> Parsers and Evaluators <<< | |
| sqlexpr-javacc | Java parser and evaluator. JavaCC generated parser that incorporates Apache ActiveMQ JMS evaluator. |
| sqlexpr-congocc | Java parser and evaluator. CongoCC generated parser that incorporates Apache ActiveMQ JMS evaluator. |
| sqlexpr-rust | Rust parser and evaluator generated from EBNF specification by Claude (see NOTE below). |
| sqlexpr-congo-rust | Rust parser, evaluator and tests generated using the Enhanced CongoCC generator (congo-parser-generator) and Claude. |
| >>> Testers <<< | |
| sqlexpr-gen | Rust test data generator for sqlexpr-* parsers and evaluators. |
| sqlexpr-load-congocc | Java load tester for sqlexpr-congocc. |
| sqlexpr-load-rust | Rust load tester for sqlexpr-rust. |
| sqlexpr-load-congo-rust | Rust load tester for sqlexpr-congo-rust. |
| sqlexpr-javacc-test | Java integration tests for sqlexpr-javacc parser. |
| sqlexpr-congocc-test | Java integration tests for sqlexpr-congocc parser. |
| >>> CongoCC Rust Extension <<< | |
| congo-parser-generator | Experimental version of CongoCC enhanced by Claude to output Rust parsers. |
NOTE: The first Rust parser/evaluator, sqlexpr-rust, was generated by Claude directly from an EBNF grammar. Load testing in sqlexpr-load-rust reveals that this implementation was actually slower than the handcrafted Java parser generated by CongoCC (sqlexpr-congocc). The second Rust parser/evaluator, sqlexpr-congo-rust, was generated using CongoCC enhanced to directly output Rust parsers. Load testing in sqlexpr-load-congo-rust results in an approximate 2.5% improvement over the CongoCC-generated Java parser (in non-scientific testing). Further performance improvements can probably be wrung from the improved Rust parser, but it's clear that a well-designed, well-written Java parser is quite competitive in certain testing scenarios.
Supported Syntax
-- Boolean operators
x > 5 AND y < 10
a = 1 OR b = 2
NOT active
-- Comparison operators
price >= 100
name <> 'admin'
-- Arithmetic in comparisons
(a + b) * c > 100
-- LIKE with wildcards (% and _) and optional ESCAPE
name LIKE 'John%'
code LIKE 'A_B%' ESCAPE '\'
-- BETWEEN (inclusive, bounds checked at parse time)
age BETWEEN 18 AND 65
temp BETWEEN -10.5 AND 100.0
-- IN lists (type-homogeneous)
status IN ('active', 'pending', 'completed')
code IN (100, 200, 300)
-- NULL checks
value IS NULL
value IS NOT NULL
-- Literals: integers, hex, octal, floats, scientific notation, long suffix
x = 42
flags = 0xFF
perms = 0755
rate = 3.14e-2
big = 1000000L
-- String literals with escaped quotes
name = 'It''s a test'
-- Identifiers with $ and _
$variable > 0
_internal = TRUE
-- Comments
x > 5 -- line comment
x /* block comment */ > 5
Building
Running Tests
The test suite includes 876 tests across 7 test files covering the lexer, parser, evaluator, pretty-printer, and parse-time type checking.
Usage
Add this crate as a dependency (using a path or git reference):
[]
= { = "../sqlexpr-congo-rust" }
Evaluating Expressions
The simplest way to use the library is through the evaluate() function, which parses and evaluates an expression in one step:
use HashMap;
use ;
RuntimeValue variants:
RuntimeValue::Integer(i64)RuntimeValue::Float(f64)RuntimeValue::String(String)RuntimeValue::Boolean(bool)RuntimeValue::Null
Parsing and Inspecting the AST
For lower-level access, use the Parser directly to get the AST:
use ;
Traversing the AST
Use the visitor for depth-first traversal:
use ;
let input = "x > 5 AND y < 10";
let mut parser = new.unwrap;
let root = parser.parse.unwrap;
// Collect all variable names
let mut variables = Vecnew;
parser.arena.visit;
assert_eq!;
Error Handling
Parse errors include position information:
use ;
let result = new
.and_then;
if let Err = result
Evaluation errors are categorized:
use ;
use HashMap;
let vars = new;
let err = evaluate.unwrap_err;
match err
Project Layout
sqlexpr-congo-rust/
├── SqlExprParser.ccc # CongoCC grammar (source of truth for the language)
├── Cargo.toml # Rust package manifest
├── CLAUDE.md # Developer guidance for Claude Code
├── src/
│ ├── lib.rs # Crate root: module declarations and public re-exports
│ ├── main.rs # Example binary
│ ├── tokens.rs # TokenType enum and Token struct
│ ├── lexer.rs # Lexer/tokenizer
│ ├── parser.rs # Recursive-descent parser
│ ├── arena.rs # Arena allocator, AstNode enum, node structs, pretty_print()
│ ├── evaluator.rs # Expression evaluator
│ ├── visitor.rs # Depth-first AST visitor
│ └── error.rs # ParseError type
├── tests/
│ ├── lexer_test.rs # 129 lexer tests
│ ├── parser_test.rs # 164 parser/AST structure tests
│ ├── parser_test2.rs # 155 comprehensive parser feature tests
│ ├── parser_type_checking_tests.rs # 97 BETWEEN/IN type checking tests
│ ├── pretty_parse_test.rs # 10 pretty-print integration tests
│ ├── evaluator_test.rs # 130 evaluator tests
│ └── evaluator_test2.rs # 191 evaluator tests with variable bindings
├── LICENSE # MIT License
└── README.md # This file
AST Structure
The parser produces an arena-allocated AST. Each node is identified by a NodeId (a type-safe index). The expression hierarchy reflects operator precedence (lowest to highest):
| Node Type | Operators |
|---|---|
OrExpression |
OR |
AndExpression |
AND |
EqualityExpression |
=, <>, IS NULL, IS NOT NULL |
ComparisonExpression |
>, >=, <, <=, LIKE, NOT LIKE, BETWEEN, NOT BETWEEN, IN, NOT IN |
AddExpression |
+, - |
MultExpr |
*, /, % |
UnaryExpr |
+ (prefix), - (negate), NOT |
PrimaryExpr |
Parenthesized expressions, literals, variables |
Literal |
TRUE, FALSE, NULL, numeric literals |
StringLiteral |
Single-quoted strings |
Variable |
Identifiers |
Dependencies
- No runtime dependencies (zero-dependency by default)
- Optional:
serde(1.0) withderivefeature, enabled via theserdecargo feature for serializing/deserializing AST types
Serde Support
Enable the serde feature to derive Serialize and Deserialize on all AST node types, tokens, and error types:
[]
= { = "../sqlexpr-congo-rust", = ["serde"] }
Related Projects
- CongoCC - The parser generator used to produce this code
- sqlexpr-rust - A related SQL expression parser project; several test suites were ported from there to validate parity
License
This project is licensed under the MIT License. See LICENSE for details.
Acknowledgments
Anthopic's Claude Opus 4.6 was used to generate most of the code and documentation in this project.