From: Robert Griesemer Date: Tue, 14 Jul 2009 17:45:43 +0000 (-0700) Subject: - use new scanner error handling code X-Git-Tag: weekly.2009-11-06~1155 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=2d58fa6f18a9b7e798301e244abb3df2314a21db;p=gostls13.git - use new scanner error handling code R=rsc DELTA=109 (0 added, 87 deleted, 22 changed) OCL=31573 CL=31603 --- diff --git a/src/pkg/ebnf/ebnf.go b/src/pkg/ebnf/ebnf.go index c54f0f8dae..368a3c8123 100644 --- a/src/pkg/ebnf/ebnf.go +++ b/src/pkg/ebnf/ebnf.go @@ -119,58 +119,6 @@ func (p *Production) Pos() token.Position { } -// ---------------------------------------------------------------------------- -// Error handling - -// TODO(gri) This is the same code as in datafmt and go/parser. -// Should factor this out as part of some parsing framework -// that could also deal with reading various input sources. - -// Error describes an individual error. The position Pos, if valid, -// indicates the format source position the error relates to. The -// error is specified with the Msg string. -// -type Error struct { - Pos token.Position; - Msg string; -} - - -// String returns the error message. If the error contains (line, column) -// position information, it starts with "line:column: ", otherwise it -// starts with a blank " ". -// -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; -} - - -// An ErrorList is a list of errors encountered during parsing. -type ErrorList []*Error - - -// ErrorList implements SortInterface and the os.Error interface. - -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); -} - - // ---------------------------------------------------------------------------- // Grammar verification @@ -181,30 +129,13 @@ func isLexical(name string) bool { type verifier struct { - errors vector.Vector; + scanner.ErrorVector; worklist vector.Vector; reached Grammar; // set of productions reached from (and including) the root production grammar Grammar; } -func (v *verifier) error(pos token.Position, msg string) { - v.errors.Push(&Error{pos, msg}); -} - - -func makeErrorList(v *vector.Vector) os.Error { - if v.Len() > 0 { - errors := make(ErrorList, v.Len()); - for i := 0; i < v.Len(); i++ { - errors[i] = v.At(i).(*Error); - } - return errors; - } - return nil; -} - - func (v *verifier) push(prod *Production) { name := prod.Name.String; if _, found := v.reached[name]; !found { @@ -217,7 +148,7 @@ func (v *verifier) push(prod *Production) { func (v *verifier) verifyChar(x *Token) int { s := x.String; if utf8.RuneCountInString(s) != 1 { - v.error(x.Pos(), "single char expected, found " + s); + v.Error(x.Pos(), "single char expected, found " + s); return 0; } ch, _ := utf8.DecodeRuneInString(s); @@ -243,12 +174,12 @@ func (v *verifier) verifyExpr(expr Expression, lexical bool) { if prod, found := v.grammar[x.String]; found { v.push(prod); } else { - v.error(x.Pos(), "missing production " + x.String); + v.Error(x.Pos(), "missing production " + x.String); } // within a lexical production references // to non-lexical productions are invalid if lexical && !isLexical(x.String) { - v.error(x.Pos(), "reference to non-lexical production " + x.String); + v.Error(x.Pos(), "reference to non-lexical production " + x.String); } case *Token: // nothing to do for now @@ -256,7 +187,7 @@ func (v *verifier) verifyExpr(expr Expression, lexical bool) { i := v.verifyChar(x.Begin); j := v.verifyChar(x.End); if i >= j { - v.error(x.Pos(), "decreasing character range"); + v.Error(x.Pos(), "decreasing character range"); } case *Group: v.verifyExpr(x.Body, lexical); @@ -275,12 +206,12 @@ func (v *verifier) verify(grammar Grammar, start string) { root, found := grammar[start]; if !found { var noPos token.Position; - v.error(noPos, "no start production " + start); + v.Error(noPos, "no start production " + start); return; } // initialize verifier - v.errors.Init(0); + v.ErrorVector.Init(); v.worklist.Init(0); v.reached = make(Grammar); v.grammar = grammar; @@ -296,7 +227,7 @@ func (v *verifier) verify(grammar Grammar, start string) { if len(v.reached) < len(v.grammar) { for name, prod := range v.grammar { if _, found := v.reached[name]; !found { - v.error(prod.Pos(), name + " is unreachable"); + v.Error(prod.Pos(), name + " is unreachable"); } } } @@ -311,5 +242,5 @@ func (v *verifier) verify(grammar Grammar, start string) { func Verify(grammar Grammar, start string) os.Error { var v verifier; v.verify(grammar, start); - return makeErrorList(&v.errors); + return v.GetError(scanner.Sorted); } diff --git a/src/pkg/ebnf/ebnf_test.go b/src/pkg/ebnf/ebnf_test.go index ab4ea4c955..9bcb5d91f8 100644 --- a/src/pkg/ebnf/ebnf_test.go +++ b/src/pkg/ebnf/ebnf_test.go @@ -41,8 +41,8 @@ var grammars = []string { } -func check(t *testing.T, src []byte) { - grammar, err := Parse(src); +func check(t *testing.T, filename string, src []byte) { + grammar, err := Parse(filename, src); if err != nil { t.Errorf("Parse(%s) failed: %v", src, err); } @@ -54,7 +54,7 @@ func check(t *testing.T, src []byte) { func TestGrammars(t *testing.T) { for _, src := range grammars { - check(t, strings.Bytes(src)); + check(t, "", strings.Bytes(src)); } } @@ -70,6 +70,6 @@ func TestFiles(t *testing.T) { if err != nil { t.Fatal(err); } - check(t, src); + check(t, filename, src); } } diff --git a/src/pkg/ebnf/parser.go b/src/pkg/ebnf/parser.go index 84905d5fe5..e621c4d89d 100644 --- a/src/pkg/ebnf/parser.go +++ b/src/pkg/ebnf/parser.go @@ -19,7 +19,7 @@ import ( type parser struct { - errors vector.Vector; + scanner.ErrorVector; scanner scanner.Scanner; pos token.Position; // token position tok token.Token; // one token look-ahead @@ -37,24 +37,6 @@ func (p *parser) next() { } -func (p *parser) init(src []byte) { - p.errors.Init(0); - p.scanner.Init(src, p, 0); - p.next(); // initializes pos, tok, lit -} - - -// The parser implements scanner.Error. -func (p *parser) Error(pos token.Position, msg string) { - // Do not collect errors that are on the same line as the previous - // error 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) errorExpected(pos token.Position, msg string) { msg = "expected " + msg; if pos.Offset == p.pos.Offset { @@ -207,10 +189,10 @@ func (p *parser) parseProduction() *Production { } -func (p *parser) parse(src []byte) Grammar { +func (p *parser) parse(filename string, src []byte) Grammar { // initialize parser - p.errors.Init(0); - p.scanner.Init(src, p, 0); + p.ErrorVector.Init(); + p.scanner.Init(filename, src, p, 0); p.next(); // initializes pos, tok, lit grammar := make(Grammar); @@ -233,8 +215,8 @@ func (p *parser) parse(src []byte) Grammar { // for incorrect syntax and if a production is declared // more than once. // -func Parse(src []byte) (Grammar, os.Error) { +func Parse(filename string, src []byte) (Grammar, os.Error) { var p parser; - grammar := p.parse(src); - return grammar, makeErrorList(&p.errors); + grammar := p.parse(filename, src); + return grammar, p.GetError(scanner.Sorted); }