1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15- package imports
15+ package fastscan
1616
1717import (
1818 "io"
@@ -26,23 +26,38 @@ var closeSymbol = map[tokenType]tokenType{
2626 openAngleToken : closeAngleToken ,
2727}
2828
29- // ScanForImports scans the given reader, which should contain Protobuf source, and
30- // returns the set of imports declared in the file. It returns an error if there is
29+ // Result is the result of scanning a Protobuf source file. It contains the
30+ // information extracted from the file.
31+ type Result struct {
32+ PackageName string
33+ Imports []string
34+ }
35+
36+ // Scan scans the given reader, which should contain Protobuf source, and
37+ // returns the set of imports declared in the file. The result also contains the
38+ // value of any package declaration in the file. It returns an error if there is
3139// an I/O error reading from r. In the event of such an error, it will still return
32- // a slice of imports that contains as many imports as were found before the I/O
33- // error occurred.
34- func ScanForImports (r io.Reader ) ([]string , error ) {
35- var imports []string
40+ // a result that contains as much information as was found before the I/O error
41+ // occurred.
42+ func Scan (r io.Reader ) (Result , error ) {
43+ var res Result
44+
45+ var currentImport []string // if non-nil, parsing an import statement
46+ var packageComponents []string // if non-nil, parsing a package statement
47+
48+ // current stack of open blocks -- those starting with {, [, (, or < for
49+ // which we haven't yet encountered the closing }, ], ), or >
3650 var contextStack []tokenType
37- var currentImport []string
51+ declarationStart := true
52+
3853 lexer := newLexer (r )
3954 for {
4055 token , text , err := lexer .Lex ()
4156 if err != nil {
42- return imports , err
57+ return res , err
4358 }
4459 if token == eofToken {
45- return imports , nil
60+ return res , nil
4661 }
4762
4863 if currentImport != nil {
@@ -51,12 +66,26 @@ func ScanForImports(r io.Reader) ([]string, error) {
5166 currentImport = append (currentImport , text .(string ))
5267 default :
5368 if len (currentImport ) > 0 {
54- imports = append (imports , strings .Join (currentImport , "" ))
69+ res . Imports = append (res . Imports , strings .Join (currentImport , "" ))
5570 }
5671 currentImport = nil
5772 }
5873 }
5974
75+ if packageComponents != nil {
76+ switch token {
77+ case identifierToken :
78+ packageComponents = append (packageComponents , text .(string ))
79+ case periodToken :
80+ packageComponents = append (packageComponents , "." )
81+ default :
82+ if len (packageComponents ) > 0 {
83+ res .PackageName = strings .Join (packageComponents , "" )
84+ }
85+ packageComponents = nil
86+ }
87+ }
88+
6089 switch token {
6190 case openParenToken , openBraceToken , openBracketToken , openAngleToken :
6291 contextStack = append (contextStack , closeSymbol [token ])
@@ -65,9 +94,15 @@ func ScanForImports(r io.Reader) ([]string, error) {
6594 contextStack = contextStack [:len (contextStack )- 1 ]
6695 }
6796 case identifierToken :
68- if text == "import" && len (contextStack ) == 0 {
69- currentImport = []string {}
97+ if declarationStart && len (contextStack ) == 0 {
98+ if text == "import" {
99+ currentImport = []string {}
100+ } else if text == "package" {
101+ packageComponents = []string {}
102+ }
70103 }
71104 }
105+
106+ declarationStart = token == closeBraceToken || token == semicolonToken
72107 }
73108}
0 commit comments