ReNode

Struct ReNode 

Source
pub struct ReNode { /* private fields */ }
Expand description

A node in the abstract syntax tree (AST) of a regular expression.

Each ReNode stores a single operation (ReOp) and a set of lazily computed properties, such as:

  • Whether the expression is nullable (i.e., accepts the empty word)
  • Whether it is universal (i.e., accepts all words)
  • Whether it denotes the empty set or the empty word
  • Whether it has a constant prefix, suffix, or word
  • The first-character partition and alphabet
  • Whether it contains a complement or difference operation

All these properties are cached and evaluated on demand to improve performance.

Every ReNode has a unique identifier assigned by ReBuilder. This is unique across all regular expressions created by the same builder, which enables fast (i.e., O(1)) equality checking and hashing. Instances of this type are also superficially order by their ID.

Note: ReNode is not meant to be used directly. Use the Regex alias, which wraps it in a reference-counted pointer.

§Cheap Cloning

The subexpressions of a regular expression are stored as reference-counted pointers (Regex) in the ReOp variant that defines the operation. All derived properties are lazily computed and cached using interior mutability. As a result, cloning a regular expression is inexpensive: it only increments the reference count to shared subexpressions and cached data. This makes it efficient to clone and pass around regular expressions, even when they are large.

§Caching and Interior Mutability

This structure uses interior mutability (RefCell) to cache the derived properties. These caches do not affect the Hash, Ord, or Eq implementations, which rely solely on the unique id.

Therefore, it is safe to use ReNode (via Regex) as a key in hash maps or sets, even though Clippy may issue warnings about interior mutability. The warning clippy::mutable_key_type can be safely suppressed for this type using #[allow(clippy::mutable_key_type)]

Implementations§

Source§

impl ReNode

Source

pub fn id(&self) -> ReId

Returns the unique identifier of the regular expression. The ID assigned by the ReBuilder and unique across all regular expressions created by the same builder.

Source

pub fn op(&self) -> &ReOp

Returns the operation defining the regular expression.

§Example
use smt_str::re::*;

let mut builder = ReBuilder::default();
let re = builder.to_re("a".into());
assert_eq!(re.op(), &ReOp::Literal("a".into()));

let re_star = builder.star(re.clone());
assert_eq!(re_star.op(), &ReOp::Star(re));
Source

pub fn nullable(&self) -> bool

Returns whether the regular expression is nullable. A regular expression is nullable if it accepts the empty word.

§Example
use smt_str::re::*;
let mut builder = ReBuilder::default();
let re = builder.to_re("a".into());
let re_star = builder.star(re.clone());
assert!(!re.nullable());
assert!(re_star.nullable());
Source

pub fn simple(&self) -> bool

Returns whether the regular expression is simple. A regular expression is simple if it does not contain complement, difference, or intersection.

§Example
use smt_str::re::*;
use smallvec::smallvec;
let mut builder = ReBuilder::default();
let re_a = builder.to_re("a".into());
let re_star = builder.star(re_a.clone());
assert!(re_a.simple());
assert!(re_star.simple());

// Complement, difference, and intersection are not simple.

let re_comp = builder.comp(re_a.clone());
let re_diff = builder.diff(re_star.clone(), re_a.clone());
let re_inter = builder.inter(smallvec![re_star.clone(), re_a.clone()]);
assert!(!re_comp.simple());
assert!(!re_diff.simple());
assert!(!re_inter.simple());
Source

pub fn universal(&self) -> Option<bool>

Returns whether the regular expression is universal. A regular expression is universal if it accepts every word. This is determined heuristically based on the structure of the regular expression. As such, this operation may return None if the universality cannot be determined.

§Example
use smt_str::re::*;
use smallvec::smallvec;
let mut builder = ReBuilder::default();

assert_eq!(builder.all().universal(), Some(true));
assert_eq!(builder.none().universal(), Some(false));

// Universally can not always be determined.
let re_a = builder.to_re("a".into());
let diff = builder.diff(builder.all(), re_a.clone());
let union = builder.union(smallvec![diff, re_a.clone()]);

assert_eq!(union.universal(), None);
Source

pub fn none(&self) -> Option<bool>

Returns whether the regular expression is the empty set. A regular expression is the empty set if it does not accept any word. This operation may return None if the emptiness cannot be determined.

§Example
use smt_str::re::*;
use smallvec::smallvec;
let mut builder = ReBuilder::default();
assert_eq!(builder.none().none(), Some(true));
assert_eq!(builder.all().none(), Some(false));

let re_a = builder.to_re("a".into());
let re_comp = builder.comp(re_a.clone());
let inter = builder.inter(smallvec![re_a.clone(), re_comp.clone()]);

assert_eq!(re_a.none(), Some(false));
assert_eq!(re_comp.none(), Some(false));
assert_eq!(inter.none(), None);
Source

pub fn epsilon(&self) -> Option<bool>

Returns whether the regular expression denotes the empty word. A regular expression denotes the empty word if it only accepts the empty word. This operation may return None if the property cannot be determined.

§Example
use smt_str::re::*;
use smallvec::smallvec;
let mut builder = ReBuilder::default();

assert_eq!(builder.epsilon().epsilon(), Some(true));

let re_a = builder.to_re("a".into());
let re_b = builder.to_re("b".into());
let re_a_star = builder.star(re_a.clone());
let re_b_star = builder.opt(re_a.clone());
// The intersection contains only the empty word but we can't determine it.
let re_inter = builder.inter(smallvec![re_a_star.clone(), re_b_star.clone()]);
assert_eq!(re_inter.epsilon(), None);
Source

pub fn first(&self) -> Rc<AlphabetPartition>

Returns the set of characters that can be first in a word accepted by the regular expression. The set of first characters is partitioned into disjoint subsets of the alphabet, such that for each two characters a and b in the same subset, the left quotient of the regular expression w.r.t. a is equal to the left quotient of the regular expression w.r.t. b. In other words, if a and b are in the same subset, then for all words u, the regular expression accepts a \cdot u iff it accepts b \cdot u.

Source

pub fn alphabet(&self) -> Rc<Alphabet>

The alphabet of the regular expression. The alphabet is the set of characters that occur in the regular expression. This is not the alphabet of words that the regular expression can accept. For example, the alphabet of [^a] is {'a'}, but the alphabet of [^a] is every character except 'a'.

§Example
use smt_str::re::*;
use smt_str::alphabet::{Alphabet, CharRange};

use smallvec::smallvec;
let mut builder = ReBuilder::default();
let re_a = builder.to_re("a".into()); // 'a'
let re_b = builder.to_re("b".into()); // 'b'
let re_a_comp = builder.star(re_a.clone()); // comp('a')
let re_union = builder.union(smallvec![re_a_comp.clone(), re_b.clone()]); // comp('a') | 'b'

assert_eq!(re_a.alphabet().as_ref(), &Alphabet::from(CharRange::singleton('a')));
// even though `comp('a')` accepts words with any character from the SMT-LIB alphabet, the alphabet of the regex is still `{'a'}`.
assert_eq!(re_a_comp.alphabet().as_ref(), &Alphabet::from(CharRange::singleton('a')));
assert_eq!(
    re_union.alphabet().as_ref(),
    &Alphabet::from_iter(vec![CharRange::singleton('a'), CharRange::singleton('b')])
);
Source

pub fn is_constant(&self) -> Option<SmtString>

Returns Some(word) if the regular expression accepts only the given constant word, None otherwise or if it cannot be determined.

§Example
use smt_str::re::*;
use smallvec::smallvec;
let mut builder = ReBuilder::default();

let re_foo = builder.to_re("foo".into());
assert_eq!(re_foo.is_constant(), Some("foo".into()));

// Not a constant word
let re_opt = builder.opt(re_foo.clone());
assert_eq!(re_opt.is_constant(), None);

// Cannot be determined
let re_bar = builder.to_re("bar".into());
let re_foo_or_bar = builder.union(smallvec![re_foo.clone(), re_bar.clone()]);
let inter = builder.inter(smallvec![re_foo.clone(), re_foo_or_bar.clone()]); // foo & (foo | bar) <--> foo
assert_eq!(inter.is_constant(), None);
Source

pub fn prefix(&self) -> Option<SmtString>

Returns the prefix of all words accepted by the regular expression. Makes a best effort to obtain the longest prefix, but does not guarantee it. Is None if the prefix cannot be determined.

§Example
use smt_str::re::*;
use smallvec::smallvec;
let mut builder = ReBuilder::default();
let re_foo = builder.to_re("foo".into());

assert_eq!(re_foo.prefix(), Some("foo".into()));

let re_bar = builder.to_re("bar".into());
let re_foobar = builder.concat(smallvec![re_foo.clone(), re_bar.clone()]);

let union = builder.union(smallvec![re_foo.clone(), re_foobar.clone()]);
assert_eq!(union.prefix(), Some("foo".into()));
Source

pub fn suffix(&self) -> Option<SmtString>

Returns the suffix of all words accepted by the regular expression. Makes a best effort to obtain the longest suffix, but does not guarantee it. Is None if the suffix cannot be determined, which is the case for some extended regexes.

§Example
use smt_str::re::*;
use smallvec::smallvec;
let mut builder = ReBuilder::default();
let re_bar = builder.to_re("bar".into());

assert_eq!(re_bar.suffix(), Some("bar".into()));

let re_foo = builder.to_re("foo".into());
let re_foobar = builder.concat(smallvec![re_foo.clone(), re_bar.clone()]);

let union = builder.union(smallvec![re_bar.clone(), re_foobar.clone()]);
assert_eq!(union.suffix(), Some("bar".into()));
Source

pub fn contains_complement(&self) -> bool

Returns whether the regular expression contains a complement operation.

§Example
use smt_str::re::*;
use smallvec::smallvec;
let mut builder = ReBuilder::default();
let re_a = builder.to_re("a".into());
let re_b = builder.to_re("b".into());
let re_a_comp = builder.comp(re_a.clone());

assert!(!re_a.contains_complement());
assert!(re_a_comp.contains_complement());

// Difference is equivalent to complement
let diff = builder.diff(re_a.clone(), re_b.clone());
assert!(diff.contains_complement());
Source

pub fn accepts(&self, w: &SmtString) -> bool

Return whether the regular expression accepts a given word.

§Example
use smt_str::re::*;
let mut builder = ReBuilder::default();
let re_a = builder.to_re("a".into());
let re_star = builder.star(re_a.clone());
assert!(re_star.accepts(&"a".into()));
assert!(re_star.accepts(&"aaaa".into()));
assert!(re_star.accepts(&"".into()));
Source

pub fn subexpr(&self) -> SubExpressions<'_>

Returns an iterator over the subexpressions of the regular expression.

The subexpressions of a regular expression are the direct children of the operation defining the regex. If the regex is a base case (literal, range, none, any, all), it has no subexpressions.

§Example
use smt_str::re::*;
use smallvec::smallvec;

let mut builder = ReBuilder::default();
let re_a = builder.to_re("a".into());
let re_star = builder.star(re_a.clone());
let re_b = builder.to_re("b".into());
let re_union = builder.union(smallvec![re_star.clone(), re_b.clone()]);

let mut subexprs = re_union.subexpr();
assert_eq!(subexprs.next(), Some(&re_star));
assert_eq!(subexprs.next(), Some(&re_b));
assert_eq!(subexprs.next(), None);

Trait Implementations§

Source§

impl Arbitrary for ReNode

Source§

fn arbitrary(g: &mut Gen) -> Self

Return an arbitrary value. Read more
Source§

fn shrink(&self) -> Box<dyn Iterator<Item = Self>>

Return an iterator of values that are smaller than itself. Read more
Source§

impl Clone for ReNode

Source§

fn clone(&self) -> ReNode

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ReNode

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ReNode

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Hash for ReNode

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl Index<usize> for ReNode

Source§

fn index(&self, index: usize) -> &Self::Output

Returns the subexpression at the given index. If the index is out of bounds, this function panics. This function always panics on regular expressions that have no subexpressions, i.e., literals, ranges, none, any, and all.

Source§

type Output = Rc<ReNode>

The returned type after indexing.
Source§

impl Ord for ReNode

Source§

fn cmp(&self, other: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl PartialEq for ReNode

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl PartialOrd for ReNode

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl Eq for ReNode

Auto Trait Implementations§

§

impl !Freeze for ReNode

§

impl !RefUnwindSafe for ReNode

§

impl !Send for ReNode

§

impl !Sync for ReNode

§

impl Unpin for ReNode

§

impl !UnwindSafe for ReNode

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Comparable<K> for Q
where Q: Ord + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V