Skip to content

Releases

SSPUR 1.0.0

Choose a tag to compare

@github-actions github-actions released this 18 Oct 15:42

SSPUR 1.0 is stable: code that works on 1.0 keeps working on every 1.x release. Builds for macOS, Linux and Windows, plus the VS Code extension, the JetBrains template and the Zed extension, all signed with build provenance.

  • The 1.x promise. The language, the standard library, run, test, check, fmt, build, deps and publish, the package and lock formats, content hashes, error codes and the language server are stable. GPU kernels, deploy, bare-metal targets, the LLVM backend, sync, PGO, the Cranelift JIT and the agent tooling stay experimental and are marked so in sspur --help. The stability policy says what that means, and a compatibility suite in CI holds every release to it. A feature is deprecated with W_DEPRECATED before 2.0 can remove it.
  • Moving from 0.14: sspur fix rewrites what 1.0 reads differently, so the program means what it meant, and lists what to check by hand. The migration guide covers every change with before and after.
  • Safer: sspur check proves that every round, floor, ceil and trunc on an F64 gets a value in Int's range, from refinements, pre, guards and loops, or warns with W_CONVERSION_MAY_TRAP and the fix. The proofs are cached by content hash, so checking unchanged code proves nothing again.
  • Lighter: the macOS binary lays out its hot paths first, so peak memory is 10 to 20% lower on every command (hello world 2.5 to 2.0 MB against 0.15.0). The playground's download is 5 KB smaller.
  • Signed releases: every file attached to this release has a build provenance attestation, and each sspur archive has a CycloneDX SBOM. Check one with gh attestation verify FILE --repo sspurlang/sspur. install.sh checks it for you when gh is installed and signed in.
  • Fixes: sspur deploy local no longer leaves a request waiting through a hot swap, an interrupt handler on the QEMU targets no longer nests when it re-arms the timer, the Zed grammar reads 0.15 strings and scoped names, and the reference now documents every builtin, flag and environment variable.

Startup, the native benchmarks and content hashes are unchanged from 0.15.0, and every published package passes the 1.0 checks.

Full list in the changelog.

SSPUR 0.15.0

Choose a tag to compare

@github-actions github-actions released this 17 Oct 21:21

sspur fmt keeps your comments, the playground checks as you type about 5 times faster, and the interpreter builds lists and maps in linear time. This is the release candidate for 1.0: it settles the last syntax and semantics questions. Builds for macOS, Linux and Windows, plus the VS Code extension, the JetBrains template and the Zed extension.

  • Comments survive formatting (ADR 0042): sspur fmt, the language server, the playground's Reformat and the registry's build.fmt keep every comment where it was, and break a line around a comment the way they break long lines.
  • Faster:
    • the playground checks an edit about 5 times faster, and its download is 2.5% smaller;
    • sspur check is about 4% faster and sspur fmt 3% faster, and both use less memory;
    • in the interpreter, xs := xs.push(x), m := m.put(k, v) and b := b.add(s) append in place, so 40,000 Map.put calls take 0.1 s instead of 15 s.
  • Language:
    • typed lambda parameters (x: Int) => x + 1, _ => e, and binding annotations xs: List[Int] = [] that are checked and kept;
    • pkg.module.Name without a use;
    • type aliases over effect rows type Handler[e] = ...;
    • json.decode[T] and db.query[T] inside generic functions;
    • operators on BigInt, Dec and Ratio;
    • \u{...} escapes.
  • Standard library: Opt.and_then, Res.and_then, List.repeat, Map.is_empty, req.peer (the client's address), and binary responses with http.bytes.
  • New diagnostics:
    • W_UNUSED_RESULT flags xs.push(x) on a line of its own, which did nothing;
    • a note when a path dependency changed since sspur.lock pinned it;
    • dependency audits are shown at the dependency's own lines.
  • Deeper recursion on request: SSPUR_STACK=256M sspur run --interp recurses as deep as that stack allows, about 130,000 calls. Without it, the limit stays 20,000 calls.
  • Fixes: effect rows shared by several lambdas, fail[E] in parameter rows, catch-all | _ => over several error types, db.tx in generic code, effects in package signatures, to_bits natively, a native compiler stack overflow, nested match arms, and catch inside a string.

Changes that can affect existing code:

  • In a string, { interpolates only an expression that isn't a lone literal. So "a{3}" and "{{x}}" are text, and "{" no longer swallows the code after it.
  • with binds tighter than comparisons.
  • -0.0 == 0.0, and round, floor, ceil and trunc trap on NaN, infinities and overflow instead of saturating; checked_round and the other checked_* functions return an Opt.
  • == uses a type's own Eq impl inside lists, options, results and tuples.

Content hashes and published packages are unchanged. Startup, memory and the native benchmarks are unchanged or better than in 0.14.0.

Full list in the changelog.

SSPUR 0.14.0

Choose a tag to compare

@github-actions github-actions released this 17 Oct 06:32

sspur fmt breaks long lines, and the playground reformats code like an IDE. Builds for macOS, Linux and Windows, plus the VS Code extension, the JetBrains template and the Zed extension.

  orders = [
    Order{customer: "ana", item: "pen", cents: 300},
    Order{customer: "bo", item: "ink", cents: 900},
  ]
  • Line breaking (ADR 0040): lines over 100 columns break at their natural points: lists, records, calls and parameter lists one element per line, and/or chains one condition per line, long if chains and method chains. Short lines stay as they are. Formatting never changes a definition's content hash or a package's export hash, so lock files and published packages keep verifying.
  • Playground: Reformat Code (Cmd+Option+L, Ctrl+Alt+L or Shift+Alt+F) for the whole file or the definitions a selection touches, keeping the cursor in place; a marker at column 100; smart indentation as you type; an optional format on run. Phones scroll long lines sideways. The download is 3 KB smaller.
  • Public modules: a package can mark a module public = true, and dependents use pkg.models.{Doc}.
  • Fixes:
    • a function imported with use no longer hides a record field of the same name;
    • p.0.1 reads as two tuple accesses;
    • escapes apply inside literal braces in strings;
    • sspur q names scoped dependencies by their key.
  • Registry site: README tables, the top 12 packages, capped descriptions, and a 404 page that suggests the closest package.

Startup, memory and the native benchmarks are unchanged from 0.13.1.

Full list in the changelog.

SSPUR 0.13.1

Choose a tag to compare

@github-actions github-actions released this 17 Oct 04:32

SSPUR has a new home: the GitHub organization sspurlang and the site sspurlang.github.io. Builds for macOS, Linux and Windows, plus the VS Code extension, the JetBrains template and the Zed extension.

  • New addresses: the repository is github.com/sspurlang/sspur, the docs, playground and Pulse are at sspurlang.github.io/sspur, and the registry is at sspurlang.github.io/sspur-packages. Old repository, release and raw URLs redirect, and the old Pages addresses forward to the new ones. Existing installs, lock files and links keep working. sspur now reads the registry from its new home. The Homebrew tap stays utkarshavardhana/sspur.
  • Registry:
    • A public member of an organization may publish the first version of a package from the organization's repositories.
    • A package whose repository was transferred or renamed on GitHub keeps publishing from its new home.
    • The check pkg.fork stops a fork from claiming a new flat name.
    • The hourly sweep reruns unanswered requests one at a time; during bursts GitHub had cancelled all but one queued run.
  • 23 packages are published, among them strings, lists, dates, validate, semver, jwt, webhooks, ratelimit, cache, jobs, sqlkit and middleware.

Startup, memory, the native benchmarks and the playground download are unchanged from 0.13.0.

Full list in the changelog.

SSPUR 0.13.0

Choose a tag to compare

@github-actions github-actions released this 16 Oct 14:50

Scoped package names, big multi-module packages, and credit for authors in the registry. Builds for macOS, Linux and Windows, plus the VS Code extension, the JetBrains template and the Zed extension.

sspur add acme/pkg                    # pkg = { package = "acme/pkg", version = "^1.0.0" }
sspur add globex/pkg --as gpkg        # two scopes' pkg in one program
sspur add pagination@0.1.1            # exactly 0.1.1; ^ and ~ take ranges
sspur deps tree                       # which version of each package you use
  • Scoped names (ADR 0039): acme/pkg, where acme is the GitHub user or organization that owns the repository. A new blocking check, pkg.scope, verifies it. The request must come from that user, or from a public member of the organization. Two companies can each have pkg, and nobody can publish under someone else's scope. Flat names like pagination work as before.
  • Big packages: a published package can contain its own modules, and every check covers every module. Limits are now 2000 files, 1 MiB per file, 4 MiB of source and 20 MiB per repository, room for a library the size of Apache Commons Lang. Shared modules are built once and cached by their inputs. A cold sspur check of a 2.5 MB package in 200 modules went from 166 s to 11 s.
  • Credit for authors: the index commit for a published version is authored by the person who requested it, with a Co-authored-by line, so it counts in their GitHub contributions.
  • Exact versions: sspur add name@1.2.3 now means exactly 1.2.3. Use ^1.2.3 for the previous meaning.

A 0.12 client keeps working with flat-name packages; scoped packages need 0.13. Startup, memory, the native benchmarks and the playground download are unchanged from 0.12.1.

Full list in the changelog.

SSPUR 0.12.1

Choose a tag to compare

@github-actions github-actions released this 16 Oct 10:00

Fixes from the first days of the package registry. Builds for macOS, Linux and Windows, plus the VS Code extension, the JetBrains template and the Zed extension.

  • sspur update moves to newer versions. A registry dependency now updates to the newest version its requirement allows, even when the exports didn't change, and says so: ~ pagination 0.1.0 -> 0.1.1 (no API change).
  • sspur fmt keeps record shorthand. Page{items, total, limit: r.limit} stays as written, and x: x prints as x. The registry's format check also accepts continued lines, else on its own line and indented match arms, so idiomatic code publishes.
  • Programs find the sspur that started them. sspur run, test and debug set SSPUR to their own executable, so the web app's tests use the same binary even when an older one is on PATH.
  • Windows: a native build could read another build's half-written library name and fail with LoadLibraryExW failed. Fixed, and loads now retry briefly and keep the system's reason.
  • Registry: the first version of a new package name waits for a maintainer's /approve, and later versions merge on their checks alone. The site has proper desktop and phone layouts.

Startup, memory, the native benchmarks and the playground download are unchanged from 0.12.0.

Full list in the changelog.

SSPUR 0.12.0

Choose a tag to compare

@github-actions github-actions released this 16 Oct 03:45

A package registry that runs entirely on GitHub at no cost (ADR 0038), and sspur new web-app, a production-shaped reference application. Builds for macOS, Linux and Windows, plus the VS Code extension, the JetBrains template and the Zed extension.

sspur new web-app notes && cd notes
sspur run tests/run.ssp   # unit, end-to-end, concurrency and load tests, both tiers
sspur run                 # http://127.0.0.1:8080
sspur add pagination@^0.1
  • Registry (sspur-packages): one JSON file per package, each version pinned to its tag, commit and the content hash of its exports, with a reproducible source snapshot kept as a release asset. Installs use the snapshot and verify it, so a deleted repository or a moved tag never changes what you get. Installing never runs package code.
  • sspur add name@^1.2, update, publish, yank, search, source: Cargo's requirement syntax with the one-version rule, offline and reproducible from the lock.
  • 35 publish checks in SSPUR: build and tests in both tiers, semver by API diff, an effects audit that needs new capabilities acknowledged, docs, licence, naming, size and secrets, and a written code-review standard. Each failure gives file, line and the fix.
  • The publish loop: a request becomes a pull request whose description lists every check. Push a fix or comment /recheck, and it merges when every blocking check passes. Only package entries merge automatically.
  • Publish page: pick your repository and tag, run the checks in the browser, and open the request on GitHub. No sign-in or tokens.
  • sspur new web-app: a notes service with accounts, about 800 lines of SSPUR. It has a JSON API and HTML pages through one svc, SQLite migrations and full-text search, Argon2id, hashed session tokens, CSRF protection and login rate limits. It ships with tests, JSON logs, backups, and a systemd unit plus a Caddyfile for deployment. The tutorial walks through it.
  • Language and library fixes the app drove:
    • svc api(app: App) parameters, and svc endpoints that take and return any JSON type;
    • where refinements checked after JSON decoding, and Secret[Str] in config.load;
    • req.form and req.cookie, JSON log fields, and proc.spawn;
    • in-tree module packages that follow their source;
    • the interpreter's catch no longer swallowing other error types;
    • debug line mapping for networking and library programs.

Startup, memory and the native benchmarks are unchanged from 0.11.0. The playground download is 753 bytes larger (973 KB gzipped), for the catch fix.

Full list in the changelog.

SSPUR 0.11.0

Choose a tag to compare

@github-actions github-actions released this 15 Oct 17:02

Databases, crypto, compression and CSV, the data and security libraries real applications need (ADR 0037). Builds for macOS, Linux and Windows, plus the VS Code extension, the JetBrains template and the Zed extension.

type User = {id: Int, name: Str}

fn main() -> Unit ! db, rand, log, fail[DbErr]
= do
  c = db.open("app.db")
  _ = db.migrate(c, ["create table users(id integer primary key, name text unique)"])
  _ = db.exec(c, "insert into users(name) values (?)", ["ada"])
  us = db.query[User](c, "select * from users where name = ?", ["ada"])
  h = crypto.hash_password("correct horse")
  log("{us.len} {crypto.verify_password("correct horse", h)}")
  • SQLite (db effect): typed queries that map columns to records by name, parameters only by binding, transactions with savepoints, migrations, WAL and a busy timeout by default, and a connection pool that the HTTP server's concurrent handlers can share. Bundled as source, so there is no system dependency.
  • Crypto: SHA-256/512, BLAKE2b, HMAC, XChaCha20-Poly1305, Argon2id password hashing, Ed25519 signatures, secure random tokens and keys (rand effect), constant-time compare, UUID v4/v7. Secrets never print their contents. Checked against NIST and RFC test vectors.
  • Compression: gzip, deflate and zstd, for bytes and streamed files. The HTTP server's gzip now uses miniz.
  • CSV: RFC 4180 reading and writing, typed decoding into records by header name, and streaming over large files.
  • Bytes: a byte string with hex and base64 forms and binary file reads and writes.

Libraries, all vendored as source and compiled on first use: SQLite (public domain), Monocypher (BSD-2/CC0), libsodium SHA-2 parts (ISC), miniz (MIT), zstd (BSD). Programs that don't use them don't load them; startup, memory, the native benchmarks and the playground download (972 KB gzipped) are unchanged from 0.10.0.

Full list in the changelog.

SSPUR 0.10.0

Choose a tag to compare

@github-actions github-actions released this 15 Oct 06:06

Networking and source-level debugging, so SSPUR can build and debug real network services. Builds for macOS, Linux and Windows, plus the VS Code extension, the JetBrains template and the Zed extension.

Networking (new net effect, ADR 0035)

Client

fn title(base: Str, id: Int) -> Str ! net, fail[HttpErr]
= json.decode[Todo](http.fetch("{base}/todos/{id}")).map(t => t.title).or("?")
  • http.get, http.post and http.send(req) return Res[Response, HttpErr] (Dns, Connect, Tls, Timeout, HttpStatus, Io); http.fetch raises for anything but 2xx.
  • Timeouts, retries with backoff and Retry-After, redirects, downloads to a file, proxies from the environment, gzip, and certificate verification on by default.
  • libcurl on macOS and Linux, WinHTTP on Windows.

Server

svc api
  ep get "/todos/{id}" = todo
  ep get "/todos" = todos
  ep post "/todos" = add

fn main() -> Unit ! net, log, env
= http.serve_with(http.server(8080) with gzip := true, health := "/healthz", api)
  • Routes come from svc: path and query parameters and JSON bodies bind and are checked as in deployed services.
  • CORS, gzip, static files, request size limits, timeouts, request ids, keep-alive, TLS (OpenSSL 3), graceful shutdown on SIGINT/SIGTERM, and concurrent handlers on a thread pool.
  • About 28,000 requests a second on an M1 Pro, with memory flat under sustained load; the request parser is fuzzed under AddressSanitizer.

Essentials: config.load (environment, then a JSON file, then defaults, checked by contracts), log.debug/info/warn/error with SSPUR_LOG_LEVEL and SSPUR_LOG=json.

Both tiers give byte-identical responses. Programs that don't use networking don't load it. In the playground, HTTP returns a typed error.

Debugging (ADR 0036)

sspur run --debug builds native code that lldb and gdb step through at the .ssp level: breakpoints by file and line or by function name, SSPUR names in backtraces and locals, readable strings, lists, records and sums, and a sspur_trap breakpoint for failed contracts. sspur debug launches the debugger; sspur debug-init installs the formatters; VS Code works through CodeLLDB. Release builds are unchanged.

Also

  • SSPUR Pulse fetches with the new client instead of curl.
  • Startup and memory: the cached sspur run path does no extra work, and peak memory is below 0.9.0 on Apple Silicon. The playground download is smaller than 0.9.0's (972 KB gzipped).
  • Native benchmarks are unchanged.

Full list in the changelog.

SSPUR 0.9.0

Choose a tag to compare

@github-actions github-actions released this 14 Oct 15:04

SSPUR Pulse, a live dashboard of the world computed by SSPUR programs, plus two compiler fixes it uncovered and an up-to-date set of docs. Builds for macOS, Linux and Windows, plus the VS Code extension, the JetBrains template and the Zed extension.

SSPUR Pulse

https://utkarshavardhana.github.io/sspur/pulse/

Eight boards, recomputed every 6 hours by SSPUR programs on free GitHub Actions and served from GitHub Pages: what the world is reading on Wikipedia, upcoming space launches with a live globe of about 16,700 satellites moving at their real speed, earthquakes, the fastest-rising GitHub repos, a Hacker News time machine, the day's AI papers, weather in 135 cities, and public holidays in more than 200 countries. Charts you can toggle, your own local weather, light and dark themes, and a few secrets to find. No servers, no keys, no trackers. The source is in pulse/ and how it works explains the design.

Fixed

  • Native json.decode gave every decoded string room for the rest of the input, so large arrays used memory quadratic in their size: 1.3 MB of JSON ran out of an 8 GB heap. It now decodes in linear memory and about 3x faster than the interpreter. Pulse runs natively because of it.
  • g.OBJECT_NAME, a field whose name starts with a capital letter, parsed as a package-qualified name. It is a field access unless g is a dependency, so JSON records with upper-case fields work.

Docs

The README, docs site, benchmark pages and editor docs are current: native code at 0.14x to 0.89x of C++'s time with memory near or below C++'s except on the GPU benchmark, the large-codebase agent results (Sonnet 0.59x TypeScript's tokens, Opus 0.85x, Haiku 0.68x), while e is p, the cached run and the Zed extension.

Full list in the changelog.