From 802c2c06fae7f3bff2f4094f805d75009e14c6b3 Mon Sep 17 00:00:00 2001 From: Morgante Pell Date: Wed, 16 Oct 2024 15:10:59 -0500 Subject: [PATCH] feat: add within until (#540) --- .github/workflows/code-quality.yaml | 2 +- .github/workflows/main.yaml | 6 +-- .../src/pattern_compiler/within_compiler.rs | 7 ++- crates/core/src/test.rs | 50 +++++++++++++++++++ .../src/pattern/within.rs | 23 ++++++--- vendor/tree-sitter-gritql | 2 +- 6 files changed, 76 insertions(+), 14 deletions(-) diff --git a/.github/workflows/code-quality.yaml b/.github/workflows/code-quality.yaml index db4d80f65..8456fc61e 100644 --- a/.github/workflows/code-quality.yaml +++ b/.github/workflows/code-quality.yaml @@ -12,7 +12,7 @@ jobs: runs-on: namespace-profile-standard-ubuntu22-amd64 steps: - name: clone code - uses: namespacelabs/nscloud-checkout-action@v4 + uses: namespacelabs/nscloud-checkout-action@v5 with: submodules: recursive - name: Install Protoc diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index a5c8179b7..5511cf6ba 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -21,7 +21,7 @@ jobs: BUILD_PLATFORM: amd64 steps: - name: clone code - uses: namespacelabs/nscloud-checkout-action@v4 + uses: namespacelabs/nscloud-checkout-action@v5 with: submodules: recursive - name: Install Protoc @@ -75,7 +75,7 @@ jobs: id-token: "write" steps: - name: clone code - uses: namespacelabs/nscloud-checkout-action@v4 + uses: namespacelabs/nscloud-checkout-action@v5 with: submodules: recursive - name: install Rust @@ -99,7 +99,7 @@ jobs: runs-on: namespace-profile-standard-ubuntu22-amd64 steps: - name: clone code - uses: namespacelabs/nscloud-checkout-action@v4 + uses: namespacelabs/nscloud-checkout-action@v5 with: submodules: recursive - name: install Rust diff --git a/crates/core/src/pattern_compiler/within_compiler.rs b/crates/core/src/pattern_compiler/within_compiler.rs index 22718f725..7da769a59 100644 --- a/crates/core/src/pattern_compiler/within_compiler.rs +++ b/crates/core/src/pattern_compiler/within_compiler.rs @@ -20,7 +20,12 @@ impl NodeCompiler for WithinCompiler { let within = node .child_by_field_name("pattern") .ok_or_else(|| anyhow!("missing pattern of pattern within"))?; + let within = PatternCompiler::from_node(&within, context)?; - Ok(Within::new(within)) + let until = node + .child_by_field_name("until") + .map(|n| PatternCompiler::from_node(&n, context)) + .transpose()?; + Ok(Within::new(within, until)) } } diff --git a/crates/core/src/test.rs b/crates/core/src/test.rs index 11d047672..70783f1db 100644 --- a/crates/core/src/test.rs +++ b/crates/core/src/test.rs @@ -7398,6 +7398,56 @@ fn simple_until() { .unwrap(); } +#[test] +fn within_until() { + run_test_expected({ + TestArgExpected { + pattern: r#" + |language js + | + |contains bubble `foo($x)` => `bar($x)` where { + | $x <: within `wrapped($_)` until `stop($_)` + |} + |"# + .trim_margin() + .unwrap(), + source: r#" + |// not match: + |foo(10) + |// this will match, since it is inside a wrapped + |wrapped(() => { + | foo(11) + |}) + |// this will not match, since the wrap is outside the stop + |wrapped(() => { + | stop(() => { + | foo(12) + | }) + |}) + |"# + .trim_margin() + .unwrap(), + expected: r#" + |// not match: + |foo(10) + |// this will match, since it is inside a wrapped + |wrapped(() => { + | bar(11) + |}) + |// this will not match, since the wrap is outside the stop + |wrapped(() => { + | stop(() => { + | foo(12) + | }) + |}) + |"# + .trim_margin() + .unwrap(), + } + }) + .unwrap(); +} + #[test] fn capitalize_no_args() { let pattern = r#" diff --git a/crates/grit-pattern-matcher/src/pattern/within.rs b/crates/grit-pattern-matcher/src/pattern/within.rs index 4ffda8f9e..22a4ce0fc 100644 --- a/crates/grit-pattern-matcher/src/pattern/within.rs +++ b/crates/grit-pattern-matcher/src/pattern/within.rs @@ -10,11 +10,12 @@ use grit_util::{error::GritResult, AnalysisLogs, AstNode}; #[derive(Debug, Clone)] pub struct Within { pub pattern: Pattern, + until: Option>, } impl Within { - pub fn new(pattern: Pattern) -> Self { - Self { pattern } + pub fn new(pattern: Pattern, until: Option>) -> Self { + Self { pattern, until } } } @@ -50,15 +51,21 @@ impl Matcher for Within { }; for n in node.ancestors() { let state = cur_state.clone(); - if self.pattern.execute( - &ResolvedPattern::from_node_binding(n), - &mut cur_state, - context, - logs, - )? { + let resolved = ResolvedPattern::from_node_binding(n); + if self + .pattern + .execute(&resolved, &mut cur_state, context, logs)? + { did_match = true; + // We still traverse upwards, so side effects can be applied to all ancestors } else { cur_state = state; + + if let Some(until) = &self.until { + if until.execute(&resolved, &mut cur_state, context, logs)? { + break; + } + } } } if did_match { diff --git a/vendor/tree-sitter-gritql b/vendor/tree-sitter-gritql index 5f4543610..f47103620 160000 --- a/vendor/tree-sitter-gritql +++ b/vendor/tree-sitter-gritql @@ -1 +1 @@ -Subproject commit 5f4543610f49f7607b5ca54082da017837219a23 +Subproject commit f47103620adcb5aa4f74ba4c52ef0f4e9461b950