Standard Library π±
The core of Mewlix's standard library is the std
yarn ball. _(:3γβ )_
It contains functions for string and shelf manipulation, type conversion and basic mathematical operations.
Implicit Import
All Mewlix yarn balls implicitly import the std
yarn ball by default. To keep this from happening, use the --no-std
compiler flag or add no-std
in the 'flags' field of your project file.
Table of Contents
Shelves and Strings
A collection of functions for manipulating shelves and stringsβmost work on both!
std.purr
type: (any) -> string
Converts any value to a string.
std.cat
type: ([any]) -> string
Converts all values in a shelf to strings and concatenates them in 'reverse' order: Each value is appended to the start of an accumulator string. As shelves are a LIFO data structure, that means std.cat([a, b]) == a .. b
.
It's named after the standard Unix utility 'cat'.
This function can be used to build strings:
["Cats have ", 10 - 1, " lives!"] |> std.cat -- "Cats have 9 lives!"
Although you should prefer to use yarn-strings instead:
:3"Cats have [10 - 1] lives!" -- "Cats have 9 lives!"
And the two really shine best together:
std.cat([
:3"I like [x]!\n",
:3"I like [y]!\n",
:3"I also like [z]!\n",
])
std.trim
type: (string) -> string
Trims any whitespace at the start and end of a string.
std.tear
type: (string, number, number) -> string
Gets a substring from a string. It expects the following arguments:
- The original string.
- The start index.
- The end index; non-inclusive.
std.tear("cat", 1, 2) -- "a"
std.tear("esoteric", 0, 3) -- "eso"
std.push_down
type: (string) -> string
Converts a string to all lowercase.
std.push_up
type: (string) -> string
Converts a string to all uppercase.
std.poke
type: <π±>([π±], number) -> π±
type: (string, number) -> string
Looks up an index in a shelf or string. Indices start at 0.
For shelves, a lookup starts at the top of the shelf. This means std.poke(shelf, 0) == paw at shelf
.
Note: While this function's time complexity for strings is O(1), its time complexity for shelves is O(n) due to how shelves work.
It accepts the following arguments:
- A shelf or string.
- A numeric index.
Additionally, this function has special behavior based on the index:
- When index is greater than the string/shelf's length, this function returns
nothing
. - When index is negative, lookup starts from the end of the string / the bottom of the shelf.
std.poke(["c", "a", "t"], 0) -- "t"
std.poke("cat", 0) -- "c"
std.poke(["c", "a", "t"], 1) -- "a"
std.poke("cat", 1) -- "a"
std.poke(["c", "a", "t"], -1) -- "c"
std.poke("cat", -1) -- "t"
std.nuzzle
type: (any) -> boolean
Converts any value to a boolean. Its rules are simple:
- When passed a truthy value, it returns
true
. - When passed a falsey value, it returns
false
.
In practice, all values in Mewlix are truthy except for false
and nothing
.
Read the documentation page for truthy values and type conversion to learn more.
std.empty
type: <π±>([π±]) -> boolean
type: (string) -> boolean
Checks if a shelf or string is empty and returns true
if it is.
std.join
type: <π±>([π±], [π±]) -> [π±]
type: (string, string) -> string
Concatenates two strings or two shelves together. Values must be of the same type.
The time complexity of this function is O(n)
.
std.join([1, 2, 3], [4, 5, 6]) -- [1, 2, 3, 4, 5, 6]
std.join("foo", "foo") -- "foofoo"
std.take
type: <π±>([π±], number) -> [π±]
type: (string, number) -> string
Takes a number of items from the top of a shelf, or a number of characters from the start of a string.
It expects the following arguments:
- A shelf or a string value.
- A number defining the amount of items to take.
std.take([1, 2, 3, 4], 2) -- [4, 3]
std.take('hello world', 5) -- 'hello'
std.drop
type: <π±>([π±], number) -> [π±]
type: (string, number) -> string
Drops a number of items from the top of a shelf, or a number of characters from the start of a string.
It expects the following arguments:
- A shelf or a string value.
- A number defining the amount of items to drop.
std.drop([1, 2, 3, 4], 2) -- [1, 2]
std.take('hello world', 5) -- ' world'
std.reverse
type: ([π±]) -> [π±]
type: (string) -> string
Reverses a shelf or a string.
std.insert
type: <π±>([π±], π±, number?) -> [π±]
Inserts a value into a shelf at an index.
Note: As shelves are a LIFO data structure, this function's time complexity is O(n).
It expects the following arguments:
- A shelf.
- A value of any type to be inserted.
- A numeric index specifying where the value should be inserted.
Additionally, this function has special behavior based on the index:
- When the index isn't specified, it defaults to
0
. - When the index is greater than the shelf's length, the value is inserted at the bottom of the shelf.
- When the index is negative, selection starts from the bottom of the shelf.
std.insert([1, 2, 3], 4, 0) -- [1, 2, 3, 4]
std.insert([1, 2, 3], 4, 1) -- [1, 2, 4, 3]
std.insert([1, 2, 3], 4, -1) -- [4, 1, 2, 3]
std.insert([1, 2, 3], 4, -2) -- [1, 4, 2, 3]
std.remove
type: <π±>([π±], number?) -> [π±]
Remove an item from a shelf at an index.
Note: As shelves are a LIFO data structure, this function's time complexity is O(n).
It expects the following arguments:
- A shelf.
- A numeric index specifying the index of the item to be removed.
Additionally, this function has special behavior based on the index:
- When the index isn't specified, it defaults to
0
. - When the index is greater than the shelf's length, nothing happens.
- When the index is negative, selection starts from the bottom of the shelf.
std.remove([1, 2, 3, 4], 0) -- [1, 2, 3]
std.remove([1, 2, 3, 4], 1) -- [1, 2, 4]
std.remove([1, 2, 3, 4], -1) -- [2, 3, 4]
std.remove([1, 2, 3, 4], -2) -- [1, 3, 4]
std.sort
type: <π±>([π±]) -> [π±]
Sorts a shelf.
Note: The shelf should contain only values of types that can be compared:
- numbers
- strings
- booleans
- shelves containing values that can be compared
Note: The function's time complexity depends on the underlying JavaScript engine's implementation of Array.prototype.sort()
. In most widely used JavaScript engines, it should be O(n log n)
.
std.sort([3, 4, 1, 2, 6, 5]) -- [1, 2, 3, 4, 5, 6]
std.sort(["c", "a", "t"]) -- ["a", "c", "t"]
std.sort([true, false, true]) -- [false, true, true]
std.shuffle
type: <π±>([π±]) -> [π±]
Shuffles the items in a shelf. This function's time complexity is O(n).
std.shuffle([1, 2, 3, 4, 5, 6]) -- [6, 3, 1, 4, 2, 5]
std.map
type: <π±,π¦>((π±) -> π¦, [π±]) -> [π¦]
Applies a function to each item in a shelf, returning a new shelf.
It expects the following arguments:
- A function to apply to each item in a shelf.
- A shelf.
std.map(π (x) -> x * x, [1, 2, 3]) -- [1, 4, 9]
std.filter
type: <π±>((π±) -> boolean, [π±]) -> [π±]
Filters elements in the shelf by a predicate. Returns a new shelf.
It expects the following arguments:
- A predicate function.
- A shelf.
std.filter(π (x) -> x % 2 == 0, [1, 2, 3, 4]) -- [2, 4]
std.fold
type: <π±,π¦>((π¦, π±) -> π¦, π¦, [π±]) -> [π¦]
Folds over a shelf. Akin to Haskell's foldl
and JavaScript's Array.prototype.reduce()
.
It expects the following arguments:
- A function accepting two arguments: the accumulator value and a shelf item, respectively.
- An initial value for the accumulator.
- A shelf to fold over.
A fold is a little hard to explain concisely, so I won't bother to explain it here. There are plenty of good resources for it online. Here's the Wikipedia page on folds!
std.fold(π (acc, x) -> acc + x, 0, [1, 2, 3]) -- 6
std.find
type: <π±>((π±) -> boolean, [π±]) -> number | nothing
Find a value in a shelf using a predicate.
This function expects the following arguments:
- A predicate function.
- A shelf.
It returns the index of the first value that satisfies the predicate.
If no value satisfies the predicate, this function returns nothing
.
std.any
type: <π±>((π±) -> boolean, [π±]) -> boolean
Asks if any item in the shelf satisfies a predicate.
This function expects the following arguments:
- A predicate function.
- A shelf.
If the shelf is empty, this function returns false
.
std.all
type: <π±>((π±) -> boolean, [π±]) -> boolean
Asks if all items in the shelf satisfy a predicate.
This function expects the following arguments:
- A predicate function.
- A shelf.
If the shelf is empty, this function returns true
.
std.zip
type: <π±,π¦>([π±], [π¦]) -> [box]
Zip two shelves together into a shelf of tuples. Akin to Haskell's zip
.
std.zip([1, 2], [3, 4]) -- [π¦ [ first: 1, second: 3 ], π¦ [ first: 2, second: 4 ]]
std.foreach
type: <π±>((π±) -> any, [π±]) -> nothing
Apply a function to each item in a shelf. This function is similar to std.map, but it discards results instead of storing them in a shelf.
This function expects the following arguments:
- A function to be called for each item.
- A shelf.
std.repeat
type: <π±>((number?) -> π±, number) -> [π±]
Invoke a function n
times, storing the return values in a shelf.
This function expects the following arguments:
- A function to be invoked. This function may accept an optional numerical argument: the number of times the function has been called so far.
- A number indicating how many times the function should be invoked.
std.sequence
type: ((number?) -> nothing, number) -> nothing
Invoke a function n
times. It works like std.repeat, but discards return values.
It accepts the same arguments as std.repeat.
std.char
type: (number) -> string
Converts a numeric value representing a UTF-16 code unit to a single-character string.
If the numeric value is outside of the range 0 <= value <= 65535
, an exception is thrown.
std.bap
type: (string) -> number
Returns a numeric value representing the first UTF-16 code unit in the string.
It calls JavaScript's String.prototype.charCodeAt method under the hood.
Bits and Bytes
std.itty
type: (number) -> number
Bitwise not.
std.bitty
type: (number, number) -> number
Bitwise or.
std.kitty
type: (number, number) -> number
Bitwise and.
std.to_bytes()
type: (string) -> [number]
Encode a string to a shelf of bytes (UTF-8).
std.from_bytes()
type: ([number]) -> string
Decode a shelf of bytes (UTF-8) to a string.
Collections
A collection of functions for creating... collections!
Most functions in this category return a box.
std.tuple
type: <π±,π¦>(π±, π¦) -> box
Create a box holding two items, stored as .first
and .second
respectively.
std.tuple(1, 2) -- π¦ [ first: 1, second: 2 ]
std.table
type: () -> table
Create a magic box that behaves like an associative array. It can be used to to store key-value pairs, and is affectionately nicknamed a 'table'.
It has the following methods:
Name | Type | Description |
---|---|---|
add | (any, any) -> table | Adds a key-value pair to the table. |
has | (any) -> boolean | Asks if the table has a given key in it. |
get | (any) -> any | Looks up a key on the table. Returns nothing if none is found. |
remove | (any) -> table | Remove a key-value pair from the table. |
clear | () -> table | Clears the table, removing all key-value pairs. |
The .add
method can be chained to initialize a table:
mew table = std.table() \
.add("one" , 1) \
.add("two" , 2) \
.add("three", 3)
std.set
type: () -> set
Create a magic box that behaves like a set. It can be used to store unique values.
It has the following methods:
Name | Type | Description |
---|---|---|
add | (any) -> set | Adds a value to the set. |
has | (any) -> boolean | Asks if the set contains a value. |
remove | (any) -> set | Removes a value from the set (if it exists). |
clear | () -> set | Clears the set, removing all values. |
The .add()
method can be chained to initialize a set:
mew set = std.set() \
.add("one") \
.add("two") \
.add("three")
Numbers
A collection of functions for manipulating number values.
std.slap
type: (any) -> number
Converts a value to a number. It has a special behavior for each type:
- Numeric values are returned without changes, as you would expect.
- Boolean values are always successfully converted:
true
is 1,false
is 0. - Strings are parsed. If a string can be parsed as a number, that number is returned. An exception is thrown otherwise.
- Any other value results in an exception being thrown.
std.round
type: (number) -> number
Rounds a number to its nearest integer.
std.floor
type: (number) -> number
Rounds down a number.
std.ceiling
type: (number) -> number
Rounds up a number.
std.min
type: (number, number) -> number
Returns the smallest of two numbers.
std.max
type: (number, number) -> number
Returns the biggest of two numbers.
std.clamp
type: (number, number, number) -> number
Clamps a number to a minimum and a maximum value. It expects the following arguments:
- A number to clamp.
- A minimum value.
- A maximum value.
std.clamp(30, 0, 20) -- 10
std.clamp(-2, 0, 20) -- 0
std.clamp(10, 0, 20) -- 10
std.abs
type: (number) -> number
Returns the absolute value of a number.
std.pi
type: number
A constant representing the mathematical constant Pi.
std.e
type: number
A constant representing Euler's number.
std.sqrt
type: (number) -> number
Calculates the square root of a given number.
This function expects a number greater or equal to zero.
std.logn
type: (number, number?) -> number
Calculates the logarithm of a number to a given base.
This function expects the following arguments:
- A number greater than 0.
- An optional numeric argument defining the base for the logarithm.
If the second argument is omitted, base e is used.
Note: Not to be confused with std.log!
std.sin
type: (number) -> number
Returns the sine of an angle. It expects the following arguments:
- An angle, in radians.
std.cos
type: (number) -> number
Returns the cosine of an angle. It expects the following arguments:
- An angle, in radians.
std.tan
type: (number) -> number
Returns the tangent of an angle. It expects the following arguments:
- An angle, in radians.
std.asin
type: (number) -> number
Returns the arcsine (in radians) of a number.
std.acos
type: (number) -> number
Returns the arccosine (in radians) of a number.
std.atan
type: (number) -> number
Returns the arctangent (in radians) of a number.
std.atan2
type: (number, number) -> number
The 2-argument arctangent function.
It expects the following arguments:
- A
y
coordinate. - A
x
coordinate.
std.truncate
type: (number, number?) -> number
Truncates a floating point number, returning its integer part.
It expects the following arguments:
- A number.
- An optional numeric argument specifying the number of decimal places to preserve.
The second argument, if present, should be greater or equal to 0. It defaults to 0.
std.truncate(3.14159) -- 3
std.truncate(3.14159, 2) -- 3.14
std.random
type: () -> number
Generates a random number x between 0 and 1, where 0 <= x < 1.
std.random_int
type: (number, number) -> number
Generates a random integer number between two numbers. It expects the following arguments:
- A 'min' value.
- A 'max' value.
This function will generate a random integer x such that min <= x <= max.
Thus, 'min' and 'max' are both inclusive.
std.count
type: (number, number?) -> [number]
Generates a shelf holding a sequence of numbers.
It behaves differently based on its number of arguments:
- When given a single argument
a
, it generates a sequence of numbers starting at 0 untila
. - When given two arguments,
a
andb
, it generates a sequence of numbers starting ata
and ending inb
.
As shelves are a last in, first out data structure, std.count
creates shelves in such a way where the starting number for the sequence is always at the top of the shelf.
std.count(3) -- [3, 2, 1, 0]
std.count(1, 3) -- [3, 2, 1]
std.count(3, 1) -- [1, 2, 3]
std.count(1, 1) -- [1]
Note: This function expects its arguments to be whole numbers. Any floating point arguments are rounded down:
std.count(3.2) == std.count(3)
Storage
A set of functions for reading from and writing to local storage.
std.read
type: (string) -> string?
Read a value from local storage associated with a given string key.
If the key isn't found in local storage, this function returns nothing
.
std.save
type: (string, string) -> string
Saves a key in local storage with a value associated with it.
If the key already exists, its value is overwritten.
IO
A set of functions for interacting with the outside world.
std.meowf
type: (any) -> string
A function wrapper around the meow
expression.
std.date
type: () -> box
Returns the current date and time as a box.
The returned box will always have the following fields:
- day: The current weekday represented as a number from 1 to 7, where 1 is Sunday and 7 is Saturday.
- month: The current month represented as a number from 1 to 12, where 1 is January and 12 is December.
- year: The current year, as a number.
- hours: The hours elapsed in the day, as a number, from 0 to 23. At 6 PM, this field's value would be 18, for example.
- minutes: The minutes elapsed in the current hour, as a number. At 6:30 PM, this field's value would be 30, for example.
- seconds: The seconds elapsed in the current minute, as a number. At 6:30:12 PM, this field's value would be 12, for example.
This function's implementation uses JavaScript's Date constructor.
std.time
type: () -> number
Returns the time elapsed since the epoch, in milliseconds.
All it does is call JavaScript's Date.now() static method.
JSON
A set of functions for JSON serialization and deserialization.
std.to_json
type: (any) -> string
Serializes a Mewlix value to JSON.
A few details to note:
- Shelves are serialized as JSON arrays.
- Boxes are serialized as JSON objects.
std.from_json
type: (string) -> any
Parses a JSON string to a valid Mewlix value.
A few details to note:
- JSON arrays become shelves.
- JSON objects become boxes.
Debugging
A section for functions meant to make debugging a little easier.
The functions in this section aren't meant to be used for anything other than debugging.
std.log
type: (any) -> nothing
Logs a value to the debugging console, if any exists.
Note: Not to be confused with std.logn!
std.error
type: box
A box containing numeric constants for every error code, intended to make error handling a little simpler.
See the documentation on error handling to learn more.