lang: Refactor all the highlight helping together

Keep this cleaner and add a bit more.
This commit is contained in:
James Shubin
2025-06-07 00:23:45 -04:00
parent 2b7e9c3200
commit 55eeb50fb4
12 changed files with 35 additions and 28 deletions

View File

@@ -6854,7 +6854,7 @@ func (obj *StmtInclude) SetScope(scope *interfaces.Scope) error {
classScopeFeedback(scope, obj.data.Logf) classScopeFeedback(scope, obj.data.Logf)
} }
err := fmt.Errorf("class `%s` does not exist in this scope", obj.Name) err := fmt.Errorf("class `%s` does not exist in this scope", obj.Name)
return highlightHelper(obj, obj.data.Logf, err) return interfaces.HighlightHelper(obj, obj.data.Logf, err)
} }
class, ok := stmt.(*StmtClass) class, ok := stmt.(*StmtClass)
if !ok { if !ok {
@@ -6863,7 +6863,8 @@ func (obj *StmtInclude) SetScope(scope *interfaces.Scope) error {
// Is it even possible for the signatures to not match? // Is it even possible for the signatures to not match?
if len(class.Args) != len(obj.Args) { if len(class.Args) != len(obj.Args) {
return fmt.Errorf("class `%s` expected %d args but got %d", obj.Name, len(class.Args), len(obj.Args)) err := fmt.Errorf("class `%s` expected %d args but got %d", obj.Name, len(class.Args), len(obj.Args))
return interfaces.HighlightHelper(obj, obj.data.Logf, err)
} }
if obj.class != nil { if obj.class != nil {
@@ -10514,7 +10515,7 @@ func (obj *ExprCall) SetScope(scope *interfaces.Scope, sctx map[string]interface
lambdaScopeFeedback(obj.scope, obj.data.Logf) lambdaScopeFeedback(obj.scope, obj.data.Logf)
} }
err := fmt.Errorf("lambda `$%s` does not exist in this scope", prefixedName) err := fmt.Errorf("lambda `$%s` does not exist in this scope", prefixedName)
return highlightHelper(obj, obj.data.Logf, err) return interfaces.HighlightHelper(obj, obj.data.Logf, err)
} }
target = f target = f
} }
@@ -10531,7 +10532,7 @@ func (obj *ExprCall) SetScope(scope *interfaces.Scope, sctx map[string]interface
functionScopeFeedback(obj.scope, obj.data.Logf) functionScopeFeedback(obj.scope, obj.data.Logf)
} }
err := fmt.Errorf("func `%s` does not exist in this scope", prefixedName) err := fmt.Errorf("func `%s` does not exist in this scope", prefixedName)
return highlightHelper(obj, obj.data.Logf, err) return interfaces.HighlightHelper(obj, obj.data.Logf, err)
} }
target = f target = f
} }
@@ -11284,7 +11285,7 @@ func (obj *ExprVar) SetScope(scope *interfaces.Scope, sctx map[string]interfaces
variableScopeFeedback(obj.scope, obj.data.Logf) variableScopeFeedback(obj.scope, obj.data.Logf)
} }
err := fmt.Errorf("var `$%s` does not exist in this scope", obj.Name) err := fmt.Errorf("var `$%s` does not exist in this scope", obj.Name)
return highlightHelper(obj, obj.data.Logf, err) return interfaces.HighlightHelper(obj, obj.data.Logf, err)
} }
obj.scope.Variables[obj.Name] = target obj.scope.Variables[obj.Name] = target
@@ -11345,7 +11346,7 @@ func (obj *ExprVar) Infer() (*types.Type, []*interfaces.UnificationInvariant, er
expr, exists := obj.scope.Variables[obj.Name] expr, exists := obj.scope.Variables[obj.Name]
if !exists { if !exists {
err := fmt.Errorf("var `%s` does not exist in this scope", obj.Name) err := fmt.Errorf("var `%s` does not exist in this scope", obj.Name)
return nil, nil, highlightHelper(obj, obj.data.Logf, err) return nil, nil, interfaces.HighlightHelper(obj, obj.data.Logf, err)
} }
// This child call to Infer is an outlier to the common pattern where // This child call to Infer is an outlier to the common pattern where

View File

@@ -574,16 +574,3 @@ func classScopeFeedback(scope *interfaces.Scope, logf func(format string, v ...i
logf("class %s", name) logf("class %s", name)
} }
} }
// highlightHelper give the user better file/line number feedback.
func highlightHelper(node interfaces.Node, logf func(format string, v ...interface{}), err error) error {
displayer, ok := node.(interfaces.TextDisplayer)
if ok {
if highlight := displayer.HighlightText(); highlight != "" {
logf("%s: %s", err.Error(), highlight)
}
//return fmt.Errorf("%s: %s", err.Error(), displayer.Byline())
}
return err
}

View File

@@ -197,3 +197,16 @@ func (obj *Textarea) HighlightText() string {
return result.String() return result.String()
} }
// HighlightHelper gives the user better file/line number feedback.
func HighlightHelper(node Node, logf func(format string, v ...interface{}), err error) error {
displayer, ok := node.(TextDisplayer)
if !ok {
return err
}
if highlight := displayer.HighlightText(); highlight != "" {
logf("%s: %s", err.Error(), highlight)
}
return fmt.Errorf("%s: %s", err.Error(), displayer.Byline())
}

View File

@@ -6,4 +6,4 @@ if true {
$b = true $b = true
} }
-- OUTPUT -- -- OUTPUT --
# err: errSetScope: var `$b` does not exist in this scope # err: errSetScope: var `$b` does not exist in this scope: /main.mcl @ 2:4-2:5

View File

@@ -16,4 +16,4 @@ class xclass {
} }
} }
-- OUTPUT -- -- OUTPUT --
# err: errSetScope: func `os.is_family_debian` does not exist in this scope # err: errSetScope: func `os.is_family_debian` does not exist in this scope: /second.mcl @ 5:12-5:33

View File

@@ -9,4 +9,4 @@ include foo
# This sort of thing is not currently supported, and not sure if it ever will. # This sort of thing is not currently supported, and not sure if it ever will.
include bar # nope! include bar # nope!
-- OUTPUT -- -- OUTPUT --
# err: errSetScope: class `bar` does not exist in this scope # err: errSetScope: class `bar` does not exist in this scope: /main.mcl @ 9:1-9:12

View File

@@ -14,4 +14,4 @@ class c1($b) {
include c1 as i1 include c1 as i1
include i1.inner include i1.inner
-- OUTPUT -- -- OUTPUT --
# err: errSetScope: class `c1` expected 1 args but got 0 # err: errSetScope: class `c1` expected 1 args but got 0: /main.mcl @ 13:1-13:17

View File

@@ -7,4 +7,4 @@ $f = func($x) {
$name = $f("foo") $name = $f("foo")
test "${name}" {} test "${name}" {}
-- OUTPUT -- -- OUTPUT --
# err: errSetScope: var `$x` does not exist in this scope # err: errSetScope: var `$x` does not exist in this scope: /main.mcl @ 1:8-1:9

View File

@@ -11,4 +11,4 @@ include funcgen1
$x1 = fun1() # not funcgen1.fun1 since it's *not* an import! $x1 = fun1() # not funcgen1.fun1 since it's *not* an import!
test "${x1}" {} # hi test "${x1}" {} # hi
-- OUTPUT -- -- OUTPUT --
# err: errSetScope: func `fun1` does not exist in this scope # err: errSetScope: func `fun1` does not exist in this scope: /main.mcl @ 10:7-10:13

View File

@@ -14,4 +14,4 @@ include funcgen2
$x2 = fun2() # not funcgen2.fun2 since it's *not* an import! $x2 = fun2() # not funcgen2.fun2 since it's *not* an import!
test "${x2}" {} # hello world test "${x2}" {} # hello world
-- OUTPUT -- -- OUTPUT --
# err: errSetScope: func `fun2` does not exist in this scope # err: errSetScope: func `fun2` does not exist in this scope: /main.mcl @ 13:7-13:13

View File

@@ -11,4 +11,4 @@ $x = "this is x.mcl"
import "x.mcl" as f import "x.mcl" as f
$y = $f.x + " and this is y.mcl" $y = $f.x + " and this is y.mcl"
-- OUTPUT -- -- OUTPUT --
# err: errSetScope: var `$g.x` does not exist in this scope # err: errSetScope: var `$g.x` does not exist in this scope: /main.mcl @ 3:6-3:14

View File

@@ -143,6 +143,10 @@ func (obj *FastInvariantSolver) Solve(ctx context.Context, data *unification.Dat
obj.Logf("%s: %s", err.Error(), highlight) obj.Logf("%s: %s", err.Error(), highlight)
} }
return nil, fmt.Errorf("%s: %s", err.Error(), displayer.Byline()) return nil, fmt.Errorf("%s: %s", err.Error(), displayer.Byline())
// XXX: when we have fully populated all the position
// information, we could replace the above code with:
//return nil, interfaces.HighlightHelper(x.Node, obj.Logf, err)
} }
if obj.Debug { if obj.Debug {
e1, e2 := unificationUtil.Extract(x.Expect), unificationUtil.Extract(x.Actual) e1, e2 := unificationUtil.Extract(x.Expect), unificationUtil.Extract(x.Actual)
@@ -165,7 +169,9 @@ func (obj *FastInvariantSolver) Solve(ctx context.Context, data *unification.Dat
// TODO: collect all of these errors and return them together? // TODO: collect all of these errors and return them together?
if t1.HasUni() { // || t2.HasUni() if t1.HasUni() { // || t2.HasUni()
return nil, fmt.Errorf("expr: %s is ambiguous: %s", x.Expr, u(t1)) err := fmt.Errorf("expr: %s is ambiguous: %s", x.Expr, u(t1))
return nil, interfaces.HighlightHelper(x.Node, obj.Logf, err)
} }
//if err := t1.Cmp(t2); err != nil { // for development/debugging //if err := t1.Cmp(t2); err != nil { // for development/debugging