From 67e8f2dea0d4eec20a839d47f1fa6302a4a5f733 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Mon, 19 Aug 2024 00:23:02 -0400 Subject: Move docs into one folder --- api/README.md | 68 --- api/arrays.md | 797 ------------------------------- api/booleans.md | 65 --- api/channels.md | 181 ------- api/enums.md | 88 ---- api/integers.md | 368 --------------- api/nums.md | 1374 ------------------------------------------------------ api/pointers.md | 133 ------ api/ranges.md | 65 --- api/sets.md | 356 -------------- api/structs.md | 39 -- api/tables.md | 294 ------------ api/text.md | 778 ------------------------------- api/threads.md | 111 ----- docs/README.md | 78 ++++ docs/arrays.md | 797 +++++++++++++++++++++++++++++++ docs/booleans.md | 65 +++ docs/channels.md | 181 +++++++ docs/enums.md | 88 ++++ docs/integers.md | 368 +++++++++++++++ docs/nums.md | 1374 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/pointers.md | 133 ++++++ docs/ranges.md | 65 +++ docs/sets.md | 356 ++++++++++++++ docs/structs.md | 39 ++ docs/tables.md | 294 ++++++++++++ docs/text.md | 778 +++++++++++++++++++++++++++++++ docs/threads.md | 111 +++++ 28 files changed, 4727 insertions(+), 4717 deletions(-) delete mode 100644 api/README.md delete mode 100644 api/arrays.md delete mode 100644 api/booleans.md delete mode 100644 api/channels.md delete mode 100644 api/enums.md delete mode 100644 api/integers.md delete mode 100644 api/nums.md delete mode 100644 api/pointers.md delete mode 100644 api/ranges.md delete mode 100644 api/sets.md delete mode 100644 api/structs.md delete mode 100644 api/tables.md delete mode 100644 api/text.md delete mode 100644 api/threads.md create mode 100644 docs/README.md create mode 100644 docs/arrays.md create mode 100644 docs/booleans.md create mode 100644 docs/channels.md create mode 100644 docs/enums.md create mode 100644 docs/integers.md create mode 100644 docs/nums.md create mode 100644 docs/pointers.md create mode 100644 docs/ranges.md create mode 100644 docs/sets.md create mode 100644 docs/structs.md create mode 100644 docs/tables.md create mode 100644 docs/text.md create mode 100644 docs/threads.md diff --git a/api/README.md b/api/README.md deleted file mode 100644 index a7fe1262..00000000 --- a/api/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# API - -Tomo has a small number of built-in functions and bunch of types. - -## Types - -- [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/api/arrays.md b/api/arrays.md deleted file mode 100644 index 0453feb6..00000000 --- a/api/arrays.md +++ /dev/null @@ -1,797 +0,0 @@ -# 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/api/booleans.md b/api/booleans.md deleted file mode 100644 index 7d2c29a4..00000000 --- a/api/booleans.md +++ /dev/null @@ -1,65 +0,0 @@ -# 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/api/channels.md b/api/channels.md deleted file mode 100644 index 88cb46ff..00000000 --- a/api/channels.md +++ /dev/null @@ -1,181 +0,0 @@ -# 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/api/enums.md b/api/enums.md deleted file mode 100644 index 4123fbc4..00000000 --- a/api/enums.md +++ /dev/null @@ -1,88 +0,0 @@ -# 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/api/integers.md b/api/integers.md deleted file mode 100644 index 653322fd..00000000 --- a/api/integers.md +++ /dev/null @@ -1,368 +0,0 @@ -# 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/api/nums.md b/api/nums.md deleted file mode 100644 index 5b258010..00000000 --- a/api/nums.md +++ /dev/null @@ -1,1374 +0,0 @@ -# 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/api/pointers.md b/api/pointers.md deleted file mode 100644 index ee7a5d8f..00000000 --- a/api/pointers.md +++ /dev/null @@ -1,133 +0,0 @@ -# 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/api/ranges.md b/api/ranges.md deleted file mode 100644 index 4771bd58..00000000 --- a/api/ranges.md +++ /dev/null @@ -1,65 +0,0 @@ -# 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/api/sets.md b/api/sets.md deleted file mode 100644 index 850d1443..00000000 --- a/api/sets.md +++ /dev/null @@ -1,356 +0,0 @@ -# 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/api/structs.md b/api/structs.md deleted file mode 100644 index 4ab78fed..00000000 --- a/api/structs.md +++ /dev/null @@ -1,39 +0,0 @@ -# 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/api/tables.md b/api/tables.md deleted file mode 100644 index f4753efb..00000000 --- a/api/tables.md +++ /dev/null @@ -1,294 +0,0 @@ -# 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/api/text.md b/api/text.md deleted file mode 100644 index 70708fe4..00000000 --- a/api/text.md +++ /dev/null @@ -1,778 +0,0 @@ -# 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/api/threads.md b/api/threads.md deleted file mode 100644 index 228fc8ac..00000000 --- a/api/threads.md +++ /dev/null @@ -1,111 +0,0 @@ -# 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() -``` 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() +``` -- cgit v1.2.3