From 5997c9b8dd30ce4144c47735954963bc5ba3d42a Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Tue, 6 Jan 2026 01:03:37 -0300 Subject: [PATCH] refactor: add batch methods to `MatchIR` builder --- crates/plotnik-lib/src/bytecode/ir.rs | 273 ++++++++++++--- crates/plotnik-lib/src/compile/capture.rs | 8 +- crates/plotnik-lib/src/compile/expressions.rs | 134 +++----- crates/plotnik-lib/src/compile/mod.rs | 13 +- crates/plotnik-lib/src/compile/quantifier.rs | 15 +- crates/plotnik-lib/src/compile/scope.rs | 311 ++++++------------ crates/plotnik-lib/src/compile/sequences.rs | 6 +- crates/plotnik-lib/src/emit/layout_tests.rs | 199 ++++------- 8 files changed, 453 insertions(+), 506 deletions(-) diff --git a/crates/plotnik-lib/src/bytecode/ir.rs b/crates/plotnik-lib/src/bytecode/ir.rs index 2c7d9be6..e117a7fb 100644 --- a/crates/plotnik-lib/src/bytecode/ir.rs +++ b/crates/plotnik-lib/src/bytecode/ir.rs @@ -130,6 +130,66 @@ impl EffectIR { } } + /// Capture current node value. + pub fn node() -> Self { + Self::simple(EffectOpcode::Node, 0) + } + + /// Capture current node text. + pub fn text() -> Self { + Self::simple(EffectOpcode::Text, 0) + } + + /// Push null value. + pub fn null() -> Self { + Self::simple(EffectOpcode::Null, 0) + } + + /// Push accumulated value to array. + pub fn push() -> Self { + Self::simple(EffectOpcode::Push, 0) + } + + /// Begin array scope. + pub fn start_arr() -> Self { + Self::simple(EffectOpcode::Arr, 0) + } + + /// End array scope. + pub fn end_arr() -> Self { + Self::simple(EffectOpcode::EndArr, 0) + } + + /// Begin object scope. + pub fn start_obj() -> Self { + Self::simple(EffectOpcode::Obj, 0) + } + + /// End object scope. + pub fn end_obj() -> Self { + Self::simple(EffectOpcode::EndObj, 0) + } + + /// Begin enum scope. + pub fn start_enum() -> Self { + Self::simple(EffectOpcode::Enum, 0) + } + + /// End enum scope. + pub fn end_enum() -> Self { + Self::simple(EffectOpcode::EndEnum, 0) + } + + /// Begin suppression (suppress effects within). + pub fn suppress_begin() -> Self { + Self::simple(EffectOpcode::SuppressBegin, 0) + } + + /// End suppression. + pub fn suppress_end() -> Self { + Self::simple(EffectOpcode::SuppressEnd, 0) + } + /// Resolve this IR effect to a concrete EffectOp. /// /// - `lookup_member`: maps (field_name Symbol, field_type TypeId) to member index @@ -235,6 +295,96 @@ pub struct MatchIR { } impl MatchIR { + /// Create a terminal/accept state (empty successors). + pub fn terminal(label: Label) -> Self { + Self { + label, + nav: Nav::Stay, + node_type: None, + node_field: None, + pre_effects: vec![], + neg_fields: vec![], + post_effects: vec![], + successors: vec![], + } + } + + /// Start building a match instruction at the given label. + pub fn at(label: Label) -> Self { + Self::terminal(label) + } + + /// Create an epsilon transition (no node interaction) to a single successor. + pub fn epsilon(label: Label, next: Label) -> Self { + Self::at(label).next(next) + } + + /// Set the navigation command. + pub fn nav(mut self, nav: Nav) -> Self { + self.nav = nav; + self + } + + /// Set the node type constraint. + pub fn node_type(mut self, t: impl Into>) -> Self { + self.node_type = t.into(); + self + } + + /// Set the field constraint. + pub fn node_field(mut self, f: impl Into>) -> Self { + self.node_field = f.into(); + self + } + + /// Add a negated field constraint. + pub fn neg_field(mut self, f: u16) -> Self { + self.neg_fields.push(f); + self + } + + /// Add a pre-match effect. + pub fn pre_effect(mut self, e: EffectIR) -> Self { + self.pre_effects.push(e); + self + } + + /// Add a post-match effect. + pub fn post_effect(mut self, e: EffectIR) -> Self { + self.post_effects.push(e); + self + } + + /// Add multiple negated field constraints. + pub fn neg_fields(mut self, fields: impl IntoIterator) -> Self { + self.neg_fields.extend(fields); + self + } + + /// Add multiple pre-match effects. + pub fn pre_effects(mut self, effects: impl IntoIterator) -> Self { + self.pre_effects.extend(effects); + self + } + + /// Add multiple post-match effects. + pub fn post_effects(mut self, effects: impl IntoIterator) -> Self { + self.post_effects.extend(effects); + self + } + + /// Set a single successor. + pub fn next(mut self, s: Label) -> Self { + self.successors = vec![s]; + self + } + + /// Set multiple successors (for branches). + pub fn next_many(mut self, s: Vec