miller/pkg/parsing/errors/errors.go
Stephen Kitt f0a7c5832f
Performance and style fixes (#1981)
* Switch to integer ranges in for loops

Signed-off-by: Stephen Kitt <steve@sk2.org>

* Switch to slices functions where appropriate

A number of utility functions can be replaced outright; since Miller
can technically be used as a library, these are deprecated rather than
removed. go:fix directives ensure that they can be replaced
automatically.

Signed-off-by: Stephen Kitt <steve@sk2.org>

* Switch to reflect.TypeFor

This is slightly more efficient than TypeOf when the type is known at
compile time.

Signed-off-by: Stephen Kitt <steve@sk2.org>

* Switch to strings.SplitSeq instead of strings.Split

SplitSeq results in fewer allocations.

Signed-off-by: Stephen Kitt <steve@sk2.org>

* Drop obsolete build directives

Signed-off-by: Stephen Kitt <steve@sk2.org>

* Use min/max instead of explicit comparisons

Signed-off-by: Stephen Kitt <steve@sk2.org>

* Append slices instead of looping

Signed-off-by: Stephen Kitt <steve@sk2.org>

---------

Signed-off-by: Stephen Kitt <steve@sk2.org>
2026-02-18 09:19:31 -05:00

95 lines
2.2 KiB
Go

// ================================================================
// During the Miller build, after GOCC codegen and Go compile, this is copied
// over the top of GOCC codegen so that we can customize handling of error
// messages.
//
// Source: pkg/parsing/errors.go.template
// Destination: pkg/parsing/errors/errors.go
// ================================================================
package errors
import (
"fmt"
"slices"
"strings"
"github.com/johnkerl/miller/v6/pkg/parsing/token"
)
type ErrorSymbol interface {
}
type Error struct {
Err error
ErrorToken *token.Token
ErrorSymbols []ErrorSymbol
ExpectedTokens []string
StackTop int
}
func (e *Error) String() string {
w := new(strings.Builder)
fmt.Fprintf(w, "Error")
if e.Err != nil {
fmt.Fprintf(w, " %s\n", e.Err)
} else {
fmt.Fprintf(w, "\n")
}
fmt.Fprintf(w, "Token: type=%d, lit=%s\n", e.ErrorToken.Type, e.ErrorToken.Lit)
fmt.Fprintf(w, "Pos: offset=%d, line=%d, column=%d\n", e.ErrorToken.Pos.Offset, e.ErrorToken.Pos.Line, e.ErrorToken.Pos.Column)
fmt.Fprintf(w, "Expected one of: ")
for _, sym := range e.ExpectedTokens {
fmt.Fprintf(w, "%s ", sym)
}
fmt.Fprintf(w, "ErrorSymbol:\n")
for _, sym := range e.ErrorSymbols {
fmt.Fprintf(w, "%v\n", sym)
}
return w.String()
}
func (e *Error) Error() string {
w := new(strings.Builder)
fmt.Fprintf(
w,
"Parse error on token \"%s\" at line %d column %d.\n",
string(e.ErrorToken.Lit),
e.ErrorToken.Pos.Line,
e.ErrorToken.Pos.Column,
)
if e.Err != nil {
fmt.Fprintf(w, "%+v\n", e.Err)
} else {
suggestSemicolons := slices.Contains(e.ExpectedTokens, ";")
if suggestSemicolons {
fmt.Fprintf(w, "Please check for missing semicolon.\n")
}
fmt.Fprintf(w, "Expected one of:\n")
//for _, expected := range e.ExpectedTokens {
// fmt.Fprintf(w, "%s ", expected)
//}
// Print a carriage return every so often, in case there are many possible
// next tokens.
line := ""
for _, expected := range e.ExpectedTokens {
if line != "" {
line += " "
}
line += expected
if len(line) > 70 {
fmt.Fprintf(w, " %s\n", line)
line = ""
}
}
if line != "" {
fmt.Fprintf(w, " %s\n", line)
}
}
return w.String()
}