From dcd4f0709ff6bc46fb9bc1c3873db795f9ff9a55 Mon Sep 17 00:00:00 2001 From: James Shubin Date: Thu, 5 Jun 2025 23:00:56 -0400 Subject: [PATCH] lang: ast: Provide better error reporting for scope errors Print these file and line numbers when we can! --- lang/ast/structs.go | 15 ++++++++++----- lang/ast/util.go | 13 +++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/lang/ast/structs.go b/lang/ast/structs.go index f3c2daa8..69ab85e5 100644 --- a/lang/ast/structs.go +++ b/lang/ast/structs.go @@ -6828,7 +6828,8 @@ func (obj *StmtInclude) SetScope(scope *interfaces.Scope) error { stmt, exists := scope.Classes[obj.Name] if !exists { - return 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) } class, ok := stmt.(*StmtClass) if !ok { @@ -10468,7 +10469,8 @@ func (obj *ExprCall) SetScope(scope *interfaces.Scope, sctx map[string]interface if obj.data.Debug || true { // TODO: leave this on permanently? lambdaScopeFeedback(obj.scope, obj.data.Logf) } - return 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) } target = f } @@ -10484,7 +10486,8 @@ func (obj *ExprCall) SetScope(scope *interfaces.Scope, sctx map[string]interface if obj.data.Debug || true { // TODO: leave this on permanently? functionScopeFeedback(obj.scope, obj.data.Logf) } - return 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) } target = f } @@ -11232,7 +11235,8 @@ func (obj *ExprVar) SetScope(scope *interfaces.Scope, sctx map[string]interfaces if obj.data.Debug || true { // TODO: leave this on permanently? variableScopeFeedback(obj.scope, obj.data.Logf) } - return 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) } obj.scope.Variables[obj.Name] = target @@ -11292,7 +11296,8 @@ func (obj *ExprVar) Infer() (*types.Type, []*interfaces.UnificationInvariant, er // lookup value from scope expr, exists := obj.scope.Variables[obj.Name] if !exists { - return nil, nil, 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) } // This child call to Infer is an outlier to the common pattern where diff --git a/lang/ast/util.go b/lang/ast/util.go index 10d5dc66..1e6ae6eb 100644 --- a/lang/ast/util.go +++ b/lang/ast/util.go @@ -562,6 +562,19 @@ func lambdaScopeFeedback(scope *interfaces.Scope, logf func(format string, v ... } } +// 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 +} + // Textarea stores the coordinates of a statement or expression in the form of a // starting line/column and ending line/column. type Textarea struct {