src/pkg/go/parser/interface.go - The Go Programming Language

Golang

Source file src/pkg/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	)
    19	
    20	// If src != nil, readSource converts src to a []byte if possible;
    21	// otherwise it returns an error. If src == nil, readSource returns
    22	// the result of reading the file specified by filename.
    23	//
    24	func readSource(filename string, src interface{}) ([]byte, error) {
    25		if src != nil {
    26			switch s := src.(type) {
    27			case string:
    28				return []byte(s), nil
    29			case []byte:
    30				return s, nil
    31			case *bytes.Buffer:
    32				// is io.Reader, but src is already available in []byte form
    33				if s != nil {
    34					return s.Bytes(), nil
    35				}
    36			case io.Reader:
    37				var buf bytes.Buffer
    38				if _, err := io.Copy(&buf, s); err != nil {
    39					return nil, err
    40				}
    41				return buf.Bytes(), nil
    42			}
    43			return nil, errors.New("invalid source")
    44		}
    45		return ioutil.ReadFile(filename)
    46	}
    47	
    48	// A Mode value is a set of flags (or 0).
    49	// They control the amount of source code parsed and other optional
    50	// parser functionality.
    51	//
    52	type Mode uint
    53	
    54	const (
    55		PackageClauseOnly Mode = 1 << iota // parsing stops after package clause
    56		ImportsOnly                        // parsing stops after import declarations
    57		ParseComments                      // parse comments and add them to AST
    58		Trace                              // print a trace of parsed productions
    59		DeclarationErrors                  // report declaration errors
    60		SpuriousErrors                     // report all (not just the first) errors per line
    61	)
    62	
    63	// ParseFile parses the source code of a single Go source file and returns
    64	// the corresponding ast.File node. The source code may be provided via
    65	// the filename of the source file, or via the src parameter.
    66	//
    67	// If src != nil, ParseFile parses the source from src and the filename is
    68	// only used when recording position information. The type of the argument
    69	// for the src parameter must be string, []byte, or io.Reader.
    70	// If src == nil, ParseFile parses the file specified by filename.
    71	//
    72	// The mode parameter controls the amount of source text parsed and other
    73	// optional parser functionality. Position information is recorded in the
    74	// file set fset.
    75	//
    76	// If the source couldn't be read, the returned AST is nil and the error
    77	// indicates the specific failure. If the source was read but syntax
    78	// errors were found, the result is a partial AST (with ast.Bad* nodes
    79	// representing the fragments of erroneous source code). Multiple errors
    80	// are returned via a scanner.ErrorList which is sorted by file position.
    81	//
    82	func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (*ast.File, error) {
    83		// get source
    84		text, err := readSource(filename, src)
    85		if err != nil {
    86			return nil, err
    87		}
    88	
    89		// parse source
    90		var p parser
    91		p.init(fset, filename, text, mode)
    92		f := p.parseFile()
    93	
    94		// sort errors
    95		if p.mode&SpuriousErrors == 0 {
    96			p.errors.RemoveMultiples()
    97		} else {
    98			p.errors.Sort()
    99		}
   100	
   101		return f, p.errors.Err()
   102	}
   103	
   104	// ParseDir calls ParseFile for the files in the directory specified by path and
   105	// returns a map of package name -> package AST with all the packages found. If
   106	// filter != nil, only the files with os.FileInfo entries passing through the filter
   107	// are considered. The mode bits are passed to ParseFile unchanged. Position
   108	// information is recorded in the file set fset.
   109	//
   110	// If the directory couldn't be read, a nil map and the respective error are
   111	// returned. If a parse error occurred, a non-nil but incomplete map and the
   112	// first error encountered are returned.
   113	//
   114	func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, mode Mode) (pkgs map[string]*ast.Package, first error) {
   115		fd, err := os.Open(path)
   116		if err != nil {
   117			return nil, err
   118		}
   119		defer fd.Close()
   120	
   121		list, err := fd.Readdir(-1)
   122		if err != nil {
   123			return nil, err
   124		}
   125	
   126		pkgs = make(map[string]*ast.Package)
   127		for _, d := range list {
   128			if filter == nil || filter(d) {
   129				filename := filepath.Join(path, d.Name())
   130				if src, err := ParseFile(fset, filename, nil, mode); err == nil {
   131					name := src.Name.Name
   132					pkg, found := pkgs[name]
   133					if !found {
   134						pkg = &ast.Package{
   135							Name:  name,
   136							Files: make(map[string]*ast.File),
   137						}
   138						pkgs[name] = pkg
   139					}
   140					pkg.Files[filename] = src
   141				} else if first == nil {
   142					first = err
   143				}
   144			}
   145		}
   146	
   147		return
   148	}
   149	
   150	// ParseExpr is a convenience function for obtaining the AST of an expression x.
   151	// The position information recorded in the AST is undefined.
   152	// 
   153	func ParseExpr(x string) (ast.Expr, error) {
   154		// parse x within the context of a complete package for correct scopes;
   155		// use //line directive for correct positions in error messages and put
   156		// x alone on a separate line (handles line comments), followed by a ';'
   157		// to force an error if the expression is incomplete
   158		file, err := ParseFile(token.NewFileSet(), "", "package p;func _(){_=\n//line :1\n"+x+"\n;}", 0)
   159		if err != nil {
   160			return nil, err
   161		}
   162		return file.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.AssignStmt).Rhs[0], nil
   163	}