Pattern Registry
The PatternRegistry stores pattern definitions and provides lookup by name. It enables extensibility without modifying core compiler code.
Location
compiler/oric/src/patterns/registry.rs (~289 lines)
Structure
pub struct PatternRegistry {
/// Pattern name -> Definition
patterns: HashMap<Name, Arc<dyn PatternDefinition>>,
/// Interner for name resolution
interner: Arc<Interner>,
}
Registration
Built-in Patterns
impl PatternRegistry {
pub fn with_builtins(interner: Arc<Interner>) -> Self {
let mut registry = Self::new(interner);
// Data transformation
registry.register(MapPattern);
registry.register(FilterPattern);
registry.register(FoldPattern);
registry.register(FindPattern);
registry.register(CollectPattern);
// Control flow
registry.register(RunPattern);
registry.register(TryPattern);
registry.register(MatchPattern);
// Recursion
registry.register(RecursePattern);
// Concurrency
registry.register(ParallelPattern);
registry.register(SpawnPattern);
registry.register(TimeoutPattern);
registry.register(RetryPattern);
// Caching/validation
registry.register(CachePattern::new());
registry.register(ValidatePattern);
// Resource management
registry.register(WithPattern);
registry
}
}
Manual Registration
impl PatternRegistry {
pub fn register<P: PatternDefinition + 'static>(&mut self, pattern: P) {
let name = self.interner.intern(pattern.name());
self.patterns.insert(name, Arc::new(pattern));
}
pub fn register_arc(&mut self, pattern: Arc<dyn PatternDefinition>) {
let name = self.interner.intern(pattern.name());
self.patterns.insert(name, pattern);
}
}
Lookup
impl PatternRegistry {
/// Get pattern by name
pub fn get(&self, name: Name) -> Option<Arc<dyn PatternDefinition>> {
self.patterns.get(&name).cloned()
}
/// Check if name is a pattern
pub fn is_pattern(&self, name: Name) -> bool {
self.patterns.contains_key(&name)
}
/// Get all pattern names
pub fn pattern_names(&self) -> impl Iterator<Item = Name> + '_ {
self.patterns.keys().copied()
}
/// Find similar pattern names (for suggestions)
pub fn suggest_similar(&self, name: Name) -> Vec<Name> {
let target = self.interner.resolve(name);
self.patterns
.keys()
.filter(|&n| {
let s = self.interner.resolve(*n);
levenshtein_distance(target, s) <= 2
})
.copied()
.collect()
}
}
Usage in Type Checker
impl TypeChecker {
fn infer_pattern_call(
&mut self,
name: Name,
args: &[NamedArg],
) -> Result<Type, TypeError> {
// Get pattern from registry
let pattern = self.pattern_registry
.get(name)
.ok_or_else(|| TypeError::UndefinedPattern(name))?;
// Type check arguments
let typed_args: Vec<TypedArg> = args
.iter()
.map(|arg| TypedArg {
name: arg.name,
ty: self.infer_expr(arg.value),
span: arg.span,
})
.collect();
// Validate required arguments
for spec in pattern.arguments() {
if spec.required && !typed_args.iter().any(|a| a.name.as_str() == spec.name) {
return Err(TypeError::MissingPatternArg {
pattern: name,
arg: spec.name,
});
}
}
// Delegate to pattern's type checking
pattern.type_check(&typed_args, self)
}
}
Usage in Evaluator
impl Evaluator {
fn eval_pattern_call(
&mut self,
name: Name,
args: &[NamedArg],
) -> Result<Value, EvalError> {
// Get pattern from registry
let pattern = self.pattern_registry
.get(name)
.ok_or_else(|| EvalError::UndefinedPattern(name))?;
// Evaluate arguments
let eval_args: Vec<EvalArg> = args
.iter()
.map(|arg| Ok(EvalArg {
name: arg.name,
value: self.eval_expr(arg.value)?,
}))
collect::<Result<_, _>>()?;
// Delegate to pattern's evaluation
pattern.evaluate(&eval_args, self)
}
}
SharedRegistry Pattern
For dependency injection in tests:
/// Newtype wrapper for shared registry
pub struct SharedRegistry<T>(Arc<T>);
impl<T> SharedRegistry<T> {
pub fn new(inner: T) -> Self {
Self(Arc::new(inner))
}
pub fn inner(&self) -> &T {
&self.0
}
}
impl<T> Clone for SharedRegistry<T> {
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}
// Usage
pub type SharedPatternRegistry = SharedRegistry<PatternRegistry>;
Thread Safety
The registry is designed for concurrent access:
// Patterns are Arc<dyn PatternDefinition>
// Registry can be cloned cheaply
let registry: SharedPatternRegistry = ...;
// Safe to use from multiple threads
thread::spawn({
let registry = registry.clone();
move || {
let pattern = registry.get(name);
// ...
}
});
Error Handling
impl PatternRegistry {
pub fn get_or_error(&self, name: Name, span: Span) -> Result<Arc<dyn PatternDefinition>, PatternError> {
self.get(name).ok_or_else(|| {
let similar = self.suggest_similar(name);
PatternError::UndefinedPattern {
name,
span,
similar,
}
})
}
}
Extension Points
Custom Patterns
Users can register custom patterns:
// In user code
registry.register(MyCustomPattern::new());
// Pattern is now available
my_pattern(arg: value)
Plugin System (Future)
// Load patterns from dynamic library
registry.load_plugin("path/to/plugin.so")?;