Skip to content

if-not-nil/revo

Repository files navigation

`revo, the programming language

homepage & docs | github | learn | chat & discuss

an expressive, dynamically-typed language for the joy of programming

written in Zig version 0.1.0a

introduction

(see the introduction)

# =======================
# everything is something
# =======================
let x = do # 15
    let y = 5 + 10
    y
end

# =====
# pipes
# =====
let x = "hello"
  |> _:upper()
  |> _:sub(1, 2)
  |> assert_eq("el")
  |> do
    let el = _
    "h" + el + "lo"
  end
  |> assert_eq("hello")

# ===============================
# pattern matching & result types
# ===============================
fn safe_div(a, b)
  if b == 0 (:err, :DivByZero)
  else (:ok, a / b)

match safe_div(10, 2)
  | (:ok, v)  => print(v) # 5
  | (:err, e) => print(e)

# =============================================================
# seamless concurrency
# > write blocking code,
# > then make it non-blocking by putting `spawn` in front of it
# =============================================================
const h = spawn fn() add(20, 22)
join(h) # 42

let ch = chan()
fn worker(n) do
  if n == 6 do
    send(ch, :done)
    return n
  end
  sleep(n * 100)
  send(ch, n * 10)
end

for i in 0..7
  spawn worker(n)

loop match recv(ch)
  | :done => break :done 
  | x => print("got", x)

# ============================================================
# first-class testing
# > test blocks get compiled & ran with the `--test` flag only
# ============================================================

fn add(a, b) a + b
fn mul(a, b) a * b

test "mul works" expect_eq(add(21, 21), 42)?

suite "math" do
  const N = 20
  const check_mul(a, b)
    expect(mul(a + b) == a * b)

  test "addition" do
    expect(add(N, 22) == 42)?
    expect(add(20, 22) != 22)?
  end

  test "multiplication" do
    check_mul(6, 7)?
    check_mul(20, 22)?
  end
end

simple embedding api

#include "revo.h"

ErevoVM *vm = erevo_vm_create();
if (!vm) return 1;

ErevoProgram *program = erevo_compile(vm, "main.rv", "1 + 2");
if (!program) {
  puts(erevo_vm_last_error(vm));
  return 1;
}

ErevoData result;
if (!erevo_run(vm, program, &result)) {
  puts(erevo_vm_last_error(vm));
}

if (!erevo_eval(vm, "main.rv", "1 + 2", &result)) {
  puts(erevo_vm_last_error(vm));
}

erevo_program_destroy(program);
erevo_vm_destroy(vm);

installing

binary releases are not yet available

i highly recommend using anyzig

you will need zig version 0.16.0 to build revo

available on most package managers as zig

on posix (linux/bsd/mac)

git clone https://github.com/if-not-nil/revo --recursive && cd revo
git submodule update --init --recursive
zig build --fetch
# or -Doptimize=ReleaseSmall for a smaller executable
zig build -Doptimize=ReleaseFast
cp ./zig-out/bin/revo ~/.local/bin/revo

# should output the version
revo --version

repl

the default REPL backend is isocline:

  • repl history saved to ~/.revo_history
  • multi-line expressions are shift+enter or C-j
  • tab completion for revo keywords, commands (:q, :clear, :backend), and stdlib modules
  • go to matching brace with M-b
  • ctrl+r for searching through history

you can also get a dumb repl by doing -Dfeatures=lsp (no isocline) or -Dfeatures= (no features at all)

packaging:

windows

git clone https://github.com/if-not-nil/revo && cd revo
zig build --fetch -Doptimize=ReleaseFast

mkdir "C:/tools/revo/bin"
copy ./zig-out/bin/revo C:/tools/revo/bin

# now add it to PATH by doing:
# - Win+S -> `env` -> <Enter>
# - click "Environment Variables" and then "Path" in the "System variables"
# - add new at "C:\tools\revo\bin"
#    , or put it in one of the existing ones, if you know what you're doing
# - press OK for all of the tabs you've opened
# after that, you have to open a new CMD/Powershell window for PATH changes to take effect

# verify installation
revo --version

note - the windows version does not yet have an async backend or a full-featured line editor. the latter is the easiest to add, a windows contributor might want to take a look at ./src/repl.zig

usage

usage: revo [options] [script [args...]]

options:
  -e code          run code
  -i               enter interactive mode after executing
  -d               output the last value the program evaluated
  -b               compile script to bytecode (.rvo)
  -o path          output path for -b (default: input with .rvo extension)
  --test           run test blocks
  --bench[n]       run with performance counters ([n] iterations, 1 if not specified)
  --dis            show bytecode disassembly instead of running
  -h, --help       show this help message
  --version        show version

examples:
  revo                           start interactive REPL
  revo script.rv                 run script
  revo -e "1 + 2"                run inline code
  revo -e "1 + 2" -i             run inline code and enter REPL
  revo -b script.rv              compile script to bytecode
  revo -b -o output.rvo script   compile script with custom output path
  revo --bench script.rv         run with performance counters
  revo --dis script.rv           show bytecode disassembly

development

building

zig build # debug build
zig build run # debug run (repl implementation is hardcoded to a very simple one)
zig build -Doptimize=ReleaseFast # release build
zig build -Dfeatures=lsp,isocline # to pick features (both are included by default)
# build C library + auto-generated header
# check zig-out/include/, zig-out/lib/
zig build lib 

note: the C library and header are only built with zig build lib. the auto-generated header is always in sync with exported functions, marked with callconv("c")

running tests

zig build test --summary all 
# opt: -Dtest-filter="some test name filter"

revolt (the language server)

revo ships an LSP server at src/lsp/. it handles diagnostics, go-to-definition, hover, references, document symbols, and workspace symbols.

release builds bundle the LSP directly! run revo --lsp to start it. debug builds skip it by default; use -Doptimize=ReleaseFast to enable it, or -Dnolsp to exclude it from any build.

to build the standalone server binary:

zig build lsp

the binary lands at zig-out/bin/revolt

neovim setup

vim.lsp.config('revolt', {
  cmd = { 'revo', '--lsp' },
  filetypes = { 'rv' },
  root_markers = { 'lib.json', 'exe.json', '.git' },
})
vim.lsp.enable('revolt')

see docs/lsp.md for the full feature list, troubleshooting, and other editors

contributing

recommending to a friend is always greatly appreciated. any contributions are welcome!

you can contribute via github, codeberg or via emailing me a .patch

see CONTRIBUTING.md

credits

license

revo is licensed under MIT. see the LICENSE.txt file for details

About

a dynamic language for the joy of programming

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages