1
1
import Parser from "web-tree-sitter" ;
2
2
import { type BasicBlock , BlockHandler } from "./cfg-defs.ts" ;
3
+ import { evolve } from "./evolve.ts" ;
4
+
5
+ const defaultQueryOptions : Parser . QueryOptions = { maxStartDepth : 0 } ;
3
6
4
7
function matchQuery (
5
8
syntax : Parser . SyntaxNode ,
6
9
queryString : string ,
10
+ options ?: Parser . QueryOptions ,
7
11
) : Parser . QueryMatch {
8
12
const language = syntax . tree . getLanguage ( ) ;
9
13
const query = language . query ( queryString ) ;
10
- const matches = query . matches ( syntax , { maxStartDepth : 0 } ) ;
14
+ options = evolve ( defaultQueryOptions , options ?? { } ) ;
15
+ const matches = query . matches ( syntax , options ) ;
16
+
11
17
if ( matches . length === 0 ) {
12
18
throw new Error ( `No match found for query.` ) ;
13
19
}
20
+ // @ts -expect-error: tsc can't deduce that an element must exist.
14
21
return matches [ 0 ] ;
15
22
}
16
23
17
24
export function matchExistsIn (
18
25
syntax : Parser . SyntaxNode ,
19
- mainName : string ,
20
26
queryString : string ,
21
27
) : boolean {
22
28
const language = syntax . tree . getLanguage ( ) ;
@@ -32,6 +38,14 @@ function getSyntax(
32
38
return getSyntaxMany ( match , name ) [ 0 ] ;
33
39
}
34
40
41
+ function getLastSyntax (
42
+ match : Parser . QueryMatch ,
43
+ name : string ,
44
+ ) : Parser . SyntaxNode | undefined {
45
+ const many = getSyntaxMany ( match , name ) ;
46
+ return many [ many . length - 1 ] ;
47
+ }
48
+
35
49
function requireSyntax (
36
50
match : Parser . QueryMatch ,
37
51
name : string ,
@@ -54,16 +68,20 @@ function getSyntaxMany(
54
68
55
69
export class BlockMatcher {
56
70
private blockHandler : BlockHandler = new BlockHandler ( ) ;
57
- private processBlock : ( syntax : Parser . SyntaxNode | null ) => BasicBlock ;
71
+ private dispatchSingle : ( syntax : Parser . SyntaxNode | null ) => BasicBlock ;
58
72
public update = this . blockHandler . update . bind ( this . blockHandler ) ;
59
73
60
- constructor ( processBlock : BlockMatcher [ "processBlock " ] ) {
61
- this . processBlock = processBlock ;
74
+ constructor ( dispatchSingle : BlockMatcher [ "dispatchSingle " ] ) {
75
+ this . dispatchSingle = dispatchSingle ;
62
76
}
63
77
64
- public match ( syntax : Parser . SyntaxNode , queryString : string ) : Match {
65
- const match = matchQuery ( syntax , queryString ) ;
66
- return new Match ( match , this . blockHandler , this . processBlock ) ;
78
+ public match (
79
+ syntax : Parser . SyntaxNode ,
80
+ queryString : string ,
81
+ options ?: Parser . QueryOptions ,
82
+ ) : Match {
83
+ const match = matchQuery ( syntax , queryString , options ) ;
84
+ return new Match ( match , this . blockHandler , this . dispatchSingle ) ;
67
85
}
68
86
69
87
public tryMatch (
@@ -82,32 +100,57 @@ export class BlockMatcher {
82
100
}
83
101
}
84
102
103
+ /**
104
+ * Maintains a single {Parser.QueryMatch} and allows accesing the captures within it.
105
+ */
85
106
export class Match {
86
107
private match : Parser . QueryMatch ;
87
108
private blockHandler : BlockHandler ;
88
- private processBlock : BlockMatcher [ "processBlock " ] ;
109
+ private dispatchSingle : BlockMatcher [ "dispatchSingle " ] ;
89
110
constructor (
90
111
match : Parser . QueryMatch ,
91
112
blockHandler : BlockHandler ,
92
- processBlock : BlockMatcher [ "processBlock " ] ,
113
+ dispatchSingle : BlockMatcher [ "dispatchSingle " ] ,
93
114
) {
94
115
this . match = match ;
95
116
this . blockHandler = blockHandler ;
96
- this . processBlock = processBlock ;
117
+ this . dispatchSingle = dispatchSingle ;
97
118
}
98
119
120
+ /**
121
+ * Get the first named syntax node from the query match.
122
+ * @param name Name of the capture
123
+ * @returns {Parser.SyntaxNode|undefined } The syntax matching the capture name, if captured.
124
+ */
99
125
public getSyntax ( name : string ) : ReturnType < typeof getSyntax > {
100
126
return getSyntax ( this . match , name ) ;
101
127
}
102
128
129
+ public getLastSyntax ( name : string ) : ReturnType < typeof getLastSyntax > {
130
+ return getLastSyntax ( this . match , name ) ;
131
+ }
132
+
103
133
public requireSyntax ( name : string ) : ReturnType < typeof requireSyntax > {
104
134
return requireSyntax ( this . match , name ) ;
105
135
}
106
136
107
137
public getSyntaxMany ( name : string ) : ReturnType < typeof getSyntaxMany > {
108
138
return getSyntaxMany ( this . match , name ) ;
109
139
}
110
- public getBlock ( syntax : Parser . SyntaxNode | null | undefined ) {
111
- return syntax ? this . blockHandler . update ( this . processBlock ( syntax ) ) : null ;
140
+
141
+ public getBlock ( syntax : Parser . SyntaxNode ) : BasicBlock ;
142
+ public getBlock (
143
+ syntax : Parser . SyntaxNode | null | undefined ,
144
+ ) : BasicBlock | null ;
145
+ public getBlock (
146
+ syntax : Parser . SyntaxNode | null | undefined ,
147
+ ) : BasicBlock | null {
148
+ return syntax
149
+ ? this . blockHandler . update ( this . dispatchSingle ( syntax ) )
150
+ : null ;
151
+ }
152
+
153
+ public getManyBlocks ( syntaxMany : Parser . SyntaxNode [ ] ) : BasicBlock [ ] {
154
+ return syntaxMany . map ( ( syntax ) => this . getBlock ( syntax ) as BasicBlock ) ;
112
155
}
113
156
}
0 commit comments