Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e1dbeec
Update more 0.5.0 changes
Oct 9, 2025
fe18cd6
Add more keywords
lens0021 Oct 9, 2025
b66c681
Update whats_new.md
lens0021 Oct 10, 2025
75e4814
Fix the Text to Bool examples
lens0021 Oct 10, 2025
8a42ef2
`\\`s are typos. Fix it
lens0021 Oct 10, 2025
04bf53c
Minor example code fixes
lens0021 Oct 10, 2025
e011568
Combine escaping-related sections into a single section
Oct 10, 2025
ce2bb91
Update whats_new.md
lens0021 Oct 13, 2025
06f7379
then -> exited
Ph0enixKM Nov 25, 2025
3a83ac8
then -> exited
Ph0enixKM Nov 25, 2025
3f3831d
then -> exited
Ph0enixKM Nov 25, 2025
c45bd61
Update amber highlighting
Ph0enixKM Nov 25, 2025
6ab957c
feat: refinements
Ph0enixKM Nov 26, 2025
193b476
feat: refactor
Ph0enixKM Nov 26, 2025
340d6e3
Merge branch 'main' into 0.5.0-docs
Ph0enixKM Nov 26, 2025
a6af750
feat: update escape sequence note
Ph0enixKM Nov 26, 2025
64eb33e
Merge branch '0.5.0-docs' of https://github.com/lens0021/amber-docs i…
Ph0enixKM Nov 26, 2025
83081ac
feat: update docs
Ph0enixKM Nov 26, 2025
11f22b2
feat: update examples
Ph0enixKM Nov 26, 2025
94d493b
feat: add new field for disabling unnecessary headings
Ph0enixKM Nov 27, 2025
32e19d6
feat: improve visual navigation
Ph0enixKM Nov 27, 2025
44e5e4b
Merge branch 'main' of https://github.com/Ph0enixKM/Docs-Builder into…
Ph0enixKM Nov 27, 2025
c683aa1
feat: add 0.6.0 as hidden and set 0.5.0 as default version
Ph0enixKM Nov 27, 2025
b9e88a4
fix: visual glitch
Ph0enixKM Nov 27, 2025
6f7442d
feat: update installers
Ph0enixKM Nov 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# Use 4 spaces as tab
set tabstop=2
set shiftwidth=2
set expandtab
[*]
indent_style = space
indent_size = 4
8 changes: 5 additions & 3 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{
"defaultVersion": "0.4.0-alpha",
"defaultVersion": "0.5.0-alpha",
"visibleVersions": [
"0.3.5-alpha",
"0.4.0-alpha"
"0.4.0-alpha",
"0.5.0-alpha"
],
"allVersions": [
"0.3.5-alpha",
"0.4.0-alpha",
"0.5.0-alpha"
"0.5.0-alpha",
"0.6.0-alpha"
]
}
47 changes: 39 additions & 8 deletions docs/0.5.0-alpha/basic_syntax/commands.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
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.

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:
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:
- `failed` - the recommended way to handle failing that enables you to write some specific logic to run when a command fails
- `succeeded` - allows you to write specific logic to run when a command completes successfully
- `exited` - allows you to write logic that runs regardless of whether the command failed or succeeded
- `?` - this shorthand for propagating the failure to the caller. This operator can only be used in a `main` block or inside of a function.
- `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.

Expand All @@ -22,7 +24,7 @@ echo result

> DETAILS: Command expression result is sent to the variable instead of _standard output_.

Command expression can also be interpolated with other expressions and variables
Command can also be interpolated with other expressions and variables

```ab
let file_path = "/path/to/file"
Expand All @@ -31,16 +33,45 @@ $ cat {file_path} $ failed {
}
```

## Getting the Exit Code
### Failed

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*.
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.

```ab
let file_path = "/path/to/file"
$ cat {file_path} $ failed {
echo "Error! Exit code: {status}"
$ cat file.txt $ failed(code) {
echo "Exited with code {code}."
}
```

### Succeeded

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.

```ab
$ cat file.txt $ succeeded {
echo "File was read successfully"
}
```

### Exited

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)`.

```ab
$ cat file.txt $ exited(code) {
echo "Command finished with exit code {code}"
}
echo "The status code is: {status}"
```


## Status

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.

```ab
trust $ no-access.txt < "some text" $ // status: 1
trust $ cat available-for-all.txt $ // status: 0
echo "The status code is: {status}" // The status code is 0
```

## Failure Propagation
Expand Down
16 changes: 15 additions & 1 deletion docs/0.5.0-alpha/basic_syntax/data_types.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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.

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

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

| Escape Sequence | Description |
| :-------------- | :---------- |
| `\n` | Newline |
| `\t` | Tab |
| `\r` | Carriage return |
| `\0` | Null byte |
| `\{` | Literal `{` |
| `\$` | Literal `$` |
| `\'` | Literal `'` |
| `\"` | Literal `"` |
| `\\` | Literal `\` |

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.

## Integer

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.
Expand Down
9 changes: 9 additions & 0 deletions docs/0.5.0-alpha/basic_syntax/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,12 @@ let age = 18
echo "Hi, I'm {name}. I'm {age} years old."
// Outputs: Hi, I'm John. I'm 18 years old
```
## Lexical Operations

Lexical operations allow you to compare sequences element by element (or character by character). These operations work with `Text`, `[Text]`, and `[Int]` data types.

```ab
"apple" < "banana" // true - 'a' comes before 'b'
["apple", "pie"] <= ["banana", "bread"] // true - "apple" < "banana"
[5, 1] > [4, 9] // true - 5 is greater than 4
```
15 changes: 6 additions & 9 deletions docs/0.5.0-alpha/basic_syntax/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Function declared in the example above has name `myFunction` and can take two ar
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

```ab
fun myFunction(arg1: Num, arg2: Num): Num {
fun myFunction(arg1: Int, arg2: Int): Int {
let result = arg1 + arg2
return result
}
Expand All @@ -28,7 +28,7 @@ An interesting fact about functions is that they are not parsed unless they are
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:

```ab
fun addition(a: Num, b: Num = 100): Num {
fun addition(a: Int, b: Int = 100): Int {
return a + b
}

Expand Down Expand Up @@ -65,7 +65,7 @@ Notice that using `?` operator is automatically failing with the `status` code o
If you specify the return type of a failable function, you must also append the `?` to the type name.

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

```ab
let result = safeDivision(15, 0) failed {
echo "function Failed"
echo status
let result = safeDivision(15, 0) failed(code) {
echo "Function failed with code {code}"
}
// Outputs:
// function Failed
// 1
// Outputs: Function failed with code 1
```

## Variable References `ref`
Expand Down
2 changes: 1 addition & 1 deletion docs/0.5.0-alpha/basic_syntax/importing.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ In Amber, functions can be imported from other files. To make a function accessi
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:

```ab
pub fun sum(left: Num, right: Num): Num {
pub fun sum(left: Int, right: Int): Int {
return left + right
}
```
Expand Down
4 changes: 0 additions & 4 deletions docs/0.5.0-alpha/basic_syntax/loops.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ The above example will iterate through all the files in the array and index them

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.

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."

```ab
let number = 1

Expand All @@ -71,5 +69,3 @@ while number < 100 {
// 32
// 64
```

Like other loops, `while` also supports `break` and `continue` to control the flow of execution.
77 changes: 77 additions & 0 deletions docs/0.5.0-alpha/by_example/backup_rotator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
This script demonstrates an automated backup rotation system that keeps only the most recent backups while deleting older ones.

```ab
import { dir_exists, dir_create, file_exists } from "std/fs"
import { parse_int, trim } from "std/text"
import { date_now, date_format_posix } from "std/date"

fun get_backup_count(backup_dir: Text): Int {
let count_output = trust $ ls -1 "{backup_dir}" | wc -l $
return parse_int(trim(count_output))?
}

fun create_backup(source: Text, backup_dir: Text): Int? {
let timestamp = date_format_posix(date_now())
let backup_name = "backup_{timestamp}.tar.gz"

echo "Creating backup: {backup_name}"
sudo $ tar -czf "{backup_dir}/{backup_name}" "{source}" $?

echo "Backup created successfully"
return 0
}

fun rotate_backups(backup_dir: Text, max_backups: Int) {
let current_count = get_backup_count(backup_dir)
echo "Current backup count: {current_count}"

// Remove old backups while we have too many
while current_count > max_backups {
echo "Removing oldest backup (count: {current_count}/{max_backups})"

// Get the oldest backup file
let oldest = trust $ ls -1t "{backup_dir}" | tail -n 1 $

sudo $ rm "{backup_dir}/{oldest}" $ succeeded {
echo "Removed: {oldest}"
}
current_count = get_backup_count(backup_dir)
}
echo "Backup rotation complete. Keeping {current_count} backups."
}

main(args) {
if len(args) < 2 {
echo "Usage: backup-rotator <source_dir> <backup_dir> [max_backups]"
echo "Example: backup-rotator /var/www /backups 5"
exit 1
}

let source_dir = args[0]
let backup_dir = args[1]
let max_backups = len(args) >= 3
then parse_int(args[2])?
else 5

// Validate source directory
if not dir_exists(source_dir) {
echo "Error: Source directory '{source_dir}' does not exist"
exit 1
}

// Create backup directory if it doesn't exist
if not dir_exists(backup_dir) {
echo "Creating backup directory: {backup_dir}"
sudo dir_create(backup_dir) failed {
echo "Failed to create backup directory"
exit 1
}
}

// Create new backup
create_backup(source_dir, backup_dir)?

// Rotate old backups
rotate_backups(backup_dir, max_backups)
}
```
12 changes: 5 additions & 7 deletions docs/0.5.0-alpha/by_example/bot_detector.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ main (args) {
exit 1
}

let start = parse_number($ date +%s $?)?
let start = parse_int($ date +%s $?)?

// Get server IP address for excluding.
let server_ip = $ hostname -i $?
Expand Down Expand Up @@ -62,20 +62,18 @@ main (args) {

for line in lines(ip_log) {
let parts = split(line, " ")
let count = parse_number(parts[0])?
let count = parse_int(parts[0])?
// Skip IP addresses that sent less than 1000 requests.
if count < 1000 {
continue
}

let ip = parts[1]
silent trust $ grep "{ip}" /etc/ipblocklist.txt $
if status == 0 {
trust $ grep "{ip}" /etc/ipblocklist.txt $ succeeded {
echo "IP address {ip} is already blocked."
continue
}
silent trust $ grep "{ip}" /etc/ipexcludedlist.txt $
if status == 0 {
trust $ grep "{ip}" /etc/ipexcludedlist.txt $ succeeded {
echo "IP address {ip} is allow-listed and will not be blocked."
continue
}
Expand All @@ -84,7 +82,7 @@ main (args) {
$ echo "\$(date) | IP addess {ip} added to the block list, RPH={count}" >> /var/log/bot-detector.log $?
}
}
let end = parse_number($ date +%s $?)?
let end = parse_int($ date +%s $?)?
let duration = end - start
echo "Execution time: {duration} seconds"
}
Expand Down
Loading