Skip to content

Commit

Permalink
add parse error context
Browse files Browse the repository at this point in the history
  • Loading branch information
mattnibs committed Feb 28, 2024
1 parent f361f11 commit 2699090
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 16 deletions.
22 changes: 18 additions & 4 deletions cli/queryflags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/brimdata/zed/compiler"
"github.com/brimdata/zed/compiler/ast"
"github.com/brimdata/zed/compiler/data"
"github.com/brimdata/zed/compiler/parser"
"github.com/brimdata/zed/compiler/semantic"
"github.com/brimdata/zed/pkg/storage"
"github.com/brimdata/zed/zbuf"
Expand All @@ -40,7 +41,8 @@ func (f *Flags) ParseSourcesAndInputs(paths []string) ([]string, ast.Seq, bool,
// Consider a lone argument to be a query if it compiles
// and appears to start with a from or yield operator.
// Otherwise, consider it a file.
if query, err := compiler.Parse(src, f.Includes...); err == nil {
query, err := compiler.Parse(src, f.Includes...)
if err == nil {
if s, err := semantic.Analyze(context.Background(), query, data.NewSource(storage.NewLocalEngine(), nil), nil); err == nil {
if semantic.HasSource(s) {
return nil, query, false, nil
Expand All @@ -50,7 +52,7 @@ func (f *Flags) ParseSourcesAndInputs(paths []string) ([]string, ast.Seq, bool,
}
}
}
return nil, nil, false, singleArgError(src)
return nil, nil, false, singleArgError(src, err)
}
}
query, err := compiler.Parse(src, f.Includes...)
Expand Down Expand Up @@ -78,13 +80,25 @@ func (f *Flags) PrintStats(stats zbuf.Progress) {
}
}

func singleArgError(src string) error {
func singleArgError(src string, err error) error {
var b strings.Builder
b.WriteString("could not invoke zq with a single argument because:")
b.WriteString("\n - the argument did not parse as a valid Zed query")
if len(src) > 20 {
src = src[:20] + "..."
}
fmt.Fprintf(&b, "\n - a file could not be found with the name %q", src)
var perr *parser.Error
if errors.As(err, &perr) {
b.WriteString("\n - the argument could not be compiled as a valid Zed query due to parse error (")
if perr.LineNum > 0 {
fmt.Fprintf(&b, "line %d, ", perr.LineNum)
}
fmt.Fprintf(&b, "column %d):", perr.Column)
for _, l := range strings.Split(perr.ParseErrorContext(), "\n") {
fmt.Fprintf(&b, "\n %s", l)
}
} else {
b.WriteString("\n - the argument did not parse as a valid Zed query")
}
return errors.New(b.String())
}
2 changes: 1 addition & 1 deletion cmd/zq/ztests/from-pool-error.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ outputs:
- name: stderr
data: |
zq: could not invoke zq with a single argument because:
- the argument did not parse as a valid Zed query
- a file could not be found with the name "from ( pool a )"
- the argument did not parse as a valid Zed query
2 changes: 1 addition & 1 deletion cmd/zq/ztests/no-files.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ outputs:
- name: stderr
data: |
zq: could not invoke zq with a single argument because:
- the argument did not parse as a valid Zed query
- a file could not be found with the name "doesnotexist"
- the argument did not parse as a valid Zed query
4 changes: 3 additions & 1 deletion cmd/zq/ztests/single-arg-error.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ outputs:
- name: stderr
data: |
zq: could not invoke zq with a single argument because:
- the argument did not parse as a valid Zed query
- a file could not be found with the name "file sample.zson | c..."
- the argument could not be compiled as a valid Zed query due to parse error (column 25):
file sample.zson | count(
=== ^ ===
25 changes: 16 additions & 9 deletions compiler/parser/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ type Error struct {
Offset int // offset into original source code

filename string // omitted from formatting if ""
lineNum int // zero-based; omitted from formatting if negative
LineNum int // zero-based; omitted from formatting if negative

line string // contains no newlines
column int // zero-based
Column int // zero-based
}

// NewError returns an Error. src is the source code containing the error. If
Expand Down Expand Up @@ -105,10 +105,10 @@ func NewError(src string, sis []SourceInfo, offset int) error {
}
return &Error{
Offset: offset,
LineNum: lineNum,
Column: column,
filename: filename,
lineNum: lineNum,
line: src,
column: column,
}
}

Expand All @@ -119,12 +119,19 @@ func (e *Error) Error() string {
fmt.Fprintf(&b, "in %s ", e.filename)
}
b.WriteString("at ")
if e.lineNum >= 0 {
fmt.Fprintf(&b, "line %d, ", e.lineNum+1)
if e.LineNum >= 0 {
fmt.Fprintf(&b, "line %d, ", e.LineNum+1)
}
fmt.Fprintf(&b, "column %d:\n%s\n", e.column+1, e.line)
for k := 0; k < e.column; k++ {
if k >= e.column-4 && k != e.column-1 {
fmt.Fprintf(&b, "column %d:\n", e.Column+1)
b.WriteString(e.ParseErrorContext())
return b.String()
}

func (e *Error) ParseErrorContext() string {
var b strings.Builder
b.WriteString(e.line + "\n")
for k := 0; k < e.Column; k++ {
if k >= e.Column-4 && k != e.Column-1 {
b.WriteByte('=')
} else {
b.WriteByte(' ')
Expand Down

0 comments on commit 2699090

Please sign in to comment.