srch/
lib.rs

1//! This crate provides a library for parsing, compiling, and executing text expressions.
2//! The text expression syntax is kind of limited if compared to regular expressions, but
3//! maintains a high readability in exchange. It's not the goal of the text expression
4//! language to replace regular expression – it's meant to fill the lack of readability
5//! for simple tasks
6//!
7//! The text expression language was created in combination with the ter cli, a text
8//! expression runner to make the execution and common usecases of text expressions as
9//! easy as possible
10//!
11//! This crate's documentation provides some simple examples, describes the
12//! [supported syntax](#syntax) exhaustively.
13//!
14//! For more specific details on text expressions, please see the documentation for the
15//! [`TextExpression`](struct.TextExpression.html) struct.
16//!
17//! # Examples
18//!
19//! ## 5 digit numbers
20//!
21//! ```rust
22//! let expr = srch::Expression::new(&"numeric and length 5".to_owned()).unwrap();
23//! assert!(expr.matches("12345"));
24//! ```
25//!
26//! ## Naive email addresses
27//!
28//! ```rust
29//! let expr = srch::Expression::new(&"contains \"@\" and contains \".com\"".to_owned()).unwrap();
30//! assert!(expr.matches("foo@baz.com"));
31
32// ```
33//
34// ## Compiling a text expression only once
35// This is same problem as with regular expressions. It is an anti-pattern to
36// compile the same text expression in a loop since compilation is expensive.
37// It's recommended to use the [`lazy_static`](https://crates.io/crates/lazy_static)
38// crate to ensure that text expressions are compiled exactly once.
39//
40// For example:
41// ```rust
42// use lazy_static::lazy_static;
43// use srch::TextExpression;
44//
45// fn utility(text: &str) -> bool {
46// 	lazy_static! {
47// 		static ref TE: TextExpression = TextExpression::new(&"...".to_owned()).unwrap();
48// 	}
49//
50// 	TE.is_match(text)
51// }
52//
53// fn main() {}
54// ```
55//
56// Since this is a common problem this crate optionally exposes a macro for this:
57//
58// ```rust
59// let te = lazy_text_expr!("length 5");
60// ```
61//
62// To use this the `lazy` feature must be enabled in your `Cargo.toml`.
63//
64// ```toml
65// [dependencies]
66// srch = { version = "0.1", features = ["lazy"] }
67// ```
68//
69// So know we can simplify the code from the first lazy example to use `lazy_text_expr!`:
70//
71// ```rust
72// use srch::lazy_text_exr;
73//
74// fn utility(text: &str) -> bool {
75// 	lazy_text_expr!("...").is_match(text)
76// }
77//
78// fn main() {}
79// ```
80//
81// A lot cleaner, right? :) So now we know how we can use performant reusable text expressions!
82
83mod error;
84mod lexer;
85mod logical_operator;
86mod parser;
87mod query;
88mod runtime;
89
90pub use error::Result;
91pub use runtime::Runtime;
92
93pub fn into_ast(source: &String) -> Result<parser::AST> {
94    let tokens = lexer::lex(source)?;
95    let ast = parser::parse(tokens)?;
96    Ok(ast)
97}
98
99pub struct Expression {
100    runtime: Runtime,
101}
102
103impl Expression {
104    pub fn new(source: &String) -> Result<Self> {
105        let ast = into_ast(source.into())?;
106        let runtime = Runtime::new(ast);
107
108        Ok(Self { runtime })
109    }
110
111    pub fn matches(&self, input: impl AsRef<str>) -> bool {
112        self.runtime.run(input.as_ref())
113    }
114}