build: return ErrorList type
Adds a very similar interface to go/scanner package for returning a list of errors. Updates #34
This commit is contained in:
22
build/cli.go
22
build/cli.go
@@ -14,6 +14,7 @@ import (
|
|||||||
// Config contains options for an avo main function.
|
// Config contains options for an avo main function.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ErrOut io.Writer
|
ErrOut io.Writer
|
||||||
|
MaxErrors int // max errors to report; 0 means unlimited
|
||||||
CPUProfile io.WriteCloser
|
CPUProfile io.WriteCloser
|
||||||
Passes []pass.Interface
|
Passes []pass.Interface
|
||||||
}
|
}
|
||||||
@@ -33,11 +34,9 @@ func Main(cfg *Config, context *Context) int {
|
|||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
|
|
||||||
f, errs := context.Result()
|
f, err := context.Result()
|
||||||
if errs != nil {
|
if err != nil {
|
||||||
for _, err := range errs {
|
LogError(diag, err, cfg.MaxErrors)
|
||||||
diag.Println(err)
|
|
||||||
}
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +52,7 @@ func Main(cfg *Config, context *Context) int {
|
|||||||
// Flags represents CLI flags for an avo program.
|
// Flags represents CLI flags for an avo program.
|
||||||
type Flags struct {
|
type Flags struct {
|
||||||
errout *outputValue
|
errout *outputValue
|
||||||
|
allerrors bool
|
||||||
cpuprof *outputValue
|
cpuprof *outputValue
|
||||||
printers []*printerValue
|
printers []*printerValue
|
||||||
}
|
}
|
||||||
@@ -64,6 +64,8 @@ func NewFlags(fs *flag.FlagSet) *Flags {
|
|||||||
f.errout = newOutputValue(os.Stderr)
|
f.errout = newOutputValue(os.Stderr)
|
||||||
fs.Var(f.errout, "log", "diagnostics output")
|
fs.Var(f.errout, "log", "diagnostics output")
|
||||||
|
|
||||||
|
fs.BoolVar(&f.allerrors, "e", false, "no limit on number of errors reported")
|
||||||
|
|
||||||
f.cpuprof = newOutputValue(nil)
|
f.cpuprof = newOutputValue(nil)
|
||||||
fs.Var(f.cpuprof, "cpuprofile", "write cpu profile to `file`")
|
fs.Var(f.cpuprof, "cpuprofile", "write cpu profile to `file`")
|
||||||
|
|
||||||
@@ -88,11 +90,19 @@ func (f *Flags) Config() *Config {
|
|||||||
passes = append(passes, p)
|
passes = append(passes, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Config{
|
|
||||||
|
cfg := &Config{
|
||||||
ErrOut: f.errout.w,
|
ErrOut: f.errout.w,
|
||||||
|
MaxErrors: 10,
|
||||||
CPUProfile: f.cpuprof.w,
|
CPUProfile: f.cpuprof.w,
|
||||||
Passes: passes,
|
Passes: passes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if f.allerrors {
|
||||||
|
cfg.MaxErrors = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
type outputValue struct {
|
type outputValue struct {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ type Context struct {
|
|||||||
file *avo.File
|
file *avo.File
|
||||||
function *avo.Function
|
function *avo.Function
|
||||||
global *avo.Global
|
global *avo.Global
|
||||||
errs []error
|
errs ErrorList
|
||||||
reg.Collection
|
reg.Collection
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,8 +176,7 @@ func (c *Context) activeglobal() *avo.Global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) adderror(err error) {
|
func (c *Context) adderror(err error) {
|
||||||
e := exterr(err)
|
c.errs.addext(err)
|
||||||
c.errs = append(c.errs, e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) adderrormessage(msg string) {
|
func (c *Context) adderrormessage(msg string) {
|
||||||
@@ -185,6 +184,6 @@ func (c *Context) adderrormessage(msg string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Result returns the built file and any accumulated errors.
|
// Result returns the built file and any accumulated errors.
|
||||||
func (c *Context) Result() (*avo.File, []error) {
|
func (c *Context) Result() (*avo.File, error) {
|
||||||
return c.file, c.errs
|
return c.file, c.errs.Err()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/mmcloughlin/avo/internal/stack"
|
"github.com/mmcloughlin/avo/internal/stack"
|
||||||
"github.com/mmcloughlin/avo/src"
|
"github.com/mmcloughlin/avo/src"
|
||||||
)
|
)
|
||||||
@@ -28,3 +31,53 @@ func (e Error) Error() string {
|
|||||||
}
|
}
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrorList is a collection of errors for a source file.
|
||||||
|
type ErrorList []Error
|
||||||
|
|
||||||
|
// Add appends an error to the list.
|
||||||
|
func (e *ErrorList) Add(err Error) {
|
||||||
|
*e = append(*e, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// addext appends an error to the list, tagged with the
|
||||||
|
func (e *ErrorList) addext(err error) {
|
||||||
|
e.Add(exterr(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err returns an error equivalent to this error list.
|
||||||
|
// If the list is empty, Err returns nil.
|
||||||
|
func (e ErrorList) Err() error {
|
||||||
|
if len(e) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ErrorList implements the error interface.
|
||||||
|
func (e ErrorList) Error() string {
|
||||||
|
switch len(e) {
|
||||||
|
case 0:
|
||||||
|
return "no errors"
|
||||||
|
case 1:
|
||||||
|
return e[0].Error()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s (and %d more errors)", e[0], len(e)-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogError logs a list of errors, one error per line, if the err parameter is
|
||||||
|
// an ErrorList. Otherwise it just logs the err string. Reports at most max
|
||||||
|
// errors, or unlimited if max is 0.
|
||||||
|
func LogError(l *log.Logger, err error, max int) {
|
||||||
|
if list, ok := err.(ErrorList); ok {
|
||||||
|
for i, e := range list {
|
||||||
|
l.Printf("%s\n", e)
|
||||||
|
if max > 0 && i == max {
|
||||||
|
l.Print("too many errors")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
l.Printf("%s\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package pass_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mmcloughlin/avo/internal/test"
|
||||||
"github.com/mmcloughlin/avo/reg"
|
"github.com/mmcloughlin/avo/reg"
|
||||||
|
|
||||||
"github.com/mmcloughlin/avo/pass"
|
"github.com/mmcloughlin/avo/pass"
|
||||||
@@ -57,11 +58,9 @@ func AssertRegistersMatchSet(t *testing.T, rs []reg.Register, s reg.Set) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ConstructLiveness(t *testing.T, ctx *build.Context) *avo.Function {
|
func ConstructLiveness(t *testing.T, ctx *build.Context) *avo.Function {
|
||||||
f, errs := ctx.Result()
|
f, err := ctx.Result()
|
||||||
if errs != nil {
|
if err != nil {
|
||||||
for _, err := range errs {
|
build.LogError(test.Logger(t), err, 0)
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user