├── .gitignore ├── ConsoleReadPasFile.dpr ├── ConsoleReadPasFile.dproj ├── LICENSE ├── README.md ├── TreeSitter.Query.pas ├── TreeSitter.pas ├── TreeSitterLib.pas └── VCLDemo ├── DelphiTreeSitterVCLDemo.dpr ├── DelphiTreeSitterVCLDemo.dproj ├── frmDTSLanguage.dfm ├── frmDTSLanguage.pas ├── frmDTSMain.dfm ├── frmDTSMain.pas ├── frmDTSQuery.dfm └── frmDTSQuery.pas /.gitignore: -------------------------------------------------------------------------------- 1 | # Uncomment these types if you want even more clean repository. But be careful. 2 | # It can make harm to an existing project source. Read explanations below. 3 | # 4 | # Resource files are binaries containing manifest, project icon and version info. 5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. 6 | #*.res 7 | # 8 | # Type library file (binary). In old Delphi versions it should be stored. 9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. 10 | #*.tlb 11 | # 12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. 13 | # Uncomment this if you are not using diagrams or use newer Delphi version. 14 | #*.ddp 15 | # 16 | # Visual LiveBindings file. Added in Delphi XE2. 17 | # Uncomment this if you are not using LiveBindings Designer. 18 | #*.vlb 19 | # 20 | # Deployment Manager configuration file for your project. Added in Delphi XE2. 21 | # Uncomment this if it is not mobile development and you do not use remote debug feature. 22 | #*.deployproj 23 | # 24 | # C++ object files produced when C/C++ Output file generation is configured. 25 | # Uncomment this if you are not using external objects (zlib library for example). 26 | #*.obj 27 | # 28 | 29 | # Delphi compiler-generated binaries (safe to delete) 30 | *.exe 31 | *.dll 32 | *.bpl 33 | *.bpi 34 | *.dcp 35 | *.so 36 | *.apk 37 | *.drc 38 | *.map 39 | *.dres 40 | *.rsm 41 | *.tds 42 | *.dcu 43 | *.lib 44 | *.a 45 | *.o 46 | *.ocx 47 | 48 | # Delphi autogenerated files (duplicated info) 49 | *.cfg 50 | *.hpp 51 | *Resource.rc 52 | 53 | # Delphi local files (user-specific info) 54 | *.local 55 | *.identcache 56 | *.projdata 57 | *.tvsconfig 58 | *.dsk 59 | 60 | # Delphi history and backups 61 | __history/ 62 | __recovery/ 63 | *.~* 64 | 65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi) 66 | *.stat 67 | 68 | # ignore auto-generated project .res files 69 | *.res 70 | 71 | # ignore auto-created DevExpress skin configuration file 72 | *.skincfg 73 | -------------------------------------------------------------------------------- /ConsoleReadPasFile.dpr: -------------------------------------------------------------------------------- 1 | program ConsoleReadPasFile; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | Classes, 9 | System.SysUtils, 10 | IOUtils, 11 | TreeSitter in 'TreeSitter.pas', 12 | TreeSitterLib in 'TreeSitterLib.pas'; 13 | 14 | function tree_sitter_pascal(): PTSLanguage; cdecl; external 'tree-sitter-pascal'; 15 | 16 | procedure ReadAndParsePasFile(const AFileName: string); 17 | var 18 | parser: TTSParser; 19 | fs: TFileStream; 20 | tree: TTSTree; 21 | begin 22 | tree:= nil; 23 | parser:= nil; 24 | fs:= TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone); 25 | try 26 | parser:= TTSParser.Create; 27 | parser.Language:= tree_sitter_pascal; 28 | tree:= parser.parse( 29 | function (AByteIndex: UInt32; APosition: TTSPoint; var ABytesRead: UInt32): TBytes 30 | const 31 | BufSize = 10 * 1024; 32 | begin 33 | if fs.Seek(AByteIndex, soFromBeginning) < 0 then 34 | begin 35 | ABytesRead:= 0; 36 | Exit; 37 | end; 38 | SetLength(Result, BufSize); 39 | try 40 | ABytesRead:= fs.Read(Result, BufSize); 41 | except 42 | ABytesRead:= 0; 43 | end; 44 | SetLength(Result, ABytesRead); 45 | end, TTSInputEncoding.TSInputEncodingUTF8); 46 | 47 | WriteLn(tree.RootNode.ToString); 48 | finally 49 | tree.Free; 50 | parser.Free; 51 | fs.Free; 52 | end; 53 | end; 54 | 55 | var 56 | fn: string; 57 | begin 58 | try 59 | fn:= TPath.Combine(TPath.GetDirectoryName(ParamStr(0)), '..\..\TreeSitter.pas'); 60 | if TFile.Exists(fn) then 61 | ReadAndParsePasFile(fn) else 62 | raise Exception.CreateFmt('Failed to find file to parse: "%s"', [fn]); 63 | ReadLn; 64 | except 65 | on E: Exception do 66 | Writeln(E.ClassName, ': ', E.Message); 67 | end; 68 | end. 69 | -------------------------------------------------------------------------------- /ConsoleReadPasFile.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {45C77D6D-775B-4ECE-8759-F18B4127BF77} 4 | 19.5 5 | None 6 | True 7 | Debug 8 | Win64 9 | 3 10 | Console 11 | ConsoleReadPasFile.dpr 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Base 34 | true 35 | 36 | 37 | true 38 | Base 39 | true 40 | 41 | 42 | true 43 | Base 44 | true 45 | 46 | 47 | true 48 | Base 49 | true 50 | 51 | 52 | true 53 | Cfg_1 54 | true 55 | true 56 | 57 | 58 | true 59 | Base 60 | true 61 | 62 | 63 | .\$(Platform)\$(Config) 64 | .\$(Platform)\$(Config) 65 | false 66 | false 67 | false 68 | false 69 | false 70 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 71 | ConsoleReadPasFile 72 | 73 | 74 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png 75 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png 76 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png 77 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png 78 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png 79 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png 80 | $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png 81 | $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png 82 | $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png 83 | $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png 84 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png 85 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png 86 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png 87 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png 88 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png 89 | 90 | 91 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png 92 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png 93 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png 94 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png 95 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png 96 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png 97 | $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png 98 | $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png 99 | $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png 100 | $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png 101 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png 102 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png 103 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png 104 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png 105 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png 106 | 107 | 108 | fmx;DbxCommonDriver;bindengine;IndyIPCommon;FireDACCommonODBC;FireDACCommonDriver;IndyProtocols;IndyIPClient;dbxcds;bindcompfmx;inetdb;FireDACSqliteDriver;DbxClientDriver;soapmidas;fmxFireDAC;dbexpress;DBXMySQLDriver;inet;fmxase;dbrtl;fmxdae;CustomIPTransport;DBXInterBaseDriver;IndySystem;bindcomp;FireDACCommon;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;FireDACPgDriver;FireDAC;inetdbxpress;xmlrtl;tethering;dsnap;CloudService;fmxobj;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) 109 | true 110 | 111 | 112 | fmx;DbxCommonDriver;bindengine;IndyIPCommon;FireDACCommonODBC;FireDACCommonDriver;IndyProtocols;IndyIPClient;dbxcds;bindcompfmx;inetdb;FireDACSqliteDriver;DbxClientDriver;soapmidas;fmxFireDAC;dbexpress;DBXMySQLDriver;inet;fmxase;dbrtl;fmxdae;CustomIPTransport;DBXInterBaseDriver;IndySystem;bindcomp;FireDACCommon;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;FireDACPgDriver;FireDAC;inetdbxpress;xmlrtl;tethering;dsnap;CloudService;fmxobj;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) 113 | true 114 | 115 | 116 | dxPSdxSpreadSheetLnkRS28;vclwinx;rbIDE2128;rbTC2128;FMXTeeLanguage928;dclRBADO2128;fmx;dxRichEditDocumentModelRS28;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;FireDACCommonODBC;cxExportRS28;rbBDE2128;FireDACCommonDriver;dxHttpIndyRequestRS28;appanalytics;IndyProtocols;vclx;LWJSDialogRXAlexandria;rbRIDE2128;IndyIPClient;dbxcds;vcledge;cxLibraryRS28;dxCloudServiceLibraryRS28;bindcompvclwinx;rbCIDE2128;dxTileControlRS28;cxPivotGridOLAPRS28;dxPScxPivotGridLnkRS28;dxPScxVGridLnkRS28;dxGDIPlusRS28;dclRBE2128;dxPSdxDBOCLnkRS28;TeeUI928;bindcompfmx;TeeGL928;madBasic_;dxCoreRS28;cxPivotGridRS28;TeeTree2D28Tee9;dxPSdxPDFViewerLnkRS28;inetdb;FixInsight_11;dxSpreadSheetCoreRS28;dxPSCoreRS28;FireDACSqliteDriver;DbxClientDriver;dxSpreadSheetRS28;dxSkinsCoreRS28;rbFireDAC2128;dxTabbedMDIRS28;FmxTeeUI928;soapmidas;dxBarRS28;vclactnband;dxWizardControlRS28;dxADOServerModeRS28;fmxFireDAC;dbexpress;dxFireDACServerModeRS28;TeeImport928;dclRBDBE2128;FMXTree28;DBXMySQLDriver;TeeLanguage928;VclSmp;inet;dxServerModeRS28;dxPSdxLCLnkRS28;vcltouch;fmxase;cxTreeListRS28;dxBarDBNavRS28;LWRXAlexandriaPackage;dbrtl;TeeMaker128;dxPSLnksRS28;fmxdae;dxPScxCommonRS28;FireDACMSAccDriver;dxNavBarRS28;CustomIPTransport;rbDAD2128;rbRCL2128;dxSpreadSheetReportDesignerRS28;TeePro928;dxChartControlRS28;vcldsnap;madExcept_;dxComnRS28;DBXInterBaseDriver;dxFlowChartDesignerRS28;IndySystem;dxSpreadSheetConditionalFormattingDialogsRS28;cxVerticalGridRS28;FMXTeeDB928;dxOrgChartAdvancedCustomizeFormRS28;vcldb;dxDBXServerModeRS28;dxmdsRS28;dxRichEditControlRS28;dxRibbonRS28;VirtualTreesR;dxPSdxOCLnkRS28;dxFlowChartLayoutsRS28;dxPScxExtCommonRS28;ActiveXTest;rbRAP2128;dxdborRS28;vclFireDAC;madDisAsm_;dxRichEditControlCoreRS28;bindcomp;FireDACCommon;rbDBE2128;rbDIDE2128;dxPsPrVwAdvRS28;FMXTeePro928;dxRibbonCustomizationFormRS28;IndyCore;RESTBackendComponents;dxPScxGridLnkRS28;cxPivotGridChartRS28;rbDB2128;bindcompdbx;dxBarExtDBItemsRS28;dxRichEditCoreRS28;cxTreeListdxBarPopupMenuRS28;rtl;FireDACMySQLDriver;dxDockingRS28;dxPDFViewerRS28;FireDACADSDriver;rbCloudSC2128;dxGaugeControlRS28;dxFlowChartAdvancedCustomizeFormRS28;rbUSERDesign2128;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;adortl;dxBarExtItemsRS28;dxPSdxFCLnkRS28;dxorgcRS28;rbRest2128;dxSpreadSheetCoreConditionalFormattingDialogsRS28;TeeImage928;rbTCUI2128;TeeDB928;FMXTee928;dxPSdxGaugeControlLnkRS28;dxPSRichEditControlLnkRS28;cxGridRS28;rbADO2128;vclimg;FireDACPgDriver;FireDAC;inetdbxpress;GLScene_RunTime;xmlrtl;tethering;rbUSER2128;TeeWorld928;bindcompvcl;dsnap;rbRTL2128;CloudService;dxPScxTLLnkRS28;LWHanauRX11;fmxobj;bindcompvclsmp;Tee928;dclRBFireDAC2128;dxFlowChartRS28;dxPScxPCProdRS28;soaprtl;FMXTeeImport928;soapserver;FireDACIBDriver;$(DCC_UsePackage) 117 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 118 | Debug 119 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 120 | 1033 121 | true 122 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 123 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 124 | 125 | 126 | dxPSdxSpreadSheetLnkRS28;vclwinx;fmx;dxRichEditDocumentModelRS28;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;FireDACCommonODBC;cxExportRS28;FireDACCommonDriver;dxHttpIndyRequestRS28;appanalytics;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;cxLibraryRS28;dxCloudServiceLibraryRS28;bindcompvclwinx;dxTileControlRS28;cxPivotGridOLAPRS28;dxPScxPivotGridLnkRS28;dxPScxVGridLnkRS28;dxGDIPlusRS28;dxPSdxDBOCLnkRS28;bindcompfmx;dxCoreRS28;cxPivotGridRS28;dxPSdxPDFViewerLnkRS28;inetdb;dxSpreadSheetCoreRS28;dxPSCoreRS28;FireDACSqliteDriver;DbxClientDriver;dxSpreadSheetRS28;dxSkinsCoreRS28;dxTabbedMDIRS28;soapmidas;dxBarRS28;vclactnband;dxWizardControlRS28;dxADOServerModeRS28;fmxFireDAC;dbexpress;dxFireDACServerModeRS28;DBXMySQLDriver;VclSmp;inet;dxServerModeRS28;dxPSdxLCLnkRS28;vcltouch;fmxase;cxTreeListRS28;dxBarDBNavRS28;dbrtl;dxPSLnksRS28;fmxdae;dxPScxCommonRS28;FireDACMSAccDriver;dxNavBarRS28;CustomIPTransport;dxSpreadSheetReportDesignerRS28;dxChartControlRS28;vcldsnap;dxComnRS28;DBXInterBaseDriver;dxFlowChartDesignerRS28;IndySystem;dxSpreadSheetConditionalFormattingDialogsRS28;cxVerticalGridRS28;dxOrgChartAdvancedCustomizeFormRS28;vcldb;dxDBXServerModeRS28;dxmdsRS28;dxRichEditControlRS28;dxRibbonRS28;VirtualTreesR;dxPSdxOCLnkRS28;dxFlowChartLayoutsRS28;dxPScxExtCommonRS28;dxdborRS28;vclFireDAC;dxRichEditControlCoreRS28;bindcomp;FireDACCommon;dxPsPrVwAdvRS28;dxRibbonCustomizationFormRS28;IndyCore;RESTBackendComponents;dxPScxGridLnkRS28;cxPivotGridChartRS28;bindcompdbx;dxBarExtDBItemsRS28;dxRichEditCoreRS28;cxTreeListdxBarPopupMenuRS28;rtl;FireDACMySQLDriver;dxDockingRS28;dxPDFViewerRS28;FireDACADSDriver;dxGaugeControlRS28;dxFlowChartAdvancedCustomizeFormRS28;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;adortl;dxBarExtItemsRS28;dxPSdxFCLnkRS28;dxorgcRS28;dxSpreadSheetCoreConditionalFormattingDialogsRS28;dxPSdxGaugeControlLnkRS28;dxPSRichEditControlLnkRS28;cxGridRS28;vclimg;FireDACPgDriver;FireDAC;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;CloudService;dxPScxTLLnkRS28;fmxobj;bindcompvclsmp;dxFlowChartRS28;dxPScxPCProdRS28;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) 127 | true 128 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 129 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 130 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) 131 | Debug 132 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 133 | 1033 134 | 135 | 136 | DEBUG;$(DCC_Define) 137 | true 138 | false 139 | true 140 | true 141 | true 142 | true 143 | true 144 | 145 | 146 | false 147 | 148 | 149 | false 150 | RELEASE;$(DCC_Define) 151 | 0 152 | 0 153 | 154 | 155 | 156 | MainSource 157 | 158 | 159 | 160 | 161 | Base 162 | 163 | 164 | Cfg_1 165 | Base 166 | 167 | 168 | Cfg_2 169 | Base 170 | 171 | 172 | 173 | Delphi.Personality.12 174 | Application 175 | 176 | 177 | 178 | ConsoleReadPasFile.dpr 179 | 180 | 181 | 182 | 183 | 184 | true 185 | 186 | 187 | 188 | 189 | true 190 | 191 | 192 | 193 | 194 | true 195 | 196 | 197 | 198 | 199 | ConsoleReadPasFile.exe 200 | true 201 | 202 | 203 | 204 | 205 | 1 206 | 207 | 208 | Contents\MacOS 209 | 1 210 | 211 | 212 | 0 213 | 214 | 215 | 216 | 217 | classes 218 | 64 219 | 220 | 221 | classes 222 | 64 223 | 224 | 225 | 226 | 227 | res\xml 228 | 1 229 | 230 | 231 | res\xml 232 | 1 233 | 234 | 235 | 236 | 237 | library\lib\armeabi-v7a 238 | 1 239 | 240 | 241 | 242 | 243 | library\lib\armeabi 244 | 1 245 | 246 | 247 | library\lib\armeabi 248 | 1 249 | 250 | 251 | 252 | 253 | library\lib\armeabi-v7a 254 | 1 255 | 256 | 257 | 258 | 259 | library\lib\mips 260 | 1 261 | 262 | 263 | library\lib\mips 264 | 1 265 | 266 | 267 | 268 | 269 | library\lib\armeabi-v7a 270 | 1 271 | 272 | 273 | library\lib\arm64-v8a 274 | 1 275 | 276 | 277 | 278 | 279 | library\lib\armeabi-v7a 280 | 1 281 | 282 | 283 | 284 | 285 | res\drawable 286 | 1 287 | 288 | 289 | res\drawable 290 | 1 291 | 292 | 293 | 294 | 295 | res\values 296 | 1 297 | 298 | 299 | res\values 300 | 1 301 | 302 | 303 | 304 | 305 | res\values-v21 306 | 1 307 | 308 | 309 | res\values-v21 310 | 1 311 | 312 | 313 | 314 | 315 | res\values 316 | 1 317 | 318 | 319 | res\values 320 | 1 321 | 322 | 323 | 324 | 325 | res\drawable 326 | 1 327 | 328 | 329 | res\drawable 330 | 1 331 | 332 | 333 | 334 | 335 | res\drawable-xxhdpi 336 | 1 337 | 338 | 339 | res\drawable-xxhdpi 340 | 1 341 | 342 | 343 | 344 | 345 | res\drawable-xxxhdpi 346 | 1 347 | 348 | 349 | res\drawable-xxxhdpi 350 | 1 351 | 352 | 353 | 354 | 355 | res\drawable-ldpi 356 | 1 357 | 358 | 359 | res\drawable-ldpi 360 | 1 361 | 362 | 363 | 364 | 365 | res\drawable-mdpi 366 | 1 367 | 368 | 369 | res\drawable-mdpi 370 | 1 371 | 372 | 373 | 374 | 375 | res\drawable-hdpi 376 | 1 377 | 378 | 379 | res\drawable-hdpi 380 | 1 381 | 382 | 383 | 384 | 385 | res\drawable-xhdpi 386 | 1 387 | 388 | 389 | res\drawable-xhdpi 390 | 1 391 | 392 | 393 | 394 | 395 | res\drawable-mdpi 396 | 1 397 | 398 | 399 | res\drawable-mdpi 400 | 1 401 | 402 | 403 | 404 | 405 | res\drawable-hdpi 406 | 1 407 | 408 | 409 | res\drawable-hdpi 410 | 1 411 | 412 | 413 | 414 | 415 | res\drawable-xhdpi 416 | 1 417 | 418 | 419 | res\drawable-xhdpi 420 | 1 421 | 422 | 423 | 424 | 425 | res\drawable-xxhdpi 426 | 1 427 | 428 | 429 | res\drawable-xxhdpi 430 | 1 431 | 432 | 433 | 434 | 435 | res\drawable-xxxhdpi 436 | 1 437 | 438 | 439 | res\drawable-xxxhdpi 440 | 1 441 | 442 | 443 | 444 | 445 | res\drawable-small 446 | 1 447 | 448 | 449 | res\drawable-small 450 | 1 451 | 452 | 453 | 454 | 455 | res\drawable-normal 456 | 1 457 | 458 | 459 | res\drawable-normal 460 | 1 461 | 462 | 463 | 464 | 465 | res\drawable-large 466 | 1 467 | 468 | 469 | res\drawable-large 470 | 1 471 | 472 | 473 | 474 | 475 | res\drawable-xlarge 476 | 1 477 | 478 | 479 | res\drawable-xlarge 480 | 1 481 | 482 | 483 | 484 | 485 | res\values 486 | 1 487 | 488 | 489 | res\values 490 | 1 491 | 492 | 493 | 494 | 495 | 1 496 | 497 | 498 | Contents\MacOS 499 | 1 500 | 501 | 502 | 0 503 | 504 | 505 | 506 | 507 | Contents\MacOS 508 | 1 509 | .framework 510 | 511 | 512 | Contents\MacOS 513 | 1 514 | .framework 515 | 516 | 517 | Contents\MacOS 518 | 1 519 | .framework 520 | 521 | 522 | 0 523 | 524 | 525 | 526 | 527 | 1 528 | .dylib 529 | 530 | 531 | 1 532 | .dylib 533 | 534 | 535 | 1 536 | .dylib 537 | 538 | 539 | Contents\MacOS 540 | 1 541 | .dylib 542 | 543 | 544 | Contents\MacOS 545 | 1 546 | .dylib 547 | 548 | 549 | Contents\MacOS 550 | 1 551 | .dylib 552 | 553 | 554 | 0 555 | .dll;.bpl 556 | 557 | 558 | 559 | 560 | 1 561 | .dylib 562 | 563 | 564 | 1 565 | .dylib 566 | 567 | 568 | 1 569 | .dylib 570 | 571 | 572 | Contents\MacOS 573 | 1 574 | .dylib 575 | 576 | 577 | Contents\MacOS 578 | 1 579 | .dylib 580 | 581 | 582 | Contents\MacOS 583 | 1 584 | .dylib 585 | 586 | 587 | 0 588 | .bpl 589 | 590 | 591 | 592 | 593 | 0 594 | 595 | 596 | 0 597 | 598 | 599 | 0 600 | 601 | 602 | 0 603 | 604 | 605 | 0 606 | 607 | 608 | Contents\Resources\StartUp\ 609 | 0 610 | 611 | 612 | Contents\Resources\StartUp\ 613 | 0 614 | 615 | 616 | Contents\Resources\StartUp\ 617 | 0 618 | 619 | 620 | 0 621 | 622 | 623 | 624 | 625 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 626 | 1 627 | 628 | 629 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 630 | 1 631 | 632 | 633 | 634 | 635 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 636 | 1 637 | 638 | 639 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 640 | 1 641 | 642 | 643 | 644 | 645 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 646 | 1 647 | 648 | 649 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 650 | 1 651 | 652 | 653 | 654 | 655 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 656 | 1 657 | 658 | 659 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 660 | 1 661 | 662 | 663 | 664 | 665 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 666 | 1 667 | 668 | 669 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 670 | 1 671 | 672 | 673 | 674 | 675 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 676 | 1 677 | 678 | 679 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 680 | 1 681 | 682 | 683 | 684 | 685 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 686 | 1 687 | 688 | 689 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 690 | 1 691 | 692 | 693 | 694 | 695 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 696 | 1 697 | 698 | 699 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 700 | 1 701 | 702 | 703 | 704 | 705 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 706 | 1 707 | 708 | 709 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 710 | 1 711 | 712 | 713 | 714 | 715 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 716 | 1 717 | 718 | 719 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 720 | 1 721 | 722 | 723 | 724 | 725 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 726 | 1 727 | 728 | 729 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 730 | 1 731 | 732 | 733 | 734 | 735 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 736 | 1 737 | 738 | 739 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 740 | 1 741 | 742 | 743 | 744 | 745 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 746 | 1 747 | 748 | 749 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 750 | 1 751 | 752 | 753 | 754 | 755 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 756 | 1 757 | 758 | 759 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 760 | 1 761 | 762 | 763 | 764 | 765 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 766 | 1 767 | 768 | 769 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 770 | 1 771 | 772 | 773 | 774 | 775 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 776 | 1 777 | 778 | 779 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 780 | 1 781 | 782 | 783 | 784 | 785 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 786 | 1 787 | 788 | 789 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 790 | 1 791 | 792 | 793 | 794 | 795 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 796 | 1 797 | 798 | 799 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 800 | 1 801 | 802 | 803 | 804 | 805 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 806 | 1 807 | 808 | 809 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 810 | 1 811 | 812 | 813 | 814 | 815 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 816 | 1 817 | 818 | 819 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 820 | 1 821 | 822 | 823 | 824 | 825 | 1 826 | 827 | 828 | 1 829 | 830 | 831 | 832 | 833 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 834 | 1 835 | 836 | 837 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 838 | 1 839 | 840 | 841 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 842 | 1 843 | 844 | 845 | 846 | 847 | ..\ 848 | 1 849 | 850 | 851 | ..\ 852 | 1 853 | 854 | 855 | ..\ 856 | 1 857 | 858 | 859 | 860 | 861 | 1 862 | 863 | 864 | 1 865 | 866 | 867 | 1 868 | 869 | 870 | 871 | 872 | ..\$(PROJECTNAME).launchscreen 873 | 64 874 | 875 | 876 | ..\$(PROJECTNAME).launchscreen 877 | 64 878 | 879 | 880 | 881 | 882 | 1 883 | 884 | 885 | 1 886 | 887 | 888 | 1 889 | 890 | 891 | 892 | 893 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 894 | 1 895 | 896 | 897 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 898 | 1 899 | 900 | 901 | 902 | 903 | ..\ 904 | 1 905 | 906 | 907 | ..\ 908 | 1 909 | 910 | 911 | ..\ 912 | 1 913 | 914 | 915 | 916 | 917 | Contents 918 | 1 919 | 920 | 921 | Contents 922 | 1 923 | 924 | 925 | Contents 926 | 1 927 | 928 | 929 | 930 | 931 | Contents\Resources 932 | 1 933 | 934 | 935 | Contents\Resources 936 | 1 937 | 938 | 939 | Contents\Resources 940 | 1 941 | 942 | 943 | 944 | 945 | library\lib\armeabi-v7a 946 | 1 947 | 948 | 949 | library\lib\arm64-v8a 950 | 1 951 | 952 | 953 | 1 954 | 955 | 956 | 1 957 | 958 | 959 | 1 960 | 961 | 962 | 1 963 | 964 | 965 | Contents\MacOS 966 | 1 967 | 968 | 969 | Contents\MacOS 970 | 1 971 | 972 | 973 | Contents\MacOS 974 | 1 975 | 976 | 977 | 0 978 | 979 | 980 | 981 | 982 | library\lib\armeabi-v7a 983 | 1 984 | 985 | 986 | 987 | 988 | 1 989 | 990 | 991 | 1 992 | 993 | 994 | 995 | 996 | Assets 997 | 1 998 | 999 | 1000 | Assets 1001 | 1 1002 | 1003 | 1004 | 1005 | 1006 | Assets 1007 | 1 1008 | 1009 | 1010 | Assets 1011 | 1 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | False 1028 | False 1029 | False 1030 | False 1031 | True 1032 | True 1033 | 1034 | 1035 | 12 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 modersohn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # delphi-tree-sitter 2 | 3 | Delphi (and potentially FreePascal) bindings for [tree-sitter][] 4 | 5 | [tree-sitter]: https://github.com/tree-sitter/tree-sitter 6 | 7 | ## Status 8 | 9 | Windows only for now and only tested with Delphi. 10 | 11 | 12 | | API section | Status | 13 | | --- | --- | 14 | | Parser | Basics covered | 15 | | Language | Mostly complete | 16 | | Tree | Mostly complete | 17 | | TreeCursor | Mostly complete | 18 | | Node | Mostly complete | 19 | | Query | Mostly complete | 20 | | QueryCursor | Mostly complete | 21 | | LookAheadIterator | Missing | 22 | | WebAssembly Integration | Missing | 23 | 24 | ## Installation 25 | 26 | No design-time packages etc. necessary. The demos with GUI - as of yet - do not require any additional 3rd party packages. 27 | 28 | To run the demos, you need to have `tree-sitter.dll` (of the right architecure) somewhere, where the EXE will 29 | be able to find it (it won't even start without). 30 | 31 | For the different parsers (sometimes called grammars) you need a DLL too, e.g. [tree-sitter-c][] 32 | 33 | If you don't have a C compiler setup at hand to compile the tree-sitter DLLs, I can highly recommend [zig][]. 34 | 35 | Tree-sitter itself already comes with a `build.zig` file, so running `zig build` in the root directory of tree-sitter will work. 36 | This might build a .lib instead of a .dll, so in `build.zig` you would need to change `b.addStaticLibrary` into `b.addSharedLibrary`. 37 | 38 | Most parsers do not seem to come with zig-support out of the box, but it should be straightforward to create a `build.zig` and use the one from tree-sitter itself as a template. 39 | 40 | [tree-sitter-c]: https://github.com/tree-sitter/tree-sitter-c 41 | [zig]: https://ziglang.org 42 | 43 | ## VCL demo project 44 | 45 | Instead of demoing a typical use-case, the VCL demo is intended to allow exploring the API and functionality that tree-sitter supplies. 46 | ![image](https://github.com/modersohn/delphi-tree-sitter/assets/44807458/27319bec-f3b6-4a67-8329-f67cc7d9d079) 47 | 48 | Currently supports a handful of languages out of the box and a treeview of nodes with field name and ID where applicable. Selects the corresponding code part in the memo when a node gets selected. 49 | 50 | Inspector-like grid with node properties. Navigation via popup menu of the tree. Lists field names of the language and allows finding child node by field ID. 51 | 52 | Now with secondary form listing symbols, fields and version of the language: 53 | ![image](https://github.com/modersohn/delphi-tree-sitter/assets/44807458/1243f2fe-ca26-4658-a24e-55ab11c5c153) 54 | 55 | New query form, showing info about the query and allowing iterating over matches and listing their captures. Selecting a capture, selects the captured node in the main form and selects the corresponding code section: 56 | ![image](https://github.com/modersohn/delphi-tree-sitter/assets/44807458/ac2cba4f-06b2-4a02-8bb4-d02f5adac857) 57 | 58 | ## Console demo project loading .pas 59 | 60 | [Simple console project](ConsoleReadPasFile.dpr) which demonstrates TTSParser.Parse called with an anonymous method for reading the text to parse. 61 | -------------------------------------------------------------------------------- /TreeSitter.Query.pas: -------------------------------------------------------------------------------- 1 | unit TreeSitter.Query; 2 | 3 | interface 4 | 5 | uses 6 | TreeSitterLib, TreeSitter; 7 | 8 | type 9 | TTSQueryError = TreeSitterLib.TSQueryError; 10 | TTSQueryPredicateStep = TreeSitterLib.TSQueryPredicateStep; 11 | TTSQueryPredicateStepType = TreeSitterLib.TSQueryPredicateStepType; 12 | 13 | TTSQueryPredicateStepArray = array of TTSQueryPredicateStep; 14 | TTSQuantifier = TreeSitterLib.TSQuantifier; 15 | 16 | TTSQuery = class 17 | strict private 18 | FQuery: PTSQuery; 19 | public 20 | constructor Create(ALanguage: PTSLanguage; const ASource: string; 21 | var AErrorOffset: UInt32; var AErrorType: TTSQueryError); virtual; 22 | destructor Destroy; override; 23 | 24 | function PatternCount: UInt32; 25 | function CaptureCount: UInt32; 26 | function StringCount: UInt32; 27 | 28 | function StartByteForPattern(APatternIndex: UInt32): UInt32; 29 | function PredicatesForPattern(APatternIndex: UInt32): TTSQueryPredicateStepArray; 30 | 31 | function CaptureNameForID(ACaptureIndex: UInt32): string; 32 | function StringValueForID(AStringIndex: UInt32): string; 33 | 34 | function QuantifierForCapture(APatternIndex, ACaptureIndex: UInt32): TTSQuantifier; 35 | 36 | property Query: PTSQuery read FQuery; 37 | end; 38 | 39 | TTSQueryCapture = TreeSitterLib.TSQueryCapture; 40 | TTSQueryCaptureArray = array of TTSQueryCapture; 41 | 42 | TTSQueryMatch = TreeSitterLib.TSQueryMatch; 43 | 44 | TTSQueryMatchHelper = record helper for TTSQueryMatch 45 | function CapturesArray: TTSQueryCaptureArray; 46 | end; 47 | 48 | TTSQueryCursor = class 49 | strict private 50 | FQueryCursor: PTSQueryCursor; 51 | 52 | function GetMatchLimit: UInt32; 53 | procedure SetMatchLimit(const Value: UInt32); 54 | public 55 | constructor Create; virtual; 56 | destructor Destroy; override; 57 | 58 | procedure Execute(AQuery: TTSQuery; ANode: TTSNode); 59 | function DidExceedMatchLimit: Boolean; 60 | procedure SetMaxStartDepth(AMaxStartDepth: UInt32); 61 | 62 | function NextMatch(var AMatch: TTSQueryMatch): Boolean; 63 | function NextCapture(var AMatch: TTSQueryMatch; var ACaptureIndex: UInt32): Boolean; 64 | 65 | property QueryCursor: PTSQueryCursor read FQueryCursor; 66 | property MatchLimit: UInt32 read GetMatchLimit write SetMatchLimit; 67 | end; 68 | 69 | 70 | implementation 71 | 72 | { TTSQuery } 73 | 74 | function TTSQuery.CaptureCount: UInt32; 75 | begin 76 | Result:= ts_query_capture_count(FQuery); 77 | end; 78 | 79 | function TTSQuery.CaptureNameForID(ACaptureIndex: UInt32): string; 80 | var 81 | pac: PAnsiChar; 82 | len: UInt32; 83 | res: AnsiString; 84 | begin 85 | pac:= ts_query_capture_name_for_id(FQuery, ACaptureIndex, len); 86 | SetLength(res, len); 87 | if len > 0 then 88 | Move(pac[0], res[1], len * SizeOf(pac[0])); 89 | Result:= string(res); 90 | end; 91 | 92 | constructor TTSQuery.Create(ALanguage: PTSLanguage; const ASource: string; 93 | var AErrorOffset: UInt32; var AErrorType: TTSQueryError); 94 | var 95 | ansiSource: AnsiString; 96 | begin 97 | ansiSource:= AnsiString(ASource); 98 | FQuery:= ts_query_new(ALanguage, PAnsiChar(ansiSource), Length(ansiSource), 99 | AErrorOffset, AErrorType); 100 | end; 101 | 102 | destructor TTSQuery.Destroy; 103 | begin 104 | ts_query_delete(FQuery); 105 | inherited; 106 | end; 107 | 108 | function TTSQuery.PatternCount: UInt32; 109 | begin 110 | Result:= ts_query_pattern_count(FQuery); 111 | end; 112 | 113 | function TTSQuery.PredicatesForPattern( 114 | APatternIndex: UInt32): TTSQueryPredicateStepArray; 115 | var 116 | count: UInt32; 117 | parr: PTSQueryPredicateStepArray; 118 | begin 119 | count:= 0; 120 | parr:= ts_query_predicates_for_pattern(FQuery, APatternIndex, count); 121 | if (parr <> nil) and (count > 0) then 122 | begin 123 | SetLength(Result, count); 124 | Move(parr[0], Result[0], count * SizeOf(Result[0])); 125 | end; 126 | end; 127 | 128 | function TTSQuery.QuantifierForCapture(APatternIndex, 129 | ACaptureIndex: UInt32): TTSQuantifier; 130 | begin 131 | Result:= ts_query_capture_quantifier_for_id(FQuery, APatternIndex, ACaptureIndex); 132 | end; 133 | 134 | function TTSQuery.StartByteForPattern(APatternIndex: UInt32): UInt32; 135 | begin 136 | Result:= ts_query_start_byte_for_pattern(FQuery, APatternIndex); 137 | end; 138 | 139 | function TTSQuery.StringCount: UInt32; 140 | begin 141 | Result:= ts_query_string_count(FQuery); 142 | end; 143 | 144 | function TTSQuery.StringValueForID(AStringIndex: UInt32): string; 145 | var 146 | pac: PAnsiChar; 147 | len: UInt32; 148 | res: AnsiString; 149 | begin 150 | pac:= ts_query_string_value_for_id(FQuery, AStringIndex, len); 151 | SetLength(res, len); 152 | if len > 0 then 153 | Move(pac[0], res[1], len * SizeOf(pac[0])); 154 | Result:= string(res); 155 | end; 156 | 157 | { TTSQueryCursor } 158 | 159 | constructor TTSQueryCursor.Create; 160 | begin 161 | FQueryCursor:= ts_query_cursor_new; 162 | end; 163 | 164 | destructor TTSQueryCursor.Destroy; 165 | begin 166 | ts_query_cursor_delete(FQueryCursor); 167 | inherited; 168 | end; 169 | 170 | function TTSQueryCursor.DidExceedMatchLimit: Boolean; 171 | begin 172 | Result:= ts_query_cursor_did_exceed_match_limit(FQueryCursor); 173 | end; 174 | 175 | procedure TTSQueryCursor.Execute(AQuery: TTSQuery; ANode: TTSNode); 176 | begin 177 | ts_query_cursor_exec(FQueryCursor, AQuery.Query, ANode); 178 | end; 179 | 180 | function TTSQueryCursor.GetMatchLimit: UInt32; 181 | begin 182 | Result:= ts_query_cursor_match_limit(FQueryCursor); 183 | end; 184 | 185 | function TTSQueryCursor.NextCapture(var AMatch: TTSQueryMatch; 186 | var ACaptureIndex: UInt32): Boolean; 187 | begin 188 | Result:= ts_query_cursor_next_capture(FQueryCursor, AMatch, ACaptureIndex); 189 | end; 190 | 191 | function TTSQueryCursor.NextMatch(var AMatch: TTSQueryMatch): Boolean; 192 | begin 193 | Result:= ts_query_cursor_next_match(FQueryCursor, AMatch); 194 | end; 195 | 196 | procedure TTSQueryCursor.SetMatchLimit(const Value: UInt32); 197 | begin 198 | ts_query_cursor_set_match_limit(FQueryCursor, Value); 199 | end; 200 | 201 | procedure TTSQueryCursor.SetMaxStartDepth(AMaxStartDepth: UInt32); 202 | begin 203 | ts_query_cursor_set_max_start_depth(FQueryCursor, AMaxStartDepth); 204 | end; 205 | 206 | { TTSQueryMatchHelper } 207 | 208 | function TTSQueryMatchHelper.CapturesArray: TTSQueryCaptureArray; 209 | begin 210 | SetLength(Result, capture_count); 211 | if capture_count > 0 then 212 | Move(captures[0], Result[0], capture_count * SizeOf(captures[0])); 213 | end; 214 | 215 | end. 216 | -------------------------------------------------------------------------------- /TreeSitter.pas: -------------------------------------------------------------------------------- 1 | unit TreeSitter; 2 | 3 | interface 4 | 5 | uses 6 | SysUtils, 7 | TreeSitterLib; 8 | 9 | type 10 | ETreeSitterException = Exception; 11 | 12 | //some aliases, so TreeSitterLib is not needed in uses clause 13 | PTSLanguage = TreeSitterLib.PTSLanguage; 14 | TTSLanguage = TSLanguage; 15 | 16 | TSFieldId = TreeSitterLib.TSFieldId; 17 | TSSymbol = TreeSitterLib.TSSymbol; 18 | TSSymbolType = TreeSitterLib.TSSymbolType; 19 | 20 | PTSGetLanguageFunc = ^TTSGetLanguageFunc; 21 | TTSGetLanguageFunc = function(): PTSLanguage; cdecl; 22 | 23 | TTSLanguageHelper = record helper for TTSLanguage 24 | private 25 | function GetFieldName(AFieldId: TSFieldId): string; 26 | function GetFieldId(const AFieldName: string): TSFieldId; 27 | function GetSymbolName(ASymbol: TSSymbol): string; 28 | function GetSymbolForName(const ASymbolName: string; AIsNamed: Boolean): TSSymbol; 29 | function GetSymbolType(ASymbol: TSSymbol): TSSymbolType; 30 | public 31 | function Version: UInt32; 32 | function FieldCount: UInt32; 33 | function SymbolCount: UInt32; 34 | 35 | function NextState(AState: TSStateId; ASymbol: TSSymbol): TSStateId; 36 | 37 | property FieldName[AFieldId: TSFieldId]: string read GetFieldName; 38 | property FieldId[const AFieldName: string]: TSFieldId read GetFieldId; 39 | property SymbolName[ASymbol: TSSymbol]: string read GetSymbolName; 40 | property SymbolForName[const ASymbolName: string; AIsNamed: Boolean]: TSSymbol read GetSymbolForName; 41 | property SymbolType[ASymbol: TSSymbol]: TSSymbolType read GetSymbolType; 42 | end; 43 | 44 | TTSTree = class; 45 | TTSNode = TSNode; 46 | TTSPoint = TSPoint; 47 | 48 | TTSInputEncoding = TreeSitterLib.TSInputEncoding; 49 | 50 | TTSParseReadFunction = reference to function (AByteIndex: UInt32; APosition: TTSPoint; var ABytesRead: UInt32): TBytes; 51 | 52 | TTSParser = class 53 | strict private 54 | FParser: PTSParser; 55 | function GetLanguage: PTSLanguage; 56 | procedure SetLanguage(const Value: PTSLanguage); 57 | public 58 | constructor Create; virtual; 59 | destructor Destroy; override; 60 | 61 | procedure Reset; 62 | 63 | function ParseString(const AString: string; const AOldTree: TTSTree = nil): TTSTree; 64 | function Parse(AParseReadFunction: TTSParseReadFunction; 65 | AEncoding: TTSInputEncoding; const AOldTree: TTSTree = nil): TTSTree; 66 | 67 | property Parser: PTSParser read FParser; 68 | property Language: PTSLanguage read GetLanguage write SetLanguage; 69 | end; 70 | 71 | TTSTree = class 72 | strict private 73 | FTree: PTSTree; 74 | public 75 | constructor Create(ATree: PTSTree); virtual; 76 | destructor Destroy; override; 77 | 78 | function Language: PTSLanguage; 79 | function RootNode: TTSNode; 80 | function TreeNilSafe: PTSTree; 81 | function Clone: TTSTree; 82 | 83 | property Tree: PTSTree read FTree; 84 | end; 85 | 86 | TTSTreeCursor = class 87 | strict private 88 | FTreeCursor: TSTreeCursor; 89 | function GetTreeCursor: PTSTreeCursor; 90 | function GetCurrentNode: TTSNode; 91 | function GetCurrentFieldName: string; 92 | function GetCurrentFieldId: TSFieldId; 93 | function GetCurrentDepth: UInt32; 94 | function GetCurrentDescendantIndex: UInt32; 95 | public 96 | constructor Create(ANode: TTSNode); overload; virtual; 97 | constructor Create(ACursorToCopy: TTSTreeCursor); overload; virtual; 98 | destructor Destroy; override; 99 | 100 | procedure Reset(ANode: TTSNode); overload; 101 | procedure Reset(ACursor: TTSTreeCursor); overload; 102 | 103 | function GotoParent: Boolean; 104 | function GotoNextSibling: Boolean; 105 | function GotoPrevSibling: Boolean; 106 | function GotoFirstChild: Boolean; 107 | function GotoLastChild: Boolean; 108 | procedure GotoDescendant(AGoalDescendantIndex: UInt32); 109 | function GotoFirstChildForGoal(AGoalByte: UInt32): Int64; overload; 110 | function GotoFirstChildForGoal(AGoalPoint: TTSPoint): Int64; overload; 111 | 112 | property TreeCursor: PTSTreeCursor read GetTreeCursor; 113 | property CurrentNode: TTSNode read GetCurrentNode; 114 | property CurrentFieldName: string read GetCurrentFieldName; 115 | property CurrentFieldId: TSFieldId read GetCurrentFieldId; 116 | property CurrentDescendantIndex: UInt32 read GetCurrentDescendantIndex; 117 | property CurrentDepth: UInt32 read GetCurrentDepth; 118 | end; 119 | 120 | TTSNodeHelper = record helper for TTSNode 121 | function Language: PTSLanguage; 122 | 123 | function NodeType: string; 124 | function Symbol: TSSymbol; 125 | function GrammarType: string; 126 | function GrammarSymbol: TSSymbol; 127 | 128 | function IsNull: Boolean; 129 | function IsError: Boolean; 130 | function HasError: Boolean; 131 | function HasChanges: Boolean; 132 | function IsExtra: Boolean; 133 | function IsMissing: Boolean; 134 | function IsNamed: Boolean; 135 | function Parent: TTSNode; 136 | function ToString: string; 137 | 138 | function ChildCount: Integer; 139 | function Child(AIndex: Integer): TTSNode; 140 | function NextSibling: TTSNode; 141 | function PrevSibling: TTSNode; 142 | 143 | function NamedChildCount: Integer; 144 | function NamedChild(AIndex: Integer): TTSNode; 145 | function NextNamedSibling: TTSNode; 146 | function PrevNamedSibling: TTSNode; 147 | 148 | function StartByte: UInt32; 149 | function StartPoint: TTSPoint; 150 | function EndByte: UInt32; 151 | function EndPoint: TTSPoint; 152 | 153 | function ChildByField(const AFieldName: string): TTSNode; overload; 154 | function ChildByField(const AFieldId: UInt32): TTSNode; overload; 155 | 156 | function DescendantCount: UInt32; 157 | 158 | class operator Equal(A: TTSNode; B: TTSNode): Boolean; 159 | end; 160 | 161 | TTSPointHelper = record helper for TTSPoint 162 | function ToString: string; 163 | end; 164 | 165 | 166 | implementation 167 | 168 | { TTSParser } 169 | 170 | constructor TTSParser.Create; 171 | begin 172 | FParser:= ts_parser_new; 173 | end; 174 | 175 | destructor TTSParser.Destroy; 176 | begin 177 | ts_parser_delete(FParser); 178 | inherited; 179 | end; 180 | 181 | function TTSParser.GetLanguage: PTSLanguage; 182 | begin 183 | Result:= ts_parser_language(FParser); 184 | end; 185 | 186 | type 187 | PTSInputReadPayLoad = ^TSInputReadPayLoad; 188 | TSInputReadPayLoad = record 189 | ParseReadFunction: TTSParseReadFunction; 190 | Buffer: TBytes; 191 | end; 192 | 193 | function TSInputRead(payload: Pointer; byte_index: UInt32; position: TSPoint; var bytes_read: UInt32): PAnsiChar; cdecl; 194 | begin 195 | PTSInputReadPayLoad(payload)^.Buffer:= PTSInputReadPayLoad(payload)^.ParseReadFunction(byte_index, position, bytes_read); 196 | if Length(PTSInputReadPayLoad(payload)^.Buffer) = 0 then 197 | Result:= nil else 198 | Result:= PAnsiChar(@PTSInputReadPayLoad(payload)^.Buffer[0]); 199 | end; 200 | 201 | function TTSParser.Parse(AParseReadFunction: TTSParseReadFunction; 202 | AEncoding: TTSInputEncoding; const AOldTree: TTSTree): TTSTree; 203 | var 204 | tsi: TSInput; 205 | payload: TSInputReadPayLoad; 206 | begin 207 | payload.ParseReadFunction:= AParseReadFunction; 208 | tsi.payload:= @payload; 209 | tsi.read:= TSInputRead; 210 | tsi.encoding:= AEncoding; 211 | Result:= TTSTree.Create(ts_parser_parse(FParser, AOldTree.TreeNilSafe, tsi)); 212 | end; 213 | 214 | function TTSParser.ParseString(const AString: string; 215 | const AOldTree: TTSTree): TTSTree; 216 | var 217 | bytes: TBytes; 218 | tree: PTSTree; 219 | len: Integer; 220 | begin 221 | bytes:= TEncoding.Unicode.GetBytes(AString); 222 | len:= Length(bytes); 223 | if len > 0 then 224 | tree:= ts_parser_parse_string_encoding(FParser, AOldTree.TreeNilSafe, 225 | @bytes[0], len, TSInputEncodingUTF16) else 226 | raise ETreeSitterException.Create('Cannot parse empty string'); 227 | if tree = nil then 228 | raise ETreeSitterException.Create('Faild to parse string'); 229 | Result:= TTSTree.Create(tree); 230 | end; 231 | 232 | procedure TTSParser.Reset; 233 | begin 234 | ts_parser_reset(FParser); 235 | end; 236 | 237 | procedure TTSParser.SetLanguage(const Value: PTSLanguage); 238 | begin 239 | if not ts_parser_set_language(FParser, Value) then 240 | raise ETreeSitterException.CreateFmt('Failed to set parser language to 0x%p', [Value]); 241 | end; 242 | 243 | { TTSTree } 244 | 245 | function TTSTree.Clone: TTSTree; 246 | begin 247 | Result:= TTSTree.Create(ts_tree_copy(FTree)); 248 | end; 249 | 250 | constructor TTSTree.Create(ATree: PTSTree); 251 | begin 252 | FTree:= ATree; 253 | end; 254 | 255 | destructor TTSTree.Destroy; 256 | begin 257 | if FTree <> nil then 258 | ts_tree_delete(FTree); 259 | inherited; 260 | end; 261 | 262 | function TTSTree.Language: PTSLanguage; 263 | begin 264 | Result:= ts_tree_language(FTree); 265 | end; 266 | 267 | function TTSTree.RootNode: TTSNode; 268 | begin 269 | Result:= ts_tree_root_node(FTree); 270 | end; 271 | 272 | function TTSTree.TreeNilSafe: PTSTree; 273 | begin 274 | if Self <> nil then 275 | Result:= FTree else 276 | Result:= nil; 277 | end; 278 | 279 | { TTSNodeHelper } 280 | 281 | function TTSNodeHelper.Child(AIndex: Integer): TTSNode; 282 | begin 283 | Result:= ts_node_child(Self, AIndex); 284 | end; 285 | 286 | function TTSNodeHelper.ChildByField(const AFieldId: UInt32): TTSNode; 287 | begin 288 | Result:= ts_node_child_by_field_id(Self, AFieldId); 289 | end; 290 | 291 | function TTSNodeHelper.ChildByField(const AFieldName: string): TTSNode; 292 | var 293 | ansiFieldName: AnsiString; 294 | begin 295 | ansiFieldName:= AnsiString(AFieldName); 296 | Result:= ts_node_child_by_field_name(Self, PAnsiChar(ansiFieldName), Length(ansiFieldName)); 297 | end; 298 | 299 | function TTSNodeHelper.ChildCount: Integer; 300 | begin 301 | Result:= ts_node_child_count(Self); 302 | end; 303 | 304 | function TTSNodeHelper.DescendantCount: UInt32; 305 | begin 306 | Result:= ts_node_descendant_count(Self); 307 | end; 308 | 309 | function TTSNodeHelper.EndByte: UInt32; 310 | begin 311 | Result:= ts_node_end_byte(Self); 312 | end; 313 | 314 | function TTSNodeHelper.EndPoint: TTSPoint; 315 | begin 316 | {$IFDEF WIN32} 317 | Result:= TTSPoint(ts_node_end_point(Self)); 318 | {$ELSE} 319 | Result:= ts_node_end_point(Self); 320 | {$ENDIF} 321 | end; 322 | 323 | class operator TTSNodeHelper.Equal(A, B: TTSNode): Boolean; 324 | begin 325 | Result:= ts_node_eq(A, B); 326 | end; 327 | 328 | function TTSNodeHelper.GrammarSymbol: TSSymbol; 329 | begin 330 | Result:= ts_node_grammar_symbol(Self); 331 | end; 332 | 333 | function TTSNodeHelper.GrammarType: string; 334 | begin 335 | Result:= string(AnsiString(ts_node_grammar_type(Self))); 336 | end; 337 | 338 | function TTSNodeHelper.HasChanges: Boolean; 339 | begin 340 | Result:= ts_node_has_changes(Self); 341 | end; 342 | 343 | function TTSNodeHelper.HasError: Boolean; 344 | begin 345 | Result:= ts_node_has_error(Self); 346 | end; 347 | 348 | function TTSNodeHelper.IsError: Boolean; 349 | begin 350 | Result:= ts_node_is_error(Self); 351 | end; 352 | 353 | function TTSNodeHelper.IsExtra: Boolean; 354 | begin 355 | Result:= ts_node_is_extra(Self); 356 | end; 357 | 358 | function TTSNodeHelper.IsMissing: Boolean; 359 | begin 360 | Result:= ts_node_is_missing(Self); 361 | end; 362 | 363 | function TTSNodeHelper.IsNamed: Boolean; 364 | begin 365 | Result:= ts_node_is_named(Self); 366 | end; 367 | 368 | function TTSNodeHelper.IsNull: Boolean; 369 | begin 370 | Result:= ts_node_is_null(Self); 371 | end; 372 | 373 | function TTSNodeHelper.Language: PTSLanguage; 374 | begin 375 | Result:= ts_node_language(Self); 376 | end; 377 | 378 | function TTSNodeHelper.NamedChild(AIndex: Integer): TTSNode; 379 | begin 380 | Result:= ts_node_named_child(Self, AIndex); 381 | end; 382 | 383 | function TTSNodeHelper.NamedChildCount: Integer; 384 | begin 385 | Result:= ts_node_named_child_count(Self); 386 | end; 387 | 388 | function TTSNodeHelper.NextNamedSibling: TTSNode; 389 | begin 390 | Result:= ts_node_next_named_sibling(Self); 391 | end; 392 | 393 | function TTSNodeHelper.NextSibling: TTSNode; 394 | begin 395 | Result:= ts_node_next_sibling(Self); 396 | end; 397 | 398 | function TTSNodeHelper.NodeType: string; 399 | begin 400 | Result:= string(AnsiString(ts_node_type(Self))); 401 | end; 402 | 403 | function TTSNodeHelper.Parent: TTSNode; 404 | begin 405 | Result:= ts_node_parent(Self); 406 | end; 407 | 408 | function TTSNodeHelper.PrevNamedSibling: TTSNode; 409 | begin 410 | Result:= ts_node_prev_named_sibling(Self); 411 | end; 412 | 413 | function TTSNodeHelper.PrevSibling: TTSNode; 414 | begin 415 | Result:= ts_node_prev_sibling(Self); 416 | end; 417 | 418 | function TTSNodeHelper.StartByte: UInt32; 419 | begin 420 | Result:= ts_node_start_byte(Self); 421 | end; 422 | 423 | function TTSNodeHelper.StartPoint: TTSPoint; 424 | begin 425 | {$IFDEF WIN32} 426 | Result:= TTSPoint(ts_node_start_point(Self)); 427 | {$ELSE} 428 | Result:= ts_node_start_point(Self); 429 | {$ENDIF} 430 | end; 431 | 432 | function TTSNodeHelper.Symbol: TSSymbol; 433 | begin 434 | Result:= ts_node_symbol(Self); 435 | end; 436 | 437 | function TTSNodeHelper.ToString: string; 438 | var 439 | pach: PAnsiChar; 440 | begin 441 | pach:= ts_node_string(Self); 442 | Result:= string(AnsiString(pach)); 443 | FreeMem(pach); 444 | end; 445 | 446 | { TTSPointHelper } 447 | 448 | function TTSPointHelper.ToString: string; 449 | begin 450 | Result:= Format('(%d, %d)', [row, column]); 451 | end; 452 | 453 | { TTSLanguageHelper } 454 | 455 | function TTSLanguageHelper.FieldCount: UInt32; 456 | begin 457 | Result:= ts_language_field_count(@Self); 458 | end; 459 | 460 | function TTSLanguageHelper.GetFieldId(const AFieldName: string): TSFieldId; 461 | var 462 | ansiFieldName: AnsiString; 463 | begin 464 | ansiFieldName:= AnsiString(AFieldName); 465 | Result:= ts_language_field_id_for_name(@Self, PAnsiChar(ansiFieldName), Length(ansiFieldName)); 466 | end; 467 | 468 | function TTSLanguageHelper.GetFieldName(AFieldId: TSFieldId): string; 469 | begin 470 | Result:= string(AnsiString(ts_language_field_name_for_id(@Self, AFieldId))); 471 | end; 472 | 473 | function TTSLanguageHelper.GetSymbolForName(const ASymbolName: string; AIsNamed: Boolean): TSSymbol; 474 | var 475 | ansiSymbolName: AnsiString; 476 | begin 477 | ansiSymbolName:= AnsiString(ASymbolName); 478 | Result:= ts_language_symbol_for_name(@Self, PAnsiChar(ansiSymbolName), Length(ansiSymbolName), AIsNamed); 479 | end; 480 | 481 | function TTSLanguageHelper.GetSymbolName(ASymbol: TSSymbol): string; 482 | begin 483 | Result:= string(AnsiString(ts_language_symbol_name(@Self, ASymbol))); 484 | end; 485 | 486 | function TTSLanguageHelper.GetSymbolType(ASymbol: TSSymbol): TSSymbolType; 487 | begin 488 | Result:= ts_language_symbol_type(@Self, ASymbol); 489 | end; 490 | 491 | function TTSLanguageHelper.NextState(AState: TSStateId; 492 | ASymbol: TSSymbol): TSStateId; 493 | begin 494 | Result:= ts_language_next_state(@Self, AState, ASymbol); 495 | end; 496 | 497 | function TTSLanguageHelper.SymbolCount: UInt32; 498 | begin 499 | Result:= ts_language_symbol_count(@Self); 500 | end; 501 | 502 | function TTSLanguageHelper.Version: UInt32; 503 | begin 504 | Result:= ts_language_version(@Self); 505 | end; 506 | 507 | { TTSTreeCursor } 508 | 509 | constructor TTSTreeCursor.Create(ANode: TTSNode); 510 | begin 511 | FTreeCursor:= ts_tree_cursor_new(ANode); 512 | end; 513 | 514 | constructor TTSTreeCursor.Create(ACursorToCopy: TTSTreeCursor); 515 | begin 516 | FTreeCursor:= ts_tree_cursor_copy(ACursorToCopy.TreeCursor); 517 | end; 518 | 519 | destructor TTSTreeCursor.Destroy; 520 | begin 521 | ts_tree_cursor_delete(@FTreeCursor); 522 | FillChar(FTreeCursor, SizeOf(FTreeCursor), 0); 523 | inherited; 524 | end; 525 | 526 | function TTSTreeCursor.GetCurrentDepth: UInt32; 527 | begin 528 | Result:= ts_tree_cursor_current_depth(@FTreeCursor); 529 | end; 530 | 531 | function TTSTreeCursor.GetCurrentDescendantIndex: UInt32; 532 | begin 533 | Result:= ts_tree_cursor_current_descendant_index(@FTreeCursor); 534 | end; 535 | 536 | function TTSTreeCursor.GetCurrentFieldId: TSFieldId; 537 | begin 538 | Result:= ts_tree_cursor_current_field_id(@FTreeCursor); 539 | end; 540 | 541 | function TTSTreeCursor.GetCurrentFieldName: string; 542 | begin 543 | Result:= string(AnsiString(ts_tree_cursor_current_field_name(@FTreeCursor))); 544 | end; 545 | 546 | function TTSTreeCursor.GetCurrentNode: TTSNode; 547 | begin 548 | Result:= ts_tree_cursor_current_node(@FTreeCursor); 549 | end; 550 | 551 | function TTSTreeCursor.GetTreeCursor: PTSTreeCursor; 552 | begin 553 | Result:= @FTreeCursor; 554 | end; 555 | 556 | procedure TTSTreeCursor.GotoDescendant(AGoalDescendantIndex: UInt32); 557 | begin 558 | ts_tree_cursor_goto_descendant(@FTreeCursor, AGoalDescendantIndex); 559 | end; 560 | 561 | function TTSTreeCursor.GotoFirstChild: Boolean; 562 | begin 563 | Result:= ts_tree_cursor_goto_first_child(@FTreeCursor); 564 | end; 565 | 566 | function TTSTreeCursor.GotoFirstChildForGoal(AGoalPoint: TTSPoint): Int64; 567 | begin 568 | Result:= ts_tree_cursor_goto_first_child_for_point(@FTreeCursor, AGoalPoint); 569 | end; 570 | 571 | function TTSTreeCursor.GotoFirstChildForGoal(AGoalByte: UInt32): Int64; 572 | begin 573 | Result:= ts_tree_cursor_goto_first_child_for_byte(@FTreeCursor, AGoalByte); 574 | end; 575 | 576 | function TTSTreeCursor.GotoLastChild: Boolean; 577 | begin 578 | Result:= ts_tree_cursor_goto_last_child(@FTreeCursor); 579 | end; 580 | 581 | function TTSTreeCursor.GotoNextSibling: Boolean; 582 | begin 583 | Result:= ts_tree_cursor_goto_next_sibling(@FTreeCursor); 584 | end; 585 | 586 | function TTSTreeCursor.GotoParent: Boolean; 587 | begin 588 | Result:= ts_tree_cursor_goto_parent(@FTreeCursor); 589 | end; 590 | 591 | function TTSTreeCursor.GotoPrevSibling: Boolean; 592 | begin 593 | Result:= ts_tree_cursor_goto_previous_sibling(@FTreeCursor); 594 | end; 595 | 596 | procedure TTSTreeCursor.Reset(ACursor: TTSTreeCursor); 597 | begin 598 | ts_tree_cursor_reset_to(@FTreeCursor, ACursor.TreeCursor); 599 | end; 600 | 601 | procedure TTSTreeCursor.Reset(ANode: TTSNode); 602 | begin 603 | ts_tree_cursor_reset(@FTreeCursor, ANode); 604 | end; 605 | 606 | { memory management functions } 607 | 608 | function ts_malloc_func(sizeOf: NativeUInt): Pointer; cdecl; 609 | begin 610 | GetMem(Result, sizeOf); 611 | end; 612 | 613 | function ts_calloc_func(nitems: NativeUInt; size: NativeUInt): Pointer; cdecl; 614 | begin 615 | GetMem(Result, nitems * size); 616 | FillChar(Result^, nitems * size, 0); 617 | end; 618 | 619 | procedure ts_free_func(ptr: Pointer); cdecl; 620 | begin 621 | FreeMem(ptr); 622 | end; 623 | 624 | function ts_realloc_func(ptr: Pointer; sizeOf: NativeUInt): Pointer; cdecl; 625 | begin 626 | Result:= ptr; 627 | ReallocMem(Result, sizeOf); 628 | end; 629 | 630 | initialization 631 | //provide our own MM functions so we can free data allocated by TS with our FreeMem 632 | ts_set_allocator(@ts_malloc_func, @ts_calloc_func, @ts_realloc_func, @ts_free_func); 633 | finalization 634 | end. 635 | -------------------------------------------------------------------------------- /TreeSitterLib.pas: -------------------------------------------------------------------------------- 1 | unit TreeSitterLib; 2 | 3 | (* 4 | 5 | Translation of tree-sitter's api.h, at their commit 09d2b23 from 2024-03-21 6 | 7 | Work in progress. The intention is to leave as much of the original .h unchanged, 8 | hence the - for Delphi - unusual comment styles 9 | 10 | *) 11 | 12 | //enforce Quad Word alignment in records 13 | {$A8} 14 | 15 | interface 16 | 17 | const 18 | ModuleName = 'tree-sitter'; 19 | 20 | (* 21 | /****************************/ 22 | /* Section - ABI Versioning */ 23 | /****************************/ 24 | /** 25 | * The latest ABI version that is supported by the current version of the 26 | * library. When Languages are generated by the Tree-sitter CLI, they are 27 | * assigned an ABI version number that corresponds to the current CLI version. 28 | * The Tree-sitter library is generally backwards-compatible with languages 29 | * generated using older CLI versions, but is not forwards-compatible. 30 | */ 31 | *) 32 | const TREE_SITTER_LANGUAGE_VERSION = 14; 33 | (* 34 | /** 35 | * The earliest ABI version that is supported by the current version of the 36 | * library. 37 | */ 38 | *) 39 | const TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION = 13; 40 | (* 41 | /*******************/ 42 | /* Section - Types */ 43 | /*******************/ 44 | *) 45 | type 46 | TSStateId = UInt16; 47 | TSSymbol = UInt16; 48 | TSFieldId = UInt16; 49 | PTSLanguage = ^TSLanguage; 50 | TSLanguage = record end; 51 | PTSParser = ^TSParser; 52 | TSParser = record end; 53 | PTSTree = ^TSTree; 54 | TSTree = record end; 55 | PTSQuery = ^TSQuery; 56 | TSQuery = record end; 57 | PTSQueryCursor = ^TSQueryCursor; 58 | TSQueryCursor = record end; 59 | TSLookaheadIterator = record end; 60 | 61 | {$MINENUMSIZE 4} 62 | TSInputEncoding = (TSInputEncodingUTF8, TSInputEncodingUTF16); 63 | 64 | TSSymbolType = (TSSymbolTypeRegular, TSSymbolTypeAnonymous, 65 | TSSymbolTypeAuxiliary); 66 | 67 | TSPoint = record 68 | row: UInt32; 69 | column: UInt32; 70 | end; 71 | (* 72 | typedef struct TSRange { 73 | TSPoint start_point; 74 | TSPoint end_point; 75 | uint32_t start_byte; 76 | uint32_t end_byte; 77 | } TSRange; 78 | *) 79 | TSInput = record 80 | payload: Pointer; 81 | read: function (payload: Pointer; byte_index: UInt32; position: TSPoint; var bytes_read: UInt32): PAnsiChar; cdecl; 82 | encoding: TSInputEncoding; 83 | end; 84 | (* 85 | typedef enum TSLogType { 86 | TSLogTypeParse, 87 | TSLogTypeLex, 88 | } TSLogType; 89 | typedef struct TSLogger { 90 | void *payload; 91 | void (*log)(void *payload, TSLogType log_type, const char *buffer); 92 | } TSLogger; 93 | typedef struct TSInputEdit { 94 | uint32_t start_byte; 95 | uint32_t old_end_byte; 96 | uint32_t new_end_byte; 97 | TSPoint start_point; 98 | TSPoint old_end_point; 99 | TSPoint new_end_point; 100 | } TSInputEdit; 101 | *) 102 | TSNode = record 103 | context: array[1..4] of UInt32; 104 | id: Pointer; 105 | tree: PTSTree; 106 | end; 107 | 108 | PTSTreeCursor = ^TSTreeCursor; 109 | TSTreeCursor = record 110 | tree: PTSTree; 111 | id: Pointer; 112 | context: array[1..3] of UInt32; 113 | end; 114 | 115 | TSQueryCapture = record 116 | node: TSNode; 117 | index: UInt32; 118 | end; 119 | 120 | PSQueryCaptureArray = ^TSQueryCaptureArray; 121 | TSQueryCaptureArray = array[0..0] of TSQueryCapture; 122 | 123 | TSQuantifier = ( 124 | TSQuantifierZero,// = 0, // must match the array initialization value 125 | TSQuantifierZeroOrOne, 126 | TSQuantifierZeroOrMore, 127 | TSQuantifierOne, 128 | TSQuantifierOneOrMore); 129 | 130 | TSQueryMatch = record 131 | id: UInt32; 132 | pattern_index: UInt16; 133 | capture_count: UInt16; 134 | captures: PSQueryCaptureArray; 135 | end; 136 | 137 | PTSQueryMatchArray = ^TSQueryMatchArray; 138 | TSQueryMatchArray = array[0..0] of TSQueryMatch; 139 | 140 | TSQueryPredicateStepType = ( 141 | TSQueryPredicateStepTypeDone, 142 | TSQueryPredicateStepTypeCapture, 143 | TSQueryPredicateStepTypeString); 144 | 145 | TSQueryPredicateStep = record 146 | &type: TSQueryPredicateStepType; 147 | value_id: UInt32; 148 | end; 149 | 150 | PTSQueryPredicateStepArray = ^TSQueryPredicateStepArray; 151 | TSQueryPredicateStepArray = array[0..0] of TSQueryPredicateStep; 152 | 153 | TSQueryError = ( 154 | TSQueryErrorNone,// = 0, 155 | TSQueryErrorSyntax, 156 | TSQueryErrorNodeType, 157 | TSQueryErrorField, 158 | TSQueryErrorCapture, 159 | TSQueryErrorStructure, 160 | TSQueryErrorLanguage); 161 | 162 | (* 163 | /********************/ 164 | /* Section - Parser */ 165 | /********************/ 166 | /** 167 | * Create a new parser. 168 | */ 169 | *) 170 | function ts_parser_new(): PTSParser; cdecl; external ModuleName; 171 | (* 172 | /** 173 | * Delete the parser, freeing all of the memory that it used. 174 | */ 175 | *) 176 | procedure ts_parser_delete(self: PTSParser); cdecl; external ModuleName; 177 | (* 178 | /** 179 | * Get the parser's current language. 180 | */ 181 | *) 182 | function ts_parser_language(self: PTSParser): PTSLanguage; cdecl; external ModuleName; 183 | (* 184 | /** 185 | * Set the language that the parser should use for parsing. 186 | * 187 | * Returns a boolean indicating whether or not the language was successfully 188 | * assigned. True means assignment succeeded. False means there was a version 189 | * mismatch: the language was generated with an incompatible version of the 190 | * Tree-sitter CLI. Check the language's version using [`ts_language_version`] 191 | * and compare it to this library's [`TREE_SITTER_LANGUAGE_VERSION`] and 192 | * [`TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION`] constants. 193 | */ 194 | *) 195 | function ts_parser_set_language(self: PTSParser; language: PTSLanguage): Boolean; cdecl; external ModuleName; 196 | { 197 | /** 198 | * Set the ranges of text that the parser should include when parsing. 199 | * 200 | * By default, the parser will always include entire documents. This function 201 | * allows you to parse only a *portion* of a document but still return a syntax 202 | * tree whose ranges match up with the document as a whole. You can also pass 203 | * multiple disjoint ranges. 204 | * 205 | * The second and third parameters specify the location and length of an array 206 | * of ranges. The parser does *not* take ownership of these ranges; it copies 207 | * the data, so it doesn't matter how these ranges are allocated. 208 | * 209 | * If `count` is zero, then the entire document will be parsed. Otherwise, 210 | * the given ranges must be ordered from earliest to latest in the document, 211 | * and they must not overlap. That is, the following must hold for all: 212 | * 213 | * `i < count - 1`: `ranges[i].end_byte <= ranges[i + 1].start_byte` 214 | * 215 | * If this requirement is not satisfied, the operation will fail, the ranges 216 | * will not be assigned, and this function will return `false`. On success, 217 | * this function returns `true` 218 | */ 219 | bool ts_parser_set_included_ranges( 220 | TSParser *self, 221 | const TSRange *ranges, 222 | uint32_t count 223 | ); 224 | /** 225 | * Get the ranges of text that the parser will include when parsing. 226 | * 227 | * The returned pointer is owned by the parser. The caller should not free it 228 | * or write to it. The length of the array will be written to the given 229 | * `count` pointer. 230 | */ 231 | const TSRange *ts_parser_included_ranges( 232 | const TSParser *self, 233 | uint32_t *count 234 | ); 235 | } 236 | (* 237 | /** 238 | * Use the parser to parse some source code and create a syntax tree. 239 | * 240 | * If you are parsing this document for the first time, pass `NULL` for the 241 | * `old_tree` parameter. Otherwise, if you have already parsed an earlier 242 | * version of this document and the document has since been edited, pass the 243 | * previous syntax tree so that the unchanged parts of it can be reused. 244 | * This will save time and memory. For this to work correctly, you must have 245 | * already edited the old syntax tree using the [`ts_tree_edit`] function in a 246 | * way that exactly matches the source code changes. 247 | * 248 | * The [`TSInput`] parameter lets you specify how to read the text. It has the 249 | * following three fields: 250 | * 1. [`read`]: A function to retrieve a chunk of text at a given byte offset 251 | * and (row, column) position. The function should return a pointer to the 252 | * text and write its length to the [`bytes_read`] pointer. The parser does 253 | * not take ownership of this buffer; it just borrows it until it has 254 | * finished reading it. The function should write a zero value to the 255 | * [`bytes_read`] pointer to indicate the end of the document. 256 | * 2. [`payload`]: An arbitrary pointer that will be passed to each invocation 257 | * of the [`read`] function. 258 | * 3. [`encoding`]: An indication of how the text is encoded. Either 259 | * `TSInputEncodingUTF8` or `TSInputEncodingUTF16`. 260 | * 261 | * This function returns a syntax tree on success, and `NULL` on failure. There 262 | * are three possible reasons for failure: 263 | * 1. The parser does not have a language assigned. Check for this using the 264 | [`ts_parser_language`] function. 265 | * 2. Parsing was cancelled due to a timeout that was set by an earlier call to 266 | * the [`ts_parser_set_timeout_micros`] function. You can resume parsing from 267 | * where the parser left out by calling [`ts_parser_parse`] again with the 268 | * same arguments. Or you can start parsing from scratch by first calling 269 | * [`ts_parser_reset`]. 270 | * 3. Parsing was cancelled using a cancellation flag that was set by an 271 | * earlier call to [`ts_parser_set_cancellation_flag`]. You can resume parsing 272 | * from where the parser left out by calling [`ts_parser_parse`] again with 273 | * the same arguments. 274 | * 275 | * [`read`]: TSInput::read 276 | * [`payload`]: TSInput::payload 277 | * [`encoding`]: TSInput::encoding 278 | * [`bytes_read`]: TSInput::read 279 | */ 280 | *) 281 | function ts_parser_parse( 282 | self: PTSParser; 283 | const old_tree: PTSTree; 284 | input: TSInput 285 | ): PTSTree; cdecl; external ModuleName; 286 | (* 287 | /** 288 | * Use the parser to parse some source code stored in one contiguous buffer. 289 | * The first two parameters are the same as in the [`ts_parser_parse`] function 290 | * above. The second two parameters indicate the location of the buffer and its 291 | * length in bytes. 292 | */ 293 | *) 294 | function ts_parser_parse_string( 295 | self: PTSParser; 296 | old_tree: PTSTree; 297 | _string: PAnsiChar; 298 | length: UInt32 299 | ): PTSTree; cdecl; external ModuleName; 300 | (* 301 | /** 302 | * Use the parser to parse some source code stored in one contiguous buffer with 303 | * a given encoding. The first four parameters work the same as in the 304 | * [`ts_parser_parse_string`] method above. The final parameter indicates whether 305 | * the text is encoded as UTF8 or UTF16. 306 | */ 307 | *) 308 | function ts_parser_parse_string_encoding( 309 | self: PTSParser; 310 | old_tree: PTSTree; 311 | _string: PByte; 312 | length: UInt32; 313 | encoding: TSInputEncoding 314 | ): PTSTree; cdecl; external ModuleName; 315 | (* 316 | /** 317 | * Instruct the parser to start the next parse from the beginning. 318 | * 319 | * If the parser previously failed because of a timeout or a cancellation, then 320 | * by default, it will resume where it left off on the next call to 321 | * [`ts_parser_parse`] or other parsing functions. If you don't want to resume, 322 | * and instead intend to use this parser to parse some other document, you must 323 | * call [`ts_parser_reset`] first. 324 | */ 325 | *) 326 | procedure ts_parser_reset(self: PTSParser); cdecl; external ModuleName; 327 | (* 328 | /** 329 | * Set the maximum duration in microseconds that parsing should be allowed to 330 | * take before halting. 331 | * 332 | * If parsing takes longer than this, it will halt early, returning NULL. 333 | * See [`ts_parser_parse`] for more information. 334 | */ 335 | void ts_parser_set_timeout_micros(TSParser *self, uint64_t timeout_micros); 336 | /** 337 | * Get the duration in microseconds that parsing is allowed to take. 338 | */ 339 | uint64_t ts_parser_timeout_micros(const TSParser *self); 340 | /** 341 | * Set the parser's current cancellation flag pointer. 342 | * 343 | * If a non-null pointer is assigned, then the parser will periodically read 344 | * from this pointer during parsing. If it reads a non-zero value, it will 345 | * halt early, returning NULL. See [`ts_parser_parse`] for more information. 346 | */ 347 | void ts_parser_set_cancellation_flag(TSParser *self, const size_t *flag); 348 | /** 349 | * Get the parser's current cancellation flag pointer. 350 | */ 351 | const size_t *ts_parser_cancellation_flag(const TSParser *self); 352 | /** 353 | * Set the logger that a parser should use during parsing. 354 | * 355 | * The parser does not take ownership over the logger payload. If a logger was 356 | * previously assigned, the caller is responsible for releasing any memory 357 | * owned by the previous logger. 358 | */ 359 | void ts_parser_set_logger(TSParser *self, TSLogger logger); 360 | /** 361 | * Get the parser's current logger. 362 | */ 363 | TSLogger ts_parser_logger(const TSParser *self); 364 | /** 365 | * Set the file descriptor to which the parser should write debugging graphs 366 | * during parsing. The graphs are formatted in the DOT language. You may want 367 | * to pipe these graphs directly to a `dot(1)` process in order to generate 368 | * SVG output. You can turn off this logging by passing a negative number. 369 | */ 370 | void ts_parser_print_dot_graphs(TSParser *self, int fd); 371 | *) 372 | (* 373 | /******************/ 374 | /* Section - Tree */ 375 | /******************/ 376 | /** 377 | * Create a shallow copy of the syntax tree. This is very fast. 378 | * 379 | * You need to copy a syntax tree in order to use it on more than one thread at 380 | * a time, as syntax trees are not thread safe. 381 | */ 382 | *) 383 | function ts_tree_copy(const self: PTSTree): PTSTree; cdecl; external ModuleName; 384 | (* 385 | /** 386 | * Delete the syntax tree, freeing all of the memory that it used. 387 | */ 388 | *) 389 | procedure ts_tree_delete(self: PTSTree); cdecl; external ModuleName; 390 | (* 391 | /** 392 | * Get the root node of the syntax tree. 393 | */ 394 | *) 395 | function ts_tree_root_node(self: PTSTree): TSNode; cdecl; external ModuleName; 396 | (* 397 | /** 398 | * Get the root node of the syntax tree, but with its position 399 | * shifted forward by the given offset. 400 | */ 401 | TSNode ts_tree_root_node_with_offset( 402 | const TSTree *self, 403 | uint32_t offset_bytes, 404 | TSPoint offset_extent 405 | ); 406 | *) 407 | (* 408 | /** 409 | * Get the language that was used to parse the syntax tree. 410 | */ 411 | *) 412 | function ts_tree_language(const self: PTSTree): PTSLanguage; cdecl; external ModuleName; 413 | (* 414 | /** 415 | * Get the array of included ranges that was used to parse the syntax tree. 416 | * 417 | * The returned pointer must be freed by the caller. 418 | */ 419 | TSRange *ts_tree_included_ranges(const TSTree *self, uint32_t *length); 420 | /** 421 | * Edit the syntax tree to keep it in sync with source code that has been 422 | * edited. 423 | * 424 | * You must describe the edit both in terms of byte offsets and in terms of 425 | * (row, column) coordinates. 426 | */ 427 | void ts_tree_edit(TSTree *self, const TSInputEdit *edit); 428 | /** 429 | * Compare an old edited syntax tree to a new syntax tree representing the same 430 | * document, returning an array of ranges whose syntactic structure has changed. 431 | * 432 | * For this to work correctly, the old syntax tree must have been edited such 433 | * that its ranges match up to the new tree. Generally, you'll want to call 434 | * this function right after calling one of the [`ts_parser_parse`] functions. 435 | * You need to pass the old tree that was passed to parse, as well as the new 436 | * tree that was returned from that function. 437 | * 438 | * The returned array is allocated using `malloc` and the caller is responsible 439 | * for freeing it using `free`. The length of the array will be written to the 440 | * given `length` pointer. 441 | */ 442 | TSRange *ts_tree_get_changed_ranges( 443 | const TSTree *old_tree, 444 | const TSTree *new_tree, 445 | uint32_t *length 446 | ); 447 | /** 448 | * Write a DOT graph describing the syntax tree to the given file. 449 | */ 450 | void ts_tree_print_dot_graph(const TSTree *self, int file_descriptor); 451 | *) 452 | (* 453 | /******************/ 454 | /* Section - Node */ 455 | /******************/ 456 | /** 457 | * Get the node's type as a null-terminated string. 458 | */ 459 | *) 460 | function ts_node_type(self: TSNode): PAnsiChar; cdecl; external ModuleName; 461 | (* 462 | /** 463 | * Get the node's type as a numerical id. 464 | */ 465 | *) 466 | function ts_node_symbol(self: TSNode): TSSymbol; cdecl; external ModuleName; 467 | (* 468 | /** 469 | * Get the node's language. 470 | */ 471 | *) 472 | function ts_node_language(self: TSNode): PTSLanguage; cdecl; external ModuleName; 473 | (* 474 | /** 475 | * Get the node's type as it appears in the grammar ignoring aliases as a 476 | * null-terminated string. 477 | */ 478 | *) 479 | function ts_node_grammar_type(self: TSNode): PAnsiChar; cdecl; external ModuleName; 480 | (* 481 | /** 482 | * Get the node's type as a numerical id as it appears in the grammar ignoring 483 | * aliases. This should be used in [`ts_language_next_state`] instead of 484 | * [`ts_node_symbol`]. 485 | */ 486 | *) 487 | function ts_node_grammar_symbol(self: TSNode): TSSymbol; cdecl; external ModuleName; 488 | (* 489 | /** 490 | * Get the node's start byte. 491 | */ 492 | *) 493 | function ts_node_start_byte(self: TSNode): UInt32; cdecl; external ModuleName; 494 | (* 495 | /** 496 | * Get the node's start position in terms of rows and columns. 497 | */ 498 | *) 499 | {$IFDEF WIN32} 500 | //the returned struct TSPoint is 8-byte in size and should be returned in EDX:EAX 501 | //which Delphi does only for Int64 according to the Language Guide 502 | //https://stackoverflow.com/a/16119171/386473 503 | function ts_node_start_point(self: TSNode): Int64; cdecl; external ModuleName; 504 | {$ELSE} 505 | function ts_node_start_point(self: TSNode): TSPoint; cdecl; external ModuleName; 506 | {$ENDIF} 507 | (* 508 | /** 509 | * Get the node's end byte. 510 | */ 511 | *) 512 | function ts_node_end_byte(self: TSNode): UInt32; cdecl; external ModuleName; 513 | (* 514 | /** 515 | * Get the node's end position in terms of rows and columns. 516 | */ 517 | *) 518 | {$IFDEF WIN32} 519 | //the returned struct TSPoint is 8-byte in size and should be returned in EDX:EAX 520 | //which Delphi does only for Int64 according to the Language Guide 521 | //https://stackoverflow.com/a/16119171/386473 522 | function ts_node_end_point(self: TSNode): Int64; cdecl; external ModuleName; 523 | {$ELSE} 524 | function ts_node_end_point(self: TSNode): TSPoint; cdecl; external ModuleName; 525 | {$ENDIF} 526 | (* 527 | /** 528 | * Get an S-expression representing the node as a string. 529 | * 530 | * This string is allocated with `malloc` and the caller is responsible for 531 | * freeing it using `free`. 532 | */ 533 | *) 534 | function ts_node_string(self: TSNode): PAnsiChar; cdecl; external ModuleName; 535 | (* 536 | /** 537 | * Check if the node is null. Functions like [`ts_node_child`] and 538 | * [`ts_node_next_sibling`] will return a null node to indicate that no such node 539 | * was found. 540 | */ 541 | *) 542 | function ts_node_is_null(self: TSNode): Boolean; cdecl; external ModuleName; 543 | (* 544 | /** 545 | * Check if the node is *named*. Named nodes correspond to named rules in the 546 | * grammar, whereas *anonymous* nodes correspond to string literals in the 547 | * grammar. 548 | */ 549 | *) 550 | function ts_node_is_named(self: TSNode): Boolean; cdecl; external ModuleName; 551 | (* 552 | /** 553 | * Check if the node is *missing*. Missing nodes are inserted by the parser in 554 | * order to recover from certain kinds of syntax errors. 555 | */ 556 | *) 557 | function ts_node_is_missing(self: TSNode): Boolean; cdecl; external ModuleName; 558 | (* 559 | /** 560 | * Check if the node is *extra*. Extra nodes represent things like comments, 561 | * which are not required the grammar, but can appear anywhere. 562 | */ 563 | *) 564 | function ts_node_is_extra(self: TSNode): Boolean; cdecl; external ModuleName; 565 | (* 566 | /** 567 | * Check if a syntax node has been edited. 568 | */ 569 | *) 570 | function ts_node_has_changes(self: TSNode): Boolean; cdecl; external ModuleName; 571 | (* 572 | /** 573 | * Check if the node is a syntax error or contains any syntax errors. 574 | */ 575 | *) 576 | function ts_node_has_error(self: TSNode): Boolean; cdecl; external ModuleName; 577 | (* 578 | /** 579 | * Check if the node is a syntax error. 580 | */ 581 | *) 582 | function ts_node_is_error(self: TSNode): Boolean; cdecl; external ModuleName; 583 | (* 584 | /** 585 | * Get this node's parse state. 586 | */ 587 | TSStateId ts_node_parse_state(TSNode self); 588 | /** 589 | * Get the parse state after this node. 590 | */ 591 | TSStateId ts_node_next_parse_state(TSNode self); 592 | *) 593 | (* 594 | /** 595 | * Get the node's immediate parent. 596 | */ 597 | *) 598 | function ts_node_parent(self: TSNode): TSNode; cdecl; external ModuleName; 599 | (* 600 | /** 601 | * Get the node's child at the given index, where zero represents the first 602 | * child. 603 | */ 604 | *) 605 | function ts_node_child(self: TSNode; child_index: UInt32): TSNode; cdecl; external ModuleName; 606 | (* 607 | /** 608 | * Get the field name for node's child at the given index, where zero represents 609 | * the first child. Returns NULL, if no field is found. 610 | */ 611 | const char *ts_node_field_name_for_child(TSNode self, uint32_t child_index); 612 | *) 613 | (* 614 | /** 615 | * Get the node's number of children. 616 | */ 617 | *) 618 | function ts_node_child_count(self: TSNode): UInt32; cdecl; external ModuleName; 619 | (* 620 | /** 621 | * Get the node's *named* child at the given index. 622 | * 623 | * See also [`ts_node_is_named`]. 624 | */ 625 | *) 626 | function ts_node_named_child(self: TSNode; child_index: UInt32): TSNode; cdecl; external ModuleName; 627 | (* 628 | /** 629 | * Get the node's number of *named* children. 630 | * 631 | * See also [`ts_node_is_named`]. 632 | */ 633 | *) 634 | function ts_node_named_child_count(self: TSNode): UInt32; cdecl; external ModuleName; 635 | (* 636 | /** 637 | * Get the node's child with the given field name. 638 | */ 639 | *) 640 | function ts_node_child_by_field_name( 641 | self: TSNode; 642 | const name: PAnsiChar; 643 | name_length: UInt32 644 | ): TSNode; cdecl; external ModuleName; 645 | (* 646 | /** 647 | * Get the node's child with the given numerical field id. 648 | * 649 | * You can convert a field name to an id using the 650 | * [`ts_language_field_id_for_name`] function. 651 | */ 652 | *) 653 | function ts_node_child_by_field_id(self: TSNode; field_id: TSFieldId): TSNode; cdecl; external ModuleName; 654 | (* 655 | /** 656 | * Get the node's next / previous sibling. 657 | */ 658 | *) 659 | function ts_node_next_sibling(self: TSNode): TSNode; cdecl; external ModuleName; 660 | function ts_node_prev_sibling(self: TSNode): TSNode; cdecl; external ModuleName; 661 | (* 662 | /** 663 | * Get the node's next / previous *named* sibling. 664 | */ 665 | *) 666 | function ts_node_next_named_sibling(self: TSNode): TSNode; cdecl; external ModuleName; 667 | function ts_node_prev_named_sibling(self: TSNode): TSNode; cdecl; external ModuleName; 668 | (* 669 | /** 670 | * Get the node's first child that extends beyond the given byte offset. 671 | */ 672 | TSNode ts_node_first_child_for_byte(TSNode self, uint32_t byte); 673 | /** 674 | * Get the node's first named child that extends beyond the given byte offset. 675 | */ 676 | TSNode ts_node_first_named_child_for_byte(TSNode self, uint32_t byte); 677 | *) 678 | (* 679 | /** 680 | * Get the node's number of descendants, including one for the node itself. 681 | */ 682 | *) 683 | function ts_node_descendant_count(self: TSNode): UInt32; cdecl; external ModuleName; 684 | (* 685 | /** 686 | * Get the smallest node within this node that spans the given range of bytes 687 | * or (row, column) positions. 688 | */ 689 | TSNode ts_node_descendant_for_byte_range(TSNode self, uint32_t start, uint32_t end); 690 | TSNode ts_node_descendant_for_point_range(TSNode self, TSPoint start, TSPoint end); 691 | /** 692 | * Get the smallest named node within this node that spans the given range of 693 | * bytes or (row, column) positions. 694 | */ 695 | TSNode ts_node_named_descendant_for_byte_range(TSNode self, uint32_t start, uint32_t end); 696 | TSNode ts_node_named_descendant_for_point_range(TSNode self, TSPoint start, TSPoint end); 697 | /** 698 | * Edit the node to keep it in-sync with source code that has been edited. 699 | * 700 | * This function is only rarely needed. When you edit a syntax tree with the 701 | * [`ts_tree_edit`] function, all of the nodes that you retrieve from the tree 702 | * afterward will already reflect the edit. You only need to use [`ts_node_edit`] 703 | * when you have a [`TSNode`] instance that you want to keep and continue to use 704 | * after an edit. 705 | */ 706 | void ts_node_edit(TSNode *self, const TSInputEdit *edit); 707 | *) 708 | (* 709 | /** 710 | * Check if two nodes are identical. 711 | */ 712 | *) 713 | function ts_node_eq(self, other: TSNode): Boolean; cdecl; external ModuleName; 714 | (* 715 | /************************/ 716 | /* Section - TreeCursor */ 717 | /************************/ 718 | /** 719 | * Create a new tree cursor starting from the given node. 720 | * 721 | * A tree cursor allows you to walk a syntax tree more efficiently than is 722 | * possible using the [`TSNode`] functions. It is a mutable object that is always 723 | * on a certain syntax node, and can be moved imperatively to different nodes. 724 | */ 725 | *) 726 | function ts_tree_cursor_new(node: TSNode): TSTreeCursor; cdecl; external ModuleName; 727 | (* 728 | /** 729 | * Delete a tree cursor, freeing all of the memory that it used. 730 | */ 731 | *) 732 | procedure ts_tree_cursor_delete(self: PTSTreeCursor); cdecl; external ModuleName; 733 | (* 734 | /** 735 | * Re-initialize a tree cursor to start at a different node. 736 | */ 737 | *) 738 | procedure ts_tree_cursor_reset(Self: PTSTreeCursor; node: TSNode); cdecl; external ModuleName; 739 | (* 740 | /** 741 | * Re-initialize a tree cursor to the same position as another cursor. 742 | * 743 | * Unlike [`ts_tree_cursor_reset`], this will not lose parent information and 744 | * allows reusing already created cursors. 745 | */ 746 | *) 747 | procedure ts_tree_cursor_reset_to(dst: PTSTreeCursor; const src: PTSTreeCursor); cdecl; external ModuleName; 748 | (* 749 | /** 750 | * Get the tree cursor's current node. 751 | */ 752 | *) 753 | function ts_tree_cursor_current_node(const self: PTSTreeCursor): TSNode; cdecl; external ModuleName; 754 | (* 755 | /** 756 | * Get the field name of the tree cursor's current node. 757 | * 758 | * This returns `NULL` if the current node doesn't have a field. 759 | * See also [`ts_node_child_by_field_name`]. 760 | */ 761 | *) 762 | function ts_tree_cursor_current_field_name(const self: PTSTreeCursor): PAnsiChar; cdecl; external ModuleName; 763 | (* 764 | /** 765 | * Get the field id of the tree cursor's current node. 766 | * 767 | * This returns zero if the current node doesn't have a field. 768 | * See also [`ts_node_child_by_field_id`], [`ts_language_field_id_for_name`]. 769 | */ 770 | *) 771 | function ts_tree_cursor_current_field_id(const self: PTSTreeCursor): TSFieldId; cdecl; external ModuleName; 772 | (* 773 | /** 774 | * Move the cursor to the parent of its current node. 775 | * 776 | * This returns `true` if the cursor successfully moved, and returns `false` 777 | * if there was no parent node (the cursor was already on the root node). 778 | */ 779 | *) 780 | function ts_tree_cursor_goto_parent(self: PTSTreeCursor): Boolean; cdecl; external ModuleName; 781 | (* 782 | /** 783 | * Move the cursor to the next sibling of its current node. 784 | * 785 | * This returns `true` if the cursor successfully moved, and returns `false` 786 | * if there was no next sibling node. 787 | */ 788 | *) 789 | function ts_tree_cursor_goto_next_sibling(self: PTSTreeCursor): Boolean; cdecl; external ModuleName; 790 | (* 791 | /** 792 | * Move the cursor to the previous sibling of its current node. 793 | * 794 | * This returns `true` if the cursor successfully moved, and returns `false` if 795 | * there was no previous sibling node. 796 | * 797 | * Note, that this function may be slower than 798 | * [`ts_tree_cursor_goto_next_sibling`] due to how node positions are stored. In 799 | * the worst case, this will need to iterate through all the children upto the 800 | * previous sibling node to recalculate its position. 801 | */ 802 | *) 803 | function ts_tree_cursor_goto_previous_sibling(self: PTSTreeCursor): Boolean; cdecl; external ModuleName; 804 | (* 805 | /** 806 | * Move the cursor to the first child of its current node. 807 | * 808 | * This returns `true` if the cursor successfully moved, and returns `false` 809 | * if there were no children. 810 | */ 811 | *) 812 | function ts_tree_cursor_goto_first_child(self: PTSTreeCursor): Boolean; cdecl; external ModuleName; 813 | (* 814 | /** 815 | * Move the cursor to the last child of its current node. 816 | * 817 | * This returns `true` if the cursor successfully moved, and returns `false` if 818 | * there were no children. 819 | * 820 | * Note that this function may be slower than [`ts_tree_cursor_goto_first_child`] 821 | * because it needs to iterate through all the children to compute the child's 822 | * position. 823 | */ 824 | *) 825 | function ts_tree_cursor_goto_last_child(self: PTSTreeCursor): Boolean; cdecl; external ModuleName; 826 | (* 827 | /** 828 | * Move the cursor to the node that is the nth descendant of 829 | * the original node that the cursor was constructed with, where 830 | * zero represents the original node itself. 831 | */ 832 | *) 833 | procedure ts_tree_cursor_goto_descendant(self: PTSTreeCursor; goal_descendant_index: UInt32); cdecl; external ModuleName; 834 | (* 835 | /** 836 | * Get the index of the cursor's current node out of all of the 837 | * descendants of the original node that the cursor was constructed with. 838 | */ 839 | *) 840 | function ts_tree_cursor_current_descendant_index(const self: PTSTreeCursor): UInt32; cdecl; external ModuleName; 841 | (* 842 | /** 843 | * Get the depth of the cursor's current node relative to the original 844 | * node that the cursor was constructed with. 845 | */ 846 | *) 847 | function ts_tree_cursor_current_depth(const self: PTSTreeCursor): UInt32; cdecl; external ModuleName; 848 | (* 849 | /** 850 | * Move the cursor to the first child of its current node that extends beyond 851 | * the given byte offset or point. 852 | * 853 | * This returns the index of the child node if one was found, and returns -1 854 | * if no such child was found. 855 | */ 856 | *) 857 | function ts_tree_cursor_goto_first_child_for_byte(self: PTSTreeCursor; goal_byte: UInt32): Int64; cdecl; external ModuleName; 858 | function ts_tree_cursor_goto_first_child_for_point(self: PTSTreeCursor; goal_point: TSPoint): Int64; cdecl; external ModuleName; 859 | 860 | function ts_tree_cursor_copy(const cursor: PTSTreeCursor): TSTreeCursor; cdecl; external ModuleName; 861 | (* 862 | /*******************/ 863 | /* Section - Query */ 864 | /*******************/ 865 | /** 866 | * Create a new query from a string containing one or more S-expression 867 | * patterns. The query is associated with a particular language, and can 868 | * only be run on syntax nodes parsed with that language. 869 | * 870 | * If all of the given patterns are valid, this returns a [`TSQuery`]. 871 | * If a pattern is invalid, this returns `NULL`, and provides two pieces 872 | * of information about the problem: 873 | * 1. The byte offset of the error is written to the `error_offset` parameter. 874 | * 2. The type of error is written to the `error_type` parameter. 875 | */ 876 | *) 877 | function ts_query_new( 878 | const language: PTSLanguage; 879 | const source: PAnsiChar; 880 | source_len: UInt32; 881 | var error_offset: UInt32; 882 | var error_type: TSQueryError): PTSQuery; cdecl; external ModuleName; 883 | (* 884 | /** 885 | * Delete a query, freeing all of the memory that it used. 886 | */ 887 | *) 888 | procedure ts_query_delete(self: PTSQuery); cdecl; external ModuleName; 889 | (* 890 | /** 891 | * Get the number of patterns, captures, or string literals in the query. 892 | */ 893 | *) 894 | function ts_query_pattern_count(const self: PTSQuery): UInt32; cdecl; external ModuleName; 895 | function ts_query_capture_count(const self: PTSQuery): UInt32; cdecl; external ModuleName; 896 | function ts_query_string_count(const self: PTSQuery): UInt32; cdecl; external ModuleName; 897 | (* 898 | /** 899 | * Get the byte offset where the given pattern starts in the query's source. 900 | * 901 | * This can be useful when combining queries by concatenating their source 902 | * code strings. 903 | */ 904 | *) 905 | function ts_query_start_byte_for_pattern(const self: PTSQuery; pattern_index: UInt32): UInt32; cdecl; external ModuleName; 906 | (* 907 | /** 908 | * Get all of the predicates for the given pattern in the query. 909 | * 910 | * The predicates are represented as a single array of steps. There are three 911 | * types of steps in this array, which correspond to the three legal values for 912 | * the `type` field: 913 | * - `TSQueryPredicateStepTypeCapture` - Steps with this type represent names 914 | * of captures. Their `value_id` can be used with the 915 | * [`ts_query_capture_name_for_id`] function to obtain the name of the capture. 916 | * - `TSQueryPredicateStepTypeString` - Steps with this type represent literal 917 | * strings. Their `value_id` can be used with the 918 | * [`ts_query_string_value_for_id`] function to obtain their string value. 919 | * - `TSQueryPredicateStepTypeDone` - Steps with this type are *sentinels* 920 | * that represent the end of an individual predicate. If a pattern has two 921 | * predicates, then there will be two steps with this `type` in the array. 922 | */ 923 | *) 924 | function ts_query_predicates_for_pattern( 925 | const self: PTSQuery; 926 | pattern_index: UInt32; 927 | var step_count: UInt32 928 | ): PTSQueryPredicateStepArray; cdecl; external ModuleName; 929 | (* 930 | /* 931 | * Check if the given pattern in the query has a single root node. 932 | */ 933 | bool ts_query_is_pattern_rooted(const TSQuery *self, uint32_t pattern_index); 934 | /* 935 | * Check if the given pattern in the query is 'non local'. 936 | * 937 | * A non-local pattern has multiple root nodes and can match within a 938 | * repeating sequence of nodes, as specified by the grammar. Non-local 939 | * patterns disable certain optimizations that would otherwise be possible 940 | * when executing a query on a specific range of a syntax tree. 941 | */ 942 | bool ts_query_is_pattern_non_local(const TSQuery *self, uint32_t pattern_index); 943 | /* 944 | * Check if a given pattern is guaranteed to match once a given step is reached. 945 | * The step is specified by its byte offset in the query's source code. 946 | */ 947 | bool ts_query_is_pattern_guaranteed_at_step(const TSQuery *self, uint32_t byte_offset); 948 | *) 949 | (* 950 | /** 951 | * Get the name and length of one of the query's captures, or one of the 952 | * query's string literals. Each capture and string is associated with a 953 | * numeric id based on the order that it appeared in the query's source. 954 | */ 955 | *) 956 | function ts_query_capture_name_for_id( 957 | const self: PTSQuery; 958 | index: UInt32; 959 | var length: UInt32 960 | ): PAnsiChar; cdecl; external ModuleName; 961 | (* 962 | /** 963 | * Get the quantifier of the query's captures. Each capture is * associated 964 | * with a numeric id based on the order that it appeared in the query's source. 965 | */ 966 | *) 967 | function ts_query_capture_quantifier_for_id( 968 | const self: PTSQuery; 969 | pattern_index: UInt32; 970 | capture_index: UInt32 971 | ): TSQuantifier; cdecl; external ModuleName; 972 | 973 | function ts_query_string_value_for_id( 974 | const self: PTSQuery; 975 | index: UInt32; 976 | var length: UInt32 977 | ): PAnsiChar; cdecl; external ModuleName; 978 | (* 979 | /** 980 | * Disable a certain capture within a query. 981 | * 982 | * This prevents the capture from being returned in matches, and also avoids 983 | * any resource usage associated with recording the capture. Currently, there 984 | * is no way to undo this. 985 | */ 986 | void ts_query_disable_capture(TSQuery *self, const char *name, uint32_t length); 987 | /** 988 | * Disable a certain pattern within a query. 989 | * 990 | * This prevents the pattern from matching and removes most of the overhead 991 | * associated with the pattern. Currently, there is no way to undo this. 992 | */ 993 | void ts_query_disable_pattern(TSQuery *self, uint32_t pattern_index); 994 | *) 995 | (* 996 | /** 997 | * Create a new cursor for executing a given query. 998 | * 999 | * The cursor stores the state that is needed to iteratively search 1000 | * for matches. To use the query cursor, first call [`ts_query_cursor_exec`] 1001 | * to start running a given query on a given syntax node. Then, there are 1002 | * two options for consuming the results of the query: 1003 | * 1. Repeatedly call [`ts_query_cursor_next_match`] to iterate over all of the 1004 | * *matches* in the order that they were found. Each match contains the 1005 | * index of the pattern that matched, and an array of captures. Because 1006 | * multiple patterns can match the same set of nodes, one match may contain 1007 | * captures that appear *before* some of the captures from a previous match. 1008 | * 2. Repeatedly call [`ts_query_cursor_next_capture`] to iterate over all of the 1009 | * individual *captures* in the order that they appear. This is useful if 1010 | * don't care about which pattern matched, and just want a single ordered 1011 | * sequence of captures. 1012 | * 1013 | * If you don't care about consuming all of the results, you can stop calling 1014 | * [`ts_query_cursor_next_match`] or [`ts_query_cursor_next_capture`] at any point. 1015 | * You can then start executing another query on another node by calling 1016 | * [`ts_query_cursor_exec`] again. 1017 | */ 1018 | *) 1019 | function ts_query_cursor_new: PTSQueryCursor; cdecl; external ModuleName; 1020 | (* 1021 | /** 1022 | * Delete a query cursor, freeing all of the memory that it used. 1023 | */ 1024 | *) 1025 | procedure ts_query_cursor_delete(self: PTSQueryCursor); cdecl; external ModuleName; 1026 | (* 1027 | /** 1028 | * Start running a given query on a given node. 1029 | */ 1030 | *) 1031 | procedure ts_query_cursor_exec(self: PTSQueryCursor; const query: PTSQuery; node: TSNode); cdecl; external ModuleName; 1032 | (* 1033 | /** 1034 | * Manage the maximum number of in-progress matches allowed by this query 1035 | * cursor. 1036 | * 1037 | * Query cursors have an optional maximum capacity for storing lists of 1038 | * in-progress captures. If this capacity is exceeded, then the 1039 | * earliest-starting match will silently be dropped to make room for further 1040 | * matches. This maximum capacity is optional — by default, query cursors allow 1041 | * any number of pending matches, dynamically allocating new space for them as 1042 | * needed as the query is executed. 1043 | */ 1044 | *) 1045 | function ts_query_cursor_did_exceed_match_limit(const self: PTSQueryCursor): Boolean; cdecl; external ModuleName; 1046 | function ts_query_cursor_match_limit(const self: PTSQueryCursor): UInt32; cdecl; external ModuleName; 1047 | procedure ts_query_cursor_set_match_limit(self: PTSQueryCursor; limit: UInt32); cdecl; external ModuleName; 1048 | (* 1049 | /** 1050 | * Set the range of bytes or (row, column) positions in which the query 1051 | * will be executed. 1052 | */ 1053 | void ts_query_cursor_set_byte_range(TSQueryCursor *self, uint32_t start_byte, uint32_t end_byte); 1054 | void ts_query_cursor_set_point_range(TSQueryCursor *self, TSPoint start_point, TSPoint end_point); 1055 | *) 1056 | (* 1057 | /** 1058 | * Advance to the next match of the currently running query. 1059 | * 1060 | * If there is a match, write it to `*match` and return `true`. 1061 | * Otherwise, return `false`. 1062 | */ 1063 | *) 1064 | function ts_query_cursor_next_match(self: PTSQueryCursor; var match: TSQueryMatch): Boolean; cdecl; external ModuleName; 1065 | procedure ts_query_cursor_remove_match(self: PTSQueryCursor; match_id: UInt32); cdecl; external ModuleName; 1066 | (* 1067 | /** 1068 | * Advance to the next capture of the currently running query. 1069 | * 1070 | * If there is a capture, write its match to `*match` and its index within 1071 | * the matche's capture list to `*capture_index`. Otherwise, return `false`. 1072 | */ 1073 | *) 1074 | function ts_query_cursor_next_capture( 1075 | self: PTSQueryCursor; 1076 | var match: TSQueryMatch; 1077 | var capture_index: UInt32 1078 | ): Boolean; cdecl; external ModuleName; 1079 | (* 1080 | /** 1081 | * Set the maximum start depth for a query cursor. 1082 | * 1083 | * This prevents cursors from exploring children nodes at a certain depth. 1084 | * Note if a pattern includes many children, then they will still be checked. 1085 | * 1086 | * The zero max start depth value can be used as a special behavior and 1087 | * it helps to destructure a subtree by staying on a node and using captures 1088 | * for interested parts. Note that the zero max start depth only limit a search 1089 | * depth for a pattern's root node but other nodes that are parts of the pattern 1090 | * may be searched at any depth what defined by the pattern structure. 1091 | * 1092 | * Set to `UINT32_MAX` to remove the maximum start depth. 1093 | */ 1094 | *) 1095 | procedure ts_query_cursor_set_max_start_depth(self: PTSQueryCursor; max_start_depth: UInt32); cdecl; external ModuleName; 1096 | (* 1097 | /**********************/ 1098 | /* Section - Language */ 1099 | /**********************/ 1100 | /** 1101 | * Get another reference to the given language. 1102 | */ 1103 | const TSLanguage *ts_language_copy(const TSLanguage *self); 1104 | /** 1105 | * Free any dynamically-allocated resources for this language, if 1106 | * this is the last reference. 1107 | */ 1108 | void ts_language_delete(const TSLanguage *self); 1109 | *) 1110 | (* 1111 | /** 1112 | * Get the number of distinct node types in the language. 1113 | */ 1114 | *) 1115 | function ts_language_symbol_count(const self: PTSLanguage): UInt32; cdecl; external ModuleName; 1116 | (* 1117 | /** 1118 | * Get the number of valid states in this language. 1119 | */ 1120 | *) 1121 | function ts_language_state_count(const self: PTSLanguage): UInt32; cdecl; external ModuleName; 1122 | (* 1123 | /** 1124 | * Get a node type string for the given numerical id. 1125 | */ 1126 | *) 1127 | function ts_language_symbol_name(const self: PTSLanguage; symbol: TSSymbol): PAnsiChar; cdecl; external ModuleName; 1128 | (* 1129 | /** 1130 | * Get the numerical id for the given node type string. 1131 | */ 1132 | *) 1133 | function ts_language_symbol_for_name( 1134 | const self: PTSLanguage; 1135 | AString: PAnsiChar; 1136 | length: UInt32; 1137 | is_named: Boolean 1138 | ): TSSymbol; cdecl; external ModuleName; 1139 | (* 1140 | /** 1141 | * Get the number of distinct field names in the language. 1142 | */ 1143 | *) 1144 | function ts_language_field_count(const Self: PTSLanguage): UInt32; cdecl; external ModuleName; 1145 | (* 1146 | /** 1147 | * Get the field name string for the given numerical id. 1148 | */ 1149 | *) 1150 | function ts_language_field_name_for_id(const Self: PTSLanguage; id: TSFieldId): PAnsiChar; cdecl; external ModuleName; 1151 | (* 1152 | /** 1153 | * Get the numerical id for the given field name string. 1154 | */ 1155 | *) 1156 | function ts_language_field_id_for_name(const Self: PTSLanguage; const name: PAnsiChar; name_length: UInt32): TSFieldId; cdecl; external ModuleName; 1157 | (* 1158 | /** 1159 | * Check whether the given node type id belongs to named nodes, anonymous nodes, 1160 | * or a hidden nodes. 1161 | * 1162 | * See also [`ts_node_is_named`]. Hidden nodes are never returned from the API. 1163 | */ 1164 | *) 1165 | function ts_language_symbol_type(const self: PTSLanguage; symbol: TSSymbol): TSSymbolType; cdecl; external ModuleName; 1166 | (* 1167 | /** 1168 | * Get the ABI version number for this language. This version number is used 1169 | * to ensure that languages were generated by a compatible version of 1170 | * Tree-sitter. 1171 | * 1172 | * See also [`ts_parser_set_language`]. 1173 | */ 1174 | *) 1175 | function ts_language_version(const self: PTSLanguage): UInt32; cdecl; external ModuleName; 1176 | (* 1177 | /** 1178 | * Get the next parse state. Combine this with lookahead iterators to generate 1179 | * completion suggestions or valid symbols in error nodes. Use 1180 | * [`ts_node_grammar_symbol`] for valid symbols. 1181 | */ 1182 | *) 1183 | function ts_language_next_state(const self: PTSLanguage; state: TSStateId; symbol: TSSymbol): TSStateId; cdecl; external ModuleName; 1184 | (* 1185 | /********************************/ 1186 | /* Section - Lookahead Iterator */ 1187 | /********************************/ 1188 | /** 1189 | * Create a new lookahead iterator for the given language and parse state. 1190 | * 1191 | * This returns `NULL` if state is invalid for the language. 1192 | * 1193 | * Repeatedly using [`ts_lookahead_iterator_next`] and 1194 | * [`ts_lookahead_iterator_current_symbol`] will generate valid symbols in the 1195 | * given parse state. Newly created lookahead iterators will contain the `ERROR` 1196 | * symbol. 1197 | * 1198 | * Lookahead iterators can be useful to generate suggestions and improve syntax 1199 | * error diagnostics. To get symbols valid in an ERROR node, use the lookahead 1200 | * iterator on its first leaf node state. For `MISSING` nodes, a lookahead 1201 | * iterator created on the previous non-extra leaf node may be appropriate. 1202 | */ 1203 | TSLookaheadIterator *ts_lookahead_iterator_new(const TSLanguage *self, TSStateId state); 1204 | /** 1205 | * Delete a lookahead iterator freeing all the memory used. 1206 | */ 1207 | void ts_lookahead_iterator_delete(TSLookaheadIterator *self); 1208 | /** 1209 | * Reset the lookahead iterator to another state. 1210 | * 1211 | * This returns `true` if the iterator was reset to the given state and `false` 1212 | * otherwise. 1213 | */ 1214 | bool ts_lookahead_iterator_reset_state(TSLookaheadIterator *self, TSStateId state); 1215 | /** 1216 | * Reset the lookahead iterator. 1217 | * 1218 | * This returns `true` if the language was set successfully and `false` 1219 | * otherwise. 1220 | */ 1221 | bool ts_lookahead_iterator_reset(TSLookaheadIterator *self, const TSLanguage *language, TSStateId state); 1222 | /** 1223 | * Get the current language of the lookahead iterator. 1224 | */ 1225 | const TSLanguage *ts_lookahead_iterator_language(const TSLookaheadIterator *self); 1226 | /** 1227 | * Advance the lookahead iterator to the next symbol. 1228 | * 1229 | * This returns `true` if there is a new symbol and `false` otherwise. 1230 | */ 1231 | bool ts_lookahead_iterator_next(TSLookaheadIterator *self); 1232 | /** 1233 | * Get the current symbol of the lookahead iterator; 1234 | */ 1235 | TSSymbol ts_lookahead_iterator_current_symbol(const TSLookaheadIterator *self); 1236 | /** 1237 | * Get the current symbol type of the lookahead iterator as a null terminated 1238 | * string. 1239 | */ 1240 | const char *ts_lookahead_iterator_current_symbol_name(const TSLookaheadIterator *self); 1241 | } 1242 | (* 1243 | /*************************************/ 1244 | /* Section - WebAssembly Integration */ 1245 | /************************************/ 1246 | typedef struct wasm_engine_t TSWasmEngine; 1247 | typedef struct TSWasmStore TSWasmStore; 1248 | typedef enum { 1249 | TSWasmErrorKindNone = 0, 1250 | TSWasmErrorKindParse, 1251 | TSWasmErrorKindCompile, 1252 | TSWasmErrorKindInstantiate, 1253 | TSWasmErrorKindAllocate, 1254 | } TSWasmErrorKind; 1255 | typedef struct { 1256 | TSWasmErrorKind kind; 1257 | char *message; 1258 | } TSWasmError; 1259 | /** 1260 | * Create a Wasm store. 1261 | */ 1262 | TSWasmStore *ts_wasm_store_new( 1263 | TSWasmEngine *engine, 1264 | TSWasmError *error 1265 | ); 1266 | /** 1267 | * Free the memory associated with the given Wasm store. 1268 | */ 1269 | void ts_wasm_store_delete(TSWasmStore * ); 1270 | /** 1271 | * Create a language from a buffer of Wasm. The resulting language behaves 1272 | * like any other Tree-sitter language, except that in order to use it with 1273 | * a parser, that parser must have a Wasm store. Note that the language 1274 | * can be used with any Wasm store, it doesn't need to be the same store that 1275 | * was used to originally load it. 1276 | */ 1277 | const TSLanguage *ts_wasm_store_load_language( 1278 | TSWasmStore *, 1279 | const char *name, 1280 | const char *wasm, 1281 | uint32_t wasm_len, 1282 | TSWasmError *error 1283 | ); 1284 | /** 1285 | * Get the number of languages instantiated in the given wasm store. 1286 | */ 1287 | size_t ts_wasm_store_language_count(const TSWasmStore * ); 1288 | /** 1289 | * Check if the language came from a Wasm module. If so, then in order to use 1290 | * this language with a Parser, that parser must have a Wasm store assigned. 1291 | */ 1292 | bool ts_language_is_wasm(const TSLanguage * ); 1293 | /** 1294 | * Assign the given Wasm store to the parser. A parser must have a Wasm store 1295 | * in order to use Wasm languages. 1296 | */ 1297 | void ts_parser_set_wasm_store(TSParser *, TSWasmStore * ); 1298 | /** 1299 | * Remove the parser's current Wasm store and return it. This returns NULL if 1300 | * the parser doesn't have a Wasm store. 1301 | */ 1302 | TSWasmStore *ts_parser_take_wasm_store(TSParser * ); 1303 | *) 1304 | { 1305 | /**********************************/ 1306 | /* Section - Global Configuration */ 1307 | /**********************************/ 1308 | /** 1309 | * Set the allocation functions used by the library. 1310 | * 1311 | * By default, Tree-sitter uses the standard libc allocation functions, 1312 | * but aborts the process when an allocation fails. This function lets 1313 | * you supply alternative allocation functions at runtime. 1314 | * 1315 | * If you pass `NULL` for any parameter, Tree-sitter will switch back to 1316 | * its default implementation of that function. 1317 | * 1318 | * If you call this function after the library has already been used, then 1319 | * you must ensure that either: 1320 | * 1. All the existing objects have been freed. 1321 | * 2. The new allocator shares its state with the old one, so it is capable 1322 | * of freeing memory that was allocated by the old allocator. 1323 | */ 1324 | } 1325 | type 1326 | Pts_malloc_func = ^Tts_malloc_func; 1327 | Tts_malloc_func = function(sizeOf: NativeUInt): Pointer; cdecl; 1328 | Pts_calloc_func = ^Tts_calloc_func; 1329 | Tts_calloc_func = function(nitems: NativeUInt; size: NativeUInt): Pointer; cdecl; 1330 | Pts_free_func = ^Tts_free_func; 1331 | Tts_free_func = procedure(ptr: Pointer); cdecl; 1332 | Pts_realloc_func = ^Tts_realloc_func; 1333 | Tts_realloc_func = function(ptr: Pointer; sizeOf: NativeUInt): Pointer; cdecl; 1334 | 1335 | procedure ts_set_allocator( 1336 | new_malloc: Pts_malloc_func; 1337 | new_calloc: Pts_calloc_func; 1338 | new_realloc: Pts_realloc_func; 1339 | new_free: Pts_free_func); cdecl; external ModuleName; 1340 | 1341 | implementation 1342 | 1343 | end. 1344 | -------------------------------------------------------------------------------- /VCLDemo/DelphiTreeSitterVCLDemo.dpr: -------------------------------------------------------------------------------- 1 | program DelphiTreeSitterVCLDemo; 2 | 3 | uses 4 | Vcl.Forms, 5 | frmDTSMain in 'frmDTSMain.pas' {DTSMainForm}, 6 | TreeSitter in '..\TreeSitter.pas', 7 | TreeSitterLib in '..\TreeSitterLib.pas', 8 | frmDTSLanguage in 'frmDTSLanguage.pas' {DTSLanguageForm}, 9 | TreeSitter.Query in '..\TreeSitter.Query.pas', 10 | frmDTSQuery in 'frmDTSQuery.pas' {DTSQueryForm}; 11 | 12 | {$R *.res} 13 | 14 | begin 15 | ReportMemoryLeaksOnShutdown:= True; 16 | Application.Initialize; 17 | Application.MainFormOnTaskbar := True; 18 | Application.CreateForm(TDTSMainForm, DTSMainForm); 19 | Application.Run; 20 | end. 21 | -------------------------------------------------------------------------------- /VCLDemo/DelphiTreeSitterVCLDemo.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {AAA39C66-11BC-4D19-9713-3C4763BC51D7} 4 | 19.5 5 | VCL 6 | True 7 | Debug 8 | Win64 9 | 3 10 | Application 11 | DelphiTreeSitterVCLDemo.dpr 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Cfg_1 34 | true 35 | true 36 | 37 | 38 | true 39 | Cfg_1 40 | true 41 | true 42 | 43 | 44 | true 45 | Base 46 | true 47 | 48 | 49 | true 50 | Cfg_2 51 | true 52 | true 53 | 54 | 55 | true 56 | Cfg_2 57 | true 58 | true 59 | 60 | 61 | ..\$(Platform)\$(Config) 62 | ..\$(Platform)\$(Config) 63 | false 64 | false 65 | false 66 | false 67 | false 68 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) 69 | $(BDS)\bin\delphi_PROJECTICON.ico 70 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 71 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 72 | DelphiTreeSitterVCLDemo 73 | 1031 74 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 75 | 76 | 77 | vclwinx;fmx;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;FireDACCommonODBC;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;bindcompfmx;inetdb;FireDACSqliteDriver;DbxClientDriver;soapmidas;vclactnband;fmxFireDAC;dbexpress;DBXMySQLDriver;VclSmp;inet;vcltouch;fmxase;dbrtl;fmxdae;FireDACMSAccDriver;CustomIPTransport;vcldsnap;DBXInterBaseDriver;IndySystem;vcldb;ActiveXTest;vclFireDAC;bindcomp;FireDACCommon;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;adortl;vclimg;FireDACPgDriver;FireDAC;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;CloudService;fmxobj;bindcompvclsmp;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) 78 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 79 | Debug 80 | true 81 | 1033 82 | $(BDS)\bin\default_app.manifest 83 | none 84 | 85 | 86 | vclwinx;fmx;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;FireDACCommonODBC;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;bindcompfmx;inetdb;FireDACSqliteDriver;DbxClientDriver;soapmidas;vclactnband;fmxFireDAC;dbexpress;DBXMySQLDriver;VclSmp;inet;vcltouch;fmxase;dbrtl;fmxdae;FireDACMSAccDriver;CustomIPTransport;vcldsnap;DBXInterBaseDriver;IndySystem;vcldb;vclFireDAC;bindcomp;FireDACCommon;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;adortl;vclimg;FireDACPgDriver;FireDAC;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;CloudService;fmxobj;bindcompvclsmp;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) 87 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) 88 | Debug 89 | true 90 | 1033 91 | $(BDS)\bin\default_app.manifest 92 | 93 | 94 | DEBUG;$(DCC_Define) 95 | true 96 | false 97 | true 98 | true 99 | true 100 | true 101 | true 102 | 103 | 104 | false 105 | PerMonitorV2 106 | true 107 | 1033 108 | 109 | 110 | PerMonitorV2 111 | 112 | 113 | false 114 | RELEASE;$(DCC_Define) 115 | 0 116 | 0 117 | 118 | 119 | PerMonitorV2 120 | true 121 | 1033 122 | 123 | 124 | PerMonitorV2 125 | 126 | 127 | 128 | MainSource 129 | 130 | 131 |
DTSMainForm
132 | dfm 133 |
134 | 135 | 136 | 137 |
DTSLanguageForm
138 | dfm 139 |
140 | 141 | 142 |
DTSQueryForm
143 | dfm 144 |
145 | 146 | Base 147 | 148 | 149 | Cfg_1 150 | Base 151 | 152 | 153 | Cfg_2 154 | Base 155 | 156 |
157 | 158 | Delphi.Personality.12 159 | Application 160 | 161 | 162 | 163 | DelphiTreeSitterVCLDemo.dpr 164 | 165 | 166 | 167 | True 168 | True 169 | 170 | 171 | 12 172 | 173 | 174 | 175 | 176 |
177 | -------------------------------------------------------------------------------- /VCLDemo/frmDTSLanguage.dfm: -------------------------------------------------------------------------------- 1 | object DTSLanguageForm: TDTSLanguageForm 2 | Left = 0 3 | Top = 0 4 | Caption = 'Language Info' 5 | ClientHeight = 441 6 | ClientWidth = 624 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -12 11 | Font.Name = 'Segoe UI' 12 | Font.Style = [] 13 | OnClose = FormClose 14 | TextHeight = 15 15 | object Splitter1: TSplitter 16 | Left = 220 17 | Top = 28 18 | Height = 413 19 | ExplicitLeft = 621 20 | ExplicitTop = 0 21 | end 22 | object pnlTop: TPanel 23 | Left = 0 24 | Top = 0 25 | Width = 624 26 | Height = 28 27 | Align = alTop 28 | BevelOuter = bvNone 29 | TabOrder = 1 30 | DesignSize = ( 31 | 624 32 | 28) 33 | object lblFieldCount: TLabel 34 | Left = 8 35 | Top = 8 36 | Width = 71 37 | Height = 15 38 | Caption = 'lblFieldCount' 39 | end 40 | object lblSymbolCount: TLabel 41 | Left = 229 42 | Top = 7 43 | Width = 51 44 | Height = 15 45 | Caption = 'lblVersion' 46 | end 47 | object lblVersion: TLabel 48 | Left = 560 49 | Top = 7 50 | Width = 51 51 | Height = 15 52 | Alignment = taRightJustify 53 | Anchors = [akTop, akRight] 54 | Caption = 'lblVersion' 55 | end 56 | end 57 | object sgSymbols: TStringGrid 58 | Left = 223 59 | Top = 28 60 | Width = 401 61 | Height = 413 62 | Align = alClient 63 | ColCount = 3 64 | DefaultColWidth = 130 65 | DefaultRowHeight = 18 66 | FixedCols = 0 67 | Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goColSizing, goFixedRowDefAlign] 68 | TabOrder = 2 69 | end 70 | object sgFields: TStringGrid 71 | Left = 0 72 | Top = 28 73 | Width = 220 74 | Height = 413 75 | Align = alLeft 76 | ColCount = 2 77 | DefaultColWidth = 120 78 | DefaultRowHeight = 18 79 | FixedCols = 0 80 | Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goColSizing, goFixedRowDefAlign] 81 | TabOrder = 0 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /VCLDemo/frmDTSLanguage.pas: -------------------------------------------------------------------------------- 1 | unit frmDTSLanguage; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 7 | System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, 8 | Vcl.ExtCtrls, Vcl.Grids, Vcl.StdCtrls, TreeSitter; 9 | 10 | type 11 | TDTSLanguageForm = class(TForm) 12 | lblFieldCount: TLabel; 13 | pnlTop: TPanel; 14 | sgSymbols: TStringGrid; 15 | sgFields: TStringGrid; 16 | Splitter1: TSplitter; 17 | lblSymbolCount: TLabel; 18 | lblVersion: TLabel; 19 | procedure FormClose(Sender: TObject; var Action: TCloseAction); 20 | private 21 | FLanguage: PTSLanguage; 22 | procedure UpdateLanguage; 23 | public 24 | { Public declarations } 25 | end; 26 | 27 | var 28 | DTSLanguageForm: TDTSLanguageForm; 29 | 30 | procedure ShowLanguageInfo(ALanguage: PTSLanguage); 31 | 32 | implementation 33 | 34 | {$R *.dfm} 35 | 36 | procedure ShowLanguageInfo(ALanguage: PTSLanguage); 37 | begin 38 | if DTSLanguageForm = nil then 39 | begin 40 | Application.Createform(TDTSLanguageForm, DTSLanguageForm); 41 | DTSLanguageForm.sgFields.ColWidths[1]:= 50; 42 | DTSLanguageForm.sgSymbols.ColWidths[0]:= 200; 43 | DTSLanguageForm.sgSymbols.ColWidths[1]:= 50; 44 | end; 45 | DTSLanguageForm.FLanguage:= ALanguage; 46 | DTSLanguageForm.UpdateLanguage; 47 | DTSLanguageForm.Show; 48 | DTSLanguageForm.BringToFront; 49 | end; 50 | 51 | procedure TDTSLanguageForm.FormClose(Sender: TObject; var Action: TCloseAction); 52 | begin 53 | Action:= caFree; 54 | if Self = DTSLanguageForm then 55 | DTSLanguageForm:= nil; 56 | end; 57 | 58 | procedure TDTSLanguageForm.UpdateLanguage; 59 | const 60 | SymbolTypes: array[TSSymbolType] of string = ('Regular', 'Anonymous', 61 | 'Auxiliary'); 62 | var 63 | i: Integer; 64 | begin 65 | lblFieldCount.Caption:= Format('Fields: %d', [FLanguage^.FieldCount]); 66 | lblSymbolCount.Caption:= Format('Symbols: %d', [FLanguage^.SymbolCount]); 67 | lblVersion.Caption:= Format('Version: %d', [FLanguage^.Version]); 68 | 69 | sgFields.RowCount:= FLanguage^.FieldCount + 1; 70 | sgFields.Cells[0, 0]:= 'Field name'; 71 | sgFields.Cells[1, 0]:= 'Field Id'; 72 | for i:= 1 to sgFields.RowCount - 1 do 73 | begin 74 | sgFields.Cells[0, i]:= FLanguage^.FieldName[TSFieldId(i)]; 75 | sgFields.Cells[1, i]:= IntToStr(i); 76 | end; 77 | 78 | sgSymbols.RowCount:= FLanguage^.SymbolCount + 1; 79 | sgSymbols.Cells[0, 0]:= 'Symbol name'; 80 | sgSymbols.Cells[1, 0]:= 'Symbol'; 81 | sgSymbols.Cells[2, 0]:= 'Type'; 82 | for i:= 1 to sgSymbols.RowCount - 1 do 83 | begin 84 | sgSymbols.Cells[0, i]:= FLanguage^.SymbolName[TSSymbol(i)]; 85 | sgSymbols.Cells[1, i]:= IntToStr(i); 86 | sgSymbols.Cells[2, i]:= SymbolTypes[FLanguage^.SymbolType[TSSymbol(i)]]; 87 | end; 88 | end; 89 | 90 | end. 91 | -------------------------------------------------------------------------------- /VCLDemo/frmDTSMain.dfm: -------------------------------------------------------------------------------- 1 | object DTSMainForm: TDTSMainForm 2 | Left = 0 3 | Top = 0 4 | Caption = 5 | 'Tree-Sitter for Delphi demo - https://github.com/modersohn/delph' + 6 | 'i-tree-sitter' 7 | ClientHeight = 478 8 | ClientWidth = 765 9 | Color = clBtnFace 10 | Font.Charset = DEFAULT_CHARSET 11 | Font.Color = clWindowText 12 | Font.Height = -12 13 | Font.Name = 'Segoe UI' 14 | Font.Style = [] 15 | OnCreate = FormCreate 16 | OnDestroy = FormDestroy 17 | TextHeight = 15 18 | object Splitter1: TSplitter 19 | Left = 512 20 | Top = 50 21 | Height = 428 22 | Align = alRight 23 | ExplicitLeft = 568 24 | ExplicitTop = 45 25 | ExplicitHeight = 425 26 | end 27 | object memCode: TMemo 28 | Left = 0 29 | Top = 50 30 | Width = 512 31 | Height = 428 32 | Align = alClient 33 | Font.Charset = ANSI_CHARSET 34 | Font.Color = clWindowText 35 | Font.Height = -15 36 | Font.Name = 'Consolas' 37 | Font.Style = [] 38 | HideSelection = False 39 | ParentFont = False 40 | ScrollBars = ssBoth 41 | TabOrder = 1 42 | OnChange = memCodeChange 43 | OnExit = memCodeExit 44 | end 45 | object pnlTop: TPanel 46 | Left = 0 47 | Top = 0 48 | Width = 765 49 | Height = 50 50 | Align = alTop 51 | BevelOuter = bvNone 52 | TabOrder = 0 53 | object lblCode: TLabel 54 | Left = 96 55 | Top = 17 56 | Width = 31 57 | Height = 15 58 | Caption = 'Code:' 59 | end 60 | object Label1: TLabel 61 | Left = 411 62 | Top = 17 63 | Width = 86 64 | Height = 15 65 | Anchors = [akTop, akRight] 66 | Caption = 'Language fields:' 67 | end 68 | object btnLoad: TButton 69 | Left = 8 70 | Top = 13 71 | Width = 66 72 | Height = 25 73 | Caption = 'Load...' 74 | TabOrder = 0 75 | OnClick = btnLoadClick 76 | end 77 | object cbCode: TComboBox 78 | Left = 133 79 | Top = 14 80 | Width = 145 81 | Height = 23 82 | Style = csDropDownList 83 | TabOrder = 1 84 | OnChange = cbCodeChange 85 | Items.Strings = ( 86 | 'c' 87 | 'cpp' 88 | 'pascal' 89 | 'proto') 90 | end 91 | object cbFields: TComboBox 92 | Left = 507 93 | Top = 14 94 | Width = 145 95 | Height = 23 96 | Style = csDropDownList 97 | Anchors = [akTop, akRight] 98 | TabOrder = 4 99 | end 100 | object btnGetChildByField: TButton 101 | Left = 658 102 | Top = 13 103 | Width = 97 104 | Height = 25 105 | Action = actGetChildByField 106 | Anchors = [akTop, akRight] 107 | TabOrder = 5 108 | end 109 | object btnLangInfo: TButton 110 | Left = 280 111 | Top = 13 112 | Width = 40 113 | Height = 25 114 | Caption = 'Info' 115 | TabOrder = 2 116 | OnClick = btnLangInfoClick 117 | end 118 | object btnQuery: TButton 119 | Left = 336 120 | Top = 13 121 | Width = 66 122 | Height = 25 123 | Caption = 'Query...' 124 | TabOrder = 3 125 | OnClick = btnQueryClick 126 | end 127 | end 128 | object Panel1: TPanel 129 | Left = 515 130 | Top = 50 131 | Width = 250 132 | Height = 428 133 | Align = alRight 134 | Caption = 'Panel1' 135 | TabOrder = 2 136 | object Splitter2: TSplitter 137 | Left = 1 138 | Top = 174 139 | Width = 248 140 | Height = 3 141 | Cursor = crVSplit 142 | Align = alBottom 143 | ExplicitLeft = 3 144 | ExplicitTop = 295 145 | ExplicitWidth = 183 146 | end 147 | object treeView: TTreeView 148 | Left = 1 149 | Top = 1 150 | Width = 248 151 | Height = 173 152 | Align = alClient 153 | HideSelection = False 154 | Indent = 19 155 | PopupMenu = pmTree 156 | ReadOnly = True 157 | TabOrder = 0 158 | OnChange = treeViewChange 159 | OnCreateNodeClass = treeViewCreateNodeClass 160 | OnExpanding = treeViewExpanding 161 | end 162 | object sgNodeProps: TStringGrid 163 | Left = 1 164 | Top = 177 165 | Width = 248 166 | Height = 250 167 | Align = alBottom 168 | ColCount = 2 169 | DefaultColWidth = 120 170 | DefaultRowHeight = 18 171 | FixedRows = 0 172 | Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goColSizing, goFixedRowDefAlign] 173 | TabOrder = 1 174 | end 175 | end 176 | object OD: TFileOpenDialog 177 | ClientGuid = '{58D00BB6-8E09-48B3-B19E-7E86D8D6B167}' 178 | FavoriteLinks = <> 179 | FileTypes = < 180 | item 181 | DisplayName = 'All files' 182 | FileMask = '*.*' 183 | end> 184 | Options = [] 185 | Left = 376 186 | Top = 248 187 | end 188 | object AL: TActionList 189 | Left = 344 190 | Top = 336 191 | object actGoto: TAction 192 | Category = 'Goto' 193 | Caption = 'Go to' 194 | OnExecute = actGotoExecute 195 | OnUpdate = actGotoUpdate 196 | end 197 | object actGotoParent: TAction 198 | Category = 'Goto' 199 | Caption = 'Parent' 200 | OnExecute = actGotoParentExecute 201 | OnUpdate = actGotoParentUpdate 202 | end 203 | object actGetChildByField: TAction 204 | Caption = 'Child by fieldID' 205 | OnExecute = actGetChildByFieldExecute 206 | OnUpdate = actGetChildByFieldUpdate 207 | end 208 | object actShowNodeAsString: TAction 209 | Caption = 'Show S-expression...' 210 | OnExecute = actShowNodeAsStringExecute 211 | OnUpdate = actShowNodeAsStringUpdate 212 | end 213 | object actGotoFirstChild: TAction 214 | Category = 'Goto' 215 | Caption = 'First child' 216 | OnExecute = actGotoFirstChildExecute 217 | OnUpdate = actGotoFirstChildUpdate 218 | end 219 | object actGotoNextSibling: TAction 220 | Category = 'Goto' 221 | Caption = 'Next sibling' 222 | OnExecute = actGotoNextSiblingExecute 223 | OnUpdate = actGotoNextSiblingUpdate 224 | end 225 | object actGotoPrevSibling: TAction 226 | Category = 'Goto' 227 | Caption = 'Previous sibling' 228 | OnExecute = actGotoPrevSiblingExecute 229 | OnUpdate = actGotoPrevSiblingUpdate 230 | end 231 | object actNamedNodesOnly: TAction 232 | AutoCheck = True 233 | Caption = 'Named nodes only' 234 | Checked = True 235 | OnExecute = actNamedNodesOnlyExecute 236 | end 237 | end 238 | object pmTree: TPopupMenu 239 | Left = 416 240 | Top = 304 241 | object mnuactNamedNodesOnly: TMenuItem 242 | Action = actNamedNodesOnly 243 | AutoCheck = True 244 | end 245 | object N4: TMenuItem 246 | Caption = '-' 247 | end 248 | object mnuactGoto: TMenuItem 249 | Action = actGoto 250 | object mnuactGotoParent: TMenuItem 251 | Action = actGotoParent 252 | end 253 | object N2: TMenuItem 254 | Caption = '-' 255 | end 256 | object mnuactGotoFirstChild: TMenuItem 257 | Action = actGotoFirstChild 258 | end 259 | object N3: TMenuItem 260 | Caption = '-' 261 | end 262 | object mnuactGotoNextSibling: TMenuItem 263 | Action = actGotoNextSibling 264 | end 265 | object mnuactGotoPrevSibling: TMenuItem 266 | Action = actGotoPrevSibling 267 | end 268 | end 269 | object N1: TMenuItem 270 | Caption = '-' 271 | end 272 | object mnuactShowNodeAsString: TMenuItem 273 | Action = actShowNodeAsString 274 | end 275 | end 276 | end 277 | -------------------------------------------------------------------------------- /VCLDemo/frmDTSMain.pas: -------------------------------------------------------------------------------- 1 | unit frmDTSMain; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 7 | System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, 8 | Vcl.ExtCtrls, Vcl.ComCtrls, Vcl.StdCtrls, TreeSitter, Vcl.Grids, 9 | System.Actions, Vcl.ActnList, Vcl.Menus; 10 | 11 | type 12 | TTSTreeViewNode = class(TTreeNode) 13 | public 14 | TSNode: TTSNode; 15 | end; 16 | 17 | TDTSMainForm = class(TForm) 18 | memCode: TMemo; 19 | pnlTop: TPanel; 20 | treeView: TTreeView; 21 | Splitter1: TSplitter; 22 | OD: TFileOpenDialog; 23 | btnLoad: TButton; 24 | lblCode: TLabel; 25 | cbCode: TComboBox; 26 | Splitter2: TSplitter; 27 | Panel1: TPanel; 28 | sgNodeProps: TStringGrid; 29 | AL: TActionList; 30 | actGoto: TAction; 31 | actGotoParent: TAction; 32 | pmTree: TPopupMenu; 33 | mnuactGoto: TMenuItem; 34 | mnuactGotoParent: TMenuItem; 35 | cbFields: TComboBox; 36 | Label1: TLabel; 37 | btnGetChildByField: TButton; 38 | actGetChildByField: TAction; 39 | actShowNodeAsString: TAction; 40 | mnuactShowNodeAsString: TMenuItem; 41 | N1: TMenuItem; 42 | actGotoFirstChild: TAction; 43 | actGotoNextSibling: TAction; 44 | actGotoPrevSibling: TAction; 45 | mnuactGotoFirstChild: TMenuItem; 46 | mnuactGotoNextSibling: TMenuItem; 47 | mnuactGotoPrevSibling: TMenuItem; 48 | N2: TMenuItem; 49 | N3: TMenuItem; 50 | btnLangInfo: TButton; 51 | btnQuery: TButton; 52 | actNamedNodesOnly: TAction; 53 | mnuactNamedNodesOnly: TMenuItem; 54 | N4: TMenuItem; 55 | procedure FormCreate(Sender: TObject); 56 | procedure FormDestroy(Sender: TObject); 57 | procedure memCodeExit(Sender: TObject); 58 | procedure treeViewCreateNodeClass(Sender: TCustomTreeView; 59 | var NodeClass: TTreeNodeClass); 60 | procedure treeViewExpanding(Sender: TObject; Node: TTreeNode; 61 | var AllowExpansion: Boolean); 62 | procedure btnLoadClick(Sender: TObject); 63 | procedure cbCodeChange(Sender: TObject); 64 | procedure treeViewChange(Sender: TObject; Node: TTreeNode); 65 | procedure memCodeChange(Sender: TObject); 66 | procedure actGotoUpdate(Sender: TObject); 67 | procedure actGotoParentExecute(Sender: TObject); 68 | procedure actGotoParentUpdate(Sender: TObject); 69 | procedure actGotoExecute(Sender: TObject); 70 | procedure actGetChildByFieldExecute(Sender: TObject); 71 | procedure actGetChildByFieldUpdate(Sender: TObject); 72 | procedure actShowNodeAsStringUpdate(Sender: TObject); 73 | procedure actShowNodeAsStringExecute(Sender: TObject); 74 | procedure actGotoFirstChildExecute(Sender: TObject); 75 | procedure actGotoFirstChildUpdate(Sender: TObject); 76 | procedure actGotoNextSiblingExecute(Sender: TObject); 77 | procedure actGotoNextSiblingUpdate(Sender: TObject); 78 | procedure actGotoPrevSiblingExecute(Sender: TObject); 79 | procedure actGotoPrevSiblingUpdate(Sender: TObject); 80 | procedure btnLangInfoClick(Sender: TObject); 81 | procedure btnQueryClick(Sender: TObject); 82 | procedure actNamedNodesOnlyExecute(Sender: TObject); 83 | private 84 | FParser: TTSParser; 85 | FTree: TTSTree; 86 | FEditChanged: Boolean; 87 | procedure ParseContent; 88 | procedure LoadLanguageParser(const ALangBaseName: string); 89 | procedure LoadLanguageFields; 90 | procedure FillNodeProps(const ANode: TTSNode); 91 | procedure ClearNodeProps; 92 | function GetSelectedTSNode: TTSNode; 93 | procedure SetSelectedTSNode(const Value: TTSNode); 94 | procedure SetupTreeTSNode(ATreeNode: TTSTreeViewNode; ATSNode: TTSNode); 95 | public 96 | property SelectedTSNode: TTSNode read GetSelectedTSNode write SetSelectedTSNode; 97 | end; 98 | 99 | var 100 | DTSMainForm: TDTSMainForm; 101 | 102 | implementation 103 | 104 | uses 105 | frmDTSLanguage, 106 | frmDTSQuery, 107 | UITypes; 108 | 109 | {$R *.dfm} 110 | 111 | type 112 | TSGNodePropRow = (rowSymbol, rowGrammarType, rowGrammarSymbol, rowIsError, 113 | rowHasError, rowIsExtra, rowIsMissing, rowIsNamed, rowChildCount, 114 | rowNamedChildCount, rowStartByte, rowStartPoint, rowEndByte, rowEndPoint, 115 | rowDescendantCount); 116 | 117 | const 118 | sgNodePropCaptions: array[TSGNodePropRow] of string = ( 119 | 'Symbol', 'GrammarType', 'GrammarSymbol', 'IsError', 120 | 'HasError', 'IsExtra', 'IsMissing', 'IsNamed', 'ChildCount', 121 | 'NamedChildCount', 'StartByte', 'StartPoint', 'EndByte', 'EndPoint', 122 | 'DescendantCount'); 123 | 124 | procedure TDTSMainForm.actGetChildByFieldExecute(Sender: TObject); 125 | var 126 | foundNode: TTSNode; 127 | begin 128 | foundNode:= SelectedTSNode.ChildByField(cbFields.ItemIndex + 1); 129 | //foundNode:= SelectedTSNode.ChildByField(cbFields.Text); 130 | if foundNode.IsNull then 131 | MessageDlg(Format('No child for field "%s" (%d) found', [cbFields.Text, cbFields.ItemIndex]), 132 | TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], 0) else 133 | SelectedTSNode:= foundNode; 134 | end; 135 | 136 | procedure TDTSMainForm.actGetChildByFieldUpdate(Sender: TObject); 137 | begin 138 | actGetChildByField.Enabled:= (not SelectedTSNode.IsNull) and 139 | (cbFields.ItemIndex >= 0); 140 | end; 141 | 142 | procedure TDTSMainForm.actGotoExecute(Sender: TObject); 143 | begin 144 | //to keep it enabled 145 | end; 146 | 147 | procedure TDTSMainForm.actGotoFirstChildExecute(Sender: TObject); 148 | begin 149 | if actNamedNodesOnly.Checked then 150 | SelectedTSNode:= SelectedTSNode.NamedChild(0) else 151 | SelectedTSNode:= SelectedTSNode.Child(0); 152 | end; 153 | 154 | procedure TDTSMainForm.actGotoFirstChildUpdate(Sender: TObject); 155 | begin 156 | if actNamedNodesOnly.Checked then 157 | actGotoFirstChild.Enabled:= SelectedTSNode.NamedChildCount > 0 else 158 | actGotoFirstChild.Enabled:= SelectedTSNode.ChildCount > 0; 159 | end; 160 | 161 | procedure TDTSMainForm.actGotoNextSiblingExecute(Sender: TObject); 162 | begin 163 | if actNamedNodesOnly.Checked then 164 | SelectedTSNode:= SelectedTSNode.NextNamedSibling else 165 | SelectedTSNode:= SelectedTSNode.NextSibling; 166 | end; 167 | 168 | procedure TDTSMainForm.actGotoNextSiblingUpdate(Sender: TObject); 169 | begin 170 | if actNamedNodesOnly.Checked then 171 | actGotoNextSibling.Enabled:= not SelectedTSNode.NextNamedSibling.IsNull else 172 | actGotoNextSibling.Enabled:= not SelectedTSNode.NextSibling.IsNull; 173 | end; 174 | 175 | procedure TDTSMainForm.actGotoParentExecute(Sender: TObject); 176 | begin 177 | SelectedTSNode:= SelectedTSNode.Parent; 178 | end; 179 | 180 | procedure TDTSMainForm.actGotoParentUpdate(Sender: TObject); 181 | begin 182 | actGotoParent.Enabled:= not SelectedTSNode.Parent.IsNull; 183 | end; 184 | 185 | procedure TDTSMainForm.actGotoPrevSiblingExecute(Sender: TObject); 186 | begin 187 | if actNamedNodesOnly.Checked then 188 | SelectedTSNode:= SelectedTSNode.PrevNamedSibling else 189 | SelectedTSNode:= SelectedTSNode.PrevSibling; 190 | end; 191 | 192 | procedure TDTSMainForm.actGotoPrevSiblingUpdate(Sender: TObject); 193 | begin 194 | if actNamedNodesOnly.Checked then 195 | actGotoPrevSibling.Enabled:= not SelectedTSNode.PrevNamedSibling.IsNull else 196 | actGotoPrevSibling.Enabled:= not SelectedTSNode.PrevSibling.IsNull; 197 | end; 198 | 199 | procedure TDTSMainForm.actGotoUpdate(Sender: TObject); 200 | begin 201 | actGoto.Enabled:= not SelectedTSNode.IsNull; 202 | end; 203 | 204 | procedure TDTSMainForm.actNamedNodesOnlyExecute(Sender: TObject); 205 | var 206 | root, prevSelected: TTSNode; 207 | rootNode: TTSTreeViewNode; 208 | begin 209 | prevSelected:= SelectedTSNode; 210 | try 211 | treeView.Items.Clear; 212 | root:= FTree.RootNode; 213 | rootNode:= TTSTreeViewNode(treeView.Items.AddChild(nil, root.NodeType)); 214 | SetupTreeTSNode(rootNode, root); 215 | finally 216 | SelectedTSNode:= prevSelected; 217 | end; 218 | end; 219 | 220 | procedure TDTSMainForm.actShowNodeAsStringExecute(Sender: TObject); 221 | begin 222 | ShowMessage(SelectedTSNode.ToString); 223 | end; 224 | 225 | procedure TDTSMainForm.actShowNodeAsStringUpdate(Sender: TObject); 226 | begin 227 | actShowNodeAsString.Enabled:= not SelectedTSNode.IsNull; 228 | end; 229 | 230 | procedure TDTSMainForm.btnLangInfoClick(Sender: TObject); 231 | begin 232 | ShowLanguageInfo(FParser.Language); 233 | end; 234 | 235 | procedure TDTSMainForm.btnLoadClick(Sender: TObject); 236 | begin 237 | if not OD.Execute(Handle) then 238 | Exit; 239 | memCode.Lines.LoadFromFile(OD.FileName); 240 | FEditChanged:= True; 241 | ParseContent; 242 | end; 243 | 244 | procedure TDTSMainForm.btnQueryClick(Sender: TObject); 245 | begin 246 | ShowQueryForm(FTree); 247 | end; 248 | 249 | procedure TDTSMainForm.LoadLanguageParser(const ALangBaseName: string); 250 | //hard coded naming scheme 251 | // DLL name: tree-sitter- 252 | // method name returning TSLanguage: tree_sitter_ 253 | //this could also be fed from e.g. an INI file or could be 254 | //hardcoded depending on the use-case 255 | var 256 | tsLibName, tsAPIName: string; 257 | libHandle: THandle; 258 | pAPI: TTSGetLanguageFunc; 259 | begin 260 | tsLibName:= Format('tree-sitter-%s', [ALangBaseName]); 261 | libHandle:= LoadLibrary(PChar(tsLibName)); 262 | if libHandle = 0 then 263 | raise Exception.CreateFmt('Could not load library "%s"', [tsLibName]); 264 | tsAPIName:= Format('tree_sitter_%s', [ALangBaseName]); 265 | pAPI:= GetProcAddress(libHandle, PChar(tsAPIName)); 266 | if pAPI = nil then 267 | raise Exception.CreateFmt('The library "%s" does not provide a method "%s"', 268 | [tsLibName, tsAPIName]); 269 | FParser.Reset; 270 | FreeAndNil(FTree); 271 | FParser.Language:= pAPI; 272 | LoadLanguageFields; 273 | end; 274 | 275 | procedure TDTSMainForm.LoadLanguageFields; 276 | var 277 | i: UInt32; 278 | begin 279 | cbFields.Items.BeginUpdate; 280 | try 281 | cbFields.Items.Clear; 282 | if FParser.Language = nil then 283 | Exit; 284 | for i:= 1 to FParser.Language^.FieldCount do 285 | cbFields.Items.AddObject(FParser.Language^.FieldName[i], TObject(i)); 286 | finally 287 | cbFields.Items.EndUpdate; 288 | end; 289 | end; 290 | 291 | procedure TDTSMainForm.cbCodeChange(Sender: TObject); 292 | begin 293 | LoadLanguageParser(cbCode.Items[cbCode.ItemIndex]); 294 | ParseContent; 295 | end; 296 | 297 | procedure TDTSMainForm.ClearNodeProps; 298 | var 299 | row: TSGNodePropRow; 300 | begin 301 | for row:= Low(TSGNodePropRow) to High(TSGNodePropRow) do 302 | sgNodeProps.Cells[1, Ord(row)]:= ''; 303 | end; 304 | 305 | procedure TDTSMainForm.FillNodeProps(const ANode: TTSNode); 306 | begin 307 | sgNodeProps.Cells[1, Ord(rowSymbol)]:= Format('%d (%s)', [ANode.Symbol, ANode.Language^.SymbolName[ANode.Symbol]]); 308 | sgNodeProps.Cells[1, Ord(rowGrammarType)]:= ANode.GrammarType; 309 | sgNodeProps.Cells[1, Ord(rowGrammarSymbol)]:= Format('%d (%s)', [ANode.GrammarSymbol, ANode.Language^.SymbolName[ANode.GrammarSymbol]]); 310 | sgNodeProps.Cells[1, Ord(rowIsError)]:= BoolToStr(ANode.IsError, True); 311 | sgNodeProps.Cells[1, Ord(rowHasError)]:= BoolToStr(ANode.HasError, True); 312 | sgNodeProps.Cells[1, Ord(rowIsExtra)]:= BoolToStr(ANode.IsExtra, True); 313 | sgNodeProps.Cells[1, Ord(rowIsMissing)]:= BoolToStr(ANode.IsMissing, True); 314 | sgNodeProps.Cells[1, Ord(rowIsNamed)]:= BoolToStr(ANode.IsNamed, True); 315 | sgNodeProps.Cells[1, Ord(rowChildCount)]:= IntToStr(ANode.ChildCount); 316 | sgNodeProps.Cells[1, Ord(rowNamedChildCount)]:= IntToStr(ANode.NamedChildCount); 317 | sgNodeProps.Cells[1, Ord(rowStartByte)]:= IntToStr(ANode.StartByte); 318 | sgNodeProps.Cells[1, Ord(rowStartPoint)]:= ANode.StartPoint.ToString; 319 | sgNodeProps.Cells[1, Ord(rowEndByte)]:= IntToStr(ANode.EndByte); 320 | sgNodeProps.Cells[1, Ord(rowEndPoint)]:= ANode.EndPoint.ToString; 321 | sgNodeProps.Cells[1, Ord(rowDescendantCount)]:= IntToStr(ANode.DescendantCount); 322 | end; 323 | 324 | procedure TDTSMainForm.FormCreate(Sender: TObject); 325 | var 326 | row: TSGNodePropRow; 327 | begin 328 | //initialize property grid captions 329 | sgNodeProps.RowCount:= Ord(High(TSGNodePropRow)) - Ord(Low(TSGNodePropRow)) + 1; 330 | for row:= Low(TSGNodePropRow) to High(TSGNodePropRow) do 331 | sgNodeProps.Cells[0, Ord(row)]:= sgNodePropCaptions[row]; 332 | 333 | FParser:= TTSParser.Create; 334 | cbCode.ItemIndex:= 0; 335 | cbCodeChange(nil); 336 | end; 337 | 338 | procedure TDTSMainForm.FormDestroy(Sender: TObject); 339 | begin 340 | FreeAndNil(FTree); 341 | FreeAndNil(FParser); 342 | end; 343 | 344 | function TDTSMainForm.GetSelectedTSNode: TTSNode; 345 | begin 346 | if treeView.Selected is TTSTreeViewNode then 347 | Result:= TTSTreeViewNode(treeView.Selected).TSNode else 348 | Result:= FTree.RootNode.Parent; //easy way to create a NULL node 349 | end; 350 | 351 | procedure TDTSMainForm.ParseContent; 352 | var 353 | root: TTSNode; 354 | rootNode: TTSTreeViewNode; 355 | sCode: string; 356 | begin 357 | treeView.Items.Clear; 358 | sCode:= memCode.Lines.Text; 359 | if DTSQueryForm <> nil then 360 | DTSQueryForm.TreeDeleted; 361 | FreeAndNil(FTree); 362 | if Length(sCode) = 0 then 363 | Exit; //avoid our own exception that empty string cannot be parsed 364 | //we no longer pass OldTree as we would need to track editing and call 365 | //ts_tree_edit 366 | FTree:= FParser.ParseString(sCode); 367 | root:= FTree.RootNode; 368 | rootNode:= TTSTreeViewNode(treeView.Items.AddChild(nil, root.NodeType)); 369 | SetupTreeTSNode(rootNode, root); 370 | FEditChanged:= False; 371 | if DTSQueryForm <> nil then 372 | DTSQueryForm.NewTreeGenerated(FTree); 373 | end; 374 | 375 | procedure TDTSMainForm.SetSelectedTSNode(const Value: TTSNode); 376 | 377 | function FindViaParent(const ATSNode: TTSNode): TTreeNode; 378 | var 379 | tsParent: TTSNode; 380 | begin 381 | tsParent:= ATSNode.Parent; 382 | if tsParent.IsNull then 383 | Result:= treeView.Items.GetFirstNode else 384 | begin 385 | Result:= FindViaParent(tsParent); 386 | if Result <> nil then 387 | begin 388 | Result.Expand(False); 389 | Result:= Result.getFirstChild; 390 | end; 391 | end; 392 | if Result = nil then 393 | Exit; 394 | while Result is TTSTreeViewNode do 395 | begin 396 | if TTSTreeViewNode(Result).TSNode = ATSNode then 397 | Exit; 398 | Result:= Result.getNextSibling as TTSTreeViewNode; 399 | end; 400 | end; 401 | 402 | begin 403 | treeView.Selected:= FindViaParent(Value); 404 | end; 405 | 406 | procedure TDTSMainForm.treeViewChange(Sender: TObject; Node: TTreeNode); 407 | var 408 | tsSelected: TTSNode; 409 | ptStart, ptEnd: TTSPoint; 410 | memSel: TSelection; 411 | line: LRESULT; 412 | begin 413 | if Node = nil then 414 | begin 415 | ClearNodeProps; 416 | Exit; 417 | end; 418 | tsSelected:= TTSTreeViewNode(Node).TSNode; 419 | FillNodeProps(tsSelected); 420 | 421 | //select the corresponding code in the memo 422 | ptStart:= tsSelected.StartPoint; 423 | ptEnd:= tsSelected.EndPoint; 424 | 425 | line:= memcode.Perform(EM_LineIndex, ptStart.row, 0); 426 | if line < 0 then 427 | Exit; //something's not right 428 | 429 | //TSPoint.Column is in bytes, we use UTF16, so divide by 2 to get character, 430 | //which is a simplification not necessarily true 431 | memSel.StartPos:= line + Integer(ptStart.column) div 2; 432 | 433 | line:= memcode.Perform(EM_LineIndex, ptEnd.row, 0); 434 | if line < 0 then 435 | Exit; //something's not right 436 | memSel.EndPos:= line + Integer(ptEnd.column) div 2; 437 | 438 | SendMessage(memCode.Handle, EM_SETSEL, memSel.StartPos, memSel.EndPos); 439 | SendMessage(memCode.Handle, EM_SCROLLCARET, 0, 0); 440 | end; 441 | 442 | procedure TDTSMainForm.treeViewCreateNodeClass(Sender: TCustomTreeView; 443 | var NodeClass: TTreeNodeClass); 444 | begin 445 | NodeClass:= TTSTreeViewNode; 446 | end; 447 | 448 | procedure TDTSMainForm.treeViewExpanding(Sender: TObject; Node: TTreeNode; 449 | var AllowExpansion: Boolean); 450 | var 451 | tsCursor: TTSTreeCursor; 452 | tsNode: TTSNode; 453 | newTreeNode: TTSTreeViewNode; 454 | s: string; 455 | begin 456 | AllowExpansion:= True; 457 | if Node.getFirstChild <> nil then 458 | Exit; 459 | tsCursor:= TTSTreeCursor.Create(TTSTreeViewNode(Node).TSNode); 460 | try 461 | if tsCursor.GotoFirstChild then 462 | begin 463 | repeat 464 | tsNode:= tsCursor.CurrentNode; 465 | if actNamedNodesOnly.Checked and not tsNode.IsNamed then 466 | Continue; 467 | if tsCursor.CurrentFieldId > 0 then 468 | s:= Format('%s (%d): %s', [tsCursor.CurrentFieldName, 469 | tsCursor.CurrentFieldId, tsNode.NodeType]) 470 | else 471 | s:= tsNode.NodeType; 472 | newTreeNode:= TTSTreeViewNode(treeView.Items.AddChild(Node, s)); 473 | SetupTreeTSNode(newTreeNode, tsNode); 474 | until not tsCursor.GotoNextSibling; 475 | end; 476 | finally 477 | tsCursor.Free; 478 | end; 479 | end; 480 | 481 | procedure TDTSMainForm.memCodeChange(Sender: TObject); 482 | begin 483 | FEditChanged:= True; 484 | end; 485 | 486 | procedure TDTSMainForm.memCodeExit(Sender: TObject); 487 | begin 488 | if FEditChanged then 489 | ParseContent; 490 | end; 491 | 492 | procedure TDTSMainForm.SetupTreeTSNode(ATreeNode: TTSTreeViewNode; ATSNode: TTSNode); 493 | begin 494 | ATreeNode.TSNode:= ATSNode; 495 | if actNamedNodesOnly.Checked then 496 | ATreeNode.HasChildren:= ATSNode.NamedChildCount > 0 else 497 | ATreeNode.HasChildren:= ATSNode.ChildCount > 0; 498 | end; 499 | 500 | end. 501 | -------------------------------------------------------------------------------- /VCLDemo/frmDTSQuery.dfm: -------------------------------------------------------------------------------- 1 | object DTSQueryForm: TDTSQueryForm 2 | Left = 0 3 | Top = 0 4 | Caption = 'Query' 5 | ClientHeight = 441 6 | ClientWidth = 764 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -12 11 | Font.Name = 'Segoe UI' 12 | Font.Style = [] 13 | OnClose = FormClose 14 | OnDestroy = FormDestroy 15 | TextHeight = 15 16 | object Splitter1: TSplitter 17 | Left = 0 18 | Top = 250 19 | Width = 764 20 | Height = 3 21 | Cursor = crVSplit 22 | Align = alTop 23 | ExplicitTop = 120 24 | ExplicitWidth = 321 25 | end 26 | object Splitter2: TSplitter 27 | Left = 350 28 | Top = 253 29 | Height = 188 30 | ExplicitLeft = 376 31 | ExplicitTop = 165 32 | ExplicitHeight = 268 33 | end 34 | object pnlTop: TPanel 35 | Left = 0 36 | Top = 0 37 | Width = 764 38 | Height = 50 39 | Align = alTop 40 | BevelOuter = bvNone 41 | TabOrder = 0 42 | object lblQueryState: TLabel 43 | Left = 83 44 | Top = 17 45 | Width = 3 46 | Height = 15 47 | end 48 | object btnExecute: TButton 49 | Left = 8 50 | Top = 13 51 | Width = 66 52 | Height = 25 53 | Caption = 'Execute' 54 | TabOrder = 0 55 | OnClick = btnExecuteClick 56 | end 57 | end 58 | object memQuery: TMemo 59 | Left = 0 60 | Top = 50 61 | Width = 764 62 | Height = 200 63 | Align = alTop 64 | Font.Charset = DEFAULT_CHARSET 65 | Font.Color = clWindowText 66 | Font.Height = -15 67 | Font.Name = 'Consolas' 68 | Font.Style = [] 69 | ParentFont = False 70 | ScrollBars = ssBoth 71 | TabOrder = 1 72 | end 73 | object pnlPredicates: TPanel 74 | Left = 0 75 | Top = 253 76 | Width = 350 77 | Height = 188 78 | Align = alLeft 79 | BevelOuter = bvNone 80 | TabOrder = 2 81 | object pnlPredicatesToolbar: TPanel 82 | Left = 0 83 | Top = 0 84 | Width = 350 85 | Height = 41 86 | Align = alTop 87 | BevelOuter = bvNone 88 | TabOrder = 0 89 | object Label1: TLabel 90 | Left = 8 91 | Top = 11 92 | Width = 41 93 | Height = 15 94 | Caption = 'Pattern:' 95 | end 96 | object cbPatternIdx: TComboBox 97 | Left = 56 98 | Top = 8 99 | Width = 57 100 | Height = 23 101 | Style = csDropDownList 102 | TabOrder = 0 103 | OnClick = cbPatternIdxClick 104 | end 105 | end 106 | object sgPredicateSteps: TStringGrid 107 | Left = 0 108 | Top = 41 109 | Width = 350 110 | Height = 147 111 | Align = alClient 112 | DefaultRowHeight = 18 113 | RowCount = 2 114 | Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goColSizing, goFixedRowDefAlign] 115 | TabOrder = 1 116 | end 117 | end 118 | object pnlMatches: TPanel 119 | Left = 353 120 | Top = 253 121 | Width = 411 122 | Height = 188 123 | Align = alClient 124 | BevelOuter = bvNone 125 | TabOrder = 3 126 | object pnlMatchesTop: TPanel 127 | Left = 0 128 | Top = 0 129 | Width = 411 130 | Height = 41 131 | Align = alTop 132 | BevelOuter = bvNone 133 | TabOrder = 0 134 | object lblMatch: TLabel 135 | Left = 219 136 | Top = 13 137 | Width = 3 138 | Height = 15 139 | end 140 | object btnMatchStart: TButton 141 | Left = 9 142 | Top = 9 143 | Width = 120 144 | Height = 25 145 | Caption = 'Start query cursor' 146 | Enabled = False 147 | TabOrder = 0 148 | OnClick = btnMatchStartClick 149 | end 150 | object btnMatchNext: TButton 151 | Left = 132 152 | Top = 9 153 | Width = 75 154 | Height = 25 155 | Caption = 'Next match' 156 | Enabled = False 157 | TabOrder = 1 158 | OnClick = btnMatchNextClick 159 | end 160 | end 161 | object sgMatchCaptures: TStringGrid 162 | Left = 0 163 | Top = 41 164 | Width = 411 165 | Height = 147 166 | Align = alClient 167 | ColCount = 2 168 | DefaultColWidth = 120 169 | DefaultRowHeight = 18 170 | RowCount = 1 171 | FixedRows = 0 172 | TabOrder = 1 173 | OnSelectCell = sgMatchCapturesSelectCell 174 | end 175 | end 176 | end 177 | -------------------------------------------------------------------------------- /VCLDemo/frmDTSQuery.pas: -------------------------------------------------------------------------------- 1 | unit frmDTSQuery; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 7 | System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, 8 | Vcl.ExtCtrls, Vcl.StdCtrls, TreeSitter.Query, TreeSitter, Vcl.Grids; 9 | 10 | type 11 | TDTSQueryForm = class(TForm) 12 | memQuery: TMemo; 13 | Splitter1: TSplitter; 14 | pnlTop: TPanel; 15 | btnExecute: TButton; 16 | lblQueryState: TLabel; 17 | pnlPredicates: TPanel; 18 | pnlPredicatesToolbar: TPanel; 19 | Label1: TLabel; 20 | cbPatternIdx: TComboBox; 21 | sgPredicateSteps: TStringGrid; 22 | Splitter2: TSplitter; 23 | pnlMatches: TPanel; 24 | pnlMatchesTop: TPanel; 25 | sgMatchCaptures: TStringGrid; 26 | btnMatchStart: TButton; 27 | btnMatchNext: TButton; 28 | lblMatch: TLabel; 29 | procedure btnExecuteClick(Sender: TObject); 30 | procedure FormDestroy(Sender: TObject); 31 | procedure FormClose(Sender: TObject; var Action: TCloseAction); 32 | procedure cbPatternIdxClick(Sender: TObject); 33 | procedure btnMatchStartClick(Sender: TObject); 34 | procedure btnMatchNextClick(Sender: TObject); 35 | procedure sgMatchCapturesSelectCell(Sender: TObject; ACol, ARow: Integer; 36 | var CanSelect: Boolean); 37 | private 38 | FTree: TTSTree; 39 | FQuery: TTSQuery; 40 | FQueryCursor: TTSQueryCursor; 41 | FCurrentMatch: TTSQueryMatch; 42 | procedure ClearQuery; 43 | procedure ClearMatches; 44 | procedure ClearPredicates; 45 | public 46 | procedure TreeDeleted; 47 | procedure NewTreeGenerated(ATree: TTSTree); 48 | end; 49 | 50 | var 51 | DTSQueryForm: TDTSQueryForm; 52 | 53 | procedure ShowQueryForm(ATree: TTSTree); 54 | 55 | implementation 56 | 57 | uses 58 | Math, frmDTSMain; 59 | 60 | {$R *.dfm} 61 | 62 | procedure ShowQueryForm(ATree: TTSTree); 63 | begin 64 | if DTSQueryForm = nil then 65 | begin 66 | Application.Createform(TDTSQueryForm, DTSQueryForm); 67 | end; 68 | DTSQueryForm.FTree:= ATree; 69 | DTSQueryForm.cbPatternIdxClick(nil); 70 | DTSQueryForm.Show; 71 | DTSQueryForm.BringToFront; 72 | end; 73 | 74 | { TDTSQuery } 75 | 76 | procedure TDTSQueryForm.btnExecuteClick(Sender: TObject); 77 | const 78 | errorStrings: array[TTSQueryError] of string = ( 79 | 'None', 'Syntax', 'NodeType', 'Field', 'Capture', 'Structure', 'Language'); 80 | var 81 | errorOffset: UInt32; 82 | errorType: TTSQueryError; 83 | i: Integer; 84 | begin 85 | ClearQuery; 86 | 87 | FQuery:= TTSQuery.Create(FTree.Language, memQuery.Lines.Text, errorOffset, errorType); 88 | if errorType <> TTSQueryError.TSQueryErrorNone then 89 | begin 90 | lblQueryState.Caption:= Format('Error at %d, type = %s', [errorOffset, errorStrings[errorType]]); 91 | 92 | memQuery.SetFocus; 93 | SendMessage(memQuery.Handle, EM_SETSEL, errorOffset, errorOffset); 94 | SendMessage(memQuery.Handle, EM_SCROLLCARET, 0, 0); 95 | end else 96 | begin 97 | lblQueryState.Caption:= Format('Patterns: %d, Captures: %d, Strings: %d', 98 | [FQuery.PatternCount, FQuery.CaptureCount, FQuery.StringCount]); 99 | for i:= 0 to FQuery.PatternCount - 1 do 100 | cbPatternIdx.Items.Add(IntToStr(i)); 101 | btnMatchStart.Enabled:= True; 102 | end; 103 | if cbPatternIdx.Items.Count > 0 then 104 | cbPatternIdx.ItemIndex:= 0; 105 | cbPatternIdxClick(nil); 106 | end; 107 | 108 | procedure TDTSQueryForm.btnMatchNextClick(Sender: TObject); 109 | var 110 | i: Integer; 111 | captures: TTSQueryCaptureArray; 112 | begin 113 | if not FQueryCursor.NextMatch(FCurrentMatch) then 114 | begin 115 | ClearMatches; 116 | lblMatch.Caption:= 'No more matches'; 117 | Exit; 118 | end; 119 | lblMatch.Caption:= Format('Match id = %d, pattern idx = %d', [FCurrentMatch.id, FCurrentMatch.pattern_index]); 120 | 121 | captures:= FCurrentMatch.CapturesArray; 122 | sgMatchCaptures.RowCount:= Length(captures) + 1; 123 | sgMatchCaptures.FixedRows:= 1; 124 | for i:= 0 to FCurrentMatch.capture_count - 1 do 125 | begin 126 | sgMatchCaptures.Cells[0, i + 1]:= IntToStr(captures[i].index); 127 | sgMatchCaptures.Cells[1, i + 1]:= captures[i].node.NodeType; 128 | end; 129 | if InRange(sgMatchCaptures.Selection.Top, 1, Length(captures)) then 130 | DTSMainForm.SelectedTSNode:= captures[sgMatchCaptures.Selection.Top - 1].node; 131 | end; 132 | 133 | procedure TDTSQueryForm.btnMatchStartClick(Sender: TObject); 134 | begin 135 | if FQueryCursor = nil then 136 | FQueryCursor:= TTSQueryCursor.Create; 137 | FQueryCursor.Execute(FQuery, FTree.RootNode); 138 | ClearMatches; 139 | sgMatchCaptures.Cells[0, 0]:= 'Capture index'; 140 | sgMatchCaptures.Cells[1, 0]:= 'Node'; 141 | btnMatchNext.Enabled:= True; 142 | btnMatchNextClick(nil); 143 | end; 144 | 145 | procedure TDTSQueryForm.cbPatternIdxClick(Sender: TObject); 146 | const 147 | stepTypeStrings: array[TTSQueryPredicateStepType] of string = ( 148 | 'Done', 'Capture', 'String'); 149 | quantifierStrings: array[TTSQuantifier] of string = ( 150 | 'Zero', 'ZeroOrOne', 'ZeroOrMore', 'One', 'OneOrMore'); 151 | var 152 | steps: TTSQueryPredicateStepArray; 153 | step: TTSQueryPredicateStep; 154 | i: Integer; 155 | begin 156 | if cbPatternIdx.ItemIndex >= 0 then 157 | steps:= FQuery.PredicatesForPattern(cbPatternIdx.ItemIndex); 158 | sgPredicateSteps.RowCount:= Length(steps) + 1; 159 | if sgPredicateSteps.RowCount > 1 then 160 | sgPredicateSteps.FixedRows:= 1; 161 | sgPredicateSteps.Cells[0, 0]:= 'Predicate'; 162 | sgPredicateSteps.Cells[1, 0]:= 'Type'; 163 | sgPredicateSteps.Cells[2, 0]:= 'ValueID'; 164 | sgPredicateSteps.Cells[3, 0]:= 'Name'; 165 | sgPredicateSteps.Cells[4, 0]:= 'Quantifier'; 166 | for i:= 1 to Length(steps) do 167 | begin 168 | step:= steps[i - 1]; 169 | sgPredicateSteps.Cells[0, i]:= IntToStr(i - 1); 170 | sgPredicateSteps.Cells[1, i]:= stepTypeStrings[step.&type]; 171 | sgPredicateSteps.Cells[2, i]:= IntToStr(step.value_id); 172 | case step.&type of 173 | TTSQueryPredicateStepType.TSQueryPredicateStepTypeCapture: 174 | begin 175 | sgPredicateSteps.Cells[3, i]:= FQuery.CaptureNameForID(step.value_id); 176 | sgPredicateSteps.Cells[4, i]:= quantifierStrings[FQuery.QuantifierForCapture(cbPatternIdx.ItemIndex, step.value_id)]; 177 | end; 178 | TTSQueryPredicateStepType.TSQueryPredicateStepTypeString: 179 | begin 180 | sgPredicateSteps.Cells[3, i]:= FQuery.StringValueForID(step.value_id); 181 | sgPredicateSteps.Cells[4, i]:= 'N/A'; 182 | end 183 | else 184 | sgPredicateSteps.Cells[3, i]:= 'N/A'; 185 | sgPredicateSteps.Cells[4, i]:= 'N/A'; 186 | end; 187 | end; 188 | end; 189 | 190 | procedure TDTSQueryForm.ClearMatches; 191 | begin 192 | sgMatchCaptures.RowCount:= 1; 193 | lblMatch.Caption:= ''; 194 | btnMatchNext.Enabled:= False; 195 | end; 196 | 197 | procedure TDTSQueryForm.ClearPredicates; 198 | begin 199 | cbPatternIdx.Items.Clear; 200 | sgPredicateSteps.RowCount:= 1; 201 | end; 202 | 203 | procedure TDTSQueryForm.ClearQuery; 204 | begin 205 | FreeAndNil(FQuery); 206 | btnMatchStart.Enabled:= False; 207 | lblQueryState.Caption:= ''; 208 | ClearPredicates; 209 | ClearMatches; 210 | end; 211 | 212 | procedure TDTSQueryForm.FormClose(Sender: TObject; var Action: TCloseAction); 213 | begin 214 | Action:= caFree; 215 | end; 216 | 217 | procedure TDTSQueryForm.FormDestroy(Sender: TObject); 218 | begin 219 | FreeAndNil(FQueryCursor); 220 | FreeAndNil(FQuery); 221 | //FTree is no longer a clone/copy but identical to main form, otherwise 222 | //finding the node in the main forms tree would not work 223 | //(nodes belowing to different trees are not considered equal) 224 | FTree:= nil; 225 | if Self = DTSQueryForm then 226 | DTSQueryForm:= nil; 227 | end; 228 | 229 | procedure TDTSQueryForm.NewTreeGenerated(ATree: TTSTree); 230 | begin 231 | ClearQuery; 232 | FTree:= ATree; 233 | end; 234 | 235 | procedure TDTSQueryForm.sgMatchCapturesSelectCell(Sender: TObject; ACol, 236 | ARow: Integer; var CanSelect: Boolean); 237 | begin 238 | if not InRange(ARow, 1, FCurrentMatch.capture_count) then 239 | Exit; 240 | 241 | DTSMainForm.SelectedTSNode:= FCurrentMatch.captures[ARow - 1].node; 242 | end; 243 | 244 | procedure TDTSQueryForm.TreeDeleted; 245 | begin 246 | ClearQuery; 247 | end; 248 | 249 | end. 250 | --------------------------------------------------------------------------------