The ucode language

A small scripting language for Linux systems.

ECMAScript syntax, an embeddable C core, JSON as a native datatype, and a template engine built into the interpreter. Synchronous and dependency-light — OpenWrt's firewall and web interface are written in it.

terminal run ▶
# preinstalled on OpenWrt 22.03 and later
$ ucode -e 'printf("%J\n", { hello: "world", nums: [ 1, 2, 3 ] })'
{ "hello": "world", "nums": [ 1, 2, 3 ] }
~64 KB
interpreter and runtime on ARM Cortex A9
64-bit
integers with a guaranteed range, distinct from doubles
json-c
the only hard dependency — everything else is optional
ISC
permissive two-clause license, whole tree

A quick tour

Four things ucode does well — the examples marked run ▶ execute in your browser on a WebAssembly build of the interpreter, same VM, no server.

ucode run ▶
let passwd = `
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
`;

let users = map(
    filter(split(trim(passwd), "\n"), (l) => length(l) > 0),
    (l) => {
        let f = split(l, ":");

        return { name: f[0], uid: int(f[2]), home: f[5], shell: f[6] };
    }
);

printf("%-8s %4s  %-10s %s\n", "NAME", "UID", "HOME", "SHELL");

for (let u in users)
    printf("%-8s %4d  %-10s %s\n", u.name, u.uid, u.home, u.shell);
output
NAME      UID  HOME       SHELL
root        0  /root      /bin/bash
daemon      1  /usr/sbin  /usr/sbin/nologin

The core builtins carry Perl's vocabulary — map, filter, split, printf — and everything above is core: no imports, no classes, no wrapper objects.

Design goals

ucode began as the template processor for OpenWrt's nftables firewall and grew into a general system scripting language. The goals it was designed around still hold.

syntaxECMAScript, minus the machinery

let, const, arrow functions, template literals, try/catch — familiar ground for JavaScript-experienced developers, and existing editor tooling keeps working.

dataJSON as a native datatype

Values are JSON-shaped — null, boolean, integer, double, string, array, object — so ubus calls, config files and HTTP payloads need no glue code.

numbersReal 64-bit integers

Distinct integer and double types with a guaranteed 64-bit integer range. No surprises when ids, timestamps and byte counts show up.

stdlibPerl-flavoured builtins

substr, index, splice, sprintf, split, join, trim — the core functions are functions, not methods on wrapper objects. 74 of them in the core alone.

regexPOSIX regular expressions

match, replace and wildcard are built in, compiled by the host libc's ERE engine — patterns behave like the rest of the system does.

flowSynchronous by design

One flow of control. Concurrency, when needed, lives in the uloop event loop module — not in the language, not in your head.

embedA C library first

libucode is a library before it is a program: a documented C API for values, VM state, native functions, resource types and precompiled bytecode.

modulesLoadable native modules

Each extension builds as an optional shared object, probed at configure time — the feature set is a build-time choice, not a runtime tax.

The standard library

Loadable native modules — link against what you need, skip the rest. Each links into the reference documentation.

In production

ucode ships preinstalled with OpenWrt 22.03 and later. These projects run on it or embed it.

firewall4 OpenWrt's nftables firewall — the project ucode was written for, rendering the ruleset from UCI configuration and templates. openwrt/firewall4 ↗
LuCI The OpenWrt web interface — ucode templates and the luci runtime behind every page. openwrt/luci ↗
rpcd The ubus RPC daemon, embedding the interpreter to publish ubus objects from scripts. openwrt/rpcd ↗
uhttpd The tiny OpenWrt web server — ucode is a first-class request backend. openwrt/uhttpd ↗
uwsd A next-generation web server with asynchronous ucode handlers on an event loop. jow-/uwsd ↗

Latest commits

Live from the ucode-lang/ucode repository — recent work on master, no changelog to go stale.

Full commit history ↗

The manual

A comprehensive ucode programming manual — covering the language, the standard library, the C embedding API and deployment in the wild.

Read the manual
  • IThe language — values, operators, functions, templates
  • IIThe standard library — core builtins and every module
  • IIINetworking & system integration — sockets, netlink, ubus
  • IVEmbedding ucode in C — the API, walked line by line
  • VDeployment & ecosystem — uhttpd, rpcd, firewall4, LuCI

Getting it

OpenWrt

opkg install ucode

Preinstalled on OpenWrt 22.03 and later.

Debian

apt-get install build-essential devscripts \
    debhelper libjson-c-dev cmake pkg-config
git clone https://github.com/ucode-lang/ucode.git
cd ucode && dpkg-buildpackage -b -us -uc

Packaging recipes ship in-tree.

From source

git clone https://github.com/ucode-lang/ucode.git
cd ucode
cmake -DUBUS_SUPPORT=OFF -DUCI_SUPPORT=OFF \
      -DULOOP_SUPPORT=OFF .
make

json-c is the only hard dependency; OpenWrt-specific modules toggle off.