WhatLang
WhatLang is a stack-based programming language created by User:YufangTSTSU (Yufang).
Written in TypeScript, its first interpreter can be installed as a private (not published on npm) plugin for Koishi.js, a bot framework for QQ and other instant messaging platforms, and used by invoking the bot command whatlang
or simply sending the code prefixed with a '¿
'.
Currently there exist web ports of the WhatLang interpreter that can be used in a browser; however, these ports do not include Koishi related functions, and currently do not provide other means of reading input from the user yet. There is also a standalone interpreter published on npm which comes with a Node.js exeutable wl
; the ability to read from standard input and interact with the filesystem are yet to be added, though.
Yufang is currently working on a revamped version of WhatLang, known as WhatLang 2025, which will introduce Latin-1 Supplement characters as new instructions, a new Map data type and local variables, but also make several breaking changes to the language.
Mechanics
WhatLang has four types of values: String, Number (64-bit float including NaN), Array, and Undefined. If two occurences of Strings have the same content, they are the same String. Arrays are mutable, have a variable length, and can hold mixed types of values.
The virtual machine has an internal stack of stacks, known as the Frame Stack. The topmost stack on the Frame Stack, aka. the Stack, is the one that your code usually interacts with. Values are pushed to and read / popped from the top of the Stack. When using the [
or |
instruction to create / edit an Array, the Array is pushed onto the Frame Stack, temporarily becoming the Stack; upon executing the ]
instruction, it is popped from the Frame Stack and pushed back onto the previous Stack as an Array. The conversion from an Array to a Stack, or vice versa, does not make it a new object, which means that if you duplicate the reference to an Array, edit it with | ]
, changes are reflected in other references to the Array.
The virtual machine also has an internal dict which stores named variables.
In some runtimes there also exists an internal Output Stack. Each time something is printed, it is pushed onto the Output Stack. send@
, sends@
or sendsto@
can then be used to pop items from the Output Stack and flush them. When the program ends, all remaining items in the Output Stack are output together. In the Koishi runtime, the Output Stack can hold fragments of text, attachments, and message reply (quote) references. Other environments may allow raw byte data to be printed besides text.
For the purpose of this documentation:
- Popping from the Stack when it is already empty yields Undefined.
- When popping multiple values, they are listed from bottom to top.
- To return something means to push it onto the Stack.
- To execute a String func with a value argument, create a shallow copy of the current Stack called tempstack; push argument and func onto it, and run the
@
instruction on it. Then, the Result of execution is the topmost value in tempstack, or Undefined if it is now empty. - Strings sometimes behave like Arrays of small Strings. Usually the items of a String are each of its characters; however in some operations, the items of a String are each of its encoding units. An encoding unit, depending on implementation, can be a character or a UTF-16 unit. Typical implementations define an encoding unit as a UTF-16 unit, meaning that a character can be either one Unicode BMP character or a pair of UTF-16 surrogates. This is important because in these implementations, different operations treat Strings containing non-BMP characters differently.
len@
, for example, counts encoding units, but#
iterates Strings by character. - If something "must" satisfy a certain constraint, unless otherwise noted, the interpreter's behavior is undefined when it does not; throwing an error is preferred, but current implementations might not do so.
- Type conversion
To convert (coerce) a value into a String, if it isn't already one, it is formatted in a human-readable way. Strings are quoted and escaped. Numbers are formatted precisely in decimal notation. Undefined becomes "undef"
. Arrays have their items formatted, separated with commas and enclosed in square brackets; implementations might ellipsize long, deeply nested, and/or circular referencing Arrays.
To convert (coerce) a value into a Number, if it isn't already one:
Value | Result |
---|---|
String | Try to parse the contents as a Number after trimming any leading or trailing whitespace. Accepts the prefixes "0b", "0o" and "0x" for binary, octal and hexadecimal unsigned integers; accepts the "E" syntax (±significandE±exponent where "E" can be upper or lower case and positive signs can be omitted) for scientific notation; does not allow thousands separators. NaN if the String cannot be parsed |
Undefined | NaN |
Array | 0 if the Array is empty; the result of converting its element into a Number if contains exactly one element; NaN otherwise |
Any value other than 0, the empty String and Undefined is truthy. NaN is considered truthy, unlike in JavaScript. Some implementations may consider empty Arrays falsey.
Instructions
Instruction | Name | Description |
---|---|---|
0
|
Zero | Returns 0. |
A 1-9 digit followed by zero or more 0-9 digits | Positive integer literal | Returns the literal Number. |
An ASCII letter, followed by zero or more ASCII alphanumerics and/or underscores | Identifier string literal | Returns the identifier as a String, converted to lower case. |
' followed by one char (encoding unit)
|
Char literal | Returns the char as a String. |
" delimited text
|
Quoted string literal | Returns the text as a String.
Line feeds and character tabulations can be escaped as |
` delimited text
|
Literal print | Similar to a " delimited string, but prints the string without doing anything with the Stack.
|
+
|
Add or concat | Pops a and b from the Stack and returns their sum.
Note that Array concatenation is only supported in very recent implementations; adding an Array with any value used to cause undefined behavior. |
- * / %
|
Other arithmatic operations | Pops a and b from the Stack, coerced into Numbers, and returns a <operator> b. |
?
|
Compare | Pops a and b from the Stack. If they are loosely equal (== in JavaScript; two occurences of Arrays need to be the same Array to be considered equal), returns 0; if a is greater than b, returns 1; if a is less than b, returns -1; otherwise, returns NaN.
|
~
|
Logical not | Pops 1 value from the Stack. If it is falsey, returns 1; otherwise returns 0. |
[
|
New Stack | Starts a new empty Stack. |
|
|
Open Stack | Pops 1 value from the Stack: an error is thrown if it is not an Array; otherwise makes it the Stack. |
]
|
Close Stack | Turns the current Stack into an Array, goes back to the previous Stack and returns the Array.
|
() delimited text (may include nested parens)
|
Parenthesized string literal | Returns the literal contents of the parens as a String. |
.
|
Prints the element at the top of the Stack without popping it.
If the stack is empty, ' | |
\
|
Swap | Swaps the topmost two elements in the Stack.
Does nothing if the Stack contains less than 2 values. |
:
|
Duplicate | Pushes the Stack's topmost element onto the Stack again.
Does not copy Arrays; a reference to the same Array is pushed. Does nothing if the Stack is empty. |
&
|
Bury | Pops 1 value from the Stack, then inserts it at the bottom of the Stack.
Does nothing if the Stack is empty. |
_
|
Pop | Pops and discards the topmost value from the Stack. |
=
|
Set named variable | Pops 1 value from the Stack, which must be a String. Sets the value of the variable named this string to the topmost remaining element of the Stack, or Undefined if there is none left. |
^
|
Get named variable | Pops 1 value from the Stack, which must be a String. If a variable named this string exists, returns its value. Otherwise, if the string is the name of a builtin function, returns the string plus "@" . Otherwise, returns Undefined.
|
@
|
Call or eval | Pops 1 value from the Stack, which must be a String. If the string is the name of a builtin function, calls the function. Otherwise, if the string is the name of an existing variable[2], executes the value as WhatLang code (the value must be a String). Otherwise, executes the string as WhatLang code. |
>
|
Gather | Pops n from the Stack, coerced into a Number which must be an integer. Removes the topmost n elements from the Stack, then returns a new Array containing the removed elements.
If n is zero or negative, gathers all but the bottommost |n| elements instead. |
<
|
Spread | Pops 1 value from the Stack and pushes each of its elements onto the Stack.
The value must be either an Array or a String, otherwise an error is thrown. |
{
|
While loop start | Pops 1 value from the Stack. If it is falsey, jumps to the corresponding } .
|
}
|
While loop end | Pops 1 value from the Stack. If it is truthy, jumps to the corresponding { .
|
One or more consecutive ! s
|
Break, return or halt | If inside of a { } loop and the number of ! s is less than or equal to the current level of nested braces, breaks out of [number of ! s] levels of loops and continues after the corresponding } . Otherwise, if running inside the @ or # instruction, ends the execution of the current String of code (for # , continues with the next Array item, if any); otherwise halts the program.
|
#
|
Map Array | Pops func from the Stack, which must be a String. For each item in the remaining topmost value a in the Stack, executes function with item. Returns an Array containing the Results of each execution.
a must be an Array or a String, otherwise an error is thrown. Older implementations didn't allow this to be a String, throwing an error if it is. |
,
|
Get Array item | Pops n from the Stack. Returns the item at index n of the Array (or String) at top of Stack.
n is coerced into a Number, which must be an integer. The remaining value at top of Stack must be an Array or a String, otherwise throws an error; if it is a String, its items are its encoding units. A negative index counts backwards from the end of the Array, with -1 being the last element. If the index is out of bounds, the result is Undefined. |
;
|
Set Array item | Pops n and value from the stack. Sets the item at index n to value in the Array at top of Stack.
n must be either NaN or some value that becomes an integer after being converted into a Number. Throws an error if the remaining value at top of Stack is not an Array. A negative index counts backwards from the end of the Array, with -1 being the last element. If n is NaN or is equal to the length of the Array, value is pushed to the end of the Array instead; otherwise if the index is out of bounds, the array is not changed. |
$
|
Delete Array item | Pops n from the stack. Removes the item at index n from the Array at top of Stack.
n is coerced into a Number, which must be an integer. Throws an error if the remaining value at top of Stack is not an Array. A negative index counts backwards from the end of the Array, with -1 being the last element. If the index is out of bounds, the array is not changed. All items following a removed item have their indices decreased by one. |
Builtin functions
Core
Function | Description |
---|---|
num@
|
Pops 1 value, converts it to a Number and returns the result. |
str@
|
Pops 1 value, converts it to a String and returns the result.
Older implementations used to quote and escape the value if it is already a String; or if the value is an Array where every item is a String containing only one encoding unit, older implementations used to simply combine the encoding units into a String. This behavior is deprecated. |
repr@
|
Pops 1 value, and returns a string that tries to recreate the value when executed as WhatLang code. |
arr@
|
Pops 1 value. If it is an Array, returns a shallow copy of it; if it is a String, returns an Array containing each of its characters; otherwise an error is thrown. |
pow@
|
Pops a and b, coerced into Numbers, and returns the result of a ** b. |
band@ bor@ bxor@
|
Popss 2 values, coerced into signed 32-bit integers, and returns the result of performing bitwise AND, OR, or XOR between them, respectively. |
bnot@
|
Pops 1 value, coerced into a signed 32-bit integer, and returns the result of performing bitwise NOT on it. |
rand@
|
Returns a random number between 0 and 1. |
randint@
|
Pops 2 values, coerced into Numbers. Returns a random number between them, rounded down to an integer. |
flr@
|
Pops 1 value, coerced into a Number. Returns the result of rounding it down to an integer. |
range@
|
Pops n, coerced into a Number which must be less than 4294967296. Returns a new Array containing every integer from 0 to n-1 (any fractional part truncated).
Throws an error if n is negative. |
len@
|
Returns the length of the topmost value in the Stack.
The value must be an Array or a String; if it is a String, the result should be the number of encoding units it contains; older implementations incorrectly report the number of characters instead. |
split@
|
Pops string and separator, coerced into Strings. Returns the result of spliting string into an Array of Strings at each occurrence of separator, or an Array containing every encoding unit in string if separator is empty.
If separator is an Array it should be understood as a regular expression like in |
join@
|
Pops separator, coerced into a String. Returns the result of converting every element in the remaining value at top of Stack (must be an Array or a String, otherwise throws an error) into a String, and combining the results into a single String sepatared by separator. |
reverse@
|
Returns a shallow copy of the topmost value in the Stack, converted to an Array, with its items reversed in order. |
in@
|
Pops value. If value is an element in the remaining value at top of Stack (must be an Array or a String, otherwise throws an error), returns the index of its first occurence. Returns -1 otherwise. |
filter@
|
Pops func. For each item in the remaining value at top of Stack (must be an Array or a String, otherwise throws an error), execute func with item. Returns a new Array containing the items for which the Result was truthy. |
chr@
|
Pops 1 value, which can be a single Unicode codepoint number or an Array of codepoint Numbers, and returns a String composed of the characters specified by the codepoint(s).
Items in the input Array, or the input value itself if it is not an Array, are coerced into Numbers. If any given Number is negative or greater than 1114111, an error is thrown. |
ord@
|
Pops 1 value, coerced into a String. Returns an Array containing each character codepoint (or unpaired UTF-16 surrogaate) in the String as a Number. |
and@
|
Pops a and b. If a is the empty String, 0 or undefined, returns a; otherwise returns b. |
or@
|
Pops a and b. If a is the empty String, 0 or undefined, returns b; otherwise returns a. |
nan@
|
Returns NaN. |
undef@
|
Returns Undefined. |
inf@
|
Returns Inf. |
ninf@
|
Returns -Inf. |
eq@
|
Pops 2 values. If they are strictly equal (=== in JavaScript), returns 1; otherwise returns 0.
|
stak@
|
Returns the Stack as an Array. Note that this makes the Stack contain itself.
The name means |
stack@
|
Returns a shallow copy of the Stack as an Array. |
try@
|
Like the @ instruction, but returns a new Array containing the error name and message if a runtime error occurs while executing. If no error occurs, returns an Array containing 2 Undefined's.
|
throw@
|
Pops 1 value, coerced into a String[3]. Throws an error with this value as the message and "Error" as the name.
|
match@
|
Pops string and expression; executes the JavaScript Regular Expression specified by expression and returns the result as an Array of Strings, or an empty Array if no match is found.
string is coerced into a String[4]. If expression is an Array, it is the arguments to JavaScript's RegExp constructor - pattern, and optionally flags; otherwise it is coerced into a String[1] and used as the pattern. An error is thrown if the expression is invalid. If the expression has the g-flag, the resulting Array contains the whole matched strings of each match; Other it contains the whole matched string and the substrings matched by each capture group. |
repl@
|
Pops string, pattern and replacement; substitutes each occurrence of pattern in string with replacement and returns the modified String. pattern[1] can be a literal String or an Array specifying a JavaScript Regular Expression like in match@ .
string[4] and replacement[3] are coerced into Strings. Backreferences are replaced in the replacement string; to avoid this, replace any dollar sign in replacement with two dollar signs. |
time@
|
Returns the current system time in epoch milliseconds. |
type@
|
Pops 1 value; returns its type (one of "String" , "Number" , "Array" , "Undefined" ).
|
Common extension
Most of these function used to be Koishi runtime specific but may be available in other environments.
Function | Description |
---|---|
pr@
|
In the Koishi runtime, returns the contents of the next message from the current user in the current channel. On timeout, returns Undefined.
Generally should be a way to interactively read user input. |
cat@
|
Pops url, which must be a String. Performs an HTTP GET request to this URL and returns the response body text as a String.
If the response has an error status code or there is a network error, an error is thrown. The name of this function originates from the "cat" command of LNNBot (maintained by DGCK81LNN) which optionally takes a URL as input: when the URL is given, it performs an HTTP GET request and outputs the response body; otherwise it outputs the user's next message similarly to |
ca@
|
Similar to cat@ but returns the response body as an Array of byte Numbers.
This function was added recently. The name means |
fetch@
|
Pops method, url, headers, and body. Performs an HTTP request specified by these parameters and returns an Array containing the response status code Number, response status description String, an Array of response header key-value pairs, and response body text as a String.
This function was added recently. method and url must be Strings. headers must be an Array where each element is an Array containing two Strings. If body is an Array, it must contain only Numbers, which are understood as bytes; if it is a Number, it is coerced into a String. For a GET or HEAD request, body must be Undefined. |
fech@
|
Similar to fetch@ but instead of a String, the response body is as an Array of byte Numbers.
This function was added recently. The name means |
reesc@
|
Pops 1 value, coerced into a String[4], and returns the result of escaping all JavaScript Regular Expression metacharacters in this String with backslash sequences. |
sleep@
|
Pops n, coerced into a Number, and sleeps for n seconds.
n must be between 0 and 2147483.647, inclusive. |
nout@
|
Pops and discards the last printed element from the Output Stack. |
nouts@
|
Pops n, coerced into a Number which must be an integer. Removes and discards the top (latest) n elements from the Output Stack.
If n is zero or negative, removes all but the bottom (oldest) |n| elements instead. Inf and -Inf are treated like zero. |
send@
|
Pops 1 element from the Output Stack and sends it immediately. In the Koishi runtime, returns an Array containing the platform-defined ID String of the message sent.
Generally should be a way to flush the topmost item in the Output Stack. |
sends@
|
Pops n, coerced into a Number which must be an integer. Pops the top (latest) n elements from the Output Stack and sends them immediately. In the Koishi runtime, returns an Array containing platform-defined ID Strings of the message(s) sent (usually only one, but there may be more if the platform does not allow the content to fit in one message).
If n is zero or negative, sends all but the bottom (oldest) |n| elements instead. Inf and -Inf are treated like zero. Generally should be a way to flush an arbitrary number of items from the Output Stack. |
ou@
|
Pops a value which must an Array of Numbers and prints it as raw bytes data.
Not present in the Koishi runtime. The name is in analogy with |
Koishi runtime specific
Some of these functions involve messages received by the bot; message contents are Strings in Koishi's XML format.
Function | Description |
---|---|
help@
|
Help function.
Pop 1 value, and returns the contents of the associated help topic as a String.
If the value is the empty String or Undefined, the result is a brief introduction to the language and some instructions on using the |
helpall@
|
Prints a list of the names of (almost) all builtin functions as an image. |
propt@
|
Pops userid. Returns the contents of the next message from any of the specified user(s) in the current channel.
If userid is falsey, messages from all users are accepted. Otherwise it should be one or more platform-defined user IDs. |
prompt@
|
Pops channelid and func. Listens for messages in specified channel(s), and for each message received, executes func with an Array containing the details of the message (see me@ ) until the Result is truthy, then returns the message details Array.
On timeout, returns Undefined. |
me@
|
Returns the details of the message triggering the interpreter, as an Array, which contains:
|
outimg@ outaudio@ outvideo@ outfile@
|
Pops 1 value, which must be a String, and prints an instance of the corresponding type of attachment with this value as its src URL. |
outquote@
|
Pops id, which must be a String, and prints a reference to the message with this ID. |
outat@
|
Pops id, which must be a String, and prints a @mention of the user with this platform-defined ID. |
outimag@
|
Pops 1 value, coerced into a String, renders its content text with a monospaced font and prints the result as an image. |
outksq@
|
Pops 1 value, coerced into a String, renders its content text with the Kreative Square font and prints the result as an image. |
outsvg@
|
Pops 1 value, which must be an Array, and prints the result of rendering the SVG image defined by this Array.
The first 2 items in the Array are the
|
nsend@
|
Pops messageid, which must be a String, and deletes (recalls) the message with this platform-defined ID in the current channel. |
sendsto@
|
Pops channelid, which must be a String, and n, coerced into a Number which must be an integer. Pops elements from the Output Stack as in sends@ and sends them in the channel with platform-defined ID channelid. Return an Array containing platform-defined ID Strings of the message(s) sent.
|
getmsg@
|
Pops func. Reads historical messages in the current channel, and for each message read, executes func with an Array containing the details of the message (see me@ ) until the Result is truthy, then returns the details Array for the last message read.
Can read up to the platform-specific limit or the end of the message history. If still nothing has been returned, returns Undefined. Currently not correctly implemented yet. |
msgbyid@
|
Pops id, which must be a String, and returns the details of the message with this ID as an Array (see me@ ).
Currently not correctly implemented yet. |
guildmem@
|
Pops guildid, which must be a String, and returns an Array of members of the current guild, each represented by an Array containing their username and platform-defined ID as Strings.
The bot needs to have received at least one message from a user for them to appear in the results. |
WhatNoter
This is a feature that provides a simple data storage based on Koishi-defined user IDs. Each user ID has a public note, a protected note and a private note. It is not required that a user with the given ID exists for the public note of that ID to be accessed. Once one of the notes of some user ID is created, other types of note belonging to the same user ID are initialized as the empty String; reading any note of an ID whose notes have never been written to yields Undefined.
Function | Description |
---|---|
notewc@
|
Pops uid, which must be a natrual Number, and str, which must be a String. Sets the public note content of user id uid to str. |
notewd@
|
Pops str, which must be a String. Sets the protected note content of the user triggering the interpreter to str. |
notewe@
|
Pops str, which must be a String. Sets the private note content of the user triggering the interpreter to str. |
noterc@
|
Pops uid, which must be a natrual Number. Returns the public note content of that user id. |
noterd@
|
Pops uid, which must be a natrual Number. Returns the protected note content of that user id. |
notere@
|
Returns the private note content of the user triggering the interpreter. |
WhatCommands
This is a feature that allows you to define custom commands using WhatLang. Each command has a name, a piece of code, a description String and a manual String. Commands can be invoked by either sending a message with the ¿¿
prefix, invoking the bot command whatcmd
, or using WhatLang's cmd@
function. Commands take a single String as input, which can be found at the top of the Stack. For example, given a command named greet
with code `Hello, `.`!`
, sending '¿¿greet my friends
', executing bot command 'whatcmd greet my friends
', and executing WhatLang code '"my friends" greet cmd@
' all produce the output 'Hello, my friends!
'
Commands return a value when invoked with cmd@
, which you can use as an exit status code. It is not accessible when invoking a command using the ¿¿
prefix.
Function | Description |
---|---|
cmdset@
|
Pops code and name, which must be Strings, and sets the code of the command named name to code. |
cmdall@
|
Returns an Array containing the names of all currently defined commands. |
cmdsethelp@
|
Pops str and name, which must be Strings, and sets the manual of the command named name to str. |
cmdseth@
|
Pops str and name, which must be Strings, and sets the description of the command named name to str. |
cmddel@
|
Pops name, which must be a String, and deletes the command with that name. |
cmdget@
|
Pops name, which must be a String, and returns the code of the command with that name, or Undefined if it does not exist. |
cmdgethelp@
|
Pops name, which must be a String, and returns the manual of the command with that name, or Undefined if it does not exist. |
cmdgeth@
|
Pops name, which must be a String, and returns the description of the command with that name, or Undefined if it does not exist. |
cmd@
|
Pops input and name, where name must be a String, and executes the code of the command named name with input and returns the Result.
If the specified command does not exist, older implementations used to return nothing; newer implementations throw an error. |
Practices and idioms
- To initialize a named variable with a literal value:
value name=_
- Pop (
_
) is used because you usually don't need the value in the stack since you have assigned it to your variable. - To define a custom function, simply enclose the code with parenthesis so it is understood as a string, and define it as a variable. The code can optionally pop arguments from the top of the Stack and optionally return one or more values. The function can be invoked by simply writing
functionname@
- Pop (
- To get negative one (or likewise any negative integer):
01-
- To get any real Number, for example, 3×10100:
(3e100)num@
- Represent the number with a String and then use
num@
to convert it into a Number.
- Represent the number with a String and then use
- If block:
condition{ statements !}
- A while loop with a break at the end.
- If-else block:
condition c={ true-branch !} c^~{ false-branch !}
- Alternatively using no variables:
1{ condition{ true-branch !!} false-branch !}
- Alternatively:
condition~[(true-branch)(false-branch)]\,\_@
- Alternatively using no variables:
- Comparison of two values (returns a truthy value when the condition satisfies)
- Loose equal (cmp(a, b) == 0):
?~
- Greater than (cmp(a, b) == 1):
?1?~
- Less than:
?(-1)?~
or\?1?~
- Less than or equal to (cmp(a, b) < 1):
?1\?1?~
- Greater than or equal to (cmp(b, a) < 1):
\?1\?1?~
- Remove the
~
for a negated condition. - Alternatively,
?[equal greater less]\,\_
can be used to implement these comparisons by replacing equal, greater and less with 0's and 1's (or any other value) depending on what you want the result to be in each case, for example,?[1:0]\,\_
for "greater than or equal". Note that when the values are not comparable, it is treated as if they were equal.- To deal with the incomparable, you can add a
2+
in it:?2+[for-incomparable for-less for-equal for-greater]\,\_
- To deal with the incomparable, you can add a
- Loose equal (cmp(a, b) == 0):
- Push value into Array (assuming Array at top of Stack):
len@ value ;
ornan@ value ;
- Comment:
0{ comment }
or(comment)_
Example programs
Some programs here are prefixed with ¿
since that's how you usually invoke the interpreter bot on a messaging platform.
¿`Hello, world!`
¿(`¿(`.`) `.) `¿(`.`) `.
A shorter one using the eval instruction:
¿(`¿(`.`):@`):@
A cheating quine:
¿me@0,.
Another one, translated from Underload code
((¿)S:aSS)(¿)S:aSS
¿((¿)._:repr@._._)(¿)._:repr@._._
Cat programGet random cat image from TheCatAPI
¿(https://api.thecatapi.com/v1/images/search) cat@ ("url":"(.+?)") match@1, outimg@
This utilizes a regular expression and Koishi runtime specific builtin functions.
- Repeat the user's next message — arguably the equivalent of a Cat program in the Koishi runtime
¿pr@ [(<) g](<)repl@ [(>) g](>)repl@ [(&) g](&)repl@ .
This unescapes <>&
in the input before outputting it. Note that it produces unexpected results when the user's message is / contains something like an image or a platform-specific emoji, because those are represented as XML tags.
- Roll a dice (made by Yufang)
¿[ (000,010,000) (001,000,100) (100,010,001) (101,000,101) (101,010,101) (101,101,101) ]( ',split@( [(0)g]' repl@ [(1)g]61496chr@repl@ )#"│\n│"join@ "╭───╮\n│"\+ "│\n╰───╯\n"+ )# 0 6 randint@, outksq@
This results in one of the following:
- Get current datetime
¿ (2>|:&&:&\/flr@:&*-]<)divmod=_ (2>| 3600000*+ 946684800000- 86400000divmod@& 146097divmod@ :5+7%1+& :59- 36524/ flr@ :0?1?~{+0!}_ 36525divmod@ 1461divmod@ :59- 365/ flr@ :0?1?~{+0!}_ 366divmod@ 1\ 1{ :31-:0?(-1)?~{!!} \_\1+\ :29-:0?(-1)?~{!!} \_\1+\ :31-:0?(-1)?~{!!} \_\1+\ :30-:0?(-1)?~{!!} \_\1+\ :31-:0?(-1)?~{!!} \_\1+\ :30-:0?(-1)?~{!!} \_\1+\ :31-:0?(-1)?~{!!} \_\1+\ :31-:0?(-1)?~{!!} \_\1+\ :30-:0?(-1)?~{!!} \_\1+\ :31-:0?(-1)?~{!!} \_\1+\ :30-:0?(-1)?~{!!} \_\1+\ :31-:0?(-1)?~{!!} \_\1+\ 0!}_ 1+ && \4*+ \100*+ \400*+ 2000+& 3600000divmod@ 60000divmod@ 1000divmod@ ])datetime=_ time@ 8 datetime@.
This defines two custom functions, divmod@
and datetime@
, and then calls datetime@
with the current timestamp and a time zone offset (in this case GMT+8). It returns something like [2024, 9, 13, 5, 6, 55, 38, 92]
(the fourth number represents the day of week, where 1 - 7 stand for Monday to Sunday respectively; the last number is the milliseconds), which is then printed.
- maybe a Brainfuck interpreter
¿(code)[ (p^,1+256%p^\;) (p^,1-256%p^\;) (p^1+p=_) (p^1-p=_) (p^,{) (p^,}) (g^len@~{ _`Please input...`send@_pr@ord@reverse@\_g= !} 01-,\|_]_p^\;) (p^,._) ]c=_ arr@( "+-><[],."\in@c^\, )#\_ ""join@\_(999range@(0)#t=\_500p=_[]g=_)\+@
You should replace code
on the first line with your Brainfuck code, and it requires a input to be send as a message whenever it meets ",".
Another one, it wastes memory.
0a=b=[0]l=[0]r=(put code here)arr@((+-<>[].,)\in@[(l^a^l^a^,\_1+255band@;)(l^a^l^a^,\_1-255band@;)(b^1+b=r^len@0;r^b^l^a^,\_;l^a^0;a^1-:0?1+~~*a=)(a^1+a=l^len@0;l^a^r^b^,\_;r^b^0;b^1-:0?1+~~*b=)(l^a^,{)(l^a^,})(l^a^,\_chr@.)(l^a^pr@ord@len@~[(0,\_)(_0)]\,\_@;_)()]\,\_)#()join@@
- yes but why
a range@
can also be implemented as:
¿:{1-!}1>|:{:1-:}]reverse@\_
when reverse@
can be implemented as:
¿:1>|len@:{1-:3>|&,&\]<:}__]
samely that's a len@
:
¿:()#(_1)#\_","+[',g]'+repl@0\+@
and since repl@
requires RegExp, it can't easily be done in WhatLang... so I guess that's it.
Oh and with len@
we can easily do a join@
:
¿2>|\:1>|<]01-,\01-$&&&"(\""\+"\"+)#"+@\_ len@:{1-'|\:{1-\'++\:}!}_@] \""++]<
Just I don't think it's very static.
- sort (bubble)
¿( sort_a= 0sort_i=_ len@ sort_j= sort_k= \_ range@( sort_j^range@( sort_i=_ sort_a^sort_i^, \sort_i^1+,\_?1?~{ sort_a^sort_i^,\sort_i^1+,sort_i^\;\sort_i^1+\;sort_a=_ !} )#_ sort_j^1-sort_j=_ )#__ sort_a^ )sort=_
Only thing is that it's too complex, maybe I'll do a easiler later.
- Another range@ len@ implementation???
range@
:
1>|[]\0\:{&&len@&&&:&;&1-\1+\:}__]<
len@
:
[0]\(__|1+])#_\<
Notes
- ↑ 1.0 1.1 1.2 Current implementations produce unexpected results when this value is Undefined.
- ↑ It is planned that in a future version, variable names will have to begin with an ASCII lowercase letter and contain only ASCII lowercase letters, digits and/or underscores, or they will be interpreted as literal code.
- ↑ 3.0 3.1 Current implementations produce unexpected results when this value is an Array or Undefined.
- ↑ 4.0 4.1 4.2 Current implementations incorrectly throw an error if this value is not a String.