1// Copyright 2016 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package syntax 6 7import ( 8 "fmt" 9 "io" 10 "os" 11) 12 13// Mode describes the parser mode. 14type Mode uint 15 16// Modes supported by the parser. 17const ( 18 CheckBranches Mode = 1 << iota // check correct use of labels, break, continue, and goto statements 19 AllowGenerics 20) 21 22// Error describes a syntax error. Error implements the error interface. 23type Error struct { 24 Pos Pos 25 Msg string 26} 27 28func (err Error) Error() string { 29 return fmt.Sprintf("%s: %s", err.Pos, err.Msg) 30} 31 32var _ error = Error{} // verify that Error implements error 33 34// An ErrorHandler is called for each error encountered reading a .go file. 35type ErrorHandler func(err error) 36 37// A Pragma value augments a package, import, const, func, type, or var declaration. 38// Its meaning is entirely up to the PragmaHandler, 39// except that nil is used to mean “no pragma seen.” 40type Pragma interface{} 41 42// A PragmaHandler is used to process //go: directives while scanning. 43// It is passed the current pragma value, which starts out being nil, 44// and it returns an updated pragma value. 45// The text is the directive, with the "//" prefix stripped. 46// The current pragma is saved at each package, import, const, func, type, or var 47// declaration, into the File, ImportDecl, ConstDecl, FuncDecl, TypeDecl, or VarDecl node. 48// 49// If text is the empty string, the pragma is being returned 50// to the handler unused, meaning it appeared before a non-declaration. 51// The handler may wish to report an error. In this case, pos is the 52// current parser position, not the position of the pragma itself. 53// Blank specifies whether the line is blank before the pragma. 54type PragmaHandler func(pos Pos, blank bool, text string, current Pragma) Pragma 55 56// Parse parses a single Go source file from src and returns the corresponding 57// syntax tree. If there are errors, Parse will return the first error found, 58// and a possibly partially constructed syntax tree, or nil. 59// 60// If errh != nil, it is called with each error encountered, and Parse will 61// process as much source as possible. In this case, the returned syntax tree 62// is only nil if no correct package clause was found. 63// If errh is nil, Parse will terminate immediately upon encountering the first 64// error, and the returned syntax tree is nil. 65// 66// If pragh != nil, it is called with each pragma encountered. 67// 68func Parse(base *PosBase, src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_ *File, first error) { 69 defer func() { 70 if p := recover(); p != nil { 71 if err, ok := p.(Error); ok { 72 first = err 73 return 74 } 75 panic(p) 76 } 77 }() 78 79 var p parser 80 p.init(base, src, errh, pragh, mode) 81 p.next() 82 return p.fileOrNil(), p.first 83} 84 85// ParseFile behaves like Parse but it reads the source from the named file. 86func ParseFile(filename string, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) { 87 f, err := os.Open(filename) 88 if err != nil { 89 if errh != nil { 90 errh(err) 91 } 92 return nil, err 93 } 94 defer f.Close() 95 return Parse(NewFileBase(filename), f, errh, pragh, mode) 96} 97