Getting Started
This guide walks you through installing Arx and compiling your first program.
Prerequisites
Installation
- Clone the repository:
git clone https://github.com/arxlang/arx.git
cd arx- Create the conda environment and install dependencies:
mamba env create --file conda/dev.yaml
conda activate arx
poetry install- Verify the installation:
arx --versionYour First Program
Create a file called hello.x:
```
title: Hello example
summary: Minimal Arx program that adds two values.
```
fn sum(a: i32, b: i32) -> i32:
```
title: sum
summary: Returns the sum of a and b.
```
return a + b
View the tokens
arx --show-tokens hello.xView the AST
arx --show-ast hello.xView the LLVM IR
arx --show-llvm-ir hello.xCompile to an object file
arx hello.x --output-file helloControl executable link mode
arx examples/print-star.x --link-mode auto
arx examples/print-star.x --link-mode pie
arx examples/print-star.x --link-mode no-pieExamples
The examples/ directory contains several sample programs:
Sum
```
title: Sum example
summary: Demonstrates a basic addition function.
```
fn sum(a: i32, b: i32) -> i32:
```
title: sum
summary: Returns the sum of two values.
```
return a + b;
Average
```
title: Average example
summary: Demonstrates a basic arithmetic average function.
```
fn average(x: f32, y: f32) -> f32:
```
title: average
summary: Returns the arithmetic mean of x and y.
```
return (x + y) * 0.5;
Fibonacci
```
title: Fibonacci example
summary: Computes Fibonacci numbers recursively.
```
fn fib(x: i32) -> i32:
```
title: fib
summary: Returns the Fibonacci number for the input index.
```
if x < 3:
return 1
else:
return fib(x-1)+fib(x-2)
Constant
```
title: Constant example
summary: Demonstrates a function that returns its argument unchanged.
```
fn get_constant(x: i32) -> i32:
```
title: get_constant
summary: Returns the provided value.
```
return x;
Template Functions
```
title: Template example
summary: Demonstrates compile-time specialization with inferred and explicit calls.
```
@<T: i32 | f64>
fn add(x: T, y: T) -> T:
```
title: add
summary: Adds two values with the same template-bound type.
```
return x + y
fn main() -> i32:
```
title: main
summary: Calls both inferred and explicit template specializations.
```
print(add(1, 2))
print(add<f64>(1.5, 2.5))
return 0
Print Star
```
title: Print star example
summary: Emits star characters using an external output function.
```
fn print_star(n: i32) -> none:
```
title: print_star
summary: Prints stars in a loop by calling putchard.
```
for i in range(0, n):
putchard(42); # ascii 42 = '*'
return none
fn main() -> i32:
```
title: main
summary: Runs the print_star demo with a fixed size and exits with status 0.
```
print_star(10)
return 0
Note: Arx entrypoint parameters currently follow the native C main ABI. A single main(n: i32) receives argc, not the numeric value from argv[1]. When using --run, prefer main() -> i32 and return 0 for a stable success exit code.
You can compile any example with:
arx examples/sum.x --show-llvm-irOr compile and run in one command:
arx --run examples/print-star.xAlias form is also available:
arx run examples/print-star.xPackages and Imports
When your project sets [build].src_dir, files under that directory are loaded as dotted package modules.
Example layout:
.
├── .arxproject.toml
├── src
│ └── geometry
│ ├── __init__.x
│ ├── shared
│ │ └── math.x
│ └── shapes
│ ├── area.x
│ └── helpers.x
└── tests
└── test_area.x
Example project manifest:
[project]
name = "geometry"
version = "0.1.0"
requires-arx = ">=1.0"
dependencies = [
"sciarx>=0.0.3,<1",
]
[environment]
kind = "conda"
name = "geometry"
[build-system]
dependencies = [
"arxlang>=1.0",
]
[build]
out_dir = "build"Use [project].requires-arx to declare the compatible Arx compiler versions for a project. The value uses the same version-specifier style as requires-python, for example ">=1.0,<2". [build-system].dependencies declares installable packages needed to build the project. If omitted, Arx defaults to arxlang; if requires-arx is present, the default build dependency uses that constraint.
Use [project].dependencies to declare runtime Arx package dependencies. Entries use standard dependency requirement strings, so packages may be unconstrained ("sciarx"), version constrained ("sciarx>=0.0.3,<1"), or direct references ("sciarx @ ../sciarx").
Use __init__.x as the package root. Arx uses src/ as the default source root when [build].src_dir is omitted. Inside a nested module such as geometry.shapes.area, use relative from imports for nearby modules and parent-package modules:
```
title: Geometry shapes area
summary: Package-internal import example.
```
import radius_to_diameter from .helpers
import clamp from ..shared.math
Outside the package, use either direct symbol imports or a namespace alias:
```
title: Geometry consumer
summary: Public direct import example.
```
import circle_area from geometry.shapes.area
```
title: Geometry namespace consumer
summary: Public namespace import example.
```
import geometry.shapes.area as area
fn main() -> f64:
```
title: main
summary: Calls one function through a module namespace alias.
```
return area.circle_area(10.0)
Current limitation: plain relative module imports such as import .area are not supported yet.
Compiled Tests
Arx now supports fatal assertion statements and a compiled test runner. Test functions follow a simple convention:
- files: any
test_*.xunder thetests/directory by default - function names:
test_* - signature: zero arguments
- return type:
none(always declared explicitly as-> none)
Inside a none function you can end with a bare return, an explicit return none, or omit the return statement entirely.
Example test module:
```
title: Example stdlib math tests
summary: Demonstrates `assert`, `import`, and `arx test`.
```
import math from stdlib
fn test_square() -> none:
assert math.square(3) == 9
fn test_clamp() -> none:
assert math.clamp(0 - 3, 0, 2) == 0
Run the test suite with:
arx test
arx test packages/arx/tests/arx/test_math.x --list
arx test -k square
arx test -x
arx test --keep-artifacts
arx test --exclude "packages/arx/tests/arx/slow_*.x"Test discovery can also be tuned from .arxproject.toml:
[tests]
paths = ["tests", "integration"]
exclude = ["tests/experimental_*.x"]
file_pattern = "test_*.x"
function_pattern = "test_*"CLI arguments always take precedence over [tests] settings. Discovered tests are displayed using the cwd-relative path of the source file (without the .x suffix) joined to the function name via ::, for example packages/arx/tests/arx/test_math::test_square, so same-named files in different directories stay unambiguous.
The runner compiles each selected test into its own temporary executable and reports assertion failures from IRx’s machine-readable runtime protocol. In v1, shared top-level support is limited to imports, extern declarations, class declarations, and helper functions; module-scope variable declarations and other top-level executable code are rejected during collection.
CLI Reference
arx [input_files] [options]
arx test [paths ...] [options]
| Option | Description |
|---|---|
--version |
Show the installed version |
--output-file |
Specify the output file path |
--lib |
Build source code as a library |
--show-ast |
Print the AST for the input source code |
--show-tokens |
Print the tokens for the input source |
--show-llvm-ir |
Print the LLVM IR for the input source |
--run |
Build and execute the compiled binary |
--shell |
Open Arx in a shell prompt (not yet implemented) |
--link-mode |
Set executable link mode: auto, pie, no-pie |
test |
Discover, compile, and run test_* functions |
Troubleshooting
PIE linker error in Colab or Conda
If the build fails with an error similar to:
relocation R_X86_64_32 against `.rodata' can not be used when making a PIE object
run the compile step with:
arx average.x --link-mode no-pieIf you need a manual fallback:
arx --lib average.x --output-file average.o
clang -no-pie average.o -o averageLanguage Basics
Arx’s syntax is influenced by Python with significant whitespace (indentation).
Types
Arx uses explicit type annotations for function parameters, variable declarations, and function return types. Return type annotations are always required, including -> none.
For annotation rules, see Data Types. For the full catalog of built-in types and aliases, see Built-in Types.
Functions
Functions are defined with the fn keyword and use : plus indentation for the body:
```
title: Function definition example
summary: Shows a basic function declaration.
```
fn add(x: i32, y: i32) -> i32:
```
title: add
summary: Returns x plus y.
```
return x + y
Trailing function arguments can declare defaults:
```
title: Default argument example
summary: Omits the optional offset argument.
```
fn add_offset(value: i32, offset: i32 = 1) -> i32:
```
title: add_offset
summary: Adds an optional offset to value.
```
return value + offset
Control Flow
If/else:
```
title: If/else example
summary: Shows conditional branching in a function.
```
fn abs(x: i32) -> i32:
```
title: abs
summary: Returns the absolute value of x.
```
if x < 0:
return 0 - x
else:
return x
For loop:
```
title: For loop example
summary: Shows loop syntax with the builtin range helper.
```
fn count(n: i32) -> none:
```
title: count
summary: Iterates and prints star characters.
```
for i in range(1, n):
putchard(42)
For-in loops iterate over list-valued expressions. Builtin range(start, stop[, step]) is one common source, and list literals or list variables work too.
Variables
Variables are declared with var:
```
title: Variable example
summary: Shows var binding inside a function.
```
fn example() -> i32:
```
title: example
summary: Binds a variable and computes a result.
```
var a: i32 = 10
return a + 1
Extern Functions
External functions (e.g., from C) are declared with extern:
```
title: Extern declaration example
summary: Declares an external function symbol.
```
extern putchard(x: i32) -> i32
Next Steps
- Check the Roadmap for planned features
- Read the Library Reference for language feature details
- Review Built-in Types for the canonical type catalog
- Read the Contributing Guide to help develop Arx
- Browse the API Docs for the compiler internals
- Join the Community on Discord