Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive

- name: Install Rust (1.96)
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.96.0
components: rustfmt, clippy

- name: Install fasm
run: sudo apt-get update && sudo apt-get install -y fasm

- name: Cache dependencies
uses: Swatinem/rust-cache@v2
with:
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ program.
app
*.o
*.so
*.ssa
*.asm
main.s
*.il
bin
Expand All @@ -14,5 +16,6 @@ zig-cache/
.zig-cache/

# SDK - tracked as separate submodule
sdk/
/sdk/
.wrangler/
/azlang-docs/book/
4 changes: 2 additions & 2 deletions azlang-docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@
# Architecture & Compiler Pipeline
- [Pipeline: Tokenizer to AST](./internals/frontend.md)
- [Semantic Validation & Symbol Tables](./internals/validator.md)
- [QBE Intermediate Representation](./internals/qbe.md)
- [Direct Assembly & Linking](./internals/assembly_linking.md)
- [fasm Assembly Emission](./internals/fasm.md)
- [Single-Pass Assembly & Binary Layout](./internals/direct_assembly.md)
40 changes: 13 additions & 27 deletions azlang-docs/src/getting-started/hello_world.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,25 @@ enum FD
Stdout
Stderr

@link("./sdk/build/write.o")
@link("./sdk/src/write.s")
op write(FD fd, const str val, const int size): void

@link("./sdk/build/exit.o")
@link("./sdk/src/exit.s")
op exit(const int val): void

write(Stdout, "Hello World from AzLang!\n", 25)
exit(0)
```

### Deconstructing the Code:
1. `enum FD`: Defines standard file descriptors (`Stdin=0`, `Stdout=1`, `Stderr=2`).
2. `@link(...)`: Links directly to an object file (`write.o` / `exit.o`) compiled from assembly stubs that perform direct Linux syscalls (`syscall` instruction).
1. `enum FD`: Defines standard file descriptors (`Stdin=0`, `Stdout=1`, `Stderr=2`). Enum variants are inlined as immediates — no lookup table exists at runtime.
2. `@link(...)`: Points at a fasm assembly source containing a syscall stub that performs a direct Linux `syscall` instruction. The source is included straight into the generated assembly — there is nothing to pre-compile.
3. `op write(...)`: Declares a callable operation function signature and parameter types.
4. `write(...)` & `exit(...)`: Calls the operations natively without libc overhead.
4. `write(...)` & `exit(...)`: Calls the operations natively without libc overhead. The string length `25` accounts for the `\n` escape, which is resolved to a single newline byte at emission time.

---

## 2. Compiling the SDK Assembly Stubs

If you are working inside the repository or using the SDK:

```bash
# Build the assembly syscall objects
as sdk/src/write.s -o sdk/build/write.o
as sdk/src/exit.s -o sdk/build/exit.o
```

---

## 3. Compiling and Running with AzCLI
## 2. Compiling with AzCLI

Compile `main.az` using `azcli`:

Expand All @@ -55,24 +43,22 @@ azcli build main.az
The AzLang pipeline will:
1. Parse `main.az` into an AST.
2. Validate symbols and types.
3. Emit QBE Intermediate Language (`main.il`).
4. Invoke `qbe` to produce `main.s`.
5. Invoke `as` to produce `main.o`.
6. Invoke `ld.lld` to link `main.o` together with `write.o` and `exit.o` into the standalone binary `app`.
3. Emit a single assembly file (`main.asm`) containing the program code, its string data, and `include` directives for `write.s` and `exit.s`.
4. Invoke `fasm`, which assembles and links that file directly into the standalone binary `main` in one pass.

> The backend tools (`qbe`, `as`, `ld.lld`) are pulled in automatically by the `azlang` package. You never need to install or call them yourself.
> The only external tool required is **[fasm](https://flatassembler.net/)**. There is no `qbe`, no `as`, no `ld` and no object files.

Run the resulting executable:

```bash
./app
./main
# Output:
# Hello World from AzLang!
```

Check the binary size:
```bash
ls -lh app
# Output: ~2.6K
ls -l main
# 228 bytes
```
A complete, functional ELF binary in less than 3 kilobytes!
A complete, functional ELF executable in 228 bytes!
14 changes: 10 additions & 4 deletions azlang-docs/src/getting-started/installation.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Installation

AzLang ships as a single, self-contained compiler. It has no dependencies: no runtime, no external toolchain, nothing else to install.
AzLang ships as a single compiler binary. There is no runtime to install, no VM, and no LLVM-sized toolchain — the only external tool the compiler invokes is **fasm**.

---

Expand All @@ -14,13 +14,19 @@ This generates the `azcli` binary executable.

---

## Arch Linux / Package Manager
## Installing fasm

AzLang emits one `.asm` file per build and hands it to [fasm](https://flatassembler.net/), which assembles and links it into a standalone ELF executable in a single pass.

```bash
sudo pacman -S azcli
# Arch Linux
sudo pacman -S fasm

# Debian / Ubuntu
sudo apt install fasm
```

That's it.
For other platforms, download fasm from <https://flatassembler.net/> and put it on your `PATH`.

---

Expand Down
28 changes: 0 additions & 28 deletions azlang-docs/src/internals/assembly_linking.md

This file was deleted.

36 changes: 36 additions & 0 deletions azlang-docs/src/internals/direct_assembly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Single-Pass Assembly & Binary Layout

The final stage of the AzLang compiler pipeline turns the emitted assembly into a finished, standalone bare-metal executable — in one invocation, with no linker.

---

## 1. Pipeline Execution Flow

AzLang produces machine code through a deterministic two-step lowering pipeline:

1. **Assembly Emission**: the validated AST is lowered into one `.asm` file — header, `include` directives for every invoked `@link` source, the program's code, and its string data.
2. **Single-Pass Assembly**: `fasm` assembles that file directly into the final ELF executable. Assembly and linking happen in the same pass, so no intermediate object files ever exist.

```bash
fasm main.asm main
```

Because `@link` targets are fasm assembly *sources* (not pre-built `.o` files), there is nothing to pre-compile: the symbols `write`, `exit`, etc. are defined in the same translation unit and resolved statically at assembly time.

---

## 2. Resulting Binary

AzLang emits `format ELF64 executable` with `entry _start` and a single `readable executable` segment (a 120-byte program header). Because the program targets the system entry point `_start` and inlines its syscall stubs, no C runtime or dynamic linker is involved:

- **No dynamic interpreter** (`/lib64/ld-linux-x86-64.so.2` is not required)
- **No section headers, no relocations** — a minimal static image
- **Tiny footprint**: the Hello World program measures **228 bytes**; a comprehensive 60-line multi-module program stays around **2 KB**
- **Instantaneous startup**: execution begins at `_start` with direct syscalls

```text
$ file main
main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, no section header
$ ./main
Hello World from AzLang!
```
58 changes: 58 additions & 0 deletions azlang-docs/src/internals/fasm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# fasm Assembly Emission

AzLang compiles code by emitting a single, human-readable **fasm** (flat assembler) assembly file, which `fasm` turns directly into a native ELF executable in one pass.

---

## 1. Why fasm?

fasm was chosen because it aligns with AzLang's minimalist engineering doctrine:
- **One Pass, One Binary**: fasm assembles *and* links in a single step — there is no separate `as`, no `ld`, no object files.
- **Small Footprint**: the entire fasm distribution is a single binary of well under 1 MB.
- **Readable Output**: the emitted `.asm` is clean, commented-friendly x86_64 assembly you can inspect directly.

---

## 2. Sample Assembly Emission

Here is the exact assembly generated for the [Hello World](../getting-started/hello_world.md) program (paths abbreviated; the compiler canonicalizes them to absolute paths):

```asm
format ELF64 executable
entry _start

segment readable executable

include "./sdk/src/write.s"
include "./sdk/src/exit.s"

_start:
push rbp
mov rbp, rsp
sub rsp, 8
mov rax, 1
push rax
lea rax, [main_str0]
push rax
mov rax, 25
push rax
pop rdx
pop rsi
pop rdi
call write
mov rax, 0
push rax
pop rdi
call exit
xor edi, edi
mov eax, 60
syscall

main_str0 db "Hello World from AzLang!",10,0
```

AzLang generates this directly from the validated AST:
- Function calls lower to ordinary `call <symbol>` instructions following the System V AMD64 ABI (register arguments, 16-byte stack alignment).
- String literals become `db` data directives (escape sequences such as `\n` are resolved to bytes at emission time).
- `@link(...)` sources that are actually invoked are pulled in with `include`, so unused SDK stubs never reach the binary.
- Programs end with a direct `sys_exit` (`rax = 60`) — no C runtime, no `ret` to nowhere.
31 changes: 0 additions & 31 deletions azlang-docs/src/internals/qbe.md

This file was deleted.

2 changes: 1 addition & 1 deletion azlang-docs/src/internals/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ During semantic validation, the compiler analyzes program declarations to verify

- **Type Safety**: Variable assignments, arithmetic expressions, and function arguments match expected types.
- **Scope Management**: Variables, constants, and functions are validated within their lexical scopes.
- **Link Registry**: External function declarations (`@link`) are recorded and prepared for the linker phase.
- **Link Registry**: External function declarations (`@link`) are recorded as `(operation, source path)` pairs and prepared for assembly emission.
- **Unused & Mutation Tracking**: Identifies immutable violations and unused bindings at compile-time.

---
Expand Down
27 changes: 11 additions & 16 deletions azlang-docs/src/introduction.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Introduction to AzLang

> **AzLang** is a minimal, blazingly fast, and readable systems programming language engineered for direct bare-metal execution, sub-3KB binary output, and zero-runtime overhead.
> **AzLang** is a minimal, blazingly fast, and readable systems programming language engineered for direct bare-metal execution, sub-kilobyte binary output, and zero-runtime overhead.

AzLang blends **Python-like visual clarity**, **Rust-like memory control**, and **TypeScript-like type safety**, stripping away heavy runtime abstractions and external runtime daemons.

Expand All @@ -9,10 +9,10 @@ AzLang blends **Python-like visual clarity**, **Rust-like memory control**, and
## Key Characteristics

- **Zero-VM Execution**: No virtual machines, dynamic garbage collectors, or heavy runtime initialization routines (`crt1.o`). Execution lowers directly to native machine code.
- **Microsecond Compilations**: A lean frontend passes verified AST directly to intermediate representation and native machine instructions.
- **Lean Binary Footprint**: Produces standalone, self-contained ELF executables often measuring between **2KB and 3KB**.
- **Microsecond Compilations**: A lean frontend passes verified AST directly to fasm assembly and native machine instructions in a single pass.
- **Lean Binary Footprint**: Produces standalone, self-contained ELF executables — a hello world program measures **228 bytes**, and a comprehensive multi-module program stays around **2 KB**.
- **Absence of Moving Parts**: Eliminates runtime state machines, dynamic heap leaks, and unwinding tables by design.
- **Direct ABI & Syscall Interop**: High-performance systems interfaces via native `@link` decorators and direct kernel syscall invocation (`x86_64` register calling conventions).
- **Direct ABI & Syscall Interop**: High-performance systems interfaces via native `@link` directives and direct kernel syscall invocation (`x86_64` register calling conventions).

---

Expand All @@ -31,18 +31,13 @@ AzLang blends **Python-like visual clarity**, **Rust-like memory control**, and
│ [AST Construction & Validation] │
│ │ │
│ ▼ │
│ [Direct AST Lowering / QBE IR (.il)] │
│ [Transpiler → fasm Assembly (.asm)] ──► @link syscall stubs included inline │
│ │ │
│ ▼ │
│ [Native Assembly Generation (.s)] ──► [Assembler: as] ──► Object (.o) │
│ │ │
│ [Direct Syscalls] │
│ │ │
│ ▼ │
│ [Linker: ld.lld] │
│ │ │
│ ▼ │
│ [~2.6 KB Bare-Metal Binary] │
│ [fasm: single-pass assembler & linker] │
│ │ │
│ ▼ │
│ [~228 Byte Bare-Metal ELF] │
└───────────────────────────────────────────────────────────────────────────────────┘
```

Expand All @@ -58,10 +53,10 @@ enum FD
Stdout
Stderr

@link("./sdk/build/write.o")
@link("./sdk/src/write.s")
op write(FD fd, const str val, const int size): void

@link("./sdk/build/exit.o")
@link("./sdk/src/exit.s")
op exit(const int val): void

write(Stdout, "Hello, Bare Metal AzLang!\n", 26)
Expand Down
Loading
Loading