diff --git a/src/TreeSitter-Spec/TSAbstractFilesVisitor.class.st b/src/TreeSitter-Spec/TSAbstractFilesVisitor.class.st new file mode 100644 index 0000000..f5fc777 --- /dev/null +++ b/src/TreeSitter-Spec/TSAbstractFilesVisitor.class.st @@ -0,0 +1,74 @@ +" +I am an abstract class to implement some visitors for a language to go over a collection of files, parse and visit them. + +My subclasses can customize what I am doing by overriding #visitNode: +" +Class { + #name : 'TSAbstractFilesVisitor', + #superclass : 'TSVisitor', + #instVars : [ + 'language', + 'extensions', + 'filesToParse', + 'code' + ], + #category : 'TreeSitter-Spec', + #package : 'TreeSitter-Spec' +} + +{ #category : 'initialization' } +TSAbstractFilesVisitor >> buildOn: aFileReference [ + + self collectFilesIn: aFileReference. + + filesToParse do: [ :file | self parseAndVisitFile: file ] displayingProgress: [ :file | file pathString ]. + + self inspect +] + +{ #category : 'initialization' } +TSAbstractFilesVisitor >> collectFilesIn: aFileReference [ + + ^ aFileReference isFile + ifTrue: [ (self extensions includes: aFileReference extension) ifTrue: [ filesToParse add: aFileReference ] ] + ifFalse: [ aFileReference children do: [ :child | self collectFilesIn: child ] ] +] + +{ #category : 'accessing' } +TSAbstractFilesVisitor >> extensions [ + ^ extensions +] + +{ #category : 'accessing' } +TSAbstractFilesVisitor >> extensions: anObject [ + extensions := anObject +] + +{ #category : 'initialization' } +TSAbstractFilesVisitor >> initialize [ + + super initialize. + filesToParse := OrderedCollection new +] + +{ #category : 'accessing' } +TSAbstractFilesVisitor >> language [ + + ^ language +] + +{ #category : 'accessing' } +TSAbstractFilesVisitor >> language: anObject [ + + language := anObject +] + +{ #category : 'initialization' } +TSAbstractFilesVisitor >> parseAndVisitFile: aFile [ + + code := [ aFile contents ] + on: ZnInvalidUTF8 + do: [ "For now we ignore files not in UTF8." '' ]. + + ((TSParser language: self language) parseString: code) rootNode accept: self +] diff --git a/src/TreeSitter-Spec/TSNode.extension.st b/src/TreeSitter-Spec/TSNode.extension.st index 269488e..368339f 100644 --- a/src/TreeSitter-Spec/TSNode.extension.st +++ b/src/TreeSitter-Spec/TSNode.extension.st @@ -4,15 +4,13 @@ Extension { #name : 'TSNode' } TSNode >> tsTreeExtension: aBuilder [ - ^ aBuilder newTreeTable addColumn: (SpCompositeTableColumn new addColumn: (SpStringTableColumn evaluated: #type); yourself); - children: [ :aTSNode | - (1 to: aTSNode namedChildCount) collect: [ :idx | - aTSNode namedChildAt: idx ] ]; + children: [ :aTSNode | (1 to: aTSNode namedChildCount) collect: [ :idx | aTSNode namedChildAt: idx ] ]; roots: { self }; beResizable; + expandAll; yourself ] diff --git a/src/TreeSitter-Spec/TSNodeFinderVisitor.class.st b/src/TreeSitter-Spec/TSNodeFinderVisitor.class.st new file mode 100644 index 0000000..577eabb --- /dev/null +++ b/src/TreeSitter-Spec/TSNodeFinderVisitor.class.st @@ -0,0 +1,97 @@ +" +I am a visitor made to find a node in a folder of surces matching a certain pattern and see the source code associated. + +For example, I wanted to find an example of code with a except_clause in python that had multiple children in the #value field: + +```st +folder := '/Users/cyril/testPython/cpython-main' asFileReference. + +TSNodeFinderVisitor + language: TSLanguage python + extensions: #( 'py' ) + selection: [ :node | node type = #except_clause and: [ (node detectChildWithFieldName: #value) isCollection ] ] + buildOn: folder +``` + +Note that in order for me to work, I need to have a matching node in the sources provided. + +I'll save the found node in my node ivar. +" +Class { + #name : 'TSNodeFinderVisitor', + #superclass : 'TSAbstractFilesVisitor', + #instVars : [ + 'selectionBlock', + 'node' + ], + #category : 'TreeSitter-Spec', + #package : 'TreeSitter-Spec' +} + +{ #category : 'as yet unclassified' } +TSNodeFinderVisitor class >> language: aTSLanguage extensions: aCollection selection: aBlock buildOn: aFileReference [ + + ^ self new + language: aTSLanguage; + extensions: aCollection; + selectionBlock: aBlock; + buildOn: aFileReference +] + +{ #category : 'inspector' } +TSNodeFinderVisitor >> inspectionFullSource: aBuilder [ + + + ^ aBuilder newCode + withoutSyntaxHighlight; + withLineNumbers; + text: code; + addTextSegmentDecoration: (SpTextPresenterDecorator forHighlight + interval: ((node startPositionFromSourceText: code) to: (node endPositionFromSourceText: code) + 1); + yourself); + beNotEditable +] + +{ #category : 'inspector' } +TSNodeFinderVisitor >> inspectionFullSourceContext: aContext [ + + aContext active: node isNotNil +] + +{ #category : 'inspector' } +TSNodeFinderVisitor >> inspectionSource: aBuilder [ + + + ^ aBuilder newCode + withoutSyntaxHighlight; + withLineNumbers; + text: (node + ifNil: [ 'No node matched.' ] + ifNotNil: [ node textFromSourceText: code ]); + beNotEditable +] + +{ #category : 'initialization' } +TSNodeFinderVisitor >> parseAndVisitFile: aFile [ + + node ifNotNil: [ ^ self "skipping." ]. + + ^ super parseAndVisitFile: aFile +] + +{ #category : 'accessing' } +TSNodeFinderVisitor >> selectionBlock: anObject [ + selectionBlock := anObject +] + +{ #category : 'visiting' } +TSNodeFinderVisitor >> visitNode: aTSNode [ + + (selectionBlock value: aTSNode) ifTrue: [ + node := aTSNode. + ^ true ]. + + aTSNode collectNamedChild do: [ :child | (self visitNode: child) ifTrue: [ ^ true ] ]. + + ^ false +] diff --git a/src/TreeSitter-Spec/TSSymbolsBuilderVisitor.class.st b/src/TreeSitter-Spec/TSSymbolsBuilderVisitor.class.st index 33898a2..cda2c4f 100644 --- a/src/TreeSitter-Spec/TSSymbolsBuilderVisitor.class.st +++ b/src/TreeSitter-Spec/TSSymbolsBuilderVisitor.class.st @@ -13,13 +13,9 @@ Warning: This visitor will build a map of all the symbols present in a project a " Class { #name : 'TSSymbolsBuilderVisitor', - #superclass : 'TSVisitor', + #superclass : 'TSAbstractFilesVisitor', #instVars : [ - 'language', - 'extensions', - 'filesToParse', - 'symbolDictionary', - 'code' + 'symbolDictionary' ], #category : 'TreeSitter-Spec', #package : 'TreeSitter-Spec' @@ -34,61 +30,13 @@ TSSymbolsBuilderVisitor class >> language: aTSLanguage extensions: aCollection b buildOn: aFileReference ] -{ #category : 'initialization' } -TSSymbolsBuilderVisitor >> buildOn: aFileReference [ - - self collectFilesIn: aFileReference. - - filesToParse - do: [ :file | - code := [ file contents ] - on: ZnInvalidUTF8 - do: [ "For now we ignore files not in UTF8." '' ]. - - ((TSParser language: self language) parseString: code) rootNode accept: self ] - displayingProgress: [ :file | file pathString ]. - - self inspect -] - -{ #category : 'initialization' } -TSSymbolsBuilderVisitor >> collectFilesIn: aFileReference [ - - ^ aFileReference isFile - ifTrue: [ (self extensions includes: aFileReference extension) ifTrue: [ filesToParse add: aFileReference ] ] - ifFalse: [ aFileReference children do: [ :child | self collectFilesIn: child ] ] -] - -{ #category : 'accessing' } -TSSymbolsBuilderVisitor >> extensions [ - ^ extensions -] - -{ #category : 'accessing' } -TSSymbolsBuilderVisitor >> extensions: anObject [ - extensions := anObject -] - { #category : 'initialization' } TSSymbolsBuilderVisitor >> initialize [ super initialize. - filesToParse := OrderedCollection new. symbolDictionary := Dictionary new ] -{ #category : 'accessing' } -TSSymbolsBuilderVisitor >> language [ - - ^ language -] - -{ #category : 'accessing' } -TSSymbolsBuilderVisitor >> language: anObject [ - - language := anObject -] - { #category : 'inspector' } TSSymbolsBuilderVisitor >> symbolsInspector: aBuilder [ @@ -115,10 +63,6 @@ TSSymbolsBuilderVisitor >> visitNode: aTSNode [ detect: [ :wrapper | wrapper field = field ] ifNone: [ fields add: (TSFieldExplorerWrapper field: field) ]. - wrap - addAll: (nodes isCollection - ifTrue: [ nodes ] - ifFalse: [ { nodes } ]) - code: code ]. + wrap addAll: nodes asTSNodes code: code ]. super visitNode: aTSNode ]