...

Source file src/go/parser/interface.go

     1	// Copyright 2009 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	// This file contains the exported entry points for invoking the parser.
     6	
     7	package parser
     8	
     9	import (
    10		"bytes"
    11		"errors"
    12		"go/ast"
    13		"go/token"
    14		"io"
    15		"io/ioutil"
    16		"os"
    17		"path/filepath"
    18		"strings"
    19	)
    20	
    21	// If src != nil, readSource converts src to a []byte if possible;
    22	// otherwise it returns an error. If src == nil, readSource returns
    23	// the result of reading the file specified by filename.
    24	//
    25	func readSource(filename string, src interface{}) ([]byte, error) {
    26		if src != nil {
    27			switch s := src.(type) {
    28			case string:
    29				return []byte(s), nil
    30			case []byte:
    31				return s, nil
    32			case *bytes.Buffer:
    33				// is io.Reader, but src is already available in []byte form
    34				if s != nil {
    35					return s.Bytes(), nil
    36				}
    37			case io.Reader:
    38				return ioutil.ReadAll(s)
    39			}
    40			return nil, errors.New("invalid source")
    41		}
    42		return ioutil.ReadFile(filename)
    43	}
    44	
    45	// A Mode value is a set of flags (or 0).
    46	// They control the amount of source code parsed and other optional
    47	// parser functionality.
    48	//
    49	type Mode uint
    50	
    51	const (
    52		PackageClauseOnly Mode             = 1 << iota // stop parsing after package clause
    53		ImportsOnly                                    // stop parsing after import declarations
    54		ParseComments                                  // parse comments and add them to AST
    55		Trace                                          // print a trace of parsed productions
    56		DeclarationErrors                              // report declaration errors
    57		SpuriousErrors                                 // same as AllErrors, for backward-compatibility
    58		AllErrors         = SpuriousErrors             // report all errors (not just the first 10 on different lines)
    59	)
    60	
    61	// ParseFile parses the source code of a single Go source file and returns
    62	// the corresponding ast.File node. The source code may be provided via
    63	// the filename of the source file, or via the src parameter.
    64	//
    65	// If src != nil, ParseFile parses the source from src and the filename is
    66	// only used when recording position information. The type of the argument
    67	// for the src parameter must be string, []byte, or io.Reader.
    68	// If src == nil, ParseFile parses the file specified by filename.
    69	//
    70	// The mode parameter controls the amount of source text parsed and other
    71	// optional parser functionality. Position information is recorded in the
    72	// file set fset, which must not be nil.
    73	//
    74	// If the source couldn't be read, the returned AST is nil and the error
    75	// indicates the specific failure. If the source was read but syntax
    76	// errors were found, the result is a partial AST (with ast.Bad* nodes
    77	// representing the fragments of erroneous source code). Multiple errors
    78	// are returned via a scanner.ErrorList which is sorted by file position.
    79	//
    80	func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (f *ast.File, err error) {
    81		if fset == nil {
    82			panic("parser.ParseFile: no token.FileSet provided (fset == nil)")
    83		}
    84	
    85		// get source
    86		text, err := readSource(filename, src)
    87		if err != nil {
    88			return nil, err
    89		}
    90	
    91		var p parser
    92		defer func() {
    93			if e := recover(); e != nil {
    94				// resume same panic if it's not a bailout
    95				if _, ok := e.(bailout); !ok {
    96					panic(e)
    97				}
    98			}
    99	
   100			// set result values
   101			if f == nil {
   102				// source is not a valid Go source file - satisfy
   103				// ParseFile API and return a valid (but) empty
   104				// *ast.File
   105				f = &ast.File{
   106					Name:  new(ast.Ident),
   107					Scope: ast.NewScope(nil),
   108				}
   109			}
   110	
   111			p.errors.Sort()
   112			err = p.errors.Err()
   113		}()
   114	
   115		// parse source
   116		p.init(fset, filename, text, mode)
   117		f = p.parseFile()
   118	
   119		return
   120	}
   121	
   122	// ParseDir calls ParseFile for all files with names ending in ".go" in the
   123	// directory specified by path and returns a map of package name -> package
   124	// AST with all the packages found.
   125	//
   126	// If filter != nil, only the files with os.FileInfo entries passing through
   127	// the filter (and ending in ".go") are considered. The mode bits are passed
   128	// to ParseFile unchanged. Position information is recorded in fset, which
   129	// must not be nil.
   130	//
   131	// If the directory couldn't be read, a nil map and the respective error are
   132	// returned. If a parse error occurred, a non-nil but incomplete map and the
   133	// first error encountered are returned.
   134	//
   135	func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, mode Mode) (pkgs map[string]*ast.Package, first error) {
   136		fd, err := os.Open(path)
   137		if err != nil {
   138			return nil, err
   139		}
   140		defer fd.Close()
   141	
   142		list, err := fd.Readdir(-1)
   143		if err != nil {
   144			return nil, err
   145		}
   146	
   147		pkgs = make(map[string]*ast.Package)
   148		for _, d := range list {
   149			if strings.HasSuffix(d.Name(), ".go") && (filter == nil || filter(d)) {
   150				filename := filepath.Join(path, d.Name())
   151				if src, err := ParseFile(fset, filename, nil, mode); err == nil {
   152					name := src.Name.Name
   153					pkg, found := pkgs[name]
   154					if !found {
   155						pkg = &ast.Package{
   156							Name:  name,
   157							Files: make(map[string]*ast.File),
   158						}
   159						pkgs[name] = pkg
   160					}
   161					pkg.Files[filename] = src
   162				} else if first == nil {
   163					first = err
   164				}
   165			}
   166		}
   167	
   168		return
   169	}
   170	
   171	// ParseExprFrom is a convenience function for parsing an expression.
   172	// The arguments have the same meaning as for ParseFile, but the source must
   173	// be a valid Go (type or value) expression. Specifically, fset must not
   174	// be nil.
   175	//
   176	func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode Mode) (ast.Expr, error) {
   177		if fset == nil {
   178			panic("parser.ParseExprFrom: no token.FileSet provided (fset == nil)")
   179		}
   180	
   181		// get source
   182		text, err := readSource(filename, src)
   183		if err != nil {
   184			return nil, err
   185		}
   186	
   187		var p parser
   188		defer func() {
   189			if e := recover(); e != nil {
   190				// resume same panic if it's not a bailout
   191				if _, ok := e.(bailout); !ok {
   192					panic(e)
   193				}
   194			}
   195			p.errors.Sort()
   196			err = p.errors.Err()
   197		}()
   198	
   199		// parse expr
   200		p.init(fset, filename, text, mode)
   201		// Set up pkg-level scopes to avoid nil-pointer errors.
   202		// This is not needed for a correct expression x as the
   203		// parser will be ok with a nil topScope, but be cautious
   204		// in case of an erroneous x.
   205		p.openScope()
   206		p.pkgScope = p.topScope
   207		e := p.parseRhsOrType()
   208		p.closeScope()
   209		assert(p.topScope == nil, "unbalanced scopes")
   210	
   211		// If a semicolon was inserted, consume it;
   212		// report an error if there's more tokens.
   213		if p.tok == token.SEMICOLON && p.lit == "\n" {
   214			p.next()
   215		}
   216		p.expect(token.EOF)
   217	
   218		if p.errors.Len() > 0 {
   219			p.errors.Sort()
   220			return nil, p.errors.Err()
   221		}
   222	
   223		return e, nil
   224	}
   225	
   226	// ParseExpr is a convenience function for obtaining the AST of an expression x.
   227	// The position information recorded in the AST is undefined. The filename used
   228	// in error messages is the empty string.
   229	//
   230	func ParseExpr(x string) (ast.Expr, error) {
   231		return ParseExprFrom(token.NewFileSet(), "", []byte(x), 0)
   232	}
   233	

View as plain text