11import Parser from "web-tree-sitter" ;
22import { type BasicBlock , BlockHandler } from "./cfg-defs.ts" ;
3+ import { evolve } from "./evolve.ts" ;
4+
5+ const defaultQueryOptions : Parser . QueryOptions = { maxStartDepth : 0 } ;
36
47function matchQuery (
58 syntax : Parser . SyntaxNode ,
69 queryString : string ,
10+ options ?: Parser . QueryOptions ,
711) : Parser . QueryMatch {
812 const language = syntax . tree . getLanguage ( ) ;
913 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+
1117 if ( matches . length === 0 ) {
1218 throw new Error ( `No match found for query.` ) ;
1319 }
20+ // @ts -expect-error: tsc can't deduce that an element must exist.
1421 return matches [ 0 ] ;
1522}
1623
1724export function matchExistsIn (
1825 syntax : Parser . SyntaxNode ,
19- mainName : string ,
2026 queryString : string ,
2127) : boolean {
2228 const language = syntax . tree . getLanguage ( ) ;
@@ -32,6 +38,14 @@ function getSyntax(
3238 return getSyntaxMany ( match , name ) [ 0 ] ;
3339}
3440
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+
3549function requireSyntax (
3650 match : Parser . QueryMatch ,
3751 name : string ,
@@ -54,16 +68,20 @@ function getSyntaxMany(
5468
5569export class BlockMatcher {
5670 private blockHandler : BlockHandler = new BlockHandler ( ) ;
57- private processBlock : ( syntax : Parser . SyntaxNode | null ) => BasicBlock ;
71+ private dispatchSingle : ( syntax : Parser . SyntaxNode | null ) => BasicBlock ;
5872 public update = this . blockHandler . update . bind ( this . blockHandler ) ;
5973
60- constructor ( processBlock : BlockMatcher [ "processBlock " ] ) {
61- this . processBlock = processBlock ;
74+ constructor ( dispatchSingle : BlockMatcher [ "dispatchSingle " ] ) {
75+ this . dispatchSingle = dispatchSingle ;
6276 }
6377
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 ) ;
6785 }
6886
6987 public tryMatch (
@@ -82,32 +100,57 @@ export class BlockMatcher {
82100 }
83101}
84102
103+ /**
104+ * Maintains a single {Parser.QueryMatch} and allows accesing the captures within it.
105+ */
85106export class Match {
86107 private match : Parser . QueryMatch ;
87108 private blockHandler : BlockHandler ;
88- private processBlock : BlockMatcher [ "processBlock " ] ;
109+ private dispatchSingle : BlockMatcher [ "dispatchSingle " ] ;
89110 constructor (
90111 match : Parser . QueryMatch ,
91112 blockHandler : BlockHandler ,
92- processBlock : BlockMatcher [ "processBlock " ] ,
113+ dispatchSingle : BlockMatcher [ "dispatchSingle " ] ,
93114 ) {
94115 this . match = match ;
95116 this . blockHandler = blockHandler ;
96- this . processBlock = processBlock ;
117+ this . dispatchSingle = dispatchSingle ;
97118 }
98119
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+ */
99125 public getSyntax ( name : string ) : ReturnType < typeof getSyntax > {
100126 return getSyntax ( this . match , name ) ;
101127 }
102128
129+ public getLastSyntax ( name : string ) : ReturnType < typeof getLastSyntax > {
130+ return getLastSyntax ( this . match , name ) ;
131+ }
132+
103133 public requireSyntax ( name : string ) : ReturnType < typeof requireSyntax > {
104134 return requireSyntax ( this . match , name ) ;
105135 }
106136
107137 public getSyntaxMany ( name : string ) : ReturnType < typeof getSyntaxMany > {
108138 return getSyntaxMany ( this . match , name ) ;
109139 }
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 ) ;
112155 }
113156}
0 commit comments