mirror of
https://github.com/golang/go
synced 2024-11-23 02:20:03 -07:00
- use new scanner error handling code
R=rsc DELTA=109 (0 added, 87 deleted, 22 changed) OCL=31573 CL=31603
This commit is contained in:
parent
a010d45caa
commit
2d58fa6f18
@ -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
|
// Grammar verification
|
||||||
|
|
||||||
@ -181,30 +129,13 @@ func isLexical(name string) bool {
|
|||||||
|
|
||||||
|
|
||||||
type verifier struct {
|
type verifier struct {
|
||||||
errors vector.Vector;
|
scanner.ErrorVector;
|
||||||
worklist vector.Vector;
|
worklist vector.Vector;
|
||||||
reached Grammar; // set of productions reached from (and including) the root production
|
reached Grammar; // set of productions reached from (and including) the root production
|
||||||
grammar Grammar;
|
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) {
|
func (v *verifier) push(prod *Production) {
|
||||||
name := prod.Name.String;
|
name := prod.Name.String;
|
||||||
if _, found := v.reached[name]; !found {
|
if _, found := v.reached[name]; !found {
|
||||||
@ -217,7 +148,7 @@ func (v *verifier) push(prod *Production) {
|
|||||||
func (v *verifier) verifyChar(x *Token) int {
|
func (v *verifier) verifyChar(x *Token) int {
|
||||||
s := x.String;
|
s := x.String;
|
||||||
if utf8.RuneCountInString(s) != 1 {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
ch, _ := utf8.DecodeRuneInString(s);
|
ch, _ := utf8.DecodeRuneInString(s);
|
||||||
@ -243,12 +174,12 @@ func (v *verifier) verifyExpr(expr Expression, lexical bool) {
|
|||||||
if prod, found := v.grammar[x.String]; found {
|
if prod, found := v.grammar[x.String]; found {
|
||||||
v.push(prod);
|
v.push(prod);
|
||||||
} else {
|
} else {
|
||||||
v.error(x.Pos(), "missing production " + x.String);
|
v.Error(x.Pos(), "missing production " + x.String);
|
||||||
}
|
}
|
||||||
// within a lexical production references
|
// within a lexical production references
|
||||||
// to non-lexical productions are invalid
|
// to non-lexical productions are invalid
|
||||||
if lexical && !isLexical(x.String) {
|
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:
|
case *Token:
|
||||||
// nothing to do for now
|
// nothing to do for now
|
||||||
@ -256,7 +187,7 @@ func (v *verifier) verifyExpr(expr Expression, lexical bool) {
|
|||||||
i := v.verifyChar(x.Begin);
|
i := v.verifyChar(x.Begin);
|
||||||
j := v.verifyChar(x.End);
|
j := v.verifyChar(x.End);
|
||||||
if i >= j {
|
if i >= j {
|
||||||
v.error(x.Pos(), "decreasing character range");
|
v.Error(x.Pos(), "decreasing character range");
|
||||||
}
|
}
|
||||||
case *Group:
|
case *Group:
|
||||||
v.verifyExpr(x.Body, lexical);
|
v.verifyExpr(x.Body, lexical);
|
||||||
@ -275,12 +206,12 @@ func (v *verifier) verify(grammar Grammar, start string) {
|
|||||||
root, found := grammar[start];
|
root, found := grammar[start];
|
||||||
if !found {
|
if !found {
|
||||||
var noPos token.Position;
|
var noPos token.Position;
|
||||||
v.error(noPos, "no start production " + start);
|
v.Error(noPos, "no start production " + start);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize verifier
|
// initialize verifier
|
||||||
v.errors.Init(0);
|
v.ErrorVector.Init();
|
||||||
v.worklist.Init(0);
|
v.worklist.Init(0);
|
||||||
v.reached = make(Grammar);
|
v.reached = make(Grammar);
|
||||||
v.grammar = grammar;
|
v.grammar = grammar;
|
||||||
@ -296,7 +227,7 @@ func (v *verifier) verify(grammar Grammar, start string) {
|
|||||||
if len(v.reached) < len(v.grammar) {
|
if len(v.reached) < len(v.grammar) {
|
||||||
for name, prod := range v.grammar {
|
for name, prod := range v.grammar {
|
||||||
if _, found := v.reached[name]; !found {
|
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 {
|
func Verify(grammar Grammar, start string) os.Error {
|
||||||
var v verifier;
|
var v verifier;
|
||||||
v.verify(grammar, start);
|
v.verify(grammar, start);
|
||||||
return makeErrorList(&v.errors);
|
return v.GetError(scanner.Sorted);
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,8 @@ var grammars = []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func check(t *testing.T, src []byte) {
|
func check(t *testing.T, filename string, src []byte) {
|
||||||
grammar, err := Parse(src);
|
grammar, err := Parse(filename, src);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Parse(%s) failed: %v", src, err);
|
t.Errorf("Parse(%s) failed: %v", src, err);
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ func check(t *testing.T, src []byte) {
|
|||||||
|
|
||||||
func TestGrammars(t *testing.T) {
|
func TestGrammars(t *testing.T) {
|
||||||
for _, src := range grammars {
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err);
|
t.Fatal(err);
|
||||||
}
|
}
|
||||||
check(t, src);
|
check(t, filename, src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
|
|
||||||
|
|
||||||
type parser struct {
|
type parser struct {
|
||||||
errors vector.Vector;
|
scanner.ErrorVector;
|
||||||
scanner scanner.Scanner;
|
scanner scanner.Scanner;
|
||||||
pos token.Position; // token position
|
pos token.Position; // token position
|
||||||
tok token.Token; // one token look-ahead
|
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) {
|
func (p *parser) errorExpected(pos token.Position, msg string) {
|
||||||
msg = "expected " + msg;
|
msg = "expected " + msg;
|
||||||
if pos.Offset == p.pos.Offset {
|
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
|
// initialize parser
|
||||||
p.errors.Init(0);
|
p.ErrorVector.Init();
|
||||||
p.scanner.Init(src, p, 0);
|
p.scanner.Init(filename, src, p, 0);
|
||||||
p.next(); // initializes pos, tok, lit
|
p.next(); // initializes pos, tok, lit
|
||||||
|
|
||||||
grammar := make(Grammar);
|
grammar := make(Grammar);
|
||||||
@ -233,8 +215,8 @@ func (p *parser) parse(src []byte) Grammar {
|
|||||||
// for incorrect syntax and if a production is declared
|
// for incorrect syntax and if a production is declared
|
||||||
// more than once.
|
// more than once.
|
||||||
//
|
//
|
||||||
func Parse(src []byte) (Grammar, os.Error) {
|
func Parse(filename string, src []byte) (Grammar, os.Error) {
|
||||||
var p parser;
|
var p parser;
|
||||||
grammar := p.parse(src);
|
grammar := p.parse(filename, src);
|
||||||
return grammar, makeErrorList(&p.errors);
|
return grammar, p.GetError(scanner.Sorted);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user