Breviv0.24

Brevi language (.bv)

Reference

Details kept out of the core guide. brevi guide WORD prints only the lines about one name.

View as Markdown · source

Details kept out of the core guide, which every session reads. brevi guide SECTION prints one section; brevi guide WORD prints every line about a name.

Strings#

Strings interpolate: "{name} is {age}", "{-x} {xs.len()} {p.0}" ({ followed by a letter, (, -, ! or " starts an expression, and strings may appear inside: "{m["k"]}"). Any other { is a plain brace; \{ and {{ always are, so "{{" is ONE brace (write '{{' for two); template tags such as "{{#each ", "{{/if}}" and "{{else}}" keep both braces.

Python format specs work inside {}: "{x:.2f} {n:03d} {name:<10} {total:>8,}".

Escapes: \n \t \r \0 \" \\ \{ \}.

'single quotes' need no \" and keep { plain unless a name or ( follows ({{ is two braces), so JSON and template text is easy: '{"id":{i},"error":"not found"}', t.starts_with('{{#each ').

"a".code() is 97 and 97.char() is "a". "7".digit() is 7 (-1 if not a digit). len counts characters; chars gives a list of one-character strings; words splits on any run of whitespace; ints() gives all whitespace-separated ints.

s.slice(a) runs to the end and s.slice(i, i + 1) is one character; negative bounds count from the end. s.int().or(-1) tests a number. (a, _, b) = s.partition("=").

Lists#

[0].repeat(n) is n zeros; unique sorts and drops repeats; (0..10).step(3) is [0, 3, 6, 9]; (0..n).rev() counts down. join(sep) takes any items.

xs.sort_by(f, desc) sorts largest first when desc is true, keeping ties in order (as sorted(xs, key=f, reverse=desc)).

first, last and pop return the item itself and stop the program on an empty list; min and max fail on an empty list. pop and remove(i) return the removed item. In map/filter/any/all/count/sort_by, (a, b) => b - a unpacks a tuple item. and/or short-circuit.

2.5.fmt(2) is "2.50"; f64 round(n) rounds to n places.

Type details#

let (a, b) = t or (a, b) = t destructures a tuple. Point(x, y) works as a constructor when variables x and y exist. A mut parameter is called as f(x). A return type is optional (fn f(x: int) = x * 2); write -> T if an error asks.

A missing map key reads as the type's zero (0, 0.0, "", [], dec 0). print(a, b) puts a space between.

Python#

Python spellings models write by habit are accepted: True False, a if c else b, range(a, b, step), for c in s, enumerate(xs) int(s) ord chr reversed, lambda x: x * 2, min(xs, key=f), sorted(xs, key=f, reverse=True), print(x, end="", sep=", "), append strip split() startswith endswith isdigit items index get(k, d), ", ".join(xs), && || ! for and or not. f"..." is a plain string (Brevi strings already fill in {x}). Also set(xs) (a sorted list without repeats) with s.add(x), xs.extend(ys), xs[::-1] and xs[::2], divmod(a, b), round(x) and round(x, 2), enumerate(xs, 1), m.setdefault(k, []).append(x), defaultdict(int), "%5.2f %s" % (x, s), "{:>5} {}".format(a, b), math.sqrt floor ceil, for line in sys.stdin; import sys, math, re and from collections import ... lines are ignored. Also rstrip() lstrip() strip(chars) splitlines() isupper() islower() isalnum(), heapq.heappush/heappop/heapify on a plain list, deque with popleft/appendleft, map(f, xs), filter(f, xs), list(xs), int/str/float/len as function values (map(int, xs), key=len) and sys.stdout.write(s). Decimal(x) is x.dec() and keeps its written places as Python does (Decimal("1.50")), with d.quantize(Decimal("0.01")) (half to even, or rounding=ROUND_HALF_UP); csv.reader(sys.stdin) or csv.reader(lines) gives the rows; date.fromisoformat(s) is date(s) and (d2 - d1).days counts the days between. next(rows) takes the first item; xs.pop(i) and m.pop(k) take an item out and give it back; sorted(s), enumerate(s, 1) and "-".join(s) read a string by character; sorted(m) gives a map's keys; OrderedDict() is a map. The re module works as in Python: re.compile(p), re.match, re.fullmatch, re.search, re.findall, re.sub, re.split, and on a compiled pattern pat.match(s) etc.; a match is [whole, group1, ...] ([], which is false, when none), so if m:, m.group(1) and m.groups() work. next(rows, None) gives the empty value when nothing is left; next(x for x in xs if c) the first match. Also zip(xs, ys), Counter(xs) with most_common(n), dict(pairs), sys.exit(n), s.count(sub), zfill title center capitalize, xs.clear(), sys.argv, sorted(m, key=f), date(y, m, d), ljust rjust, split(sep, n), rsplit(sep, n), list(s), set(a) - set(b), s.update(xs) / m.update(m2), datetime.date(y, m, d), datetime.strptime(s, "%Y-%m-%d"), timedelta(days=n), d.isoformat() toordinal() weekday() isoweekday(), calendar.monthrange isleap, format(x, spec), isascii(), Fraction(...) (as a decimal), to_integral_value(), m.setdefault(k, v), defaultdict(lambda: 0), enumerate(xs, start=1), bool(x), sys.setrecursionlimit(n), json.loads(s), json.load(sys.stdin), isinstance(v, T) and isinstance(v, (T1, T2)), import aliases (from datetime import date as Date, import datetime as dt), datetime.timedelta(...), string.digits / ascii_lowercase and the other string letter constants, repr(x), next(iter(xs)), groupby(xs, key=f), del xs[a:b]. A file with def, class, global or import lines prints values the Python way (True, ['a'], {'k': 1}).

Functions are values: ops = [add, mul], for (name, f) in [("+", add)]: f(1, 2), ops[0](3, 4). A map of functions works when at least one value is a named function: ops = {"+": add, "-": lambda a, b: a - b}, then ops[op](a, b).

None works for int, float, str and tuple values: best = None, if best is None or v > best: best = v, return None from -> int. It is a reserved value, not an Option, so it cannot hold a user type.

Tools#

brevi build f.bv -o app --release builds an optimized binary. Runtime errors print {"e":"runtime","line":N,"msg":...}.

brevi emit f.bv shows the Rust. --explain on any command adds the guide lines under each error. brevi check f.bv --fast skips rustc. del fn name in a patch file removes a function.

A fixed typo prints {"line":N,"fixed":"totl -> total"}.

allow read, write at the top declares what a program touches (read, write, native for rust fn, py fn, crates and Python libraries such as import subprocess); in a Python file write it as a comment, # allow read, write, so the file stays valid Python. Under brevi run --sandbox and in the MCP tools only the caller grants capabilities (--allow read,write,native, --allow-py requests; MCP allow, allow_py), and an allow line in the file grants nothing; they refuse anything not granted, except path text (os.path.join, pathlib.PurePath) and random, which Brevi builds itself without native; a program with an allow line is held to it on every command. A refusal is final: it never falls back to a dynamic build, a library call or python3.