The Go Programming Language

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		"go/ast"
    12		"go/scanner"
    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, os.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				_, err := io.Copy(&buf, s)
    39				if err != nil {
    40					return nil, err
    41				}
    42				return buf.Bytes(), nil
    43			default:
    44				return nil, os.NewError("invalid source")
    45			}
    46		}
    47	
    48		return ioutil.ReadFile(filename)
    49	}
    50	
    51	func (p *parser) errors() os.Error {
    52		mode := scanner.Sorted
    53		if p.mode&SpuriousErrors == 0 {
    54			mode = scanner.NoMultiples
    55		}
    56		return p.GetError(mode)
    57	}
    58	
    59	// ParseExpr parses a Go expression and returns the corresponding
    60	// AST node. The fset, filename, and src arguments have the same interpretation
    61	// as for ParseFile. If there is an error, the result expression
    62	// may be nil or contain a partial AST.
    63	//
    64	func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr, os.Error) {
    65		data, err := readSource(filename, src)
    66		if err != nil {
    67			return nil, err
    68		}
    69	
    70		var p parser
    71		p.init(fset, filename, data, 0)
    72		x := p.parseRhs()
    73		if p.tok == token.SEMICOLON {
    74			p.next() // consume automatically inserted semicolon, if any
    75		}
    76		p.expect(token.EOF)
    77	
    78		return x, p.errors()
    79	}
    80	
    81	// ParseStmtList parses a list of Go statements and returns the list
    82	// of corresponding AST nodes. The fset, filename, and src arguments have the same
    83	// interpretation as for ParseFile. If there is an error, the node
    84	// list may be nil or contain partial ASTs.
    85	//
    86	func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast.Stmt, os.Error) {
    87		data, err := readSource(filename, src)
    88		if err != nil {
    89			return nil, err
    90		}
    91	
    92		var p parser
    93		p.init(fset, filename, data, 0)
    94		list := p.parseStmtList()
    95		p.expect(token.EOF)
    96	
    97		return list, p.errors()
    98	}
    99	
   100	// ParseDeclList parses a list of Go declarations and returns the list
   101	// of corresponding AST nodes. The fset, filename, and src arguments have the same
   102	// interpretation as for ParseFile. If there is an error, the node
   103	// list may be nil or contain partial ASTs.
   104	//
   105	func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast.Decl, os.Error) {
   106		data, err := readSource(filename, src)
   107		if err != nil {
   108			return nil, err
   109		}
   110	
   111		var p parser
   112		p.init(fset, filename, data, 0)
   113		list := p.parseDeclList()
   114		p.expect(token.EOF)
   115	
   116		return list, p.errors()
   117	}
   118	
   119	// ParseFile parses the source code of a single Go source file and returns
   120	// the corresponding ast.File node. The source code may be provided via
   121	// the filename of the source file, or via the src parameter.
   122	//
   123	// If src != nil, ParseFile parses the source from src and the filename is
   124	// only used when recording position information. The type of the argument
   125	// for the src parameter must be string, []byte, or io.Reader.
   126	//
   127	// If src == nil, ParseFile parses the file specified by filename.
   128	//
   129	// The mode parameter controls the amount of source text parsed and other
   130	// optional parser functionality. Position information is recorded in the
   131	// file set fset.
   132	//
   133	// If the source couldn't be read, the returned AST is nil and the error
   134	// indicates the specific failure. If the source was read but syntax
   135	// errors were found, the result is a partial AST (with ast.BadX nodes
   136	// representing the fragments of erroneous source code). Multiple errors
   137	// are returned via a scanner.ErrorList which is sorted by file position.
   138	//
   139	func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint) (*ast.File, os.Error) {
   140		data, err := readSource(filename, src)
   141		if err != nil {
   142			return nil, err
   143		}
   144	
   145		var p parser
   146		p.init(fset, filename, data, mode)
   147		file := p.parseFile() // parseFile reads to EOF
   148	
   149		return file, p.errors()
   150	}
   151	
   152	// ParseFiles calls ParseFile for each file in the filenames list and returns
   153	// a map of package name -> package AST with all the packages found. The mode
   154	// bits are passed to ParseFile unchanged. Position information is recorded
   155	// in the file set fset.
   156	//
   157	// Files with parse errors are ignored. In this case the map of packages may
   158	// be incomplete (missing packages and/or incomplete packages) and the first
   159	// error encountered is returned.
   160	//
   161	func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[string]*ast.Package, first os.Error) {
   162		pkgs = make(map[string]*ast.Package)
   163		for _, filename := range filenames {
   164			if src, err := ParseFile(fset, filename, nil, mode); err == nil {
   165				name := src.Name.Name
   166				pkg, found := pkgs[name]
   167				if !found {
   168					// TODO(gri) Use NewPackage here; reconsider ParseFiles API.
   169					pkg = &ast.Package{name, nil, nil, make(map[string]*ast.File)}
   170					pkgs[name] = pkg
   171				}
   172				pkg.Files[filename] = src
   173			} else if first == nil {
   174				first = err
   175			}
   176		}
   177		return
   178	}
   179	
   180	// ParseDir calls ParseFile for the files in the directory specified by path and
   181	// returns a map of package name -> package AST with all the packages found. If
   182	// filter != nil, only the files with os.FileInfo entries passing through the filter
   183	// are considered. The mode bits are passed to ParseFile unchanged. Position
   184	// information is recorded in the file set fset.
   185	//
   186	// If the directory couldn't be read, a nil map and the respective error are
   187	// returned. If a parse error occurred, a non-nil but incomplete map and the
   188	// error are returned.
   189	//
   190	func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, os.Error) {
   191		fd, err := os.Open(path)
   192		if err != nil {
   193			return nil, err
   194		}
   195		defer fd.Close()
   196	
   197		list, err := fd.Readdir(-1)
   198		if err != nil {
   199			return nil, err
   200		}
   201	
   202		filenames := make([]string, len(list))
   203		n := 0
   204		for i := 0; i < len(list); i++ {
   205			d := &list[i]
   206			if filter == nil || filter(d) {
   207				filenames[n] = filepath.Join(path, d.Name)
   208				n++
   209			}
   210		}
   211		filenames = filenames[0:n]
   212	
   213		return ParseFiles(fset, filenames, mode)
   214	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.