summaryrefslogtreecommitdiff
path: root/src/lib/go/parser/parser.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/go/parser/parser.go')
-rw-r--r--src/lib/go/parser/parser.go1975
1 files changed, 0 insertions, 1975 deletions
diff --git a/src/lib/go/parser/parser.go b/src/lib/go/parser/parser.go
deleted file mode 100644
index 056868695..000000000
--- a/src/lib/go/parser/parser.go
+++ /dev/null
@@ -1,1975 +0,0 @@
-// 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;
-}