Breviv0.24

Brevi language (.bv)

Language guide

Brevi's own syntax, for .bv files. You do not need it to build Python. This is the guide built into the compiler (brevi guide); it is written for models, so it is dense on purpose.

View as Markdown · source

Brevi compiles to Rust. Write it like Python: one statement per line, indented blocks after a line ending in : (a short block can follow the :), # comments. Types are optional: parameters, return types and empty values are worked out from use. Write one only when brevi check asks.

A file can be just statements or define fn main(). Scope works as in Python, global x included. Without any global line, functions may also set top-level names directly.

use "util.bv" brings in another file's definitions. This guide is the core: brevi guide WORD prints every line about a name, and brevi guide Strings, Lists, Python or Libraries a section of details.

nums = stdin().ints()
print("total {nums.sum()}, mean {(nums.sum().float() / nums.len().float()).fmt(2)}")

Types#

int (64-bit), f64, bool, str, [T] list, {K: V} map (sorted by key), (A, B) tuple, dec exact decimal, big exact integer, Date, Json, heap[T] min-heap.

A parameter changed in place (xs.push(x), xs[i] = v, p.n += 1) changes the caller's value, as in Python. Mark it mut only to replace it whole (mut xs, then xs = xs.filter(f)). Other values act as copies.

Tuples, lists and strings compare element by element: pairs.sort_by(p => (-p.1, p.0)). p.0 is a tuple field (p[0] also works).

type Point:
  x: f64
  y: f64
  label: str = ""              # default
enum Shape:
  Circle(r: f64)
  Rect(w: f64, h: f64)
  Empty
p = Point(x: 1.0, y: 2.0)      # or Point(1.0, 2.0)
s = Rect(w: 2.0, h: 3.0)

Functions#

fn area(s) = match s:
  Circle(r) => 3.14159 * r * r
  Rect(w, h) => w * h
  Empty => 0.0
fn load(path):
  text = read(path)                    # can fail; the error passes up
  if text.is_empty(): fail("empty file")
  text.lines()                         # last line is returned
fn add(xs, x):
  xs.push(x)                           # edits caller's list

Errors pass up automatically, no ?: a function using fail(msg) (like Python's raise), read or s.int() can fail, and so can its callers. Handle a failure with .or(default) (s.int().or(0)) or match f(x): with arms Ok(v) => ... and Err(msg) => ....

Statements#

x = 1 creates or changes a variable (x: [str] = [] gives a type), a, b = b, a + b, x += 1, return v, break, continue, assert cond.

if c: / elif d: / else: with Python truth (if xs:, if not s:), for x in xs:, for k, v in m.pairs():, for i in 0..n:, while c:.

if and match are values: y = if a > b: a else: b. A variable set in every branch of an if/else or match can be used after it; one first set inside a loop ends with the loop, so set it before the loop.

Match arms are one expression or statement, or an indented block after =>. Patterns: literals, _, names, Variant(a, b), (a, b).

Operators#

+ - * / // % (int / and % round toward zero, // rounds down), == != < > <= >=, x in xs and x not in xs (list item, map key or substring), and or not, a ~= b (float equal within 1e-6). + joins strings and lists.

int and f64 never mix: convert with .float() or .int() (a whole-number literal next to an f64 is an f64: x * 2).

Strings interpolate "{name} is {age}, {xs.len()} items" and take Python format specs: "{x:.2f} {n:03d} {s:<10}". In double quotes {{ is ONE brace. For JSON or template text use 'single quotes': no \" needed and { stays plain unless a name follows ('{"id":{i}}', '{{#each '). Details: brevi guide Strings.

Collections#

xs[-1], slices xs[a:b] s[1:], xs[i] = v, m[k] += 1, m[k].push(x), books[id].shelf -= 1 change the stored item (b = books[id] is a copy). A missing map key reads as the type's zero; m.has(k) tells.

Empty values xs = [], m = {}, h = heap() need no type.

Comprehensions ([*xs for xs in xss] joins lists), len sum min max sorted any all and tuple map keys (dist[(x, y)]) work as in Python.

Lambdas: x => x * 2, (a, b) => a + b (also unpacks a tuple item).

Methods#

Every call has parentheses: xs.first().

Most methods return a new value (ys = xs.sort()); as a statement xs.sort() sorts xs, and push pop insert remove change it in place. xs.max() can fail (.or(0)); find and index_of give -1 when absent; a..b excludes b.

Python spellings work too (range(), .append(), .items(), ", ".join(xs), lambda x:, sorted(xs, key=f)): brevi guide Python.

Built-in functions#

print(a, b), str(x), read(path), write(path, text), args(), input() (one line), stdin() (all text), lines() (stdin lines), fail(msg), abs(x), min(a, b), max(a, b).

Data formats#

Tests#

test "area of unit circle":
  assert area(Circle(1.0)) ~= 3.14159

Commands#

brevi run|test|check f.bv, brevi build f.bv -o app, brevi patch f.bv p.bv (replaces each fn/type/test by name), brevi fix f.bv (applies suggested renames).

Errors are one JSON line each, {"line":N,"msg":...,"fix":...}. To fix one, change only the lines it names; do not rewrite the whole file.