@@ -17,6 +17,7 @@ package python
1717import (
1818 "context"
1919 "fmt"
20+ "log"
2021 "os"
2122 "path/filepath"
2223 "strings"
@@ -55,7 +56,10 @@ func NewFileParser() *FileParser {
5556 return & FileParser {}
5657}
5758
58- func ParseCode (code []byte ) (* sitter.Node , error ) {
59+ // ParseCode instantiates a new tree-sitter Parser and parses the python code, returning
60+ // the tree-sitter RootNode.
61+ // It prints a warning if parsing fails.
62+ func ParseCode (code []byte , path string ) (* sitter.Node , error ) {
5963 parser := sitter .NewParser ()
6064 parser .SetLanguage (python .GetLanguage ())
6165
@@ -64,9 +68,27 @@ func ParseCode(code []byte) (*sitter.Node, error) {
6468 return nil , err
6569 }
6670
67- return tree .RootNode (), nil
71+ root := tree .RootNode ()
72+ if root .HasError () {
73+ log .Printf ("WARNING: failed to parse %q. The resulting BUILD target may be incorrect." , path )
74+
75+ verbose , envExists := os .LookupEnv ("GAZELLE_VERBOSE" )
76+ if envExists && verbose == "1" {
77+ for i := 0 ; i < int (root .ChildCount ()); i ++ {
78+ child := root .Child (i )
79+ if child .IsError () {
80+ log .Printf ("Parse error at %+v:\n %+v" , child .StartPoint (), child .Content (code ))
81+ log .Printf ("The above was parsed as: %v" , child .String ())
82+ }
83+ }
84+ }
85+ }
86+
87+ return root , nil
6888}
6989
90+ // parseMain returns true if the python file has an `if __name__ == "__main__":` block,
91+ // which is a common idiom for python scripts/binaries.
7092func (p * FileParser ) parseMain (ctx context.Context , node * sitter.Node ) bool {
7193 for i := 0 ; i < int (node .ChildCount ()); i ++ {
7294 if err := ctx .Err (); err != nil {
@@ -94,6 +116,8 @@ func (p *FileParser) parseMain(ctx context.Context, node *sitter.Node) bool {
94116 return false
95117}
96118
119+ // parseImportStatement parses a node for an import statement, returning a `module` and a boolean
120+ // representing if the parse was OK or not.
97121func parseImportStatement (node * sitter.Node , code []byte ) (module , bool ) {
98122 switch node .Type () {
99123 case sitterNodeTypeDottedName :
@@ -112,6 +136,9 @@ func parseImportStatement(node *sitter.Node, code []byte) (module, bool) {
112136 return module {}, false
113137}
114138
139+ // parseImportStatements parses a node for import statements, returning true if the node is
140+ // an import statement. It updates FileParser.output.Modules with the `module` that the
141+ // import represents.
115142func (p * FileParser ) parseImportStatements (node * sitter.Node ) bool {
116143 if node .Type () == sitterNodeTypeImportStatement {
117144 for j := 1 ; j < int (node .ChildCount ()); j ++ {
@@ -146,6 +173,8 @@ func (p *FileParser) parseImportStatements(node *sitter.Node) bool {
146173 return true
147174}
148175
176+ // parseComments parses a node for comments, returning true if the node is a comment.
177+ // It updates FileParser.output.Comments with the parsed comment.
149178func (p * FileParser ) parseComments (node * sitter.Node ) bool {
150179 if node .Type () == sitterNodeTypeComment {
151180 p .output .Comments = append (p .output .Comments , comment (node .Content (p .code )))
@@ -180,7 +209,7 @@ func (p *FileParser) parse(ctx context.Context, node *sitter.Node) {
180209}
181210
182211func (p * FileParser ) Parse (ctx context.Context ) (* ParserOutput , error ) {
183- rootNode , err := ParseCode (p .code )
212+ rootNode , err := ParseCode (p .code , p . relFilepath )
184213 if err != nil {
185214 return nil , err
186215 }
0 commit comments