feat: add error handling part

This commit is contained in:
2025-04-19 19:53:22 +02:00
parent 74b02df3c1
commit 0346b79dd2

240
README.md
View File

@@ -406,19 +406,239 @@ print(coroutine.resume(routine, 7, 8, 9)) -- 1+2+3 = '6'
### Error handling
Lua allows low-level error handling with the `error` function and high-level error handling with the `assert` function. The `error` function raises an error and handles it with the `pcall` or `xpcall` function. The `assert` function checks a condition and raises an error if the condition is not met.
Lua provides several core functions for error handling: `assert`, `error`, `pcall` (protected call), and `xpcall` (extended protected call), each offering different levels of control.
The examples below will explain and illustrate how each method is intended to be used.
````lua
#### assert
`assert` is used to check a condition. If the result is `false` or `nil`, it triggers an error with a custom message.
It's especially useful when validating user input or enforcing preconditions.
```lua
local function isMajorUser(age)
assert(age >= 18, "You are not allowed to buy this item, you need to be 18 years old")
end
isMajorUser(15)
-- Output : You are not allowed to buy this item, you need to be 18 years old !
```
#### error(message [, level])
The `error` function allows you to manually raise an error, similar to `throw` in other languages. It immediately stops the current execution flow.
You can provide a custom error message, as well as a `level` parameter to control where the traceback starts in the call stack.
Possible values for `level`:
- **0**: No call stack information is shown.
```lua
error("Simple error without trace", 0)
-- Result: Simple error without trace
```
- **1** *(default)*: The error appears at the exact place where `error` is called.
```lua
local function triggerError()
error("An error has occurred", 1)
end
triggerError()
-- Result
--[[
lua: script.lua:2: An error has occurred
stack traceback:
script.lua:2: in function 'triggerError'
script.lua:5: in main chunk
]]
```
- **2**: The error appears at the place where the function **calling `error`** was itself called.
```lua
local function triggerError()
error("Error reported to caller", 2)
end
local function wrapper()
triggerError()
end
wrapper()
-- Result
--[[
lua: script.lua:7: Error reported to caller
stack traceback:
script.lua:7: in function 'wrapper'
script.lua:10: in main chunk
]]
```
#### pcall (protected call)
As its name suggests, `pcall` allows you to execute a function in **protected mode**, catching any potential error that might occur.
It acts similarly to a `try-catch` block found in other programming languages.
The result of calling `pcall` returns two values, typically stored in two variables like `success` and `result`, though you can name them as you wish.
- If the call succeeds:
- `success` will be `true`,
- `result` will contain the functions returned value(s).
- If an error occurs:
- `success` will be `false`,
- `result` will contain the error message.
If the function does not return anything, `result` will be `nil`.
```lua
local function divideANumberByAnOther(a, b)
return a / b -- it would be better to validate parameters, but this is for example purposes
end
-------------------------------
-- First scenario: error case
-------------------------------
local success, result = pcall(divideANumberByAnOther, 1, 0)
if not success then
print("An error has occured :", result)
end
-- Output: An error has occured :
-- Throw an error if the first argument is false
-- the second argument is the error message.
assert(type(firstvariable) = 'string', 'not a string')
-- TODO to continue
-------------------------------
-- Second scenario: valid case
-------------------------------
````
local success, result = pcall(divideANumberByAnOther, 10, 2)
if success then
print("Result is :", result)
end
-- Output: Result is : 5
----------------------------------
-- Third scenario: combine pcall with assert for critical operations
----------------------------------
local function readFile(fileName)
local fileToRead = assert(io.open(fileName, "r"), "Impossible to read the file")
-- Continue processing if successfully opened
fileToRead:close()
end
local success, result = pcall(readFile, "data.txt") -- providing a file name that doesn't exist
if not success then
print("An error has occured :", result)
end
-- Output: An error has occured : Impossible to read the file
-- Here we use assert to robustly manage errors: if the file cannot be opened,
-- assert triggers an error and immediately stops the program with the message.
--------------------------------
-- Fourth scenario: pcall with a function that returns multiple values
--------------------------------------
local function sumAndProduct(a, b)
return a + b, a * b
end
local success, sum, product = pcall(sumAndProduct, 3, 4)
if success then
print("Sum :", sum) -- 7
print("Product :", product) -- 12
else
print("Error : ", sum) -- sum would contain the error message if one occurred
end
-- Reminder: pcall always returns two things:
-- 1. A boolean indicating if the call was successful.
-- 2. All values returned by the function if successful.
```
#### xpcall (extended protected call)
`xpcall` is the big brother of `pcall`. It works in the same way but with an extra feature:
we can provide a **custom error handler function** that will be executed if an error occurs during the protected function call.
This is especially useful when we want to customize how errors are displayed or logged, for example by adding stack traces or additional context.
```lua
local function errorHandler(err)
print("🔴 Error caught:", err)
print(debug.traceback("Stack trace:", 2))
end
local function riskyFunction()
print("🟢 In riskyFunction")
error("Something went wrong!")
end
local function wrapper()
print("🟡 Calling riskyFunction()")
riskyFunction()
print("🟡 After riskyFunction") -- never reached
end
print("1. Start")
local success, result = xpcall(wrapper, errorHandler)
print("2. Execution finished")
print("3. Success:", success)
print("4. Result:", result)
-- Output:
--[[
1. Start
🟡 Calling riskyFunction()
🟢 In riskyFunction
🔴 Error caught: Something went wrong!
Stack trace:
stack traceback:
script.lua:6: in function 'riskyFunction'
script.lua:11: in function 'wrapper'
...
2. Execution finished
3. Success: false
4. Result: nil
]]
--[[
===========================
debug.traceback Cheatsheet
===========================
debug.traceback([message], [level])
- message (string) → optional message shown before the stack trace
- level (number) → determines where the trace starts in the call stack:
level = 0 → shows EVERYTHING, including debug.traceback itself
level = 1 → (default) starts trace inside errorHandler() (not very useful)
level = 2 → starts trace at the point where the error actually occurred (e.g., riskyFunction)
Recommended usage:
debug.traceback("Optional message", 2)
]]
```
### Modules
@@ -476,3 +696,9 @@ g() -- Prints out '343', nothing printed before now.
````
### Credits
- EndMove - [contact@endmove.eu](mailto:contact@endmove.eu)
- Varmix - [contact@varmix.fr](mailto:contact@varmix.fr)