Changelog
All notable changes to Baa are recorded here.
The format follows Keep a Changelog. Baa follows semantic versioning from 1.0; before then, minor versions may change the language, and every such change appears here with a migration note.
[0.8.0], 2026-08-19#
The tooling release: Baa's diagnostics can be read by a program, its formatter can show its work, its checker can stay running, and a program can be given less than the shell that started it.
Added#
--format jsononcheck,lintandfmt. One JSON object on stdoutper run, carrying every diagnostic with its stable code, both wordings, file, range, notes, help and trace. It is a second presentation of the same
Diagnosticvalues the terminal renders — nothing parses formatted text — so JSON cannot report a problem the terminal would not, or miss one it does. One line per run, so a log of reports is also valid JSON Lines. The schema is documented in docs/diagnostics-json.md and versioned: within a version, fields are added and never removed.
run and test refuse the flag with BAA301. Their stdout belongs to the program, and a report written into that stream could not be told apart from what the program printed.
baa fmt --diff. A unified diff of what formatting would change, withoutchanging it. Exits exactly like
--check, and prints nothing at all for a file that is already formatted, so any output means "this would change".baa check --watch. Re-checks only what changed: 92 ms cold on a200-file project, 12 ms after one edit. There is no dependency graph, and that is not a shortcut — Baa's analysis is per-file, because a module's diagnostics do not depend on the modules it imports, so a graph would always report no dependents. Changing
baa.tomldrops the whole cache, since it decides which module names are importable.- Capability flags on
baa runandbaa test:--deny-fs,--deny-fs-write,--deny-env,--deny-process. They wrap the host rather than auditing the standard library, so an allowed operation is untouched and a denied one raises the newBAA313where it happens, which a program can catch. Nothing is denied by default.
--allow-fs <dir> confines rather than refuses, and is repeatable. A path is judged by where it leads: resolved first, so .. cannot climb out, and with the part of it that exists followed to its real location, so a link inside an allowed directory cannot point out of one.
There is deliberately no --deny-network — Baa cannot open a socket, and a flag denying a capability the language lacks would suggest the others are the same gesture — and no --deny-randomness, because --seed already does what that usually means. SECURITY.md says what this claims and what it does not.
- Application icons and version metadata on Windows.
[app] iconpoints atan
.ico, andtitle,version,companyandcopyrightfill in the Details tab of the executable's Properties. Written into the PE by hand, because the build has no linker: a section header after the last one, the bytes at the end of the file, three numbers corrected. It refuses rather than guessing on anything it does not recognise. [wool]dependencies inside a native application.import my_libisbundled like any other file, along with whatever it imports in turn. Nothing is fetched and nothing runs at build time: a dependency is a local path. A bare import that is neither a standard module nor a declared dependency stops the build.
- Regular expressions in the native runtime. The five
woolfunctions thattake a pattern used to report that the native runtime had no engine. It has one now: a parser, a backtracking virtual machine, and a subset written into SPEC.md rather than left to whatever the implementation happened to do.
Backtracking rather than a Thompson simulation, because JavaScript's answers depend on it: alternation is leftmost-first, so a|ab matches a in abc, and a greedy quantifier gives characters back one at a time until the rest of the pattern fits.
Lookahead, lookbehind, backreferences and \p{...} are refused by name with the new BAA314, and a pattern that would run for ever is abandoned with the same code. A near-miss reimplementation is worse than an absence: a pattern that quietly means something different is a bug that survives review.
Thirteen pattern programs joined the conformance suite, so both runtimes are now held to byte-identical output on greedy and lazy quantifiers, named groups, empty matches, $& and $1 replacements, flags, boundaries and classes. The suite is 63 programs, and the native runtime passes all of them.
- Timers in
barn:barn.every(millis, handler), `barn.after(millis,handler)
andbarn.cancel(id). Ticks arrive on the event loop, in the same single thread as every other handler, so there is no second concurrency model to reason about: a handler that takes 200ms delays the next tick rather than overlapping it. The handler is called with the timer's id, so a timer can stop itself, andafter` cancels itself once it has fired.
examples/native/clock is a stopwatch built on it, and a test drives the real event loop on a real window: three ticks, a cancel from inside the handler, then a one-shot that quits.
baa doc, a Markdown reference for everything a project exports, from the///comments the parser already keeps for the language server's hovers.--outwrites a file,--checkfails when that file is stale, and the output is deterministic so--checkin CI means something.- Nine standard-library functions, in both runtimes.
pasture.walk,pasture.globandpasture.matches;flock.union,flock.intersect,flock.differenceandflock.is_subset;meadow.durationandmeadow.format_duration.meadow.partsandmeadow.isotake an optional UTC offset in whole minutes, and the ISO text then ends in+01:00rather than lying withZ.
The glob subset is ?, * and ** and nothing else. There are no time-zone names: an offset is a fact about an instant, while a zone name is a rule that changes twice a year and needs a database shipping updates.
Changed#
- Reading a variable is an array index. The resolver records how many
scopes out each name lives and which position it holds there;
Environmentkeeps its bindings in declaration order. Measured back to back on one machine, best of three: 300k loop iterations 56.0 ms → 46.6 ms,map/filter/sum42.1 ms → 36.1 ms,fib(22)unchanged within noise, because a call defines its parameters and that bookkeeping offsets what its lookups save.
The slot carries the name it was resolved from and is checked before it is trusted: a disagreement falls back to the name walk rather than reading the wrong binding, and a test asserts the fallback never fires. Nothing about the language changed, and the native runtime is untouched — the image format carries no slots.
docs/stdlib.mdnow carries prose beside the signatures where a one-linedescription cannot carry the rules, which is how the glob subset and the offset range are published.
Fixed#
shepherd.runbypassed the capability boundary. It calledchild_processdirectly, so the most dangerous operation in the language was the one operationRuntimeHostcould not see — whilehost.tsclaimed everything went through it. It now goes throughhost.runProcess, still without a shell, and a test asserts the module does not importchild_processat all.baa check --watchinstalls its watcher before the first sweep rather thanafter it, so an edit that lands during a long first check is not lost.
[0.8.0]: https://github.com/PatrickJnr/sheep/releases/tag/v0.8.0
[0.7.1], 2026-08-19#
Fixed#
- The marketplace listing had no description. The extension published as
0.7.0 was built before the README and icon existed, so its page read "No README available" — the package on disk carried both by then, and the upload did not. A version cannot be replaced once published, so this is the release that carries them.
The same version number therefore existed as two different packages, which is the actual lesson: vsce publish --packagePath uploads whatever file it is handed, and nothing checks that the file matches the working tree it was named from. The release workflow builds the package it publishes in the same job, so it cannot drift.
[0.7.1]: https://github.com/PatrickJnr/sheep/releases/tag/v0.7.1
[0.7.0], 2026-08-18#
The native runtime is published, so building a desktop application no longer means installing Rust.
Added#
- Prebuilt native runtimes on every release.
baa-native-windows-x64.tar.gzcarriesbaa-native.exeandbaa-nativew.exe;baa-native-linux-x64.tar.gzcarriesbaa-native. Each archive has asha256beside the binaries, because an artefact nobody can verify is an artefact nobody should run. CI has compiled the runtime on both platforms every commit since 0.4.0 and thrown the result away.
Unpack one into ~/.baa/runtime and baa app build finds it. That directory is searched before any checkout, so a downloaded runtime cannot be shadowed by a stale cargo build in a clone. When no runtime is found, the message names the archive for the platform it is running on.
BAA_SERVER_PATHpoints the VS Code extension at a language server, forthe places with no settings UI to type one into: a container, a CI job, a remote host started by a script. The
baa.server.pathsetting still wins.
Changed#
- A Linux build that imports
barnnow warns. The window model isplatform-independent and only Windows has a backend, so the executable is real, runs, and cannot draw. Saying that at build time is the difference between a documented limit and a program somebody ships and then discovers. A test asserts the CLI only ever offers a download the release workflow actually builds, so the link cannot outlive the job that produces it.
Fixed#
- The VS Code integration test could not pass on a hosted runner. It
assumed a global npm install puts
baaonPATH, which is true on a developer's machine and not on a runner, so the job failed for being right about the wrong thing. The logic that matters — deriving the server's entry point from the shim, because Node will not spawn a.cmd— is now a module with novscodeimport, tested against a fake filesystem.
[0.7.0]: https://github.com/PatrickJnr/sheep/releases/tag/v0.7.0
[0.6.0], 2026-08-18#
VS Code gets the language server it has been able to run for two releases.
Added#
- A VS Code extension that actually starts
baa lsp. Diagnostics as youtype, formatting, an outline, hover, go to definition, find references and rename — all from the same analysis
baa checkruns, with no configuration whenbaais onPATH. Install the.vsixattached to this release withcode --install-extension baa-lang.vsix.
The extension implements no language intelligence of its own, and a test asserts it registers no providers: a second opinion about what a program means is worse than no opinion.
- An integration test that launches a real VS Code, loads the extension,
opens a
.baafile and checks thatBAA102arrives on the right range, that formatting returns edits and that go to definition lands on the declaration.npm run test:vscodeineditors/vscode, and a CI job on Windows.
It earned itself immediately. npm install -g writes baa.cmd on Windows, and since CVE-2024-27980 Node refuses to spawn a .cmd without a shell, so the obvious implementation found nothing on the platform most people use and failed silently. shell: true would have been re-opening that hole; the extension resolves the JavaScript entry npm installed beside the shim and runs it under the editor's own Node.
- The
.vsixis built by CI and attached to every release, since theextension is not on the marketplace and there is no publisher to trust.
Changed#
actions/checkoutandactions/setup-nodemoved from v4 to v7. Both weretargeting Node 20 and being forced onto Node 24 with a warning on every run.
[0.6.0]: https://github.com/PatrickJnr/sheep/releases/tag/v0.6.0
[0.5.0], 2026-08-18#
An audit release. The largest gap between Baa's two runtimes is closed, and three things the documentation asserted turned out not to be true — including one the tooling had been asserting louder.
Added#
shepherdandmeadowin the native runtime. An application can readits own command line, its environment and standard input, start a program without a shell, ask what time it is, and shuffle a list. Both modules match the reference function for function and arity for arity, and the calendar arithmetic is written out rather than pulled in, so the crate still has no dependencies.
With them, all 50 conformance programs run on the native runtime and all 50 pass. Nothing is skipped.
One case is refused rather than approximated. meadow.parse_iso on a date-time with no zone — 2026-08-18T09:30 — means local time in JavaScript, so the same program would produce a different number on a machine in a different place. The native runtime raises BAA301 naming the fix. Text with Z or an explicit offset, and date-only text, are read identically by both.
- A drift guard over every native module, not just
barn. It compares eachmodule's function names and argument counts against the reference implementation's own module objects, so a function that quietly takes one argument fewer on one side fails a test rather than a program.
/llms.txtand/llms-full.txt, generated bytools/gen-llms.tsfromthe same catalogue the compiler reads. Every standard-library signature, the rule that decides whether a file is a web page or a native application, which modules exist on which target, and the mistakes that compile and do the wrong thing. The examples in them are compiled by the test suite and
npm run gen:checkfails when the published copy is stale, because a wrong signature handed to a language model produces code that cannot run and gives it no way to notice.
Fixed#
- The language tour contained a truncated copy of itself. A
$inside ashell heredoc ate the rest of a sentence about regular-expression flags, and the whole document landed in the gap, so LANGUAGE.md introduced itself twice and one explanation stopped mid-clause. It shipped that way in the npm package and on the website for two releases, because every link still resolved and the duplicate was valid Markdown. The document is repaired and a test now asserts that no document states its own title twice.
- A skipped conformance program was counted as a pass. The native
conformance harness marked a program it had decided not to run as passing, so its summary line read
50/50when 49 programs had executed. The documentation had said 49 all along; the tool contradicted it and the tool was believed.
Skips are counted separately now, printed as SKIP under --verbose, and a test asserts a skip can never become a pass. With shepherd and meadow landing in this same release the count is genuinely 50 of 50, which is the point: the number is true rather than reworded.
- Heading anchors matched neither GitHub nor themselves. The site's slug
generator collapsed a run of spaces into one hyphen where GitHub emits one per space, so a link to a heading such as
Goal — **NEXT**worked in one renderer and 404'd in the other. It now uses GitHub's algorithm. - A web-page module answered 500 with the server's absolute path. A
.baafile the CGI handler could not execute was still claimed by
AddHandler cgi-script .baa, which matches by extension regardless of permissions. Modules now deploy as.baalib, which the handler does not claim, withRedirectMatch 403refusing them outright. - Two CI checks believed things that had not happened. The test-count check
counted an environment rather than a suite, and treated a site build that had silently skipped as a build that had succeeded.
Changed#
- The documentation index lists every page, including the web and native
application guides and the files written for language models, and reads its module and diagnostic counts out of the implementation rather than stating them by hand.
[0.5.0]: https://github.com/PatrickJnr/sheep/releases/tag/v0.5.0
[0.4.0], 2026-08-18#
Baa runs in a second place. A .baa file has always been a web page, executed by a server per request; it is now also a desktop application, held open by a runtime that draws a real window. Nothing about the language changed to make that true.
Added#
- Native applications.
baa app new | build | run | testturns a projectinto a single Windows executable containing the runtime and the program. No Node.js on the machine that runs it, no browser inside it, no unpacking.
The architecture, and the reasoning for it, is in ARCHITECTURE.md. In short: the reference implementation stays the only frontend. baa app build runs exactly the analysis baa check runs, writes the resolved tree into a .fleece image, and appends that image to a runtime written in Rust. One frontend cannot disagree with itself, and a program that fails baa check produces no executable.
barn, the ninth standard-library module: windows, rows and columns withweights, labels, buttons, inputs, text areas, lists, checkboxes, a real menu bar, message boxes, file dialogs, the clipboard, and per-monitor DPI so text is sharp on a scaled display rather than stretched.
It is gate's opposite number — a program imports one or the other — and importing gate into an application is a build error naming it. barn exists in the reference implementation too, where every function reports that it needs the native runtime, so that baa check, the linter and the language server all work on an application's source.
- The native runtime,
rust/crates/baa-native: a tree-walking interpreterin Rust with no dependencies at all, including its own JSON parser and its own Win32 declarations. It implements
barn,flock,lamb,pasture,ramandwool, and passes every one of the 49 conformance programs it can run, byte for byte. The fiftieth importsshepherd, which it does not have, and the harness reports that as a skip. - Three applications that are also the tests.
examples/native/calculatorimports the web calculator's arithmetic module unchanged — the same tokeniser and precedence-climbing parser, the same tests, two front ends.examples/native/notepadis a text editor with menus, file dialogs and unsaved-change tracking derived from the text rather than from a flag.examples/native/json-viewerparses a document and walks the result into an outline. All three are driven through Win32 by the test suite, which sends the messages a click actually is and reads back what the window says. - Documentation: native applications,
barn, application projects, building for Windows and the runtime's insides, plustools/bench-native.tsso the numbers in them can be checked rather than believed.
Changed#
- A newline inside
{ends a statement again, even inside(. The lexercounted open brackets and suppressed every newline while any
(or[was open. That made a multi-line function literal impossible to pass as an argument:
``baa on(button, "click", fn() { state = next(state) refresh() // BAA006: expected the end of the statement }) ``
It now tracks which bracket is innermost: ( and [ suppress newlines, { restores them. The rule in SPEC.md §2.2 is corrected to match.
Migration: nothing. The whole test suite passed unchanged, because the old behaviour had no use — it turned working-looking code into a syntax error reported against the wrong line. Map literals are unaffected: their entries end in ,, which a different rule already covers.
Fixed#
baa app buildover a running application says "it is running" rather thanprinting
EBUSY: resource busy or lockedand a Node stack trace.
[0.4.0]: https://github.com/PatrickJnr/sheep/releases/tag/v0.4.0
[0.3.2], 2026-08-18#
Changed#
- A page costs less to serve. The CLI imported the language server, the
development HTTP server and the REPL at module scope on every invocation. Each is needed by exactly one command, and
lsppulls in the whole analysis stack. That is invisible when a command runs once on a developer's machine and is paid on every request under CGI, where each request is a fresh process.
All three are imported at their call site now. Measured by building the previous commit into a worktree and running both alternately, so drift in the machine hit each equally: what Baa adds to a request fell from 217ms to 161ms, a 26% cut. What remains is the lexer, parser, runtime and standard library, which a page genuinely needs.
Fixed#
- The example site works wherever it is mounted. Every link was
root-absolute, so a deployment under a subdirectory rendered its pages and broke its stylesheet and every link.
layout.baaexportsbase(), which reads CGI'sSCRIPT_NAMEand returns the directory the page is served from, and every link goes through it. Nothing has to be configured. baa serveaccepts a URL that names the page file. Its walk-up lookedfor the rest of a path under
<name>.baaand never considered that the URL might already say.baa. Apache maps a URL to a file and will not invent the extension, so the spelling a deployed site has to use was the one the development server rejected.
[0.3.2]: https://github.com/PatrickJnr/sheep/releases/tag/v0.3.2
[0.3.1], 2026-08-18#
Fixed#
baa page.baaruns the file. A page executed by its shebang arrives asbaa /path/to/page.baa, because the kernel appends the script to the interpreter's arguments. The CLI looked for a subcommand of that name and reportedUnknown command, so every CGI page was a 500 and every./script.baafailed, with an error blaming the part that was correct.
A first argument ending in .baa, or naming something that exists, is now run. Anything else still gets the command list, so a mistyped buidl is not reported as a missing file. Remaining arguments reach the program through shepherd.args().
This also makes baa hello.baa work without run, the way python x.py does.
Added#
tools/build-cgi.tsgenerateswebsite/baa/: the example site with theshebang,
.htaccessand a diagnostic page a real web server needs. The interpreter path differs on every host, soBAA_CGI_SHEBANGsets it.
[0.3.1]: https://github.com/PatrickJnr/sheep/releases/tag/v0.3.1
[0.3.0], 2026-08-18#
Added#
- Go to definition, find references and rename, in the language server.
All three read the resolver's symbol table rather than the text, so a binding that shadows an outer one of the same name is a different symbol: renaming the inner
countin a function rewrites its own uses and leaves the outercountalone. A search and replace would touch both. - Prepare-rename, so an editor can refuse a rename before prompting for a
name. Rename itself rejects anything the lexer would not accept as an identifier, rather than writing a file that no longer parses.
ResolveResultnow carriessymbols, and eachSymbolInfocarriesreferences: the span of every use that binds to that declaration. The resolver already decided this while checking for unused bindings; it simply threw the positions away afterwards.CheckResult.analysisexposes that fromcheckandlint.
Changed#
- Hover is scope-aware. It resolved names against the file's top-level
declarations, so a local sharing a name with a top-level function showed that function's documentation. It now asks the symbol table first.
lintno longer resolves the program twice. It re-ran the whole resolver toget an analysis that
checkhad already produced, which an editor paid for on every keystroke.
[0.3.0]: https://github.com/PatrickJnr/sheep/releases/tag/v0.3.0
[0.2.2], 2026-08-18#
Fixed#
- The installed
baacommand did nothing and exited successfully. npminstalls a bin as a symlink, so running
node_modules/.bin/baagives anargv[1]pointing at the link whileimport.meta.urlpoints at the file it targets. The entry-point check compared the two directly, decided it was being imported rather than run, and skippedmainentirely. Both sides are now resolved throughrealpathSync.
Windows hid it: there npm writes a .cmd shim that invokes node with the real path, so the paths matched and only Linux and macOS were affected. The CI step added in 0.2.1 runs on Linux and caught it on its first outing.
0.2.1 reached the GitHub releases but never reached npm, so the only version published before this one is 0.2.0.
[0.2.2]: https://github.com/PatrickJnr/sheep/releases/tag/v0.2.2
[0.2.1], 2026-08-18#
Fixed#
- The published package could not run. 0.2.0 shipped its TypeScript
sources with
binpointing atsrc/cli/index.ts. It installed cleanly and then failed on the first command withERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING: Node refuses to strip types from files undernode_modules. The package now ships compiled JavaScript, built bynpm run buildand invoked automatically byprepack.
Nothing changes for a clone. Development still runs src directly and still has no build step; the build exists only to produce the tarball.
0.2.0 is deprecated on npm. Use 0.2.1.
Added#
- A CI step that packs the tarball, installs it into a scratch project and
runs a program through the installed binary. Every other check runs from the checkout, which is why a package that only fails once installed passed all of them.
[0.2.1]: https://github.com/PatrickJnr/sheep/releases/tag/v0.2.1
[0.2.0], 2026-08-18#
An audit release. Nothing in the language changed shape; several things that were wrong about it are now right, and the tooling grew a language server.
Added#
baa lsp, a language server over stdin and stdout: diagnostics as youtype, whole-file formatting, a document outline, and hover for top-level declarations. It runs the same analysis as
baa checkandbaa lintrather than a second copy of it. Go to definition, find references and rename are not implemented and are not advertised. See docs/editors.md.baa build --locked, which verifiesbaa.lockinstead of rewriting itand reports
BAA406naming the wool that arrived, changed, moved or went away. Every build previously rewrote the file, so a dependency whose contents had changed silently updated its own recorded hash.BAA406, for a lockfile that no longer describes the project.- Eight conformance programs covering the semantics newly written down below.
Fixed#
- Diagnostic messages no longer double their articles. Four templates wrote
the article themselves while every call site also supplied one, so programs were told "You can't add a an array and a a number", "A an array has no field called
merge" and "expected a count of 0 or more, but got a a negative number".BAA302,BAA305,BAA309andBAA311are affected. Codes and spans are unchanged; only the wording is. - Two diagnostics reported JavaScript type names, so
ram.parse([1])andshepherd.exit("x")could tell a program it had passed "a object". - Array growth is bounded.
push,unshift,insertandconcathad nosize limit, though
repeatandflock.rangehave had one since 0.1. Appending to an array while iterating it allocated for about forty seconds and then surfaced a JavaScriptRangeErrorwrapped inBAA301. It is nowBAA312, reported against the call. - The standard-library module count said seven in seven different files, in
SPEC.mdamong them, while eight were listed. The diagnostic count was given as 41 in one place and 44 in another, against 45. The dependencies badge said "none" while three development dependencies are installed.
Documented#
SPEC.mdnow states whatforbinds (one name is the value, two are theposition and the value, and for a
mapa single name binds the value), thatforre-reads a collection's length rather than taking a snapshot, how afinallyblock that returns or throws replaces the outcome that was pending, and that map keys are not coerced so1and"1"are two entries. All four were well defined in the implementation and absent from the document a second implementation would be written against.docs/editors.md, covering the language server and configuration for Neovim,Helix and Emacs.
Changed#
- Diagnostic wording only, as above. No code, span, severity or exit code
changed, so anything grepping CI logs for
BAAnnnis unaffected.
[0.2.0]: https://github.com/PatrickJnr/sheep/releases/tag/v0.2.0
[0.1.0], 2026-08-17#
The first release. Baa is a complete, working language rather than a prototype: every feature listed here is implemented, tested and exercised by a real program in examples/.
Language#
- Values:
nil,bool,number,string,array,map,range, plusfirst-class
functionandmodule. - One numeric type (IEEE-754 double). Literals in decimal, hex (
0xFF), octal(
0o17) and binary (0b1010), with_separators and exponents. letandconstbindings, block-scoped, with shadowing, and destructuringof arrays and maps (
let [a, ..rest] = xs,let { name as who } = sheep).- Four string spellings: plain,
"""block strings indented by their closingdelimiter, and
r"..."/r"""..."""raw strings with no escapes and no interpolation. - String interpolation (
"{expr}"), with full expressions and nested stringliterals inside the braces.
- Operators: arithmetic including
**, comparison,&&,||,??,!,in, ranges..and..=, and compound assignment. - Structural equality for arrays and maps.
if/else if/else,while,for ... in,break,continue.forover arrays, strings, maps and ranges, with one or two bindings.- Functions with default parameters, rest parameters (
..rest), closures andhoisting.
matchexpressions with literal, binding and wildcard patterns,||alternatives and
ifguards.throw,try/catch/finally, and catchable runtime errors thatarrive as a map with a stable code.
- Modules:
export,importby name or path, aliases, named imports,load-once semantics and cycle detection.
test "name" { ... }blocks as a language construct.- Comments:
//, nesting/* */, and///doc comments. - Optional semicolons, via a three-rule newline policy handled in the lexer.
Tooling#
baa run,check,test,fmt,lint,serve,repl,init,build,add,remove,doctor,modules,version.- Deterministic formatter that preserves comments and is a fixed point.
- Linter with six rules (
BAA901–BAA906) and_-prefix and--disableescape hatches.
- REPL with persistent scope, multi-line continuation and
:commands. - Project manifest
baa.toml, lockfilebaa.lock, local path dependencies. --seedfor reproducible runs of anything usingmeadow.
Diagnostics#
- 45 diagnostic codes across six ranges, each with a stable
BAAnnncode. - Rendered with the file, line, column, the source line and an underline of the
exact span, plus suggestions where possible.
- Runtime errors carry a real call stack captured at the point of failure.
- Two wordings per diagnostic: sheep-flavoured by default, neutral under
--no-baa,BAA_NO_BAA=1orCI=true, with identical codes and spans. - Parser recovery:
baa checkreports many syntax errors in one pass. - "Did you mean" suggestions for names, methods, module names and map keys.
Standard library#
wool, text: formatting, case conversion, wrapping, centring, bytes,regular expressions, HTML and URL escaping.
flock, collections: grouping, chunking, zipping, partitioning, mapconstruction.
ram, arithmetic: rounding, integer division, statistics, constants.meadow, time and randomness, seedable for reproducibility.pasture, files and platform-aware paths.shepherd, arguments, environment, stdin, and shell-free subprocesses.lamb: JSON encoding and decoding.gate, the web: reading a request and writing a reply over CGI, withescaping that is safe by default.
- Prelude:
len,type_of,to_string,to_number,inspect,clone,assert,assert_eq,panic,exit. - Methods on strings, arrays, maps, ranges and numbers.
Project#
- 536 automated tests across lexer, parser, resolver, runtime, standard
library, diagnostics, formatter, linter, modules, CLI and examples.
- Baa's own test blocks, run by
baa test. - Recorded example transcripts, asserted by the suite.
- Benchmarks for the front end and the runtime.
- Documentation: README, language tour, specification, architecture, CLI
reference, generated standard-library and diagnostic references, FAQ, roadmap, contributing guide, security policy.
- Static website, deployable to any web host.
- VS Code extension with syntax highlighting, snippets and language
configuration.
- CI across Windows, Linux and macOS.
- No third-party packages at runtime.
[0.1.0]: https://github.com/PatrickJnr/sheep/releases/tag/v0.1.0