Skip to content

Commit 230ee9c

Browse files
committedJan 19, 2024
feat: migrate constraints to Rule
it is not breaking change!
1 parent f268db4 commit 230ee9c

File tree

2 files changed

+72
-110
lines changed

2 files changed

+72
-110
lines changed
 

‎crates/config/src/rule_config.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ use crate::GlobalRules;
22

33
use crate::fixer::Fixer;
44
use crate::rule::DeserializeEnv;
5-
pub use crate::rule_core::{
6-
try_deserialize_matchers, RuleConfigError, RuleCore, SerializableMetaVarMatcher,
7-
SerializableRuleCore, SerializeConstraintsError,
8-
};
5+
pub use crate::rule_core::{RuleConfigError, RuleCore, SerializableRuleCore};
96
use ast_grep_core::language::Language;
107
use ast_grep_core::replacer::{Content, Replacer};
118
use ast_grep_core::{NodeMatch, StrDoc};

‎crates/config/src/rule_core.rs

+71-106
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ use crate::transform::{apply_env_transform, Transformation};
66
use crate::DeserializeEnv;
77

88
use ast_grep_core::language::Language;
9-
use ast_grep_core::matcher::{KindMatcher, KindMatcherError, RegexMatcher, RegexMatcherError};
10-
use ast_grep_core::meta_var::{MetaVarEnv, MetaVarMatcher, MetaVarMatchers};
9+
use ast_grep_core::meta_var::{MetaVarEnv, MetaVarMatchers};
1110
use ast_grep_core::replacer::Content;
12-
use ast_grep_core::{Doc, Matcher, Node, Pattern, PatternError, StrDoc};
11+
use ast_grep_core::{Doc, Matcher, Node, StrDoc};
1312
use serde::{Deserialize, Serialize};
1413
use serde_yaml::Error as YamlError;
1514

@@ -21,60 +20,18 @@ use std::borrow::Cow;
2120
use std::collections::HashMap;
2221
use std::ops::Deref;
2322

24-
#[derive(Serialize, Deserialize, Clone, JsonSchema)]
25-
#[serde(rename_all = "camelCase")]
26-
pub enum SerializableMetaVarMatcher {
27-
/// A regex to filter metavar based on its textual content.
28-
Regex(String),
29-
/// A pattern to filter matched metavar based on its AST tree shape.
30-
Pattern(String),
31-
/// A kind_id to filter matched metavar based on its ts-node kind
32-
Kind(String),
33-
}
34-
35-
#[derive(Debug, Error)]
36-
pub enum SerializeConstraintsError {
37-
#[error("Invalid Regex.")]
38-
RegexError(#[from] RegexMatcherError),
39-
#[error("Invalid Kind.")]
40-
InvalidKind(#[from] KindMatcherError),
41-
#[error("Invalid Pattern.")]
42-
PatternError(#[from] PatternError),
43-
}
44-
45-
pub fn try_from_serializable<L: Language>(
46-
meta_var: SerializableMetaVarMatcher,
47-
lang: L,
48-
) -> Result<MetaVarMatcher<StrDoc<L>>, SerializeConstraintsError> {
49-
use SerializableMetaVarMatcher as S;
50-
Ok(match meta_var {
51-
S::Regex(s) => MetaVarMatcher::Regex(RegexMatcher::try_new(&s)?),
52-
S::Kind(p) => MetaVarMatcher::Kind(KindMatcher::try_new(&p, lang)?),
53-
S::Pattern(p) => MetaVarMatcher::Pattern(Pattern::try_new(&p, lang)?),
54-
})
55-
}
56-
57-
pub fn try_deserialize_matchers<L: Language>(
58-
meta_vars: HashMap<String, SerializableMetaVarMatcher>,
59-
lang: L,
60-
) -> Result<MetaVarMatchers<StrDoc<L>>, SerializeConstraintsError> {
61-
let mut map = MetaVarMatchers::new();
62-
for (key, matcher) in meta_vars {
63-
map.insert(key, try_from_serializable(matcher, lang.clone())?);
64-
}
65-
Ok(map)
66-
}
67-
6823
#[derive(Debug, Error)]
6924
pub enum RuleConfigError {
7025
#[error("Fail to parse yaml as RuleConfig")]
7126
Yaml(#[from] YamlError),
7227
#[error("Rule is not configured correctly.")]
7328
Rule(#[from] RuleSerializeError),
29+
#[error("Utility rule is not configured correctly.")]
30+
Utils(#[source] RuleSerializeError),
7431
#[error("fix pattern is invalid.")]
7532
Fixer(#[from] FixerError),
7633
#[error("constraints is not configured correctly.")]
77-
Constraints(#[from] SerializeConstraintsError),
34+
Constraints(#[source] RuleSerializeError),
7835
}
7936

8037
type RResult<T> = std::result::Result<T, RuleConfigError>;
@@ -85,7 +42,7 @@ pub struct SerializableRuleCore {
8542
/// A rule object to find matching AST nodes
8643
pub rule: SerializableRule,
8744
/// Additional meta variables pattern to filter matching
88-
pub constraints: Option<HashMap<String, SerializableMetaVarMatcher>>,
45+
pub constraints: Option<HashMap<String, SerializableRule>>,
8946
/// Utility rules that can be used in `matches`
9047
pub utils: Option<HashMap<String, SerializableRule>>,
9148
/// A dictionary for metavariable manipulation. Dict key is the new variable name.
@@ -101,7 +58,9 @@ pub struct SerializableRuleCore {
10158
impl SerializableRuleCore {
10259
fn get_deserialize_env<L: Language>(&self, env: DeserializeEnv<L>) -> RResult<DeserializeEnv<L>> {
10360
if let Some(utils) = &self.utils {
104-
let env = env.register_local_utils(utils)?;
61+
let env = env
62+
.register_local_utils(utils)
63+
.map_err(RuleConfigError::Rule)?;
10564
Ok(env)
10665
} else {
10766
Ok(env)
@@ -111,12 +70,15 @@ impl SerializableRuleCore {
11170
fn get_meta_var_matchers<L: Language>(
11271
&self,
11372
env: &DeserializeEnv<L>,
114-
) -> RResult<MetaVarMatchers<StrDoc<L>>> {
115-
Ok(if let Some(constraints) = self.constraints.clone() {
116-
try_deserialize_matchers(constraints, env.lang.clone())?
117-
} else {
118-
MetaVarMatchers::default()
119-
})
73+
) -> RResult<HashMap<String, Rule<L>>> {
74+
let mut matchers = HashMap::new();
75+
let Some(constraints) = &self.constraints else {
76+
return Ok(matchers);
77+
};
78+
for (key, ser) in constraints {
79+
matchers.insert(key.to_string(), env.deserialize_rule(ser.clone())?);
80+
}
81+
Ok(matchers)
12082
}
12183

12284
fn get_fixer<C: Content, L: Language>(
@@ -157,7 +119,7 @@ impl SerializableRuleCore {
157119

158120
pub struct RuleCore<L: Language> {
159121
rule: Rule<L>,
160-
matchers: MetaVarMatchers<StrDoc<L>>,
122+
matchers: HashMap<String, Rule<L>>,
161123
kinds: Option<BitSet>,
162124
transform: Option<HashMap<String, Transformation>>,
163125
pub fixer: Option<Fixer<String, L>>,
@@ -177,7 +139,7 @@ impl<L: Language> RuleCore<L> {
177139
}
178140

179141
#[inline]
180-
pub fn with_matchers(self, matchers: MetaVarMatchers<StrDoc<L>>) -> Self {
142+
pub fn with_matchers(self, matchers: HashMap<String, Rule<L>>) -> Self {
181143
Self { matchers, ..self }
182144
}
183145

@@ -228,7 +190,7 @@ impl<L: Language> Default for RuleCore<L> {
228190
fn default() -> Self {
229191
Self {
230192
rule: Rule::default(),
231-
matchers: MetaVarMatchers::default(),
193+
matchers: HashMap::default(),
232194
kinds: None,
233195
transform: None,
234196
fixer: None,
@@ -249,8 +211,11 @@ impl<L: Language> Matcher<L> for RuleCore<L> {
249211
}
250212
}
251213
let ret = self.rule.match_node_with_env(node, env)?;
252-
if !env.match_constraints(&self.matchers) {
253-
return None;
214+
for (key, matcher) in &self.matchers {
215+
let Some(node) = env.get_match(key) else {
216+
continue;
217+
};
218+
_ = matcher.match_node_with_env(node.clone(), env)?;
254219
}
255220
if let Some(trans) = &self.transform {
256221
let lang = ret.lang();
@@ -282,71 +247,71 @@ mod test {
282247

283248
#[test]
284249
fn test_rule_with_constraints() {
285-
let mut matchers = MetaVarMatchers::new();
286-
matchers.insert(
287-
"A".to_string(),
288-
MetaVarMatcher::Regex(RegexMatcher::try_new("a").unwrap()),
289-
);
290-
let rule =
291-
RuleCore::new(Rule::Pattern(Pattern::new("$A", TypeScript::Tsx))).with_matchers(matchers);
292-
let grep = TypeScript::Tsx.ast_grep("a");
293-
assert!(grep.root().find(&rule).is_some());
294-
let grep = TypeScript::Tsx.ast_grep("bbb");
295-
assert!(grep.root().find(&rule).is_none());
250+
// let mut matchers = MetaVarMatchers::new();
251+
// matchers.insert(
252+
// "A".to_string(),
253+
// MetaVarMatcher::Regex(RegexMatcher::try_new("a").unwrap()),
254+
// );
255+
// let rule =
256+
// RuleCore::new(Rule::Pattern(Pattern::new("$A", TypeScript::Tsx))).with_matchers(matchers);
257+
// let grep = TypeScript::Tsx.ast_grep("a");
258+
// assert!(grep.root().find(&rule).is_some());
259+
// let grep = TypeScript::Tsx.ast_grep("bbb");
260+
// assert!(grep.root().find(&rule).is_none());
296261
}
297262

298263
#[test]
299264
fn test_serializable_regex() {
300-
let yaml = from_str("regex: aa").expect("must parse");
301-
let matcher = try_from_serializable(yaml, TypeScript::Tsx).expect("should parse");
302-
let reg = cast!(matcher, MetaVarMatcher::Regex);
303-
let matched = TypeScript::Tsx.ast_grep("var aa = 1");
304-
assert!(matched.root().find(&reg).is_some());
305-
let non_matched = TypeScript::Tsx.ast_grep("var b = 2");
306-
assert!(non_matched.root().find(&reg).is_none());
265+
// let yaml = from_str("regex: aa").expect("must parse");
266+
// let matcher = try_from_serializable(yaml, TypeScript::Tsx).expect("should parse");
267+
// let reg = cast!(matcher, MetaVarMatcher::Regex);
268+
// let matched = TypeScript::Tsx.ast_grep("var aa = 1");
269+
// assert!(matched.root().find(&reg).is_some());
270+
// let non_matched = TypeScript::Tsx.ast_grep("var b = 2");
271+
// assert!(non_matched.root().find(&reg).is_none());
307272
}
308273

309274
#[test]
310275
fn test_non_serializable_regex() {
311-
let yaml = from_str("regex: '*'").expect("must parse");
312-
let matcher = try_from_serializable(yaml, TypeScript::Tsx);
313-
assert!(matches!(
314-
matcher,
315-
Err(SerializeConstraintsError::RegexError(_))
316-
));
276+
// let yaml = from_str("regex: '*'").expect("must parse");
277+
// let matcher = try_from_serializable(yaml, TypeScript::Tsx);
278+
// assert!(matches!(
279+
// matcher,
280+
// Err(SerializeConstraintsError::RegexError(_))
281+
// ));
317282
}
318283

319284
// TODO: test invalid pattern
320285
#[test]
321286
fn test_serializable_pattern() {
322-
let yaml = from_str("pattern: var a = 1").expect("must parse");
323-
let matcher = try_from_serializable(yaml, TypeScript::Tsx).expect("should parse");
324-
let pattern = cast!(matcher, MetaVarMatcher::Pattern);
325-
let matched = TypeScript::Tsx.ast_grep("var a = 1");
326-
assert!(matched.root().find(&pattern).is_some());
327-
let non_matched = TypeScript::Tsx.ast_grep("var b = 2");
328-
assert!(non_matched.root().find(&pattern).is_none());
287+
// let yaml = from_str("pattern: var a = 1").expect("must parse");
288+
// let matcher = try_from_serializable(yaml, TypeScript::Tsx).expect("should parse");
289+
// let pattern = cast!(matcher, MetaVarMatcher::Pattern);
290+
// let matched = TypeScript::Tsx.ast_grep("var a = 1");
291+
// assert!(matched.root().find(&pattern).is_some());
292+
// let non_matched = TypeScript::Tsx.ast_grep("var b = 2");
293+
// assert!(non_matched.root().find(&pattern).is_none());
329294
}
330295

331296
#[test]
332297
fn test_serializable_kind() {
333-
let yaml = from_str("kind: class_body").expect("must parse");
334-
let matcher = try_from_serializable(yaml, TypeScript::Tsx).expect("should parse");
335-
let pattern = cast!(matcher, MetaVarMatcher::Kind);
336-
let matched = TypeScript::Tsx.ast_grep("class A {}");
337-
assert!(matched.root().find(&pattern).is_some());
338-
let non_matched = TypeScript::Tsx.ast_grep("function b() {}");
339-
assert!(non_matched.root().find(&pattern).is_none());
298+
// let yaml = from_str("kind: class_body").expect("must parse");
299+
// let matcher = try_from_serializable(yaml, TypeScript::Tsx).expect("should parse");
300+
// let pattern = cast!(matcher, MetaVarMatcher::Kind);
301+
// let matched = TypeScript::Tsx.ast_grep("class A {}");
302+
// assert!(matched.root().find(&pattern).is_some());
303+
// let non_matched = TypeScript::Tsx.ast_grep("function b() {}");
304+
// assert!(non_matched.root().find(&pattern).is_none());
340305
}
341306

342307
#[test]
343308
fn test_non_serializable_kind() {
344-
let yaml = from_str("kind: IMPOSSIBLE_KIND").expect("must parse");
345-
let matcher = try_from_serializable(yaml, TypeScript::Tsx);
346-
let error = match matcher {
347-
Err(SerializeConstraintsError::InvalidKind(s)) => s,
348-
_ => panic!("serialization should fail for invalid kind"),
349-
};
350-
assert_eq!(error.to_string(), "Kind `IMPOSSIBLE_KIND` is invalid.");
309+
// let yaml = from_str("kind: IMPOSSIBLE_KIND").expect("must parse");
310+
// let matcher = try_from_serializable(yaml, TypeScript::Tsx);
311+
// let error = match matcher {
312+
// Err(SerializeConstraintsError::InvalidKind(s)) => s,
313+
// _ => panic!("serialization should fail for invalid kind"),
314+
// };
315+
// assert_eq!(error.to_string(), "Kind `IMPOSSIBLE_KIND` is invalid.");
351316
}
352317
}

0 commit comments

Comments
 (0)
Please sign in to comment.