diff options
Diffstat (limited to 'src/pkg/go/parser/parser.go')
-rw-r--r-- | src/pkg/go/parser/parser.go | 1975 |
1 files changed, 1975 insertions, 0 deletions
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go new file mode 100644 index 000000000..056868695 --- /dev/null +++ b/src/pkg/go/parser/parser.go @@ -0,0 +1,1975 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// A parser for Go source text. The input is a stream of lexical tokens +// provided via the Scanner interface. The output is an abstract syntax +// tree (AST) representing the Go source. The parser is invoked by calling +// Parse. +// +package parser + +import ( + "container/vector"; + "fmt"; + "go/ast"; + "go/scanner"; + "go/token"; + "io"; + "os"; +) + + +// A parser error is represented by an Error node. The position Pos, if +// valid, points to the beginning of the offending token, and the error +// condition is described by Msg. +// +type Error struct { + Pos token.Position; + Msg string; +} + + +func (e *Error) String() string { + pos := ""; + if e.Pos.IsValid() { + pos = fmt.Sprintf("%d:%d: ", e.Pos.Line, e.Pos.Column); + } + return pos + e.Msg; +} + + +// Parser errors are returned as an ErrorList. +type ErrorList []*Error + + +// ErrorList implements the SortInterface. +func (p ErrorList) Len() int { return len(p); } +func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i]; } +func (p ErrorList) Less(i, j int) bool { return p[i].Pos.Offset < p[j].Pos.Offset; } + + +func (p ErrorList) String() string { + switch len(p) { + case 0: return "unspecified error"; + case 1: return p[0].String(); + } + return fmt.Sprintf("%s (and %d more errors)", p[0].String(), len(p) - 1); +} + + +type interval struct { + beg, end int; +} + + +// The parser structure holds the parser's internal state. +type parser struct { + errors vector.Vector; + scanner scanner.Scanner; + + // Tracing/debugging + mode uint; // parsing mode + trace bool; // == (mode & Trace != 0) + indent uint; // indentation used for tracing output + + // Comments + comments vector.Vector; // list of collected, unassociated comments + last_doc interval; // last comments interval of consecutive comments + + // The next token + pos token.Position; // token position + tok token.Token; // one token look-ahead + lit []byte; // token literal + + // Non-syntactic parser control + opt_semi bool; // true if semicolon separator is optional in statement list + expr_lev int; // < 0: in control clause, >= 0: in expression +}; + + +// noPos is used when there is no corresponding source position for a token +var noPos token.Position; + + +// ---------------------------------------------------------------------------- +// Parsing support + +func (p *parser) printTrace(a ...) { + const dots = + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "; + const n = uint(len(dots)); + fmt.Printf("%5d:%3d: ", p.pos.Line, p.pos.Column); + i := 2*p.indent; + for ; i > n; i -= n { + fmt.Print(dots); + } + fmt.Print(dots[0 : i]); + fmt.Println(a); +} + + +func trace(p *parser, msg string) *parser { + p.printTrace(msg, "("); + p.indent++; + return p; +} + + +func un/*trace*/(p *parser) { + p.indent--; + p.printTrace(")"); +} + + +func (p *parser) next0() { + // Because of one-token look-ahead, print the previous token + // when tracing as it provides a more readable output. The + // very first token (p.pos.Line == 0) is not initialized (it + // is token.ILLEGAL), so don't print it . + if p.trace && p.pos.Line > 0 { + s := p.tok.String(); + switch { + case p.tok.IsLiteral(): + p.printTrace(s, string(p.lit)); + case p.tok.IsOperator(), p.tok.IsKeyword(): + p.printTrace("\"" + s + "\""); + default: + p.printTrace(s); + } + } + + p.pos, p.tok, p.lit = p.scanner.Scan(); + p.opt_semi = false; +} + + +// Collect a comment in the parser's comment list and return the line +// on which the comment ends. +// +func (p *parser) collectComment() int { + // For /*-style comments, the comment may end on a different line. + // Scan the comment for '\n' chars and adjust the end line accordingly. + // (Note that the position of the next token may be even further down + // as there may be more whitespace lines after the comment.) + endline := p.pos.Line; + if p.lit[1] == '*' { + for _, b := range p.lit { + if b == '\n' { + endline++; + } + } + } + p.comments.Push(&ast.Comment{p.pos, p.lit, endline}); + p.next0(); + + return endline; +} + + +func (p *parser) getComments() interval { + // group adjacent comments, an empty line terminates a group + beg := p.comments.Len(); + endline := p.pos.Line; + for p.tok == token.COMMENT && endline+1 >= p.pos.Line { + endline = p.collectComment(); + } + end := p.comments.Len(); + return interval {beg, end}; +} + + +func (p *parser) getDoc() ast.Comments { + doc := p.last_doc; + n := doc.end - doc.beg; + + if n <= 0 || p.comments.At(doc.end - 1).(*ast.Comment).EndLine + 1 < p.pos.Line { + // no comments or empty line between last comment and current token; + // do not use as documentation + return nil; + } + + // found immediately adjacent comment interval; + // use as documentation + c := make(ast.Comments, n); + for i := 0; i < n; i++ { + c[i] = p.comments.At(doc.beg + i).(*ast.Comment); + } + + // remove comments from the general list + p.comments.Cut(doc.beg, doc.end); + + return c; +} + + +func (p *parser) next() { + p.next0(); + p.last_doc = interval{0, 0}; + for p.tok == token.COMMENT { + p.last_doc = p.getComments(); + } +} + + +// The parser implements scanner.Error. +func (p *parser) Error(pos token.Position, msg string) { + // Don't collect errors that are on the same line as the previous error + // in the hope to reduce the number of spurious errors due to incorrect + // parser synchronization. + if p.errors.Len() == 0 || p.errors.Last().(*Error).Pos.Line != pos.Line { + p.errors.Push(&Error{pos, msg}); + } +} + + +func (p *parser) error_expected(pos token.Position, msg string) { + msg = "expected " + msg; + if pos.Offset == p.pos.Offset { + // the error happened at the current position; + // make the error message more specific + msg += ", found '" + p.tok.String() + "'"; + if p.tok.IsLiteral() { + msg += " " + string(p.lit); + } + } + p.Error(pos, msg); +} + + +func (p *parser) expect(tok token.Token) token.Position { + pos := p.pos; + if p.tok != tok { + p.error_expected(pos, "'" + tok.String() + "'"); + } + p.next(); // make progress in any case + return pos; +} + + +// ---------------------------------------------------------------------------- +// Common productions + +func (p *parser) tryType() ast.Expr; +func (p *parser) parseStringList(x *ast.StringLit) []*ast.StringLit +func (p *parser) parseExpression() ast.Expr; +func (p *parser) parseStatement() ast.Stmt; +func (p *parser) parseDeclaration() ast.Decl; + + +func (p *parser) parseIdent() *ast.Ident { + if p.tok == token.IDENT { + x := &ast.Ident{p.pos, string(p.lit)}; + p.next(); + return x; + } + p.expect(token.IDENT); // use expect() error handling + return &ast.Ident{p.pos, ""}; +} + + +func (p *parser) parseIdentList(x ast.Expr) []*ast.Ident { + if p.trace { + defer un(trace(p, "IdentList")); + } + + list := vector.New(0); + if x == nil { + x = p.parseIdent(); + } + list.Push(x); + for p.tok == token.COMMA { + p.next(); + list.Push(p.parseIdent()); + } + + // convert vector + idents := make([]*ast.Ident, list.Len()); + for i := 0; i < list.Len(); i++ { + idents[i] = list.At(i).(*ast.Ident); + } + + return idents; +} + + +func (p *parser) parseExpressionList() []ast.Expr { + if p.trace { + defer un(trace(p, "ExpressionList")); + } + + list := vector.New(0); + list.Push(p.parseExpression()); + for p.tok == token.COMMA { + p.next(); + list.Push(p.parseExpression()); + } + + // convert list + exprs := make([]ast.Expr, list.Len()); + for i := 0; i < list.Len(); i++ { + exprs[i] = list.At(i).(ast.Expr); + } + + return exprs; +} + + +// ---------------------------------------------------------------------------- +// Types + +func (p *parser) parseType() ast.Expr { + if p.trace { + defer un(trace(p, "Type")); + } + + typ := p.tryType(); + + if typ == nil { + p.error_expected(p.pos, "type"); + p.next(); // make progress + return &ast.BadExpr{p.pos}; + } + + return typ; +} + + +func (p *parser) parseQualifiedIdent() ast.Expr { + if p.trace { + defer un(trace(p, "QualifiedIdent")); + } + + var x ast.Expr = p.parseIdent(); + if p.tok == token.PERIOD { + // first identifier is a package identifier + p.next(); + sel := p.parseIdent(); + x = &ast.SelectorExpr{x, sel}; + } + return x; +} + + +func (p *parser) parseTypeName() ast.Expr { + if p.trace { + defer un(trace(p, "TypeName")); + } + + return p.parseQualifiedIdent(); +} + + +func (p *parser) parseArrayType(ellipsis_ok bool) ast.Expr { + if p.trace { + defer un(trace(p, "ArrayType")); + } + + lbrack := p.expect(token.LBRACK); + var len ast.Expr; + if ellipsis_ok && p.tok == token.ELLIPSIS { + len = &ast.Ellipsis{p.pos}; + p.next(); + } else if p.tok != token.RBRACK { + len = p.parseExpression(); + } + p.expect(token.RBRACK); + elt := p.parseType(); + + return &ast.ArrayType{lbrack, len, elt}; +} + + +func (p *parser) makeIdentList(list *vector.Vector) []*ast.Ident { + idents := make([]*ast.Ident, list.Len()); + for i := 0; i < list.Len(); i++ { + ident, is_ident := list.At(i).(*ast.Ident); + if !is_ident { + pos := list.At(i).(ast.Expr).Pos(); + p.error_expected(pos, "identifier"); + idents[i] = &ast.Ident{pos, ""}; + } + idents[i] = ident; + } + return idents; +} + + +func (p *parser) parseFieldDecl() *ast.Field { + if p.trace { + defer un(trace(p, "FieldDecl")); + } + + doc := p.getDoc(); + + // a list of identifiers looks like a list of type names + list := vector.New(0); + for { + // TODO do not allow ()'s here + list.Push(p.parseType()); + if p.tok == token.COMMA { + p.next(); + } else { + break; + } + } + + // if we had a list of identifiers, it must be followed by a type + typ := p.tryType(); + + // optional tag + var tag []*ast.StringLit; + if p.tok == token.STRING { + tag = p.parseStringList(nil); + } + + // analyze case + var idents []*ast.Ident; + if typ != nil { + // IdentifierList Type + idents = p.makeIdentList(list); + } else { + // Type (anonymous field) + if list.Len() == 1 { + // TODO check that this looks like a type + typ = list.At(0).(ast.Expr); + } else { + p.error_expected(p.pos, "anonymous field"); + typ = &ast.BadExpr{p.pos}; + } + } + + return &ast.Field{doc, idents, typ, tag}; +} + + +func (p *parser) parseStructType() *ast.StructType { + if p.trace { + defer un(trace(p, "StructType")); + } + + pos := p.expect(token.STRUCT); + var lbrace, rbrace token.Position; + var fields []*ast.Field; + if p.tok == token.LBRACE { + lbrace = p.pos; + p.next(); + + list := vector.New(0); + for p.tok != token.RBRACE && p.tok != token.EOF { + list.Push(p.parseFieldDecl()); + if p.tok == token.SEMICOLON { + p.next(); + } else { + break; + } + } + if p.tok == token.SEMICOLON { + p.next(); + } + + rbrace = p.expect(token.RBRACE); + p.opt_semi = true; + + // convert vector + fields = make([]*ast.Field, list.Len()); + for i := list.Len() - 1; i >= 0; i-- { + fields[i] = list.At(i).(*ast.Field); + } + } + + return &ast.StructType{pos, lbrace, fields, rbrace}; +} + + +func (p *parser) parsePointerType() *ast.StarExpr { + if p.trace { + defer un(trace(p, "PointerType")); + } + + star := p.expect(token.MUL); + base := p.parseType(); + + return &ast.StarExpr{star, base}; +} + + +func (p *parser) tryParameterType(ellipsis_ok bool) ast.Expr { + if ellipsis_ok && p.tok == token.ELLIPSIS { + pos := p.pos; + p.next(); + if p.tok != token.RPAREN { + // "..." always must be at the very end of a parameter list + p.Error(pos, "expected type, found '...'"); + } + return &ast.Ellipsis{pos}; + } + return p.tryType(); +} + + +func (p *parser) parseParameterType(ellipsis_ok bool) ast.Expr { + typ := p.tryParameterType(ellipsis_ok); + if typ == nil { + p.error_expected(p.pos, "type"); + p.next(); // make progress + typ = &ast.BadExpr{p.pos}; + } + return typ; +} + + +func (p *parser) parseParameterDecl(ellipsis_ok bool) (*vector.Vector, ast.Expr) { + if p.trace { + defer un(trace(p, "ParameterDecl")); + } + + // a list of identifiers looks like a list of type names + list := vector.New(0); + for { + // TODO do not allow ()'s here + list.Push(p.parseParameterType(ellipsis_ok)); + if p.tok == token.COMMA { + p.next(); + } else { + break; + } + } + + // if we had a list of identifiers, it must be followed by a type + typ := p.tryParameterType(ellipsis_ok); + + return list, typ; +} + + +func (p *parser) parseParameterList(ellipsis_ok bool) []*ast.Field { + if p.trace { + defer un(trace(p, "ParameterList")); + } + + list, typ := p.parseParameterDecl(ellipsis_ok); + if typ != nil { + // IdentifierList Type + idents := p.makeIdentList(list); + list.Init(0); + list.Push(&ast.Field{nil, idents, typ, nil}); + + for p.tok == token.COMMA { + p.next(); + idents := p.parseIdentList(nil); + typ := p.parseParameterType(ellipsis_ok); + list.Push(&ast.Field{nil, idents, typ, nil}); + } + + } else { + // Type { "," Type } (anonymous parameters) + // convert list of types into list of *Param + for i := 0; i < list.Len(); i++ { + list.Set(i, &ast.Field{nil, nil, list.At(i).(ast.Expr), nil}); + } + } + + // convert list + params := make([]*ast.Field, list.Len()); + for i := 0; i < list.Len(); i++ { + params[i] = list.At(i).(*ast.Field); + } + + return params; +} + + +func (p *parser) parseParameters(ellipsis_ok bool) []*ast.Field { + if p.trace { + defer un(trace(p, "Parameters")); + } + + var params []*ast.Field; + p.expect(token.LPAREN); + if p.tok != token.RPAREN { + params = p.parseParameterList(ellipsis_ok); + } + p.expect(token.RPAREN); + + return params; +} + + +func (p *parser) parseResult() []*ast.Field { + if p.trace { + defer un(trace(p, "Result")); + } + + var results []*ast.Field; + if p.tok == token.LPAREN { + results = p.parseParameters(false); + } else if p.tok != token.FUNC { + typ := p.tryType(); + if typ != nil { + results = make([]*ast.Field, 1); + results[0] = &ast.Field{nil, nil, typ, nil}; + } + } + + return results; +} + + +func (p *parser) parseSignature() (params []*ast.Field, results []*ast.Field) { + if p.trace { + defer un(trace(p, "Signature")); + } + + params = p.parseParameters(true); + results = p.parseResult(); + + return params, results; +} + + +func (p *parser) parseFuncType() *ast.FuncType { + if p.trace { + defer un(trace(p, "FuncType")); + } + + pos := p.expect(token.FUNC); + params, results := p.parseSignature(); + + return &ast.FuncType{pos, params, results}; +} + + +func (p *parser) parseMethodSpec() *ast.Field { + if p.trace { + defer un(trace(p, "MethodSpec")); + } + + doc := p.getDoc(); + var idents []*ast.Ident; + var typ ast.Expr; + x := p.parseQualifiedIdent(); + if tmp, is_ident := x.(*ast.Ident); is_ident && (p.tok == token.COMMA || p.tok == token.LPAREN) { + // methods + idents = p.parseIdentList(x); + params, results := p.parseSignature(); + typ = &ast.FuncType{noPos, params, results}; + } else { + // embedded interface + typ = x; + } + + return &ast.Field{doc, idents, typ, nil}; +} + + +func (p *parser) parseInterfaceType() *ast.InterfaceType { + if p.trace { + defer un(trace(p, "InterfaceType")); + } + + pos := p.expect(token.INTERFACE); + var lbrace, rbrace token.Position; + var methods []*ast.Field; + if p.tok == token.LBRACE { + lbrace = p.pos; + p.next(); + + list := vector.New(0); + for p.tok == token.IDENT { + list.Push(p.parseMethodSpec()); + if p.tok != token.RBRACE { + p.expect(token.SEMICOLON); + } + } + + rbrace = p.expect(token.RBRACE); + p.opt_semi = true; + + // convert vector + methods = make([]*ast.Field, list.Len()); + for i := list.Len() - 1; i >= 0; i-- { + methods[i] = list.At(i).(*ast.Field); + } + } + + return &ast.InterfaceType{pos, lbrace, methods, rbrace}; +} + + +func (p *parser) parseMapType() *ast.MapType { + if p.trace { + defer un(trace(p, "MapType")); + } + + pos := p.expect(token.MAP); + p.expect(token.LBRACK); + key := p.parseType(); + p.expect(token.RBRACK); + value := p.parseType(); + + return &ast.MapType{pos, key, value}; +} + + +func (p *parser) parseChanType() *ast.ChanType { + if p.trace { + defer un(trace(p, "ChanType")); + } + + pos := p.pos; + dir := ast.SEND | ast.RECV; + if p.tok == token.CHAN { + p.next(); + if p.tok == token.ARROW { + p.next(); + dir = ast.SEND; + } + } else { + p.expect(token.ARROW); + p.expect(token.CHAN); + dir = ast.RECV; + } + value := p.parseType(); + + return &ast.ChanType{pos, dir, value}; +} + + +func (p *parser) tryRawType(ellipsis_ok bool) ast.Expr { + switch p.tok { + case token.IDENT: return p.parseTypeName(); + case token.LBRACK: return p.parseArrayType(ellipsis_ok); + case token.STRUCT: return p.parseStructType(); + case token.MUL: return p.parsePointerType(); + case token.FUNC: return p.parseFuncType(); + case token.INTERFACE: return p.parseInterfaceType(); + case token.MAP: return p.parseMapType(); + case token.CHAN, token.ARROW: return p.parseChanType(); + case token.LPAREN: + lparen := p.pos; + p.next(); + typ := p.parseType(); + rparen := p.expect(token.RPAREN); + return &ast.ParenExpr{lparen, typ, rparen}; + } + + // no type found + return nil; +} + + +func (p *parser) tryType() ast.Expr { + return p.tryRawType(false); +} + + +// ---------------------------------------------------------------------------- +// Blocks + +func makeStmtList(list *vector.Vector) []ast.Stmt { + stats := make([]ast.Stmt, list.Len()); + for i := 0; i < list.Len(); i++ { + stats[i] = list.At(i).(ast.Stmt); + } + return stats; +} + + +func (p *parser) parseStatementList() []ast.Stmt { + if p.trace { + defer un(trace(p, "StatementList")); + } + + list := vector.New(0); + expect_semi := false; + for p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE && p.tok != token.EOF { + if expect_semi { + p.expect(token.SEMICOLON); + expect_semi = false; + } + list.Push(p.parseStatement()); + if p.tok == token.SEMICOLON { + p.next(); + } else if p.opt_semi { + p.opt_semi = false; // "consume" optional semicolon + } else { + expect_semi = true; + } + } + + return makeStmtList(list); +} + + +func (p *parser) parseBlockStmt() *ast.BlockStmt { + if p.trace { + defer un(trace(p, "BlockStmt")); + } + + lbrace := p.expect(token.LBRACE); + list := p.parseStatementList(); + rbrace := p.expect(token.RBRACE); + p.opt_semi = true; + + return &ast.BlockStmt{lbrace, list, rbrace}; +} + + +// ---------------------------------------------------------------------------- +// Expressions + +func (p *parser) parseStringList(x *ast.StringLit) []*ast.StringLit { + if p.trace { + defer un(trace(p, "StringList")); + } + + list := vector.New(0); + if x != nil { + list.Push(x); + } + + for p.tok == token.STRING { + list.Push(&ast.StringLit{p.pos, p.lit}); + p.next(); + } + + // convert list + strings := make([]*ast.StringLit, list.Len()); + for i := 0; i < list.Len(); i++ { + strings[i] = list.At(i).(*ast.StringLit); + } + + return strings; +} + + +func (p *parser) parseFuncLit() ast.Expr { + if p.trace { + defer un(trace(p, "FuncLit")); + } + + typ := p.parseFuncType(); + p.expr_lev++; + body := p.parseBlockStmt(); + p.opt_semi = false; // function body requires separating ";" + p.expr_lev--; + + return &ast.FuncLit{typ, body}; +} + + +// parseOperand may return an expression or a raw type (incl. array +// types of the form [...]T. Callers must verify the result. +// +func (p *parser) parseOperand() ast.Expr { + if p.trace { + defer un(trace(p, "Operand")); + } + + switch p.tok { + case token.IDENT: + return p.parseIdent(); + + case token.INT: + x := &ast.IntLit{p.pos, p.lit}; + p.next(); + return x; + + case token.FLOAT: + x := &ast.FloatLit{p.pos, p.lit}; + p.next(); + return x; + + case token.CHAR: + x := &ast.CharLit{p.pos, p.lit}; + p.next(); + return x; + + case token.STRING: + x := &ast.StringLit{p.pos, p.lit}; + p.next(); + if p.tok == token.STRING { + return &ast.StringList{p.parseStringList(x)}; + } + return x; + + case token.LPAREN: + lparen := p.pos; + p.next(); + p.expr_lev++; + x := p.parseExpression(); + p.expr_lev--; + rparen := p.expect(token.RPAREN); + return &ast.ParenExpr{lparen, x, rparen}; + + case token.FUNC: + return p.parseFuncLit(); + + default: + t := p.tryRawType(true); // could be type for composite literal + if t != nil { + return t; + } + } + + p.error_expected(p.pos, "operand"); + p.next(); // make progress + return &ast.BadExpr{p.pos}; +} + + +func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr { + if p.trace { + defer un(trace(p, "SelectorOrTypeAssertion")); + } + + p.expect(token.PERIOD); + if p.tok == token.IDENT { + // selector + sel := p.parseIdent(); + return &ast.SelectorExpr{x, sel}; + } + + // type assertion + p.expect(token.LPAREN); + var typ ast.Expr; + if p.tok == token.TYPE { + // special case for type switch + typ = &ast.Ident{p.pos, "type"}; + p.next(); + } else { + typ = p.parseType(); + } + p.expect(token.RPAREN); + + return &ast.TypeAssertExpr{x, typ}; +} + + +func (p *parser) parseIndex(x ast.Expr) ast.Expr { + if p.trace { + defer un(trace(p, "Index")); + } + + p.expect(token.LBRACK); + p.expr_lev++; + begin := p.parseExpression(); + var end ast.Expr; + if p.tok == token.COLON { + p.next(); + end = p.parseExpression(); + } + p.expr_lev--; + p.expect(token.RBRACK); + + return &ast.IndexExpr{x, begin, end}; +} + + +func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { + if p.trace { + defer un(trace(p, "CallOrConversion")); + } + + lparen := p.expect(token.LPAREN); + var args []ast.Expr; + if p.tok != token.RPAREN { + args = p.parseExpressionList(); + } + rparen := p.expect(token.RPAREN); + + return &ast.CallExpr{fun, lparen, args, rparen}; +} + + +func (p *parser) parseElement() ast.Expr { + if p.trace { + defer un(trace(p, "Element")); + } + + x := p.parseExpression(); + if p.tok == token.COLON { + colon := p.pos; + p.next(); + x = &ast.KeyValueExpr{x, colon, p.parseExpression()}; + } + + return x; +} + + +func (p *parser) parseElementList() []ast.Expr { + if p.trace { + defer un(trace(p, "ElementList")); + } + + list := vector.New(0); + for p.tok != token.RBRACE && p.tok != token.EOF { + list.Push(p.parseElement()); + if p.tok == token.COMMA { + p.next(); + } else { + break; + } + } + + // convert list + elts := make([]ast.Expr, list.Len()); + for i := 0; i < list.Len(); i++ { + elts[i] = list.At(i).(ast.Expr); + } + + return elts; +} + + +func (p *parser) parseCompositeLit(typ ast.Expr) ast.Expr { + if p.trace { + defer un(trace(p, "CompositeLit")); + } + + lbrace := p.expect(token.LBRACE); + var elts []ast.Expr; + if p.tok != token.RBRACE { + elts = p.parseElementList(); + } + rbrace := p.expect(token.RBRACE); + return &ast.CompositeLit{typ, lbrace, elts, rbrace}; +} + + +// TODO Consider different approach to checking syntax after parsing: +// Provide a arguments (set of flags) to parsing functions +// restricting what they are syupposed to accept depending +// on context. + +// checkExpr checks that x is an expression (and not a type). +func (p *parser) checkExpr(x ast.Expr) ast.Expr { + // TODO should provide predicate in AST nodes + switch t := x.(type) { + case *ast.BadExpr: + case *ast.Ident: + case *ast.IntLit: + case *ast.FloatLit: + case *ast.CharLit: + case *ast.StringLit: + case *ast.StringList: + case *ast.FuncLit: + case *ast.CompositeLit: + case *ast.ParenExpr: + case *ast.SelectorExpr: + case *ast.IndexExpr: + case *ast.TypeAssertExpr: + case *ast.CallExpr: + case *ast.StarExpr: + case *ast.UnaryExpr: + if t.Op == token.RANGE { + // the range operator is only allowed at the top of a for statement + p.error_expected(x.Pos(), "expression"); + x = &ast.BadExpr{x.Pos()}; + } + case *ast.BinaryExpr: + default: + // all other nodes are not proper expressions + p.error_expected(x.Pos(), "expression"); + x = &ast.BadExpr{x.Pos()}; + } + return x; +} + + +// isTypeName returns true iff x is type name. +func isTypeName(x ast.Expr) bool { + // TODO should provide predicate in AST nodes + switch t := x.(type) { + case *ast.BadExpr: + case *ast.Ident: + case *ast.ParenExpr: return isTypeName(t.X); // TODO should (TypeName) be illegal? + case *ast.SelectorExpr: return isTypeName(t.X); + default: return false; // all other nodes are not type names + } + return true; +} + + +// isCompositeLitType returns true iff x is a legal composite literal type. +func isCompositeLitType(x ast.Expr) bool { + // TODO should provide predicate in AST nodes + switch t := x.(type) { + case *ast.BadExpr: + case *ast.Ident: + case *ast.ParenExpr: return isCompositeLitType(t.X); + case *ast.SelectorExpr: return isTypeName(t.X); + case *ast.ArrayType: + case *ast.StructType: + case *ast.MapType: + default: return false; // all other nodes are not legal composite literal types + } + return true; +} + + +// checkExprOrType checks that x is an expression or a type +// (and not a raw type such as [...]T). +// +func (p *parser) checkExprOrType(x ast.Expr) ast.Expr { + // TODO should provide predicate in AST nodes + switch t := x.(type) { + case *ast.UnaryExpr: + if t.Op == token.RANGE { + // the range operator is only allowed at the top of a for statement + p.error_expected(x.Pos(), "expression"); + x = &ast.BadExpr{x.Pos()}; + } + case *ast.ArrayType: + if len, is_ellipsis := t.Len.(*ast.Ellipsis); is_ellipsis { + p.Error(len.Pos(), "expected array length, found '...'"); + x = &ast.BadExpr{x.Pos()}; + } + } + + // all other nodes are expressions or types + return x; +} + + +func (p *parser) parsePrimaryExpr() ast.Expr { + if p.trace { + defer un(trace(p, "PrimaryExpr")); + } + + x := p.parseOperand(); +L: for { + switch p.tok { + case token.PERIOD: x = p.parseSelectorOrTypeAssertion(p.checkExpr(x)); + case token.LBRACK: x = p.parseIndex(p.checkExpr(x)); + case token.LPAREN: x = p.parseCallOrConversion(p.checkExprOrType(x)); + case token.LBRACE: + if isCompositeLitType(x) && (p.expr_lev >= 0 || !isTypeName(x)) { + x = p.parseCompositeLit(x); + } else { + break L; + } + default: + break L; + } + } + + return p.checkExprOrType(x); +} + + +func (p *parser) parseUnaryExpr() ast.Expr { + if p.trace { + defer un(trace(p, "UnaryExpr")); + } + + switch p.tok { + case token.ADD, token.SUB, token.NOT, token.XOR, token.ARROW, token.AND, token.RANGE: + pos, op := p.pos, p.tok; + p.next(); + x := p.parseUnaryExpr(); + return &ast.UnaryExpr{pos, op, p.checkExpr(x)}; + + case token.MUL: + // unary "*" expression or pointer type + pos := p.pos; + p.next(); + x := p.parseUnaryExpr(); + return &ast.StarExpr{pos, p.checkExprOrType(x)}; + } + + return p.parsePrimaryExpr(); +} + + +func (p *parser) parseBinaryExpr(prec1 int) ast.Expr { + if p.trace { + defer un(trace(p, "BinaryExpr")); + } + + x := p.parseUnaryExpr(); + for prec := p.tok.Precedence(); prec >= prec1; prec-- { + for p.tok.Precedence() == prec { + pos, op := p.pos, p.tok; + p.next(); + y := p.parseBinaryExpr(prec + 1); + x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)}; + } + } + + return x; +} + + +func (p *parser) parseExpression() ast.Expr { + if p.trace { + defer un(trace(p, "Expression")); + } + + return p.parseBinaryExpr(token.LowestPrec + 1); +} + + +// ---------------------------------------------------------------------------- +// Statements + + +func (p *parser) parseSimpleStmt(label_ok bool) ast.Stmt { + if p.trace { + defer un(trace(p, "SimpleStmt")); + } + + x := p.parseExpressionList(); + + switch p.tok { + case token.COLON: + // labeled statement + p.next(); + if label_ok && len(x) == 1 { + if label, is_ident := x[0].(*ast.Ident); is_ident { + return &ast.LabeledStmt{label, p.parseStatement()}; + } + } + p.Error(x[0].Pos(), "illegal label declaration"); + return &ast.BadStmt{x[0].Pos()}; + + case + token.DEFINE, token.ASSIGN, token.ADD_ASSIGN, + token.SUB_ASSIGN, token.MUL_ASSIGN, token.QUO_ASSIGN, + token.REM_ASSIGN, token.AND_ASSIGN, token.OR_ASSIGN, + token.XOR_ASSIGN, token.SHL_ASSIGN, token.SHR_ASSIGN, token.AND_NOT_ASSIGN: + // assignment statement + pos, tok := p.pos, p.tok; + p.next(); + y := p.parseExpressionList(); + if len(x) > 1 && len(y) > 1 && len(x) != len(y) { + p.Error(x[0].Pos(), "arity of lhs doesn't match rhs"); + } + return &ast.AssignStmt{x, pos, tok, y}; + } + + if len(x) > 1 { + p.Error(x[0].Pos(), "only one expression allowed"); + // continue with first expression + } + + if p.tok == token.INC || p.tok == token.DEC { + // increment or decrement + s := &ast.IncDecStmt{x[0], p.tok}; + p.next(); // consume "++" or "--" + return s; + } + + // expression + return &ast.ExprStmt{x[0]}; +} + + +func (p *parser) parseCallExpr() *ast.CallExpr { + x := p.parseExpression(); + if call, is_call := x.(*ast.CallExpr); is_call { + return call; + } + p.error_expected(x.Pos(), "function/method call"); + return nil; +} + + +func (p *parser) parseGoStmt() ast.Stmt { + if p.trace { + defer un(trace(p, "GoStmt")); + } + + pos := p.expect(token.GO); + call := p.parseCallExpr(); + if call != nil { + return &ast.GoStmt{pos, call}; + } + return &ast.BadStmt{pos}; +} + + +func (p *parser) parseDeferStmt() ast.Stmt { + if p.trace { + defer un(trace(p, "DeferStmt")); + } + + pos := p.expect(token.DEFER); + call := p.parseCallExpr(); + if call != nil { + return &ast.DeferStmt{pos, call}; + } + return &ast.BadStmt{pos}; +} + + +func (p *parser) parseReturnStmt() *ast.ReturnStmt { + if p.trace { + defer un(trace(p, "ReturnStmt")); + } + + pos := p.pos; + p.expect(token.RETURN); + var x []ast.Expr; + if p.tok != token.SEMICOLON && p.tok != token.RBRACE { + x = p.parseExpressionList(); + } + + return &ast.ReturnStmt{pos, x}; +} + + +func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt { + if p.trace { + defer un(trace(p, "BranchStmt")); + } + + s := &ast.BranchStmt{p.pos, tok, nil}; + p.expect(tok); + if tok != token.FALLTHROUGH && p.tok == token.IDENT { + s.Label = p.parseIdent(); + } + + return s; +} + + +func (p *parser) isExpr(s ast.Stmt) bool { + if s == nil { + return true; + } + dummy, is_expr := s.(*ast.ExprStmt); + return is_expr; +} + + +func (p *parser) makeExpr(s ast.Stmt) ast.Expr { + if s == nil { + return nil; + } + if es, is_expr := s.(*ast.ExprStmt); is_expr { + return p.checkExpr(es.X); + } + p.Error(s.Pos(), "expected condition, found simple statement"); + return &ast.BadExpr{s.Pos()}; +} + + +func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) { + if p.tok != token.LBRACE { + prev_lev := p.expr_lev; + p.expr_lev = -1; + + if p.tok != token.SEMICOLON { + s1 = p.parseSimpleStmt(false); + } + if p.tok == token.SEMICOLON { + p.next(); + if p.tok != token.LBRACE && p.tok != token.SEMICOLON { + s2 = p.parseSimpleStmt(false); + } + if isForStmt { + // for statements have a 3rd section + p.expect(token.SEMICOLON); + if p.tok != token.LBRACE { + s3 = p.parseSimpleStmt(false); + } + } + } else { + s1, s2 = nil, s1; + } + + p.expr_lev = prev_lev; + } + + return s1, s2, s3; +} + + +func (p *parser) parseIfStmt() *ast.IfStmt { + if p.trace { + defer un(trace(p, "IfStmt")); + } + + pos := p.expect(token.IF); + s1, s2, dummy := p.parseControlClause(false); + body := p.parseBlockStmt(); + var else_ ast.Stmt; + if p.tok == token.ELSE { + p.next(); + else_ = p.parseStatement(); + } + + return &ast.IfStmt{pos, s1, p.makeExpr(s2), body, else_}; +} + + +func (p *parser) parseCaseClause() *ast.CaseClause { + if p.trace { + defer un(trace(p, "CaseClause")); + } + + // SwitchCase + pos := p.pos; + var x []ast.Expr; + if p.tok == token.CASE { + p.next(); + x = p.parseExpressionList(); + } else { + p.expect(token.DEFAULT); + } + + colon := p.expect(token.COLON); + body := p.parseStatementList(); + + return &ast.CaseClause{pos, x, colon, body}; +} + + +func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause { + if p.trace { + defer un(trace(p, "CaseClause")); + } + + // TypeSwitchCase + pos := p.pos; + var typ ast.Expr; + if p.tok == token.CASE { + p.next(); + typ = p.parseType(); + } else { + p.expect(token.DEFAULT); + } + + colon := p.expect(token.COLON); + body := p.parseStatementList(); + + return &ast.TypeCaseClause{pos, typ, colon, body}; +} + + +func (p *parser) parseSwitchStmt() ast.Stmt { + if p.trace { + defer un(trace(p, "SwitchStmt")); + } + + pos := p.expect(token.SWITCH); + s1, s2, dummy := p.parseControlClause(false); + + if p.isExpr(s2) { + // expression switch + lbrace := p.expect(token.LBRACE); + cases := vector.New(0); + for p.tok == token.CASE || p.tok == token.DEFAULT { + cases.Push(p.parseCaseClause()); + } + rbrace := p.expect(token.RBRACE); + p.opt_semi = true; + body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace}; + return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body}; + } + + // type switch + // TODO do all the checks! + lbrace := p.expect(token.LBRACE); + cases := vector.New(0); + for p.tok == token.CASE || p.tok == token.DEFAULT { + cases.Push(p.parseTypeCaseClause()); + } + rbrace := p.expect(token.RBRACE); + p.opt_semi = true; + body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace}; + return &ast.TypeSwitchStmt{pos, s1, s2, body}; +} + + +func (p *parser) parseCommClause() *ast.CommClause { + if p.trace { + defer un(trace(p, "CommClause")); + } + + // CommCase + pos := p.pos; + var tok token.Token; + var lhs, rhs ast.Expr; + if p.tok == token.CASE { + p.next(); + if p.tok == token.ARROW { + // RecvExpr without assignment + rhs = p.parseExpression(); + } else { + // SendExpr or RecvExpr + rhs = p.parseExpression(); + if p.tok == token.ASSIGN || p.tok == token.DEFINE { + // RecvExpr with assignment + tok = p.tok; + p.next(); + lhs = rhs; + if p.tok == token.ARROW { + rhs = p.parseExpression(); + } else { + p.expect(token.ARROW); // use expect() error handling + } + } + // else SendExpr + } + } else { + p.expect(token.DEFAULT); + } + + colon := p.expect(token.COLON); + body := p.parseStatementList(); + + return &ast.CommClause{pos, tok, lhs, rhs, colon, body}; +} + + +func (p *parser) parseSelectStmt() *ast.SelectStmt { + if p.trace { + defer un(trace(p, "SelectStmt")); + } + + pos := p.expect(token.SELECT); + lbrace := p.expect(token.LBRACE); + cases := vector.New(0); + for p.tok == token.CASE || p.tok == token.DEFAULT { + cases.Push(p.parseCommClause()); + } + rbrace := p.expect(token.RBRACE); + p.opt_semi = true; + body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace}; + + return &ast.SelectStmt{pos, body}; +} + + +func (p *parser) parseForStmt() ast.Stmt { + if p.trace { + defer un(trace(p, "ForStmt")); + } + + pos := p.expect(token.FOR); + s1, s2, s3 := p.parseControlClause(true); + body := p.parseBlockStmt(); + + if as, is_as := s2.(*ast.AssignStmt); is_as { + // possibly a for statement with a range clause; check assignment operator + if as.Tok != token.ASSIGN && as.Tok != token.DEFINE { + p.error_expected(as.TokPos, "'=' or ':='"); + return &ast.BadStmt{pos}; + } + // check lhs + var key, value ast.Expr; + switch len(as.Lhs) { + case 2: + value = as.Lhs[1]; + fallthrough; + case 1: + key = as.Lhs[0]; + default: + p.error_expected(as.Lhs[0].Pos(), "1 or 2 expressions"); + return &ast.BadStmt{pos}; + } + // check rhs + if len(as.Rhs) != 1 { + p.error_expected(as.Rhs[0].Pos(), "1 expressions"); + return &ast.BadStmt{pos}; + } + if rhs, is_unary := as.Rhs[0].(*ast.UnaryExpr); is_unary && rhs.Op == token.RANGE { + // rhs is range expression; check lhs + return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body} + } else { + p.error_expected(s2.Pos(), "range clause"); + return &ast.BadStmt{pos}; + } + } else { + // regular for statement + return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}; + } + + panic(); // unreachable + return nil; +} + + +func (p *parser) parseStatement() ast.Stmt { + if p.trace { + defer un(trace(p, "Statement")); + } + + switch p.tok { + case token.CONST, token.TYPE, token.VAR: + return &ast.DeclStmt{p.parseDeclaration()}; + case + // tokens that may start a top-level expression + token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand + token.LBRACK, token.STRUCT, // composite type + token.MUL, token.AND, token.ARROW: // unary operators + return p.parseSimpleStmt(true); + case token.GO: + return p.parseGoStmt(); + case token.DEFER: + return p.parseDeferStmt(); + case token.RETURN: + return p.parseReturnStmt(); + case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH: + return p.parseBranchStmt(p.tok); + case token.LBRACE: + return p.parseBlockStmt(); + case token.IF: + return p.parseIfStmt(); + case token.SWITCH: + return p.parseSwitchStmt(); + case token.SELECT: + return p.parseSelectStmt(); + case token.FOR: + return p.parseForStmt(); + case token.SEMICOLON, token.RBRACE: + // don't consume the ";", it is the separator following the empty statement + return &ast.EmptyStmt{p.pos}; + } + + // no statement found + p.error_expected(p.pos, "statement"); + p.next(); // make progress + return &ast.BadStmt{p.pos}; +} + + +// ---------------------------------------------------------------------------- +// Declarations + +type parseSpecFunction func(p *parser, doc ast.Comments) ast.Spec + +func parseImportSpec(p *parser, doc ast.Comments) ast.Spec { + if p.trace { + defer un(trace(p, "ImportSpec")); + } + + var ident *ast.Ident; + if p.tok == token.PERIOD { + ident = &ast.Ident{p.pos, "."}; + p.next(); + } else if p.tok == token.IDENT { + ident = p.parseIdent(); + } + + var path []*ast.StringLit; + if p.tok == token.STRING { + path = p.parseStringList(nil); + } else { + p.expect(token.STRING); // use expect() error handling + } + + return &ast.ImportSpec{doc, ident, path}; +} + + +func parseConstSpec(p *parser, doc ast.Comments) ast.Spec { + if p.trace { + defer un(trace(p, "ConstSpec")); + } + + idents := p.parseIdentList(nil); + typ := p.tryType(); + var values []ast.Expr; + if typ != nil || p.tok == token.ASSIGN { + p.expect(token.ASSIGN); + values = p.parseExpressionList(); + } + + return &ast.ValueSpec{doc, idents, typ, values}; +} + + +func parseTypeSpec(p *parser, doc ast.Comments) ast.Spec { + if p.trace { + defer un(trace(p, "TypeSpec")); + } + + ident := p.parseIdent(); + typ := p.parseType(); + + return &ast.TypeSpec{doc, ident, typ}; +} + + +func parseVarSpec(p *parser, doc ast.Comments) ast.Spec { + if p.trace { + defer un(trace(p, "VarSpec")); + } + + idents := p.parseIdentList(nil); + typ := p.tryType(); + var values []ast.Expr; + if typ == nil || p.tok == token.ASSIGN { + p.expect(token.ASSIGN); + values = p.parseExpressionList(); + } + + return &ast.ValueSpec{doc, idents, typ, values}; +} + + +func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl { + if p.trace { + defer un(trace(p, keyword.String() + "Decl")); + } + + doc := p.getDoc(); + pos := p.expect(keyword); + var lparen, rparen token.Position; + list := vector.New(0); + if p.tok == token.LPAREN { + lparen = p.pos; + p.next(); + for p.tok != token.RPAREN && p.tok != token.EOF { + doc := p.getDoc(); + list.Push(f(p, doc)); + if p.tok == token.SEMICOLON { + p.next(); + } else { + break; + } + } + rparen = p.expect(token.RPAREN); + p.opt_semi = true; + } else { + list.Push(f(p, doc)); + } + + // convert vector + specs := make([]ast.Spec, list.Len()); + for i := 0; i < list.Len(); i++ { + specs[i] = list.At(i); + } + return &ast.GenDecl{doc, pos, keyword, lparen, specs, rparen}; +} + + +func (p *parser) parseReceiver() *ast.Field { + if p.trace { + defer un(trace(p, "Receiver")); + } + + pos := p.pos; + par := p.parseParameters(false); + + // must have exactly one receiver + if len(par) != 1 || len(par) == 1 && len(par[0].Names) > 1 { + p.error_expected(pos, "exactly one receiver"); + return &ast.Field{nil, nil, &ast.BadExpr{noPos}, nil}; + } + + recv := par[0]; + + // recv type must be TypeName or *TypeName + base := recv.Type; + if ptr, is_ptr := base.(*ast.StarExpr); is_ptr { + base = ptr.X; + } + if !isTypeName(base) { + p.error_expected(base.Pos(), "type name"); + } + + return recv; +} + + +func (p *parser) parseFunctionDecl() *ast.FuncDecl { + if p.trace { + defer un(trace(p, "FunctionDecl")); + } + + doc := p.getDoc(); + pos := p.expect(token.FUNC); + + var recv *ast.Field; + if p.tok == token.LPAREN { + recv = p.parseReceiver(); + } + + ident := p.parseIdent(); + params, results := p.parseSignature(); + + var body *ast.BlockStmt; + if p.tok == token.LBRACE { + body = p.parseBlockStmt(); + } + + return &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body}; +} + + +func (p *parser) parseDeclaration() ast.Decl { + if p.trace { + defer un(trace(p, "Declaration")); + } + + var f parseSpecFunction; + switch p.tok { + case token.CONST: f = parseConstSpec; + case token.TYPE: f = parseTypeSpec; + case token.VAR: f = parseVarSpec; + case token.FUNC: + return p.parseFunctionDecl(); + default: + pos := p.pos; + p.error_expected(pos, "declaration"); + p.next(); // make progress + return &ast.BadDecl{pos}; + } + + return p.parseGenDecl(p.tok, f); +} + + +// ---------------------------------------------------------------------------- +// Packages + +// The mode parameter to the Parse function is a set of flags (or 0). +// They control the amount of source code parsed and other optional +// parser functionality. +// +const ( + PackageClauseOnly uint = 1 << iota; // parsing stops after package clause + ImportsOnly; // parsing stops after import declarations + ParseComments; // parse comments and add them to AST + Trace; // print a trace of parsed productions +) + + +func (p *parser) parsePackage() *ast.Program { + if p.trace { + defer un(trace(p, "Program")); + } + + // package clause + comment := p.getDoc(); + pos := p.expect(token.PACKAGE); + ident := p.parseIdent(); + var decls []ast.Decl; + + // Don't bother parsing the rest if we had errors already. + // Likely not a Go source file at all. + + if p.errors.Len() == 0 && p.mode & PackageClauseOnly == 0 { + // import decls + list := vector.New(0); + for p.tok == token.IMPORT { + list.Push(p.parseGenDecl(token.IMPORT, parseImportSpec)); + if p.tok == token.SEMICOLON { + p.next(); + } + } + + if p.mode & ImportsOnly == 0 { + // rest of package body + for p.tok != token.EOF { + list.Push(p.parseDeclaration()); + if p.tok == token.SEMICOLON { + p.next(); + } + } + } + + // convert declaration list + decls = make([]ast.Decl, list.Len()); + for i := 0; i < list.Len(); i++ { + decls[i] = list.At(i).(ast.Decl); + } + } + + // convert comments list + comments := make([]*ast.Comment, p.comments.Len()); + for i := 0; i < p.comments.Len(); i++ { + comments[i] = p.comments.At(i).(*ast.Comment); + } + + return &ast.Program{comment, pos, ident, decls, comments}; +} + + +// ---------------------------------------------------------------------------- +// Parsing of entire programs. + +func readSource(src interface{}) ([]byte, os.Error) { + if src != nil { + switch s := src.(type) { + case string: + return io.StringBytes(s), nil; + case []byte: + return s, nil; + case *io.ByteBuffer: + // is io.Read, but src is already available in []byte form + if s != nil { + return s.Data(), nil; + } + case io.Reader: + var buf io.ByteBuffer; + n, err := io.Copy(s, &buf); + if err != nil { + return nil, err; + } + return buf.Data(), nil; + } + } + return nil, os.ErrorString("invalid source"); +} + + +// scannerMode returns the scanner mode bits given the parser's mode bits. +func scannerMode(mode uint) uint { + if mode & ParseComments != 0 { + return scanner.ScanComments; + } + return 0; +} + + +// Parse parses a Go program. +// +// The program source src may be provided in a variety of formats. At the +// moment the following types are supported: string, []byte, and io.Read. +// The mode parameter controls the amount of source text parsed and other +// optional parser functionality. +// +// Parse returns a complete AST if no error occured. Otherwise, if the +// source couldn't be read, the returned program is nil and the error +// indicates the specific failure. If the source was read but syntax +// errors were found, the result is a partial AST (with ast.BadX nodes +// representing the fragments of erroneous source code) and an ErrorList +// describing the syntax errors. +// +func Parse(src interface{}, mode uint) (*ast.Program, os.Error) { + data, err := readSource(src); + if err != nil { + return nil, err; + } + + // initialize parser state + var p parser; + p.errors.Init(0); + p.scanner.Init(data, &p, scannerMode(mode)); + p.mode = mode; + p.trace = mode & Trace != 0; // for convenience (p.trace is used frequently) + p.comments.Init(0); + p.next(); + + // parse program + prog := p.parsePackage(); + + // convert errors list, if any + if p.errors.Len() > 0 { + errors := make(ErrorList, p.errors.Len()); + for i := 0; i < p.errors.Len(); i++ { + errors[i] = p.errors.At(i).(*Error); + } + return prog, errors; + } + + return prog, nil; +} |