# Baa 0.8.0: a complete reference for language models
Everything needed to write Baa that compiles and runs. Generated from the implementation, so every signature here is real. Source: https://github.com/PatrickJnr/sheep
---
## Two targets, decided by what a file imports
Every Baa file has the extension `.baa`. What a file *is* depends on its imports, not on where it lives:
| Imports | It is | Run it with |
| --- | --- | --- |
| `gate` | a web page, executed once per HTTP request | `baa serve
`, or CGI on a real host |
| `barn` | a native application with a window | `baa app run`, built with `baa app build` |
| neither | an ordinary module, usable from both | `baa run`, `baa test` |
Never import both into one file. `gate` is unavailable to native applications and the build refuses it; `barn` under `baa run` reports that it needs the native runtime.
Put logic in a module that imports neither. It is testable in milliseconds with `baa test`, and it is the only part that both targets can share.
## Syntax
```baa
// Bindings. `const` cannot be reassigned, and the analyser checks.
let count = 0
const FLOCK = ["Dolly", "Shaun"]
// Functions: defaults, rest parameters, closures, first-class values.
fn greet(name, greeting = "Baa") {
return "{greeting}, {name}!" // interpolation with { }
}
fn sum(..numbers) {
return numbers.reduce(fn(total, n) { return total + n }, 0)
}
// Printing. `baa` is the print statement; it takes several values.
baa greet("Dolly"), count
// Control flow. `if` is a statement; `match` is an expression.
if count > 0 {
baa "some"
} else if count == 0 {
baa "none"
} else {
baa "negative"
}
const label = match count {
0 => "none",
1 => "one",
n if n < 10 => "a few",
_ => "many",
}
// Loops. `for` walks arrays, maps, strings and ranges.
for name in FLOCK { baa name }
for index, name in FLOCK { baa index, name }
for key, value in { a: 1 } { baa key, value }
for n in 0..10 { } // 0 to 9
for n in 0..=10 { } // 0 to 10
while count < 3 { count += 1 }
// Destructuring, in `let` and `const`.
const [first, ..rest] = FLOCK
const { name, age } = { name: "Dolly", age: 6 }
// Errors. `throw` any value; `catch` binds it.
try {
throw { code: "TOO_WOOLLY" }
} catch problem {
baa problem.code
} finally {
baa "always"
}
// Modules. Relative imports need the path; standard ones do not.
// import wool
// import { trim } from wool
// import "./basket.baa" as basket
// Tests live anywhere and run with `baa test`.
test "greets" {
assert_eq(greet("Dolly"), "Baa, Dolly!")
}
```
Operators: `+ - * / % **`, `== != < <= > >=`, `&& || !`, `??` (nil-coalescing), `in`, `..` and `..=` (ranges), `= += -= *= /= %=`. `**` is exponentiation and is right-associative.
Newlines end statements. There is no semicolon requirement and no line-continuation character: a newline is ignored inside `(` or `[`, or after an operator, or before a leading `.` in a method chain. A `{` makes newlines significant again, so a multi-line function literal can be an argument.
## Mistakes that compile
Each of these was a real error made while writing the example applications in this repository. They are listed first because they cost the most time.
### `{` inside a string starts an interpolation
This is the one mistake that compiles and produces a wrong answer with no error, so it is worth knowing exactly when it does and does not.
| Written | What happens |
| --- | --- |
| `"{" + x` | `BAA001`: the interpolation is never closed. A loud error |
| `"{" + x + "}"` | **Silently wrong.** The closing `"}"` completes the interpolation, so the whole thing is one string and it prints that interpolation's own text: `` + x + `` |
| `"{\"a\": 1}"` | `BAA001`. JSON written directly in a string does not work |
| `"\{" + x + "\}"` | Correct: `{5}`. Escape the braces |
| `r"{a}"` | Correct: `{a}`. A raw string processes no interpolation |
Write `"\{"` and `"\}"` for literal braces. For anything brace-heavy, such as JSON or CSS, use a raw string: `r"..."`, or a raw block string `r"""` ... `"""` when it contains quotes. To build text from values, use interpolation as intended: `"{name} has {count} sheep"`.
### `if` is a statement, not an expression
`let x = if a { 1 } else { 2 }` does not parse. Use `match`, which is an expression: `let x = match true { _ if a => 1, _ => 2 }`.
### `fn` declarations are hoisted; `let` and `const` are not
A `fn` declaration can be called before the line it appears on. A function bound with `const f = fn() { ... }` cannot.
### Only `nil` and `false` are falsy
`0`, `""` and `[]` are all truthy, as in Lua and Ruby. Test emptiness explicitly with `x.is_empty()` or `len(x) == 0`.
### There is one number type
`12` and `12.0` are the same value and `12 == 12.0` is true. Integer division is `ram.idiv(a, b)`. Dividing by zero is an error (`BAA306`), not `inf`.
### Arrays and maps are references; `clone` copies
Passing an array to a function passes the same array. `clone(x)` is a deep copy.
### Maps keep insertion order
Iteration and printing follow the order keys were first added. Replacing a value does not move it.
### `from` and `to` are reserved words
Neither can be a variable name. `flock`, `wool`, `ram`, `gate` and `barn` are ordinary bindings that shadow the module of the same name if you declare them, which then breaks every later use of the module.
### Strings index by character, not by byte
`len`, `[]`, `slice` and `index_of` all count characters, so a string containing emoji behaves the way it looks.
### A negative index counts from the end
`items[-1]` is the last item. An out-of-range index is `BAA304`, not `nil`.
### `match` needs a total set of arms
No arm matching is a runtime error (`BAA301`), not `nil`. End with `_ => ...` unless every case is genuinely covered.
### Comparison needs matching types
`<` works on two numbers or two strings; anything else is `BAA302`. Sorting mixed types needs an explicit comparison function.
## The prelude
Available in every file with no import. A local declaration may shadow any of them.
| Function | Arguments | Description |
| --- | --- | --- |
| `len` | 1 | Length of a string, array, map or range. |
| `type_of` | 1 | Type name: "nil", "bool", "number", "string", "array", "map", "range", "function" or "module". |
| `to_string` | 1 | Text form of any value. |
| `inspect` | 1 | Developer-facing form of any value, with quoted strings. |
| `to_number` | 1 | Parse a value as a number, or nil when it is not numeric. |
| `clone` | 1 | Deep copy of an array or map. Other values are returned unchanged. |
| `assert` | 1-2 | Fail the program when a condition is not truthy. |
| `assert_eq` | 2-3 | Fail unless two values are equal, showing both when they are not. |
| `panic` | 1 | Stop the program immediately with a message. |
| `exit` | 0-1 | Exit the program with a status code (default 0). |
## Methods on values
### On any value
| Method | Arguments | Description |
| --- | --- | --- |
| `to_string` | 0 | Text form of this value. |
| `inspect` | 0 | Developer-facing form, with quotes. |
| `type_of` | 0 | Name of this value's type. |
### On a string
| Method | Arguments | Description |
| --- | --- | --- |
| `length` | 0 | Number of characters. |
| `is_empty` | 0 | True when the string has no characters. |
| `upper` | 0 | Uppercase copy. |
| `lower` | 0 | Lowercase copy. |
| `trim` | 0 | Copy without leading or trailing whitespace. |
| `trim_start` | 0 | Copy without leading whitespace. |
| `trim_end` | 0 | Copy without trailing whitespace. |
| `contains` | 1 | True when the string contains a substring. |
| `starts_with` | 1 | True when the string starts with a prefix. |
| `ends_with` | 1 | True when the string ends with a suffix. |
| `index_of` | 1 | First index of a substring, or -1. |
| `split` | 0-1 | Split into an array on a separator. |
| `lines` | 0 | Split into an array of lines. |
| `chars` | 0 | Array of single-character strings. |
| `replace` | 2 | Replace the first occurrence. |
| `replace_all` | 2 | Replace every occurrence. |
| `slice` | 1-2 | Substring from start (inclusive) to end (exclusive). |
| `repeat` | 1 | Repeat the string n times. |
| `pad_start` | 1-2 | Pad on the left to a target width. |
| `pad_end` | 1-2 | Pad on the right to a target width. |
| `reverse` | 0 | Reversed copy. |
| `to_number` | 0 | Parse as a number, or nil when it isn't one. |
### On a array
| Method | Arguments | Description |
| --- | --- | --- |
| `length` | 0 | Number of items. |
| `is_empty` | 0 | True when there are no items. |
| `push` | 1+ | Append items; returns the array. |
| `pop` | 0 | Remove and return the last item, or nil. |
| `shift` | 0 | Remove and return the first item, or nil. |
| `unshift` | 1+ | Insert items at the front. |
| `insert` | 2 | Insert a value at an index. |
| `remove` | 1 | Remove the item at an index and return it. |
| `clear` | 0 | Remove every item. |
| `contains` | 1 | True when a value is present. |
| `index_of` | 1 | First index of a value, or -1. |
| `first` | 0 | First item, or nil. |
| `last` | 0 | Last item, or nil. |
| `slice` | 1-2 | Sub-array from start (inclusive) to end (exclusive). |
| `concat` | 1 | New array with another array appended. |
| `join` | 0-1 | Join items into a string. |
| `reverse` | 0 | Reversed copy. |
| `map` | 1 | New array with fn applied to each item. |
| `filter` | 1 | New array of items where fn is truthy. |
| `reduce` | 2 | Fold the array into a single value. |
| `for_each` | 1 | Call fn with each item. |
| `find` | 1 | First item where fn is truthy, or nil. |
| `any` | 1 | True when fn is truthy for any item. |
| `all` | 1 | True when fn is truthy for every item. |
| `count` | 0-1 | Count items, optionally matching fn. |
| `sort` | 0-1 | Sorted copy; pass fn(a, b) for a custom order. |
| `unique` | 0 | Copy with duplicates removed, keeping first occurrences. |
| `flatten` | 0 | Concatenate nested arrays one level deep. |
| `sum` | 0 | Add every item; all items must be numbers. |
### On a map
| Method | Arguments | Description |
| --- | --- | --- |
| `length` | 0 | Number of entries. |
| `is_empty` | 0 | True when there are no entries. |
| `get` | 1-2 | Value for a key, or a fallback (default nil). |
| `expect` | 1 | Value for a key; fails when the key is missing. |
| `set` | 2 | Insert or replace a key; returns the map. |
| `has` | 1 | True when the key is present. |
| `remove` | 1 | Remove a key; returns the removed value or nil. |
| `clear` | 0 | Remove every entry. |
| `keys` | 0 | Array of keys, in insertion order. |
| `values` | 0 | Array of values, in insertion order. |
| `entries` | 0 | Array of [key, value] pairs. |
| `merge` | 1 | New map with another map's entries layered on top. |
| `for_each` | 1 | Call fn with each key and value. |
### On a range
| Method | Arguments | Description |
| --- | --- | --- |
| `length` | 0 | How many values the range yields. |
| `start` | 0 | First value. |
| `end` | 0 | Bound value. |
| `is_empty` | 0 | True when the range yields nothing. |
| `contains` | 1 | True when a number falls inside the range. |
| `to_array` | 0 | Materialise the range as an array. |
### On a number
| Method | Arguments | Description |
| --- | --- | --- |
| `abs` | 0 | Absolute value. |
| `floor` | 0 | Round down. |
| `ceil` | 0 | Round up. |
| `round` | 0 | Round to the nearest whole number. |
| `is_whole` | 0 | True when the number has no fractional part. |
| `to_fixed` | 1 | Text with a fixed number of decimal places. |
| `clamp` | 2 | Constrain between a low and high bound. |
## Standard library
9 modules. Import with `import `, or a few names with `import { a, b } from `.
| Module | Contents | Web | Native |
| --- | --- | --- | --- |
| `wool` | Text: formatting, casing, wrapping, bytes. | yes | yes |
| `flock` | Collections: grouping, chunking, zipping, building maps. | yes | yes |
| `ram` | Arithmetic: rounding, integer division, statistics, constants. | yes | yes |
| `meadow` | Time and chance: clocks, calendars, seeded randomness. | yes | yes |
| `pasture` | Files and paths: reading, writing, listing, joining. | yes | yes |
| `shepherd` | The outside world: arguments, environment, stdin, subprocesses. | yes | yes |
| `lamb` | Data: JSON encoding and decoding. | yes | yes |
| `gate` | The web: reading a request and writing a reply, over CGI. | yes | no |
| `barn` | Native windows: controls, layout and events. Needs the native runtime. | no | yes |
`wool`'s five pattern functions (`matches`, `find`, `find_all`, `substitute`, `split_on`) need a regular-expression engine and are unavailable in native applications; they report that when called. Everything else in `wool` works in both.
`meadow.parse_iso` reads a date-only string, or a date-time carrying `Z` or an offset, identically on both targets. A date-time with neither (`2026-08-18T09:30`) means *local* time on the web target and is a `BAA301` error in a native application, because the same program would otherwise mean a different instant on a different machine. Always write the zone.
### `wool`
| Function | Arguments | Description |
| --- | --- | --- |
| `wool.join` | 1-2 | Join an array of values into a string. |
| `wool.concat` | 0+ | Concatenate every argument as text. |
| `wool.format` | 1+ | Fill `%s` placeholders in order: `wool.format("%s of %s", 3, 10)`. `%%` is a literal percent. |
| `wool.repeat` | 2 | Repeat a string n times. |
| `wool.title_case` | 1 | Capitalise the first letter of each word. |
| `wool.snake_case` | 1 | Convert text to snake_case. |
| `wool.camel_case` | 1 | Convert text to camelCase. |
| `wool.kebab_case` | 1 | Convert text to kebab-case. |
| `wool.wrap` | 2 | Wrap text to a maximum line width, breaking on spaces. |
| `wool.center` | 2-3 | Centre text within a width. |
| `wool.escape_html` | 1 | Escape text so it is safe inside HTML or an attribute. |
| `wool.safe_url` | 1 | A URL if its scheme is safe to link to, otherwise nil. |
| `wool.percent_encode` | 1 | Percent-encode text for use in a URL. |
| `wool.percent_decode` | 1 | Decode percent-encoded text, or nil when it is malformed. |
| `wool.matches` | 2-3 | True when a pattern matches anywhere in the text. |
| `wool.find` | 2-3 | First match as a map of match, start, end and groups, or nil. |
| `wool.find_all` | 2-3 | Every non-overlapping match, as an array of maps. |
| `wool.substitute` | 3-4 | Replace every match. `$1` in the replacement is a group. |
| `wool.split_on` | 2-3 | Split text on every match of a pattern. |
| `wool.is_blank` | 1 | True when a string is empty or only whitespace. |
| `wool.to_bytes` | 1 | UTF-8 byte values of a string. |
| `wool.from_bytes` | 1 | Build a string from an array of UTF-8 byte values. |
| `wool.inspect` | 1 | Developer-facing text for any value. |
### `flock`
| Function | Arguments | Description |
| --- | --- | --- |
| `flock.of` | 0+ | Build an array from the arguments. |
| `flock.repeat` | 2 | An array with the same value repeated n times. |
| `flock.zip` | 2 | Pair up two arrays, stopping at the shorter one. |
| `flock.chunk` | 2 | Split an array into chunks of a fixed size. |
| `flock.group_by` | 2 | Group items into a map keyed by fn(item). |
| `flock.partition` | 2 | Split into [matching, rest] using a predicate. |
| `flock.sort_by` | 2 | Sorted copy, ordered by the key fn(item) returns. |
| `flock.min_by` | 2 | Item with the smallest fn(item), or nil when empty. |
| `flock.max_by` | 2 | Item with the largest fn(item), or nil when empty. |
| `flock.to_map` | 1 | Build a map from an array of [key, value] pairs. |
| `flock.from_keys` | 2 | Build a map giving every key the same value. |
| `flock.invert` | 1 | Swap a map's keys and values. |
| `flock.range` | 1-3 | An array of numbers: range(end), range(start, end[, step]). |
| `flock.to_array` | 1 | Turn a range, string or map into an array. |
| `flock.union` | 2 | Everything in either array, first-seen order, no repeats. |
| `flock.intersect` | 2 | Everything in both arrays, in the first array's order. |
| `flock.difference` | 2 | Everything in the first array and not the second. |
| `flock.is_subset` | 2 | True when every item of the first array is in the second. |
### `ram`
| Constant | Value |
| --- | --- |
| `ram.PI` | 3.141592653589793 |
| `ram.E` | 2.718281828459045 |
| `ram.TAU` | 6.283185307179586 |
| `ram.INF` | inf |
| `ram.NAN` | nan |
| `ram.EPSILON` | 2.220446049250313e-16 |
| `ram.MAX_SAFE_WHOLE` | 9007199254740991 |
| Function | Arguments | Description |
| --- | --- | --- |
| `ram.abs` | 1 | Absolute value. |
| `ram.sign` | 1 | -1, 0 or 1. |
| `ram.floor` | 1 | Round down. |
| `ram.ceil` | 1 | Round up. |
| `ram.trunc` | 1 | Drop the fractional part. |
| `ram.round` | 1-2 | Round to the nearest whole number, or to n decimal places. |
| `ram.sqrt` | 1 | Square root. |
| `ram.pow` | 2 | Raise to a power. |
| `ram.exp` | 1 | e raised to a power. |
| `ram.log` | 1-2 | Natural logarithm, or logarithm in a given base. |
| `ram.sin` | 1 | Sine, in radians. |
| `ram.cos` | 1 | Cosine, in radians. |
| `ram.tan` | 1 | Tangent, in radians. |
| `ram.atan2` | 2 | Angle of the vector (x, y), in radians. |
| `ram.hypot` | 2 | Length of the vector (x, y). |
| `ram.min` | 1+ | Smallest of the arguments. |
| `ram.max` | 1+ | Largest of the arguments. |
| `ram.clamp` | 3 | Constrain a value between low and high. |
| `ram.lerp` | 3 | Linear interpolation between a and b. |
| `ram.idiv` | 2 | Integer division, rounding toward negative infinity. |
| `ram.modulo` | 2 | Remainder that always takes the sign of the divisor. |
| `ram.gcd` | 2 | Greatest common divisor of two whole numbers. |
| `ram.is_nan` | 1 | True when the value is not a number. |
| `ram.is_finite` | 1 | True when the value is a finite number. |
| `ram.is_whole` | 1 | True when the value is a whole number. |
| `ram.sum` | 1 | Add every number in an array. |
| `ram.mean` | 1 | Arithmetic mean of an array, or nil when empty. |
| `ram.median` | 1 | Median of an array, or nil when empty. |
| `ram.to_binary` | 1 | Binary text for a whole number. |
| `ram.to_hex` | 1 | Hexadecimal text for a whole number. |
| `ram.parse` | 1-2 | Parse text as a number in a given base (default 10). |
### `meadow`
| Function | Arguments | Description |
| --- | --- | --- |
| `meadow.now` | 0 | Milliseconds since 1970-01-01 UTC. |
| `meadow.clock` | 0 | High-resolution milliseconds, for measuring durations. |
| `meadow.parts` | 0-2 | Break a timestamp into calendar parts (UTC, or at an offset). |
| `meadow.format` | 1-2 | Format a timestamp as YYYY-MM-DD or with a pattern. |
| `meadow.iso` | 0-2 | ISO-8601 text for a timestamp (default: now, UTC). |
| `meadow.duration` | 1 | Break a length of time in milliseconds into parts. |
| `meadow.format_duration` | 1 | A length of time as `1d 2h 3m 4s`. |
| `meadow.parse_iso` | 1 | Parse ISO-8601 text into a timestamp, or nil. |
| `meadow.random` | 0 | A random number in [0, 1). |
| `meadow.random_int` | 2 | A random whole number between low and high, inclusive. |
| `meadow.pick` | 1 | A random item from an array or range, or nil when empty. |
| `meadow.shuffle` | 1 | A shuffled copy of an array. |
| `meadow.sample` | 2 | n random items from an array, without repeats. |
### `pasture`
| Constant | Value |
| --- | --- |
| `pasture.SEPARATOR` | \ |
| Function | Arguments | Description |
| --- | --- | --- |
| `pasture.read` | 1 | Read a whole text file as a string. |
| `pasture.read_lines` | 1 | Read a text file and split it into lines. |
| `pasture.write` | 2 | Write text to a file, replacing anything already there. |
| `pasture.append` | 2 | Append text to a file, creating it when missing. |
| `pasture.write_lines` | 2 | Write an array of lines to a file. |
| `pasture.exists` | 1 | True when a file or directory exists. |
| `pasture.list` | 1 | Names inside a directory. |
| `pasture.make_dir` | 1 | Create a directory, including any missing parents. |
| `pasture.info` | 1 | Size, kind and modification time of a path, or nil. |
| `pasture.join` | 1+ | Join path segments with the platform separator. |
| `pasture.resolve` | 1+ | Turn path segments into one absolute path. |
| `pasture.dir_name` | 1 | The directory part of a path. |
| `pasture.base_name` | 1-2 | The final component of a path, optionally without a suffix. |
| `pasture.extension` | 1 | The file extension, including the dot. |
| `pasture.normalise` | 1 | Collapse `.` and `..` segments. |
| `pasture.relative_to` | 2 | The path from one location to another. |
| `pasture.is_absolute` | 1 | True when a path is absolute. |
| `pasture.cwd` | 0 | The current working directory. |
| `pasture.walk` | 1-2 | Every file under a directory, recursively, sorted. |
| `pasture.glob` | 2 | Files under a directory whose path matches a glob pattern. |
| `pasture.matches` | 2 | True when a path matches a glob pattern. |
### `shepherd`
| Constant | Value |
| --- | --- |
| `shepherd.PLATFORM` | win32 |
| `shepherd.ARCH` | x64 |
| Function | Arguments | Description |
| --- | --- | --- |
| `shepherd.args` | 0 | Arguments passed to the Baa program after `--`. |
| `shepherd.env` | 1-2 | An environment variable, or a fallback when it is unset. |
| `shepherd.env_all` | 0 | Every environment variable as a map. |
| `shepherd.write` | 1+ | Write to stdout without a trailing newline. |
| `shepherd.write_error` | 1+ | Write to stderr without a trailing newline. |
| `shepherd.input` | 0-1 | Read one line from stdin, or nil at end of input. |
| `shepherd.read_all` | 0 | Read all of stdin as a single string. |
| `shepherd.run` | 1-3 | Run a program with an explicit argument array. Never uses a shell. |
| `shepherd.exit` | 0-1 | Exit with a status code (default 0). |
### `lamb`
| Function | Arguments | Description |
| --- | --- | --- |
| `lamb.encode` | 1-2 | JSON text for a value; pass an indent for pretty output. |
| `lamb.decode` | 1 | Parse JSON text into Baa values. |
| `lamb.try_decode` | 1-2 | Parse JSON text, or return a fallback (default nil). |
| `lamb.is_valid` | 1 | True when a string parses as JSON. |
### `gate`
| Function | Arguments | Description |
| --- | --- | --- |
| `gate.method` | 0 | The request method, uppercase. Defaults to GET. |
| `gate.path` | 0 | The path below the script, or "/". |
| `gate.query` | 0 | The query string parsed into a map. |
| `gate.query_string` | 0 | The raw, undecoded query string. |
| `gate.body` | 0 | The request body as text. |
| `gate.form` | 0 | A urlencoded request body parsed into a map. |
| `gate.header` | 1-2 | A request header, or a fallback when it is absent. |
| `gate.headers` | 0 | Every request header as a map, in Header-Case. |
| `gate.cookies` | 0 | The Cookie header parsed into a map. |
| `gate.status` | 1 | Set the status code. Must come before the reply starts. |
| `gate.set_header` | 2 | Set a response header. Must come before the reply starts. |
| `gate.text` | 1 | Reply with plain text. |
| `gate.html` | 1 | Reply with HTML, exactly as given. Escape values yourself. |
| `gate.fill` | 1+ | Reply with HTML, escaping each value put into a `%s`. The safe way to build a page. |
| `gate.json` | 1 | Reply with a value encoded as JSON. |
| `gate.redirect` | 1-2 | Reply with a redirect (303 by default). |
| `gate.escape` | 1 | Escape a value for HTML. Same as `wool.escape_html`. |
| `gate.safe_url` | 1-2 | A URL if its scheme is safe to link to, else a fallback (default "#"). |
| `gate.format` | 1+ | Build HTML, escaping each value put into a `%s`, without sending it. |
### `barn`
| Function | Arguments | Description |
| --- | --- | --- |
| `barn.window` | 0-1 | Create a window. Options: title, width, height, padding, spacing. |
| `barn.row` | 1-2 | A container that lays its children out left to right. |
| `barn.column` | 1-2 | A container that lays its children out top to bottom. |
| `barn.label` | 1-2 | Text that cannot be edited. |
| `barn.button` | 1-2 | A push button. |
| `barn.input` | 1-2 | A single-line text field. |
| `barn.text_area` | 1-2 | A multi-line text editor with scrollbars. |
| `barn.list` | 1-2 | A list of selectable rows. |
| `barn.checkbox` | 1-2 | A checkbox. |
| `barn.spacer` | 1-2 | Empty space that takes a share of the layout. |
| `barn.menu` | 2 | A menu on the window's menu bar. |
| `barn.item` | 2-3 | An entry in a menu. Fires `click`. |
| `barn.separator` | 1 | A dividing line in a menu. |
| `barn.on` | 3 | Register a handler: "click", "change", "select", "toggle" or "close". |
| `barn.text` | 1 | The widget's current text. |
| `barn.set_text` | 2 | Replace the widget's text. |
| `barn.items` | 1 | A list's rows, as an array of strings. |
| `barn.set_items` | 2 | Replace a list's rows. |
| `barn.selected` | 1 | The selected row's index, or -1. |
| `barn.select` | 2 | Select a row by index. |
| `barn.checked` | 1 | Whether a checkbox is ticked. |
| `barn.set_checked` | 2 | Tick or untick a checkbox. |
| `barn.enable` | 2 | Enable or disable a widget. |
| `barn.focus` | 1 | Give a widget keyboard focus. |
| `barn.title` | 2 | Set a window's title. |
| `barn.show` | 1 | Put a window on screen. |
| `barn.run` | 0 | Run the event loop until every window has closed. |
| `barn.close` | 1 | Close a window. |
| `barn.quit` | 0 | Close every window, ending the event loop. |
| `barn.alert` | 2-3 | Show a message box. |
| `barn.confirm` | 2-3 | Ask a yes/no question. Returns true for yes. |
| `barn.open_file` | 0-2 | Ask for a file to open. Returns a path, or nil if cancelled. |
| `barn.save_file` | 0-2 | Ask where to save. Returns a path, or nil if cancelled. |
| `barn.every` | 2 | Call a function every n milliseconds. Returns a timer id. |
| `barn.after` | 2 | Call a function once, n milliseconds from now. Returns a timer id. |
| `barn.cancel` | 1 | Stop a timer, by the id `every` or `after` returned. |
| `barn.clipboard` | 0 | The clipboard's text, or nil. |
| `barn.set_clipboard` | 1 | Put text on the clipboard. |
## Worked examples
### A module, and its tests
`basket.baa`:
```baa
/// A module: imports neither `gate` nor `barn`, so a web page and a native
/// application can both use it, and `baa test` can test it with no window and
/// no server involved. Put anything that can be wrong here.
export fn total(items) {
let sum = 0
for item in items {
sum += item.price * item.quantity
}
return sum
}
```
`tests/basket_test.baa`, run with `baa test`:
```baa
import "../basket.baa" as basket
test "adds up a basket" {
const items = [{ price: 2, quantity: 3 }, { price: 5, quantity: 1 }]
assert_eq(basket.total(items), 11)
}
test "an empty basket costs nothing" {
assert_eq(basket.total([]), 0)
}
```
### A web page
Runs under CGI: one process per request, no shared state between requests, and no JavaScript required on the page. Serve a directory with `baa serve `.
```baa
#!/usr/bin/env baa
/// A web page. Runs under CGI: one process per request, writing one reply.
import gate
const name = gate.query("name") ?? "world"
// Concatenate markup, and escape at each value. `gate.format` escapes what it
// interpolates, so passing markup through it renders the tags as text.
gate.html(
"Hello" +
"Baa, " + gate.escape(name) + "
" +
"",
)
```
Escaping rule: `gate.escape` every value that came from a request. `gate.format` escapes what it interpolates, so never pass markup through it: build markup by concatenation and escape at each value. `gate.safe_url` before putting a URL in an `href`, because `javascript:` survives HTML escaping unchanged.
### A native application
Windows only today. The window model is platform-independent but only a Win32 backend exists; on any other platform `barn.show` reports that there is no backend. Build with `baa app build`, which produces one executable needing no Node.js.
```baa
/// A native application. Build with `baa app build`; run with `baa app run`.
/// `baa run` cannot show a window and will say so.
import barn
let count = 0
const window = barn.window({ title: "Counter", width: 320, height: 160 })
const layout = barn.column(window, { weight: 1, spacing: 12 })
const label = barn.label(layout, { text: "0", align: "center", size: 22, weight: 1 })
const button = barn.button(layout, { text: "More" })
fn on_click() {
count += 1
barn.set_text(label, to_string(count))
}
barn.on(button, "click", on_click)
barn.show(window)
barn.run()
```
Build the whole widget tree before `barn.show`. Handlers run between events, so a handler may do anything, including opening a dialog or closing the window. `barn.text(widget)` reads what the person typed; compare before calling `barn.set_text` on a text area, or the caret jumps to the start on every keystroke.
## Commands
| Command | Purpose |
| --- | --- |
| `baa run [file]` | Execute a program, or the project entry point |
| `baa ` | The same, without saying `run`. What a shebang uses |
| `baa check [paths]` | Parse and analyse without running. The fastest way to validate |
| `baa test [paths]` | Run `test "..." { ... }` blocks |
| `baa fmt [paths]` | Format in place; `--check` in CI |
| `baa lint [paths]` | Warnings; `--deny-warnings` in CI |
| `baa serve [dir]` | Serve a directory of pages over HTTP, for development |
| `baa app new|build|run|test` | Native applications |
| `baa repl` | Interactive session |
| `baa init [dir]` | Create a project |
| `baa doctor` | Check the installation |
Exit codes: `0` success, `1` the program failed or a check found errors, `2` the command line was wrong, `70` an internal error. `CI=true` or `--no-baa` swaps the sheep wording for neutral wording, keeping every code identical.
## Diagnostics
Every error has a stable code. 48 in total; the ranges are what matter when reading one.
| Range | Meaning |
| --- | --- |
| `BAA0xx` | Lexical and syntax errors: the shape of the source is wrong |
| `BAA1xx` | Names and scope |
| `BAA2xx` | Calls, arity, and static shape |
| `BAA3xx` | Runtime |
| `BAA4xx` | Modules, project and CLI |
| `BAA9xx` | Lints, which are warnings and never fatal |
The ones most often hit while writing new code:
| Code | Meaning |
| --- | --- |
| `BAA102` | Undefined name `{0}`. |
| `BAA201` | `{0}` expects {1} argument(s) but received {2}. |
| `BAA202` | `{0}` expects {1} argument(s) but received {2}. |
| `BAA302` | Unsupported operand types for {0}: {1} and {2}. |
| `BAA304` | Index {0} out of range for {1} of length {2}. |
| `BAA305` | `{1}` is not a property of {0}. |
| `BAA306` | Division by zero. |
| `BAA309` | Cannot iterate over {0}. |
| `BAA311` | `{0}`: argument {2} must be {1}, received {3}. |
Full catalogue: https://sheep.grimtech.co.uk/docs/errors.html
---
Generated from the implementation at version 0.8.0. If something here disagrees with the compiler, the compiler is right and it is a bug: https://github.com/PatrickJnr/sheep/issues