Skip to content

Commit 4d6123b

Browse files
committed
Polish error handling docs
1 parent 3e93ce5 commit 4d6123b

File tree

1 file changed

+31
-199
lines changed

1 file changed

+31
-199
lines changed

docs/guide/language/error-handling.md

Lines changed: 31 additions & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,47 @@ AIScript provides a robust and elegant error handling system inspired by modern
44

55
## Error Types
66

7-
In AIScript, errors are represented using enums with a special `!` suffix:
7+
In AIScript, errors are represented using enum or class with a special `!` suffix:
88

99
```js
1010
enum FileError! {
1111
NotFound,
1212
PermissionDenied,
13-
InvalidFormat(str),
13+
InvalidFormat,
14+
}
15+
16+
class SyntaxError! {
17+
message: str,
18+
line: int,
1419
}
1520
```
1621

17-
This syntax clearly communicates that an enum is meant to represent error cases.
22+
This syntax clearly communicates that an enum or class is meant to represent error cases.
1823

1924
## Declaring Functions with Error Types
2025

2126
Functions that can fail should declare their potential error types in the return signature using the pipe (`|`) operator:
2227

23-
```js
28+
```rust
2429
fn read_file(path: str) -> str | FileError! {
2530
// Implementation that might fail...
2631
}
2732
```
2833

2934
This return type specifies that the function returns either a string or a `FileError!`.
3035

36+
```rust
37+
fn read_file(path: str) -> str | FileError! | IoError! {
38+
}
39+
```
40+
41+
For multiple error types, use the`|` to seperate them.
42+
3143
## Raising Errors
3244

3345
Use the `raise` keyword to signal an error from a function:
3446

35-
```js
47+
```rust
3648
fn read_file(path: str) -> str | FileError! {
3749
if !file_exists(path) {
3850
raise FileError!::NotFound;
@@ -44,7 +56,7 @@ fn read_file(path: str) -> str | FileError! {
4456

4557
let content = read_file_contents(path);
4658
if !is_valid_format(content) {
47-
raise FileError!::InvalidFormat("Invalid file format");
59+
raise FileError!::InvalidFormat;
4860
}
4961

5062
return content;
@@ -55,40 +67,40 @@ fn read_file(path: str) -> str | FileError! {
5567

5668
AIScript provides three main ways to handle errors:
5769

58-
### 1. Using the Error Handler Syntax
70+
### Error Handler
5971

60-
The error handler syntax uses the pipe (`|`) operator followed by a code block:
72+
The error handler syntax uses the pipe (`|err|`) syntax followed by a code block:
6173

62-
```js
74+
```rust
6375
let content = read_file("config.json") |err| {
6476
match err {
6577
FileError!::NotFound => {
6678
print("File not found, using default config");
67-
return "{}"; // Default empty config
79+
"{}" // Default empty config
6880
},
6981
FileError!::PermissionDenied => {
7082
print("Permission denied, please check file permissions");
71-
return "{}";
83+
"{}"
7284
},
73-
FileError!::InvalidFormat(msg) => {
74-
print("Invalid file format: {msg}");
75-
return "{}";
85+
FileError!::InvalidFormat => {
86+
print("Invalid file format");
87+
"{}"
7688
}
7789
}
7890
};
7991

8092
// content is guaranteed to be a string here
81-
print("Config loaded: {content}");
93+
print("Config loaded:", content");
8294
```
8395
8496
The error handler receives the error as a parameter and must return a value of the same type as the success case.
8597
86-
### 2. Using the Propagation Operator (`?`)
98+
### Error Propagation
8799
88100
For functions that might fail with similar error types, you can use the `?` operator to immediately return errors to the caller:
89101
90-
```js
91-
fn load_configuration() -> object | FileError! {
102+
```rust
103+
fn load_configuration() -> str | FileError! {
92104
let file_content = read_file("config.json")?; // Propagate error
93105
let config = parse_json(file_content)?; // Propagate error
94106
return config;
@@ -97,192 +109,12 @@ fn load_configuration() -> object | FileError! {
97109
// Usage
98110
let config = load_configuration() |err| {
99111
print("Error loading configuration: {err}");
100-
return {}; // Default empty config
112+
{} // Default empty config
101113
};
102114
```
103115
104116
When a function call with `?` returns an error, the current function immediately returns with that error.
105117
106-
### 3. Match on Result Types
107-
108-
For more complex error handling logic, you can match on result types explicitly:
109-
110-
```js
111-
fn process_file() -> str | FileError! {
112-
let result = read_file("data.txt");
113-
114-
match result {
115-
str content => {
116-
// Process the content
117-
return "Processed: {content}";
118-
},
119-
FileError!::NotFound => {
120-
// Handle specific error
121-
raise FileError!::NotFound;
122-
},
123-
FileError! err => {
124-
// Handle any other error from FileError
125-
print("Error: {err}");
126-
raise err;
127-
}
128-
}
129-
}
130-
```
131-
132-
## Creating Custom Error Types
133-
134-
Create custom error types to represent domain-specific failures:
135-
136-
```js
137-
enum ValidationError! {
138-
InvalidEmail(str),
139-
InvalidPassword {
140-
reason: str,
141-
score: int,
142-
},
143-
MissingField(str),
144-
}
145-
146-
fn validate_user(user: object) -> bool | ValidationError! {
147-
if !user.email {
148-
raise ValidationError!::MissingField("email");
149-
}
150-
151-
if !is_valid_email(user.email) {
152-
raise ValidationError!::InvalidEmail(user.email);
153-
}
154-
155-
if !user.password {
156-
raise ValidationError!::MissingField("password");
157-
}
158-
159-
let password_score = calculate_password_strength(user.password);
160-
if password_score < 50 {
161-
raise ValidationError!::InvalidPassword {
162-
reason: "Password too weak",
163-
score: password_score,
164-
};
165-
}
166-
167-
return true;
168-
}
169-
```
170-
171-
## Combining Multiple Error Types
172-
173-
Functions can declare multiple potential error types:
174-
175-
```js
176-
enum DatabaseError! {
177-
ConnectionFailed,
178-
QueryFailed(str),
179-
}
180-
181-
fn save_user(user: object) -> bool | ValidationError! | DatabaseError! {
182-
// First validate the user
183-
validate_user(user)?;
184-
185-
// Then attempt to save to database
186-
if !db_connected() {
187-
raise DatabaseError!::ConnectionFailed;
188-
}
189-
190-
let result = db_insert("users", user);
191-
if !result.success {
192-
raise DatabaseError!::QueryFailed(result.message);
193-
}
194-
195-
return true;
196-
}
197-
```
198-
199-
## Converting Between Error Types
200-
201-
You can convert between error types to provide more context:
202-
203-
```js
204-
fn register_user(user_data: object) -> object | ValidationError! | DatabaseError! {
205-
let validated = validate_user(user_data)?;
206-
207-
try {
208-
return db_create_user(validated);
209-
} catch (db_error) {
210-
// Convert database error to a more user-friendly error
211-
if db_error is DatabaseError!::ConnectionFailed {
212-
print("Database connection issue, please try again later");
213-
raise DatabaseError!::ConnectionFailed;
214-
}
215-
216-
// Add context to the error
217-
raise DatabaseError!::QueryFailed("User registration failed: {db_error}");
218-
}
219-
}
220-
```
221-
222-
## Error Handling in Web APIs
223-
224-
AIScript's error handling is particularly useful for web APIs:
225-
226-
```js
227-
enum ApiError! {
228-
NotFound(str),
229-
Unauthorized,
230-
BadRequest(str),
231-
InternalError,
232-
}
233-
234-
get /users/:id {
235-
// Path parameters
236-
let user_id = params.id;
237-
238-
// Try to get user from database
239-
let user = db.get_user(user_id) |err| {
240-
match err {
241-
DatabaseError!::ConnectionFailed => {
242-
return response(500, { error: "Database connection failed" });
243-
},
244-
_ => {
245-
return response(404, { error: "User not found" });
246-
}
247-
}
248-
};
249-
250-
// Return user data
251-
return response(200, { user });
252-
}
253-
```
254-
255-
## Error Context and Debugging
256-
257-
Add context to errors to make debugging easier:
258-
259-
```js
260-
enum AppError! {
261-
OperationFailed {
262-
operation: str,
263-
cause: str,
264-
context: object,
265-
}
266-
}
267-
268-
fn process_data(data: array) -> array | AppError! {
269-
try {
270-
return transform_data(data);
271-
} catch (error) {
272-
// Add context to the error
273-
raise AppError!::OperationFailed {
274-
operation: "transform_data",
275-
cause: "{error}",
276-
context: {
277-
data_length: len(data),
278-
data_sample: data.slice(0, 5),
279-
timestamp: now(),
280-
}
281-
};
282-
}
283-
}
284-
```
285-
286118
## Best Practices
287119
288120
1. **Be specific with error types**: Create domain-specific error types for different categories of errors

0 commit comments

Comments
 (0)