We are currently working on new rules for what content should and shouldn't be allowed on this website, and are looking for feedback! See Esolang:2026 topicality proposal to view and give feedback on the current draft.

WhatLang

From Esolang
Jump to navigation Jump to search
WhatLang
Designed by User:YufangTSTSU, User:DGCK81LNN
Appeared in 2024
Memory system Stack-based with named global variables
Computational class Turing-complete
Reference implementation TypeScript
File extension(s) .what

WhatLang is a stack-based programming language created by User:YufangTSTSU (Yufang) in June 2024 and currently maintained by User:DGCK81LNN, who adapted the language as part of LNNBot.

WhatLang's first interpreter, aka. the Koishi runtime, is written in TypeScript and can be installed as a 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 '¿'. The Koishi runtime has a built-in help@ function which documents the language in Chinese.

DGCK81LNN published the core interpreter as an npm package with a Node.js exeutable what. The ability to read from stdin and interact with the filesystem are not yet added.

DGCK81LNN also created another runtime, known as WhatServer, which lives inside the web console of a Koishi instance and handles any HTTP request whose path begins with /what. It notably supports WhatNoter and WhatCommands but lacks most other Koishi runtime-specific functions.

Yufang has been working on a revamped version of WhatLang which will introduce Latin-1 Supplement characters as new instructions, a new Map data type and local variables, but with several breaking changes to the language.

Mechanics

WhatLang has four types of values: String, Number (64-bit floating point including NaN), Array, and Undefined. Strings and Numbers are immutable; 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 that 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. Functions like send@ and sends@ 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 text fragments, attachments, and message reply (quote) references. Other environments may allow raw byte data to be printed.

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 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. The official implementation uses UTF-16 units, meaning that a character can be either one Unicode BMP character or a pair of UTF-16 surrogates. This is important because different operations will treat Strings containing non-BMP characters differently. For example, len@ counts encoding units, while # iterates Strings by character; arr@ separates the characters in a string, while ""split@ separates encoding units.
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; since v0.4.0, long or deeply nested Arrays are ellipsized.

To convert (coerce) a value into a Number, if it isn't already one:

Value Result
String Tries 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 integers; accepts the "E" syntax (±significandexponent 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; if it contains exactly one element, the result of converting it into a Number; NaN otherwise

Any value other than 0, the empty String and Undefined is truthy. NaN and empty Arrays are notably truthy.

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 Word literal Returns the identifier as a String, converted to lower case.
' followed by one character Char literal Returns the char as a String.

Used to only take a single encoding unit (not allowing non-BMP characters) until v0.3.0.

" delimited text Quoted string literal Returns the text as a String.

Line feeds and character tabulations can be escaped as \n and \t; also supports \r, \f, \v as of v0.2.0. A backslash otherwise forces the next character to be treated literally.

` 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.
  • If the operands are both Arrays or both Strings, they are concatenated.
  • Otherwise if one of the operands is an Array, the other is treated like another Array with just one item, and they are then concatenated.
  • Otherwise if one of the operands is a String, the other will be coerced into a String and they are concatenated.
  • Otherwise if at least one of the operands is NaN or Undefined, the result is NaN.
  • Otherwise the operands are added numerically.

Array concatenation was added in v0.2.2; adding Arrays previously led to undefined behavior.

- * / % Other arithmetic 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 occurrences 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.

[ ] or | ] must be properly paired.

() delimited text (may include nested parens) Parenthesized string literal Returns the literal contents of the parens as a String without parsing escape sequences.
. Print Prints the element at the top of the Stack without popping it.

If the stack is empty, 'undef' is printed.

\ 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, executes the value as WhatLang code (the value must be a String). Otherwise, executes the string as WhatLang code.

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.

> 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 {.

{ } must be properly paired.

One or more consecutive !s Break, return or halt Breaks out of the same number of levels of nested { } as the number of !s, and continues after the corresponding }. If there are more !s than the nested levels of { }, quits the current execution, which means ending the calling @ instruction, continuing to the next iteration of #, or halting 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. Strings were not supported prior to v0.2.0.

, 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.

Prior to v0.2.0, Strings were quoted and escaped, and Arrays whose items are all Strings containing exactly one encoding unit were simply joined together to form a String (for empty Arrays the result was the empty String).

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. Prior to v0.2.0, the number of characters was reported 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.

As of v0.2.1, if separator is an Array, it is understood as a regular expression like in match@, each match adding the matched substrings of every capture group to the results.

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@ without copying it.

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. 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. 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 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 can be a literal String or an Array specifying a JavaScript Regular Expression like in match@.

string and replacement 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").
b64@ Pops 1 value, which must be an Array of Numbers which are understood as bytes. Returns the Base64 representation of this sequence of bytes.

Added in v0.3.3.

nb64@ Pops 1 value, coerced into a String, and returns the result of decoding it from Base64 into an Array of Bytes.

Added in v0.3.3. Before decoding, any non-Base64 characters and equal signs are ignored, then the string is padded with equal signs until its length is a multiple of 4.

utf8@ Pops 1 value, coerced into a String. Returns an Array of byte Numbers that represent this string in UTF-8.

Added in v0.3.3.

nutf8@ Pops 1 value, which must be an Array of Numbers which are understood as bytes. Returns the result of decoding this sequence as UTF-8 into a String.

Added in v0.3.3.

Common extension

Most of these function used to be Koishi runtime specific but may be available in other environments.

Function Description
you@ Returns a String containing information about the current runtime environment. For the Koishi runtime it is "WhatLang/2024 Environment/messaging Framework/koishi Platform/platform Id/id" where platform is the id of the current messaging platform and id is the platform-defined user ID String of the bot. Custom information can be added between "Framework" and "Platform" using the Koishi plugin configuration, which is by convention Brand/botName.

Added to the Koishi runtime on June 22, 2025.

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 User: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 pr@.

ca@ Similar to cat@ but returns the response body as an Array of byte Numbers.

Added to WhatServer as catb@ on May 14, 2025, then renamed ca@ on May 29, 2025, meaning cat@ without decoding the body as text. Added to the Koishi runtime on June 22, 2025.

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.

Added on June 3, 2025.

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.

Added on June 3, 2025. The name means fetch@ without decoding the body as text.

reesc@ Pops 1 value, coerced into a String, 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; added to WhatServer as outb@ on May 14, 2025, then renamed ou@ on May 29, 2025. The name is in analogy with ca@ and fech@, removing a letter t from "out" to mean outputting bytes instead of text.

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 help@ function.

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:
  • index 0: contents of the message in XML as a String
  • index 1: platform-defined ID of the message as a String
  • index 2: username of the user who sent the message, as a String
  • index 3: platform-defined ID of the user as a String
  • index 4: ID of the user in Koishi's database as a Number
  • index 5: platform-defined ID of the current channel, as a String
  • index 6: platform-defined ID of the message that this message quotes / is replying to, or Undefined if none

This function is available in WhatServer but the values have different meanings due to the nature of WhatServer, though they attempt to be compatible:

  • index 0: request method and url, for example, GET /whatfoo/bar. URL-encoded characters without special meanings in the url are decoded.
  • index 1: random String
  • index 2 and 3: client IP address
  • index 4: ID of the user in Koishi's database as a Number if the request is authenticated using the X-Lnnbot-Whatserver-Login-Token request header, or Undefined
  • index 5: "__WHATSERVER__"
  • index 6: Undefined
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. (Animation is not currently supported yet)

The first 2 items in the Array are the width and height of the <svg> element. Each following item should be an Array that defines an element, where the first item is a String indicating its type, the second item is a String specifying its style attribute, and the remaining items specifies other properties depending on type.

  • path or p indicates a <path> element. It accepts the d attribute as the third item in the Array.
  • text or t indicates a <text> element. It accepts the x, y attributes and the content text as the 3rd, 4th and 5th items in the Array.
  • img or i indicates an <image> element. It accepts the x, y, width, height and href attributes as the 3rd through 7th items in the Array.
outhtml@ Pops 1 value, coerced into a String, renders its content as HTML and prints the result as an image.

Added on Oct 3, 2025.
It is currently not possible to generate Wikipedia-style tables using the "class=wikitable" shortcut, because outhtml@ does not support Javascript. The developers are trying hard to fix this problem.

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.
findmsg@ 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.

getmsg@ Pops id, which must be a String, and returns the details of the message with this ID as an Array (see me@).
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 IDs of users in Koishi's database. 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 natural 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 natural Number. Returns the public note content of that user id.
noterd@ Pops uid, which must be a natural 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.

WhatServer specific

Function Description
hset@ Pops key and value, which must be Strings, and sets the value of response header named key to value.

In addition to builtin functions, a WhatServer environment also has the pre-defined variables reqh, reqm and reqb, which store the request headers (Array of key-value pairs of Strings), method and body (String, Array of byte Numbers or Undefined depending on method and Content-Type).

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@
  • 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.
  • 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)]\,\_@
  • 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]\,\_
  • Push value into Array (assuming Array at top of Stack): len@ value ; or nan@ value ;
  • Comment: 0{ comment } or (comment)_

Examples

Some programs here are prefixed with ¿ since that's how you usually invoke the interpreter bot on a messaging platform.

Hello, world!
¿`Hello, world!`
Quine
¿(`¿(`.`) `.) `¿(`.`) `.

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 program Get 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 — the actual Cat program
¿pr@ [(&lt;) g](<)repl@ [(&gt;) g](>)repl@ [(&amp;) 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:

Show current time

Simple one that outputs something like "Current UTC time: Tue at 9:34":

time@ 60000/: 60/:                         (Calculate Unix epoch minutes and hours)_
24/ flr@ 4+ 7%                             (Divide by 24 and floor for days, add 4 becaude 1970-01-01 is Thursday)_
["Sun""Mon""Tue""Wed""Thu""Fri""Sat"]\,\_  (Map to name)_
"Current UTC time: "\+" at "+\             (Add text before and after)_
flr@ 24% ':++\                             (Floor hours and mod by 24, append that and a colon to the text)_
flr@ 60% :9?1?{ '0\+ !} +                  (Floor minutes and mod by 60, add a zero if it's not greater than 9, and append it to the text)_
.                                          (Output the final text)_

Calculate Gregorian date and time with custom timezone offset:

(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.

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 sent 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@@
Sorting algorithm

A bubble sort:

(
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=_

External resources