Skip to content

Commit

Permalink
Add filename, line number and column number to error context (#67)
Browse files Browse the repository at this point in the history
* feat: add filename, line number and column number to scanner context

* feat: limit the output error context and add filename to wbnf test command error
  • Loading branch information
ChloePlanet authored Apr 8, 2020
1 parent 6253b1c commit d5b0d9d
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 14 deletions.
4 changes: 3 additions & 1 deletion ast/helpers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package ast

import "github.com/arr-ai/wbnf/parser"
import (
"github.com/arr-ai/wbnf/parser"
)

// Which returns the first child of the branch from the list of names supplied
func Which(b Branch, names ...string) (string, Children) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func test(c *cli.Context) error {
if !g.HasRule(parser.Rule(startingRule)) {
return fmt.Errorf("starting rule '%s' not in test grammar", startingRule)
}
tree, err := g.Parse(parser.Rule(startingRule), parser.NewScanner(input))
tree, err := g.Parse(parser.Rule(startingRule), parser.NewScannerWithFilename(input, source))
if err != nil {
if uci, ok := err.(parser.UnconsumedInputError); ok {
logrus.Warningln("Partial result:")
Expand Down
2 changes: 1 addition & 1 deletion parser/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func UnconsumedInput(residue Scanner, result TreeElement) UnconsumedInputError {
}

func (e UnconsumedInputError) Error() string {
return fmt.Sprintf("unconsumed input: %v", e.residue)
return fmt.Sprintf("unconsumed input\n %v", e.residue.Context(DefaultLimit))
}

func (e UnconsumedInputError) Result() TreeElement { return e.tree }
Expand Down
6 changes: 3 additions & 3 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func getErrorStrings(input *Scanner) string {
text = text[:40] + " ..."
}

return NewScanner(text).Context()
return NewScanner(text).Context(DefaultLimit)
}

func eatRegexp(input *Scanner, re *regexp.Regexp, output *TreeElement) bool {
Expand Down Expand Up @@ -233,7 +233,7 @@ func (p *sParser) Parse(scope Scope, input *Scanner, output *TreeElement) error
}
if ok := eatRegexp(input, p.re, output); !ok {
return newParseError(p.rule, "", scope.GetCutPoint(),
fmt.Errorf("expect: %s", NewScanner(p.t.String()).Context()),
fmt.Errorf("expect: %s", NewScanner(p.t.String()).Context(DefaultLimit)),
fmt.Errorf("actual: %s", getErrorStrings(input)), scope.GetCallStack())
}
return nil
Expand Down Expand Up @@ -261,7 +261,7 @@ func (p *reParser) Parse(scope Scope, input *Scanner, output *TreeElement) error
}
if ok := eatRegexp(input, p.re, output); !ok {
return newParseError(p.rule, "", scope.GetCutPoint(),
fmt.Errorf("expect: %s", NewScanner(p.re.String()).Context()),
fmt.Errorf("expect: %s", NewScanner(p.re.String()).Context(DefaultLimit)),
fmt.Errorf("actual: %s", getErrorStrings(input)), scope.GetCallStack())
}
return nil
Expand Down
37 changes: 33 additions & 4 deletions parser/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ func NewScannerWithFilename(str, filename string) *Scanner {
}

func NewScannerAt(str string, offset, size int) *Scanner {
if offset+size > len(str) {
panic(fmt.Errorf("%d is out of range [:%d]", offset+size, len(str)))
}
return &Scanner{stringSource{origin: &str}, offset, size}
}

Expand All @@ -57,12 +60,35 @@ func (s Scanner) Format(state fmt.State, c rune) {
}
}

func (s Scanner) Context() string {
var (
NoLimit = -1
DefaultLimit = 3
)

func (s Scanner) Context(limitLines int) string {
end := s.sliceStart + s.sliceLength
return fmt.Sprintf("%s\033[1;31m%s\033[0m%s",
s.src.slice(0, s.sliceStart),
lineno, colno := s.Position()

aboveCxt := s.src.slice(0, s.sliceStart)
belowCxt := s.src.slice(end, s.src.length()-end)
if limitLines != NoLimit {
a := strings.Split(aboveCxt, "\n")
if len(a) > limitLines {
aboveCxt = strings.Join(a[len(a)-limitLines-1:], "\n")
}
b := strings.Split(belowCxt, "\n")
if len(b) > limitLines {
belowCxt = strings.Join(b[:limitLines], "\n")
}
}

return fmt.Sprintf("\n%s:%d:%d:\n\n%s\033[1;31m%s\033[0m%s",
s.Filename(),
lineno,
colno,
aboveCxt,
s.slice(),
s.src.slice(end, s.src.length()-end),
belowCxt,
)
}

Expand All @@ -89,6 +115,7 @@ func (s Scanner) Skip(i int) *Scanner {
return &Scanner{s.src, s.sliceStart + i, s.sliceLength - i}
}

// Eat returns a scanner containing the next i bytes and advances s past them.
func (s *Scanner) Eat(i int, eaten *Scanner) *Scanner {
eaten.src = s.src
eaten.sliceStart = s.sliceStart
Expand Down Expand Up @@ -125,7 +152,9 @@ func (s *Scanner) EatRegexp(re *regexp.Regexp, match *Scanner, captures []Scanne
for i := range captures {
captures[i] = *s.Slice(loc[2*i], loc[2*i+1])
}

*s = *s.Skip(skip)

return n, true
}
return 0, false
Expand Down
3 changes: 2 additions & 1 deletion parser/scanner_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package parser

import (
"github.com/stretchr/testify/assert"
"testing"

"github.com/stretchr/testify/assert"
)

func TestScannerLineColumn(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions wbnf/cutpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package wbnf

import (
"fmt"

"github.com/arr-ai/frozen"
"github.com/arr-ai/wbnf/parser"
)
Expand Down
6 changes: 3 additions & 3 deletions wbnf/grammar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func assertParseToNode(t *testing.T, expected parser.Node, rule parser.Rule, inp
if assert.NoError(t, err) {
return parser.AssertEqualNodes(t, expected, v.(parser.Node))
} else {
t.Logf("input: %s", input.Context())
t.Logf("input: %s", input.Context(parser.NoLimit))
}
return false
}
Expand Down Expand Up @@ -175,8 +175,8 @@ func TestExprGrammarGrammar(t *testing.T) {
parsers := Core()
r := parser.NewScanner(exprGrammarSrc)
v, err := parsers.Parse("grammar", r)
require.NoError(t, err, "r=%v\nv=%v", r.Context(), v)
require.Equal(t, len(exprGrammarSrc), r.Offset(), "r=%v\nv=%v", r.Context(), v)
require.NoError(t, err, "r=%v\nv=%v", r.Context(parser.NoLimit), v)
require.Equal(t, len(exprGrammarSrc), r.Offset(), "r=%v\nv=%v", r.Context(parser.NoLimit), v)
assertUnparse(t,
`// Simple expression grammar`+
`expr->@:[-+]`+
Expand Down

0 comments on commit d5b0d9d

Please sign in to comment.