mod matcher;
mod vm;
mod leaf;
mod meta;
mod structure;
pub mod dcbor_integration;
use std::{
cell::RefCell,
collections::HashMap,
ops::{RangeBounds, RangeInclusive},
};
use bc_envelope::prelude::*;
use known_values::KnownValue;
pub use matcher::{Matcher, Path, compile_as_atomic};
use self::{
leaf::{
ArrayPattern, BoolPattern, ByteStringPattern, DatePattern,
KnownValuePattern, LeafPattern, MapPattern, NullPattern, NumberPattern,
TextPattern,
},
meta::{
AndPattern, AnyPattern, CapturePattern, GroupPattern, MetaPattern,
NotPattern, OrPattern, SearchPattern, TraversePattern,
},
structure::{
AssertionsPattern, DigestPattern, LeafStructurePattern, NodePattern,
ObjectPattern, ObscuredPattern, PredicatePattern, StructurePattern,
SubjectPattern, WrappedPattern,
},
};
use crate::{
DCBORPattern, Quantifier, Reluctance,
pattern::{leaf::CBORPattern, vm::Instr},
};
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum Pattern {
Leaf(LeafPattern),
Structure(StructurePattern),
Meta(MetaPattern),
}
impl Matcher for Pattern {
fn paths_with_captures(
&self,
haystack: &Envelope,
) -> (Vec<Path>, HashMap<String, Vec<Path>>) {
let results = self.vm_run(haystack);
let mut paths = Vec::new();
let mut captures: HashMap<String, Vec<Path>> = HashMap::new();
for (p, caps) in results {
paths.push(p);
for (name, mut vals) in caps {
captures.entry(name).or_default().append(&mut vals);
}
}
(paths, captures)
}
fn is_complex(&self) -> bool {
match self {
Pattern::Leaf(leaf) => leaf.is_complex(),
Pattern::Structure(structure) => structure.is_complex(),
Pattern::Meta(meta) => meta.is_complex(),
}
}
}
impl Pattern {
pub fn any_cbor() -> Self {
Pattern::Leaf(LeafPattern::Cbor(CBORPattern::any()))
}
pub fn cbor(cbor: impl CBOREncodable) -> Self {
Pattern::Leaf(LeafPattern::Cbor(CBORPattern::value(cbor)))
}
pub fn cbor_pattern(pattern: DCBORPattern) -> Self {
Pattern::Leaf(LeafPattern::Cbor(CBORPattern::pattern(pattern)))
}
}
impl Pattern {
pub fn any_bool() -> Self {
Pattern::Leaf(LeafPattern::Bool(BoolPattern::any()))
}
pub fn bool(b: bool) -> Self {
Pattern::Leaf(LeafPattern::Bool(BoolPattern::value(b)))
}
}
impl Pattern {
pub fn any_text() -> Self {
Pattern::Leaf(LeafPattern::Text(TextPattern::any()))
}
pub fn text<T: Into<String>>(value: T) -> Self {
Pattern::Leaf(LeafPattern::Text(TextPattern::value(value)))
}
pub fn text_regex(regex: regex::Regex) -> Self {
Pattern::Leaf(LeafPattern::Text(TextPattern::regex(regex)))
}
}
impl Pattern {
pub fn any_date() -> Self {
Pattern::Leaf(LeafPattern::Date(DatePattern::any()))
}
pub fn date(date: Date) -> Self {
Pattern::Leaf(LeafPattern::Date(DatePattern::value(date)))
}
pub fn date_range(range: RangeInclusive<Date>) -> Self {
Pattern::Leaf(LeafPattern::Date(DatePattern::range(range)))
}
pub fn date_earliest(date: Date) -> Self {
Pattern::Leaf(LeafPattern::Date(DatePattern::earliest(date)))
}
pub fn date_latest(date: Date) -> Self {
Pattern::Leaf(LeafPattern::Date(DatePattern::latest(date)))
}
pub fn date_iso8601(iso_string: impl Into<String>) -> Self {
Pattern::Leaf(LeafPattern::Date(DatePattern::string(iso_string)))
}
pub fn date_regex(regex: regex::Regex) -> Self {
Pattern::Leaf(LeafPattern::Date(DatePattern::regex(regex)))
}
}
impl Pattern {
pub fn any_number() -> Self {
Pattern::Leaf(LeafPattern::Number(NumberPattern::any()))
}
pub fn number<T: Into<f64>>(value: T) -> Self {
Pattern::Leaf(LeafPattern::Number(NumberPattern::exact(value)))
}
pub fn number_range<A: Into<f64> + Copy>(range: RangeInclusive<A>) -> Self {
Pattern::Leaf(LeafPattern::Number(NumberPattern::range(range)))
}
pub fn number_greater_than<T: Into<f64>>(value: T) -> Self {
Pattern::Leaf(LeafPattern::Number(NumberPattern::greater_than(value)))
}
pub fn number_greater_than_or_equal<T: Into<f64>>(value: T) -> Self {
Pattern::Leaf(LeafPattern::Number(
NumberPattern::greater_than_or_equal(value),
))
}
pub fn number_less_than<T: Into<f64>>(value: T) -> Self {
Pattern::Leaf(LeafPattern::Number(NumberPattern::less_than(value)))
}
pub fn number_less_than_or_equal<T: Into<f64>>(value: T) -> Self {
Pattern::Leaf(LeafPattern::Number(NumberPattern::less_than_or_equal(
value,
)))
}
pub fn number_nan() -> Self {
Pattern::Leaf(LeafPattern::Number(NumberPattern::nan()))
}
}
impl Pattern {
pub fn any_byte_string() -> Self {
Pattern::Leaf(LeafPattern::ByteString(ByteStringPattern::any()))
}
pub fn byte_string(value: impl AsRef<[u8]>) -> Self {
Pattern::Leaf(LeafPattern::ByteString(ByteStringPattern::value(value)))
}
pub fn byte_string_binary_regex(regex: regex::bytes::Regex) -> Self {
Pattern::Leaf(LeafPattern::ByteString(ByteStringPattern::regex(regex)))
}
}
impl Pattern {
pub fn any_known_value() -> Self {
Pattern::Leaf(LeafPattern::KnownValue(KnownValuePattern::any()))
}
pub fn known_value(value: KnownValue) -> Self {
Pattern::Leaf(LeafPattern::KnownValue(KnownValuePattern::value(value)))
}
pub fn known_value_named<T: Into<String>>(name: T) -> Self {
Pattern::Leaf(LeafPattern::KnownValue(KnownValuePattern::named(name)))
}
pub fn known_value_regex(regex: regex::Regex) -> Self {
Pattern::Leaf(LeafPattern::KnownValue(KnownValuePattern::regex(regex)))
}
pub fn unit() -> Self { Self::known_value(known_values::UNIT) }
}
impl Pattern {
pub fn any_array() -> Self {
Pattern::Leaf(LeafPattern::Array(ArrayPattern::any()))
}
pub fn array_with_range(interval: impl RangeBounds<usize>) -> Self {
Pattern::Leaf(LeafPattern::Array(ArrayPattern::interval(interval)))
}
pub fn array_with_count(count: usize) -> Self {
Pattern::Leaf(LeafPattern::Array(ArrayPattern::count(count)))
}
pub fn array_from_dcbor_pattern(pattern: DCBORPattern) -> Self {
Pattern::Leaf(LeafPattern::Array(ArrayPattern::from_dcbor_pattern(
pattern,
)))
}
}
impl Pattern {
pub fn any_map() -> Self {
Pattern::Leaf(LeafPattern::Map(MapPattern::any()))
}
pub fn map_with_range(interval: impl RangeBounds<usize>) -> Self {
Pattern::Leaf(LeafPattern::Map(MapPattern::interval(interval)))
}
pub fn map_with_count(count: usize) -> Self {
Pattern::Leaf(LeafPattern::Map(MapPattern::interval(count..=count)))
}
}
impl Pattern {
pub fn null() -> Self { Pattern::Leaf(LeafPattern::Null(NullPattern)) }
}
impl Pattern {
pub fn any_tag() -> Self {
Pattern::Leaf(crate::pattern::leaf::LeafPattern::Tag(
crate::pattern::leaf::TaggedPattern::any(),
))
}
pub fn tagged(tag: impl Into<Tag>, pattern: DCBORPattern) -> Self {
Pattern::Leaf(crate::pattern::leaf::LeafPattern::Tag(
crate::pattern::leaf::TaggedPattern::with_tag(tag, pattern),
))
}
pub fn tagged_name(name: impl Into<String>, pattern: DCBORPattern) -> Self {
Pattern::Leaf(crate::pattern::leaf::LeafPattern::Tag(
crate::pattern::leaf::TaggedPattern::with_name(
name.into(),
pattern,
),
))
}
pub fn tagged_regex(regex: regex::Regex, pattern: DCBORPattern) -> Self {
Pattern::Leaf(crate::pattern::leaf::LeafPattern::Tag(
crate::pattern::leaf::TaggedPattern::with_regex(regex, pattern),
))
}
pub(crate) fn tagged_from_dcbor_pattern(
tagged_pattern: dcbor_pattern::TaggedPattern,
) -> Self {
Pattern::Leaf(crate::pattern::leaf::LeafPattern::Tag(
crate::pattern::leaf::TaggedPattern::from_dcbor_pattern(
tagged_pattern,
),
))
}
}
impl Pattern {
pub fn leaf() -> Self {
Pattern::Structure(StructurePattern::Leaf(LeafStructurePattern::new()))
}
pub fn any_assertion() -> Self {
Pattern::Structure(StructurePattern::Assertions(
AssertionsPattern::any(),
))
}
pub fn assertion_with_predicate(pattern: Pattern) -> Self {
Pattern::Structure(StructurePattern::Assertions(
AssertionsPattern::with_predicate(pattern),
))
}
pub fn assertion_with_object(pattern: Pattern) -> Self {
Pattern::Structure(StructurePattern::Assertions(
AssertionsPattern::with_object(pattern),
))
}
}
impl Pattern {
pub fn any_subject() -> Self {
Pattern::Structure(StructurePattern::Subject(SubjectPattern::any()))
}
pub fn subject(pattern: Pattern) -> Self {
Pattern::Structure(StructurePattern::Subject(SubjectPattern::pattern(
pattern,
)))
}
}
impl Pattern {
pub fn any_predicate() -> Self {
Pattern::Structure(StructurePattern::Predicate(PredicatePattern::any()))
}
pub fn predicate(pattern: Pattern) -> Self {
Pattern::Structure(StructurePattern::Predicate(
PredicatePattern::pattern(pattern),
))
}
pub fn any_object() -> Self {
Pattern::Structure(StructurePattern::Object(ObjectPattern::any()))
}
pub fn object(pattern: Pattern) -> Self {
Pattern::Structure(StructurePattern::Object(ObjectPattern::pattern(
pattern,
)))
}
}
impl Pattern {
pub fn digest(digest: bc_components::Digest) -> Self {
Pattern::Structure(StructurePattern::Digest(DigestPattern::digest(
digest,
)))
}
pub fn digest_prefix(prefix: impl AsRef<[u8]>) -> Self {
Pattern::Structure(StructurePattern::Digest(DigestPattern::prefix(
prefix,
)))
}
pub fn digest_binary_regex(regex: regex::bytes::Regex) -> Self {
Pattern::Structure(StructurePattern::Digest(
DigestPattern::binary_regex(regex),
))
}
pub fn any_node() -> Self {
Pattern::Structure(StructurePattern::Node(NodePattern::any()))
}
pub fn node_with_assertions_range(range: impl RangeBounds<usize>) -> Self {
Pattern::Structure(StructurePattern::Node(NodePattern::interval(range)))
}
pub fn node_with_assertions_count(count: usize) -> Self {
Pattern::Structure(StructurePattern::Node(NodePattern::interval(
count..=count,
)))
}
pub fn obscured() -> Self {
Pattern::Structure(StructurePattern::Obscured(ObscuredPattern::any()))
}
pub fn elided() -> Self {
Pattern::Structure(
StructurePattern::Obscured(ObscuredPattern::elided()),
)
}
pub fn encrypted() -> Self {
Pattern::Structure(StructurePattern::Obscured(
ObscuredPattern::encrypted(),
))
}
pub fn compressed() -> Self {
Pattern::Structure(StructurePattern::Obscured(
ObscuredPattern::compressed(),
))
}
}
impl Pattern {
pub fn any() -> Self { Pattern::Meta(MetaPattern::Any(AnyPattern::new())) }
}
impl Pattern {
pub fn and(patterns: Vec<Pattern>) -> Self {
Pattern::Meta(MetaPattern::And(AndPattern::new(patterns)))
}
pub fn or(patterns: Vec<Pattern>) -> Self {
Pattern::Meta(MetaPattern::Or(OrPattern::new(patterns)))
}
}
impl Pattern {
pub fn traverse(patterns: Vec<Pattern>) -> Self {
Pattern::Meta(MetaPattern::Traverse(TraversePattern::new(patterns)))
}
}
impl Pattern {
pub fn search(pattern: Pattern) -> Self {
Pattern::Meta(MetaPattern::Search(SearchPattern::new(pattern)))
}
}
impl Pattern {
pub fn not_matching(pattern: Pattern) -> Self {
Pattern::Meta(MetaPattern::Not(NotPattern::new(pattern)))
}
}
impl Pattern {
pub(crate) fn compile(
&self,
code: &mut Vec<Instr>,
lits: &mut Vec<Pattern>,
captures: &mut Vec<String>,
) {
use Pattern::*;
match self {
Leaf(leaf_pattern) => leaf_pattern.compile(code, lits, captures),
Structure(struct_pattern) => {
struct_pattern.compile(code, lits, captures)
}
Meta(meta_pattern) => meta_pattern.compile(code, lits, captures),
}
}
}
impl Pattern {
pub fn repeat(
pattern: Pattern,
interval: impl RangeBounds<usize>,
reluctance: Reluctance,
) -> Self {
Pattern::Meta(MetaPattern::Group(GroupPattern::repeat(
pattern,
Quantifier::new(interval, reluctance),
)))
}
pub fn group(pattern: Pattern) -> Self {
Pattern::Meta(MetaPattern::Group(GroupPattern::new(pattern)))
}
}
impl Pattern {
pub fn capture(name: impl AsRef<str>, pattern: Pattern) -> Self {
Pattern::Meta(MetaPattern::Capture(CapturePattern::new(name, pattern)))
}
}
impl std::fmt::Display for Pattern {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Pattern::Leaf(leaf) => write!(f, "{}", leaf),
Pattern::Structure(structure) => write!(f, "{}", structure),
Pattern::Meta(meta) => write!(f, "{}", meta),
}
}
}
impl Pattern {
fn vm_run(
&self,
env: &Envelope,
) -> Vec<(Path, HashMap<String, Vec<Path>>)> {
thread_local! {
static PROG: RefCell<HashMap<u64, vm::Program>> = RefCell::new(HashMap::new());
}
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
};
let mut h = DefaultHasher::new();
self.hash(&mut h);
let key = h.finish();
let prog = PROG
.with(|cell| cell.borrow().get(&key).cloned())
.unwrap_or_else(|| {
let mut p = vm::Program {
code: Vec::new(),
literals: Vec::new(),
capture_names: Vec::new(),
};
self.compile(
&mut p.code,
&mut p.literals,
&mut p.capture_names,
);
p.code.push(Instr::Accept);
PROG.with(|cell| {
cell.borrow_mut().insert(key, p.clone());
});
p
});
vm::run(&prog, env)
}
#[allow(dead_code)]
fn vm_paths(&self, env: &Envelope) -> Vec<Path> {
self.vm_run(env).into_iter().map(|(p, _)| p).collect()
}
pub(crate) fn collect_capture_names(&self, out: &mut Vec<String>) {
if let Pattern::Meta(meta) = self {
meta.collect_capture_names(out)
}
}
}
impl Pattern {
pub fn wrapped() -> Self {
Pattern::Structure(StructurePattern::Wrapped(WrappedPattern::new()))
}
pub fn unwrap_matching(pattern: Pattern) -> Self {
Pattern::Structure(StructurePattern::Wrapped(
WrappedPattern::unwrap_matching(pattern),
))
}
pub fn unwrap() -> Self {
Pattern::Structure(StructurePattern::Wrapped(WrappedPattern::unwrap()))
}
}