sysl

Standard Library

What ships with the compiler, module by module — the core every program has, and the layers a target may not.

The reference is the language: what the compiler reads, what a type is, what a declaration binds. This section is the other half of what a program has — the modules that ship with the compiler, and what each of them offers.

They are kept apart on purpose. Nothing in this section is a language feature: every type here is an ordinary struct or enum, every function is ordinary sysl, and a program could have written any of it. Option is a generic enum, unwrap is a member that calls exit, print is a library function reached by a desugaring. The line matters because it is the language’s own rule about itself — there are no functions built into the compiler that a program could not have written, and the one exception is the seam out to C.

So a page in the reference tells you what the compiler will accept. A page here tells you what somebody already wrote for you, and where it will not be there.

The library is a tree, and the tree is the point

sysl is one module with submodules under it, and each is a directory. A program reaches the core without asking; everything below it is imported by name.

moduleholdsrequires
syslthe core — Option, Result, Display, the operator traits, print, assert, and exit for a program that chooses its own status—
sysl.textthe whole text surface — validation, the character cursors, Ascii and Search, splitting and joining, StrBuilder, the parsers, CString—
sysl.fmtintegers in base sixteen, two and eight as plain functions — hex, binary, octal — over the renderer an f"$v%x" hole uses, so a bare target has them—
sysl.unicodethe Unicode Character Database — case mapping that answers for é, fold as the comparison key, the four normal forms, grapheme clusters, and General_Category—
sysl.regexPOSIX Extended Regular Expressions — regex, Regex, Match—
sysl.bufBuf[T], the growable sequence, and ByteSink—
sysl.containerfive containers — Map and Set over one flat probe table, Deque, Heap, and an immutable List that shares its tail—
sysl.container.ringRing[T], a queue of a fixed capacity over storage the caller supplies — no allocator, a full ring that answers rather than grows, and overwrite for a window over an unbounded stream—
sysl.dmaRegion, memory a device can reach by address — it carries the device’s address of its first byte, a part of it is a region too, and to_device/from_device are the cache maintenance a handover needs—
sysl.ioReader, stdin(), lines() and console_lines(), and the in-memory bytes_reader() / bytes_writer()—
sysl.patha path by the string alone — join, parent, file_name, extension, stem, normalize, relative_to. It opens nothing—
sysl.fswhat is at the end of a path — read_text, write_bytes, metadata, the links, make_dir_all, copy_file, canonicalize, and IoErroros
sysl.mathmax, min, pi, the float functions, the integer traits Signed and Bits, Magnitude and the size a type measures in, and the integer arithmetic above them — pow, gcd, lcm, divmod, is_power_of_two, next_power_of_two—
sysl.math.complexComplex[F: Float] — the operators at two argument lists each, the transcendental set, and the branch cuts—
sysl.math.bigintBigInt — an integer with no width: sign and magnitude over 32-bit limbs, the five operators, pow, and text in any base from 2 to 36—
sysl.math.decimalDecimal — exact decimal arithmetic, so a tenth and a fifth make three tenths: a coefficient and a scale that is part of the value, and a division that takes a rounding mode—
sysl.math.rationalRational — exact fractions over BigInt, in lowest terms: the four operators, floor/ceil/trunc, a comparison against a real at its exact value, and a correctly rounded to_real—
sysl.timeInstant and Duration — with 5.ms and 5.hours on any integer — the civil calendar — LocalDate, LocalTime, LocalDateTime, Offset — the fixed-offset conversions, resolve for a zone whose clocks move, and the ISO 8601 renderers and parsers — and now/monotonic, which read a clock the linker supplies rather than one this module knows about—
sysl.time.tzifa zone decoded from the bytes of a TZif file — no copy, no allocator, and no filesystem—
sysl.posix.timethe two clocks the host keeps — now for a wall reading, monotonic for measuring — the zone it is set to, and the zone database by nameposix
sysl.envthe environment a program was started with — get, get_or, is_set, and vars to list it. Reading only; answered by the program where there is no C library (sysl.env.sys)os (vars: posix)
sysl.processstarting another program and waiting for it — run, capture, Status, a timeout so a child that never ends cannot hold its caller, and no shell anywhere in itposix
sysl.signalsignals as flags — watch and Watch.take, ignore, restore_default, send and raise, at the target’s own numbers, with no sysl code ever run inside a handler; answered by the program where there is no C library (sysl.signal.sys)os
sysl.netblocking TCP and UDP — resolve, socket, udp_socket, bind, listen, accept, connect, send, recv, send_to, recv_from, shutdown, close, a timeout so a blocking call cannot wait forever, and addresses as values (ipv4, ipv6); answered by the program where there is no C library (sysl.net.sys)os
sysl.syncAtomic[T], SpinLock, and the five memory orderings—
sysl.threadsspawn, Thread.join, yield_now, Mutex[T], Condvar, and Channel[T] — the bounded queue two threads hand values acrossos
sysl.termthe escape sequences a terminal understands — colour, emphasis, and the screen—
sysl.posix.ttywhether to write them at all — is_tty, color_wanted, color, color_err — and the host’s half of taking the terminal over: flush, tty_writer, and sysl.tty‘s raw, hidden and cooked under this module’s namesposix
sysl.ttya terminal’s mode — raw, hidden for a password, cooked, and mode/set_mode over a Mode; answered by the program where there is no C library (sysl.tty.sys)os
sysl.term.edita line editor for a terminal with no line discipline — echo, editing, history, over a Reader and a Writer—
sysl.sliceswhat a program does to a []T — searching, comparing, reverse, copy, two sorts that neither allocate, binary_search, and as_ptr for a C binding—
sysl.seqwhat a program asks of a sequence — map, filter, fold, any, all, find, position, count_where, each, flat_map, on a slice or a Buf alike—
sysl.encodinghexadecimal and base64 both ways, fixed-width integers to and from bytes at either byte order, and DecodeError—
sysl.encoding.jsonJSON read into a Json tree that keeps its order and its integers, written back compactly or pretty, and refused with a JsonError naming line and column—
sysl.cryptothe SHA-2 family, SHA-1 and HMAC over any of them — digests as bytes, a hasher that streams, and no allocator—
sysl.checksumCRC-32 (the zip, PNG and Ethernet one) — crc32 in one call, or Crc32 fed in pieces; for accidental corruption, not security—
sysl.randPCG32, seeded by the caller and reproducible — below without modulo bias, range, unit, shuffle—
sysl.posix.randseed_from_os and entropy_from_os, kept apart so the generator stays freestandingposix
sysl.argscommand-line options — Scan, Cli, and args_of for a raw argv—
sysl.logstructured logging — a Record, a Sink of one method, text and json renderings, and a threshold that costs a relaxed load on a filtered call—
sysl.testingskip(why) — a @test that finds out it cannot run ends without a verdict, reported as skipped—
sysl.harnessa test framework that runs on the target — run, check, check_eq, check_slice_eq, skip, and a tally—
sysl.systhe platform seam — what a freestanding target replaces—

The split is by capability, not by taste, and the namespace is the column written into the path. sysl.fs is requires os, because a filesystem is something the environment either has or does not — and files exist on operating systems that are not POSIX, which is why it is the one gated module that does not sit under sysl.posix. Everything under sysl.posix is requires posix, libc and nothing else: threads because pthreads is what they are, tty because isatty and termios are, rand because entropy comes from the kernel, time because clock_gettime is a call into it — and libc because each of them calls those functions by symbol, so it needs a C library to link against as well as POSIX’s behaviour. So a module a target cannot support is not one that fails to link — it is one a capability clause will not let that program import in the first place, and now one you can spot by its name.

sysl.path is the same rule one step further out, and the clearest instance of it: not a submodule of sysl.fs but a module beside it, because it requires nothing. It touches no syscall — it is string manipulation whose rules happen to be per-platform — so one getcwd filed next to join would have taken the whole of path handling away from every program that has no operating system to ask. What that buys is concrete rather than tidy: a module loader can resolve an import and then say which file it could not read, which is only writable because the resolution never touched the disk.

It is also why sysl.posix.tty, sysl.posix.rand and sysl.posix.time are modules of their own rather than functions in sysl.term, sysl.rand and sysl.time. A requirement is module-wide, so one function asking for posix beside the escape sequences would have taken all forty constants away from the allocator-free programs that most want to colour a line; one asking for it beside the generator would have taken PCG32 away from every target that has no operating system to seed it from; and one asking for it beside Instant would have taken the whole civil calendar away from a program that only wanted to add two durations. Three instances of one shape, and the shape is worth naming: where a module is portable except for how it gets started, the getting started goes in a submodule.

That is why the atomics live apart from the threads: sysl.sync requires nothing, so a kernel can have a spinlock without acquiring a scheduler along with it.

alloc is not in that column, and the omission is the point. No module requires it, because allocation is refused at the call rather than at the import — so a program under no alloc still imports sysl.text and still gets from_utf8, the cursors, and Search, and is refused only where it reaches for join or a StrBuilder. A capability that gated whole modules would have cost the allocator-free subset most of the library it can actually use.

What belongs here, and what is a package

The library is what a program cannot get on with the language without. That is the whole rule, and it is a principle rather than a list because a list goes stale the first time somebody adds a module and answers nothing about the next one.

Read as a question to ask of a candidate: can a program take part in the language without it?

  • Yes, and it is a domain — matrices, an FFT, a JSON parser, a QR encoder, a physics engine. Those are packages, fetched by coordinate. They are not lesser; they are simply not what everybody has to have, and a standard library that carried one carries an opinion about what everybody is writing.
  • No, because the language desugars onto it — Option and Result for ?, Display and the print family for print, Iterate for for … in, the operator traits for +, Drop for a destructor, From for a ? across two error types. These are in sysl itself, unimported, because a program that had to name them would be naming part of the language.
  • No, because it is the platform — the filesystem, the clock, the environment, threads, the terminal, starting another process. These are modules a program imports, and they are here rather than in packages because there is one right answer per operating system and every program that wants one wants the same one.
  • No, because all code touches it — text, slices, sequences, containers, hashing, formatting, encoding. The line here is the vaguest of the four and the test is the same: a program that avoided sysl.text would be writing UTF-8 validation, which is not a domain, it is a tax.

The display_* renderers are the boundary case, and they sharpen the rule rather than escaping it. No desugaring names one, so the letter of the first test puts them in a sysl.fmt — and the split was tried and works. They stay in sysl because a program writing impl Display is not reaching for a library; it is implementing a language feature, and the renderers are the vocabulary that contract is written in. A program that could not write its display body without an import has been asked to name part of the language.

Two things have left for being domains, which is the rule working rather than a reversal: matrices and vectors went out to linalg and the FFT to fft. Both were leaves — nothing else in the library imported them — and both were a subject in a library otherwise made of the platform and of things all code touches. sysl.math.complex stays, and the reason generalises: standard libraries across languages carry the complex type and leave the algorithms over it to packages.

What “complete” means here is that the four answers above are covered, not that the list is long. A module added because it would be useful, rather than because one of the four asks for it, is a package that has not been written yet.

Where some of this already is

Three pieces of the library are documented in the reference instead, because the language has machinery that only makes sense beside them:

  • Option, Result and the Fallible latch are on errors and contracts, because ? is a language form and it is what those types are for.
  • assert and panic are on attributes and compile time, beside the @test protocol they exist to serve.
  • The operator traits — which trait a + or a < reaches — are on expressions, because dispatch is a rule about the operator rather than about the trait.

This section links to them rather than repeating them.

Pages

  • The core module — `sysl` itself — the names every program has without asking: rendering, hashing, subscripting, iteration, callables, and the two ways a program stops.
  • The text module — `sysl.text` — validating bytes into text, walking it by character, searching and trimming without an allocator, building and splitting with one, and reading values back out.
  • The fmt module — `sysl.fmt` — the renderers behind an f-string's specifiers: integers in hexadecimal, binary and octal as plain functions, floats correctly rounded under `%f`, `%e` and `%g`, and the shortest reading of a float — all in sysl, so they work on a target with no C library.
  • The unicode module — `sysl.unicode` — the Unicode Character Database in the standard library: case mapping that answers for `é`, case folding, the four normal forms, grapheme clusters, and General_Category.
  • Regular expressions — `sysl.regex` — POSIX Extended Regular Expressions, matched by a Pike VM whose cost is the input length times the pattern length and never anything worse.
  • The buf module — `sysl.buf` — `Buf[T]`, the growable sequence written in ordinary sysl, and `ByteSink`, the `Writer` that keeps what is written into it.
  • The container module — `sysl.container` — `Map` and `Set` over one flat probe table, `Deque` for a queue at both ends, `Heap` for a priority queue, and an immutable `List` that shares its tail.
  • The ring module — `sysl.container.ring` — `Ring[T]`, a queue of a fixed capacity over storage the caller supplies: no allocator, a full ring that answers rather than grows, and `overwrite` for a window over an unbounded stream.
  • The dma module — `sysl.dma` — `Region`, memory a device can reach by address: it carries the device's address of its first byte, a part of it is a region too, and `to_device`/`from_device` are the cache maintenance a handover needs.
  • The io module — `sysl.io` — `Reader`, the one trait input travels through; `FdReader` and `stdin()`; and `lines()`, the cursor that borrows what it reads from.
  • The fs module — `sysl.fs` — files and paths, in three tiers; `IoError` and why it is an enum; and `requires os`, the capability that decides whether the module exists at all.
  • The path module — `sysl.path` — joining, taking apart and normalizing a path by the string alone: `join`, `parent`, `file_name`, `extension`, `stem`, `normalize`, `relative_to`. It requires nothing, and `normalize` is not `canonicalize`.
  • The slices module — `sysl.slices` — the operations over a built-in slice: searching, comparing, reversing, a copy that is right where the two slices overlap, two sorts that neither of them allocates, a binary search that answers where a missing value belongs, and the pointer a C binding hands across.
  • The seq module — `sysl.seq` — `map`, `filter`, `fold` and the seven questions beside them, as one trait a slice and a `Buf` both answer.
  • The encoding module — `sysl.encoding` — hexadecimal and base64 in both directions, fixed-width integers to and from bytes at either byte order, and a `DecodeError` that says what a caller can act on.
  • The crypto module — `sysl.crypto` — the SHA-2 family, SHA-1, MD5, HMAC over any of them, and PBKDF2 and HKDF, written in sysl, answering bytes and allocating nothing.
  • The JSON module — `sysl.encoding.json` — a JSON document read into a value tree that keeps its order and its integers, written back compactly or for a person, and refused with the line and column where it went wrong.
  • The checksum module — `sysl.checksum` — CRC-32, the zip, PNG and Ethernet one, in one call or fed in pieces, with no allocator.
  • The math module — `sysl.math` — the `Float` trait over every floating width, `Signed` and `Bits` over the open integer family, `Magnitude` and the size a type measures in, the constants, `min`/`max`/`clamp` over anything ordered, the float comparisons, and the integer arithmetic above the operators.
  • The complex module — `sysl.math.complex` — `Complex[F: Float]`, generic over both float widths: the operators at two argument lists each, the transcendental set, and the branch cuts written down.
  • The rand module — `sysl.rand` — PCG32, seeded by the caller and reproducible; a bounded integer with no modulo bias, a shuffle that is Fisher-Yates, and OS seeding kept in a module of its own so a freestanding target need never import it.
  • The bigint module — `sysl.math.bigint` — integers with no width: sign and magnitude over 32-bit limbs, schoolbook multiply, Knuth's algorithm D, bit operations on an infinite two's complement, and text in any base.
  • The decimal module — `sysl.math.decimal` — exact decimal arithmetic: a big-integer coefficient and a scale, so a tenth and a fifth make three tenths.
  • The rational module — `sysl.math.rational` — exact fractions over `BigInt`: lowest terms with a positive denominator, the four operations, floor and ceiling, an exact comparison against a `real`, and a correctly rounded conversion to one.
  • The time module — `sysl.time` — `Instant` and `Duration` kept apart, the proleptic Gregorian calendar, `LocalDate`/`LocalTime`/`LocalDateTime`, the ISO 8601 renderers and the parsers that read them back.
  • sysl.sync — Atomics, the five memory orderings, and a spinlock — the concurrency a target has before it has a scheduler.
  • The env module — `sysl.env` — reading the environment a program was started with: `get`, `get_or`, `is_set`, `vars`, and why nothing here writes one.
  • The process module — `sysl.process` — starting another program and waiting for it: `run`, `capture`, `start` and `Child`, `spawn` and `pipe` for a pipeline, `Status`, how long a child may take, `exec` to become another program, why there is no shell or `fork` anywhere in it, and which user the program runs as.
  • The signal module — `sysl.signal` — signals as flags: `watch` and `Watch.take`, `ignore` and `restore_default`, `send` and `raise`, the target's own numbers, and why no sysl code ever runs inside a handler.
  • The net module — `sysl.net` — blocking TCP and UDP and the names they resolve: `socket`, `bind`, `listen`, `accept`, `connect`, `send`, `recv`, `send_to`, `recv_from`, `shutdown`, `close`; addresses as sysl values; and the hooks a target without a C library answers.
  • sysl.threads — Starting a thread, waiting for one, and the lock, condition variable and channel above the spinlock — the half of concurrency that needs a scheduler.
  • sysl.term — The escape sequences a terminal understands — colour, emphasis, and the screen — as constants a program with no allocator can still name.
  • sysl.args — How argc and argv become a []string, and the two layers that read options out of them.
  • The log module — `sysl.log` — levels, a sink trait, and three renderings: a line for a person, an object for a machine, and the bare message for a sink that stamps its own.
  • The harness module — `sysl.harness` — a test framework that runs on the target: named tests, a located failure with both values rendered, three verdicts and a tally, with no allocator, no operating system and no debug host underneath.
  • sysl.sys — The platform seam — every declaration in the standard library that is not sysl, in one file you cannot call.

Search

Esc
↑↓ to navigate ↵ to open Esc to close