What's new in TB 3.0
TB 3.0.0 brings classes, pattern matching, generators, tasks and a much bigger standard library to the same friendly language, plus a formatter, a checker, a debugger, packages and a VS Code extension. Press Run under any example to try it here.
The language
Everything below is explained step by step in the TB 3.0 lessons, and exactly in the language specification.
Classes, enums and pattern matching
class with fields, methods, static members, extends and super; special methods such as text(), equals() and compare(); enum; and match with value, range, list, map, type and class patterns, or and guards.
enum Level { low, medium, high }
class Alert {
fn init(rule, level) {
self.rule = rule
self.level = level
}
}
let a = Alert("ssh brute force", Level.high)
say(match a {
Alert {level: Level.high} => f"page someone: {a.rule}"
_ => "log it"
})
Functions and data
Default, named, ...rest and **opts arguments; lambdas (x => x * 2); destructuring in let, for and parameters; spread ([...a, ...b], {...m}, f(...xs)); swaps (a, b = b, a); const; and if ... then ... else as an expression.
fn scan(host, port = 22, timeout = 5) {
return f"{host}:{port} ({timeout}s)"
}
let {name, ip, owner = "nobody"} = {"name": "web01", "ip": "192.0.2.10"}
say(scan(ip, timeout = 1), name, owner)
say([3, 1, 2].map(x => x * 10), if len(name) > 3 then "long" else "short")
Numbers, text and bytes
Whole numbers and fractions are separate (//, **, is_int()); hex, binary and octal literals with _; bit operators; chained comparisons; format specs in f-strings ({x:.2f}, {n:,}, {n:08b}, {p:.1%}, {s:>10}); escapes, raw r"..." and multi-line """...""" text; a bytes type with b"..."; and ranges (1..5, 1..=5) and slices (xs[1:3], xs[::-1]).
say(0xff, 0b1010, 1_000_000, 7 // 2, 2 ** 10, 0b1100 & 0b1010)
say(f"{1234.5678:,.2f} | {255:x} | {0.257:.1%} | {"tb":>6}")
let data = b"MZ\x90\x00"
say(data.hex(), data[0], (1..=5).to_list(), "detection"[::-1])
Errors, generators and tasks
Errors are objects with a kind: catch err: ParseError, your own classes that extend Error, and finally. Generators (yield) make lazy pipelines with map, filter, take and zip. async fn starts a task and await collects its answer. defer and assert round it off.
import json
fn evens() {
let n = 0
while true {
yield n
n += 2
}
}
say(evens().filter(n => n % 3 == 0).take(4).to_list())
try {
json.parse("{oops")
} catch err: ParseError {
say("kind:", err.kind)
} finally {
say("done")
}
Modules and packages
export decides what a module shares, from ... import picks names, and packages install into a project with tb add. See Packages.
A bytecode virtual machine
Programs are now compiled to bytecode and run on a virtual machine, which is faster than the 2.x interpreter on loops, function calls and methods, and runs generators without threads. Error messages are the same as before. The 2.x-style tree-walking interpreter is still there for one release: TB_ENGINE=tree tb file.tb or tb --engine tree file.tb.
The playground on this site runs the same virtual machine in your browser.
Concurrency
async fn and await run work as tasks on their own threads, and the parallel library adds parallel.map, parallel.run, parallel.all, queues and locks. Desktop windows stay responsive with win.run_in_background.
import net
import parallel
let hosts = ["192.0.2.10", "192.0.2.11", "192.0.2.12"]
let open = parallel.map(h => net.tcp_check(h, 443, 2), hosts, 16)
say(hosts.zip(open))
The browser playground has no threads: tasks there run one after another, and parallel needs the TB app.
Tools
New commands for bigger projects, all part of the tb program: tb fmt (formatter), tb check (finds mistakes before you run, with optional type hints), tb debug (breakpoints and stepping), tb test --coverage, tb doc for your own files, tb build (a folder you can give to someone without TB), tb lsp (a language server for editors), and tb init, tb add, tb remove, tb update and tb packages for packages. The VS Code extension brings them into your editor.
New libraries
The standard library grew from 20 to 43 libraries. New in 3.0:
| Core | datetime decimal binary |
|---|---|
| Files and data | yaml toml xml sqlite archive template |
| Security operations | crypto pcap evtx pe elf scan attack stix siem |
| Networking | dns tls websocket server |
| Concurrency | parallel |
Existing libraries grew too: detect runs full Sigma (all modifiers, aggregations, correlation rules) and converts rules to Splunk, Elastic and Sentinel queries; logs reads EVTX files and keeps time zones; fs reads and writes bytes and watches folders; net sends UDP; gui has tabs, trees, charts, canvases, sliders, themes and notifications; test has mocks, fixtures, parametrised cases and coverage.
import pcap
let packets = pcap.read("apps/data/sample.pcap")
for q in pcap.dns_queries(packets).slice(0, 3) {
say(q.name, q.answers)
}
New apps
The apps gallery now has every app that ships with TB, including pcap-triage, evtx-triage, file-inspector (and a desktop version), sigma-studio, ioc-feed, siem-forwarder, alerts-dashboard-gui, network-monitor, parallel-scan, dns-check, cert-check and dashboard, a web dashboard served by the server library.
What might break
Almost every 2.x program runs unchanged and prints the same. The few changes: new reserved words (class, match, from, is, const, ... can't be names any more, and TB suggests another), / always gives a fraction (displayed as before), and errors from libraries have specific kinds. The migration guide lists everything with fixes.
Earlier releases
2.0.1
Neutral sample programs and docs; no language changes. The first program became welcome.tb, a short tour of TB.
2.0
Maps, methods, f-strings, modules and import, try/catch/throw, twenty libraries (desktop GUI, logs, detection rules, IOCs, hashing, networking, threat intel), the Windows installer and the security apps.