Home | History | Annotate | Download | only in syntax
      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 
      5 package syntax
      6 
      7 import (
      8 	"cmd/internal/src"
      9 	"fmt"
     10 	"io"
     11 	"os"
     12 )
     13 
     14 // Mode describes the parser mode.
     15 type Mode uint
     16 
     17 // Modes supported by the parser.
     18 const (
     19 	CheckBranches Mode = 1 << iota // check correct use of labels, break, continue, and goto statements
     20 )
     21 
     22 // Error describes a syntax error. Error implements the error interface.
     23 type Error struct {
     24 	Pos src.Pos
     25 	Msg string
     26 }
     27 
     28 func (err Error) Error() string {
     29 	return fmt.Sprintf("%s: %s", err.Pos, err.Msg)
     30 }
     31 
     32 var _ error = Error{} // verify that Error implements error
     33 
     34 // An ErrorHandler is called for each error encountered reading a .go file.
     35 type ErrorHandler func(err error)
     36 
     37 // A Pragma value is a set of flags that augment a function or
     38 // type declaration. Callers may assign meaning to the flags as
     39 // appropriate.
     40 type Pragma uint16
     41 
     42 // A PragmaHandler is used to process //go: directives as
     43 // they're scanned. The returned Pragma value will be unioned into the
     44 // next FuncDecl node.
     45 type PragmaHandler func(pos src.Pos, text string) Pragma
     46 
     47 // A FilenameHandler is used to process each filename encountered
     48 // in //line directives. The returned value is used as the absolute filename.
     49 type FilenameHandler func(name string) string
     50 
     51 // Parse parses a single Go source file from src and returns the corresponding
     52 // syntax tree. If there are errors, Parse will return the first error found,
     53 // and a possibly partially constructed syntax tree, or nil if no correct package
     54 // clause was found. The base argument is only used for position information.
     55 //
     56 // If errh != nil, it is called with each error encountered, and Parse will
     57 // process as much source as possible. If errh is nil, Parse will terminate
     58 // immediately upon encountering an error.
     59 //
     60 // If a PragmaHandler is provided, it is called with each pragma encountered.
     61 //
     62 // If a FilenameHandler is provided, it is called to process each filename
     63 // encountered in //line directives.
     64 //
     65 // The Mode argument is currently ignored.
     66 func Parse(base *src.PosBase, src io.Reader, errh ErrorHandler, pragh PragmaHandler, fileh FilenameHandler, mode Mode) (_ *File, first error) {
     67 	defer func() {
     68 		if p := recover(); p != nil {
     69 			if err, ok := p.(Error); ok {
     70 				first = err
     71 				return
     72 			}
     73 			panic(p)
     74 		}
     75 	}()
     76 
     77 	var p parser
     78 	p.init(base, src, errh, pragh, fileh, mode)
     79 	p.next()
     80 	return p.fileOrNil(), p.first
     81 }
     82 
     83 // ParseBytes behaves like Parse but it reads the source from the []byte slice provided.
     84 func ParseBytes(base *src.PosBase, src []byte, errh ErrorHandler, pragh PragmaHandler, fileh FilenameHandler, mode Mode) (*File, error) {
     85 	return Parse(base, &bytesReader{src}, errh, pragh, fileh, mode)
     86 }
     87 
     88 type bytesReader struct {
     89 	data []byte
     90 }
     91 
     92 func (r *bytesReader) Read(p []byte) (int, error) {
     93 	if len(r.data) > 0 {
     94 		n := copy(p, r.data)
     95 		r.data = r.data[n:]
     96 		return n, nil
     97 	}
     98 	return 0, io.EOF
     99 }
    100 
    101 // ParseFile behaves like Parse but it reads the source from the named file.
    102 func ParseFile(filename string, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
    103 	f, err := os.Open(filename)
    104 	if err != nil {
    105 		if errh != nil {
    106 			errh(err)
    107 		}
    108 		return nil, err
    109 	}
    110 	defer f.Close()
    111 	return Parse(src.NewFileBase(filename, filename), f, errh, pragh, nil, mode)
    112 }
    113