476 lines
10 KiB
Markdown
476 lines
10 KiB
Markdown
|
|
# ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
The `ON ERROR RESUME NEXT` keyword enables BASIC error handling, allowing scripts to continue execution when errors occur instead of terminating immediately.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Syntax
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT ' Enable error trapping
|
||
|
|
ON ERROR GOTO 0 ' Disable error trapping
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Description
|
||
|
|
|
||
|
|
`ON ERROR RESUME NEXT` enables error trapping mode where execution continues to the next statement after an error occurs, rather than halting the script. This pattern is borrowed from BASIC and provides a simple way to handle errors gracefully in BASIC scripts.
|
||
|
|
|
||
|
|
When error trapping is enabled:
|
||
|
|
- Errors are captured but don't stop execution
|
||
|
|
- The `ERROR` function returns `TRUE` if an error occurred
|
||
|
|
- The `ERROR MESSAGE` function returns the error description
|
||
|
|
- The `ERR` variable contains the error number
|
||
|
|
|
||
|
|
Use `ON ERROR GOTO 0` to disable error trapping and restore normal error behavior.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Error State Keywords
|
||
|
|
|
||
|
|
| Keyword | Description | Example |
|
||
|
|
|---------|-------------|---------|
|
||
|
|
| `ON ERROR RESUME NEXT` | Enable error trapping | `ON ERROR RESUME NEXT` |
|
||
|
|
| `ON ERROR GOTO 0` | Disable error trapping | `ON ERROR GOTO 0` |
|
||
|
|
| `ERROR` | Returns TRUE if error occurred | `IF ERROR THEN` |
|
||
|
|
| `ERROR MESSAGE` | Get last error message | `msg = ERROR MESSAGE` |
|
||
|
|
| `ERR` | Get error number | `code = ERR` |
|
||
|
|
| `CLEAR ERROR` | Clear error state | `CLEAR ERROR` |
|
||
|
|
| `THROW` | Raise a custom error | `THROW "Invalid input"` |
|
||
|
|
| `ASSERT` | Assert a condition | `ASSERT count > 0, "Count must be positive"` |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
### Basic Error Handling
|
||
|
|
|
||
|
|
```basic
|
||
|
|
' Enable error trapping
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
' Attempt a risky operation
|
||
|
|
result = GET "https://api.example.com/data"
|
||
|
|
|
||
|
|
' Check if it failed
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "Sorry, I couldn't fetch the data: " + ERROR MESSAGE
|
||
|
|
ELSE
|
||
|
|
TALK "Data retrieved successfully!"
|
||
|
|
END IF
|
||
|
|
```
|
||
|
|
|
||
|
|
### Multiple Operations with Error Checking
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
' Try to read a file
|
||
|
|
content = READ "config.csv"
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "Config file not found, using defaults"
|
||
|
|
CLEAR ERROR
|
||
|
|
content = "name,value\ndefault,true"
|
||
|
|
END IF
|
||
|
|
|
||
|
|
' Try to parse it
|
||
|
|
data = PARSE_CSV(content)
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "Failed to parse config: " + ERROR MESSAGE
|
||
|
|
CLEAR ERROR
|
||
|
|
END IF
|
||
|
|
|
||
|
|
' Continue with whatever data we have
|
||
|
|
TALK "Loaded " + LEN(data) + " configuration entries"
|
||
|
|
```
|
||
|
|
|
||
|
|
### Database Operations
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
' Try to insert a record
|
||
|
|
INSERT "customers", #{
|
||
|
|
"name": customer_name,
|
||
|
|
"email": customer_email,
|
||
|
|
"created_at": NOW()
|
||
|
|
}
|
||
|
|
|
||
|
|
IF ERROR THEN
|
||
|
|
IF INSTR(ERROR MESSAGE, "duplicate") > 0 THEN
|
||
|
|
TALK "This customer already exists in our system."
|
||
|
|
ELSE IF INSTR(ERROR MESSAGE, "connection") > 0 THEN
|
||
|
|
TALK "Database is temporarily unavailable. Please try again."
|
||
|
|
ELSE
|
||
|
|
TALK "Could not save customer: " + ERROR MESSAGE
|
||
|
|
END IF
|
||
|
|
ELSE
|
||
|
|
TALK "Customer saved successfully!"
|
||
|
|
END IF
|
||
|
|
|
||
|
|
ON ERROR GOTO 0 ' Disable error trapping
|
||
|
|
```
|
||
|
|
|
||
|
|
### HTTP Request with Fallback
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
' Try primary API
|
||
|
|
data = GET "https://primary-api.example.com/endpoint"
|
||
|
|
|
||
|
|
IF ERROR THEN
|
||
|
|
PRINT "Primary API failed: " + ERROR MESSAGE
|
||
|
|
CLEAR ERROR
|
||
|
|
|
||
|
|
' Try fallback API
|
||
|
|
data = GET "https://fallback-api.example.com/endpoint"
|
||
|
|
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "Both APIs are unavailable. Please try again later."
|
||
|
|
RETURN
|
||
|
|
END IF
|
||
|
|
END IF
|
||
|
|
|
||
|
|
' Process the data
|
||
|
|
TALK "Retrieved: " + data.name
|
||
|
|
```
|
||
|
|
|
||
|
|
### File Operations with Cleanup
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
' Generate a report
|
||
|
|
report = GENERATE PDF "templates/report.html", report_data, "temp/report.pdf"
|
||
|
|
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "Failed to generate report: " + ERROR MESSAGE
|
||
|
|
CLEAR ERROR
|
||
|
|
ELSE
|
||
|
|
' Try to send it
|
||
|
|
SEND MAIL recipient, "Your Report", "Please find your report attached.", [report.localName]
|
||
|
|
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "Report generated but email failed: " + ERROR MESSAGE
|
||
|
|
DOWNLOAD report.url AS "report.pdf"
|
||
|
|
TALK "You can download it directly instead."
|
||
|
|
ELSE
|
||
|
|
TALK "Report sent successfully!"
|
||
|
|
END IF
|
||
|
|
|
||
|
|
' Clean up temp file
|
||
|
|
DELETE "temp/report.pdf"
|
||
|
|
' Ignore cleanup errors
|
||
|
|
CLEAR ERROR
|
||
|
|
END IF
|
||
|
|
|
||
|
|
ON ERROR GOTO 0
|
||
|
|
```
|
||
|
|
|
||
|
|
### Validation with ASSERT
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
' Validate input
|
||
|
|
ASSERT LEN(email) > 0, "Email is required"
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK ERROR MESSAGE
|
||
|
|
RETURN
|
||
|
|
END IF
|
||
|
|
|
||
|
|
ASSERT INSTR(email, "@") > 0, "Invalid email format"
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK ERROR MESSAGE
|
||
|
|
RETURN
|
||
|
|
END IF
|
||
|
|
|
||
|
|
ASSERT amount > 0, "Amount must be positive"
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK ERROR MESSAGE
|
||
|
|
RETURN
|
||
|
|
END IF
|
||
|
|
|
||
|
|
' All validations passed
|
||
|
|
TALK "Processing your request..."
|
||
|
|
```
|
||
|
|
|
||
|
|
### Custom Error with THROW
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
' Check business rules
|
||
|
|
IF quantity > inventory_count THEN
|
||
|
|
THROW "Insufficient inventory: only " + inventory_count + " items available"
|
||
|
|
END IF
|
||
|
|
|
||
|
|
IF customer_credit < total_price THEN
|
||
|
|
THROW "Insufficient credit: need $" + FORMAT(total_price - customer_credit, "#,##0.00") + " more"
|
||
|
|
END IF
|
||
|
|
|
||
|
|
' Check for errors from THROW
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "Cannot process order: " + ERROR MESSAGE
|
||
|
|
RETURN
|
||
|
|
END IF
|
||
|
|
|
||
|
|
' Continue with order processing
|
||
|
|
TALK "Order confirmed!"
|
||
|
|
```
|
||
|
|
|
||
|
|
### Loop with Error Recovery
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
successful = 0
|
||
|
|
failed = 0
|
||
|
|
|
||
|
|
FOR EACH item IN items_to_process
|
||
|
|
' Process each item
|
||
|
|
result = POST "https://api.example.com/process", item
|
||
|
|
|
||
|
|
IF ERROR THEN
|
||
|
|
PRINT "Failed to process item " + item.id + ": " + ERROR MESSAGE
|
||
|
|
failed = failed + 1
|
||
|
|
CLEAR ERROR ' Clear error to continue loop
|
||
|
|
ELSE
|
||
|
|
successful = successful + 1
|
||
|
|
END IF
|
||
|
|
NEXT
|
||
|
|
|
||
|
|
ON ERROR GOTO 0
|
||
|
|
|
||
|
|
TALK "Processing complete: " + successful + " succeeded, " + failed + " failed"
|
||
|
|
```
|
||
|
|
|
||
|
|
### Nested Error Handling
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
' Outer operation
|
||
|
|
connection = CONNECT "database"
|
||
|
|
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "Database connection failed"
|
||
|
|
RETURN
|
||
|
|
END IF
|
||
|
|
|
||
|
|
' Inner operation
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
result = QUERY connection, "SELECT * FROM users"
|
||
|
|
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "Query failed, trying alternative..."
|
||
|
|
CLEAR ERROR
|
||
|
|
result = QUERY connection, "SELECT * FROM users_backup"
|
||
|
|
END IF
|
||
|
|
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "All queries failed: " + ERROR MESSAGE
|
||
|
|
ELSE
|
||
|
|
TALK "Found " + LEN(result) + " users"
|
||
|
|
END IF
|
||
|
|
|
||
|
|
ON ERROR GOTO 0
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Error Codes
|
||
|
|
|
||
|
|
Common error codes returned by `ERR`:
|
||
|
|
|
||
|
|
| Code | Category | Description |
|
||
|
|
|------|----------|-------------|
|
||
|
|
| 1xxx | Network | HTTP and connection errors |
|
||
|
|
| 2xxx | Database | SQL and data errors |
|
||
|
|
| 3xxx | File | File system errors |
|
||
|
|
| 4xxx | Validation | Input validation errors |
|
||
|
|
| 5xxx | Auth | Authentication/authorization errors |
|
||
|
|
| 9xxx | System | Internal system errors |
|
||
|
|
|
||
|
|
### Checking Error Codes
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
result = GET url
|
||
|
|
|
||
|
|
IF ERROR THEN
|
||
|
|
SELECT CASE ERR
|
||
|
|
CASE 1001
|
||
|
|
TALK "Network timeout - please try again"
|
||
|
|
CASE 1002
|
||
|
|
TALK "Server not found"
|
||
|
|
CASE 1003
|
||
|
|
TALK "Connection refused"
|
||
|
|
CASE 1404
|
||
|
|
TALK "Resource not found"
|
||
|
|
CASE 1500
|
||
|
|
TALK "Server error - please try later"
|
||
|
|
CASE ELSE
|
||
|
|
TALK "Error " + ERR + ": " + ERROR MESSAGE
|
||
|
|
END SELECT
|
||
|
|
END IF
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Best Practices
|
||
|
|
|
||
|
|
### Always Clear Errors When Continuing
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
result = RISKY_OPERATION()
|
||
|
|
IF ERROR THEN
|
||
|
|
' Handle the error
|
||
|
|
TALK "Operation failed"
|
||
|
|
CLEAR ERROR ' Clear before next operation
|
||
|
|
END IF
|
||
|
|
|
||
|
|
' Next operation won't see stale error
|
||
|
|
result2 = ANOTHER_OPERATION()
|
||
|
|
```
|
||
|
|
|
||
|
|
### Disable Error Trapping When Done
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
' Protected code section
|
||
|
|
result = RISKY_OPERATION()
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "Handled error: " + ERROR MESSAGE
|
||
|
|
END IF
|
||
|
|
|
||
|
|
ON ERROR GOTO 0 ' Re-enable normal error behavior
|
||
|
|
|
||
|
|
' Errors here will halt execution as normal
|
||
|
|
```
|
||
|
|
|
||
|
|
### Log Errors for Debugging
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
result = COMPLEX_OPERATION()
|
||
|
|
|
||
|
|
IF ERROR THEN
|
||
|
|
' Log full details for debugging
|
||
|
|
PRINT "ERROR at " + FORMAT(NOW(), "YYYY-MM-DD HH:mm:ss")
|
||
|
|
PRINT " Code: " + ERR
|
||
|
|
PRINT " Message: " + ERROR MESSAGE
|
||
|
|
PRINT " Context: processing " + current_item.id
|
||
|
|
|
||
|
|
' User-friendly message
|
||
|
|
TALK "Something went wrong. Our team has been notified."
|
||
|
|
CLEAR ERROR
|
||
|
|
END IF
|
||
|
|
```
|
||
|
|
|
||
|
|
### Don't Ignore Errors Silently
|
||
|
|
|
||
|
|
```basic
|
||
|
|
' BAD - Errors are silently ignored
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
data = GET url
|
||
|
|
TALK "Got data: " + data ' May fail if GET failed
|
||
|
|
|
||
|
|
' GOOD - Check and handle errors
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
data = GET url
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "Could not fetch data"
|
||
|
|
data = DEFAULT_DATA
|
||
|
|
END IF
|
||
|
|
TALK "Got data: " + data
|
||
|
|
```
|
||
|
|
|
||
|
|
### Use Specific Error Checks
|
||
|
|
|
||
|
|
```basic
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
|
||
|
|
result = DATABASE_OPERATION()
|
||
|
|
|
||
|
|
IF ERROR THEN
|
||
|
|
error_msg = ERROR MESSAGE
|
||
|
|
|
||
|
|
' Handle specific errors differently
|
||
|
|
IF INSTR(error_msg, "timeout") > 0 THEN
|
||
|
|
WAIT 2
|
||
|
|
result = DATABASE_OPERATION() ' Retry
|
||
|
|
ELSE IF INSTR(error_msg, "duplicate") > 0 THEN
|
||
|
|
TALK "This record already exists"
|
||
|
|
ELSE IF INSTR(error_msg, "permission") > 0 THEN
|
||
|
|
TALK "You don't have permission for this action"
|
||
|
|
ELSE
|
||
|
|
TALK "Database error: " + error_msg
|
||
|
|
END IF
|
||
|
|
END IF
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Comparison with TRY...CATCH
|
||
|
|
|
||
|
|
For more complex error handling, you can use structured `TRY...CATCH` blocks:
|
||
|
|
|
||
|
|
```basic
|
||
|
|
' ON ERROR style (simpler)
|
||
|
|
ON ERROR RESUME NEXT
|
||
|
|
result = RISKY()
|
||
|
|
IF ERROR THEN
|
||
|
|
TALK "Error: " + ERROR MESSAGE
|
||
|
|
END IF
|
||
|
|
ON ERROR GOTO 0
|
||
|
|
|
||
|
|
' TRY...CATCH style (more structured)
|
||
|
|
TRY
|
||
|
|
result = RISKY()
|
||
|
|
CATCH e
|
||
|
|
TALK "Error: " + e.message
|
||
|
|
END TRY
|
||
|
|
```
|
||
|
|
|
||
|
|
Use `ON ERROR RESUME NEXT` for:
|
||
|
|
- Simple scripts with few error points
|
||
|
|
- Quick prototyping
|
||
|
|
- BASIC-familiar developers
|
||
|
|
|
||
|
|
Use `TRY...CATCH` for:
|
||
|
|
- Complex error handling logic
|
||
|
|
- Multiple specific catch blocks needed
|
||
|
|
- Modern structured programming style
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Implementation Notes
|
||
|
|
|
||
|
|
- Implemented in Rust under `src/basic/keywords/errors/on_error.rs`
|
||
|
|
- Error state is thread-local per script execution
|
||
|
|
- Error trapping scope is global to the script (not block-scoped)
|
||
|
|
- `CLEAR ERROR` resets both `ERROR` flag and `ERROR MESSAGE`
|
||
|
|
- Maximum error message length: 4096 characters
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Related Keywords
|
||
|
|
|
||
|
|
- [THROW](keyword-throw.md) — Raise custom errors
|
||
|
|
- [ASSERT](keyword-assert.md) — Assert conditions
|
||
|
|
- [PRINT](keyword-print.md) — Debug output for error logging
|
||
|
|
- [WAIT](keyword-wait.md) — Delay before retry
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Summary
|
||
|
|
|
||
|
|
`ON ERROR RESUME NEXT` provides BASIC error handling for BASIC scripts, allowing graceful handling of errors without script termination. Always check `ERROR` after risky operations, use `CLEAR ERROR` before subsequent operations, and disable error trapping with `ON ERROR GOTO 0` when protection is no longer needed. For user-facing errors, provide clear messages while logging technical details for debugging.
|