# 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