2008-09-18 17:58:37 -06:00
|
|
|
// 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.
|
|
|
|
|
2009-03-10 17:31:19 -06:00
|
|
|
// 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.
|
|
|
|
//
|
2009-03-26 17:10:07 -06:00
|
|
|
package parser
|
2008-09-18 17:58:37 -06:00
|
|
|
|
2009-01-09 17:28:09 -07:00
|
|
|
import (
|
2009-01-23 14:50:14 -07:00
|
|
|
"fmt";
|
2009-02-13 16:07:56 -07:00
|
|
|
"vector";
|
2009-03-03 19:25:07 -07:00
|
|
|
"token";
|
2009-03-05 18:15:36 -07:00
|
|
|
"ast";
|
2009-01-09 17:28:09 -07:00
|
|
|
)
|
2008-09-22 19:26:12 -06:00
|
|
|
|
2008-09-18 17:58:37 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
type interval struct {
|
|
|
|
beg, end int;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
// An implementation of a Scanner must be provided to the Parser.
|
|
|
|
// The parser calls Scan() repeatedly until token.EOF is returned.
|
|
|
|
// Scan must return the current token position pos, the token value
|
|
|
|
// tok, and the corresponding token literal string lit if the token
|
|
|
|
// is a literal (i.e., if tok.IsLiteral() is true).
|
|
|
|
//
|
|
|
|
type Scanner interface {
|
|
|
|
Scan() (pos token.Position, tok token.Token, lit []byte);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// An implementation of an ErrorHandler must be provided to the parser.
|
|
|
|
// If a syntax error is encountered, Error is called with a position and
|
|
|
|
// an error message. The position points to the beginning of the offending
|
|
|
|
// token.
|
2009-03-10 17:31:19 -06:00
|
|
|
//
|
2009-03-26 17:10:07 -06:00
|
|
|
type ErrorHandler interface {
|
|
|
|
Error(pos token.Position, msg string);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// The following flags control optional parser functionality. A set of
|
|
|
|
// flags (or 0) must be provided as a parameter to the Parse function.
|
|
|
|
//
|
|
|
|
const (
|
|
|
|
Trace = 1 << iota;
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// The parser structure holds the parser's internal state.
|
|
|
|
type parser struct {
|
|
|
|
scanner Scanner;
|
|
|
|
err ErrorHandler;
|
2009-03-02 21:27:09 -07:00
|
|
|
|
2008-10-18 17:42:25 -06:00
|
|
|
// Tracing/debugging
|
2009-03-05 18:15:36 -07:00
|
|
|
trace bool;
|
2008-09-18 17:58:37 -06:00
|
|
|
indent uint;
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
comments vector.Vector; // list of collected, unassociated comments
|
|
|
|
last_doc interval; // last comments interval of consecutive comments
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-03 19:25:07 -07:00
|
|
|
// The next token
|
2009-03-26 17:10:07 -06:00
|
|
|
pos token.Position; // token location
|
2009-03-26 11:53:14 -06:00
|
|
|
tok token.Token; // one token look-ahead
|
2009-03-26 17:10:07 -06:00
|
|
|
lit []byte; // token literal
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2008-10-10 17:03:32 -06:00
|
|
|
// Non-syntactic parser control
|
2009-02-27 16:40:17 -07:00
|
|
|
opt_semi bool; // true if semicolon separator is optional in statement list
|
2009-03-03 17:00:06 -07:00
|
|
|
expr_lev int; // < 0: in control clause, >= 0: in expression
|
2008-09-18 17:58:37 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
// When we don't have a location use nopos.
|
2009-03-11 13:52:11 -06:00
|
|
|
// TODO make sure we always have a location.
|
2009-03-26 17:10:07 -06:00
|
|
|
var nopos token.Position;
|
2009-03-11 13:52:11 -06:00
|
|
|
|
|
|
|
|
2008-09-18 17:58:37 -06:00
|
|
|
// ----------------------------------------------------------------------------
|
2009-03-05 18:15:36 -07:00
|
|
|
// Helper functions
|
2009-01-08 13:04:00 -07:00
|
|
|
|
|
|
|
func unreachable() {
|
|
|
|
panic("unreachable");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Parsing support
|
2008-09-18 17:58:37 -06:00
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) printIndent() {
|
2009-02-05 15:22:09 -07:00
|
|
|
i := P.indent;
|
2009-02-06 12:10:25 -07:00
|
|
|
// reduce printing time by a factor of 2 or more
|
2009-02-05 15:22:09 -07:00
|
|
|
for ; i > 10; i -= 10 {
|
|
|
|
fmt.Printf(". . . . . . . . . . ");
|
|
|
|
}
|
|
|
|
for ; i > 0; i-- {
|
2009-02-03 18:44:01 -07:00
|
|
|
fmt.Printf(". ");
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func trace(P *parser, msg string) *parser {
|
2009-02-05 15:22:09 -07:00
|
|
|
P.printIndent();
|
|
|
|
fmt.Printf("%s (\n", msg);
|
2009-02-03 18:44:01 -07:00
|
|
|
P.indent++;
|
2009-02-05 15:22:09 -07:00
|
|
|
return P;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func un/*trace*/(P *parser) {
|
2009-02-03 18:44:01 -07:00
|
|
|
P.indent--;
|
2009-02-05 15:22:09 -07:00
|
|
|
P.printIndent();
|
|
|
|
fmt.Printf(")\n");
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) next0() {
|
|
|
|
P.pos, P.tok, P.lit = P.scanner.Scan();
|
2008-10-10 17:03:32 -06:00
|
|
|
P.opt_semi = false;
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
P.printIndent();
|
|
|
|
switch P.tok {
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING:
|
2009-03-26 17:10:07 -06:00
|
|
|
fmt.Printf("%d:%d: %s = %s\n", P.pos.Line, P.pos.Column, P.tok.String(), P.lit);
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.LPAREN:
|
2009-02-05 15:22:09 -07:00
|
|
|
// don't print '(' - screws up selection in terminal window
|
2009-03-26 17:10:07 -06:00
|
|
|
fmt.Printf("%d:%d: LPAREN\n", P.pos.Line, P.pos.Column);
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.RPAREN:
|
2009-02-05 15:22:09 -07:00
|
|
|
// don't print ')' - screws up selection in terminal window
|
2009-03-26 17:10:07 -06:00
|
|
|
fmt.Printf("%d:%d: RPAREN\n", P.pos.Line, P.pos.Column);
|
2009-02-05 15:22:09 -07:00
|
|
|
default:
|
2009-03-26 17:10:07 -06:00
|
|
|
fmt.Printf("%d:%d: %s\n", P.pos.Line, P.pos.Column, P.tok.String());
|
2009-01-23 10:44:01 -07:00
|
|
|
}
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
// Collect a comment in the parser's comment list and return the line
|
|
|
|
// on which the comment ends.
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) collectComment() int {
|
2009-03-20 18:18:48 -06:00
|
|
|
// 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;
|
2009-03-26 17:10:07 -06:00
|
|
|
if P.lit[1] == '*' {
|
|
|
|
for i, b := range P.lit {
|
2009-03-12 18:24:03 -06:00
|
|
|
if b == '\n' {
|
|
|
|
endline++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-03-26 17:10:07 -06:00
|
|
|
P.comments.Push(&ast.Comment{P.pos, P.lit, endline});
|
2009-03-20 18:18:48 -06:00
|
|
|
P.next0();
|
2009-03-12 18:24:03 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return endline;
|
2009-03-12 18:24:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) getComments() interval {
|
2009-03-20 18:18:48 -06:00
|
|
|
// 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();
|
2009-03-12 18:24:03 -06:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
end := P.comments.Len();
|
|
|
|
return interval {beg, end};
|
2009-03-12 18:24:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) next() {
|
2009-03-12 18:24:03 -06:00
|
|
|
P.next0();
|
2009-03-20 18:18:48 -06:00
|
|
|
P.last_doc = interval{0, 0};
|
2009-03-12 18:24:03 -06:00
|
|
|
for P.tok == token.COMMENT {
|
2009-03-20 18:18:48 -06:00
|
|
|
P.last_doc = P.getComments();
|
2008-10-17 00:30:42 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) error(pos token.Position, msg string) {
|
2009-03-20 18:18:48 -06:00
|
|
|
P.err.Error(pos, msg);
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) expect(tok token.Token) token.Position {
|
2008-09-18 17:58:37 -06:00
|
|
|
if P.tok != tok {
|
2009-03-26 11:53:14 -06:00
|
|
|
msg := "expected '" + tok.String() + "', found '" + P.tok.String() + "'";
|
|
|
|
if P.tok.IsLiteral() {
|
2009-03-26 17:10:07 -06:00
|
|
|
msg += " " + string(P.lit);
|
2008-10-18 17:42:25 -06:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
P.error(P.pos, msg);
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
loc := P.pos;
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next(); // make progress in any case
|
2009-03-17 19:41:35 -06:00
|
|
|
return loc;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) getDoc() ast.Comments {
|
2009-03-20 18:18:48 -06:00
|
|
|
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);
|
|
|
|
// TODO find a better way to do this
|
|
|
|
P.comments.Set(doc.beg + i, nil); // remove the comment from the general list
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-18 17:58:37 -06:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Common productions
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) tryType() ast.Expr;
|
|
|
|
func (P *parser) parseExpression(prec int) ast.Expr;
|
|
|
|
func (P *parser) parseStatement() ast.Stmt;
|
|
|
|
func (P *parser) parseDeclaration() ast.Decl;
|
2008-09-18 17:58:37 -06:00
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseIdent() *ast.Ident {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Ident"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2009-01-20 15:40:40 -07:00
|
|
|
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.IDENT {
|
2009-03-26 17:10:07 -06:00
|
|
|
x := &ast.Ident{P.pos, P.lit};
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-02-03 18:44:01 -07:00
|
|
|
return x;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-03 19:25:07 -07:00
|
|
|
P.expect(token.IDENT); // use expect() error handling
|
2009-03-20 18:18:48 -06:00
|
|
|
|
|
|
|
return &ast.Ident{P.pos, [0]byte{}};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseIdentList(x ast.Expr) []*ast.Ident {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "IdentList"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-09-18 17:58:37 -06:00
|
|
|
|
2009-03-16 21:29:31 -06:00
|
|
|
list := vector.New(0);
|
2009-02-19 17:47:58 -07:00
|
|
|
if x == nil {
|
2009-03-05 18:15:36 -07:00
|
|
|
x = P.parseIdent();
|
2009-02-19 17:47:58 -07:00
|
|
|
}
|
2009-03-16 21:29:31 -06:00
|
|
|
list.Push(x);
|
2009-03-03 19:25:07 -07:00
|
|
|
for P.tok == token.COMMA {
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-03-16 21:29:31 -06:00
|
|
|
list.Push(P.parseIdent());
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
2009-03-16 21:29:31 -06:00
|
|
|
// convert vector
|
|
|
|
idents := make([]*ast.Ident, list.Len());
|
|
|
|
for i := 0; i < list.Len(); i++ {
|
|
|
|
idents[i] = list.At(i).(*ast.Ident);
|
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
|
2009-03-16 21:29:31 -06:00
|
|
|
return idents;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseExpressionList() []ast.Expr {
|
2009-02-27 16:40:17 -07:00
|
|
|
if P.trace {
|
2009-03-16 21:29:31 -06:00
|
|
|
defer un(trace(P, "ExpressionList"));
|
2009-02-27 16:40:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
list := vector.New(0);
|
2009-03-17 19:41:35 -06:00
|
|
|
list.Push(P.parseExpression(1));
|
2009-03-03 19:25:07 -07:00
|
|
|
for P.tok == token.COMMA {
|
2009-02-27 16:40:17 -07:00
|
|
|
P.next();
|
2009-03-17 19:41:35 -06:00
|
|
|
list.Push(P.parseExpression(1));
|
2009-02-27 16:40:17 -07:00
|
|
|
}
|
|
|
|
|
2009-03-17 19:41:35 -06:00
|
|
|
// convert list
|
2009-03-16 21:29:31 -06:00
|
|
|
exprs := make([]ast.Expr, list.Len());
|
2009-02-27 16:40:17 -07:00
|
|
|
for i := 0; i < list.Len(); i++ {
|
2009-03-16 21:29:31 -06:00
|
|
|
exprs[i] = list.At(i).(ast.Expr);
|
2009-02-27 16:40:17 -07:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
|
2009-03-16 21:29:31 -06:00
|
|
|
return exprs;
|
2009-02-27 16:40:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-18 17:58:37 -06:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Types
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseType() ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Type"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
typ := P.tryType();
|
|
|
|
if typ == nil {
|
|
|
|
P.error(P.pos, "type expected");
|
|
|
|
typ = &ast.BadExpr{P.pos};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return typ;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseVarType() ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "VarType"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-02-05 15:22:09 -07:00
|
|
|
return P.parseType();
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseQualifiedIdent() ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "QualifiedIdent"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-10-14 19:14:01 -06:00
|
|
|
|
2009-03-05 18:15:36 -07:00
|
|
|
var x ast.Expr = P.parseIdent();
|
2009-03-03 19:25:07 -07:00
|
|
|
for P.tok == token.PERIOD {
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-03-17 19:41:35 -06:00
|
|
|
sel := P.parseIdent();
|
2009-03-20 18:18:48 -06:00
|
|
|
x = &ast.SelectorExpr{x, sel};
|
2008-10-14 19:14:01 -06:00
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseTypeName() ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "TypeName"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
return P.parseQualifiedIdent();
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseArrayType() *ast.ArrayType {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "ArrayType"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
lbrack := P.expect(token.LBRACK);
|
2009-03-05 18:15:36 -07:00
|
|
|
var len ast.Expr;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.ELLIPSIS {
|
2009-03-20 18:18:48 -06:00
|
|
|
len = &ast.Ellipsis{P.pos};
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-03-03 19:25:07 -07:00
|
|
|
} else if P.tok != token.RBRACK {
|
2009-02-27 16:40:17 -07:00
|
|
|
len = P.parseExpression(1);
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-03 19:25:07 -07:00
|
|
|
P.expect(token.RBRACK);
|
2009-02-27 16:40:17 -07:00
|
|
|
elt := P.parseType();
|
2008-09-18 17:58:37 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.ArrayType{lbrack, len, elt};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseChannelType() *ast.ChannelType {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "ChannelType"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
pos := P.pos;
|
|
|
|
dir := ast.SEND | ast.RECV;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.CHAN {
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.ARROW {
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-03-20 18:18:48 -06:00
|
|
|
dir = ast.SEND;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
} else {
|
2009-03-03 19:25:07 -07:00
|
|
|
P.expect(token.ARROW);
|
|
|
|
P.expect(token.CHAN);
|
2009-03-20 18:18:48 -06:00
|
|
|
dir = ast.RECV;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
value := P.parseVarType();
|
2008-09-18 17:58:37 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.ChannelType{pos, dir, value};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) tryParameterType() ast.Expr {
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.ELLIPSIS {
|
2009-03-20 18:18:48 -06:00
|
|
|
loc := P.pos;
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-03-11 13:52:11 -06:00
|
|
|
return &ast.Ellipsis{loc};
|
2008-10-18 17:42:25 -06:00
|
|
|
}
|
2009-02-27 16:40:17 -07:00
|
|
|
return P.tryType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseParameterType() ast.Expr {
|
2009-02-27 16:40:17 -07:00
|
|
|
typ := P.tryParameterType();
|
|
|
|
if typ == nil {
|
2009-03-20 18:18:48 -06:00
|
|
|
P.error(P.pos, "type expected");
|
|
|
|
typ = &ast.BadExpr{P.pos};
|
2009-02-27 16:40:17 -07:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
return typ;
|
2008-10-18 17:42:25 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseParameterDecl(ellipsis_ok bool) (*vector.Vector, ast.Expr) {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-02-27 16:40:17 -07:00
|
|
|
defer un(trace(P, "ParameterDecl"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-10-01 15:31:44 -06:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
// a list of identifiers looks like a list of type names
|
|
|
|
list := vector.New(0);
|
2008-10-24 15:04:54 -06:00
|
|
|
for {
|
2009-02-27 16:40:17 -07:00
|
|
|
// TODO do not allow ()'s here
|
|
|
|
list.Push(P.parseParameterType());
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.COMMA {
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2008-10-24 15:04:54 -06:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
2008-10-01 15:31:44 -06:00
|
|
|
}
|
2008-10-15 12:48:18 -06:00
|
|
|
|
2009-01-12 18:44:10 -07:00
|
|
|
// if we had a list of identifiers, it must be followed by a type
|
2009-02-27 16:40:17 -07:00
|
|
|
typ := P.tryParameterType();
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
return list, typ;
|
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseParameterList(ellipsis_ok bool) []*ast.Field {
|
2009-02-27 16:40:17 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "ParameterList"));
|
2008-10-18 17:42:25 -06:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
list, typ := P.parseParameterDecl(false);
|
2008-10-15 12:48:18 -06:00
|
|
|
if typ != nil {
|
2009-02-27 16:40:17 -07:00
|
|
|
// IdentifierList Type
|
|
|
|
// convert list of identifiers into []*Ident
|
2009-03-05 18:15:36 -07:00
|
|
|
idents := make([]*ast.Ident, list.Len());
|
2009-02-27 16:40:17 -07:00
|
|
|
for i := 0; i < list.Len(); i++ {
|
2009-03-05 18:15:36 -07:00
|
|
|
idents[i] = list.At(i).(*ast.Ident);
|
2009-02-27 16:40:17 -07:00
|
|
|
}
|
|
|
|
list.Init(0);
|
2009-03-20 18:18:48 -06:00
|
|
|
list.Push(&ast.Field{nil, idents, typ, nil});
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-03-03 19:25:07 -07:00
|
|
|
for P.tok == token.COMMA {
|
2009-02-27 16:40:17 -07:00
|
|
|
P.next();
|
2009-03-16 21:29:31 -06:00
|
|
|
idents := P.parseIdentList(nil);
|
2009-02-27 16:40:17 -07:00
|
|
|
typ := P.parseParameterType();
|
2009-03-20 18:18:48 -06:00
|
|
|
list.Push(&ast.Field{nil, idents, typ, nil});
|
2008-10-15 12:48:18 -06:00
|
|
|
}
|
2008-10-15 18:06:28 -06:00
|
|
|
|
2008-10-15 12:48:18 -06:00
|
|
|
} else {
|
2009-02-27 16:40:17 -07:00
|
|
|
// Type { "," Type }
|
|
|
|
// convert list of types into list of *Param
|
|
|
|
for i := 0; i < list.Len(); i++ {
|
2009-03-20 18:18:48 -06:00
|
|
|
list.Set(i, &ast.Field{nil, nil, list.At(i).(ast.Expr), nil});
|
2008-10-15 18:06:28 -06:00
|
|
|
}
|
2008-09-27 18:42:18 -06:00
|
|
|
}
|
2008-09-18 17:58:37 -06:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
// convert list
|
2009-03-05 18:15:36 -07:00
|
|
|
params := make([]*ast.Field, list.Len());
|
2009-02-27 16:40:17 -07:00
|
|
|
for i := 0; i < list.Len(); i++ {
|
2009-03-05 18:15:36 -07:00
|
|
|
params[i] = list.At(i).(*ast.Field);
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
return params;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
// TODO make sure Go spec is updated
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseParameters(ellipsis_ok bool) []*ast.Field {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Parameters"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-05 18:15:36 -07:00
|
|
|
var params []*ast.Field;
|
2009-03-03 19:25:07 -07:00
|
|
|
P.expect(token.LPAREN);
|
|
|
|
if P.tok != token.RPAREN {
|
2009-02-27 16:40:17 -07:00
|
|
|
params = P.parseParameterList(ellipsis_ok);
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-03 19:25:07 -07:00
|
|
|
P.expect(token.RPAREN);
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
return params;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseResult() []*ast.Field {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Result"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
var results []*ast.Field;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.LPAREN {
|
2009-03-25 13:45:06 -06:00
|
|
|
results = P.parseParameters(false);
|
2009-03-03 19:25:07 -07:00
|
|
|
} else if P.tok != token.FUNC {
|
2009-02-05 15:22:09 -07:00
|
|
|
typ := P.tryType();
|
2008-10-15 18:06:28 -06:00
|
|
|
if typ != nil {
|
2009-03-25 13:45:06 -06:00
|
|
|
results = make([]*ast.Field, 1);
|
|
|
|
results[0] = &ast.Field{nil, nil, typ, nil};
|
2008-10-15 18:06:28 -06:00
|
|
|
}
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
return results;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-19 13:12:28 -06:00
|
|
|
// Function types
|
2008-09-18 17:58:37 -06:00
|
|
|
//
|
|
|
|
// (params)
|
|
|
|
// (params) type
|
|
|
|
// (params) (results)
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseSignature() (params []*ast.Field, results []*ast.Field) {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Signature"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
params = P.parseParameters(true); // TODO find better solution
|
|
|
|
results = P.parseResult();
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
return params, results;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseFunctionType() *ast.FunctionType {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "FunctionType"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2009-01-30 16:31:04 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
pos := P.expect(token.FUNC);
|
2009-03-25 13:45:06 -06:00
|
|
|
params, results := P.parseSignature();
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.FunctionType{pos, params, results};
|
2009-01-30 16:31:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseMethodSpec() *ast.Field {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-02-27 16:40:17 -07:00
|
|
|
defer un(trace(P, "MethodSpec"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
doc := P.getDoc();
|
2009-03-05 18:15:36 -07:00
|
|
|
var idents []*ast.Ident;
|
|
|
|
var typ ast.Expr;
|
2009-02-19 17:47:58 -07:00
|
|
|
x := P.parseQualifiedIdent();
|
2009-03-05 18:15:36 -07:00
|
|
|
if tmp, is_ident := x.(*ast.Ident); is_ident && (P.tok == token.COMMA || P.tok == token.LPAREN) {
|
2009-02-19 17:47:58 -07:00
|
|
|
// method(s)
|
2009-03-16 21:29:31 -06:00
|
|
|
idents = P.parseIdentList(x);
|
2009-03-25 13:45:06 -06:00
|
|
|
params, results := P.parseSignature();
|
|
|
|
typ = &ast.FunctionType{nopos, params, results};
|
2009-02-19 17:47:58 -07:00
|
|
|
} else {
|
|
|
|
// embedded interface
|
2009-02-27 16:40:17 -07:00
|
|
|
typ = x;
|
2009-02-19 17:47:58 -07:00
|
|
|
}
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.Field{doc, idents, typ, nil};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseInterfaceType() *ast.InterfaceType {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "InterfaceType"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
pos := P.expect(token.INTERFACE);
|
2009-03-26 17:10:07 -06:00
|
|
|
var lbrace, rbrace token.Position;
|
2009-03-05 18:15:36 -07:00
|
|
|
var methods []*ast.Field;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.LBRACE {
|
2009-03-20 18:18:48 -06:00
|
|
|
lbrace = P.pos;
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-01-08 13:04:00 -07:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
list := vector.New(0);
|
2009-03-03 19:25:07 -07:00
|
|
|
for P.tok == token.IDENT {
|
2009-02-27 16:40:17 -07:00
|
|
|
list.Push(P.parseMethodSpec());
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok != token.RBRACE {
|
|
|
|
P.expect(token.SEMICOLON);
|
2008-10-07 18:57:19 -06:00
|
|
|
}
|
|
|
|
}
|
2009-01-08 13:04:00 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
rbrace = P.expect(token.RBRACE);
|
2009-02-27 16:40:17 -07:00
|
|
|
P.opt_semi = true;
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
// convert vector
|
2009-03-05 18:15:36 -07:00
|
|
|
methods = make([]*ast.Field, list.Len());
|
2009-02-27 16:40:17 -07:00
|
|
|
for i := list.Len() - 1; i >= 0; i-- {
|
2009-03-05 18:15:36 -07:00
|
|
|
methods[i] = list.At(i).(*ast.Field);
|
2009-02-27 16:40:17 -07:00
|
|
|
}
|
2008-10-07 18:57:19 -06:00
|
|
|
}
|
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.InterfaceType{pos, lbrace, methods, rbrace};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseMapType() *ast.MapType {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "MapType"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
pos := P.expect(token.MAP);
|
2009-03-03 19:25:07 -07:00
|
|
|
P.expect(token.LBRACK);
|
2009-02-27 16:40:17 -07:00
|
|
|
key := P.parseVarType();
|
2009-03-03 19:25:07 -07:00
|
|
|
P.expect(token.RBRACK);
|
2009-03-20 18:18:48 -06:00
|
|
|
value := P.parseVarType();
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.MapType{pos, key, value};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseStringList(x *ast.StringLit) []*ast.StringLit
|
2008-10-31 15:27:34 -06:00
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseFieldDecl() *ast.Field {
|
2009-02-27 16:40:17 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "FieldDecl"));
|
|
|
|
}
|
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
doc := P.getDoc();
|
2009-03-12 18:24:03 -06:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
// 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());
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.COMMA {
|
2009-02-27 16:40:17 -07:00
|
|
|
P.next();
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we had a list of identifiers, it must be followed by a type
|
|
|
|
typ := P.tryType();
|
|
|
|
|
|
|
|
// optional tag
|
2009-03-25 13:45:06 -06:00
|
|
|
var tag []*ast.StringLit;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.STRING {
|
2009-03-25 13:45:06 -06:00
|
|
|
tag = P.parseStringList(nil);
|
2009-02-27 16:40:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// analyze case
|
2009-03-05 18:15:36 -07:00
|
|
|
var idents []*ast.Ident;
|
2009-02-27 16:40:17 -07:00
|
|
|
if typ != nil {
|
|
|
|
// non-empty identifier list followed by a type
|
2009-03-05 18:15:36 -07:00
|
|
|
idents = make([]*ast.Ident, list.Len());
|
2009-02-27 16:40:17 -07:00
|
|
|
for i := 0; i < list.Len(); i++ {
|
2009-03-05 18:15:36 -07:00
|
|
|
if ident, is_ident := list.At(i).(*ast.Ident); is_ident {
|
2009-02-27 16:40:17 -07:00
|
|
|
idents[i] = ident;
|
|
|
|
} else {
|
2009-03-17 19:41:35 -06:00
|
|
|
P.error(list.At(i).(ast.Expr).Pos(), "identifier expected");
|
2009-02-27 16:40:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// anonymous field
|
|
|
|
if list.Len() == 1 {
|
|
|
|
// TODO should do more checks here
|
2009-03-05 18:15:36 -07:00
|
|
|
typ = list.At(0).(ast.Expr);
|
2009-02-27 16:40:17 -07:00
|
|
|
} else {
|
2009-03-20 18:18:48 -06:00
|
|
|
P.error(P.pos, "anonymous field expected");
|
2009-02-27 16:40:17 -07:00
|
|
|
}
|
|
|
|
}
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.Field{doc, idents, typ, tag};
|
2009-02-27 16:40:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseStructType() *ast.StructType {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "StructType"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-09-25 12:50:34 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
pos := P.expect(token.STRUCT);
|
2009-03-26 17:10:07 -06:00
|
|
|
var lbrace, rbrace token.Position;
|
2009-03-05 18:15:36 -07:00
|
|
|
var fields []*ast.Field;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.LBRACE {
|
2009-03-20 18:18:48 -06:00
|
|
|
lbrace = P.pos;
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-01-08 13:04:00 -07:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
list := vector.New(0);
|
2009-03-03 19:25:07 -07:00
|
|
|
for P.tok != token.RBRACE && P.tok != token.EOF {
|
2009-02-27 16:40:17 -07:00
|
|
|
list.Push(P.parseFieldDecl());
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.SEMICOLON {
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2008-10-31 15:27:34 -06:00
|
|
|
} else {
|
|
|
|
break;
|
2008-10-07 18:57:19 -06:00
|
|
|
}
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-10 19:20:08 -06:00
|
|
|
if P.tok == token.SEMICOLON {
|
|
|
|
P.next();
|
|
|
|
}
|
2009-01-08 13:04:00 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
rbrace = P.expect(token.RBRACE);
|
2009-02-27 16:40:17 -07:00
|
|
|
P.opt_semi = true;
|
2009-02-13 15:48:32 -07:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
// convert vector
|
2009-03-05 18:15:36 -07:00
|
|
|
fields = make([]*ast.Field, list.Len());
|
2009-02-27 16:40:17 -07:00
|
|
|
for i := list.Len() - 1; i >= 0; i-- {
|
2009-03-05 18:15:36 -07:00
|
|
|
fields[i] = list.At(i).(*ast.Field);
|
2009-01-23 10:44:01 -07:00
|
|
|
}
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2008-10-07 18:57:19 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.StructType{pos, lbrace, fields, rbrace};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parsePointerType() *ast.StarExpr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "PointerType"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
star := P.expect(token.MUL);
|
2009-02-27 16:40:17 -07:00
|
|
|
base := P.parseType();
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.StarExpr{star, base};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) tryType() ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Type (try)"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2008-09-18 17:58:37 -06:00
|
|
|
switch P.tok {
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.IDENT: return P.parseTypeName();
|
|
|
|
case token.LBRACK: return P.parseArrayType();
|
|
|
|
case token.CHAN, token.ARROW: return P.parseChannelType();
|
|
|
|
case token.INTERFACE: return P.parseInterfaceType();
|
|
|
|
case token.FUNC: return P.parseFunctionType();
|
|
|
|
case token.MAP: return P.parseMapType();
|
|
|
|
case token.STRUCT: return P.parseStructType();
|
|
|
|
case token.MUL: return P.parsePointerType();
|
|
|
|
case token.LPAREN:
|
2009-03-20 18:18:48 -06:00
|
|
|
lparen := P.pos;
|
2009-02-19 17:47:58 -07:00
|
|
|
P.next();
|
2009-03-17 19:41:35 -06:00
|
|
|
x := P.parseType();
|
|
|
|
rparen := P.expect(token.RPAREN);
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.ParenExpr{lparen, x, rparen};
|
2009-02-13 17:27:53 -07:00
|
|
|
}
|
2009-03-03 17:00:06 -07:00
|
|
|
|
2009-02-13 17:27:53 -07:00
|
|
|
// no type found
|
|
|
|
return nil;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Blocks
|
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
func asStmtList(list *vector.Vector) []ast.Stmt {
|
|
|
|
stats := make([]ast.Stmt, list.Len());
|
2009-03-20 18:18:48 -06:00
|
|
|
for i := 0; i < list.Len(); i++ {
|
2009-03-25 13:45:06 -06:00
|
|
|
stats[i] = list.At(i).(ast.Stmt);
|
2009-03-20 18:18:48 -06:00
|
|
|
}
|
|
|
|
return stats;
|
|
|
|
}
|
|
|
|
|
2009-02-04 19:28:41 -07:00
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseStatementList() []ast.Stmt {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "StatementList"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
list := vector.New(0);
|
2009-02-12 17:06:21 -07:00
|
|
|
expect_semi := false;
|
2009-03-03 19:25:07 -07:00
|
|
|
for P.tok != token.CASE && P.tok != token.DEFAULT && P.tok != token.RBRACE && P.tok != token.EOF {
|
2009-02-12 17:06:21 -07:00
|
|
|
if expect_semi {
|
2009-03-03 19:25:07 -07:00
|
|
|
P.expect(token.SEMICOLON);
|
2009-02-12 17:06:21 -07:00
|
|
|
expect_semi = false;
|
2008-10-17 17:19:31 -06:00
|
|
|
}
|
2009-02-12 17:06:21 -07:00
|
|
|
list.Push(P.parseStatement());
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.SEMICOLON {
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2008-10-10 17:03:32 -06:00
|
|
|
} else if P.opt_semi {
|
|
|
|
P.opt_semi = false; // "consume" optional semicolon
|
2008-09-23 17:40:12 -06:00
|
|
|
} else {
|
2009-02-12 17:06:21 -07:00
|
|
|
expect_semi = true;
|
2008-09-23 17:40:12 -06:00
|
|
|
}
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
return asStmtList(list);
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseBlockStmt() *ast.BlockStmt {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-03-25 13:45:06 -06:00
|
|
|
defer un(trace(P, "compositeStmt"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
lbrace := P.expect(token.LBRACE);
|
2009-03-20 18:18:48 -06:00
|
|
|
list := P.parseStatementList();
|
2009-03-25 13:45:06 -06:00
|
|
|
rbrace := P.expect(token.RBRACE);
|
|
|
|
P.opt_semi = true;
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.BlockStmt{lbrace, list, rbrace};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Expressions
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseFunctionLit() ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "FunctionLit"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
typ := P.parseFunctionType();
|
2009-03-03 17:00:06 -07:00
|
|
|
P.expr_lev++;
|
2009-03-25 13:45:06 -06:00
|
|
|
body := P.parseBlockStmt();
|
2009-03-03 17:00:06 -07:00
|
|
|
P.expr_lev--;
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.FunctionLit{typ, body};
|
2009-03-05 18:15:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseStringList(x *ast.StringLit) []*ast.StringLit {
|
2009-03-05 18:15:36 -07:00
|
|
|
if P.trace {
|
2009-03-25 13:45:06 -06:00
|
|
|
defer un(trace(P, "StringList"));
|
2009-03-05 18:15:36 -07:00
|
|
|
}
|
|
|
|
|
2009-03-17 19:41:35 -06:00
|
|
|
list := vector.New(0);
|
2009-03-20 18:18:48 -06:00
|
|
|
if x != nil {
|
|
|
|
list.Push(x);
|
|
|
|
}
|
|
|
|
|
2009-03-05 18:15:36 -07:00
|
|
|
for P.tok == token.STRING {
|
2009-03-26 17:10:07 -06:00
|
|
|
list.Push(&ast.StringLit{P.pos, P.lit});
|
2009-03-05 18:15:36 -07:00
|
|
|
P.next();
|
|
|
|
}
|
|
|
|
|
2009-03-17 19:41:35 -06:00
|
|
|
// convert list
|
2009-03-25 13:45:06 -06:00
|
|
|
strings := make([]*ast.StringLit, list.Len());
|
2009-03-17 19:41:35 -06:00
|
|
|
for i := 0; i < list.Len(); i++ {
|
2009-03-25 13:45:06 -06:00
|
|
|
strings[i] = list.At(i).(*ast.StringLit);
|
2009-03-17 19:41:35 -06:00
|
|
|
}
|
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
return strings;
|
2008-10-23 18:56:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseOperand() ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Operand"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-09-18 17:58:37 -06:00
|
|
|
|
2008-09-23 17:40:12 -06:00
|
|
|
switch P.tok {
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.IDENT:
|
2009-03-05 18:15:36 -07:00
|
|
|
return P.parseIdent();
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
case token.INT:
|
2009-03-26 17:10:07 -06:00
|
|
|
x := &ast.IntLit{P.pos, P.lit};
|
2009-03-25 13:45:06 -06:00
|
|
|
P.next();
|
|
|
|
return x;
|
|
|
|
|
|
|
|
case token.FLOAT:
|
2009-03-26 17:10:07 -06:00
|
|
|
x := &ast.FloatLit{P.pos, P.lit};
|
2009-03-25 13:45:06 -06:00
|
|
|
P.next();
|
|
|
|
return x;
|
|
|
|
|
|
|
|
case token.CHAR:
|
2009-03-26 17:10:07 -06:00
|
|
|
x := &ast.CharLit{P.pos, P.lit};
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-02-03 18:44:01 -07:00
|
|
|
return x;
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-03-05 18:15:36 -07:00
|
|
|
case token.STRING:
|
2009-03-26 17:10:07 -06:00
|
|
|
x := &ast.StringLit{P.pos, P.lit};
|
2009-03-20 18:18:48 -06:00
|
|
|
P.next();
|
|
|
|
if P.tok == token.STRING {
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.StringList{P.parseStringList(x)};
|
2009-03-20 18:18:48 -06:00
|
|
|
}
|
|
|
|
return x;
|
2008-10-10 17:03:32 -06:00
|
|
|
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.LPAREN:
|
2009-03-20 18:18:48 -06:00
|
|
|
lparen := P.pos;
|
2009-03-03 19:25:07 -07:00
|
|
|
P.next();
|
|
|
|
P.expr_lev++;
|
|
|
|
x := P.parseExpression(1);
|
|
|
|
P.expr_lev--;
|
2009-03-17 19:41:35 -06:00
|
|
|
rparen := P.expect(token.RPAREN);
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.ParenExpr{lparen, x, rparen};
|
2009-03-03 19:25:07 -07:00
|
|
|
|
|
|
|
case token.FUNC:
|
2009-02-05 15:22:09 -07:00
|
|
|
return P.parseFunctionLit();
|
2008-10-23 18:56:54 -06:00
|
|
|
|
2008-09-23 17:40:12 -06:00
|
|
|
default:
|
2009-02-05 15:22:09 -07:00
|
|
|
t := P.tryType();
|
2008-10-15 18:06:28 -06:00
|
|
|
if t != nil {
|
2009-02-27 16:40:17 -07:00
|
|
|
return t;
|
2008-10-15 18:06:28 -06:00
|
|
|
} else {
|
2009-03-20 18:18:48 -06:00
|
|
|
P.error(P.pos, "operand expected");
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next(); // make progress
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.BadExpr{P.pos};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-03-17 19:41:35 -06:00
|
|
|
defer un(trace(P, "SelectorOrTypeAssertion"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-09-18 17:58:37 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
P.expect(token.PERIOD);
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.IDENT {
|
2009-03-17 19:41:35 -06:00
|
|
|
// selector
|
|
|
|
sel := P.parseIdent();
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.SelectorExpr{x, sel};
|
|
|
|
|
2008-09-18 17:58:37 -06:00
|
|
|
} else {
|
2009-03-20 18:18:48 -06:00
|
|
|
// type assertion
|
|
|
|
P.expect(token.LPAREN);
|
|
|
|
var typ ast.Expr;
|
|
|
|
if P.tok == token.TYPE {
|
|
|
|
// special case for type switch syntax
|
2009-03-26 17:10:07 -06:00
|
|
|
typ = &ast.Ident{P.pos, P.lit};
|
2009-03-20 18:18:48 -06:00
|
|
|
P.next();
|
|
|
|
} else {
|
|
|
|
typ = P.parseType();
|
|
|
|
}
|
|
|
|
P.expect(token.RPAREN);
|
|
|
|
return &ast.TypeAssertExpr{x, typ};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
|
|
|
|
unreachable();
|
|
|
|
return nil;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "IndexOrSlice"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
P.expect(token.LBRACK);
|
2009-03-03 17:00:06 -07:00
|
|
|
P.expr_lev++;
|
2009-03-17 19:41:35 -06:00
|
|
|
index := P.parseExpression(1);
|
2009-03-03 17:00:06 -07:00
|
|
|
P.expr_lev--;
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-17 19:41:35 -06:00
|
|
|
if P.tok == token.RBRACK {
|
|
|
|
// index
|
|
|
|
P.next();
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.IndexExpr{x, index};
|
2009-03-17 19:41:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// slice
|
2009-03-20 18:18:48 -06:00
|
|
|
P.expect(token.COLON);
|
2009-03-17 19:41:35 -06:00
|
|
|
P.expr_lev++;
|
|
|
|
end := P.parseExpression(1);
|
|
|
|
P.expr_lev--;
|
2009-03-20 18:18:48 -06:00
|
|
|
P.expect(token.RBRACK);
|
|
|
|
return &ast.SliceExpr{x, index, end};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseCall(fun ast.Expr) *ast.CallExpr {
|
2009-03-17 19:41:35 -06:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Call"));
|
|
|
|
}
|
|
|
|
|
|
|
|
lparen := P.expect(token.LPAREN);
|
|
|
|
var args []ast.Expr;
|
|
|
|
if P.tok != token.RPAREN {
|
|
|
|
args = P.parseExpressionList();
|
|
|
|
}
|
|
|
|
rparen := P.expect(token.RPAREN);
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.CallExpr{fun, lparen, args, rparen};
|
2008-10-16 13:16:50 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseElementList() []ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-03-17 19:41:35 -06:00
|
|
|
defer un(trace(P, "ElementList"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-17 19:41:35 -06:00
|
|
|
list := vector.New(0);
|
|
|
|
singles := true;
|
|
|
|
for P.tok != token.RBRACE {
|
|
|
|
x := P.parseExpression(0);
|
|
|
|
if list.Len() == 0 {
|
|
|
|
// first element determines syntax for remaining elements
|
2009-03-26 17:10:07 -06:00
|
|
|
if t, is_binary := x.(*ast.BinaryExpr); is_binary && t.Op == token.COLON {
|
2009-03-17 19:41:35 -06:00
|
|
|
singles = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// not the first element - check syntax
|
|
|
|
if singles {
|
2009-03-26 17:10:07 -06:00
|
|
|
if t, is_binary := x.(*ast.BinaryExpr); is_binary && t.Op == token.COLON {
|
2009-03-17 19:41:35 -06:00
|
|
|
P.error(t.X.Pos(), "single value expected; found pair");
|
|
|
|
}
|
|
|
|
} else {
|
2009-03-26 17:10:07 -06:00
|
|
|
if t, is_binary := x.(*ast.BinaryExpr); !is_binary || t.Op != token.COLON {
|
2009-03-17 19:41:35 -06:00
|
|
|
P.error(x.Pos(), "key:value pair expected; found single value");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
list.Push(x);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseCompositeLit(typ ast.Expr) ast.Expr {
|
2009-03-17 19:41:35 -06:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "CompositeLit"));
|
2008-10-17 17:19:31 -06:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-17 19:41:35 -06:00
|
|
|
lbrace := P.expect(token.LBRACE);
|
|
|
|
var elts []ast.Expr;
|
|
|
|
if P.tok != token.RBRACE {
|
|
|
|
elts = P.parseElementList();
|
|
|
|
}
|
|
|
|
rbrace := P.expect(token.RBRACE);
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.CompositeLit{typ, lbrace, elts, rbrace};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parsePrimaryExpr() ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "PrimaryExpr"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-02-05 15:22:09 -07:00
|
|
|
x := P.parseOperand();
|
2008-10-09 19:03:16 -06:00
|
|
|
for {
|
2008-09-18 17:58:37 -06:00
|
|
|
switch P.tok {
|
2009-03-17 19:41:35 -06:00
|
|
|
case token.PERIOD: x = P.parseSelectorOrTypeAssertion(x);
|
|
|
|
case token.LBRACK: x = P.parseIndexOrSlice(x);
|
|
|
|
case token.LPAREN: x = P.parseCall(x);
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.LBRACE:
|
2009-03-03 17:00:06 -07:00
|
|
|
if P.expr_lev >= 0 {
|
2009-03-17 19:41:35 -06:00
|
|
|
x = P.parseCompositeLit(x);
|
2009-03-03 17:00:06 -07:00
|
|
|
} else {
|
|
|
|
return x;
|
|
|
|
}
|
2009-02-03 18:44:01 -07:00
|
|
|
default:
|
|
|
|
return x;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-02-03 18:44:01 -07:00
|
|
|
unreachable();
|
|
|
|
return nil;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseUnaryExpr() ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "UnaryExpr"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2008-09-18 17:58:37 -06:00
|
|
|
switch P.tok {
|
2009-03-20 18:18:48 -06:00
|
|
|
case token.ADD, token.SUB, token.NOT, token.XOR, token.ARROW, token.AND, token.RANGE:
|
|
|
|
pos, tok := P.pos, P.tok;
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-03-20 18:18:48 -06:00
|
|
|
x := P.parseUnaryExpr();
|
|
|
|
return &ast.UnaryExpr{pos, tok, x};
|
|
|
|
|
|
|
|
case token.MUL:
|
|
|
|
// unary "*" expression or pointer type
|
|
|
|
pos := P.pos;
|
|
|
|
P.next();
|
|
|
|
x := P.parseUnaryExpr();
|
|
|
|
return &ast.StarExpr{pos, x};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-02-05 15:22:09 -07:00
|
|
|
return P.parsePrimaryExpr();
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseBinaryExpr(prec1 int) ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "BinaryExpr"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-02-05 15:22:09 -07:00
|
|
|
x := P.parseUnaryExpr();
|
2009-03-26 11:53:14 -06:00
|
|
|
for prec := P.tok.Precedence(); prec >= prec1; prec-- {
|
|
|
|
for P.tok.Precedence() == prec {
|
2009-03-20 18:18:48 -06:00
|
|
|
pos, tok := P.pos, P.tok;
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
|
|
|
y := P.parseBinaryExpr(prec + 1);
|
2009-03-20 18:18:48 -06:00
|
|
|
x = &ast.BinaryExpr{x, pos, tok, y};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2008-09-18 17:58:37 -06:00
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseExpression(prec int) ast.Expr {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Expression"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-10-18 21:20:30 -06:00
|
|
|
|
|
|
|
if prec < 0 {
|
|
|
|
panic("precedence must be >= 0");
|
|
|
|
}
|
2009-02-03 18:44:01 -07:00
|
|
|
|
2009-02-13 17:27:53 -07:00
|
|
|
return P.parseBinaryExpr(prec);
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Statements
|
|
|
|
|
2009-03-16 21:29:31 -06:00
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseSimpleStmt() ast.Stmt {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-03-25 13:45:06 -06:00
|
|
|
defer un(trace(P, "SimpleStmt"));
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
2009-02-05 15:22:09 -07:00
|
|
|
x := P.parseExpressionList();
|
2009-02-04 19:28:41 -07:00
|
|
|
|
|
|
|
switch P.tok {
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.COLON:
|
2009-03-13 17:59:51 -06:00
|
|
|
// labeled statement
|
2009-03-16 21:29:31 -06:00
|
|
|
P.expect(token.COLON);
|
2009-03-20 18:18:48 -06:00
|
|
|
if len(x) == 1 {
|
2009-03-16 21:29:31 -06:00
|
|
|
if label, is_ident := x[0].(*ast.Ident); is_ident {
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.LabeledStmt{label, P.parseStatement()};
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
P.error(x[0].Pos(), "illegal label declaration");
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.BadStmt{x[0].Pos()};
|
2009-02-13 15:48:32 -07:00
|
|
|
|
2009-02-04 19:28:41 -07:00
|
|
|
case
|
2009-03-03 19:25:07 -07:00
|
|
|
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:
|
2009-03-25 13:45:06 -06:00
|
|
|
// assignment statement
|
2009-03-20 18:18:48 -06:00
|
|
|
pos, tok := P.pos, P.tok;
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-03-20 18:18:48 -06:00
|
|
|
y := P.parseExpressionList();
|
2009-03-25 13:45:06 -06:00
|
|
|
if len(x) > 1 && len(y) > 1 && len(x) != len(y) {
|
|
|
|
P.error(x[0].Pos(), "arity of lhs doesn't match rhs");
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.AssignStmt{x, pos, tok, y};
|
|
|
|
}
|
2009-02-13 15:48:32 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
if len(x) > 1 {
|
|
|
|
P.error(x[0].Pos(), "only one expression allowed");
|
|
|
|
// continue with first expression
|
|
|
|
}
|
2009-02-13 15:48:32 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
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;
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
// expression
|
|
|
|
return &ast.ExprStmt{x[0]};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseCallExpr() *ast.CallExpr {
|
2009-03-25 13:45:06 -06:00
|
|
|
x := P.parseExpression(1);
|
|
|
|
if call, is_call := x.(*ast.CallExpr); is_call {
|
|
|
|
return call;
|
|
|
|
}
|
|
|
|
P.error(x.Pos(), "expected function/method call");
|
2009-02-04 19:28:41 -07:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseGoStmt() ast.Stmt {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-03-25 13:45:06 -06:00
|
|
|
defer un(trace(P, "GoStmt"));
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
pos := P.expect(token.GO);
|
2009-03-25 13:45:06 -06:00
|
|
|
call := P.parseCallExpr();
|
|
|
|
if call != nil {
|
|
|
|
return &ast.GoStmt{pos, call};
|
|
|
|
}
|
|
|
|
return &ast.BadStmt{pos};
|
2009-03-20 18:18:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseDeferStmt() ast.Stmt {
|
2009-03-20 18:18:48 -06:00
|
|
|
if P.trace {
|
2009-03-25 13:45:06 -06:00
|
|
|
defer un(trace(P, "DeferStmt"));
|
2009-03-20 18:18:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pos := P.expect(token.DEFER);
|
2009-03-25 13:45:06 -06:00
|
|
|
call := P.parseCallExpr();
|
|
|
|
if call != nil {
|
|
|
|
return &ast.DeferStmt{pos, call};
|
|
|
|
}
|
|
|
|
return &ast.BadStmt{pos};
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseReturnStmt() *ast.ReturnStmt {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-03-25 13:45:06 -06:00
|
|
|
defer un(trace(P, "ReturnStmt"));
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
loc := P.pos;
|
2009-03-03 19:25:07 -07:00
|
|
|
P.expect(token.RETURN);
|
2009-03-16 21:29:31 -06:00
|
|
|
var x []ast.Expr;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok != token.SEMICOLON && P.tok != token.RBRACE {
|
2009-02-05 15:22:09 -07:00
|
|
|
x = P.parseExpressionList();
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.ReturnStmt{loc, x};
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-03-25 13:45:06 -06:00
|
|
|
defer un(trace(P, "BranchStmt"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
s := &ast.BranchStmt{P.pos, tok, nil};
|
2009-02-05 15:22:09 -07:00
|
|
|
P.expect(tok);
|
2009-03-03 19:25:07 -07:00
|
|
|
if tok != token.FALLTHROUGH && P.tok == token.IDENT {
|
2009-03-05 18:15:36 -07:00
|
|
|
s.Label = P.parseIdent();
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2008-10-14 19:14:01 -06:00
|
|
|
return s;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) isExpr(s ast.Stmt) bool {
|
2009-03-25 13:45:06 -06:00
|
|
|
if s == nil {
|
|
|
|
return true;
|
2009-03-20 18:18:48 -06:00
|
|
|
}
|
2009-03-25 13:45:06 -06:00
|
|
|
dummy, is_expr := s.(*ast.ExprStmt);
|
|
|
|
return is_expr;
|
2009-03-20 18:18:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) asExpr(s ast.Stmt) ast.Expr {
|
2009-03-25 13:45:06 -06:00
|
|
|
if s == nil {
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
if es, is_expr := s.(*ast.ExprStmt); is_expr {
|
|
|
|
return es.X;
|
2009-03-20 18:18:48 -06:00
|
|
|
}
|
2009-03-25 13:45:06 -06:00
|
|
|
P.error(s.Pos(), "condition expected; found simple statement");
|
|
|
|
return &ast.BadExpr{s.Pos()};
|
2009-03-20 18:18:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "ControlClause"));
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok != token.LBRACE {
|
2009-03-03 17:00:06 -07:00
|
|
|
prev_lev := P.expr_lev;
|
2009-03-11 17:06:17 -06:00
|
|
|
P.expr_lev = -1;
|
2009-03-16 21:29:31 -06:00
|
|
|
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok != token.SEMICOLON {
|
2009-03-25 13:45:06 -06:00
|
|
|
s1 = P.parseSimpleStmt();
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
if P.tok == token.SEMICOLON {
|
|
|
|
P.next();
|
|
|
|
if P.tok != token.LBRACE && P.tok != token.SEMICOLON {
|
2009-03-25 13:45:06 -06:00
|
|
|
s2 = P.parseSimpleStmt();
|
2009-03-20 18:18:48 -06:00
|
|
|
}
|
2009-03-25 13:45:06 -06:00
|
|
|
if isForStmt {
|
2009-03-20 18:18:48 -06:00
|
|
|
// for statements have a 3rd section
|
|
|
|
P.expect(token.SEMICOLON);
|
|
|
|
if P.tok != token.LBRACE {
|
2009-03-25 13:45:06 -06:00
|
|
|
s3 = P.parseSimpleStmt();
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
} else {
|
|
|
|
s1, s2 = nil, s1;
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
|
2009-03-03 17:00:06 -07:00
|
|
|
P.expr_lev = prev_lev;
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return s1, s2, s3;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseIfStmt() *ast.IfStmt {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-03-25 13:45:06 -06:00
|
|
|
defer un(trace(P, "IfStmt"));
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
pos := P.expect(token.IF);
|
|
|
|
s1, s2, dummy := P.parseControlClause(false);
|
2009-03-25 13:45:06 -06:00
|
|
|
body := P.parseBlockStmt();
|
|
|
|
var else_ ast.Stmt;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.ELSE {
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-03-05 18:15:36 -07:00
|
|
|
else_ = P.parseStatement();
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.IfStmt{pos, s1, P.asExpr(s2), body, else_};
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseCaseClause() *ast.CaseClause {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-03-20 18:18:48 -06:00
|
|
|
defer un(trace(P, "CaseClause"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
// SwitchCase
|
|
|
|
loc := P.pos;
|
|
|
|
var x []ast.Expr;
|
|
|
|
if P.tok == token.CASE {
|
|
|
|
P.next();
|
|
|
|
x = P.parseExpressionList();
|
|
|
|
} else {
|
|
|
|
P.expect(token.DEFAULT);
|
2009-03-16 21:29:31 -06:00
|
|
|
}
|
2009-03-25 13:45:06 -06:00
|
|
|
|
|
|
|
colon := P.expect(token.COLON);
|
|
|
|
body := P.parseStatementList();
|
2009-03-16 21:29:31 -06:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.CaseClause{loc, x, colon, body};
|
2009-03-16 21:29:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseTypeCaseClause() *ast.TypeCaseClause {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "CaseClause"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
// TypeSwitchCase
|
|
|
|
pos := P.pos;
|
|
|
|
var typ ast.Expr;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.CASE {
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-03-20 18:18:48 -06:00
|
|
|
typ = P.parseType();
|
2008-09-18 17:58:37 -06:00
|
|
|
} else {
|
2009-03-03 19:25:07 -07:00
|
|
|
P.expect(token.DEFAULT);
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
colon := P.expect(token.COLON);
|
|
|
|
body := P.parseStatementList();
|
|
|
|
|
|
|
|
return &ast.TypeCaseClause{pos, typ, colon, body};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseSwitchStmt() ast.Stmt {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-03-25 13:45:06 -06:00
|
|
|
defer un(trace(P, "SwitchStmt"));
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
pos := P.expect(token.SWITCH);
|
|
|
|
s1, s2, dummy := P.parseControlClause(false);
|
2009-02-04 19:28:41 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
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());
|
2009-03-16 21:29:31 -06:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
rbrace := P.expect(token.RBRACE);
|
|
|
|
P.opt_semi = true;
|
2009-03-25 13:45:06 -06:00
|
|
|
body := &ast.BlockStmt{lbrace, asStmtList(cases), rbrace};
|
|
|
|
return &ast.SwitchStmt{pos, s1, P.asExpr(s2), body};
|
2009-03-20 18:18:48 -06:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// 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;
|
2009-03-25 13:45:06 -06:00
|
|
|
body := &ast.BlockStmt{lbrace, asStmtList(cases), rbrace};
|
|
|
|
return &ast.TypeSwitchStmt{pos, s1, s2, body};
|
2009-03-16 21:29:31 -06:00
|
|
|
}
|
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
unreachable();
|
|
|
|
return nil;
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseCommClause() *ast.CommClause {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "CommClause"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-10-14 19:14:01 -06:00
|
|
|
|
2009-02-05 12:05:02 -07:00
|
|
|
// CommCase
|
2009-03-20 18:18:48 -06:00
|
|
|
loc := P.pos;
|
2009-03-26 11:53:14 -06:00
|
|
|
var tok token.Token;
|
2009-03-16 21:29:31 -06:00
|
|
|
var lhs, rhs ast.Expr;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.CASE {
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-03-16 21:29:31 -06:00
|
|
|
if P.tok == token.ARROW {
|
|
|
|
// RecvExpr without assignment
|
|
|
|
rhs = P.parseExpression(1);
|
|
|
|
} else {
|
|
|
|
// SendExpr or RecvExpr
|
|
|
|
rhs = P.parseExpression(1);
|
|
|
|
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(1);
|
|
|
|
} else {
|
|
|
|
P.expect(token.ARROW); // use expect() error handling
|
|
|
|
}
|
2008-10-26 22:32:30 -06:00
|
|
|
}
|
2009-03-16 21:29:31 -06:00
|
|
|
// else SendExpr
|
2008-10-14 19:14:01 -06:00
|
|
|
}
|
|
|
|
} else {
|
2009-03-03 19:25:07 -07:00
|
|
|
P.expect(token.DEFAULT);
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2008-10-14 19:14:01 -06:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
colon := P.expect(token.COLON);
|
|
|
|
body := P.parseStatementList();
|
|
|
|
|
|
|
|
return &ast.CommClause{loc, tok, lhs, rhs, colon, body};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseSelectStmt() *ast.SelectStmt {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
2009-03-25 13:45:06 -06:00
|
|
|
defer un(trace(P, "SelectStmt"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
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());
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
rbrace := P.expect(token.RBRACE);
|
2009-02-04 19:28:41 -07:00
|
|
|
P.opt_semi = true;
|
2009-03-25 13:45:06 -06:00
|
|
|
body := &ast.BlockStmt{lbrace, asStmtList(cases), rbrace};
|
2009-02-04 19:28:41 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.SelectStmt{pos, body};
|
2009-03-20 18:18:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseForStmt() ast.Stmt {
|
2009-03-20 18:18:48 -06:00
|
|
|
if P.trace {
|
2009-03-25 13:45:06 -06:00
|
|
|
defer un(trace(P, "ForStmt"));
|
2009-03-20 18:18:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pos := P.expect(token.FOR);
|
|
|
|
s1, s2, s3 := P.parseControlClause(true);
|
2009-03-25 13:45:06 -06:00
|
|
|
body := P.parseBlockStmt();
|
2009-03-20 18:18:48 -06:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
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 {
|
2009-03-26 17:10:07 -06:00
|
|
|
P.error(as.TokPos, "'=' or ':=' expected");
|
2009-03-25 13:45:06 -06:00
|
|
|
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(as.Lhs[0].Pos(), "expected 1 or 2 expressions");
|
|
|
|
return &ast.BadStmt{pos};
|
|
|
|
}
|
|
|
|
// check rhs
|
|
|
|
if len(as.Rhs) != 1 {
|
|
|
|
P.error(as.Rhs[0].Pos(), "expected 1 expressions");
|
|
|
|
return &ast.BadStmt{pos};
|
|
|
|
}
|
2009-03-26 17:10:07 -06:00
|
|
|
if rhs, is_unary := as.Rhs[0].(*ast.UnaryExpr); is_unary && rhs.Op == token.RANGE {
|
2009-03-25 13:45:06 -06:00
|
|
|
// rhs is range expression; check lhs
|
2009-03-26 17:10:07 -06:00
|
|
|
return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
|
2009-03-25 13:45:06 -06:00
|
|
|
} else {
|
|
|
|
P.error(s2.Pos(), "range clause expected");
|
|
|
|
return &ast.BadStmt{pos};
|
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
} else {
|
|
|
|
// regular for statement
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.ForStmt{pos, s1, P.asExpr(s2), s3, body};
|
2009-03-20 18:18:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
unreachable();
|
|
|
|
return nil;
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseStatement() ast.Stmt {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Statement"));
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
switch P.tok {
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.CONST, token.TYPE, token.VAR:
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.DeclStmt{P.parseDeclaration()};
|
2009-02-04 19:28:41 -07:00
|
|
|
case
|
2009-03-13 17:59:51 -06:00
|
|
|
// tokens that may start a top-level expression
|
|
|
|
token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand
|
2009-03-03 19:25:07 -07:00
|
|
|
token.LBRACK, token.STRUCT, // composite type
|
2009-03-13 17:59:51 -06:00
|
|
|
token.MUL, token.AND, token.ARROW: // unary operators
|
2009-03-25 13:45:06 -06:00
|
|
|
return P.parseSimpleStmt();
|
2009-03-20 18:18:48 -06:00
|
|
|
case token.GO:
|
2009-03-25 13:45:06 -06:00
|
|
|
return P.parseGoStmt();
|
2009-03-20 18:18:48 -06:00
|
|
|
case token.DEFER:
|
2009-03-25 13:45:06 -06:00
|
|
|
return P.parseDeferStmt();
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.RETURN:
|
2009-03-25 13:45:06 -06:00
|
|
|
return P.parseReturnStmt();
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH:
|
2009-03-25 13:45:06 -06:00
|
|
|
return P.parseBranchStmt(P.tok);
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.LBRACE:
|
2009-03-25 13:45:06 -06:00
|
|
|
return P.parseBlockStmt();
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.IF:
|
2009-03-25 13:45:06 -06:00
|
|
|
return P.parseIfStmt();
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.FOR:
|
2009-03-25 13:45:06 -06:00
|
|
|
return P.parseForStmt();
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.SWITCH:
|
2009-03-25 13:45:06 -06:00
|
|
|
return P.parseSwitchStmt();
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.SELECT:
|
2009-03-25 13:45:06 -06:00
|
|
|
return P.parseSelectStmt();
|
2009-03-13 17:59:51 -06:00
|
|
|
case token.SEMICOLON, token.RBRACE:
|
2009-02-12 17:06:21 -07:00
|
|
|
// don't consume the ";", it is the separator following the empty statement
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.EmptyStmt{P.pos};
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
2009-02-12 17:06:21 -07:00
|
|
|
// no statement found
|
2009-03-20 18:18:48 -06:00
|
|
|
P.error(P.pos, "statement expected");
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.BadStmt{P.pos};
|
2009-02-04 19:28:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-18 17:58:37 -06:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Declarations
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseImportSpec(pos token.Position, doc ast.Comments) *ast.ImportDecl {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "ImportSpec"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-05 18:15:36 -07:00
|
|
|
var ident *ast.Ident;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.PERIOD {
|
2009-03-20 18:18:48 -06:00
|
|
|
P.error(P.pos, `"import ." not yet handled properly`);
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-03-03 19:25:07 -07:00
|
|
|
} else if P.tok == token.IDENT {
|
2009-03-05 18:15:36 -07:00
|
|
|
ident = P.parseIdent();
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
var path []*ast.StringLit;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.STRING {
|
2009-03-25 13:45:06 -06:00
|
|
|
path = P.parseStringList(nil);
|
2008-09-18 17:58:37 -06:00
|
|
|
} else {
|
2009-03-03 19:25:07 -07:00
|
|
|
P.expect(token.STRING); // use expect() error handling
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.ImportDecl{doc, pos, ident, path};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseConstSpec(pos token.Position, doc ast.Comments) *ast.ConstDecl {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "ConstSpec"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-16 21:29:31 -06:00
|
|
|
names := P.parseIdentList(nil);
|
2009-02-27 16:40:17 -07:00
|
|
|
typ := P.tryType();
|
2009-03-16 21:29:31 -06:00
|
|
|
var values []ast.Expr;
|
2009-03-13 17:59:51 -06:00
|
|
|
if typ != nil || P.tok == token.ASSIGN {
|
|
|
|
P.expect(token.ASSIGN);
|
2009-03-16 21:29:31 -06:00
|
|
|
values = P.parseExpressionList();
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.ConstDecl{doc, pos, names, typ, values};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseTypeSpec(pos token.Position, doc ast.Comments) *ast.TypeDecl {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "TypeSpec"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-09-18 17:58:37 -06:00
|
|
|
|
2009-03-05 18:15:36 -07:00
|
|
|
ident := P.parseIdent();
|
2009-02-27 16:40:17 -07:00
|
|
|
typ := P.parseType();
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.TypeDecl{doc, pos, ident, typ};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseVarSpec(pos token.Position, doc ast.Comments) *ast.VarDecl {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "VarSpec"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-16 21:29:31 -06:00
|
|
|
names := P.parseIdentList(nil);
|
2009-03-13 17:59:51 -06:00
|
|
|
typ := P.tryType();
|
2009-03-16 21:29:31 -06:00
|
|
|
var values []ast.Expr;
|
2009-03-13 17:59:51 -06:00
|
|
|
if typ == nil || P.tok == token.ASSIGN {
|
|
|
|
P.expect(token.ASSIGN);
|
2009-03-16 21:29:31 -06:00
|
|
|
values = P.parseExpressionList();
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.VarDecl{doc, pos, names, typ, values};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseSpec(pos token.Position, doc ast.Comments, keyword int) ast.Decl {
|
2009-02-27 16:40:17 -07:00
|
|
|
switch keyword {
|
2009-03-20 18:18:48 -06:00
|
|
|
case token.IMPORT: return P.parseImportSpec(pos, doc);
|
|
|
|
case token.CONST: return P.parseConstSpec(pos, doc);
|
|
|
|
case token.TYPE: return P.parseTypeSpec(pos, doc);
|
|
|
|
case token.VAR: return P.parseVarSpec(pos, doc);
|
2009-01-23 10:44:01 -07:00
|
|
|
}
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
unreachable();
|
|
|
|
return nil;
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseDecl(keyword int) ast.Decl {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Decl"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
doc := P.getDoc();
|
|
|
|
pos := P.expect(keyword);
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.LPAREN {
|
2009-03-20 18:18:48 -06:00
|
|
|
lparen := P.pos;
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2009-02-27 16:40:17 -07:00
|
|
|
list := vector.New(0);
|
2009-03-03 19:25:07 -07:00
|
|
|
for P.tok != token.RPAREN && P.tok != token.EOF {
|
2009-03-20 18:18:48 -06:00
|
|
|
list.Push(P.parseSpec(nopos, nil, keyword));
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.SEMICOLON {
|
2009-02-05 15:22:09 -07:00
|
|
|
P.next();
|
2008-10-09 19:03:16 -06:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-20 18:18:48 -06:00
|
|
|
rparen := P.expect(token.RPAREN);
|
2008-10-10 17:03:32 -06:00
|
|
|
P.opt_semi = true;
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-02-27 16:40:17 -07:00
|
|
|
// convert vector
|
2009-03-05 18:15:36 -07:00
|
|
|
decls := make([]ast.Decl, list.Len());
|
2009-02-27 16:40:17 -07:00
|
|
|
for i := 0; i < list.Len(); i++ {
|
2009-03-05 18:15:36 -07:00
|
|
|
decls[i] = list.At(i).(ast.Decl);
|
2009-02-27 16:40:17 -07:00
|
|
|
}
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return &ast.DeclList{doc, pos, keyword, lparen, decls, rparen};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
return P.parseSpec(pos, doc, keyword);
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-05 18:15:36 -07:00
|
|
|
// Function and method declarations
|
2008-09-19 13:12:28 -06:00
|
|
|
//
|
|
|
|
// func ident (params)
|
|
|
|
// func ident (params) type
|
|
|
|
// func ident (params) (results)
|
|
|
|
// func (recv) ident (params)
|
|
|
|
// func (recv) ident (params) type
|
|
|
|
// func (recv) ident (params) (results)
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseFunctionDecl() *ast.FuncDecl {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "FunctionDecl"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
doc := P.getDoc();
|
|
|
|
pos := P.expect(token.FUNC);
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-05 18:15:36 -07:00
|
|
|
var recv *ast.Field;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.LPAREN {
|
2009-03-20 18:18:48 -06:00
|
|
|
loc := P.pos;
|
2009-02-27 16:40:17 -07:00
|
|
|
tmp := P.parseParameters(true);
|
|
|
|
if len(tmp) == 1 {
|
|
|
|
recv = tmp[0];
|
|
|
|
} else {
|
2009-03-11 13:52:11 -06:00
|
|
|
P.error(loc, "must have exactly one receiver");
|
2008-09-19 13:12:28 -06:00
|
|
|
}
|
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-05 18:15:36 -07:00
|
|
|
ident := P.parseIdent();
|
2009-03-25 13:45:06 -06:00
|
|
|
params, results := P.parseSignature();
|
2008-10-16 13:16:50 -06:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
var body *ast.BlockStmt;
|
2009-03-03 19:25:07 -07:00
|
|
|
if P.tok == token.LBRACE {
|
2009-03-25 13:45:06 -06:00
|
|
|
body = P.parseBlockStmt();
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-25 13:45:06 -06:00
|
|
|
return &ast.FuncDecl{doc, recv, ident, &ast.FunctionType{pos, params, results}, body};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parseDeclaration() ast.Decl {
|
2009-02-05 15:22:09 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Declaration"));
|
2009-02-03 18:44:01 -07:00
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2008-09-18 17:58:37 -06:00
|
|
|
switch P.tok {
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.CONST, token.TYPE, token.VAR:
|
2009-02-27 16:40:17 -07:00
|
|
|
return P.parseDecl(P.tok);
|
2009-03-03 19:25:07 -07:00
|
|
|
case token.FUNC:
|
2009-02-27 16:40:17 -07:00
|
|
|
return P.parseFunctionDecl();
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-11 17:06:17 -06:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
loc := P.pos;
|
2009-03-11 13:52:11 -06:00
|
|
|
P.error(loc, "declaration expected");
|
2009-02-27 16:40:17 -07:00
|
|
|
P.next(); // make progress
|
2009-03-11 13:52:11 -06:00
|
|
|
return &ast.BadDecl{loc};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
2009-03-26 17:10:07 -06:00
|
|
|
// Packages
|
2008-09-18 17:58:37 -06:00
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
// The Mode constants control how much of the source text is parsed.
|
|
|
|
type Mode int;
|
2009-03-12 18:24:03 -06:00
|
|
|
const (
|
2009-03-26 17:10:07 -06:00
|
|
|
ParseEntirePackage Mode = iota;
|
2009-03-12 18:24:03 -06:00
|
|
|
ParseImportDeclsOnly;
|
|
|
|
ParsePackageClauseOnly;
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2009-03-26 17:10:07 -06:00
|
|
|
func (P *parser) parsePackage(mode Mode) *ast.Package {
|
2009-03-05 18:15:36 -07:00
|
|
|
if P.trace {
|
|
|
|
defer un(trace(P, "Program"));
|
|
|
|
}
|
|
|
|
|
2009-03-12 18:24:03 -06:00
|
|
|
// package clause
|
2009-03-20 18:18:48 -06:00
|
|
|
comment := P.getDoc();
|
|
|
|
pos := P.expect(token.PACKAGE);
|
2009-03-12 18:24:03 -06:00
|
|
|
name := P.parseIdent();
|
2009-03-13 17:59:51 -06:00
|
|
|
if P.tok == token.SEMICOLON {
|
|
|
|
// common error
|
2009-03-20 18:18:48 -06:00
|
|
|
P.error(P.pos, "extra semicolon");
|
2009-03-13 17:59:51 -06:00
|
|
|
P.next();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-12 18:24:03 -06:00
|
|
|
var decls []ast.Decl;
|
|
|
|
if mode <= ParseImportDeclsOnly {
|
|
|
|
// import decls
|
|
|
|
list := vector.New(0);
|
|
|
|
for P.tok == token.IMPORT {
|
|
|
|
list.Push(P.parseDecl(token.IMPORT));
|
|
|
|
if P.tok == token.SEMICOLON {
|
|
|
|
P.next();
|
|
|
|
}
|
2009-03-10 19:20:08 -06:00
|
|
|
}
|
2009-02-27 16:40:17 -07:00
|
|
|
|
2009-03-12 18:24:03 -06:00
|
|
|
if mode <= ParseEntirePackage {
|
|
|
|
// rest of package body
|
|
|
|
for P.tok != token.EOF {
|
|
|
|
list.Push(P.parseDeclaration());
|
|
|
|
if P.tok == token.SEMICOLON {
|
|
|
|
P.next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
// convert declaration list
|
2009-03-12 18:24:03 -06:00
|
|
|
decls = make([]ast.Decl, list.Len());
|
|
|
|
for i := 0; i < list.Len(); i++ {
|
|
|
|
decls[i] = list.At(i).(ast.Decl);
|
|
|
|
}
|
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
|
2009-03-20 18:18:48 -06:00
|
|
|
// convert comments list
|
|
|
|
comments := make([]*ast.Comment, P.comments.Len());
|
|
|
|
for i := 0; i < P.comments.Len(); i++ {
|
|
|
|
c := P.comments.At(i);
|
|
|
|
if c != nil {
|
|
|
|
comments[i] = c.(*ast.Comment);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &ast.Package{comment, pos, name, decls, comments};
|
2008-09-18 17:58:37 -06:00
|
|
|
}
|
2009-03-26 17:10:07 -06:00
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Parsing of entire programs.
|
|
|
|
|
|
|
|
// Parse invokes the Go parser. It calls the scanner's Scan method repeatedly
|
|
|
|
// to obtain the token sequence corresponding to the source code. The sequence
|
|
|
|
// is parsed according to Go syntax and the corresponding abstract syntax tree
|
|
|
|
// is constructed. The error handler err will be used to report syntax errors.
|
|
|
|
//
|
|
|
|
// If no syntax errors were encountered (i.e., if the error handler was never
|
|
|
|
// called), the result is a correct AST. If errors were encountered, the AST
|
|
|
|
// may only be constructed partially, with ast.BadX nodes representing the
|
|
|
|
// fragments of source code that contained syntax errors.
|
|
|
|
//
|
|
|
|
// The amount of source text parsed can be controlled with the mode parameter.
|
|
|
|
// The flags parameter controls optional parser functionality such as tracing.
|
|
|
|
//
|
|
|
|
func Parse(scanner Scanner, err ErrorHandler, mode Mode, flags uint) *ast.Package {
|
|
|
|
// initialize parser state
|
|
|
|
var p parser;
|
|
|
|
p.scanner = scanner;
|
|
|
|
p.err = err;
|
|
|
|
p.trace = flags & Trace != 0;
|
|
|
|
p.comments.Init(0);
|
|
|
|
p.next();
|
|
|
|
|
|
|
|
// parse program
|
|
|
|
return p.parsePackage(mode);
|
|
|
|
}
|