ast_grep_core/match_tree/
strictness.rs1use crate::matcher::{kind_utils, PatternNode};
2use crate::meta_var::MetaVariable;
3use crate::{Doc, Node};
4use std::iter::Peekable;
5use std::str::FromStr;
6
7#[derive(Clone)]
8pub enum MatchStrictness {
9 Cst, Smart, Ast, Relaxed, Signature, }
15
16pub(crate) enum MatchOneNode {
17 MatchedBoth,
18 SkipBoth,
19 SkipGoal,
20 SkipCandidate,
21 NoMatch,
22}
23
24fn skip_comment_or_unnamed(n: &Node<impl Doc>) -> bool {
25 if !n.is_named() {
26 return true;
27 }
28 let kind = n.kind();
29 kind.contains("comment")
30}
31
32impl MatchStrictness {
33 pub(crate) fn match_terminal<D: Doc>(
34 &self,
35 is_named: bool,
36 text: &str,
37 goal_kind: u16,
38 candidate: &Node<D>,
39 ) -> MatchOneNode {
40 use MatchStrictness as M;
41 let cand_kind = candidate.kind_id();
42 let is_kind_matched = kind_utils::are_kinds_matching(goal_kind, cand_kind);
43 if is_kind_matched && (!is_named || text == candidate.text()) {
47 return MatchOneNode::MatchedBoth;
48 }
49 let (skip_goal, skip_candidate) = match self {
50 M::Cst => (false, false),
51 M::Smart => (false, !candidate.is_named()),
52 M::Ast => (!is_named, !candidate.is_named()),
53 M::Relaxed => (!is_named, skip_comment_or_unnamed(candidate)),
54 M::Signature => {
55 if is_kind_matched {
56 return MatchOneNode::MatchedBoth;
57 }
58 (!is_named, skip_comment_or_unnamed(candidate))
59 }
60 };
61 match (skip_goal, skip_candidate) {
62 (true, true) => MatchOneNode::SkipBoth,
63 (true, false) => MatchOneNode::SkipGoal,
64 (false, true) => MatchOneNode::SkipCandidate,
65 (false, false) => MatchOneNode::NoMatch,
66 }
67 }
68
69 pub(crate) fn should_skip_trailing<D: Doc>(&self, candidate: &Node<D>) -> bool {
71 use MatchStrictness as M;
72 match self {
73 M::Cst => false,
74 M::Smart => true,
75 M::Ast => false,
76 M::Relaxed => skip_comment_or_unnamed(candidate),
77 M::Signature => skip_comment_or_unnamed(candidate),
78 }
79 }
80
81 pub(crate) fn should_skip_goal<'p>(
82 &self,
83 goal_children: &mut Peekable<impl Iterator<Item = &'p PatternNode>>,
84 ) -> bool {
85 use MatchStrictness as M;
86 while let Some(pattern) = goal_children.peek() {
87 let skipped = match self {
88 M::Cst => false,
89 M::Smart => match pattern {
90 PatternNode::MetaVar { meta_var } => match meta_var {
91 MetaVariable::Multiple => true,
92 MetaVariable::MultiCapture(_) => true,
93 MetaVariable::Dropped(_) => false,
94 MetaVariable::Capture(..) => false,
95 },
96 PatternNode::Terminal { .. } => false,
97 PatternNode::Internal { .. } => false,
98 },
99 M::Ast | M::Relaxed | M::Signature => match pattern {
100 PatternNode::MetaVar { meta_var } => match meta_var {
101 MetaVariable::Multiple => true,
102 MetaVariable::MultiCapture(_) => true,
103 MetaVariable::Dropped(named) => !named,
104 MetaVariable::Capture(_, named) => !named,
105 },
106 PatternNode::Terminal { is_named, .. } => !is_named,
107 PatternNode::Internal { .. } => false,
108 },
109 };
110 if !skipped {
111 return false;
112 }
113 goal_children.next();
114 }
115 true
116 }
117}
118
119impl FromStr for MatchStrictness {
120 type Err = &'static str;
121 fn from_str(s: &str) -> Result<Self, Self::Err> {
122 match s {
123 "cst" => Ok(MatchStrictness::Cst),
124 "smart" => Ok(MatchStrictness::Smart),
125 "ast" => Ok(MatchStrictness::Ast),
126 "relaxed" => Ok(MatchStrictness::Relaxed),
127 "signature" => Ok(MatchStrictness::Signature),
128 _ => Err("invalid strictness, valid options are: cst, smart, ast, relaxed, signature"),
129 }
130 }
131}