Fix error messages if no parser match found

As mentioned in the comment, this is a workaround for an issue in the parser.
If the parser does not find a match for any of the rules, it returns a bogus
error location.
This commit is contained in:
Torin Sandall
2016-10-24 11:47:51 -07:00
parent 98297212c2
commit 048afcdcf8
5 changed files with 429 additions and 345 deletions
+373 -339
View File
File diff suppressed because it is too large Load Diff
+27 -1
View File
@@ -235,13 +235,39 @@ func ParseStatement(input string) (interface{}, error) {
func ParseStatements(filename, input string) ([]interface{}, error) {
parsed, err := Parse(filename, []byte(input))
if err != nil {
return nil, err
switch err := err.(type) {
case errList:
return nil, convertErrList(filename, err)
default:
return nil, err
}
}
stmts := parsed.([]interface{})
postProcess(filename, stmts)
return stmts, err
}
func convertErrList(filename string, errs errList) error {
r := make(Errors, len(errs))
for i, e := range errs {
switch e := e.(type) {
case *parserError:
r[i] = formatParserError(filename, e)
default:
r[i] = e
}
}
return r
}
func formatParserError(filename string, e *parserError) error {
var prefix string
if filename != "" {
prefix = filename + ":"
}
return fmt.Errorf("%v%v:%v: %v", prefix, e.pos.line, e.pos.col, e.Inner)
}
func parseModule(stmts []interface{}) (*Module, error) {
if len(stmts) == 0 {
+16 -1
View File
@@ -517,6 +517,21 @@ func TestWildcards(t *testing.T) {
)))
}
func TestNoMatchError(t *testing.T) {
mod := `package test
p :- true,
1 != 0, // <-- parse error: no match`
_, err := ParseModule("foo.rego", mod)
expected := "1 error occurred: foo.rego:4:13: no match found, unexpected '/'"
if err.Error() != expected {
t.Fatalf("Bad parse error, expected %v but got: %v", expected, err)
}
}
func assertParse(t *testing.T, msg string, input string, correct func([]interface{})) {
p, err := ParseStatements("", input)
if err != nil {
@@ -542,7 +557,7 @@ func assertParseErrorEquals(t *testing.T, msg string, input string, expected str
return
}
result := err.Error()
// line:col (#): <parser-rule>: <message>
// error occurred: <line>:<col>: <message>
parts := strings.SplitN(result, ":", 4)
result = strings.TrimSpace(parts[len(parts)-1])
+11 -2
View File
@@ -31,10 +31,19 @@ Program <- _ vals:(head:Stmt tail:(ws Stmt)*)? _ EOF {
return buf, nil
}
Stmt <- val:(Package / Import / Rule / Body / Comment) {
Stmt <- val:(Package / Import / Rule / Body / Comment / ParseError) {
return val, nil
}
// Workaround for https://github.com/PuerkitoBio/pigeon/issues/18. Without this,
// the parser returns an error with a bogus position. The workaround is to
// provide a rule that panics on any input. This way, if the rule is ever
// encountered, parsing will stop. The parser will capture a more accurate
// position this way.
ParseError <- . {
panic(fmt.Sprintf("no match found, unexpected '%s'", c.text))
}
Package <- "package" ws val:(Ref / Var) {
// All packages are implicitly declared under the default root document.
path := RefTerm(DefaultRootDocument)
@@ -168,7 +177,7 @@ Rule <- name:Var key:( _ "[" _ Term _ "]" _ )? value:( _ "=" _ Term )? body:( _
return rule, nil
}
Body <- head:Expr tail:( _ "," _ Expr)* {
Body <- head:Expr tail:( _ "," _ (Expr / ParseError))* {
var buf Body
buf = append(buf, head.(*Expr))
for _, s := range tail.([]interface{}) {
+2 -2
View File
@@ -58,7 +58,7 @@ type Runtime struct {
func (rt *Runtime) Start(params *Params) {
if err := rt.init(params); err != nil {
fmt.Println("error initializing runtime:", err)
fmt.Println(err)
os.Exit(1)
}
@@ -79,7 +79,7 @@ func (rt *Runtime) init(params *Params) error {
parsed, err := parseInputs(params.Paths)
if err != nil {
return errors.Wrapf(err, "parse error")
return err
}
// Open data store and load base documents.