Skip to content

Commit 5511987

Browse files
lens0021Ph0enixKMKrosFire
authored
Document more v0.5.0 changes (#105)
* Update more 0.5.0 changes Co-authored-by: lens0021 <lorentz0021@gmail.com> * Add more keywords * Update whats_new.md * Fix the Text to Bool examples * `\\`s are typos. Fix it * Minor example code fixes * Combine escaping-related sections into a single section * Update whats_new.md * then -> exited Co-authored-by: Hubert Jabłoński <hubik080@gmail.com> * then -> exited Co-authored-by: Hubert Jabłoński <hubik080@gmail.com> * then -> exited Co-authored-by: Hubert Jabłoński <hubik080@gmail.com> * Update amber highlighting Co-authored-by: Hubert Jabłoński <hubik080@gmail.com> * feat: refinements * feat: refactor * feat: update escape sequence note * feat: update docs * feat: update examples * feat: add new field for disabling unnecessary headings * feat: improve visual navigation * feat: add 0.6.0 as hidden and set 0.5.0 as default version * fix: visual glitch * feat: update installers --------- Co-authored-by: gemini-cli <users.noreply.github.com> Co-authored-by: Paweł Karaś <pkaras.it@gmail.com> Co-authored-by: Hubert Jabłoński <hubik080@gmail.com>
1 parent bdd3a76 commit 5511987

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+5671
-696
lines changed

.editorconfig

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# Use 4 spaces as tab
2-
set tabstop=2
3-
set shiftwidth=2
4-
set expandtab
1+
[*]
2+
indent_style = space
3+
indent_size = 4

config.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
{
2-
"defaultVersion": "0.4.0-alpha",
2+
"defaultVersion": "0.5.0-alpha",
33
"visibleVersions": [
44
"0.3.5-alpha",
5-
"0.4.0-alpha"
5+
"0.4.0-alpha",
6+
"0.5.0-alpha"
67
],
78
"allVersions": [
89
"0.3.5-alpha",
910
"0.4.0-alpha",
10-
"0.5.0-alpha"
11+
"0.5.0-alpha",
12+
"0.6.0-alpha"
1113
]
1214
}

docs/0.5.0-alpha/basic_syntax/commands.md

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
The only way to access the bash shell is through Amber's commands. Commands can be used in the form of a statement or an expression.
22

3-
Commands can sometimes _fail_, so it’s important for whoever uses them to be ready to handle what happens next. There are different ways to deal with failures, each with its own pros and cons:
3+
Commands (as well as *failable functions*) can sometimes _fail_, so it’s important for whoever uses them to be ready to handle what happens next. There are different ways to deal with failures, each with its own pros and cons:
44
- `failed` - the recommended way to handle failing that enables you to write some specific logic to run when a command fails
5+
- `succeeded` - allows you to write specific logic to run when a command completes successfully
6+
- `exited` - allows you to write logic that runs regardless of whether the command failed or succeeded
57
- `?` - this shorthand for propagating the failure to the caller. This operator can only be used in a `main` block or inside of a function.
68
- `trust` - the discouraged way to handle failing. This modifier will treat commands as if they have completed successfully and will allow them to be parsed without any further steps.
79

@@ -22,7 +24,7 @@ echo result
2224

2325
> DETAILS: Command expression result is sent to the variable instead of _standard output_.
2426
25-
Command expression can also be interpolated with other expressions and variables
27+
Command can also be interpolated with other expressions and variables
2628

2729
```ab
2830
let file_path = "/path/to/file"
@@ -31,16 +33,45 @@ $ cat {file_path} $ failed {
3133
}
3234
```
3335

34-
## Getting the Exit Code
36+
### Failed
3537

36-
In order to get the exit code, you can use the `status` keyword. It will always return you the exit code of the last bash command or *failable function*.
38+
The `failed` modifier allows you to write specific logic that runs only when a command fails. This is useful when you want to handle errors gracefully or perform recovery operations. Note that `failed` can optionally accept an exit code parameter, like `failed(code)`, to access the command's exit code.
3739

3840
```ab
39-
let file_path = "/path/to/file"
40-
$ cat {file_path} $ failed {
41-
echo "Error! Exit code: {status}"
41+
$ cat file.txt $ failed(code) {
42+
echo "Exited with code {code}."
43+
}
44+
```
45+
46+
### Succeeded
47+
48+
Just like `failed` allows you to handle command failures, `succeeded` lets you write specific logic that runs only when a command completes successfully. This can be useful when you want to perform additional operations that should only happen if the command succeeds.
49+
50+
```ab
51+
$ cat file.txt $ succeeded {
52+
echo "File was read successfully"
53+
}
54+
```
55+
56+
### Exited
57+
58+
The `exited` modifier allows you to write logic that runs regardless of whether the command failed or succeeded. This is useful when you need to perform cleanup or logging operations that should always happen. Note that `exited` can only be used when an exit code parameter is provided, like `exited(code)`.
59+
60+
```ab
61+
$ cat file.txt $ exited(code) {
62+
echo "Command finished with exit code {code}"
4263
}
43-
echo "The status code is: {status}"
64+
```
65+
66+
67+
## Status
68+
69+
The `status` keyword allows you to access the exit code of a command. This is the old school and Bash way of handling failures. Its trait is that it holds the exit code of only the previous command or *failable function* call.
70+
71+
```ab
72+
trust $ no-access.txt < "some text" $ // status: 1
73+
trust $ cat available-for-all.txt $ // status: 0
74+
echo "The status code is: {status}" // The status code is 0
4475
```
4576

4677
## Failure Propagation

docs/0.5.0-alpha/basic_syntax/data_types.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
In Bash there is only one primitive data type, string, which internal implementation is represented by an array of characters `char*`. Amber extends on this data type to introduce a few more.
22

3-
Amber supports five data types:
3+
Amber supports six data types:
44
- `Text` - The textual data type. In other programming languages it can also be called "string".
55
- `Int` - Integer data type.
66
- `Num` - The numeric data type. It's basically any number.
@@ -21,6 +21,20 @@ Text literal in Amber is contained between double quotes. Amber makes sure to pr
2121

2222
Just like in other programming languages, characters in `Text` literals can be escaped.
2323

24+
| Escape Sequence | Description |
25+
| :-------------- | :---------- |
26+
| `\n` | Newline |
27+
| `\t` | Tab |
28+
| `\r` | Carriage return |
29+
| `\0` | Null byte |
30+
| `\{` | Literal `{` |
31+
| `\$` | Literal `$` |
32+
| `\'` | Literal `'` |
33+
| `\"` | Literal `"` |
34+
| `\\` | Literal `\` |
35+
36+
Any other escape sequence not listed above will be treated as a literal escape sequence, similar to how Bash handles them. For instance, escaping `\c` will result in the literal `\c` being output.
37+
2438
## Integer
2539

2640
Under the hood its value is stored as a string of characters - the same way as it's done in Bash. However when performing operations the values are treated as 64-bit signed integers.

docs/0.5.0-alpha/basic_syntax/expressions.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,12 @@ let age = 18
9999
echo "Hi, I'm {name}. I'm {age} years old."
100100
// Outputs: Hi, I'm John. I'm 18 years old
101101
```
102+
## Lexical Operations
103+
104+
Lexical operations allow you to compare sequences element by element (or character by character). These operations work with `Text`, `[Text]`, and `[Int]` data types.
105+
106+
```ab
107+
"apple" < "banana" // true - 'a' comes before 'b'
108+
["apple", "pie"] <= ["banana", "bread"] // true - "apple" < "banana"
109+
[5, 1] > [4, 9] // true - 5 is greater than 4
110+
```

docs/0.5.0-alpha/basic_syntax/functions.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Function declared in the example above has name `myFunction` and can take two ar
1717
If you want to declare a function that takes arguments of certain type - you are encouraged to do this. However, for consistency you are required to specify the return type as well
1818

1919
```ab
20-
fun myFunction(arg1: Num, arg2: Num): Num {
20+
fun myFunction(arg1: Int, arg2: Int): Int {
2121
let result = arg1 + arg2
2222
return result
2323
}
@@ -28,7 +28,7 @@ An interesting fact about functions is that they are not parsed unless they are
2828
On the condition that you specify an argument's type, you can also specify its default value — it will be used if none other is provided when the function is called:
2929

3030
```ab
31-
fun addition(a: Num, b: Num = 100): Num {
31+
fun addition(a: Int, b: Int = 100): Int {
3232
return a + b
3333
}
3434
@@ -65,7 +65,7 @@ Notice that using `?` operator is automatically failing with the `status` code o
6565
If you specify the return type of a failable function, you must also append the `?` to the type name.
6666

6767
```ab
68-
fun failable(): Num? {
68+
fun failable(): Int? {
6969
if 0 > 5 {
7070
fail 1
7171
}
@@ -98,13 +98,10 @@ echo "{result}, {status}"
9898
This was a happy ending. Now let's see what happens when we divide by zero:
9999

100100
```ab
101-
let result = safeDivision(15, 0) failed {
102-
echo "function Failed"
103-
echo status
101+
let result = safeDivision(15, 0) failed(code) {
102+
echo "Function failed with code {code}"
104103
}
105-
// Outputs:
106-
// function Failed
107-
// 1
104+
// Outputs: Function failed with code 1
108105
```
109106

110107
## Variable References `ref`

docs/0.5.0-alpha/basic_syntax/importing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ In Amber, functions can be imported from other files. To make a function accessi
55
To declare a function as public we can use a `pub` keyword. Let's keep in mind that `pub` keyword has to be used before the `fun` keyword that declares our function:
66

77
```ab
8-
pub fun sum(left: Num, right: Num): Num {
8+
pub fun sum(left: Int, right: Int): Int {
99
return left + right
1010
}
1111
```

docs/0.5.0-alpha/basic_syntax/loops.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ The above example will iterate through all the files in the array and index them
5353

5454
The `while` loop is used to repeat a block of code as long as a condition is true. It's most powerful in situations where the number of iterations is not easily known beforehand.
5555

56-
Consider an example where we want to find all powers of two less than 1000. While this could be calculated with a `for` loop, a `while` loop expresses the goal more directly: "keep doubling the number as long as it's less than 1000."
57-
5856
```ab
5957
let number = 1
6058
@@ -71,5 +69,3 @@ while number < 100 {
7169
// 32
7270
// 64
7371
```
74-
75-
Like other loops, `while` also supports `break` and `continue` to control the flow of execution.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
This script demonstrates an automated backup rotation system that keeps only the most recent backups while deleting older ones.
2+
3+
```ab
4+
import { dir_exists, dir_create, file_exists } from "std/fs"
5+
import { parse_int, trim } from "std/text"
6+
import { date_now, date_format_posix } from "std/date"
7+
8+
fun get_backup_count(backup_dir: Text): Int {
9+
let count_output = trust $ ls -1 "{backup_dir}" | wc -l $
10+
return parse_int(trim(count_output))?
11+
}
12+
13+
fun create_backup(source: Text, backup_dir: Text): Int? {
14+
let timestamp = date_format_posix(date_now())
15+
let backup_name = "backup_{timestamp}.tar.gz"
16+
17+
echo "Creating backup: {backup_name}"
18+
sudo $ tar -czf "{backup_dir}/{backup_name}" "{source}" $?
19+
20+
echo "Backup created successfully"
21+
return 0
22+
}
23+
24+
fun rotate_backups(backup_dir: Text, max_backups: Int) {
25+
let current_count = get_backup_count(backup_dir)
26+
echo "Current backup count: {current_count}"
27+
28+
// Remove old backups while we have too many
29+
while current_count > max_backups {
30+
echo "Removing oldest backup (count: {current_count}/{max_backups})"
31+
32+
// Get the oldest backup file
33+
let oldest = trust $ ls -1t "{backup_dir}" | tail -n 1 $
34+
35+
sudo $ rm "{backup_dir}/{oldest}" $ succeeded {
36+
echo "Removed: {oldest}"
37+
}
38+
current_count = get_backup_count(backup_dir)
39+
}
40+
echo "Backup rotation complete. Keeping {current_count} backups."
41+
}
42+
43+
main(args) {
44+
if len(args) < 2 {
45+
echo "Usage: backup-rotator <source_dir> <backup_dir> [max_backups]"
46+
echo "Example: backup-rotator /var/www /backups 5"
47+
exit 1
48+
}
49+
50+
let source_dir = args[0]
51+
let backup_dir = args[1]
52+
let max_backups = len(args) >= 3
53+
then parse_int(args[2])?
54+
else 5
55+
56+
// Validate source directory
57+
if not dir_exists(source_dir) {
58+
echo "Error: Source directory '{source_dir}' does not exist"
59+
exit 1
60+
}
61+
62+
// Create backup directory if it doesn't exist
63+
if not dir_exists(backup_dir) {
64+
echo "Creating backup directory: {backup_dir}"
65+
sudo dir_create(backup_dir) failed {
66+
echo "Failed to create backup directory"
67+
exit 1
68+
}
69+
}
70+
71+
// Create new backup
72+
create_backup(source_dir, backup_dir)?
73+
74+
// Rotate old backups
75+
rotate_backups(backup_dir, max_backups)
76+
}
77+
```

docs/0.5.0-alpha/by_example/bot_detector.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ main (args) {
2121
exit 1
2222
}
2323
24-
let start = parse_number($ date +%s $?)?
24+
let start = parse_int($ date +%s $?)?
2525
2626
// Get server IP address for excluding.
2727
let server_ip = $ hostname -i $?
@@ -62,20 +62,18 @@ main (args) {
6262
6363
for line in lines(ip_log) {
6464
let parts = split(line, " ")
65-
let count = parse_number(parts[0])?
65+
let count = parse_int(parts[0])?
6666
// Skip IP addresses that sent less than 1000 requests.
6767
if count < 1000 {
6868
continue
6969
}
7070
7171
let ip = parts[1]
72-
silent trust $ grep "{ip}" /etc/ipblocklist.txt $
73-
if status == 0 {
72+
trust $ grep "{ip}" /etc/ipblocklist.txt $ succeeded {
7473
echo "IP address {ip} is already blocked."
7574
continue
7675
}
77-
silent trust $ grep "{ip}" /etc/ipexcludedlist.txt $
78-
if status == 0 {
76+
trust $ grep "{ip}" /etc/ipexcludedlist.txt $ succeeded {
7977
echo "IP address {ip} is allow-listed and will not be blocked."
8078
continue
8179
}
@@ -84,7 +82,7 @@ main (args) {
8482
$ echo "\$(date) | IP addess {ip} added to the block list, RPH={count}" >> /var/log/bot-detector.log $?
8583
}
8684
}
87-
let end = parse_number($ date +%s $?)?
85+
let end = parse_int($ date +%s $?)?
8886
let duration = end - start
8987
echo "Execution time: {duration} seconds"
9088
}

0 commit comments

Comments
 (0)