From 47295859603c7697113d62591432cd38fbf44991 Mon Sep 17 00:00:00 2001 From: thedae Date: Wed, 13 Nov 2024 12:46:44 +0100 Subject: [PATCH 1/2] Properly parse syntax errors --- error.go | 47 +++++++++++++++++++++++++++++++++++++--------- error_test.go | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 9 deletions(-) diff --git a/error.go b/error.go index 2b6d8e7..80b6d05 100644 --- a/error.go +++ b/error.go @@ -177,22 +177,26 @@ func newError(err error, h errSourceHandler) error { switch err.(type) { case *lua.ApiError: e := err.(*lua.ApiError) - p := strings.Split(e.Object.String(), ":") - c := len(p) - var ( problem = -1 text = e.Error() ) - if c > 1 { - if v, err := strconv.Atoi(p[1]); err == nil { - problem = v + if e.Type == lua.ApiErrorSyntax { + text, problem = parseSyntaxError(e.Object.String()) + } else { + p := strings.Split(e.Object.String(), ":") + c := len(p) + + if c > 1 { + if v, err := strconv.Atoi(p[1]); err == nil { + problem = v + } } - } - if c > 2 { - text = strings.Trim(strings.Join(p[2:], ":"), " ") + if c > 2 { + text = strings.Trim(strings.Join(p[2:], ":"), " ") + } } return &Error{ @@ -205,6 +209,31 @@ func newError(err error, h errSourceHandler) error { return err } +func parseSyntaxError(errorText string) (string, int) { + var ( + problem = -1 + text = errorText + ) + + if strings.Contains(errorText, " at EOF:") { + problem = 0 + text = strings.TrimSpace(strings.Split(errorText, ":")[1]) + " at EOF" + + return text, problem + } + + parts := strings.Split(errorText, " near ") + if len(parts) == 2 { + text = strings.TrimSuffix(parts[1], "\n") + where := strings.Split(strings.TrimSuffix(strings.ReplaceAll(parts[0], " line:", ""), ")"), "(column:") + if v, err := strconv.Atoi(where[0]); err == nil { + problem = v + } + + } + return text, problem +} + func highlight(s string) string { var buf bytes.Buffer if err := quick.Highlight(&buf, s, "lua", "terminal", "solarized-dark"); err != nil { diff --git a/error_test.go b/error_test.go index 89fe92d..aeb921f 100644 --- a/error_test.go +++ b/error_test.go @@ -6,6 +6,58 @@ import ( "testing" ) +func TestErrorSourceSyntaxError(t *testing.T) { + tests := []struct { + name string + src string + expected string + }{ + { + name: "Inline", + src: "local p = person.new('Steeve');lokal t = 'fail'", + expected: "Line 1: 't': parse error", + }, + { + name: "Parsing error", + src: "local p = person.new('Steeve')\nlokal t = 'fail'", + expected: "Line 2: 't': parse error", + }, + { + name: "Bad token", + src: "local p = person.new('Steeve')\nlocal t & 'fail'", + expected: "Line 2: '&': Invalid token", + }, + { + name: "Unterminated string", + src: "local p = person.new('Steeve)\nlocal t = 'okay'", + expected: "Line 2: 'Steeve)': unterminated string", + }, + { + name: "End of file", + src: "local p = person.new('Steeve')\nprint(p:email()", + expected: "Line 0: syntax error at EOF", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + b := getBinder() + + if err := b.DoString(test.src); err != nil { + switch err.(type) { + case *Error: + e := err.(*Error) + if e.Error() != test.expected { + t.Errorf("Error message does not match, expected=\"%s\" got=\"%s\"", test.expected, e.Error()) + } + default: + t.Error("Must return error", err) + } + } + }) + } +} + func TestErrorSourceSmall_Func(t *testing.T) { b := getBinder() From d0ebcabe17eac7a66a4504f177ac2fdc0962e4cc Mon Sep 17 00:00:00 2001 From: thedae Date: Thu, 14 Nov 2024 09:22:00 +0100 Subject: [PATCH 2/2] Remove extra spaces in syntax errors --- error.go | 2 +- error_test.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/error.go b/error.go index 80b6d05..e7ee9b5 100644 --- a/error.go +++ b/error.go @@ -224,7 +224,7 @@ func parseSyntaxError(errorText string) (string, int) { parts := strings.Split(errorText, " near ") if len(parts) == 2 { - text = strings.TrimSuffix(parts[1], "\n") + text = strings.Join(strings.Fields(strings.TrimSuffix(parts[1], "\n")), " ") where := strings.Split(strings.TrimSuffix(strings.ReplaceAll(parts[0], " line:", ""), ")"), "(column:") if v, err := strconv.Atoi(where[0]); err == nil { problem = v diff --git a/error_test.go b/error_test.go index aeb921f..0535a74 100644 --- a/error_test.go +++ b/error_test.go @@ -15,22 +15,22 @@ func TestErrorSourceSyntaxError(t *testing.T) { { name: "Inline", src: "local p = person.new('Steeve');lokal t = 'fail'", - expected: "Line 1: 't': parse error", + expected: "Line 1: 't': parse error", }, { name: "Parsing error", src: "local p = person.new('Steeve')\nlokal t = 'fail'", - expected: "Line 2: 't': parse error", + expected: "Line 2: 't': parse error", }, { name: "Bad token", src: "local p = person.new('Steeve')\nlocal t & 'fail'", - expected: "Line 2: '&': Invalid token", + expected: "Line 2: '&': Invalid token", }, { name: "Unterminated string", src: "local p = person.new('Steeve)\nlocal t = 'okay'", - expected: "Line 2: 'Steeve)': unterminated string", + expected: "Line 2: 'Steeve)': unterminated string", }, { name: "End of file",