aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/README.md78
-rw-r--r--docs/arrays.md797
-rw-r--r--docs/booleans.md65
-rw-r--r--docs/channels.md181
-rw-r--r--docs/enums.md88
-rw-r--r--docs/integers.md368
-rw-r--r--docs/nums.md1374
-rw-r--r--docs/pointers.md133
-rw-r--r--docs/ranges.md65
-rw-r--r--docs/sets.md356
-rw-r--r--docs/structs.md39
-rw-r--r--docs/tables.md294
-rw-r--r--docs/text.md778
-rw-r--r--docs/threads.md111
14 files changed, 4727 insertions, 0 deletions
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 00000000..55bc63ba
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,78 @@
+# Documentation
+
+This is an overview of the documentation on Tomo.
+
+## Topics
+
+A few topics that are documented:
+
+- [Compilation Pipeline](compilation.md)
+- [Libraries/Modules](libraries.md)
+- [Special Methods](metamethods.md)
+- [Namespacing](namespacing.md)
+- [Operator Overloading](operators.md)
+
+## Types
+
+Information about Tomo's built-in types can be found here:
+
+- [Arrays](arrays.md)
+- [Booleans](booleans.md)
+- [Channels](channels.md)
+- [Enums](enums.md)
+- [Floating point numbers](nums.md)
+- [Integer Ranges](ranges.md)
+- [Integers](integers.md)
+- [Sets](sets.md)
+- [Structs](structs.md)
+- [Tables](tables.md)
+- [Text](text.md)
+- [Threads](threads.md)
+
+## Built-in Functions
+
+### `say`
+
+**Description:**
+Prints a message to the console.
+
+**Usage:**
+```markdown
+say(text:Text) -> Void
+```
+
+**Parameters:**
+
+- `text`: The text to print.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+say("Hello world!")
+```
+
+---
+
+### `fail`
+
+**Description:**
+Prints a message to the console, aborts the program, and prints a stack trace.
+
+**Usage:**
+```markdown
+fail(message:Text) -> Abort
+```
+
+**Parameters:**
+
+- `message`: The error message to print.
+
+**Returns:**
+Nothing, aborts the program.
+
+**Example:**
+```markdown
+fail("Oh no!")
+```
diff --git a/docs/arrays.md b/docs/arrays.md
new file mode 100644
index 00000000..0453feb6
--- /dev/null
+++ b/docs/arrays.md
@@ -0,0 +1,797 @@
+# Arrays
+
+Tomo supports arrays as a container type that holds a list of elements of any
+type in a compact format. Arrays are immutable by default, but use
+copy-on-write semantics to efficiently mutate in place when possible. **Arrays
+are 1-indexed**, which means the first item in the array has index `1`.
+
+## Syntax
+
+Arrays are written using square brackets and a list of comma-separated elements:
+
+```tomo
+nums := [10, 20, 30]
+```
+
+Each element must have the same type (or be easily promoted to the same type). If
+you want to have an empty array, you must specify what type goes inside the array
+like this:
+
+```tomo
+empty := [:Int]
+```
+
+For type annotations, an array that holds items with type `T` is written as `[T]`.
+
+### Array Comprehensions
+
+Arrays can also use comprehensions, where you specify how to dynamically create
+all the elements by iteration instead of manually specifying each:
+
+```tomo
+>> [i*10 for i in 3:to(8)]
+= [30, 40, 50, 60, 70, 80]
+>> [i*10 for i in 3:to(8) if i != 4]
+= [30, 50, 60, 70, 80]
+```
+
+Comprehensions can be combined with regular items or other comprehensions:
+
+```tomo
+>> [-1, i*10 for i in 3:to(8), i for i in 3]
+= [-1, 30, 40, 50, 60, 70, 80, 1, 2, 3]
+```
+
+## Length
+
+Array length can be accessed by the `.length` field:
+
+```tomo
+>> [10, 20, 30].length
+= 3
+```
+
+## Indexing
+
+Array values are accessed using square bracket indexing. Since arrays are
+1-indexed, the index `1` corresponds to the first item in the array. Negative
+indices are used to refer to items from the back of the array, so `-1` is the
+last item, `-2` is the second-to-last, and so on.
+
+```tomo
+arr := [10, 20, 30, 40]
+>> arr[1]
+= 10
+
+>> arr[2]
+= 20
+
+>> arr[-1]
+= 40
+
+>> arr[-2]
+= 30
+```
+
+If an array index of `0` or any value larger than the length of the array is
+used, it will trigger a runtime error that will print what the invalid array
+index was, the length of the array, and a stack trace. As a performance
+operation, if array bounds checking proves to be a performance hot spot, you
+can explicitly disable bounds checking by adding `arr[i; unchecked]` to the
+array access.
+
+## Iteration
+
+You can iterate over the items in an array like this:
+
+```tomo
+for item in array:
+ ...
+
+for i, item in array:
+ ...
+```
+
+Array iteration operates over the value of the array when the loop began, so
+modifying the array during iteration is safe and will not result in the loop
+iterating over any of the new values.
+
+## Concatenation
+
+Arrays can be concatenated with the `++` operator, which returns an array that
+has the items from one appended to the other. This should not be confused with
+the addition operator `+`, which does not work with arrays.
+
+```tomo
+>> [1, 2] ++ [3, 4]
+= [1, 2, 3, 4]
+```
+
+## Array Methods
+
+### `binary_search`
+
+**Description:**
+Performs a binary search on a sorted array.
+
+**Usage:**
+```markdown
+binary_search(arr: [T], by=T.compare) -> Int
+```
+
+**Parameters:**
+
+- `arr`: The sorted array to search.
+- `by`: The comparison function used to determine order. If not specified, the
+ default comparison function for the item type will be used.
+
+**Returns:**
+Assuming the input array is sorted according to the given comparison function,
+return the index where the given item would be inserted to maintain the sorted
+order.
+
+**Example:**
+```markdown
+>> [1, 3, 5, 7, 9]:binary_search(5)
+= 3
+
+>> [1, 3, 5, 7, 9]:binary_search(-999)
+= 1
+
+>> [1, 3, 5, 7, 9]:binary_search(999)
+= 6
+```
+
+---
+
+### `by`
+
+**Description:**
+Creates a new array with elements spaced by the specified step value.
+
+**Usage:**
+```markdown
+by(arr: [T], step: Int) -> [T]
+```
+
+**Parameters:**
+
+- `arr`: The original array.
+- `step`: The step value for selecting elements.
+
+**Returns:**
+A new array with every `step`-th element from the original array.
+
+**Example:**
+```markdown
+>> [1, 2, 3, 4, 5, 6]:by(2)
+= [1, 3, 5]
+```
+
+---
+
+### `clear`
+
+**Description:**
+Clears all elements from the array.
+
+**Usage:**
+```markdown
+clear(arr: & [T]) -> Void
+```
+
+**Parameters:**
+
+- `arr`: The mutable reference to the array to be cleared.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+>> my_array:clear()
+```
+
+---
+
+### `counts`
+
+**Description:**
+Counts the occurrences of each element in the array.
+
+**Usage:**
+```markdown
+counts(arr: [T]) -> {T: Int}
+```
+
+**Parameters:**
+
+- `arr`: The array to count elements in.
+
+**Returns:**
+A table mapping each element to its count.
+
+**Example:**
+```markdown
+>> [10, 20, 30, 30, 30]:counts()
+= {10: 1, 20: 1, 30: 3}
+```
+
+---
+
+### `find`
+
+**Description:**
+Finds the index of the first occurrence of an element.
+
+**Usage:**
+```markdown
+find(arr: [T]) -> Int
+```
+
+**Parameters:**
+
+- `arr`: The array to search through.
+
+**Returns:**
+The index of the first occurrence or `0` if not found.
+
+**Example:**
+```markdown
+>> [10, 20, 30, 40, 50]:find(20)
+= 2
+
+>> [10, 20, 30, 40, 50]:find(9999)
+= 0
+```
+
+---
+
+### `first`
+
+**Description:**
+Find the first item that matches a predicate function.
+
+**Usage:**
+```markdown
+first(arr: [T], predicate: func(item:&T)->Bool) -> Int
+```
+
+**Parameters:**
+
+- `arr`: The array to search through.
+- `predicate`: A function that returns `yes` if the item should be returned or
+ `no` if it should not.
+
+**Returns:**
+Returns a pointer to the first item that matches the given predicate, or null
+if no match is found.
+
+**Example:**
+```markdown
+when nums:find(func(i:&Int): i:is_prime()) is @prime:
+ say("Got a prime: $prime")
+else:
+ say("No primes")
+```
+
+---
+
+### `from`
+
+**Description:**
+Returns a slice of the array starting from a specified index.
+
+**Usage:**
+```markdown
+from(arr: [T], first: Int) -> [T]
+```
+
+**Parameters:**
+
+- `arr`: The original array.
+- `first`: The index to start from.
+
+**Returns:**
+A new array starting from the specified index.
+
+**Example:**
+```markdown
+>> [10, 20, 30, 40, 50]:from(3)
+= [30, 40, 50]
+```
+
+---
+
+### `has`
+
+**Description:**
+Checks if the array has any elements.
+
+**Usage:**
+```markdown
+has(arr: [T]) -> Bool
+```
+
+**Parameters:**
+
+- `arr`: The array to check.
+
+**Returns:**
+`yes` if the array has elements, `no` otherwise.
+
+**Example:**
+```markdown
+>> [10, 20, 30]:has(20)
+= yes
+```
+
+---
+
+### `heap_pop`
+
+**Description:**
+Removes and returns the top element of a heap. By default, this is the
+*minimum* value in the heap.
+
+**Usage:**
+```markdown
+heap_pop(arr: & [T], by=T.compare) -> T
+```
+
+**Parameters:**
+
+- `arr`: The mutable reference to the heap.
+- `by`: The comparison function used to determine order. If not specified, the
+ default comparison function for the item type will be used.
+
+**Returns:**
+The removed top element of the heap.
+
+**Example:**
+```markdown
+>> my_heap := [30, 10, 20]
+>> my_heap:heapify()
+>> my_heap:heap_pop()
+= 10
+```
+
+---
+
+### `heap_push`
+
+**Description:**
+Adds an element to the heap and maintains the heap property. By default, this
+is a *minimum* heap.
+
+**Usage:**
+```markdown
+heap_push(arr: & [T], item: T, by=T.compare) -> Void
+```
+
+**Parameters:**
+
+- `arr`: The mutable reference to the heap.
+- `item`: The item to be added.
+- `by`: The comparison function used to determine order. If not specified, the
+ default comparison function for the item type will be used.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+>> my_heap:heap_push(10)
+```
+
+---
+
+### `heapify`
+
+**Description:**
+Converts an array into a heap.
+
+**Usage:**
+```markdown
+heapify(arr: & [T], by=T.compare) -> Void
+```
+
+**Parameters:**
+
+- `arr`: The mutable reference to the array to be heapified.
+- `by`: The comparison function used to determine order. If not specified, the
+ default comparison function for the item type will be used.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+>> my_heap := [30, 10, 20]
+>> my_heap:heapify()
+```
+
+---
+
+### `insert`
+
+**Description:**
+Inserts an element at a specified position in the array.
+
+**Usage:**
+```markdown
+insert(arr: & [T], item: T, at: Int = 0) -> Void
+```
+
+**Parameters:**
+
+- `arr`: The mutable reference to the array.
+- `item`: The item to be inserted.
+- `at`: The index at which to insert the item (default is `0`). Since indices
+ are 1-indexed and negative indices mean "starting from the back", an index of
+ `0` means "after the last item".
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+>> arr := [10, 20]
+>> arr:insert(30)
+>> arr
+= [10, 20, 30]
+
+>> arr:insert(999, at=2)
+>> arr
+= [10, 999, 20, 30]
+```
+
+---
+
+### `insert_all`
+
+**Description:**
+Inserts an array of items at a specified position in the array.
+
+**Usage:**
+```markdown
+insert_all(arr: & [T], items: [T], at: Int = 0) -> Void
+```
+
+**Parameters:**
+
+- `arr`: The mutable reference to the array.
+- `items`: The items to be inserted.
+- `at`: The index at which to insert the item (default is `0`). Since indices
+ are 1-indexed and negative indices mean "starting from the back", an index of
+ `0` means "after the last item".
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+arr := [10, 20]
+arr:insert_all([30, 40])
+>> arr
+= [10, 20, 30, 40]
+
+arr:insert_all([99, 100], at=2)
+>> arr
+= [10, 99, 100, 20, 30, 40]
+```
+
+---
+
+### `random`
+
+**Description:**
+Selects a random element from the array.
+
+**Usage:**
+```markdown
+random(arr: [T]) -> T
+```
+
+**Parameters:**
+
+- `arr`: The array from which to select a random element.
+
+**Returns:**
+A random element from the array.
+
+**Example:**
+```markdown
+>> [10, 20, 30]:random()
+= 20
+```
+
+---
+
+### `remove_at`
+
+**Description:**
+Removes elements from the array starting at a specified index.
+
+**Usage:**
+```markdown
+remove_at(arr: & [T], at: Int = -1, count: Int = 1) -> Void
+```
+
+**Parameters:**
+
+- `arr`: The mutable reference to the array.
+- `at`: The index at which to start removing elements (default is `-1`, which means the end of the array).
+- `count`: The number of elements to remove (default is `1`).
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+arr := [10, 20, 30, 40, 50]
+arr:remove_at(2)
+>> arr
+= [10, 30, 40, 50]
+
+arr:remove_at(2, count=2)
+>> arr
+= [10, 50]
+```
+
+---
+
+### `remove_item`
+
+**Description:**
+Removes all occurrences of a specified item from the array.
+
+**Usage:**
+```markdown
+remove_item(arr: & [T], item: T, max_count: Int = -1) -> Void
+```
+
+**Parameters:**
+
+- `arr`: The mutable reference to the array.
+- `item`: The item to be removed.
+- `max_count`: The maximum number of occurrences to remove (default is `-1`, meaning all occurrences).
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+arr := [10, 20, 10, 20, 30]
+arr:remove_item(10)
+>> arr
+= [20, 20, 30]
+
+arr:remove_item(20, max_count=1)
+>> arr
+= [20, 30]
+```
+
+---
+
+### `reversed`
+
+**Description:**
+Returns a reversed slice of the array.
+
+**Usage:**
+```markdown
+reversed(arr: [T]) -> [T]
+```
+
+**Parameters:**
+
+- `arr`: The array to be reversed.
+
+**Returns:**
+A slice of the array with elements in reverse order.
+
+**Example:**
+```markdown
+>> [10, 20, 30]:reversed()
+= [30, 20, 10]
+```
+
+---
+
+### `sample`
+
+**Description:**
+Selects a sample of elements from the array, optionally with weighted
+probabilities.
+
+**Usage:**
+```markdown
+sample(arr: [T], count: Int, weights: [Num]) -> [T]
+```
+
+**Parameters:**
+
+- `arr`: The array to sample from.
+- `count`: The number of elements to sample.
+- `weights`: The probability weights for each element in the array. These
+ values do not need to add up to any particular number, they are relative
+ weights. If no weights are provided, the default is equal probabilities.
+ Negative, infinite, or NaN weights will cause a runtime error. If the number of
+ weights given is less than the length of the array, elements from the rest of
+ the array are considered to have zero weight.
+
+**Returns:**
+A list of sampled elements from the array.
+
+**Example:**
+```markdown
+>> [10, 20, 30]:sample(2, weights=[90%, 5%, 5%])
+= [10, 10]
+```
+
+---
+
+### `shuffle`
+
+**Description:**
+Shuffles the elements of the array in place.
+
+**Usage:**
+```markdown
+shuffle(arr: & [T]) -> Void
+```
+
+**Parameters:**
+
+- `arr`: The mutable reference to the array to be shuffled.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+>> arr:shuffle()
+```
+
+---
+
+### `shuffled`
+
+**Description:**
+Creates a new array with elements shuffled.
+
+**Usage:**
+```markdown
+shuffled(arr: [T]) -> [T]
+```
+
+**Parameters:**
+
+- `arr`: The array to be shuffled.
+
+**Returns:**
+A new array with shuffled elements.
+
+**Example:**
+```markdown
+>> [10, 20, 30, 40]:shuffled()
+= [40, 10, 30, 20]
+```
+
+---
+
+### `sort`
+
+**Description:**
+Sorts the elements of the array in place in ascending order (small to large).
+
+**Usage:**
+```markdown
+sort(arr: & [T], by=T.compare) -> Void
+```
+
+**Parameters:**
+
+- `arr`: The mutable reference to the array to be sorted.
+- `by`: The comparison function used to determine order. If not specified, the
+ default comparison function for the item type will be used.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+arr := [40, 10, -30, 20]
+arr:sort()
+>> arr
+= [-30, 10, 20, 40]
+
+arr:sort(func(a,b:&Int): a:abs() <> b:abs())
+>> arr
+= [10, 20, -30, 40]
+```
+
+---
+
+### `sorted`
+
+**Description:**
+Creates a new array with elements sorted.
+
+**Usage:**
+```markdown
+sorted(arr: [T], by=T.compare) -> [T]
+```
+
+**Parameters:**
+
+- `arr`: The array to be sorted.
+- `by`: The comparison function used to determine order. If not specified, the
+ default comparison function for the item type will be used.
+
+**Returns:**
+A new array with sorted elements.
+
+**Example:**
+```markdown
+>> [40, 10, -30, 20]:sorted()
+= [-30, 10, 20, 40]
+
+>> [40, 10, -30, 20]:sorted(func(a,b:&Int): a:abs() <> b:abs())
+= [10, 20, -30, 40]
+```
+
+---
+
+### `to`
+
+**Description:**
+Returns a slice of the array from the start of the original array up to a specified index (inclusive).
+
+**Usage:**
+```markdown
+to(arr: [T], last: Int) -> [T]
+```
+
+**Parameters:**
+
+- `arr`: The original array.
+- `last`: The index up to which elements should be included.
+
+**Returns:**
+A new array containing elements from the start up to the specified index.
+
+**Example:**
+```markdown
+>> [10, 20, 30, 40, 50]:to(3)
+= [10, 20, 30]
+
+>> [10, 20, 30, 40, 50]:to(-2)
+= [10, 20, 30, 40]
+```
+
+---
+
+### `unique`
+
+**Description:**
+Returns a Set that contains the unique elements of the array.
+
+**Usage:**
+```markdown
+unique(arr: [T]) -> {T}
+```
+
+**Parameters:**
+
+- `arr`: The array to process.
+
+**Returns:**
+A set containing only unique elements from the array.
+
+**Example:**
+```markdown
+>> [10, 20, 10, 10, 30]:unique()
+= {10, 20, 30}
+```
diff --git a/docs/booleans.md b/docs/booleans.md
new file mode 100644
index 00000000..7d2c29a4
--- /dev/null
+++ b/docs/booleans.md
@@ -0,0 +1,65 @@
+# Boolean Values
+
+Boolean values have the type `Bool` and can be either `yes` ("true") or `no`
+("false").
+
+# Boolean Functions
+
+This documentation provides details on boolean functions available in the API.
+
+## `from_text`
+
+**Description:**
+Converts a string representation of a boolean value into a boolean. Acceptable
+boolean values are case-insensitive variations of `yes`/`no`, `y`/`n`,
+`true`/`false`, `on`/`off`.
+
+**Usage:**
+```tomo
+from_text(text: Text, success: Bool = !&Bool) -> Bool
+```
+
+**Parameters:**
+
+- `text`: The string containing the boolean value.
+- `success`: If provided, this boolean value reference will be set to `yes` if the given text is a recognizable boolean value or `no` otherwise.
+
+**Returns:**
+`yes` if the string matches a recognized truthy boolean value; otherwise return `no`.
+
+**Example:**
+```tomo
+>> Bool.from_text("yes")
+= yes
+>> Bool.from_text("no")
+= no
+>> success := yes
+>> Bool.from_text("???", &success)
+= no
+>> success
+= no
+```
+
+---
+
+## `random`
+
+**Description:**
+Generates a random boolean value based on a specified probability.
+
+**Usage:**
+```tomo
+random(p: Float = 0.5) -> Bool
+```
+
+**Parameters:**
+
+- `p`: The probability (between `0` and `1`) of returning `yes`. Default is `0.5`.
+
+**Returns:**
+`yes` with probability `p`, and `no` with probability `1 - p`.
+
+**Example:**
+```tomo
+>> Bool.random(70%) // yes (with 70% probability)
+```
diff --git a/docs/channels.md b/docs/channels.md
new file mode 100644
index 00000000..88cb46ff
--- /dev/null
+++ b/docs/channels.md
@@ -0,0 +1,181 @@
+# Channels
+
+Channels are a thread-safe message queue for communicating between threads,
+although they can also be used as a general-purpose queue.
+
+## Syntax
+
+The syntax to create a channel is `|:T|`, where `T` is the type that will be
+passed through the channel. You can also specify a maximum size for the
+channel, which will cause giving to block until the recipient has gotten from
+the channel if the maximum size is reached.
+
+```tomo
+channel := |:Int|
+channel:give(10)
+channel:give(20)
+>> channel:get()
+= 10
+>> channel:get()
+= 20
+
+small_channel := |:Int; max_size=5|
+```
+
+## Channel Methods
+
+### `give`
+
+**Description:**
+Adds an item to the channel.
+
+**Usage:**
+```markdown
+give(channel:|T|, item: T, where: Where = Where.End) -> Void
+```
+
+**Parameters:**
+
+- `channel`: The channel to which the item will be added.
+- `item`: The item to add to the channel.
+- `where`: Where to put the item (at the `Start` or `End` of the queue).
+ `Anywhere` defaults to `End`.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+>> channel:give("Hello")
+```
+
+---
+
+### `give_all`
+
+**Description:**
+Adds multiple items to the channel.
+
+**Usage:**
+```markdown
+give_all(channel:|T|, items: [T], where: Where = Where.End) -> Void
+```
+
+**Parameters:**
+
+- `channel`: The channel to which the items will be added.
+- `items`: The array of items to add to the channel.
+- `where`: Where to put the items (at the `Start` or `End` of the queue).
+ `Anywhere` defaults to `End`.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+>> channel:give_all([1, 2, 3])
+```
+
+---
+
+### `get`
+
+**Description:**
+Removes and returns an item from the channel. If the channel is empty, it waits until an item is available.
+
+**Usage:**
+```markdown
+get(channel:|T|, where: Where = Where.Start) -> T
+```
+
+**Parameters:**
+
+- `channel`: The channel from which to remove an item.
+- `where`: Where to get the item from (from the `Start` or `End` of the queue).
+ `Anywhere` defaults to `Start`.
+
+**Returns:**
+The item removed from the channel.
+
+**Example:**
+```markdown
+>> channel:peek()
+= "Hello"
+```
+
+---
+
+### `peek`
+
+**Description:**
+Returns the next item that will come out of the channel, but without removing
+it. If the channel is empty, it waits until an item is available.
+
+**Usage:**
+```markdown
+peek(channel:|T|, where: Where = Where.Start) -> T
+```
+
+**Parameters:**
+
+- `channel`: The channel from which to remove an item.
+- `where`: Which end of the channel to peek from (the `Start` or `End`).
+ `Anywhere` defaults to `Start`.
+
+**Returns:**
+The item removed from the channel.
+
+**Example:**
+```markdown
+>> channel:get()
+= "Hello"
+```
+
+---
+
+### `clear`
+
+**Description:**
+Removes all items from the channel.
+
+**Usage:**
+```markdown
+clear(channel:|T|) -> Void
+```
+
+**Parameters:**
+
+- `channel`: The mutable reference to the channel.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+>> channel:clear()
+```
+
+---
+
+### `view`
+
+**Description:**
+Returns a list of all items currently in the channel without removing them.
+
+**Usage:**
+```markdown
+channel:view() -> [T]
+```
+
+**Parameters:**
+
+- `channel`: The channel to view.
+
+**Returns:**
+An array of items currently in the channel.
+
+**Example:**
+```markdown
+>> channel:view()
+= [1, 2, 3]
+```
diff --git a/docs/enums.md b/docs/enums.md
new file mode 100644
index 00000000..4123fbc4
--- /dev/null
+++ b/docs/enums.md
@@ -0,0 +1,88 @@
+# Enums
+
+Tomo supports tagged enumerations, also known as "sum types." Users
+can define their own using the `enum` keyword:
+
+```tomo
+enum VariousThings(AnInteger(i:Int), TwoWords(word1, word2:Text), Nothing)
+
+...
+
+a := VariousThings.AnInteger(5)
+b := VariousThings.TwoWords("one", "two")
+c := VariousThings.Nothing
+```
+
+## Pattern Matching
+
+The values inside an enum can be accessed with pattern matching:
+
+```tomo
+when x is AnInteger(i):
+ say("It was $i")
+is TwoWords(x, y):
+ say("It was $x and $y")
+is Nothing:
+ say("It was nothing")
+```
+
+Pattern matching blocks are always checked for exhaustiveness, but you can add
+an `else` block to handle all unmatched patterns.
+
+## Tag Checking
+
+Tags can also be quickly checked using the `.TagName` field:
+
+```tomo
+>> a.AnInteger
+= yes
+>> a.TwoWords
+= no
+```
+
+## Reducing Boilerplate
+
+There are three main areas where we can easily reduce the amount of boilerplate
+around enums. We don't need to type `VariousThings.` in front of enum values
+when we already know what type of enum we're dealing with. This means that we
+don't need the name of the type for pattern matching (because we can infer the
+type of the expression being matched). We also don't need the name of the type
+when calling a function with an enum argument, nor when returning an enum value
+from a function with an explicit return type:
+
+```tomo
+enum ArgumentType(AnInt(x:Int), SomeText(text:Text))
+enum ReturnType(Nothing, AnInt(x:Int))
+
+func increment(arg:ArgumentType)->ReturnType:
+ when arg is AnInt(x):
+ return AnInt(x + 1)
+ is SomeText:
+ return Nothing
+
+...
+
+>> increment(AnInt(5))
+= ReturnType.AnInt(6)
+>> increment(SomeText("HI"))
+= ReturnType.Nothiing
+```
+
+This lets us have overlapping tag names for different types, but smartly infer
+which enum's value is being created when we know what we're expecting to get.
+This also works for variable assignment to a variable whose type is already
+known.
+
+## Namespacing
+
+Enums can also define their own methods and variables inside their namespace:
+
+```tomo
+enum VariousThings(AnInteger(i:Int), TwoWords(word1, word2:Text), Nothing):
+ meaningful_thing := AnInteger(42)
+ func doop(v:VariousThings):
+ say("$v")
+```
+
+Functions defined in an enum's namespace can be invoked as methods with `:` if
+the first argument is the enum's type or a pointer to one (`vt:doop()`).
diff --git a/docs/integers.md b/docs/integers.md
new file mode 100644
index 00000000..653322fd
--- /dev/null
+++ b/docs/integers.md
@@ -0,0 +1,368 @@
+# Integers
+
+Tomo has five types of integers:
+
+- `Int`: the default integer type, which uses an efficient tagged 29-bit
+ integer value for small numbers, and falls back to a bigint implementation
+ when values are too large to fit in 29-bits. The bigint implementation uses
+ the GNU MP library. These integers are fast for small numbers and guaranteed
+ to always be correct and never overflow.
+- `Int8`/`Int16`/`Int32`/`Int64`: Fixed-size integers that take up `N` bits.
+ These integers must be manually specified with their suffix (e.g. `5_i64`)
+ and are subject to overflowing. If an overflow occurs, a runtime error will
+ be raised.
+
+Conversion between integer types can be done by calling the target type as a
+function: `Int32(x)`. For fixed-width types, the conversion function also
+accepts a second parameter, `truncate`. If `truncate` is `no` (the default),
+conversion will create a runtime error if the value is too large to fit in the
+target type. If `truncate` is `yes`, then the resulting value will be a
+truncated form of the input value.
+
+Integers support the standard math operations (`x+y`, `x-y`, `x*y`, `x/y`) as
+well as powers/exponentiation (`x^y`), modulus (`x mod y` and `x mod1 y`), and
+bitwise operations: `x and y`, `x or y`, `x xor y`, `x << y`, and `x >> y`. The
+operators `and`, `or`, and `xor` are _bitwise_, not logical operators.
+
+# Integer Functions
+
+Each integer type has its own version of the following functions. Functions
+can be called either on the type itself: `Int.sqrt(x)` or as a method call:
+`x:sqrt()`. Method call syntax is preferred.
+
+## `format`
+
+**Description:**
+Formats an integer as a string with a specified number of digits.
+
+**Usage:**
+```tomo
+format(i: Int, digits: Int = 0) -> Text
+```
+
+**Parameters:**
+
+- `i`: The integer to be formatted.
+- `digits`: The minimum number of digits to which the integer should be padded. Default is `0`.
+
+**Returns:**
+A string representation of the integer, padded to the specified number of digits.
+
+**Example:**
+```tomo
+>> 42:format(digits=5)
+= "00042"
+```
+
+---
+
+## `hex`
+
+**Description:**
+Converts an integer to its hexadecimal representation.
+
+**Usage:**
+```tomo
+hex(i: Int, digits: Int = 0, uppercase: Bool = yes, prefix: Bool = yes) -> Text
+```
+
+**Parameters:**
+
+- `i`: The integer to be converted.
+- `digits`: The minimum number of digits in the output string. Default is `0`.
+- `uppercase`: Whether to use uppercase letters for hexadecimal digits. Default is `yes`.
+- `prefix`: Whether to include a "0x" prefix. Default is `yes`.
+
+**Returns:**
+The hexadecimal string representation of the integer.
+
+**Example:**
+```tomo
+>> 255:hex(digits=4, uppercase=yes, prefix=yes)
+= "0x00FF"
+```
+
+---
+
+## `octal`
+
+**Description:**
+Converts an integer to its octal representation.
+
+**Usage:**
+```tomo
+octal(i: Int, digits: Int = 0, prefix: Bool = yes) -> Text
+```
+
+**Parameters:**
+
+- `i`: The integer to be converted.
+- `digits`: The minimum number of digits in the output string. Default is `0`.
+- `prefix`: Whether to include a "0o" prefix. Default is `yes`.
+
+**Returns:**
+The octal string representation of the integer.
+
+**Example:**
+```tomo
+>> 64:octal(digits=4, prefix=yes)
+= "0o0100"
+```
+
+---
+
+## `random`
+
+**Description:**
+Generates a random integer between the specified minimum and maximum values.
+
+**Usage:**
+```tomo
+random(min: Int, max: Int) -> Int
+```
+
+**Parameters:**
+
+- `min`: The minimum value of the range.
+- `max`: The maximum value of the range.
+
+**Returns:**
+A random integer between `min` and `max` (inclusive).
+
+**Example:**
+```tomo
+>> Int.random(1, 100)
+= 47
+```
+
+---
+
+## `from_text`
+
+**Description:**
+Converts a text representation of an integer into an integer.
+
+**Usage:**
+```tomo
+from_text(text: Text, the_rest: Text = "!&Text") -> Int
+```
+
+**Parameters:**
+
+- `text`: The string containing the integer.
+- `the_rest`: If non-null, this pointer will be set to point to any unparseable text after the integer.
+
+**Returns:**
+The integer represented by the string.
+
+**Example:**
+```tomo
+>> from_text("123")
+= 123
+>> from_text("0xFF")
+= 255
+```
+
+---
+
+## `to`
+
+**Description:**
+Creates an inclusive range of integers between the specified start and end values.
+
+**Usage:**
+```tomo
+to(from: Int, to: Int) -> Range
+```
+
+**Parameters:**
+
+- `from`: The starting value of the range.
+- `to`: The ending value of the range.
+
+**Returns:**
+A range object representing all integers from `from` to `to` (inclusive).
+
+**Example:**
+```tomo
+>> 1:to(5)
+= Range(first=1, last=5, step=1)
+```
+
+---
+
+## `abs`
+
+**Description:**
+Calculates the absolute value of an integer.
+
+**Usage:**
+```tomo
+abs(x: Int) -> Int
+```
+
+**Parameters:**
+
+- `x`: The integer whose absolute value is to be calculated.
+
+**Returns:**
+The absolute value of `x`.
+
+**Example:**
+```tomo
+>> -10:abs()
+= 10
+```
+
+---
+
+## `sqrt`
+
+**Description:**
+Calculates the square root of an integer.
+
+**Usage:**
+```tomo
+sqrt(x: Int) -> Int
+```
+
+**Parameters:**
+
+- `x`: The integer whose square root is to be calculated.
+
+**Returns:**
+The integer part of the square root of `x`.
+
+**Example:**
+```tomo
+>> 16:sqrt()
+= 4
+>> 17:sqrt()
+= 4
+```
+
+---
+
+## `is_prime`
+
+**Description:**
+Determines if an integer is a prime number.
+
+**Note:**
+This function is _probabilistic_. With the default arguments, the chances of
+getting an incorrect answer are astronomically small (on the order of 10^(-30)).
+See [the GNU MP docs](https://gmplib.org/manual/Number-Theoretic-Functions#index-mpz_005fprobab_005fprime_005fp)
+for more details.
+
+**Usage:**
+```tomo
+is_prime(x: Int, reps: Int = 50) -> Bool
+```
+
+**Parameters:**
+
+- `x`: The integer to be checked.
+- `reps`: The number of repetitions for primality tests. Default is `50`.
+
+**Returns:**
+`yes` if `x` is a prime number, `no` otherwise.
+
+**Example:**
+```tomo
+>> 7:is_prime()
+= yes
+>> 6:is_prime()
+= no
+```
+
+---
+
+## `next_prime`
+
+**Description:**
+Finds the next prime number greater than the given integer.
+
+**Note:**
+This function is _probabilistic_, but the chances of getting an incorrect
+answer are astronomically small (on the order of 10^(-30)).
+See [the GNU MP docs](https://gmplib.org/manual/Number-Theoretic-Functions#index-mpz_005fprobab_005fprime_005fp)
+for more details.
+
+**Usage:**
+```tomo
+next_prime(x: Int) -> Int
+```
+
+**Parameters:**
+
+- `x`: The integer after which to find the next prime.
+
+**Returns:**
+The next prime number greater than `x`.
+
+**Example:**
+```tomo
+>> 11:next_prime()
+= 13
+```
+
+---
+
+## `prev_prime`
+
+**Description:**
+Finds the previous prime number less than the given integer.
+If there is no previous prime number (i.e. if a number less than `2` is
+provided), then the function will create a runtime error.
+
+**Note:**
+This function is _probabilistic_, but the chances of getting an incorrect
+answer are astronomically small (on the order of 10^(-30)).
+See [the GNU MP docs](https://gmplib.org/manual/Number-Theoretic-Functions#index-mpz_005fprobab_005fprime_005fp)
+for more details.
+
+**Usage:**
+```tomo
+prev_prime(x: Int) -> Int
+```
+
+**Parameters:**
+
+- `x`: The integer before which to find the previous prime.
+
+**Returns:**
+The previous prime number less than `x`.
+
+**Example:**
+```tomo
+>> 11:prev_prime()
+= 7
+```
+
+---
+
+## `clamped`
+
+**Description:**
+Returns the given number clamped between two values so that it is within
+that range.
+
+**Usage:**
+```tomo
+clamped(x, low, high: Int) -> Int
+```
+
+**Parameters:**
+
+- `x`: The integer to clamp.
+- `low`: The lowest value the result can take.
+- `high`: The highest value the result can take.
+
+**Returns:**
+The first argument clamped between the other two arguments.
+
+**Example:**
+```tomo
+>> 2:clamped(5, 10)
+= 5
+```
diff --git a/docs/nums.md b/docs/nums.md
new file mode 100644
index 00000000..5b258010
--- /dev/null
+++ b/docs/nums.md
@@ -0,0 +1,1374 @@
+# Nums
+
+Tomo has two floating point number types: `Num` (64-bit, AKA `double`) and
+`Num32` (32-bit, AKA `float`). Num literals can have a decimal point (e.g.
+`5.`), a scientific notation suffix (e.g. `1e8`) or a percent sign. Numbers
+that end in a percent sign are divided by 100 at compile time (i.e. `5% ==
+0.05`).
+
+Nums support the standard math operations (`x+y`, `x-y`, `x*y`, `x/y`) as well as
+powers/exponentiation (`x^y`) and modulus (`x mod y` and `x mod1 y`).
+
+# Num Functions
+
+Each Num type has its own version of the following functions. Functions can be
+called either on the type itself: `Num.sqrt(x)` or as a method call:
+`x:sqrt()`. Method call syntax is preferred.
+
+## Constants
+
+- **`1_PI`**: \( \frac{1}{\pi} \)
+- **`2_PI`**: \( 2 \times \pi \)
+- **`2_SQRTPI`**: \( 2 \times \sqrt{\pi} \)
+- **`E`**: Base of natural logarithms (\( e \))
+- **`INF`**: Positive infinity
+- **`LN10`**: Natural logarithm of 10
+- **`LN2`**: Natural logarithm of 2
+- **`LOG2E`**: Logarithm base 2 of \( e \)
+- **`PI`**: Pi (\( \pi \))
+- **`PI_2`**: \( \frac{\pi}{2} \)
+- **`PI_4`**: \( \frac{\pi}{4} \)
+- **`SQRT1_2`**: \( \sqrt{\frac{1}{2}} \)
+- **`SQRT2`**: \( \sqrt{2} \)
+- **`TAU`**: Tau (\( 2 \times \pi \))
+
+## Functions
+
+### `abs`
+
+**Description:**
+Calculates the absolute value of a number.
+
+**Usage:**
+```tomo
+abs(n: Num) -> Num
+```
+
+**Parameters:**
+
+- `n`: The number whose absolute value is to be computed.
+
+**Returns:**
+The absolute value of `n`.
+
+**Example:**
+```tomo
+>> -3.5:abs()
+= 3.5
+```
+
+---
+
+### `acos`
+
+**Description:**
+Computes the arc cosine of a number.
+
+**Usage:**
+```tomo
+acos(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the arc cosine is to be calculated.
+
+**Returns:**
+The arc cosine of `x` in radians.
+
+**Example:**
+```tomo
+>> 0.0:acos() // -> (π/2)
+= 1.5708
+```
+
+---
+
+### `acosh`
+
+**Description:**
+Computes the inverse hyperbolic cosine of a number.
+
+**Usage:**
+```tomo
+acosh(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the inverse hyperbolic cosine is to be calculated.
+
+**Returns:**
+The inverse hyperbolic cosine of `x`.
+
+**Example:**
+```tomo
+>> 1.0:acosh()
+= 0
+```
+
+---
+
+### `asin`
+
+**Description:**
+Computes the arc sine of a number.
+
+**Usage:**
+```tomo
+asin(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the arc sine is to be calculated.
+
+**Returns:**
+The arc sine of `x` in radians.
+
+**Example:**
+```tomo
+>> 0.5:asin() // -> (π/6)
+= 0.5236
+```
+
+---
+
+### `asinh`
+
+**Description:**
+Computes the inverse hyperbolic sine of a number.
+
+**Usage:**
+```tomo
+asinh(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the inverse hyperbolic sine is to be calculated.
+
+**Returns:**
+The inverse hyperbolic sine of `x`.
+
+**Example:**
+```tomo
+>> 0.0:asinh()
+= 0
+```
+
+---
+
+### `atan2`
+
+**Description:**
+Computes the arc tangent of the quotient of two numbers.
+
+**Usage:**
+```tomo
+atan2(x: Num, y: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The numerator.
+- `y`: The denominator.
+
+**Returns:**
+The arc tangent of `x/y` in radians.
+
+**Example:**
+```tomo
+>> Num.atan2(1, 1) // -> (π/4)
+= 0.7854
+```
+
+---
+
+### `atan`
+
+**Description:**
+Computes the arc tangent of a number.
+
+**Usage:**
+```tomo
+atan(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the arc tangent is to be calculated.
+
+**Returns:**
+The arc tangent of `x` in radians.
+
+**Example:**
+```tomo
+>> 1.0:atan() // -> (π/4)
+= 0.7854
+```
+
+---
+
+### `atanh`
+
+**Description:**
+Computes the inverse hyperbolic tangent of a number.
+
+**Usage:**
+```tomo
+atanh(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the inverse hyperbolic tangent is to be calculated.
+
+**Returns:**
+The inverse hyperbolic tangent of `x`.
+
+**Example:**
+```tomo
+>> 0.5:atanh()
+= 0.5493
+```
+
+---
+
+### `cbrt`
+
+**Description:**
+Computes the cube root of a number.
+
+**Usage:**
+```tomo
+cbrt(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the cube root is to be calculated.
+
+**Returns:**
+The cube root of `x`.
+
+**Example:**
+```tomo
+>> 27.0:cbrt()
+= 3
+```
+
+---
+
+### `ceil`
+
+**Description:**
+Rounds a number up to the nearest integer.
+
+**Usage:**
+```tomo
+ceil(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number to be rounded up.
+
+**Returns:**
+The smallest integer greater than or equal to `x`.
+
+**Example:**
+```tomo
+>> 3.2:ceil()
+= 4
+```
+
+---
+
+### `copysign`
+
+**Description:**
+Copies the sign of one number to another.
+
+**Usage:**
+```tomo
+copysign(x: Num, y: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number whose magnitude will be copied.
+- `y`: The number whose sign will be copied.
+
+**Returns:**
+A number with the magnitude of `x` and the sign of `y`.
+
+**Example:**
+```tomo
+>> 3.0:copysign(-1)
+= -3
+```
+
+---
+
+### `cos`
+
+**Description:**
+Computes the cosine of a number (angle in radians).
+
+**Usage:**
+```tomo
+cos(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The angle in radians.
+
+**Returns:**
+The cosine of `x`.
+
+**Example:**
+```tomo
+>> 0.0:cos()
+= 1
+```
+
+---
+
+### `cosh`
+
+**Description:**
+Computes the hyperbolic cosine of a number.
+
+**Usage:**
+```tomo
+cosh(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the hyperbolic cosine is to be calculated.
+
+**Returns:**
+The hyperbolic cosine of `x`.
+
+**Example:**
+```tomo
+>> 0.0:cosh()
+= 1
+```
+
+---
+
+### `erf`
+
+**Description:**
+Computes the error function of a number.
+
+**Usage:**
+```tomo
+erf(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the error function is to be calculated.
+
+**Returns:**
+The error function of `x`.
+
+**Example:**
+```tomo
+>> 0.0:erf()
+= 0
+```
+
+---
+
+### `erfc`
+
+**Description:**
+Computes the complementary error function of a number.
+
+**Usage:**
+```tomo
+erfc(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the complementary error function is to be calculated.
+
+**Returns:**
+The complementary error function of `x`.
+
+**Example:**
+```tomo
+>> 0.0:erfc()
+= 1
+```
+
+---
+
+### `exp2`
+
+**Description:**
+Computes \( 2^x \) for a number.
+
+**Usage:**
+```tomo
+exp2(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The exponent.
+
+**Returns:**
+The value of \( 2^x \).
+
+**Example:**
+```tomo
+>> 3.0:exp2()
+= 8
+```
+
+---
+
+### `exp`
+
+**Description:**
+Computes the exponential function \( e^x \) for a number.
+
+**Usage:**
+```tomo
+exp(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The exponent.
+
+**Returns:**
+The value of \( e^x \).
+
+**Example:**
+```tomo
+>> 1.0:exp()
+= 2.7183
+```
+
+---
+
+### `expm1`
+
+**Description:**
+Computes \( e^x - 1 \) for a number.
+
+**Usage:**
+```tomo
+expm1(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The exponent.
+
+**Returns:**
+The value of \( e^x - 1 \).
+
+**Example:**
+```tomo
+>> 1.0:expm1()
+= 1.7183
+```
+
+---
+
+### `fdim`
+
+**Description:**
+Computes the positive difference between two numbers.
+
+**Usage:**
+```tomo
+fdim(x: Num, y: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The first number.
+- `y`: The second number.
+
+**Returns:**
+The positive difference \( \max(0, x - y) \).
+
+**Example:**
+```tomo
+fd
+
+>> 5.0:fdim(3)
+= 2
+```
+
+---
+
+### `floor`
+
+**Description:**
+Rounds a number down to the nearest integer.
+
+**Usage:**
+```tomo
+floor(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number to be rounded down.
+
+**Returns:**
+The largest integer less than or equal to `x`.
+
+**Example:**
+```tomo
+>> 3.7:floor()
+= 3
+```
+
+---
+
+### `format`
+
+**Description:**
+Formats a number as a string with a specified precision.
+
+**Usage:**
+```tomo
+format(n: Num, precision: Int = 0) -> Text
+```
+
+**Parameters:**
+
+- `n`: The number to be formatted.
+- `precision`: The number of decimal places. Default is `0`.
+
+**Returns:**
+A string representation of the number with the specified precision.
+
+**Example:**
+```tomo
+>> 3.14159:format(precision=2)
+= "3.14"
+```
+
+---
+
+### `from_text`
+
+**Description:**
+Converts a string representation of a number into a floating-point number.
+
+**Usage:**
+```tomo
+from_text(text: Text, the_rest: Text = "!&Text") -> Num
+```
+
+**Parameters:**
+
+- `text`: The string containing the number.
+- `the_rest`: A string indicating what to return if the conversion fails. Default is `"!&Text"`.
+
+**Returns:**
+The number represented by the string.
+
+**Example:**
+```tomo
+>> Num.from_text("3.14")
+= 3.14
+>> Num.from_text("1e3")
+= 1000
+```
+
+---
+
+### `hypot`
+
+**Description:**
+Computes the Euclidean norm, \( \sqrt{x^2 + y^2} \), of two numbers.
+
+**Usage:**
+```tomo
+hypot(x: Num, y: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The first number.
+- `y`: The second number.
+
+**Returns:**
+The Euclidean norm of `x` and `y`.
+
+**Example:**
+```tomo
+>> Num.hypot(3, 4)
+= 5
+```
+
+---
+
+### `isfinite`
+
+**Description:**
+Checks if a number is finite.
+
+**Usage:**
+```tomo
+isfinite(n: Num) -> Bool
+```
+
+**Parameters:**
+
+- `n`: The number to be checked.
+
+**Returns:**
+`yes` if `n` is finite, `no` otherwise.
+
+**Example:**
+```tomo
+>> 1.0:isfinite()
+= yes
+>> Num.INF:isfinite()
+= no
+```
+
+---
+
+### `isinf`
+
+**Description:**
+Checks if a number is infinite.
+
+**Usage:**
+```tomo
+isinf(n: Num) -> Bool
+```
+
+**Parameters:**
+
+- `n`: The number to be checked.
+
+**Returns:**
+`yes` if `n` is infinite, `no` otherwise.
+
+**Example:**
+```tomo
+>> Num.INF:isinf()
+= yes
+>> 1.0:isinf()
+= no
+```
+
+---
+
+### `isnan`
+
+**Description:**
+Checks if a number is NaN (Not a Number).
+
+**Usage:**
+```tomo
+isnan(n: Num) -> Bool
+```
+
+**Parameters:**
+
+- `n`: The number to be checked.
+
+**Returns:**
+`yes` if `n` is NaN, `no` otherwise.
+
+**Example:**
+```tomo
+>> Num.nan():isnan()
+= yes
+>> 1.0:isnan()
+= no
+```
+
+---
+
+### `j0`
+
+**Description:**
+Computes the Bessel function of the first kind of order 0.
+
+**Usage:**
+```tomo
+j0(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the Bessel function is to be calculated.
+
+**Returns:**
+The Bessel function of the first kind of order 0 of `x`.
+
+**Example:**
+```tomo
+>> 0.0:j0()
+= 1
+```
+
+---
+
+### `j1`
+
+**Description:**
+Computes the Bessel function of the first kind of order 1.
+
+**Usage:**
+```tomo
+j1(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the Bessel function is to be calculated.
+
+**Returns:**
+The Bessel function of the first kind of order 1 of `x`.
+
+**Example:**
+```tomo
+>> 0.0:j1()
+= 0
+```
+
+---
+
+### `log10`
+
+**Description:**
+Computes the base-10 logarithm of a number.
+
+**Usage:**
+```tomo
+log10(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the base-10 logarithm is to be calculated.
+
+**Returns:**
+The base-10 logarithm of `x`.
+
+**Example:**
+```tomo
+>> 100.0:log10()
+= 2
+```
+
+---
+
+### `log1p`
+
+**Description:**
+Computes \( \log(1 + x) \) for a number.
+
+**Usage:**
+```tomo
+log1p(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which \( \log(1 + x) \) is to be calculated.
+
+**Returns:**
+The value of \( \log(1 + x) \).
+
+**Example:**
+```tomo
+>> 1.0:log1p()
+= 0.6931
+```
+
+---
+
+### `log2`
+
+**Description:**
+Computes the base-2 logarithm of a number.
+
+**Usage:**
+```tomo
+log2(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the base-2 logarithm is to be calculated.
+
+**Returns:**
+The base-2 logarithm of `x`.
+
+**Example:**
+```tomo
+>> 8.0:log2()
+= 3
+```
+
+---
+
+### `log`
+
+**Description:**
+Computes the natural logarithm (base \( e \)) of a number.
+
+**Usage:**
+```tomo
+log(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the natural logarithm is to be calculated.
+
+**Returns:**
+The natural logarithm of `x`.
+
+**Example:**
+```tomo
+>> Num.E:log()
+= 1
+```
+
+---
+
+### `logb`
+
+**Description:**
+Computes the binary exponent (base-2 logarithm) of a number.
+
+**Usage:**
+```tomo
+logb(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the binary exponent is to be calculated.
+
+**Returns:**
+The binary exponent of `x`.
+
+**Example:**
+```tomo
+>> 8.0:logb()
+= 3
+```
+
+---
+
+### `mix`
+
+**Description:**
+Interpolates between two numbers based on a given amount.
+
+**Usage:**
+```tomo
+mix(amount: Num, x: Num, y: Num) -> Num
+```
+
+**Parameters:**
+
+- `amount`: The interpolation factor (between `0` and `1`).
+- `x`: The starting number.
+- `y`: The ending number.
+
+**Returns:**
+The interpolated number between `x` and `y` based on `amount`.
+
+**Example:**
+```tomo
+>> 0.5:mix(10, 20)
+= 15
+>> 0.25:mix(10, 20)
+= 12.5
+```
+
+---
+
+### `nan`
+
+**Description:**
+Generates a NaN (Not a Number) value.
+
+**Usage:**
+```tomo
+nan(tag: Text = "") -> Num
+```
+
+**Parameters:**
+
+- `tag`: An optional tag to describe the NaN. Default is an empty string.
+
+**Returns:**
+A NaN value.
+
+**Example:**
+```tomo
+>> Num.nan()
+= NaN
+```
+
+---
+
+### `near`
+
+**Description:**
+Checks if two numbers are approximately equal within specified tolerances. If
+two numbers are within an absolute difference or the ratio between the two is
+small enough, they are considered near each other.
+
+**Usage:**
+```tomo
+near(x: Num, y: Num, ratio: Num = 1e-9, min_epsilon: Num = 1e-9) -> Bool
+```
+
+**Parameters:**
+
+- `x`: The first number.
+- `y`: The second number.
+- `ratio`: The relative tolerance. Default is `1e-9`.
+- `min_epsilon`: The absolute tolerance. Default is `1e-9`.
+
+**Returns:**
+`yes` if `x` and `y` are approximately equal within the specified tolerances, `no` otherwise.
+
+**Example:**
+```tomo
+>> 1.0:near(1.000000001)
+= yes
+
+>> 100.0:near(110, ratio=0.1)
+= yes
+
+>> 5.0:near(5.1, min_epsilon=0.1)
+= yes
+```
+
+---
+
+### `nextafter`
+
+**Description:**
+Computes the next representable value after a given number towards a specified direction.
+
+**Usage:**
+```tomo
+nextafter(x: Num, y: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The starting number.
+- `y`: The direction towards which to find the next representable value.
+
+**Returns:**
+The next representable value after `x` in the direction of `y`.
+
+**Example:**
+```tomo
+>> 1.0:nextafter(1.1)
+= 1.0000000000000002
+```
+
+---
+
+### `random`
+
+**Description:**
+Generates a random floating-point number.
+
+**Usage:**
+```tomo
+random() -> Num
+```
+
+**Parameters:**
+None
+
+**Returns:**
+A random floating-point number between 0 and 1.
+
+**Example:**
+```tomo
+>> Num.random()
+= 0.4521
+```
+
+---
+
+### `rint`
+
+**Description:**
+Rounds a number to the nearest integer, with ties rounded to the nearest even integer.
+
+**Usage:**
+```tomo
+rint(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number to be rounded.
+
+**Returns:**
+The nearest integer value of `x`.
+
+**Example:**
+```tomo
+>> 3.5:rint()
+= 4
+>> 2.5:rint()
+= 2
+```
+
+---
+
+### `round`
+
+**Description:**
+Rounds a number to the nearest whole number integer.
+
+**Usage:**
+```tomo
+round(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number to be rounded.
+
+**Returns:**
+The nearest integer value of `x`.
+
+**Example:**
+```tomo
+>> 2.3:round()
+= 2
+>> 2.7:round()
+= 3
+```
+
+---
+
+### `scientific`
+
+**Description:**
+Formats a number in scientific notation with a specified precision.
+
+**Usage:**
+```tomo
+scientific(n: Num, precision: Int = 0) -> Text
+```
+
+**Parameters:**
+
+- `n`: The number to be formatted.
+- `precision`: The number of decimal places. Default is `0`.
+
+**Returns:**
+A string representation of the number in scientific notation with the specified precision.
+
+**Example:**
+```tomo
+>> 12345.6789:scientific(precision=2)
+= "1.23e+04"
+```
+
+---
+
+### `significand`
+
+**Description:**
+Extracts the significand (or mantissa) of a number.
+
+**Usage:**
+```tomo
+significand(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number from which to extract the significand.
+
+**Returns:**
+The significand of `x`.
+
+**Example:**
+```tomo
+>> 1234.567:significand()
+= 0.1234567
+```
+
+---
+
+### `sin`
+
+**Description:**
+Computes the sine of a number (angle in radians).
+
+**Usage:**
+```tomo
+sin(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The angle in radians.
+
+**Returns:**
+The sine of `x`.
+
+**Example:**
+```tomo
+>> 0.0:sin()
+= 0
+```
+
+---
+
+### `sinh`
+
+**Description:**
+Computes the hyperbolic sine of a number.
+
+**Usage:**
+```tomo
+sinh(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the hyperbolic sine is to be calculated.
+
+**Returns:**
+The hyperbolic sine of `x`.
+
+**Example:**
+```tomo
+>> 0.0:sinh()
+= 0
+```
+
+---
+
+### `sqrt`
+
+**Description:**
+Computes the square root of a number.
+
+**Usage:**
+```tomo
+sqrt(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the square root is to be calculated.
+
+**Returns:**
+The square root of `x`.
+
+**Example:**
+```tomo
+>> 16.0:sqrt()
+= 4
+```
+
+---
+
+### `tan`
+
+**Description:**
+Computes the tangent of a number (angle in radians).
+
+**Usage:**
+```tomo
+tan(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The angle in radians.
+
+**Returns:**
+The tangent of `x`.
+
+**Example:**
+```tomo
+>> 0.0:tan()
+= 0
+```
+
+---
+
+### `tanh`
+
+**Description:**
+Computes the hyperbolic tangent of a number.
+
+**Usage:**
+```tomo
+tanh(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the hyperbolic tangent is to be calculated.
+
+**Returns:**
+The hyperbolic tangent of `x`.
+
+**Example:**
+```tomo
+>> 0.0:tanh()
+= 0
+```
+
+---
+
+### `tgamma`
+
+**Description:**
+Computes the gamma function of a number.
+
+**Usage:**
+```tomo
+tgamma(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the gamma function is to be calculated.
+
+**Returns:**
+The gamma function of `x`.
+
+**Example:**
+```tomo
+>> 1.0:tgamma()
+= 1
+```
+
+---
+
+### `trunc`
+
+**Description:**
+Truncates a number to the nearest integer towards zero.
+
+**Usage:**
+```tomo
+trunc(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number to be truncated.
+
+**Returns:**
+The integer part of `x` towards zero.
+
+**Example:**
+```tomo
+>> 3.7:trunc()
+= 3
+>> (-3.7):trunc()
+= -3
+```
+
+---
+
+### `y0`
+
+**Description:**
+Computes the Bessel function of the second kind of order 0.
+
+**Usage:**
+```tomo
+y0(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the Bessel function is to be calculated.
+
+**Returns:**
+The Bessel function of the second kind of order 0 of `x`.
+
+**Example:**
+```tomo
+>> 1.0:y0()
+= -0.7652
+```
+
+---
+
+### `y1`
+
+**Description:**
+Computes the Bessel function of the second kind of order 1.
+
+**Usage:**
+```tomo
+y1(x: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number for which the Bessel function is to be calculated.
+
+**Returns:**
+The Bessel function of the second kind of order 1 of `x`.
+
+**Example:**
+```tomo
+>> 1.0:y1()
+= 0.4401
+```
+
+---
+
+## `clamped`
+
+**Description:**
+Returns the given number clamped between two values so that it is within
+that range.
+
+**Usage:**
+```tomo
+clamped(x, low, high: Num) -> Num
+```
+
+**Parameters:**
+
+- `x`: The number to clamp.
+- `low`: The lowest value the result can take.
+- `high`: The highest value the result can take.
+
+**Returns:**
+The first argument clamped between the other two arguments.
+
+**Example:**
+```tomo
+>> 2.5:clamped(5.5, 10.5)
+= 5.5
+```
diff --git a/docs/pointers.md b/docs/pointers.md
new file mode 100644
index 00000000..ee7a5d8f
--- /dev/null
+++ b/docs/pointers.md
@@ -0,0 +1,133 @@
+# Pointers
+
+Pointers are numeric values that represent a location in memory where some type
+of data lives. Pointers are created using either the `@` prefix operator to
+**a**llocate heap memory or the `&` prefix operator to get the address of a
+variable. Stack pointers (`&`) are more limited than heap pointers (`@`) and
+cannot be stored inside an array, set, table, struct, enum, or channel.
+However, stack pointers are useful for methods that mutate local variables and
+don't need to save the pointer anywhere.
+
+Pointers are the way in Tomo that you can create mutable data. All
+datastructures are by default, immutable, but using pointers, you can create
+a region of memory where different immutable values can be held, which change
+over time. Essentially, you can think about mutation as the act of creating
+a new, different value and assigning it to a pointer's memory location to
+replace the value that previously resided there.
+
+```tomo
+func no_mutation_possible(nums:[Int]):
+ nums[1] = 10 // This performs a copy-on-write and creates a new array
+ // The new array is only accessible as a local variable here
+...
+my_nums := [0, 1, 2]
+no_mutation_possible(my_nums)
+>> my_nums
+= [0, 1, 2]
+
+func do_mutation(nums:@[Int]):
+ nums[1] = 10 // The mutates the value at the given pointer's location
+...
+my_nums := @[0, 1, 2]
+do_mutation(my_nums)
+>> my_nums
+= @[10, 1, 2]
+```
+
+In general, heap pointers can be used as stack pointers if necessary, since
+the usage of stack pointers is restricted, but heap pointers don't have the
+same restrictions, so it's good practice to define functions that don't need
+to store pointers to use stack references. This lets you pass references to
+local variables or pointers to heap data depending on your needs.
+
+```tomo
+func swap_first_two(data:&[Int]):
+ data[1], data[2] = data[2], data[1]
+
+...
+
+heap_nums := @[10, 20, 30]
+swap_first_two(heap_nums)
+
+local_nums := [10, 20, 30]
+swap_first_two(&local_nums)
+```
+
+## Dereferencing
+
+Pointers can be dereferenced to access the value that's stored at the pointer's
+memory location using the `[]` postfix operator (with no value inside).
+
+```tomo
+nums := @[10, 20]
+>> nums[]
+= [10, 20]
+```
+
+## Equality and Comparisons
+
+When comparing two pointers, the comparison operates on the _memory address_,
+not the contents of the memory. This is "referential" equality, not
+"structural" equality. The easy way to think about it is that two pointers are
+equal to each other only if doing a mutation to one of them is the same as
+doing a mutation to the other.
+
+```tomo
+x := @[10, 20, 30]
+y := @[10, 20, 30]
+>> x == y
+= no
+
+z := x
+>> x == z
+= yes
+```
+
+Pointers are ordered by memory address, which is somewhat arbitrary, but
+consistent.
+
+## Null Safety
+
+Tomo pointers are, by default, guaranteed to be non-null. If you write a
+function that takes either a `&T` or `@T`, the value that will be given
+is always non-null. However, optional pointers can be used by adding a
+question mark to the type: `&T?` or `@T?`. A null value can be created
+using the syntax `!@T` or `!&T`. You can also append a question mark to
+a pointer value so the type checker knows it's supposed to be optional:
+
+```
+optional := @[10, 20]?
+optional := &foo?
+```
+
+The compiler will not allow you to dereference an optionally null pointer
+without explicitly checking for null. To do so, use pattern matching like
+this:
+
+```
+when optional is @ptr:
+ ok := ptr[]
+else:
+ say("Oh, it was null")
+```
+
+## Using Pointers
+
+For convenience, most operations that work on values can work with pointers to
+values implicitly. For example, if you have a struct type with a `.foo` field,
+you can use `ptr.foo` on a pointer to that struct type as well, without needing
+to use `ptr[].foo`. The same is true for array accesses like `ptr[i]` and method
+calls like `ptr:reversed()`.
+
+As a matter of convenience, local variables can also be automatically promoted
+to stack references when invoking methods that require a stack reference as the
+first argument. For example:
+
+```tomo
+func swap_first_two(arr:&[Int]):
+ arr[1], arr[2] = arr[2], arr[1]
+...
+my_arr := [10, 20, 30] // not a pointer
+swap_first_two(my_arr) // ok, automatically converted to &my_arr
+my_arr:shuffle() // ok, automatically converted to &my_arr
+```
diff --git a/docs/ranges.md b/docs/ranges.md
new file mode 100644
index 00000000..4771bd58
--- /dev/null
+++ b/docs/ranges.md
@@ -0,0 +1,65 @@
+# Ranges
+
+Ranges are Tomo's way to do iteration over numeric ranges. Ranges are typically
+created using the `Int.to()` method like so: `5:to(10)`. Ranges are
+*inclusive*.
+
+```tomo
+>> [i for i in 3:to(5)]
+= [3, 4, 5]
+```
+
+---
+
+## Range Methods
+
+### `reversed`
+
+**Description:**
+Returns a reversed copy of the range.
+
+**Usage:**
+```tomo
+reversed(range: Range) -> Range
+```
+
+**Parameters:**
+
+- `range`: The range to be reversed.
+
+**Returns:**
+A new `Range` with the order of elements reversed.
+
+**Example:**
+```tomo
+>> 1:to(5):reversed()
+= Range(first=5, last=1, step=-1)
+```
+
+---
+
+### `by`
+
+**Description:**
+Creates a new range with a specified step value.
+
+**Usage:**
+```tomo
+by(range: Range, step: Int) -> Range
+```
+
+**Parameters:**
+
+- `range`: The original range.
+- `step`: The step value to be used in the new range.
+
+**Returns:**
+A new `Range` that increments by the specified step value.
+
+**Example:**
+```tomo
+>> 1:to(5):by(2)
+= Range(first=1, last=5, step=2)
+```
+
+---
diff --git a/docs/sets.md b/docs/sets.md
new file mode 100644
index 00000000..850d1443
--- /dev/null
+++ b/docs/sets.md
@@ -0,0 +1,356 @@
+# Sets
+
+Sets represent an unordered collection of unique elements. These are
+implemented using hash tables.
+
+```tomo
+a := {10, 20, 30}
+b := {20, 30}
+>> a:overlap(b)
+= {20}
+```
+
+## Syntax
+
+Sets are written using `{}` curly braces with comma-separated items:
+
+```tomo
+nums := {10, 20, 30}
+```
+
+Empty sets must specify the item type explicitly:
+
+```tomo
+empty := {:Int}
+```
+
+For type annotations, a set that holds items with type `T` is written as `{T}`.
+
+### Comprehensions
+
+Similar to arrays, sets can use comprehensions:
+
+```tomo
+set := {10*i for i in 10}
+set2 := {10*i for i in 10 if i mod 2 == 0}
+set3 := {-10, 10*i for i in 10}
+```
+
+## Accessing Items
+
+Sets internally store their items in an array, which you can access with the
+`.items` field. This is a constant-time operation that produces an immutable
+view:
+
+```tomo
+set := {10, 20, 30}
+>> set.items
+= [10, 20, 30]
+```
+
+## Length
+
+Set length can be accessed by the `.length` field:
+
+```tomo
+>> {10, 20, 30}.length
+= 3
+```
+
+## Iteration
+
+You can iterate over the items in a table like this:
+
+```tomo
+for item in set:
+ ...
+
+for i, item in set:
+ ...
+```
+
+Set iteration operates over the value of the set when the loop began, so
+modifying the set during iteration is safe and will not result in the loop
+iterating over any of the new values.
+
+## Set Methods
+
+### `has`
+
+**Description:**
+Checks if the set contains a specified item.
+
+**Usage:**
+```tomo
+has(set:{T}, item:T) -> Bool
+```
+
+**Parameters:**
+
+- `set`: The set to check.
+- `item`: The item to check for presence.
+
+**Returns:**
+`yes` if the item is present, `no` otherwise.
+
+**Example:**
+```tomo
+>> {10, 20}:has(20)
+= yes
+```
+
+---
+
+### `add`
+
+**Description:**
+Adds an item to the set.
+
+**Usage:**
+```tomo
+add(set:{T}, item: T) -> Void
+```
+
+**Parameters:**
+
+- `set`: The mutable reference to the set.
+- `item`: The item to add to the set.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```tomo
+>> nums:add(42)
+```
+
+---
+
+### `add_all`
+
+**Description:**
+Adds multiple items to the set.
+
+**Usage:**
+```tomo
+add_all(set:&{T}, items: [T]) -> Void
+```
+
+**Parameters:**
+
+- `set`: The mutable reference to the set.
+- `items`: The array of items to add to the set.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```tomo
+>> nums:add_all([1, 2, 3])
+```
+
+---
+
+### `remove`
+
+**Description:**
+Removes an item from the set.
+
+**Usage:**
+```tomo
+remove(set:&{T}, item: T) -> Void
+```
+
+**Parameters:**
+
+- `set`: The mutable reference to the set.
+- `item`: The item to remove from the set.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```tomo
+>> nums:remove(42)
+```
+
+---
+
+### `remove_all`
+
+**Description:**
+Removes multiple items from the set.
+
+**Usage:**
+```tomo
+remove_all(set:&{T}, items: [T]) -> Void
+```
+
+**Parameters:**
+
+- `set`: The mutable reference to the set.
+- `items`: The array of items to remove from the set.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```tomo
+>> nums:remove_all([1, 2, 3])
+```
+
+---
+
+### `clear`
+
+**Description:**
+Removes all items from the set.
+
+**Usage:**
+```tomo
+clear(set:&{T}) -> Void
+```
+
+**Parameters:**
+
+- `set`: The mutable reference to the set.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```tomo
+>> nums:clear()
+```
+
+---
+
+### `with`
+
+**Description:**
+Creates a new set that is the union of the original set and another set.
+
+**Usage:**
+```tomo
+with(set:{T}, other: {T}) -> {T}
+```
+
+**Parameters:**
+
+- `set`: The original set.
+- `other`: The set to union with.
+
+**Returns:**
+A new set containing all items from both sets.
+
+**Example:**
+```tomo
+>> {1, 2}:with({2, 3})
+= {1, 2, 3}
+```
+
+---
+
+### `overlap`
+
+**Description:**
+Creates a new set with items that are in both the original set and another set.
+
+**Usage:**
+```tomo
+overlap(set:{T}, other: {T}) -> {T}
+```
+
+**Parameters:**
+
+- `set`: The original set.
+- `other`: The set to intersect with.
+
+**Returns:**
+A new set containing only items present in both sets.
+
+**Example:**
+```tomo
+>> {1, 2}:overlap({2, 3})
+= {2}
+```
+
+---
+
+### `without`
+
+**Description:**
+Creates a new set with items from the original set but without items from another set.
+
+**Usage:**
+```tomo
+without(set:{T}, other: {T}) -> {T}
+```
+
+**Parameters:**
+
+- `set`: The original set.
+- `other`: The set of items to remove from the original set.
+
+**Returns:**
+A new set containing items from the original set excluding those in the other set.
+
+**Example:**
+```tomo
+>> {1, 2}:without({2, 3})
+= {1}
+```
+
+---
+
+### `is_subset_of`
+
+**Description:**
+Checks if the set is a subset of another set.
+
+**Usage:**
+```tomo
+set:is_subset_of(other: {T}, strict: Bool = no) -> Bool
+```
+
+**Parameters:**
+
+- `set`: The set to check.
+- `other`: The set to compare against.
+- `strict`: If `yes`, checks if the set is a strict subset (does not equal the other set).
+
+**Returns:**
+`yes` if the set is a subset of the other set (strictly or not), `no` otherwise.
+
+**Example:**
+```tomo
+>> {1, 2}:is_subset_of({1, 2, 3})
+= yes
+```
+
+---
+
+### `is_superset_of`
+
+**Description:**
+Checks if the set is a superset of another set.
+
+**Usage:**
+```tomo
+is_superset_of(set:{T}, other: {T}, strict: Bool = no) -> Bool
+```
+
+**Parameters:**
+
+- `set`: The set to check.
+- `other`: The set to compare against.
+- `strict`: If `yes`, checks if the set is a strict superset (does not equal the other set).
+
+**Returns:**
+`yes` if the set is a superset of the other set (strictly or not), `no` otherwise.
+
+**Example:**
+```tomo
+>> {1, 2, 3}:is_superset_of({1, 2})
+= yes
+```
diff --git a/docs/structs.md b/docs/structs.md
new file mode 100644
index 00000000..4ab78fed
--- /dev/null
+++ b/docs/structs.md
@@ -0,0 +1,39 @@
+# Structs
+
+In Tomo, you can define your own structs, which hold members with arbitrary
+types that can be accessed by fields:
+
+```tomo
+struct Foo(name:Text, age:Int)
+...
+>> my_foo := Foo("Bob", age=10)
+= Foo(name="Bob", age=10)
+>> my_foo.name
+= "Bob"
+```
+
+Structs are value types and comparisons on them operate on the member values
+one after the other.
+
+## Namespaces
+
+Structs can define their own methods that can be called with a `:` or different
+values that are stored on the type itself.
+
+```tomo
+struct Foo(name:Text, age:Int):
+ oldest := Foo("Methuselah", 969)
+
+ func greet(f:Foo):
+ say("Hi my name is $f.name and I am $f.age years old!")
+
+ func get_older(f:&Foo):
+ f.age += 1
+...
+my_foo := Foo("Alice", 28)
+my_foo:greet()
+my_foo:get_older()
+```
+
+Method calls work when the first argument is the struct type or a pointer to
+the struct type.
diff --git a/docs/tables.md b/docs/tables.md
new file mode 100644
index 00000000..f4753efb
--- /dev/null
+++ b/docs/tables.md
@@ -0,0 +1,294 @@
+# Tables
+
+Tables are Tomo's associative mapping structure, also known as a Dictionary or
+Map. Tables are efficiently implemented as a hash table that preserves
+insertion order and has fast access to keys and values as array slices. Tables
+support *all* types as both keys and values.
+
+Tables do not support square bracket indexing (`t[key]`), but instead rely on
+the methods `:get(key)` and `:set(key, value)`. This is explicit to avoid
+hiding the fact that table lookups and table insertion are performing function
+calls and have edge conditions like a failure to find an entry.
+
+## Syntax
+
+Tables are written using `{}` curly braces with `:` colons associating key
+expressions with value expressions and commas between entries:
+
+```tomo
+table := {"A": 10, "B": 20}
+```
+
+Empty tables must specify the key and value types explicitly:
+
+```tomo
+empty := {:Text:Int}
+```
+
+For type annotations, a table that maps keys with type `K` to values of type
+`V` is written as `{K:V}`.
+
+### Comprehensions
+
+Similar to arrays, tables can use comprehensions to dynamically construct tables:
+
+```tomo
+t := {i: 10*i for i in 10}
+t := {i: 10*i for i in 10 if i mod 2 == 0}
+t := {-1:-10, i: 10*i for i in 10}
+```
+
+### Fallback Tables
+
+Tables can specify a fallback table that is used when looking up a value if it
+is not found in the table itself:
+
+```tomo
+t := {"A": 10}
+t2 := {"B": 20; fallback=t}
+>> t2:get("A")
+= 10
+```
+
+The fallback is available by the `.fallback` field, which returns an optional
+readonly pointer to the fallback table (if present) or null if it is not.
+
+## Length
+
+Table length can be accessed by the `.length` field:
+
+```tomo
+>> {"A":10, "B":20}.length
+= 2
+```
+
+## Accessing Keys and Values
+
+The keys and values of a table can be efficiently accessed as arrays using a
+constant-time immutable slice of the internal data from the table:
+
+```tomo
+t := {"A": 10, "B": 20}
+>> t.keys
+= ["A", "B"]
+>> t.values
+= [10, 20]
+```
+
+## Iteration
+
+You can iterate over the key/value pairs in a table like this:
+
+```tomo
+for key, value in table:
+ ...
+
+for key in table:
+ ...
+```
+
+Table iteration operates over the value of the table when the loop began, so
+modifying the table during iteration is safe and will not result in the loop
+iterating over any of the new values.
+
+## Table Methods
+
+### `bump`
+
+**Description:**
+Increments the value associated with a key by a specified amount. If the key is
+not already in the table, its value will be assumed to be zero.
+
+**Usage:**
+```markdown
+bump(t:{K:V}, key: K, amount: Int = 1) -> Void
+```
+
+**Parameters:**
+
+- `t`: The mutable reference to the table.
+- `key`: The key whose value is to be incremented.
+- `amount`: The amount to increment the value by (default: 1).
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+>> t := {"A":1}
+t:bump("A")
+t:bump("B", 10)
+>> t
+= {"A": 2, "B": 10}
+```
+
+---
+
+### `clear`
+
+**Description:**
+Removes all key-value pairs from the table.
+
+**Usage:**
+```markdown
+t:clear() -> Void
+```
+
+**Parameters:**
+
+- `t`: The mutable reference to the table.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+>> t:clear()
+```
+
+---
+
+### `get`
+
+**Description:**
+Retrieves the value associated with a key, or returns a default value if the key is not present.
+
+**Usage:**
+```markdown
+t:get(key: K, default: V) -> V
+```
+
+**Parameters:**
+
+- `t`: The table.
+- `key`: The key whose associated value is to be retrieved.
+- `default`: The value to return if the key is not present. If this argument is
+ not provided, a runtime error will be created if the key is not present.
+
+**Returns:**
+The value associated with the key or the default value if the key is not found.
+
+**Example:**
+```markdown
+>> t := {"A":1, "B":2}
+>> t:get("A")
+= 1
+
+>> t:get("xxx", 0)
+= 0
+```
+
+---
+
+### `get_or_null`
+
+**Description:**
+Retrieves the value associated with a key, or returns `null` if the key is not present.
+This method is only available on tables whose values are pointers.
+
+**Usage:**
+```markdown
+t:get_or_null(key: K) -> @V?
+```
+
+**Parameters:**
+
+- `t`: The table.
+- `key`: The key whose associated value is to be retrieved.
+
+**Returns:**
+A mutable reference to the value associated with the key or `null` if the key is not found.
+
+**Example:**
+```markdown
+>> t := {"A": @[10]}
+>> t:get_or_null("A")
+= @[10]?
+>> t:get_or_null("xxx")
+= !@[Int]
+```
+
+---
+
+### `has`
+
+**Description:**
+Checks if the table contains a specified key.
+
+**Usage:**
+```markdown
+has(t:{K:V}, key: K) -> Bool
+```
+
+**Parameters:**
+
+- `t`: The table.
+- `key`: The key to check for presence.
+
+**Returns:**
+`yes` if the key is present, `no` otherwise.
+
+**Example:**
+```markdown
+>> {"A":1, "B":2}:has("A")
+= yes
+>> {"A":1, "B":2}:has("xxx")
+= no
+```
+
+---
+
+### `remove`
+
+**Description:**
+Removes the key-value pair associated with a specified key.
+
+**Usage:**
+```markdown
+remove(t:{K:V}, key: K) -> Void
+```
+
+**Parameters:**
+
+- `t`: The mutable reference to the table.
+- `key`: The key of the key-value pair to remove.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+t := {"A":1, "B":2}
+t:remove("A")
+>> t
+= {"B": 2}
+```
+
+---
+
+### `set`
+
+**Description:**
+Sets or updates the value associated with a specified key.
+
+**Usage:**
+```markdown
+set(t:{K:V}, key: K, value: V) -> Void
+```
+
+**Parameters:**
+
+- `t`: The mutable reference to the table.
+- `key`: The key to set or update.
+- `value`: The value to associate with the key.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+t := {"A": 1, "B": 2}
+t:set("C", 3)
+>> t
+= {"A": 1, "B": 2, "C": 3}
+```
diff --git a/docs/text.md b/docs/text.md
new file mode 100644
index 00000000..70708fe4
--- /dev/null
+++ b/docs/text.md
@@ -0,0 +1,778 @@
+# Text
+
+`Text` is Tomo's datatype to represent text. The name `Text` is used instead of
+"string" because Tomo represents text as an immutable UTF-8-encoded value that
+uses the Boehm Cord library for efficient storage and concatenation. These are
+_not_ C-style NULL-terminated character arrays. GNU libunistring is used for
+full Unicode functionality (grapheme cluster counts, capitalization, etc.).
+
+## Syntax
+
+Text has a flexible syntax designed to make it easy to hold values from
+different languages without the need to have lots of escape sequences and
+without using printf-style string formatting.
+
+```
+// Basic text:
+str := "Hello world"
+str2 := 'Also text'
+str3 := `Backticks too`
+```
+
+## Line Splits
+
+Long text can be split across multiple lines by having two or more dots at the
+start of a new line on the same indentation level that started the text:
+
+```
+str := "This is a long
+....... line that is split in code"
+```
+
+## Multi-line Text
+
+Multi-line text has indented (i.e. at least one tab more than the start of the
+text) text inside quotation marks. The leading and trailing newline are
+ignored:
+
+```
+multi_line := "
+ This text has multiple lines.
+ Line two.
+
+ You can split a line
+.... using two or more dots to make an elipsis.
+
+ Remember to include whitespace after the elipsis if desired.
+
+ Or don't if you're splitting a long word like supercalifragilisticexpia
+....lidocious
+
+ This text is indented by one level in the text
+
+ "quotes" are ignored unless they're at the same indentation level as the
+.... start of the text.
+
+ The end (no newline after this).
+"
+```
+
+## Text Interpolations
+
+Inside double quoted text, you can use a dollar sign (`$`) to insert an
+expression that you want converted to text. This is called text interpolation:
+
+```
+// Interpolation:
+my_var := 5
+str := "My var is $my_var!"
+// Equivalent to "My var is 5!"
+
+// Using parentheses:
+str := "Sum: $(1 + 2)"
+// equivalent to "Sum: 3"
+```
+
+Single-quoted text does not have interpolations:
+
+```
+// No interpolation here:
+str := 'Sum: $(1 + 2)'
+```
+
+## Text Escapes
+
+Unlike other languages, backslash is *not* a special character inside of text.
+For example, `"x\ny"` has the characters `x`, `\`, `n`, `y`, not a newline.
+Instead, a series of character escapes act as complete text literals without
+quotation marks:
+
+```
+newline := \n
+crlf := \r\n
+quote := \"
+```
+
+These text literals can be used as interpolation values with or without
+parentheses, depending on which you find more readable:
+
+```
+two_lines := "one$(\n)two"
+has_quotes := "some $\"quotes$\" here"
+```
+
+However, in general it is best practice to use multi-line text to avoid these problems:
+
+```
+str := "
+ This has
+ multiple lines and "quotes" too!
+"
+```
+
+### Multi-line Text
+
+There are two reasons for text to span multiple lines in code: either you
+have text that contains newlines and you want to represent it without `\n`
+escapes, or you have a long single-line text that you want to split across
+multiple lines for readability. To support this, you can use newlines inside of
+text with indentation-sensitivity. For splitting long lines, use two or more
+"."s at the same indentation level as the start of the text literal:
+
+```
+single_line := "This is a long text that
+... spans multiple lines"
+```
+For text that contains newlines, you may put multiple indented lines inside
+the quotes:
+
+```
+multi_line := "
+ line one
+ line two
+ this line is indented
+ last line
+"
+```
+
+Text may only end on lines with the same indentation as the starting quote
+and nested quotes are ignored:
+
+```
+multi_line := "
+ Quotes in indented regions like this: " don't count
+"
+```
+
+If there is a leading or trailing newline, it is ignored and not included in
+the text.
+
+```
+str := "
+ one line
+"
+
+>>> str == "one line"
+=== yes
+```
+
+Additional newlines *are* counted though:
+
+```
+str := "
+
+ blank lines
+
+"
+
+>>> str == "{\n}blank lines{\n}"
+```
+
+### Customizable `$`-Text
+
+Sometimes you might need to use a lot of literal `$`s or quotation marks in
+text. In such cases, you can use the more customizable form of text. The
+customizable form lets you explicitly specify which character to use for
+interpolation and which characters to use for delimiting the text.
+
+The first character after the `$` is the custom interpolation character, which
+can be any of the following symbols: `~!@#$%^&*+=\?`. If none of these
+characters is used, the default interpolation character is `$`. Since this is
+the default, you can disable interpolation altogether by using `$` here (i.e. a
+double `$$`).
+
+The next thing in a customizable text is the character used to delimit the
+text. The text delimiter can be any of the following symbols: `` "'`|/;([{< ``
+If the text delimiter is one of `([{<`, then the text will continue until a
+matching `)]}>` is found, not terminating unless the delimiters are balanced
+(i.e. nested pairs of delimiters are considered part of the text).
+
+Here are some examples:
+
+```
+$"Equivalent to normal text with dollar interps: $(1 + 2)"
+$@"The same, but the AT symbol interpolates: @(1 + 2)"
+$$"No interpolation here, $ is just a literal character"
+$|This text is pipe-delimited, so it can have "quotes" and 'single quotes' and interpolates with dollar sign: $(1+2)|
+$(This text is parens-delimited, so you can have (nested) parens without ending the text)
+$=[This text is square-bracket delimited [which can be nested] and uses equals for interps: =(1 + 2)]
+$@/look ma, regex literals!/
+```
+
+When text is delimited by matching pairs (`()`, `[]`, `{}`, or `<>`), they
+can only be closed by a matched closing character at the same indentation
+level, ignoring nested pairs:
+
+```
+$$(Inside parens, you can have (nested ()) parens no problem)
+$$"But only (), [], {}, and <> are matching pairs, you can't have nested quotes"
+$$(
+ When indented, an unmatched ) won't close the text
+ An unmatched ( won't mess things up either
+ Only matching pairs on the same indentation level are counted:
+)
+$$(Multi-line text with nested (parens) and
+.. line continuation)
+```
+
+As a special case, when you use the same character for interpolation and text
+delimiting, no interpolations are allowed:
+
+```
+plain := $""This text has {no interpolations}!"
+```
+
+**Note:** Normal doubly quoted text with no dollar sign (e.g. `"foo"`) are a
+shorthand for `${}"foo"`. Singly quoted text with no dollar sign (e.g.
+`'foo'`) are shorthand for `$''foo'`.
+
+## Operations
+
+### Concatenation
+
+Concatenation in the typical case is an O(1) operation: `"{x}{y}"` or `x ++ y`.
+
+Because text concatenation is typically an O(1) operation, there is no need for
+a separate "string builder" class in the language and no need to use an array
+of text fragments.
+
+### Text Length
+
+Text length is an ambiguous term in the context of UTF-8 text. There are
+several possible meanings, so each of these meanings is split into a separate
+method:
+
+- Number of grapheme clusters: `text:num_clusters()`. This is probably what
+ you want to use, since it corresponds to the everyday notion of "letters".
+- Size in bytes: `text:num_bytes()`
+- Number of unicode codepoints: `text:num_codepoints()` (you probably want to
+ use clusters, not codepoints in most applications)
+
+Since the typical user expectation is that text length refers to "letters,"
+the `#` length operator returns the number of grapheme clusters, which is the
+closest unicode equivalent to "letters."
+
+### Iteration
+
+Iteration is *not* supported for text because of the ambiguity between bytes,
+codepoints, and grapheme clusters. It is instead recommended that you
+explicitly iterate over bytes, codepoints, graphemes, words, lines, etc:
+
+### Equality, Comparison, and Hashing
+
+All text is compared and hashed using unicode normalization. Unicode provides
+several different ways to represent the same text. For example, the single
+codepoint `U+E9` (latin small e with accent) is rendered the same as the two
+code points `U+65 U+301` (latin small e, acute combining accent) and has an
+equivalent linguistic meaning. These are simply different ways to represent the
+same "letter." In order to make it easy to write correct code that takes this
+into account, Tomo uses unicode normalization for all text comparisons and
+hashing. Normalization does the equivalent of converting text to a canonical
+form before performing comparisons or hashing. This means that if a table is
+created that has text with the codepoint `U+E9` as a key, then a lookup with
+the same text but with `U+65 U+301` instead of `U+E9` will still succeed in
+finding the value because the two texts are equivalent under normalization.
+
+
+# Text Functions
+
+## `as_c_string`
+
+**Description:**
+Converts a `Text` value to a C-style string.
+
+**Usage:**
+```tomo
+as_c_string(text: Text) -> CString
+```
+
+**Parameters:**
+
+- `text`: The text to be converted to a C-style string.
+
+**Returns:**
+A C-style string (`CString`) representing the text.
+
+**Example:**
+```tomo
+>> "Hello":as_c_string()
+= CString("Hello")
+```
+
+---
+
+## `bytes`
+
+**Description:**
+Converts a `Text` value to an array of bytes.
+
+**Usage:**
+```tomo
+bytes(text: Text) -> [Int8]
+```
+
+**Parameters:**
+
+- `text`: The text to be converted to bytes.
+
+**Returns:**
+An array of bytes (`[Int8]`) representing the text.
+
+**Example:**
+```tomo
+>> "Amélie":bytes()
+= [65_i8, 109_i8, 101_i8, -52_i8, -127_i8, 108_i8, 105_i8, 101_i8]
+```
+
+---
+
+## `character_names`
+
+**Description:**
+Returns a list of character names from the text.
+
+**Usage:**
+```tomo
+character_names(text: Text) -> [Text]
+```
+
+**Parameters:**
+
+- `text`: The text from which to extract character names.
+
+**Returns:**
+A list of character names (`[Text]`).
+
+**Example:**
+```tomo
+>> "Amélie":character_names()
+= ["LATIN CAPITAL LETTER A", "LATIN SMALL LETTER M", "LATIN SMALL LETTER E", "COMBINING ACUTE ACCENT", "LATIN SMALL LETTER L", "LATIN SMALL LETTER I", "LATIN SMALL LETTER E"]
+```
+
+---
+
+## `clusters`
+
+**Description:**
+Breaks the text into a list of unicode graphical clusters. Clusters are what
+you typically think of when you think of "letters" or "characters". If you're
+in a text editor and you hit the left or right arrow key, it will move the
+cursor by one graphical cluster.
+
+**Usage:**
+```tomo
+clusters(text: Text) -> [Text]
+```
+
+**Parameters:**
+
+- `text`: The text to be broken into graphical clusters.
+
+**Returns:**
+A list of graphical clusters (`[Text]`) within the text.
+
+**Example:**
+```tomo
+>> "Amélie":clusters()
+= ["A", "m", "é", "l", "i", "e"] : [Text]
+```
+
+---
+
+## `codepoints`
+
+**Description:**
+Returns a list of Unicode code points for the text.
+
+**Usage:**
+```tomo
+codepoints(text: Text) -> [Int32]
+```
+
+**Parameters:**
+
+- `text`: The text from which to extract Unicode code points.
+
+**Returns:**
+A list of Unicode code points (`[Int32]`).
+
+**Example:**
+```tomo
+>> "Amélie":codepoints()
+= [65_i32, 109_i32, 101_i32, 769_i32, 108_i32, 105_i32, 101_i32] : [Int32]
+```
+
+---
+
+## `from_c_string`
+
+**Description:**
+Converts a C-style string to a `Text` value.
+
+**Usage:**
+```tomo
+from_c_string(str: CString) -> Text
+```
+
+**Parameters:**
+
+- `str`: The C-style string to be converted.
+
+**Returns:**
+A `Text` value representing the C-style string.
+
+**Example:**
+```tomo
+>> Text.from_c_string(CString("Hello"))
+= "Hello"
+```
+
+---
+
+## `has`
+
+**Description:**
+Checks if the `Text` contains a target substring.
+
+**Usage:**
+```tomo
+has(text: Text, target: Text, where: Where = Where.Anywhere) -> Bool
+```
+
+**Parameters:**
+
+- `text`: The text to be searched.
+- `target`: The substring to search for.
+- `where`: The location to search (`Where.Anywhere` by default). This can
+ also be `Start` or `End`.
+
+**Returns:**
+`yes` if the target substring is found, `no` otherwise.
+
+**Example:**
+```tomo
+>> "hello world":has("wo")
+= yes
+>> "hello world":has("wo", where=Start)
+= no
+>> "hello world":has("he", where=Start)
+= yes
+```
+
+---
+
+## `join`
+
+**Description:**
+Joins a list of text pieces with a specified glue.
+
+**Usage:**
+```tomo
+join(glue: Text, pieces: [Text]) -> Text
+```
+
+**Parameters:**
+
+- `glue`: The text used to join the pieces.
+- `pieces`: The list of text pieces to be joined.
+
+**Returns:**
+A single `Text` value with the pieces joined by the glue.
+
+**Example:**
+```tomo
+>> ", ":join(["one", "two", "three"])
+= "one, two, three"
+```
+
+---
+
+## `lower`
+
+**Description:**
+Converts all characters in the text to lowercase.
+
+**Usage:**
+```tomo
+lower(text: Text) -> Text
+```
+
+**Parameters:**
+
+- `text`: The text to be converted to lowercase.
+
+**Returns:**
+The lowercase version of the text.
+
+**Example:**
+```tomo
+>> "AMÉLIE":lower()
+= "amélie"
+```
+
+---
+
+## `num_bytes`
+
+**Description:**
+Returns the number of bytes used by the text.
+
+**Usage:**
+```tomo
+num_bytes(text: Text) -> Int
+```
+
+**Parameters:**
+
+- `text`: The text to measure.
+
+**Returns:**
+The number of bytes used by the text.
+
+**Example:**
+```tomo
+>> "Amélie":num_bytes()
+= 8
+```
+
+---
+
+## `num_clusters`
+
+**Description:**
+Returns the number of clusters in the text.
+
+**Usage:**
+```tomo
+num_clusters(text: Text) -> Int
+```
+
+**Parameters:**
+
+- `text`: The text to measure.
+
+**Returns:**
+The number of clusters in the text.
+
+**Example:**
+```tomo
+>> "Amélie":num_clusters()
+= 6
+```
+
+---
+
+## `num_codepoints`
+
+**Description:**
+Returns the number of Unicode code points in the text.
+
+**Usage:**
+```tomo
+num_codepoints(text: Text) -> Int
+```
+
+**Parameters:**
+
+- `text`: The text to measure.
+
+**Returns:**
+The number of Unicode code points in the text.
+
+**Example:**
+```tomo
+>> "Amélie":num_codepoints()
+= 7
+```
+
+---
+
+## `quoted`
+
+**Description:**
+Formats the text as a quoted string.
+
+**Usage:**
+```tomo
+quoted(text: Text, color: Bool = no) -> Text
+```
+
+**Parameters:**
+
+- `text`: The text to be quoted.
+- `color`: Whether to add color formatting (default is `no`).
+
+**Returns:**
+The text formatted as a quoted string.
+
+**Example:**
+```tomo
+>> "one$(\n)two":quoted()
+= "\"one\\ntwo\""
+```
+
+---
+
+## `replace`
+
+**Description:**
+Replaces occurrences of a pattern in the text with a replacement string.
+
+**Usage:**
+```tomo
+replace(text: Text, pattern: Text, replacement: Text, limit: Int = -1) -> Text
+```
+
+**Parameters:**
+
+- `text`: The text in which to perform replacements.
+- `pattern`: The substring to be replaced.
+- `replacement`: The text to replace the pattern with.
+- `limit`: The maximum number of replacements (default is `-1`, meaning no limit).
+
+**Returns:**
+The text with occurrences of the pattern replaced.
+
+**Example:**
+```tomo
+>> "Hello world":replace("world", "there")
+= "Hello there"
+
+>> "xxxx":replace("x", "y", limit=2)
+= "yyxx"
+```
+
+---
+
+## `split`
+
+**Description:**
+Splits the text into a list of substrings based on a delimiter.
+
+**Usage:**
+```tomo
+split(text: Text, split: Text) -> [Text]
+```
+
+**Parameters:**
+
+- `text`: The text to be split.
+- `split`: The delimiter used to split the text.
+
+**Returns:**
+A list of substrings resulting from the split.
+
+**Example:**
+```tomo
+>> "one,two,three":split(",")
+= ["one", "two", "three"]
+```
+
+---
+
+## `title`
+
+**Description:**
+Converts the text to title case (capitalizing the first letter of each word).
+
+**Usage:**
+```tomo
+title(text: Text) -> Text
+```
+
+**Parameters:**
+
+- `text`: The text to be converted to title case.
+
+**Returns:**
+The text in title case.
+
+**Example:**
+```tomo
+>> "amélie":title()
+= "Amélie"
+```
+
+---
+
+## `trimmed`
+
+**Description:**
+Trims characters from the beginning and end of the text.
+
+**Usage:**
+```tomo
+trimmed(text: Text, trim: Text = " {\n\r\t}", where: Where = Where.Anywhere) -> Text
+```
+
+**Parameters:**
+
+- `text`: The text to be trimmed.
+- `trim`: The set of characters to remove (default is `" {\n\r\t}"`).
+- `where`: Specifies where to trim (`Where.Anywhere` by default).
+
+**Returns:**
+The trimmed text.
+
+**Example:**
+```tomo
+>> " xxx ":trimmed()
+= "xxx"
+
+>> "xxyyxx":trimmed("x", where=Start)
+= "yyxx"
+```
+
+---
+
+## `upper`
+
+**Description:**
+Converts all characters in the text to uppercase.
+
+**Usage:**
+```tomo
+upper(text: Text) -> Text
+```
+
+**Parameters:**
+
+- `text`: The text to be converted to uppercase.
+
+**Returns:**
+The uppercase version of the text.
+
+**Example:**
+```tomo
+>> "amélie":upper()
+= "AMÉLIE"
+```
+
+---
+
+## `without`
+
+**Description:**
+Removes all occurrences of a target substring from the text.
+
+**Usage:**
+```tomo
+without(text: Text, target: Text, where: Where = Where.Anywhere) -> Text
+```
+
+**Parameters:**
+
+- `text`: The text from which to remove substrings.
+- `target`: The substring to remove.
+- `where`: The location to remove the target (`Where.Anywhere` by default).
+
+**Returns:**
+The text with occurrences of the target removed.
+
+**Example:**
+```tomo
+>> "banana":without("na")
+= "ba"
+>> "banana":without("na", where=End)
+= "bana"
+```
diff --git a/docs/threads.md b/docs/threads.md
new file mode 100644
index 00000000..228fc8ac
--- /dev/null
+++ b/docs/threads.md
@@ -0,0 +1,111 @@
+# Threads
+
+Tomo supports POSIX threads (pthreads) through the `Thread` type. The
+recommended practice is to have each thread interact with other threads only
+through thread-safe Channels with no other shared data.
+
+## Thread Methods
+
+### `new`
+
+**Description:**
+Creates a new thread to execute a specified function.
+
+**Usage:**
+```tomo
+Thread.new(fn: func() -> Void) -> Thread
+```
+
+**Parameters:**
+
+- `fn`: The function to be executed by the new thread.
+
+**Returns:**
+A new `Thread` object representing the created thread.
+
+**Example:**
+```tomo
+>> jobs := |Int|
+>> results := |Int|
+>> thread := Thread.new(func():
+ while yes:
+ input := jobs:get()
+ results:give(input + 10
+)
+= Thread<0x12345678>
+>> jobs:give(10)
+>> results:get()
+= 11
+```
+
+---
+
+### `cancel`
+
+**Description:**
+Requests the cancellation of a specified thread.
+
+**Usage:**
+```tomo
+cancel(thread: Thread) -> Void
+```
+
+**Parameters:**
+
+- `thread`: The thread to cancel.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```tomo
+>> thread:cancel()
+```
+
+---
+
+### `join`
+
+**Description:**
+Waits for a specified thread to terminate.
+
+**Usage:**
+```tomo
+join(thread: Thread) -> Void
+```
+
+**Parameters:**
+
+- `thread`: The thread to join.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```tomo
+>> thread:join()
+```
+
+---
+
+### `detach`
+
+**Description:**
+Detaches a specified thread, allowing it to run independently.
+
+**Usage:**
+```tomo
+detach(thread: Thread) -> Void
+```
+
+**Parameters:**
+
+- `thread`: The thread to detach.
+
+**Returns:**
+Nothing.
+
+**Example:**
+```tomo
+>> thread:detach()
+```