package synchk

import (
	"go/parser"
	"go/scanner"
	"go/token"
	"gosubli.me/mg"
)

type SynChk struct {
	Files []FileRef
}

type FileRef struct {
	Fn  string
	Src string
}

type Error struct {
	Fn      string
	Line    int
	Column  int
	Message string
}

type Res struct {
	Errors []Error
}

func (s *SynChk) Call() (interface{}, string) {
	fset := token.NewFileSet()
	res := Res{
		Errors: []Error{},
	}

	for _, f := range s.Files {
		if f.Fn == "" && f.Src == "" {
			continue
		}

		var src []byte
		if f.Src != "" {
			src = []byte(f.Src)
		}

		_, err := parser.ParseFile(fset, f.Fn, src, parser.DeclarationErrors)
		if el, ok := err.(scanner.ErrorList); ok {
			for _, e := range el {
				res.Errors = append(res.Errors, Error{
					Fn:      e.Pos.Filename,
					Line:    e.Pos.Line,
					Column:  e.Pos.Column,
					Message: e.Msg,
				})
			}
		}
	}

	return res, ""
}

func init() {
	mg.Register("synchk", func(_ *mg.Broker) mg.Caller {
		return &SynChk{}
	})
}

package synchk

import (
	"gosubli.me/mg"
	"gosubli.me/mg/sa"
)

type SynChk struct {
	Files []FileRef
}

type FileRef struct {
	Fn  string
	Src string
}

type Res struct {
	Errors []*sa.Error
}

func (s *SynChk) Call() (interface{}, string) {
	res := Res{}
	for _, f := range s.Files {
		if f, _ := sa.Parse(f.Fn, []byte(f.Src)); f != nil {
			res.Errors = append(res.Errors, f.Errors...)
		}
	}
	return res, ""
}

func init() {
	mg.Register("synchk", func(_ *mg.Broker) mg.Caller {
		return &SynChk{}
	})
}

Use pkg sa to parse the files being syntax checked. It gives us cached parsing and error lists for free.
Use pkg sa to parse the files being syntax checked. It gives us cached parsing and error lists for free.
