Skip to content

Commit 444ba52

Browse files
committed
use untyped_ast
1 parent 7399bd0 commit 444ba52

28 files changed

Lines changed: 453 additions & 3172 deletions

matching/INTERNAL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Expression metavars capture the candidate expression at that position.
5050
Repeated uses compare the parsed expression structure, ignoring locations.
5151

5252
Identifier metavars store `Identifier(String)`. Expr, var, and pattern values
53-
go through `rule/syntax_id` normalization where possible. Binder and label
53+
go through `untyped_ast` normalization helpers where possible. Binder and label
5454
matching uses the candidate name directly because those nodes already carry the
5555
short name being compared.
5656

matching/INTERNAL_CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ expression metavar 会捕获该位置上的候选表达式。重复使用时比
4141
并忽略源码位置。
4242

4343
identifier metavar 会存储 `Identifier(String)`。Expr、var 和 pattern 值会在可能时经过
44-
`rule/syntax_id` 规范化。Binder 和 label 匹配直接使用候选名称,因为这些节点已经携带了用于比较的短名称。
44+
`untyped_ast` 规范化 helper。Binder 和 label 匹配直接使用候选名称,因为这些节点已经携带了用于比较的短名称。
4545

4646
constant metavar 会存储 `Constant(@syntax.Constant)`。表达式占位符只接受
4747
`Expr::Constant`,pattern 占位符只接受 `Pattern::Constant`,重复使用时通过

moon.pkg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
"moonbit-community/moongrep/rule/load" @rule_load,
88
"moonbit-community/moongrep/rule/model" @rule_model,
99
"moonbit-community/moongrep/rule/prefilter" @rule_prefilter,
10+
"moonbit-community/moongrep/untyped_ast",
1011
"moonbit-community/miniio",
1112
"moonbitlang/core/argparse",
1213
"moonbitlang/core/json",

query/moon.pkg

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
"moonbit-community/moongrep/rule/compile" @rule_compile,
44
"moonbit-community/moongrep/rule/model" @rule_model,
55
"moonbit-community/moongrep/rule/prefilter" @rule_prefilter,
6-
"moonbit-community/moongrep/rule/traverse" @rule_traverse,
76
"moonbit-community/moongrep/untyped_ast",
87
"moonbitlang/core/hashmap",
98
"moonbitlang/lexer/basic",

query/query.mbt

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ using @rule_model {
55
type RawRuleSpec,
66
}
77

8-
///|
9-
using @rule_traverse {type ScopedExpr}
10-
118
///|
129
priv suberror QueryError {
1310
ParseError(source_name~ : String, info~ : String)
@@ -84,24 +81,29 @@ fn collect_impl_matches(
8481
node : @syntax.Impl,
8582
matches : Array[Map[String, @untyped_ast.Node]],
8683
) -> Unit {
87-
@rule_traverse.visit_impl_scoped_expr_roots(node, fn(scoped_expr) {
88-
collect_scoped_expr_matches(pattern, scoped_expr, matches)
84+
@untyped_ast.visit_node_scoped_expr_roots(@untyped_ast.from_impl(node), fn(
85+
scoped_expr,
86+
) {
87+
collect_scoped_node_matches(pattern, scoped_expr, matches)
88+
@untyped_ast.NodeVisitAction::NodeVisitPrune
8989
})
9090
}
9191

9292
///|
93-
fn collect_scoped_expr_matches(
93+
fn collect_scoped_node_matches(
9494
pattern : CompiledRulePattern,
95-
scoped_expr : ScopedExpr,
95+
scoped_expr : @untyped_ast.ScopedNodeExpr,
9696
matches : Array[Map[String, @untyped_ast.Node]],
9797
) -> Unit {
98-
let candidate = @untyped_ast.from_expr(scoped_expr.expr)
99-
if @matching.match_expr_pattern(pattern.compiled, candidate) is Some(result) {
98+
if @matching.match_expr_pattern(pattern.compiled, scoped_expr.expr)
99+
is Some(result) {
100100
matches.push(capture_map_from_bindings(result.bindings))
101101
} else {
102-
@rule_traverse.visit_scoped_expr_children(scoped_expr, fn(child) {
103-
collect_scoped_expr_matches(pattern, child, matches)
104-
})
102+
@untyped_ast.visit_node_scoped_expr_children(
103+
scoped_expr.expr,
104+
scoped_expr.shadowed_names,
105+
fn(child) { collect_scoped_node_matches(pattern, child, matches) },
106+
)
105107
}
106108
}
107109

rule/apply/apply.mbt

Lines changed: 54 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ using @model {
1111
///|
1212
using @taint_lowering {lower_compiled_taint_rule}
1313

14-
///|
15-
using @traverse {type ScopedExpr}
16-
1714
///|
1815
priv enum RuleTraversalAction {
1916
RuleContinue
@@ -37,38 +34,32 @@ priv struct AstStructuralRuleEntry {
3734
}
3835

3936
///|
40-
/// Applies only structural rules to the supplied parser AST nodes.
37+
/// Applies only structural rules to the supplied untyped AST root.
4138
///
42-
/// Supported expression subtrees collected by `collect_impl_exprs` and
43-
/// `collect_exprs` are visited in source-tree order. For a single expression
44-
/// and rule, the first matching pattern wins and determines `pattern_index`.
39+
/// Supported expression subtrees are visited in source-tree order. For a
40+
/// single expression and rule, the first matching pattern wins and determines
41+
/// `pattern_index`.
4542
pub fn apply_structural_rules(
4643
file : String,
47-
impls : @list.List[@syntax.Impl],
44+
root_node : @untyped_ast.Node,
4845
rules : Array[CompiledRule],
4946
) -> Array[RuleFinding] {
50-
let hits : Array[RuleFinding] = []
51-
for node in impls {
52-
let node_hits = apply_structural_rules_to_impl(file, node, rules)
53-
for hit in node_hits {
54-
hits.push(hit)
55-
}
56-
}
57-
hits
47+
apply_structural_rules_to_node(file, root_node, rules)
5848
}
5949

6050
///|
61-
pub fn apply_structural_rules_to_impl(
51+
pub fn apply_structural_rules_to_node(
6252
file : String,
63-
node : @syntax.Impl,
53+
node : @untyped_ast.Node,
6454
rules : Array[CompiledRule],
6555
) -> Array[RuleFinding] {
6656
let hits : Array[RuleFinding] = []
6757
let entries = ast_structural_rule_entries(rules)
68-
@traverse.visit_impl_scoped_expr_roots(node, fn(scoped_expr) {
58+
@untyped_ast.visit_node_scoped_expr_roots(node, fn(scoped_expr) {
6959
apply_ast_structural_rule_entries_to_scoped_expr(
7060
file, entries, scoped_expr, hits,
7161
)
62+
@untyped_ast.NodeVisitAction::NodeVisitPrune
7263
})
7364
hits
7465
}
@@ -108,7 +99,7 @@ fn ast_structural_rule_entries(
10899
fn apply_ast_structural_rule_entries_to_scoped_expr(
109100
file : String,
110101
entries : Array[AstStructuralRuleEntry],
111-
scoped_expr : ScopedExpr,
102+
scoped_expr : @untyped_ast.ScopedNodeExpr,
112103
hits : Array[RuleFinding],
113104
) -> Unit {
114105
let child_entries : Array[AstStructuralRuleEntry] = []
@@ -124,18 +115,22 @@ fn apply_ast_structural_rule_entries_to_scoped_expr(
124115
if child_entries.length() == 0 {
125116
return
126117
}
127-
@traverse.visit_scoped_expr_children(scoped_expr, fn(child) {
128-
apply_ast_structural_rule_entries_to_scoped_expr(
129-
file, child_entries, child, hits,
130-
)
131-
})
118+
@untyped_ast.visit_node_scoped_expr_children(
119+
scoped_expr.expr,
120+
scoped_expr.shadowed_names,
121+
fn(child) {
122+
apply_ast_structural_rule_entries_to_scoped_expr(
123+
file, child_entries, child, hits,
124+
)
125+
},
126+
)
132127
}
133128

134129
///|
135130
fn apply_ast_structural_rule_entry_to_scoped_expr(
136131
file : String,
137132
entry : AstStructuralRuleEntry,
138-
scoped_expr : ScopedExpr,
133+
scoped_expr : @untyped_ast.ScopedNodeExpr,
139134
hits : Array[RuleFinding],
140135
) -> RuleTraversalAction {
141136
if entry.structural.inside_expr is Some(inside) {
@@ -152,7 +147,7 @@ fn apply_ast_structural_rule_entry_to_scoped_expr(
152147
)
153148
RuleContinue
154149
} else {
155-
apply_ast_patterns_at_expr(
150+
apply_ast_patterns_at_node(
156151
file,
157152
entry.rule,
158153
entry.pattern_buckets,
@@ -166,18 +161,26 @@ fn apply_ast_structural_rule_entry_to_scoped_expr(
166161
}
167162

168163
///|
169-
/// Applies only taint rules to function-like parser AST nodes.
164+
/// Applies only taint rules to function-like untyped AST nodes.
170165
///
171166
/// Unsupported top-level nodes are ignored. Other taint-analysis errors are
172167
/// propagated to the caller.
173168
pub fn apply_taint_rules(
174169
file : String,
175-
impls : @list.List[@syntax.Impl],
170+
root_node : @untyped_ast.Node,
176171
rules : Array[CompiledRule],
177172
) -> Array[RuleFinding] raise {
178173
let hits : Array[RuleFinding] = []
179-
for node in impls {
180-
let node_hits = apply_taint_rules_to_impl(file, node, rules)
174+
if root_node.kind == @untyped_ast.NodeKind::ImplList {
175+
for entry in root_node.children {
176+
let (_, node) = entry
177+
let node_hits = apply_taint_rules_to_node(file, node, rules)
178+
for hit in node_hits {
179+
hits.push(hit)
180+
}
181+
}
182+
} else {
183+
let node_hits = apply_taint_rules_to_node(file, root_node, rules)
181184
for hit in node_hits {
182185
hits.push(hit)
183186
}
@@ -186,25 +189,24 @@ pub fn apply_taint_rules(
186189
}
187190

188191
///|
189-
pub fn apply_taint_rules_to_impl(
192+
pub fn apply_taint_rules_to_node(
190193
file : String,
191-
node : @syntax.Impl,
194+
node : @untyped_ast.Node,
192195
rules : Array[CompiledRule],
193196
) -> Array[RuleFinding] raise {
194197
let hits : Array[RuleFinding] = []
195-
let untyped_node = @untyped_ast.from_impl(node)
196198
for rule in rules {
197199
match rule.definition {
198200
Taint(taint_rule) =>
199-
apply_taint_rule_to_impl(file, rule, taint_rule, untyped_node, hits)
201+
apply_taint_rule_to_node(file, rule, taint_rule, node, hits)
200202
_ => ()
201203
}
202204
}
203205
hits
204206
}
205207

206208
///|
207-
fn apply_taint_rule_to_impl(
209+
fn apply_taint_rule_to_node(
208210
file : String,
209211
rule : CompiledRule,
210212
taint_rule : CompiledTaintRule,
@@ -249,13 +251,13 @@ fn apply_inside_expr_ast_bucketed(
249251
inside_root_key : @untyped_ast.NodeKind?,
250252
pattern_buckets : ExprPatternBuckets,
251253
negative_pattern_buckets : ExprPatternBuckets,
252-
expr : @syntax.Expr,
254+
expr : @untyped_ast.Node,
253255
hits : Array[RuleFinding],
254256
) -> Unit {
255-
if !ast_bucket_root_key_matches(inside_root_key, expr) {
257+
if !node_root_key_matches(inside_root_key, expr) {
256258
return
257259
}
258-
if match_ast_rule_pattern(inside, expr, None) is Some(result) {
260+
if match_node_rule_pattern(inside, expr, None) is Some(result) {
259261
if result.bindings.get("__TARGET__") is Some(target) {
260262
if structural.patterns.is_empty() {
261263
let target_exprs : Array[@untyped_ast.ScopedNodeExpr] = []
@@ -265,7 +267,7 @@ fn apply_inside_expr_ast_bucketed(
265267
rule,
266268
negative_pattern_buckets,
267269
target_exprs,
268-
expr.loc(),
270+
expr.loc,
269271
result.bindings,
270272
inside.compiled.identifier_metavars,
271273
hits,
@@ -279,7 +281,7 @@ fn apply_inside_expr_ast_bucketed(
279281
pattern_buckets,
280282
negative_pattern_buckets,
281283
target,
282-
Some(expr.loc()),
284+
Some(expr.loc),
283285
result.bindings,
284286
inside.compiled.identifier_metavars,
285287
hits,
@@ -291,7 +293,7 @@ fn apply_inside_expr_ast_bucketed(
291293
pattern_buckets,
292294
negative_pattern_buckets,
293295
target,
294-
Some(expr.loc()),
296+
Some(expr.loc),
295297
result.bindings,
296298
inside.compiled.identifier_metavars,
297299
hits,
@@ -492,31 +494,31 @@ fn apply_ast_bucketed_patterns_at_scoped_expr(
492494
}
493495

494496
///|
495-
fn apply_ast_patterns_at_expr(
497+
fn apply_ast_patterns_at_node(
496498
file : String,
497499
rule : CompiledRule,
498500
pattern_buckets : ExprPatternBuckets,
499501
negative_pattern_buckets : ExprPatternBuckets,
500-
expr : @syntax.Expr,
502+
expr : @untyped_ast.Node,
501503
outer_loc : @basic.Location?,
502504
initial_bindings : @hashmap.HashMap[String, @matching.BoundValue]?,
503505
hits : Array[RuleFinding],
504506
) -> RuleTraversalAction {
505-
for indexed in pattern_buckets.patterns_for_expr(expr) {
506-
if match_ast_rule_pattern(indexed.pattern, expr, initial_bindings)
507+
for indexed in pattern_buckets.patterns_for_node(expr) {
508+
if match_node_rule_pattern(indexed.pattern, expr, initial_bindings)
507509
is Some(_) {
508510
hits.push({
509511
file,
510512
rule_id: rule.rule_id,
511513
description: rule.description,
512514
pattern_index: indexed.pattern_index,
513-
loc: expr.loc(),
515+
loc: expr.loc,
514516
outer_loc,
515517
})
516518
return RulePrune
517519
}
518520
}
519-
if ast_negative_patterns_match_expr(
521+
if ast_negative_patterns_match_node(
520522
negative_pattern_buckets, expr, initial_bindings,
521523
) {
522524
return RulePrune
@@ -525,13 +527,13 @@ fn apply_ast_patterns_at_expr(
525527
}
526528

527529
///|
528-
fn ast_negative_patterns_match_expr(
530+
fn ast_negative_patterns_match_node(
529531
negative_pattern_buckets : ExprPatternBuckets,
530-
expr : @syntax.Expr,
532+
expr : @untyped_ast.Node,
531533
initial_bindings : @hashmap.HashMap[String, @matching.BoundValue]?,
532534
) -> Bool {
533-
for indexed in negative_pattern_buckets.patterns_for_expr(expr) {
534-
if match_ast_rule_pattern(indexed.pattern, expr, initial_bindings)
535+
for indexed in negative_pattern_buckets.patterns_for_node(expr) {
536+
if match_node_rule_pattern(indexed.pattern, expr, initial_bindings)
535537
is Some(_) {
536538
return true
537539
}
@@ -614,19 +616,6 @@ fn names_contain(names : Array[String], needle : String) -> Bool {
614616
false
615617
}
616618

617-
///|
618-
fn match_ast_rule_pattern(
619-
pattern : CompiledRulePattern,
620-
expr : @syntax.Expr,
621-
initial_bindings : @hashmap.HashMap[String, @matching.BoundValue]?,
622-
) -> @matching.ExprMatch? {
623-
match_node_rule_pattern(
624-
pattern,
625-
@untyped_ast.from_expr(expr),
626-
initial_bindings,
627-
)
628-
}
629-
630619
///|
631620
fn match_node_rule_pattern(
632621
pattern : CompiledRulePattern,

0 commit comments

Comments
 (0)