lang: ast, gapi, interfaces, parser: Print line numbers on error

This adds an initial implementation of printing line numbers on type
unification errors. It also attempts to print a visual position
indicator for most scenarios.

This patch was started by Felix Frank and finished by James Shubin.

Co-authored-by: Felix Frank <Felix.Frank.de@gmail.com>
This commit is contained in:
James Shubin
2025-02-25 20:15:02 -05:00
parent f754bbbf90
commit d7ecc72b41
20 changed files with 714 additions and 172 deletions

View File

@@ -35,6 +35,7 @@ import (
"fmt"
"io"
"reflect"
"regexp"
"strings"
"testing"
@@ -45,8 +46,9 @@ import (
langUtil "github.com/purpleidea/mgmt/lang/util"
"github.com/purpleidea/mgmt/util"
"github.com/davecgh/go-spew/spew"
godiff "github.com/kylelemons/godebug/diff"
"github.com/kylelemons/godebug/pretty"
"github.com/sanity-io/litter"
)
func TestLexParse0(t *testing.T) {
@@ -2221,6 +2223,36 @@ func TestLexParse0(t *testing.T) {
}
// double check because DeepEqual is different since the func exists
lo := &litter.Options{
//Compact: false,
StripPackageNames: true,
HidePrivateFields: true,
HideZeroValues: true,
FieldExclusions: regexp.MustCompile(`^(Textarea)$`),
//FieldFilter func(reflect.StructField, reflect.Value) bool
//HomePackage string
//Separator string
DisablePointerReplacement: true,
}
// The litter package adds pointer comments everywhere,
// which make it not diff correctly. Clean them here!
pattern := regexp.MustCompile(`\ \/\/\ p[0-9]+$`) // the p0, p1 comments...
clean := func(s string) string {
lines := []string{}
for _, line := range strings.Split(s, "\n") {
s := pattern.ReplaceAllLiteralString(line, "")
lines = append(lines, s)
}
return strings.Join(lines, "\n")
}
lo1 := clean(lo.Sdump(exp))
lo2 := clean(lo.Sdump(xast))
if lo1 == lo2 { // simple diff
return
}
// more details, for tricky cases:
diffable := &pretty.Config{
Diffable: true,
@@ -2228,18 +2260,22 @@ func TestLexParse0(t *testing.T) {
//PrintStringers: false, // always false!
//PrintTextMarshalers: false,
SkipZeroFields: true,
//Formatter: map[reflect.Type]interface{}{
// reflect.TypeOf(ast.Textarea{}): func(x ast.Textarea) string {
// return ""
// },
//},
}
diff := diffable.Compare(exp, xast)
if diff == "" { // bonus
return
}
diff = godiff.Diff(lo1, lo2) // for printing
t.Errorf("test #%d: AST did not match expected", index)
// TODO: consider making our own recursive print function
t.Logf("test #%d: actual: \n\n%s\n", index, spew.Sdump(xast))
t.Logf("test #%d: expected: \n\n%s", index, spew.Sdump(exp))
t.Logf("test #%d: actual: \n\n%s\n", index, diffable.Sprint(xast))
t.Logf("test #%d: expected: \n\n%s", index, diffable.Sprint(exp))
t.Logf("test #%d: actual: \n\n%s\n", index, lo1)
t.Logf("test #%d: expected: \n\n%s", index, lo2)
t.Logf("test #%d: diff:\n%s", index, diff)
})
}