summaryrefslogtreecommitdiff
path: root/src/lib/go/parser/parser.go
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2009-05-18 14:59:16 -0700
committerRobert Griesemer <gri@golang.org>2009-05-18 14:59:16 -0700
commitd4383f34051f1b4f799e413f7be57587f40affa1 (patch)
treeedfd6ba7cec1d606d3b6cc2a0e4206214c31b684 /src/lib/go/parser/parser.go
parentc40d14204290410ba56a30eb0457e37a71dae82e (diff)
downloadgolang-d4383f34051f1b4f799e413f7be57587f40affa1.tar.gz
- changed parser to return os.Error, removed ErrorHandler
- added IsValid predicate to token.Position - updated pretty, godoc, gobuild - updated/expanded test cases R=rsc DELTA=265 (97 added, 78 deleted, 90 changed) OCL=28961 CL=29005
Diffstat (limited to 'src/lib/go/parser/parser.go')
-rw-r--r--src/lib/go/parser/parser.go151
1 files changed, 92 insertions, 59 deletions
diff --git a/src/lib/go/parser/parser.go b/src/lib/go/parser/parser.go
index c766526af..8663289f8 100644
--- a/src/lib/go/parser/parser.go
+++ b/src/lib/go/parser/parser.go
@@ -16,16 +16,41 @@ import (
"go/scanner";
"go/token";
"io";
+ "os";
)
-// An implementation of an ErrorHandler may be provided to the parser.
-// If a syntax error is encountered and a handler was installed, Error
-// is called with a position and an error message. The position points
-// to the beginning of the offending token.
+// 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 ErrorHandler interface {
- Error(pos token.Position, msg string);
+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 {
+ return fmt.Sprintf("%d syntax errors", len(p));
}
@@ -36,9 +61,8 @@ type interval struct {
// The parser structure holds the parser's internal state.
type parser struct {
+ errors vector.Vector;
scanner scanner.Scanner;
- err ErrorHandler; // nil if no handler installed
- hasErrors bool;
// Tracing/debugging
mode uint; // parsing mode
@@ -185,11 +209,14 @@ func (p *parser) next() {
}
-func (p *parser) error(pos token.Position, msg string) {
- if p.err != nil {
- p.err.Error(pos, msg);
+// 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});
}
- p.hasErrors = true;
}
@@ -203,7 +230,7 @@ func (p *parser) error_expected(pos token.Position, msg string) {
msg += " " + string(p.lit);
}
}
- p.error(pos, msg);
+ p.Error(pos, msg);
}
@@ -470,7 +497,7 @@ func (p *parser) tryParameterType(ellipsis_ok bool) ast.Expr {
p.next();
if p.tok != token.RPAREN {
// "..." always must be at the very end of a parameter list
- p.error(pos, "expected type, found '...'");
+ p.Error(pos, "expected type, found '...'");
}
return &ast.Ellipsis{pos};
}
@@ -1115,7 +1142,7 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
}
case *ast.ArrayType:
if len, is_ellipsis := t.Len.(*ast.Ellipsis); is_ellipsis {
- p.error(len.Pos(), "expected array length, found '...'");
+ p.Error(len.Pos(), "expected array length, found '...'");
x = &ast.BadExpr{x.Pos()};
}
}
@@ -1223,7 +1250,7 @@ func (p *parser) parseSimpleStmt(label_ok bool) ast.Stmt {
return &ast.LabeledStmt{label, p.parseStatement()};
}
}
- p.error(x[0].Pos(), "illegal label declaration");
+ p.Error(x[0].Pos(), "illegal label declaration");
return &ast.BadStmt{x[0].Pos()};
case
@@ -1236,13 +1263,13 @@ func (p *parser) parseSimpleStmt(label_ok bool) ast.Stmt {
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");
+ 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");
+ p.Error(x[0].Pos(), "only one expression allowed");
// continue with first expression
}
@@ -1343,7 +1370,7 @@ func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
if es, is_expr := s.(*ast.ExprStmt); is_expr {
return p.checkExpr(es.X);
}
- p.error(s.Pos(), "expected condition, found simple statement");
+ p.Error(s.Pos(), "expected condition, found simple statement");
return &ast.BadExpr{s.Pos()};
}
@@ -1846,7 +1873,7 @@ func (p *parser) parsePackage() *ast.Program {
// Don't bother parsing the rest if we had errors already.
// Likely not a Go source file at all.
- if !p.hasErrors && p.mode & PackageClauseOnly == 0 {
+ if p.errors.Len() == 0 && p.mode & PackageClauseOnly == 0 {
// import decls
list := vector.New(0);
for p.tok == token.IMPORT {
@@ -1886,32 +1913,28 @@ func (p *parser) parsePackage() *ast.Program {
// ----------------------------------------------------------------------------
// Parsing of entire programs.
-func readSource(src interface{}, err ErrorHandler) []byte {
- errmsg := "invalid input type (or nil)";
-
- switch s := src.(type) {
- case string:
- return io.StringBytes(s);
- case []byte:
- return s;
- case *io.ByteBuffer:
- // is io.Read, but src is already available in []byte form
- if s != nil {
- return s.Data();
- }
- case io.Reader:
- var buf io.ByteBuffer;
- n, os_err := io.Copy(s, &buf);
- if os_err == nil {
- return buf.Data();
+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;
}
- errmsg = os_err.String();
}
-
- if err != nil {
- err.Error(noPos, errmsg);
- }
- return nil;
+ return nil, os.ErrorString("invalid source");
}
@@ -1919,25 +1942,26 @@ func readSource(src interface{}, err ErrorHandler) []byte {
//
// 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.
//
-// The ErrorHandler err, if not nil, is invoked if src cannot be read and
-// for each syntax error found. The mode parameter controls the amount of
-// source text parsed and other optional parser functionality.
-//
-// Parse returns an AST and the boolean value true if no errors occured;
-// it returns a partial AST (or nil if the source couldn't be read) and
-// the boolean value false to indicate failure.
+// 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.
//
-// If syntax errors were found, the AST may only be constructed partially,
-// with ast.BadX nodes representing the fragments of erroneous source code.
-//
-func Parse(src interface{}, err ErrorHandler, mode uint) (*ast.Program, bool) {
- data := readSource(src, err);
+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.scanner.Init(data, err, mode & ParseComments != 0);
- p.err = err;
+ p.errors.Init(0);
+ p.scanner.Init(data, &p, mode & ParseComments != 0);
p.mode = mode;
p.trace = mode & Trace != 0; // for convenience (p.trace is used frequently)
p.comments.Init(0);
@@ -1946,5 +1970,14 @@ func Parse(src interface{}, err ErrorHandler, mode uint) (*ast.Program, bool) {
// parse program
prog := p.parsePackage();
- return prog, p.scanner.ErrorCount == 0 && !p.hasErrors;
+ // 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;
}