-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexcept.go
More file actions
337 lines (297 loc) · 10.2 KB
/
except.go
File metadata and controls
337 lines (297 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
// Package except provides try-catch-finally exception handling for Go.
//
// This package implements a traditional exception handling mechanism
// inspired by languages like Java, Python, and JavaScript, allowing
// developers to use familiar try-catch-finally patterns in Go.
//
// Copyright (c) 2025 mew-sh
// Licensed under the MIT License. See LICENSE file for details.
package except
import (
"fmt"
"reflect"
"runtime/debug"
"strings"
)
// ExceptionType represents the type of exception
type ExceptionType string
// Predefined exception types
const (
UnknownErrorType ExceptionType = "UnknownError"
IndexErrorType ExceptionType = "IndexError"
RuntimeErrorType ExceptionType = "RuntimeError"
ValueErrorType ExceptionType = "ValueError"
NetworkErrorType ExceptionType = "NetworkError"
SyntaxErrorType ExceptionType = "SyntaxError"
PermissionErrorType ExceptionType = "PermissionError"
TimeoutErrorType ExceptionType = "TimeoutError"
TypeErrorType ExceptionType = "TypeError"
AssertionErrorType ExceptionType = "AssertionError"
ConnectionErrorType ExceptionType = "ConnectionError"
ReferenceErrorType ExceptionType = "ReferenceError"
EOFErrorType ExceptionType = "EOFError"
LookupErrorType ExceptionType = "LookupError"
)
// exceptionErrorMap maps exception types to their default error messages
var exceptionErrorMap = map[ExceptionType]string{
UnknownErrorType: "Unknown Error",
IndexErrorType: "Index Error",
ValueErrorType: "Value Error",
NetworkErrorType: "Network Error",
SyntaxErrorType: "Syntax Error",
PermissionErrorType: "Permission Error",
TimeoutErrorType: "Timeout Error",
TypeErrorType: "Type Error",
AssertionErrorType: "Assertion Error",
ConnectionErrorType: "Connection Error",
ReferenceErrorType: "Reference Error",
EOFErrorType: "EOF Error",
LookupErrorType: "Lookup Error",
}
// Exception represents an exception with message, type and stack trace
type Exception struct {
Message string
Type ExceptionType
StackTrace string
}
// ExceptionHandler is the main handler for try-catch-finally operations
type ExceptionHandler struct {
exception *Exception
tryHandler func()
catchHandlers []catchBlockEntry
finallyHandler func()
// Export exception types for easy access
AssertionErrorType ExceptionType
IndexErrorType ExceptionType
RuntimeErrorType ExceptionType
ValueErrorType ExceptionType
NetworkErrorType ExceptionType
SyntaxErrorType ExceptionType
PermissionErrorType ExceptionType
TimeoutErrorType ExceptionType
TypeErrorType ExceptionType
ConnectionErrorType ExceptionType
ReferenceErrorType ExceptionType
EOFErrorType ExceptionType
LookupErrorType ExceptionType
UnknownErrorType ExceptionType
}
// catchBlockEntry represents a catch block with exception types and handler
type catchBlockEntry struct {
Exceptions []ExceptionType
Handler func(excep *Exception)
}
// New creates a new exception handler instance
func New() *ExceptionHandler {
return &ExceptionHandler{
exception: &Exception{Message: ""},
catchHandlers: []catchBlockEntry{},
finallyHandler: nil,
AssertionErrorType: AssertionErrorType,
IndexErrorType: IndexErrorType,
RuntimeErrorType: RuntimeErrorType,
ValueErrorType: ValueErrorType,
NetworkErrorType: NetworkErrorType,
SyntaxErrorType: SyntaxErrorType,
PermissionErrorType: PermissionErrorType,
TimeoutErrorType: TimeoutErrorType,
TypeErrorType: TypeErrorType,
ConnectionErrorType: ConnectionErrorType,
ReferenceErrorType: ReferenceErrorType,
EOFErrorType: EOFErrorType,
LookupErrorType: LookupErrorType,
UnknownErrorType: UnknownErrorType,
}
}
// NewException creates a new Exception with the specified type and optional message
func (e *ExceptionHandler) NewException(exceptionType ExceptionType, args ...interface{}) *Exception {
message, ok := exceptionErrorMap[exceptionType]
if !ok {
message = string(exceptionType)
}
if len(args) > 0 {
message = fmt.Sprintf("%v", args[0])
}
return &Exception{
Message: message,
Type: exceptionType,
}
}
// Try executes the provided function and captures any panics or exceptions
func (e *ExceptionHandler) Try(cb func()) *ExceptionHandler {
e.tryHandler = cb
return e
}
// Catch handles exceptions based on the provided exception types
func (e *ExceptionHandler) Catch(exceptionTypes []ExceptionType, cb func(excep *Exception)) *ExceptionHandler {
e.catchHandlers = append(e.catchHandlers, catchBlockEntry{
Exceptions: exceptionTypes,
Handler: cb,
})
return e
}
// Finally executes the provided function regardless of whether an exception occurred
func (e *ExceptionHandler) Finally(cb func()) *ExceptionHandler {
e.finallyHandler = cb
return e
}
// Run executes the try-catch-finally flow
func (e *ExceptionHandler) Run() {
e.executeTry()
e.executeCatchHandler()
e.executeFinally()
}
// Throw throws an exception
func (e *ExceptionHandler) Throw(exp *Exception) {
message := exp.Message
errorMsg := fmt.Sprintf("Message::%s||Exception::%s", message, exp.Type)
panic(errorMsg)
}
// In creates a list of exception types for matching in catch blocks
func (e *ExceptionHandler) In(exceptionTypes ...ExceptionType) []ExceptionType {
return exceptionTypes
}
// Predefined exception constructors
// AssertionError creates an assertion error exception
func (e *ExceptionHandler) AssertionError(args ...interface{}) *Exception {
return e.NewException(AssertionErrorType, args...)
}
// IndexError creates an index error exception
func (e *ExceptionHandler) IndexError(args ...interface{}) *Exception {
return e.NewException(IndexErrorType, args...)
}
// RuntimeError creates a runtime error exception
func (e *ExceptionHandler) RuntimeError(args ...interface{}) *Exception {
return e.NewException(RuntimeErrorType, args...)
}
// ValueError creates a value error exception
func (e *ExceptionHandler) ValueError(args ...interface{}) *Exception {
return e.NewException(ValueErrorType, args...)
}
// NetworkError creates a network error exception
func (e *ExceptionHandler) NetworkError(args ...interface{}) *Exception {
return e.NewException(NetworkErrorType, args...)
}
// SyntaxError creates a syntax error exception
func (e *ExceptionHandler) SyntaxError(args ...interface{}) *Exception {
return e.NewException(SyntaxErrorType, args...)
}
// PermissionError creates a permission error exception
func (e *ExceptionHandler) PermissionError(args ...interface{}) *Exception {
return e.NewException(PermissionErrorType, args...)
}
// TimeoutError creates a timeout error exception
func (e *ExceptionHandler) TimeoutError(args ...interface{}) *Exception {
return e.NewException(TimeoutErrorType, args...)
}
// TypeError creates a type error exception
func (e *ExceptionHandler) TypeError(args ...interface{}) *Exception {
return e.NewException(TypeErrorType, args...)
}
// ConnectionError creates a connection error exception
func (e *ExceptionHandler) ConnectionError(args ...interface{}) *Exception {
return e.NewException(ConnectionErrorType, args...)
}
// ReferenceError creates a reference error exception
func (e *ExceptionHandler) ReferenceError(args ...interface{}) *Exception {
return e.NewException(ReferenceErrorType, args...)
}
// EOFError creates an EOF error exception
func (e *ExceptionHandler) EOFError(args ...interface{}) *Exception {
return e.NewException(EOFErrorType, args...)
}
// LookupError creates a lookup error exception
func (e *ExceptionHandler) LookupError(args ...interface{}) *Exception {
return e.NewException(LookupErrorType, args...)
}
// UnknownError creates an unknown error exception
func (e *ExceptionHandler) UnknownError(args ...interface{}) *Exception {
return e.NewException(UnknownErrorType, args...)
}
// Private methods
// executeTry executes the try block and captures any panics
func (e *ExceptionHandler) executeTry() {
defer func() {
err := recover()
if err != nil {
value := reflect.ValueOf(err)
errorMessage := fmt.Sprintf("%v", value)
if !strings.Contains(errorMessage, "||") {
errorMessage = fmt.Sprintf("Message::%s||Exception::%s", errorMessage, RuntimeErrorType)
}
e.exception = &Exception{
Message: errorMessage,
StackTrace: string(debug.Stack()),
}
}
}()
if e.tryHandler != nil {
e.tryHandler()
}
}
// executeCatchHandler executes the appropriate catch handler
func (e *ExceptionHandler) executeCatchHandler() {
if len(e.catchHandlers) == 0 || e.exception == nil || len(e.exception.Message) == 0 {
return
}
var defaultHandler func(*Exception)
for _, handler := range e.catchHandlers {
if len(handler.Exceptions) > 0 {
// Check if this handler matches any of the exception types
for _, exceptionType := range handler.Exceptions {
exceptionTypePart := e.getExceptionType()
if exceptionTypePart == string(exceptionType) {
e.exception.Type = ExceptionType(exceptionTypePart)
e.exception.Message = e.getMessage()
handler.Handler(e.exception)
return
}
}
} else {
// This is a default handler (nil exception types)
defaultHandler = handler.Handler
}
}
// If no specific handler matched, use the default handler
if defaultHandler != nil {
e.exception.Type = ExceptionType(e.getExceptionType())
e.exception.Message = e.getMessage()
defaultHandler(e.exception)
}
}
// executeFinally executes the finally block
func (e *ExceptionHandler) executeFinally() {
if e.finallyHandler != nil {
e.finallyHandler()
}
}
// getExceptionType extracts the exception type from the error message
func (e *ExceptionHandler) getExceptionType() string {
if e.exception == nil {
return ""
}
messageItems := strings.Split(e.exception.Message, "||")
if len(messageItems) > 1 {
exceptionPart := messageItems[1]
parts := strings.Split(exceptionPart, "::")
if len(parts) > 1 {
return parts[1]
}
}
return ""
}
// getMessage extracts the actual message from the error message
func (e *ExceptionHandler) getMessage() string {
if e.exception == nil {
return ""
}
messageItems := strings.Split(e.exception.Message, "||")
if len(messageItems) > 0 {
messagePart := messageItems[0]
splitedMessage := strings.Split(messagePart, "::")
if len(splitedMessage) > 1 {
return splitedMessage[1]
}
}
return ""
}