mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal/syntax: fix error handling for Read/Parse calls
- define syntax.Error for cleaner error reporting - abort parsing after first error if no error handler is installed - make sure to always report the first error, if any - document behavior of API calls - while at it: rename ReadXXX -> ParseXXX (clearer) - adjust cmd/compile noder.go accordingly Fixes #17774. Change-Id: I7893eedea454a64acd753e32f7a8bf811ddbb03c Reviewed-on: https://go-review.googlesource.com/32950 Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
ad020477f4
commit
60a9bf9f95
8 changed files with 126 additions and 85 deletions
|
|
@ -5,35 +5,72 @@
|
|||
package syntax
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Mode describes the parser mode.
|
||||
type Mode uint
|
||||
|
||||
// Error describes a syntax error. Error implements the error interface.
|
||||
type Error struct {
|
||||
// TODO(gri) decide what we really need here
|
||||
Pos int // byte offset from file start
|
||||
Line int // line (starting with 1)
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (err Error) Error() string {
|
||||
return fmt.Sprintf("%d: %s", err.Line, err.Msg)
|
||||
}
|
||||
|
||||
var _ error = Error{} // verify that Error implements error
|
||||
|
||||
// An ErrorHandler is called for each error encountered reading a .go file.
|
||||
type ErrorHandler func(err error)
|
||||
|
||||
// A Pragma value is a set of flags that augment a function or
|
||||
// type declaration. Callers may assign meaning to the flags as
|
||||
// appropriate.
|
||||
type Pragma uint16
|
||||
|
||||
type ErrorHandler func(pos, line int, msg string)
|
||||
|
||||
// A PragmaHandler is used to process //line and //go: directives as
|
||||
// they're scanned. The returned Pragma value will be unioned into the
|
||||
// next FuncDecl node.
|
||||
type PragmaHandler func(pos, line int, text string) Pragma
|
||||
|
||||
// TODO(gri) These need a lot more work.
|
||||
// Parse parses a single Go source file from src and returns the corresponding
|
||||
// syntax tree. If there are syntax errors, Parse will return the first error
|
||||
// encountered.
|
||||
//
|
||||
// If errh != nil, it is called with each error encountered, and Parse will
|
||||
// process as much source as possible. If errh is nil, Parse will terminate
|
||||
// immediately upon encountering an error.
|
||||
//
|
||||
// If a PragmaHandler is provided, it is called with each pragma encountered.
|
||||
//
|
||||
// The Mode argument is currently ignored.
|
||||
func Parse(src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_ *File, err error) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
var ok bool
|
||||
if err, ok = p.(Error); ok {
|
||||
return
|
||||
}
|
||||
panic(p)
|
||||
}
|
||||
}()
|
||||
|
||||
func ReadFile(filename string, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
|
||||
src, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer src.Close()
|
||||
return Read(src, errh, pragh, mode)
|
||||
var p parser
|
||||
p.init(src, errh, pragh)
|
||||
p.next()
|
||||
return p.file(), p.first
|
||||
}
|
||||
|
||||
// ParseBytes behaves like Parse but it reads the source from the []byte slice provided.
|
||||
func ParseBytes(src []byte, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
|
||||
return Parse(&bytesReader{src}, errh, pragh, mode)
|
||||
}
|
||||
|
||||
type bytesReader struct {
|
||||
|
|
@ -49,37 +86,15 @@ func (r *bytesReader) Read(p []byte) (int, error) {
|
|||
return 0, io.EOF
|
||||
}
|
||||
|
||||
func ReadBytes(src []byte, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
|
||||
return Read(&bytesReader{src}, errh, pragh, mode)
|
||||
}
|
||||
|
||||
func Read(src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (ast *File, err error) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
if msg, ok := p.(parserError); ok {
|
||||
err = errors.New(string(msg))
|
||||
return
|
||||
}
|
||||
panic(p)
|
||||
// ParseFile behaves like Parse but it reads the source from the named file.
|
||||
func ParseFile(filename string, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
|
||||
src, err := os.Open(filename)
|
||||
if err != nil {
|
||||
if errh != nil {
|
||||
errh(err)
|
||||
}
|
||||
}()
|
||||
|
||||
var p parser
|
||||
p.init(src, errh, pragh)
|
||||
p.next()
|
||||
ast = p.file()
|
||||
|
||||
// TODO(gri) This isn't quite right: Even if there's an error handler installed
|
||||
// we should report an error if parsing found syntax errors. This also
|
||||
// requires updating the noder's ReadFile call.
|
||||
if errh == nil && p.nerrors > 0 {
|
||||
ast = nil
|
||||
err = fmt.Errorf("%d syntax errors", p.nerrors)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func Write(w io.Writer, n *File) error {
|
||||
panic("unimplemented")
|
||||
defer src.Close()
|
||||
return Parse(src, errh, pragh, mode)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue