Getting started
Install a release
The quickest way in — no compiler needed:
$ curl -fsSL https://github.com/NT9712/vela/releases/latest/download/vela-1.1.0-linux-x86_64.tar.gz | tar xz
$ cd vela-1.1.0-linux-x86_64
$ ./install.sh ~/.local
$ export PATH="$HOME/.local/bin:$PATH"
$ vela version
vela 1.0.0
velac finds its standard library next to itself, so no environment variable is needed unless you move the binaries apart from lib/vela.
To build from source instead, read on.
Requirements
- Linux on x86-64 or ARM64
- a C compiler (
ccorgcc) andmake— needed once, to build the bootstrap compiler
Nothing else. The compiler has no library dependencies and the programs it produces have none either.
Build the toolchain
$ cd vela
$ make
cc -O2 ... -o bin/velac ...
VELA_ROOT=... bin/velac -o bin/vela tools/cli.vela
make builds two things:
bin/velac— the bootstrap compiler, written in Cbin/vela— the toolchain driver, written in Vela and compiled byvelac
Put them on your PATH and tell the compiler where the standard library lives:
$ export PATH="$PWD/bin:$PATH"
$ export VELA_ROOT="$PWD"
$ vela version
vela 1.0.0
VELA_ROOT is only needed if you move the binaries away from the checkout; velac otherwise finds the library relative to its own location. It accepts either the installation root (containing lib/) or the library directory itself (containing core/ and std/).
Your first project
$ vela new hello
created hello/
cd hello
vela run
$ cd hello
$ ls
.gitignore src/ vela.toml
vela.toml is the manifest:
[package]
name = "hello"
version = "0.1.0"
main = "src/main.vela"
[deps]
src/main.vela:
use std/io
fn main() {
io.println("hello from hello")
}
test "greeting is not empty" {
assert(len("hello") > 0)
}
Build, run, test
$ vela run
hello from hello
$ vela build
built /home/you/hello/build/hello
$ ./build/hello
hello from hello
$ vela test
test greeting is not empty ... ok
1 passed, 0 failed, 1 total
The binary is static and self-contained:
$ ls -l build/hello
-rwxr-xr-x 1 you you 10K build/hello
$ ldd build/hello
not a dynamic executable
Write something real
Replace src/main.vela:
use std/io
use std/os
struct Task {
title: Str,
done: Bool,
}
fn Task.to_str(self) -> Str {
let box = if self.done { "[x]" } else { "[ ]" }
return "{box} {self.title}"
}
fn main() {
let tasks = [
Task{ title: "write a language", done: true },
Task{ title: "write the docs", done: false },
]
for i, t in tasks {
io.println("{i + 1}. {t}")
}
let left = tasks.filter(|t| not t.done)
io.println("{len(left)} remaining")
}
$ vela run
1. [x] write a language
2. [ ] write the docs
1 remaining
Note Task.to_str — defining it changes how Task renders everywhere, including inside lists and maps.
Break it on purpose
fn main() {
let name = "bob"
let age = 30
println(name + age)
}
$ vela check
error: cannot add `Str` and `Int`
--> src/main.vela:4:13
|
4 | println(name + age)
| ^^^^^^^^^^
= note: expected `Str + Str`
= note: found `Str + Int`
= note: help: convert the right side with `str(x)`, or write `"{a}{b}"`
1 error
Try a few more: misspell a method, forget a match arm, assign to a let that is not mut. The compiler is meant to tell you what to do next, not just what is wrong.
Format
$ vela fmt
formatted src/main.vela
$ vela fmt --check # exits 1 if anything would change; good for CI
1 file(s) already formatted
There is one canonical style and no options.
Add a dependency
Dependencies are local directories with their own vela.toml.
$ vela add mathx --path ../mathx
added mathx = ../mathx
[deps]
mathx = { path = "../mathx" }
use mathx/mathx
fn main() {
println("{mathx.triple(14)}")
}
vela add also writes vela.lock, which records each dependency's resolved path, version and a content hash, so a build is reproducible and you can see when a local dependency changed.
Generate documentation
$ vela doc
wrote 1 page(s) to /home/you/hello/docs/api
/// comments become Markdown, one page per module.
The REPL
$ vela repl
vela 1.0.0 repl - type an expression, or :help
> 1 + 2
3
> let xs = [3, 1, 2]
> xs.sort_by(|a, b| a < b)
> xs
[1, 2, 3]
> fn double(n: Int) -> Int { return n * 2 }
> double(21)
42
> :q
Definitions persist for the session. :clear forgets them, :list shows them.
Cross-compile
$ vela build --target arm64
built /home/you/hello/build/hello-arm64
$ file build/hello-arm64
build/hello-arm64: ELF 64-bit LSB executable, ARM aarch64, statically linked
Nothing needs installing for this. velac encodes the instructions and writes the ELF itself, so there is no cross assembler and no cross linker in the way. The same works in the other direction from an ARM64 machine.
Where to go next
- The tour — every feature, with examples
- The specification — the precise rules
- The standard library — every public API
examples/— a calculator, a word counter, an HTTP server, Conway's life, and a multi-file application