Examine individual changes

Abuse Filter navigation (Home | Recent filter changes | Examine past edits | Abuse log)
Jump to navigation Jump to search

This page allows you to examine the variables generated by the Abuse Filter for an individual change.

Variables generated for this change

VariableValue
Edit count of the user (user_editcount)
119
Name of the user account (user_name)
'DGCK81LNN'
Age of the user account (user_age)
160678874
Page ID (page_id)
20274
Page namespace (page_namespace)
0
Page title (without namespace) (page_title)
'WhatLang'
Full page title (page_prefixedtitle)
'WhatLang'
Action (action)
'edit'
Edit summary/reason (summary)
''
Old content model (old_content_model)
'wikitext'
New content model (new_content_model)
'wikitext'
Old page wikitext, before the edit (old_wikitext)
''''WhatLang''' is a stack-based programming language created by [[User:YufangTSTSU]] (Yufang) in June, 2024. Written in TypeScript, its first interpreter can be installed as a private (not published on ''npm'') plugin for [https://koishi.chat Koishi.js], a bot framework for QQ and other instant messaging platforms, and used by invoking the bot command <code>whatlang</code> or simply sending the code prefixed with a '<code>¿</code>'. 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 [https://www.npmjs.com/package/whatlang-interpreter on npm] which comes with a Node.js exeutable <code>what</code>; the ability to read from standard input and interact with the filesystem are yet to be added, though. The preferred file extension for WhatLang code is <code>.what</code>. 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 <code>[</code> or <code>|</code> instruction to create / edit an Array, the Array is pushed onto the Frame Stack, temporarily becoming the Stack; upon executing the <code>]</code> 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 <code>| ]</code>, 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. <code>send@</code>, <code>sends@</code> or <code>sendsto@</code> 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 <code>@</code> 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. <code>len@</code>, for example, counts ''encoding units'', but <code>#</code> 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 <code>"undef"</code>. 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: {|class="wikitable" ! 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 (±''significand''E±''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 == {|class="wikitable" ! Instruction !! Name !! Description |- | <code>0</code> | 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. |- | <code>'</code> followed by one char ('''encoding unit''') | Char literal | Returns the char as a String. |- | <code>"</code> delimited text | Quoted string literal | Returns the text as a String. Line feeds and character tabulations can be escaped as <code>\n</code> and <code>\t</code>. A backslash otherwise forces the next character to be treated literally. |- | <code>`</code> delimited text | Literal print | Similar to a <code>"</code> delimited string, but prints the string ''without'' doing anything with the Stack. |- | <code>+</code> | 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<ref name="forgot-to-coerce-to-string-undef-only"/> 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. Note that Array concatenation is only supported in very recent implementations; adding an Array with any value used to cause undefined behavior. |- | <code>-</code> <code>*</code> <code>/</code> <code>%</code> | Other arithmatic operations | Pops ''a'' and ''b'' from the Stack, coerced into Numbers, and returns ''a &lt;operator&gt; b''. |- | <code>?</code> | Compare | Pops ''a'' and ''b'' from the Stack. If they are loosely equal (<code>==</code> 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. |- | <code>~</code> | Logical not | Pops 1 value from the Stack. If it is falsey, returns 1; otherwise returns 0. |- | <code>[</code> | New Stack | Starts a new empty Stack. |- | <code><nowiki>|</nowiki></code> | Open Stack | Pops 1 value from the Stack: an error is thrown if it is not an Array; otherwise makes it the Stack. |- | <code>]</code> | Close Stack | Turns the current Stack into an Array, goes back to the previous Stack and returns the Array. <code>[ ]</code> or <code>| ]</code> must be properly paired. |- | <code>()</code> delimited text (may include nested parens) | Parenthesized string literal | Returns the literal contents of the parens as a String. |- | <code>.</code> | Print | Prints the element at the top of the Stack ''without'' popping it. If the stack is empty, '<code>undef</code>' is printed. |- | <code>\</code> | Swap | Swaps the topmost two elements in the Stack. Does nothing if the Stack contains less than 2 values. |- | <code>:</code> | 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. |- | <code>&</code> | Bury | Pops 1 value from the Stack, then inserts it at the bottom of the Stack. Does nothing if the Stack is empty. |- | <code>_</code> | Pop | Pops and discards the topmost value from the Stack. |- | <code>=</code> | 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. |- | <code>^</code> | 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 <code>"@"</code>. Otherwise, returns Undefined. |- | <code>@</code> | 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<ref>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.</ref>, executes the value as WhatLang code (the value must be a String). Otherwise, executes the string as WhatLang code. |- | <code>></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 <nowiki>|</nowiki>''n''<nowiki>|</nowiki> elements instead. |- | <code><</code> | 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. |- | <code>{</code> | While loop start | Pops 1 value from the Stack. If it is falsey, jumps to the corresponding <code>}</code>. |- | <code>}</code> | While loop end | Pops 1 value from the Stack. If it is truthy, jumps to the corresponding <code>{</code>. <code>{ }</code> must be properly paired. |- | One or more consecutive <code>!</code>s | Break, return or halt | If inside of a <code>{ }</code> loop and the number of <code>!</code>s is less than or equal to the current level of nested braces, breaks out of ''[number of <code>!</code>s]'' levels of loops and continues after the corresponding <code>}</code>. Otherwise, if running inside the <code>@</code> or </code>#</code> instruction, ends the execution of the current String of code (for <code>#</code>, continues with the next Array item, if any); otherwise halts the program. |- | <code>#</code> | 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. |- | <code>,</code> | 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. |- | <code>;</code> | 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. |- | <code>$</code> | 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 === {|class="wikitable" ! Function !! Description |- | <code>num@</code> | Pops 1 value, converts it to a Number and returns the result. |- | <code>str@</code> | 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. |- | <code>repr@</code> | Pops 1 value, and returns a string that tries to recreate the value when executed as WhatLang code. |- | <code>arr@</code> | 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. |- | <code>pow@</code> | Pops ''a'' and ''b'', coerced into Numbers, and returns the result of ''a ** b''. |- | <code>band@</code> <code>bor@</code> <code> bxor@</code> | Popss 2 values, coerced into signed 32-bit integers, and returns the result of performing bitwise AND, OR, or XOR between them, respectively. |- | <code>bnot@</code> | Pops 1 value, coerced into a signed 32-bit integer, and returns the result of performing bitwise NOT on it. |- | <code>rand@</code> | Returns a random number between 0 and 1. |- | <code>randint@</code> | Pops 2 values, coerced into Numbers. Returns a random number between them, rounded down to an integer. |- | <code>flr@</code> | Pops 1 value, coerced into a Number. Returns the result of rounding it down to an integer. |- | <code>range@</code> | 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. |- | <code>len@</code> | 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. |- | <code>split@</code> | 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 <code>match@</code>, each match adding the matched substrings of every capture group to the results. However currently no implementation supports this yet. |- | <code>join@</code> | 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''. |- | <code>reverse@</code> | Returns a shallow copy of the topmost value in the Stack, converted to an Array, with its items reversed in order. |- | <code>in@</code> | 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. |- | <code>filter@</code> | 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. |- | <code>chr@</code> | 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. |- | <code>ord@</code> | 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. |- | <code>and@</code> | Pops ''a'' and ''b''. If ''a'' is the empty String, 0 or undefined, returns ''a''; otherwise returns ''b''. |- | <code>or@</code> | Pops ''a'' and ''b''. If ''a'' is the empty String, 0 or undefined, returns ''b''; otherwise returns ''a''. |- | <code>nan@</code> | Returns NaN. |- | <code>undef@</code> | Returns Undefined. |- | <code>inf@</code> | Returns Inf. |- | <code>ninf@</code> | Returns -Inf. |- | <code>eq@</code> | Pops 2 values. If they are strictly equal (<code>===</code> in JavaScript), returns 1; otherwise returns 0. |- | <code>stak@</code> | Returns the Stack as an Array. Note that this makes the Stack contain itself. The name means <code>stack@</code> without '''c'''opying it. |- | <code>stack@</code> | Returns a shallow copy of the Stack as an Array. |- | <code>try@</code> | Like the <code>@</code> 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. |- | <code>throw@</code> | Pops 1 value, coerced into a String<ref name="forgot-to-coerce-to-string">Older implementations produce unexpected results when this value is an Array, Inf, -Inf or Undefined.</ref>. Throws an error with this value as the message and <code>"Error"</code> as the name. |- | <code>match@</code> | 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<ref name="forgot-to-coerce-to-string-throws">Older implementations incorrectly throw an error if this value is not a String.</ref>. 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<ref name="forgot-to-coerce-to-string-undef-only">Older implementations produce unexpected results when this value is Inf, -Inf or Undefined.</ref> 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. |- | <code>repl@</code> | Pops ''string'', ''pattern'' and ''replacement''; substitutes each occurrence of ''pattern'' in ''string'' with ''replacement'' and returns the modified String. ''pattern''<ref name="forgot-to-coerce-to-string-undef-only"/> can be a literal String or an Array specifying a JavaScript Regular Expression like in <code>match@</code>. ''string''<ref name="forgot-to-coerce-to-string-throws"/> and ''replacement''<ref name="forgot-to-coerce-to-string"/> are coerced into Strings. Backreferences are replaced in the replacement string; to avoid this, replace any dollar sign in ''replacement'' with two dollar signs. |- | <code>time@</code> | Returns the current system time in epoch milliseconds. |- | <code>type@</code> | Pops 1 value; returns its type (one of <code>"String"</code>, <code>"Number"</code>, <code>"Array"</code>, <code>"Undefined"</code>). |} === Common extension === Most of these function used to be ''Koishi'' runtime specific but may be available in other environments. {|class="wikitable" ! Function !! Description |- | <code>you@</code> | Returns a String containing information about the current runtime environment. For the Koishi runtime it is <code>"WhatLang/2024 Environment/messaging Framework/koishi Platform/''platform'' Id/''id''"</code> 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 <code>Brand/''botName''</code>. Added on June 22, 2025. |- | <code>pr@</code> | 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. |- | <code>cat@</code> | Pops <var>url</var>, 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 <code>pr@</code>. |- | <code>ca@</code> | Similar to <code>cat@</code> but returns the response body as an Array of byte Numbers. This function was added recently. The name means <code>cat@</code> without decoding the body as '''t'''ext. |- | <code>fetch@</code> | 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. |- | <code>fech@</code> | Similar to <code>fetch@</code> but instead of a String, the response body is as an Array of byte Numbers. This function was added recently. The name means <code>fetch@</code> without decoding the body as '''t'''ext. |- | <code>reesc@</code> | Pops 1 value, coerced into a String<ref name="forgot-to-coerce-to-string-throws"/>, and returns the result of escaping all JavaScript Regular Expression metacharacters in this String with backslash sequences. |- | <code>sleep@</code> | Pops <var>n</var>, coerced into a Number, and sleeps for <var>n</var> seconds. <var>n</var> must be between 0 and 2147483.647, inclusive. |- | <code>nout@</code> | Pops and discards the last printed element from the Output Stack. |- | <code>nouts@</code> | Pops <var>n</var>, coerced into a Number which must be an integer. Removes and discards the top (latest) <var>n</var> elements from the Output Stack. If <var>n</var> is zero or negative, removes all but the bottom (oldest) &#124;<var>n</var>&#124; elements instead. Inf and -Inf are treated like zero. |- | <code>send@</code> | 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. |- | <code>sends@</code> | Pops <var>n</var>, coerced into a Number which must be an integer. Pops the top (latest) <var>n</var> 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 <var>n</var> is zero or negative, sends all but the bottom (oldest) &#124;<var>n</var>&#124; 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. |- | <code>ou@</code> | 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 <code>ca@</code> and <code>fech@</code>, 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. {|class="wikitable" ! Function !! Description |- | <code>help@</code> | 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 <code>help@</code> function. |- | <code>helpall@</code> | Prints a list of the names of (almost) all builtin functions as an image. |- | <code>propt@</code> | 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. |- | <code>prompt@</code> | 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 <code>me@</code>) until the Result is truthy, then returns the message details Array. On timeout, returns Undefined. |- | <code>me@</code> | 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: Koishi-defined ID of the user 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 |- | <code>outimg@</code> <code>outaudio@</code> <code>outvideo@</code> <code>outfile@</code> | 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. |- | <code>outquote@</code> | Pops <var>id</var>, which must be a String, and prints a reference to the message with this ID. |- | <code>outat@</code> | Pops <var>id</var>, which must be a String, and prints a @mention of the user with this platform-defined ID. |- | <code>outimag@</code> | Pops 1 value, coerced into a String, renders its content text with a monospaced font and prints the result as an image. |- | <code>outksq@</code> | Pops 1 value, coerced into a String, renders its content text with the [https://www.kreativekorp.com/software/fonts/ksquare/ Kreative Square] font and prints the result as an image. |- | <code>outsvg@</code> | 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 [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width#svg <code>width</code>] and [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height#svg <code>height</code>] of the <code>&lt;svg&gt;</code> 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 [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/style <code>style</code>] attribute, and the remaining items specifies other properties depending on type. * <code>path</code> or <code>p</code> indicates a [https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path <code>&lt;path&gt;</code>] element. It accepts the [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d <code>d</code>] attribute as the third item in the Array. * <code>text</code> or <code>t</code> indicates a [https://developer.mozilla.org/en-US/docs/Web/SVG/Element/text <code>&lt;text&gt;</code>] element. It accepts the [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x#text <code>x</code>], [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/y#text <code>y</code>] attributes and the content text as the 3rd, 4th and 5th items in the Array. * <code>img</code> or <code>i</code> indicates an [https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image <code>&lt;image&gt;</code>] element. It accepts the [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x#image <code>x</code>], [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/y#image <code>y</code>], [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width#image <code>width</code>], [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height#image <code>height</code>] and [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/href#image <code>href</code>] attributes as the 3rd through 7th items in the Array. |- | <code>nsend@</code> | Pops <var>messageid</var>, which must be a String, and deletes (recalls) the message with this platform-defined ID in the current channel. |- | <code>sendsto@</code> | Pops <var>channelid</var>, which must be a String, and <var>n</var>, coerced into a Number which must be an integer. Pops elements from the Output Stack as in <code>sends@</code> and sends them in the channel with platform-defined ID <var>channelid</var>. Return an Array containing platform-defined ID Strings of the message(s) sent. |- | <code>findmsg@</code> | 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 <code>me@</code>) 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. |- | <code>getmsg@</code> | Pops <var>id</var>, which must be a String, and returns the details of the message with this ID as an Array (see <code>me@</code>). |- | <code>guildmem@</code> | Pops <var>guildid</var>, 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. {|class="wikitable" ! Function !! Description |- | <code>notewc@</code> | 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''. |- | <code>notewd@</code> | Pops ''str'', which must be a String. Sets the protected note content of the user triggering the interpreter to ''str''. |- | <code>notewe@</code> | Pops ''str'', which must be a String. Sets the private note content of the user triggering the interpreter to ''str''. |- | <code>noterc@</code> | Pops ''uid'', which must be a natrual Number. Returns the public note content of that user id. |- | <code>noterd@</code> | Pops ''uid'', which must be a natrual Number. Returns the protected note content of that user id. |- | <code>notere@</code> | 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 <code>¿¿</code> prefix, invoking the bot command <code>whatcmd</code>, or using WhatLang's <code>cmd@</code> function. Commands take a single String as input, which can be found at the top of the Stack. For example, given a command named <code>greet</code> with code <code>`Hello, `.`!`</code>, sending '<code>¿¿greet my friends</code>', executing bot command '<code>whatcmd greet my friends</code>', and executing WhatLang code '<code>"my friends" greet cmd@</code>' all produce the output '<code>Hello, my friends!</code>' Commands return a value when invoked with <code>cmd@</code>, which you can use as an exit status code. It is not accessible when invoking a command using the <code>¿¿</code> prefix. {|class="wikitable" ! Function !! Description |- | <code>cmdset@</code> | Pops ''code'' and ''name'', which must be Strings, and sets the code of the command named ''name'' to ''code''. |- | <code>cmdall@</code> | Returns an Array containing the names of all currently defined commands. |- | <code>cmdsethelp@</code> | Pops ''str'' and ''name'', which must be Strings, and sets the manual of the command named ''name'' to ''str''. |- | <code>cmdseth@</code> | Pops ''str'' and ''name'', which must be Strings, and sets the description of the command named ''name'' to ''str''. |- | <code>cmddel@</code> | Pops ''name'', which must be a String, and deletes the command with that name. |- | <code>cmdget@</code> | Pops ''name'', which must be a String, and returns the code of the command with that name, or Undefined if it does not exist. |- | <code>cmdgethelp@</code> | Pops ''name'', which must be a String, and returns the manual of the command with that name, or Undefined if it does not exist. |- | <code>cmdgeth@</code> | Pops ''name'', which must be a String, and returns the description of the command with that name, or Undefined if it does not exist. |- | <code>cmd@</code> | 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: <code><var>value</var> <var>name</var>=_</code> ** Pop (<code>_</code>) 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 <code><var>functionname</var>@</code> * To get negative one (or likewise any negative integer): <code>01-</code> * To get any real Number, for example, 3&times;10<sup>100</sup>: <code>(3e100)num@</code> ** Represent the number with a String and then use <code>num@</code> to convert it into a Number. * If block: <code><var>condition</var>{ <var>statements</var> !}</code> ** A while loop with a break at the end. * If-else block: <code><var>condition</var> c={ <var>true-branch</var> !} c^~{ <var>false-branch</var> !}</code> ** Alternatively using no variables: <code>1{ <var>condition</var>{ <var>true-branch</var> !!} <var>false-branch</var> !}</code> ** Alternatively: <code><var>condition</var>~[(<var>true-branch</var>)(<var>false-branch</var>)]\,\_@</code> * Comparison of two values (returns a truthy value when the condition satisfies) ** Loose equal (cmp(a, b) == 0): <code>?~</code> ** Greater than (cmp(a, b) == 1): <code>?1?~</code> ** Less than: <code>?(-1)?~</code> or <code>\?1?~</code> ** Less than or equal to (cmp(a, b) < 1): <code>?1\?1?~</code> ** Greater than or equal to (cmp(b, a) < 1): <code>\?1\?1?~</code> ** Remove the <code>~</code> for a negated condition. ** Alternatively, <code>?[<var>equal</var> <var>greater</var> <var>less</var>]\,\_</code> can be used to implement these comparisons by replacing <var>equal</var>, <var>greater</var> and <var>less</var> with 0's and 1's (or any other value) depending on what you want the result to be in each case, for example, <code>?[1:0]\,\_</code> 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 <code>2+</code> in it:<code>?2+[<var>for-incomparable</var> <var>for-less</var> <var>for-equal</var> <var>for-greater</var>]\,\_</code> * Push value into Array (assuming Array at top of Stack): <code>len@ <var>value</var> ;</code> or <code>nan@ <var>value</var> ;</code> * Comment: <code>0{ <var>comment</var> }</code> or <code>(<var>comment</var>)_</code> == Example programs == Some programs here are prefixed with <code>¿</code> 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 <code>((¿)S:aSS)(¿)S:aSS</code> ¿((¿)._:repr@._._)(¿)._:repr@._._ ;<s>Cat program</s> Get random cat image from [https://thecatapi.com 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@ [(&amp;lt;) g](<)repl@ [(&amp;gt;) g](>)repl@ [(&amp;amp;) g](&)repl@ . This unescapes <code>&lt;&gt;&</code> 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: [[File:WhatLang dices.png|300px]] ; 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, <code>divmod@</code> and <code>datetime@</code>, and then calls <code>datetime@</code> with the current timestamp and a time zone offset (in this case GMT+8). It returns something like <code>[2024, 9, 13, 5, 6, 55, 38, 92]</code> (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>code</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. <pre class="rectwrap">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@@</pre> ;yes but why a <code>range@</code> can also be implemented as: ¿:{1-!}1>|:{:1-:}]reverse@\_ when <code>reverse@</code> can be implemented as: ¿:1>|len@:{1-:3>|&,&\]<:}__] samely that's a <code>len@</code>: ¿:()#(_1)#\_","+[',g]'+repl@0\+@ and since <code>repl@</code> requires RegExp, it can't easily be done in WhatLang... so I guess that's it. Oh and with <code>len@</code> we can easily do a <code>join@</code>: ¿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??? <code>range@</code>: 1>|[]\0\:{&&len@&&&:&;&1-\1+\:}__]< <code>len@</code>: [0]\(__|1+])#_\< == Notes == <references/> == External resources == * [https://github.com/DGCK81LNN/whatlang-interpreter whatlang-interpreter]: DGCK81LNN's fork of the interpreter core with a simple (makeshift) CLI runtime ** also [https://www.npmjs.com/package/whatlang-interpreter published on npm] * [https://github.com/YufangProbably/koishi-plugins/tree/main/plugins/whatlang/src/ Original interpreter source code] (core and Koishi runtime) * [https://github.com/DGCK81LNN/yufang-koishi-plugins/tree/main/plugins/whatlang DGCK81LNN's fork of the Koishi runtime] * [https://dgck81lnn.github.io/whatlang/ DGCK81LNN's web port of the interpreter] ** and a [http://哼.site/whatlang/ Babel.js transpiled version] which can run on IE 11 and Safari 5 * [https://yufangprobably.github.io/whatlang/ Yufang's web port of the interpreter] (includes editor with syntax highlighting, albeit buggy) [[Category:Languages]] [[Category:Implemented]] [[Category:Stack-based]] [[Category:Turing complete]] [[Category:2024]]'
New page wikitext, after the edit (new_wikitext)
''''WhatLang''' is a stack-based programming language created by [[User:YufangTSTSU]] (Yufang) in June, 2024. == Implementations == Written in TypeScript, its first interpreter can be installed as [https://www.npmjs.com/package/koishi-plugin-whatlang a plugin] for [https://koishi.chat Koishi.js], a bot framework for QQ and other instant messaging platforms, and used by invoking the bot command <code>whatlang</code> or simply sending the code prefixed with a '<code>¿</code>'. 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 interactively reading input from the user yet. There is also a standalone interpreter published [https://www.npmjs.com/package/whatlang-interpreter on npm] which comes with a Node.js exeutable <code>what</code>; the ability to read from standard input and interact with the filesystem are yet to be added, though. The preferred file extension for WhatLang code is <code>.what</code>. A special runtime created by [[User:DGCK81LNN|DGCK81LNN]], known as '''WhatServer''', is another Koishi.js plugin which handles HTTP requests to <code>/what''(name-without-prefix)''/''(input)''</code> on the Koishi server by executing special [[#WhatCommands|WhatCommands]] whose names start with <code>server </code> (for GET requests), <code>server''(method)'' </code> or <code>serverall </code> (note the space at the end of the prefixes which makes them impossible to invoke using the normal <code>¿¿</code> syntax on messaging platforms). It notably supports WhatNoter and WhatCommands but lacks most of the other Koishi runtime specific functions. Yufang is 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 <code>[</code> or <code>|</code> instruction to create / edit an Array, the Array is pushed onto the Frame Stack, temporarily becoming the Stack; upon executing the <code>]</code> 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 <code>| ]</code>, 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. <code>send@</code>, <code>sends@</code> or <code>sendsto@</code> 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 <code>@</code> 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. <code>len@</code>, for example, counts ''encoding units'', but <code>#</code> 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 <code>"undef"</code>. 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: {|class="wikitable" ! 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 (±''significand''E±''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 == {|class="wikitable" ! Instruction !! Name !! Description |- | <code>0</code> | 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. |- | <code>'</code> 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 [https://github.com/DGCK81LNN/whatlang-interpreter/commit/8663d565a51a8f7176ac5eb8ece3ac509be2167a Aug 25, 2025]. |- | <code>"</code> delimited text | Quoted string literal | Returns the text as a String. Line feeds and character tabulations can be escaped as <code>\n</code> and <code>\t</code>. A backslash otherwise forces the next character to be treated literally. |- | <code>`</code> delimited text | Literal print | Similar to a <code>"</code> delimited string, but prints the string ''without'' doing anything with the Stack. |- | <code>+</code> | 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<ref name="forgot-to-coerce-to-string-undef-only"/> 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. Note that Array concatenation is only supported in very recent implementations; adding an Array with any value used to cause undefined behavior. |- | <code>-</code> <code>*</code> <code>/</code> <code>%</code> | Other arithmatic operations | Pops ''a'' and ''b'' from the Stack, coerced into Numbers, and returns ''a &lt;operator&gt; b''. |- | <code>?</code> | Compare | Pops ''a'' and ''b'' from the Stack. If they are loosely equal (<code>==</code> 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. |- | <code>~</code> | Logical not | Pops 1 value from the Stack. If it is falsey, returns 1; otherwise returns 0. |- | <code>[</code> | New Stack | Starts a new empty Stack. |- | <code><nowiki>|</nowiki></code> | Open Stack | Pops 1 value from the Stack: an error is thrown if it is not an Array; otherwise makes it the Stack. |- | <code>]</code> | Close Stack | Turns the current Stack into an Array, goes back to the previous Stack and returns the Array. <code>[ ]</code> or <code>| ]</code> must be properly paired. |- | <code>()</code> delimited text (may include nested parens) | Parenthesized string literal | Returns the literal contents of the parens as a String. |- | <code>.</code> | Print | Prints the element at the top of the Stack ''without'' popping it. If the stack is empty, '<code>undef</code>' is printed. |- | <code>\</code> | Swap | Swaps the topmost two elements in the Stack. Does nothing if the Stack contains less than 2 values. |- | <code>:</code> | 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. |- | <code>&</code> | Bury | Pops 1 value from the Stack, then inserts it at the bottom of the Stack. Does nothing if the Stack is empty. |- | <code>_</code> | Pop | Pops and discards the topmost value from the Stack. |- | <code>=</code> | 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. |- | <code>^</code> | 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 <code>"@"</code>. Otherwise, returns Undefined. |- | <code>@</code> | 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<ref>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.</ref>, executes the value as WhatLang code (the value must be a String). Otherwise, executes the string as WhatLang code. |- | <code>></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 <nowiki>|</nowiki>''n''<nowiki>|</nowiki> elements instead. |- | <code><</code> | 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. |- | <code>{</code> | While loop start | Pops 1 value from the Stack. If it is falsey, jumps to the corresponding <code>}</code>. |- | <code>}</code> | While loop end | Pops 1 value from the Stack. If it is truthy, jumps to the corresponding <code>{</code>. <code>{ }</code> must be properly paired. |- | One or more consecutive <code>!</code>s | Break, return or halt | If inside of a <code>{ }</code> loop and the number of <code>!</code>s is less than or equal to the current level of nested braces, breaks out of ''[number of <code>!</code>s]'' levels of loops and continues after the corresponding <code>}</code>. Otherwise, if running inside the <code>@</code> or </code>#</code> instruction, ends the execution of the current String of code (for <code>#</code>, continues with the next Array item, if any); otherwise halts the program. |- | <code>#</code> | 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. |- | <code>,</code> | 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. |- | <code>;</code> | 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. |- | <code>$</code> | 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 === {|class="wikitable" ! Function !! Description |- | <code>num@</code> | Pops 1 value, converts it to a Number and returns the result. |- | <code>str@</code> | 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. |- | <code>repr@</code> | Pops 1 value, and returns a string that tries to recreate the value when executed as WhatLang code. |- | <code>arr@</code> | 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. |- | <code>pow@</code> | Pops ''a'' and ''b'', coerced into Numbers, and returns the result of ''a ** b''. |- | <code>band@</code> <code>bor@</code> <code> bxor@</code> | Popss 2 values, coerced into signed 32-bit integers, and returns the result of performing bitwise AND, OR, or XOR between them, respectively. |- | <code>bnot@</code> | Pops 1 value, coerced into a signed 32-bit integer, and returns the result of performing bitwise NOT on it. |- | <code>rand@</code> | Returns a random number between 0 and 1. |- | <code>randint@</code> | Pops 2 values, coerced into Numbers. Returns a random number between them, rounded down to an integer. |- | <code>flr@</code> | Pops 1 value, coerced into a Number. Returns the result of rounding it down to an integer. |- | <code>range@</code> | 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. |- | <code>len@</code> | 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. |- | <code>split@</code> | 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 <code>match@</code>, each match adding the matched substrings of every capture group to the results. However currently no implementation supports this yet. |- | <code>join@</code> | 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''. |- | <code>reverse@</code> | Returns a shallow copy of the topmost value in the Stack, converted to an Array, with its items reversed in order. |- | <code>in@</code> | 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. |- | <code>filter@</code> | 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. |- | <code>chr@</code> | 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. |- | <code>ord@</code> | 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. |- | <code>and@</code> | Pops ''a'' and ''b''. If ''a'' is the empty String, 0 or undefined, returns ''a''; otherwise returns ''b''. |- | <code>or@</code> | Pops ''a'' and ''b''. If ''a'' is the empty String, 0 or undefined, returns ''b''; otherwise returns ''a''. |- | <code>nan@</code> | Returns NaN. |- | <code>undef@</code> | Returns Undefined. |- | <code>inf@</code> | Returns Inf. |- | <code>ninf@</code> | Returns -Inf. |- | <code>eq@</code> | Pops 2 values. If they are strictly equal (<code>===</code> in JavaScript), returns 1; otherwise returns 0. |- | <code>stak@</code> | Returns the Stack as an Array. Note that this makes the Stack contain itself. The name means <code>stack@</code> without '''c'''opying it. |- | <code>stack@</code> | Returns a shallow copy of the Stack as an Array. |- | <code>try@</code> | Like the <code>@</code> 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. |- | <code>throw@</code> | Pops 1 value, coerced into a String<ref name="forgot-to-coerce-to-string">Older implementations produce unexpected results when this value is an Array, Inf, -Inf or Undefined.</ref>. Throws an error with this value as the message and <code>"Error"</code> as the name. |- | <code>match@</code> | 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<ref name="forgot-to-coerce-to-string-throws">Older implementations incorrectly throw an error if this value is not a String.</ref>. 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<ref name="forgot-to-coerce-to-string-undef-only">Older implementations produce unexpected results when this value is Inf, -Inf or Undefined.</ref> 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. |- | <code>repl@</code> | Pops ''string'', ''pattern'' and ''replacement''; substitutes each occurrence of ''pattern'' in ''string'' with ''replacement'' and returns the modified String. ''pattern''<ref name="forgot-to-coerce-to-string-undef-only"/> can be a literal String or an Array specifying a JavaScript Regular Expression like in <code>match@</code>. ''string''<ref name="forgot-to-coerce-to-string-throws"/> and ''replacement''<ref name="forgot-to-coerce-to-string"/> are coerced into Strings. Backreferences are replaced in the replacement string; to avoid this, replace any dollar sign in ''replacement'' with two dollar signs. |- | <code>time@</code> | Returns the current system time in epoch milliseconds. |- | <code>type@</code> | Pops 1 value; returns its type (one of <code>"String"</code>, <code>"Number"</code>, <code>"Array"</code>, <code>"Undefined"</code>). |- | <code>b64@</code> | Pops 1 value, which must be an Array of Numbers which are understood as bytes. Returns the [[w:Base64|Base64]] representation of this sequence of bytes. Added on [https://github.com/DGCK81LNN/whatlang-interpreter/commit/4a23a8a2cec1577c7ff6110c80c65a3d59430933 Oct 3, 2025]. |- | <code>nb64@</code> | Pops 1 value, coerced into a String, and returns the result of decoding it from [[w:Base64|]] into an Array of Bytes. Added on [https://github.com/DGCK81LNN/whatlang-interpreter/commit/4a23a8a2cec1577c7ff6110c80c65a3d59430933 Oct 3, 2025]. Before decoding, any non-[[w:Base64|Base64]] characters and equal signs are ignored, then the string is padded with equal signs until its length is a multiple of 4. |- | <code>utf8@</code> | Pops 1 value, coerced into a String. Returns an Array of byte Numbers that represent this string in UTF-8. Added on [https://github.com/DGCK81LNN/whatlang-interpreter/commit/4a23a8a2cec1577c7ff6110c80c65a3d59430933 Oct 3, 2025]. |- | <code>nutf8@</code> | 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 on [https://github.com/DGCK81LNN/whatlang-interpreter/commit/4a23a8a2cec1577c7ff6110c80c65a3d59430933 Oct 3, 2025]. |} === Common extension === Most of these function used to be Koishi runtime specific but may be available in other environments. {|class="wikitable" ! Function !! Description |- | <code>you@</code> | Returns a String containing information about the current runtime environment. For the Koishi runtime it is <code>"WhatLang/2024 Environment/messaging Framework/koishi Platform/''platform'' Id/''id''"</code> 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 <code>Brand/''botName''</code>. Added on [https://github.com/DGCK81LNN/yufang-koishi-plugins/commit/279e74d166c8673a984ffd7ce0b64ac6c597f9bb June 22, 2025]. |- | <code>pr@</code> | 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. |- | <code>cat@</code> | Pops <var>url</var>, 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|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 <code>pr@</code>. |- | <code>ca@</code> | Similar to <code>cat@</code> but returns the response body as an Array of byte Numbers. Added as <code>catb@</code> on May 14, 2025, then renamed as <code>ca@</code> on May 29, 2025, meaning <code>cat@</code> without decoding the body as '''t'''ext. |- | <code>fetch@</code> | 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. |- | <code>fech@</code> | Similar to <code>fetch@</code> but instead of a String, the response body is as an Array of byte Numbers. Added on June 3, 2025. The name means <code>fetch@</code> without decoding the body as '''t'''ext. |- | <code>reesc@</code> | Pops 1 value, coerced into a String<ref name="forgot-to-coerce-to-string-throws"/>, and returns the result of escaping all JavaScript Regular Expression metacharacters in this String with backslash sequences. |- | <code>sleep@</code> | Pops <var>n</var>, coerced into a Number, and sleeps for <var>n</var> seconds. <var>n</var> must be between 0 and 2147483.647, inclusive. |- | <code>nout@</code> | Pops and discards the last printed element from the Output Stack. |- | <code>nouts@</code> | Pops <var>n</var>, coerced into a Number which must be an integer. Removes and discards the top (latest) <var>n</var> elements from the Output Stack. If <var>n</var> is zero or negative, removes all but the bottom (oldest) &#124;<var>n</var>&#124; elements instead. Inf and -Inf are treated like zero. |- | <code>send@</code> | 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. |- | <code>sends@</code> | Pops <var>n</var>, coerced into a Number which must be an integer. Pops the top (latest) <var>n</var> 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 <var>n</var> is zero or negative, sends all but the bottom (oldest) &#124;<var>n</var>&#124; 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. |- | <code>ou@</code> | 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 <code>ca@</code> and <code>fech@</code>, 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. {|class="wikitable" ! Function !! Description |- | <code>help@</code> | 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 <code>help@</code> function. |- | <code>helpall@</code> | Prints a list of the names of (almost) all builtin functions as an image. |- | <code>propt@</code> | 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. |- | <code>prompt@</code> | 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 <code>me@</code>) until the Result is truthy, then returns the message details Array. On timeout, returns Undefined. |- | <code>me@</code> | 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, <code>GET /whatfoo/bar</code>. 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 <code>X-Lnnbot-Whatserver-Login-Token</code> request header, or Undefined * index 5: <code>"__WHATSERVER__"</code> * index 6: Undefined |- | <code>outimg@</code> <code>outaudio@</code> <code>outvideo@</code> <code>outfile@</code> | 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. |- | <code>outquote@</code> | Pops <var>id</var>, which must be a String, and prints a reference to the message with this ID. |- | <code>outat@</code> | Pops <var>id</var>, which must be a String, and prints a @mention of the user with this platform-defined ID. |- | <code>outimag@</code> | Pops 1 value, coerced into a String, renders its content text with a monospaced font and prints the result as an image. |- | <code>outksq@</code> | Pops 1 value, coerced into a String, renders its content text with the [https://www.kreativekorp.com/software/fonts/ksquare/ Kreative Square] font and prints the result as an image. |- | <code>outsvg@</code> | 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 [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width#svg <code>width</code>] and [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height#svg <code>height</code>] of the <code>&lt;svg&gt;</code> 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 [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/style <code>style</code>] attribute, and the remaining items specifies other properties depending on type. * <code>path</code> or <code>p</code> indicates a [https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path <code>&lt;path&gt;</code>] element. It accepts the [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d <code>d</code>] attribute as the third item in the Array. * <code>text</code> or <code>t</code> indicates a [https://developer.mozilla.org/en-US/docs/Web/SVG/Element/text <code>&lt;text&gt;</code>] element. It accepts the [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x#text <code>x</code>], [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/y#text <code>y</code>] attributes and the content text as the 3rd, 4th and 5th items in the Array. * <code>img</code> or <code>i</code> indicates an [https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image <code>&lt;image&gt;</code>] element. It accepts the [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x#image <code>x</code>], [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/y#image <code>y</code>], [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width#image <code>width</code>], [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height#image <code>height</code>] and [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/href#image <code>href</code>] attributes as the 3rd through 7th items in the Array. |- | <code>outhtml@</code> | Pops 1 value, coerced into a String, renders its content as HTML and prints the result as an image. Added on [https://github.com/DGCK81LNN/yufang-koishi-plugins/commit/6c98e706c38ca9c2adbc7645bd3ebcb04b7ca524 Oct 3, 2025]. |- | <code>nsend@</code> | Pops <var>messageid</var>, which must be a String, and deletes (recalls) the message with this platform-defined ID in the current channel. |- | <code>sendsto@</code> | Pops <var>channelid</var>, which must be a String, and <var>n</var>, coerced into a Number which must be an integer. Pops elements from the Output Stack as in <code>sends@</code> and sends them in the channel with platform-defined ID <var>channelid</var>. Return an Array containing platform-defined ID Strings of the message(s) sent. |- | <code>findmsg@</code> | 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 <code>me@</code>) 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. |- | <code>getmsg@</code> | Pops <var>id</var>, which must be a String, and returns the details of the message with this ID as an Array (see <code>me@</code>). |- | <code>guildmem@</code> | Pops <var>guildid</var>, 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. {|class="wikitable" ! Function !! Description |- | <code>notewc@</code> | 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''. |- | <code>notewd@</code> | Pops ''str'', which must be a String. Sets the protected note content of the user triggering the interpreter to ''str''. |- | <code>notewe@</code> | Pops ''str'', which must be a String. Sets the private note content of the user triggering the interpreter to ''str''. |- | <code>noterc@</code> | Pops ''uid'', which must be a natrual Number. Returns the public note content of that user id. |- | <code>noterd@</code> | Pops ''uid'', which must be a natrual Number. Returns the protected note content of that user id. |- | <code>notere@</code> | 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 <code>¿¿</code> prefix, invoking the bot command <code>whatcmd</code>, or using WhatLang's <code>cmd@</code> function. Commands take a single String as input, which can be found at the top of the Stack. For example, given a command named <code>greet</code> with code <code>`Hello, `.`!`</code>, sending '<code>¿¿greet my friends</code>', executing bot command '<code>whatcmd greet my friends</code>', and executing WhatLang code '<code>"my friends" greet cmd@</code>' all produce the output '<code>Hello, my friends!</code>' Commands return a value when invoked with <code>cmd@</code>, which you can use as an exit status code. It is not accessible when invoking a command using the <code>¿¿</code> prefix. {|class="wikitable" ! Function !! Description |- | <code>cmdset@</code> | Pops ''code'' and ''name'', which must be Strings, and sets the code of the command named ''name'' to ''code''. |- | <code>cmdall@</code> | Returns an Array containing the names of all currently defined commands. |- | <code>cmdsethelp@</code> | Pops ''str'' and ''name'', which must be Strings, and sets the manual of the command named ''name'' to ''str''. |- | <code>cmdseth@</code> | Pops ''str'' and ''name'', which must be Strings, and sets the description of the command named ''name'' to ''str''. |- | <code>cmddel@</code> | Pops ''name'', which must be a String, and deletes the command with that name. |- | <code>cmdget@</code> | Pops ''name'', which must be a String, and returns the code of the command with that name, or Undefined if it does not exist. |- | <code>cmdgethelp@</code> | Pops ''name'', which must be a String, and returns the manual of the command with that name, or Undefined if it does not exist. |- | <code>cmdgeth@</code> | Pops ''name'', which must be a String, and returns the description of the command with that name, or Undefined if it does not exist. |- | <code>cmd@</code> | 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: <code><var>value</var> <var>name</var>=_</code> ** Pop (<code>_</code>) 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 <code><var>functionname</var>@</code> * To get negative one (or likewise any negative integer): <code>01-</code> * To get any real Number, for example, 3&times;10<sup>100</sup>: <code>(3e100)num@</code> ** Represent the number with a String and then use <code>num@</code> to convert it into a Number. * If block: <code><var>condition</var>{ <var>statements</var> !}</code> ** A while loop with a break at the end. * If-else block: <code><var>condition</var> c={ <var>true-branch</var> !} c^~{ <var>false-branch</var> !}</code> ** Alternatively using no variables: <code>1{ <var>condition</var>{ <var>true-branch</var> !!} <var>false-branch</var> !}</code> ** Alternatively: <code><var>condition</var>~[(<var>true-branch</var>)(<var>false-branch</var>)]\,\_@</code> * Comparison of two values (returns a truthy value when the condition satisfies) ** Loose equal (cmp(a, b) == 0): <code>?~</code> ** Greater than (cmp(a, b) == 1): <code>?1?~</code> ** Less than: <code>?(-1)?~</code> or <code>\?1?~</code> ** Less than or equal to (cmp(a, b) < 1): <code>?1\?1?~</code> ** Greater than or equal to (cmp(b, a) < 1): <code>\?1\?1?~</code> ** Remove the <code>~</code> for a negated condition. ** Alternatively, <code>?[<var>equal</var> <var>greater</var> <var>less</var>]\,\_</code> can be used to implement these comparisons by replacing <var>equal</var>, <var>greater</var> and <var>less</var> with 0's and 1's (or any other value) depending on what you want the result to be in each case, for example, <code>?[1:0]\,\_</code> 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 <code>2+</code> in it:<code>?2+[<var>for-incomparable</var> <var>for-less</var> <var>for-equal</var> <var>for-greater</var>]\,\_</code> * Push value into Array (assuming Array at top of Stack): <code>len@ <var>value</var> ;</code> or <code>nan@ <var>value</var> ;</code> * Comment: <code>0{ <var>comment</var> }</code> or <code>(<var>comment</var>)_</code> == Example programs == Some programs here are prefixed with <code>¿</code> 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 <code>((¿)S:aSS)(¿)S:aSS</code> ¿((¿)._:repr@._._)(¿)._:repr@._._ ;<s>Cat program</s> Get random cat image from [https://thecatapi.com 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@ [(&amp;lt;) g](<)repl@ [(&amp;gt;) g](>)repl@ [(&amp;amp;) g](&)repl@ . This unescapes <code>&lt;&gt;&</code> 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: [[File:WhatLang dices.png|300px]] ; 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, <code>divmod@</code> and <code>datetime@</code>, and then calls <code>datetime@</code> with the current timestamp and a time zone offset (in this case GMT+8). It returns something like <code>[2024, 9, 13, 5, 6, 55, 38, 92]</code> (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>code</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. <pre class="rectwrap">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@@</pre> ;yes but why a <code>range@</code> can also be implemented as: ¿:{1-!}1>|:{:1-:}]reverse@\_ when <code>reverse@</code> can be implemented as: ¿:1>|len@:{1-:3>|&,&\]<:}__] samely that's a <code>len@</code>: ¿:()#(_1)#\_","+[',g]'+repl@0\+@ and since <code>repl@</code> requires RegExp, it can't easily be done in WhatLang... so I guess that's it. Oh and with <code>len@</code> we can easily do a <code>join@</code>: ¿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??? <code>range@</code>: 1>|[]\0\:{&&len@&&&:&;&1-\1+\:}__]< <code>len@</code>: [0]\(__|1+])#_\< == Notes == <references/> == External resources == * [https://github.com/DGCK81LNN/whatlang-interpreter whatlang-interpreter]: [[User:DGCK81LNN|DGCK81LNN]]'s fork of the interpreter core with a simple (makeshift) CLI runtime ** also [https://www.npmjs.com/package/whatlang-interpreter published on npm] * [https://github.com/YufangProbably/koishi-plugins/tree/main/plugins/whatlang/src/ Original interpreter source code] (core and Koishi runtime) * [https://github.com/DGCK81LNN/yufang-koishi-plugins/tree/main/plugins/whatlang DGCK81LNN's fork of the Koishi runtime] * [https://dgck81lnn.github.io/whatlang/ DGCK81LNN's web port of the interpreter] ** and a [http://哼.site/whatlang/ Babel.js transpiled version (outdated)] which can run on IE 11 and Safari 5 * [https://yufangprobably.github.io/whatlang/ Yufang's web port of the interpreter] (includes editor with syntax highlighting, albeit buggy) * [https://gitee.com/DGCK81LNN/lnnbot-miniplugs/blob/master/plugins/common/-lnnbot-whatapi.js WhatServer source code] [[Category:Languages]] [[Category:Implemented]] [[Category:Stack-based]] [[Category:Turing complete]] [[Category:2024]]'
Unified diff of changes made by edit (edit_diff)
'@@ -1,9 +1,15 @@ '''WhatLang''' is a stack-based programming language created by [[User:YufangTSTSU]] (Yufang) in June, 2024. -Written in TypeScript, its first interpreter can be installed as a private (not published on ''npm'') plugin for [https://koishi.chat Koishi.js], a bot framework for QQ and other instant messaging platforms, and used by invoking the bot command <code>whatlang</code> or simply sending the code prefixed with a '<code>¿</code>'. +== Implementations == -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 [https://www.npmjs.com/package/whatlang-interpreter on npm] which comes with a Node.js exeutable <code>what</code>; the ability to read from standard input and interact with the filesystem are yet to be added, though. The preferred file extension for WhatLang code is <code>.what</code>. +Written in TypeScript, its first interpreter can be installed as [https://www.npmjs.com/package/koishi-plugin-whatlang a plugin] for [https://koishi.chat Koishi.js], a bot framework for QQ and other instant messaging platforms, and used by invoking the bot command <code>whatlang</code> or simply sending the code prefixed with a '<code>¿</code>'. -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. +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 interactively reading input from the user yet. + +There is also a standalone interpreter published [https://www.npmjs.com/package/whatlang-interpreter on npm] which comes with a Node.js exeutable <code>what</code>; the ability to read from standard input and interact with the filesystem are yet to be added, though. The preferred file extension for WhatLang code is <code>.what</code>. + +A special runtime created by [[User:DGCK81LNN|DGCK81LNN]], known as '''WhatServer''', is another Koishi.js plugin which handles HTTP requests to <code>/what''(name-without-prefix)''/''(input)''</code> on the Koishi server by executing special [[#WhatCommands|WhatCommands]] whose names start with <code>server </code> (for GET requests), <code>server''(method)'' </code> or <code>serverall </code> (note the space at the end of the prefixes which makes them impossible to invoke using the normal <code>¿¿</code> syntax on messaging platforms). It notably supports WhatNoter and WhatCommands but lacks most of the other Koishi runtime specific functions. + +Yufang is 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 == @@ -61,7 +67,8 @@ | Returns the identifier as a String, converted to lower case. |- -| <code>'</code> followed by one char ('''encoding unit''') +| <code>'</code> 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 [https://github.com/DGCK81LNN/whatlang-interpreter/commit/8663d565a51a8f7176ac5eb8ece3ac509be2167a Aug 25, 2025]. |- | <code>"</code> delimited text @@ -309,9 +316,26 @@ | <code>type@</code> | Pops 1 value; returns its type (one of <code>"String"</code>, <code>"Number"</code>, <code>"Array"</code>, <code>"Undefined"</code>). +|- +| <code>b64@</code> +| Pops 1 value, which must be an Array of Numbers which are understood as bytes. Returns the [[w:Base64|Base64]] representation of this sequence of bytes. +Added on [https://github.com/DGCK81LNN/whatlang-interpreter/commit/4a23a8a2cec1577c7ff6110c80c65a3d59430933 Oct 3, 2025]. +|- +| <code>nb64@</code> +| Pops 1 value, coerced into a String, and returns the result of decoding it from [[w:Base64|]] into an Array of Bytes. + +Added on [https://github.com/DGCK81LNN/whatlang-interpreter/commit/4a23a8a2cec1577c7ff6110c80c65a3d59430933 Oct 3, 2025]. Before decoding, any non-[[w:Base64|Base64]] characters and equal signs are ignored, then the string is padded with equal signs until its length is a multiple of 4. +|- +| <code>utf8@</code> +| Pops 1 value, coerced into a String. Returns an Array of byte Numbers that represent this string in UTF-8. +Added on [https://github.com/DGCK81LNN/whatlang-interpreter/commit/4a23a8a2cec1577c7ff6110c80c65a3d59430933 Oct 3, 2025]. +|- +| <code>nutf8@</code> +| 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 on [https://github.com/DGCK81LNN/whatlang-interpreter/commit/4a23a8a2cec1577c7ff6110c80c65a3d59430933 Oct 3, 2025]. |} === Common extension === -Most of these function used to be ''Koishi'' runtime specific but may be available in other environments. +Most of these function used to be Koishi runtime specific but may be available in other environments. {|class="wikitable" @@ -321,5 +345,5 @@ | Returns a String containing information about the current runtime environment. For the Koishi runtime it is <code>"WhatLang/2024 Environment/messaging Framework/koishi Platform/''platform'' Id/''id''"</code> 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 <code>Brand/''botName''</code>. -Added on June 22, 2025. +Added on [https://github.com/DGCK81LNN/yufang-koishi-plugins/commit/279e74d166c8673a984ffd7ce0b64ac6c597f9bb June 22, 2025]. |- | <code>pr@</code> @@ -331,13 +355,13 @@ 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 <code>pr@</code>. +The name of this function originates from the "cat" command of LNNBot (maintained by [[User:DGCK81LNN|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 <code>pr@</code>. |- | <code>ca@</code> | Similar to <code>cat@</code> but returns the response body as an Array of byte Numbers. -This function was added recently. The name means <code>cat@</code> without decoding the body as '''t'''ext. +Added as <code>catb@</code> on May 14, 2025, then renamed as <code>ca@</code> on May 29, 2025, meaning <code>cat@</code> without decoding the body as '''t'''ext. |- | <code>fetch@</code> | 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. +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. @@ -345,5 +369,5 @@ | <code>fech@</code> | Similar to <code>fetch@</code> but instead of a String, the response body is as an Array of byte Numbers. -This function was added recently. The name means <code>fetch@</code> without decoding the body as '''t'''ext. +Added on June 3, 2025. The name means <code>fetch@</code> without decoding the body as '''t'''ext. |- | <code>reesc@</code> @@ -376,5 +400,5 @@ |} -=== ''Koishi'' runtime specific === +=== Koishi runtime specific === Some of these functions involve messages received by the bot; message contents are Strings in Koishi's XML format. @@ -405,7 +429,16 @@ * 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: Koishi-defined ID of the user as a Number +* 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, <code>GET /whatfoo/bar</code>. 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 <code>X-Lnnbot-Whatserver-Login-Token</code> request header, or Undefined +* index 5: <code>"__WHATSERVER__"</code> +* index 6: Undefined |- | <code>outimg@</code> <code>outaudio@</code> <code>outvideo@</code> <code>outfile@</code> @@ -430,4 +463,8 @@ * <code>text</code> or <code>t</code> indicates a [https://developer.mozilla.org/en-US/docs/Web/SVG/Element/text <code>&lt;text&gt;</code>] element. It accepts the [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x#text <code>x</code>], [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/y#text <code>y</code>] attributes and the content text as the 3rd, 4th and 5th items in the Array. * <code>img</code> or <code>i</code> indicates an [https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image <code>&lt;image&gt;</code>] element. It accepts the [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x#image <code>x</code>], [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/y#image <code>y</code>], [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width#image <code>width</code>], [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height#image <code>height</code>] and [https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/href#image <code>href</code>] attributes as the 3rd through 7th items in the Array. +|- +| <code>outhtml@</code> +| Pops 1 value, coerced into a String, renders its content as HTML and prints the result as an image. +Added on [https://github.com/DGCK81LNN/yufang-koishi-plugins/commit/6c98e706c38ca9c2adbc7645bd3ebcb04b7ca524 Oct 3, 2025]. |- | <code>nsend@</code> @@ -451,5 +488,5 @@ ==== 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. +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. {|class="wikitable" @@ -691,11 +728,12 @@ == External resources == -* [https://github.com/DGCK81LNN/whatlang-interpreter whatlang-interpreter]: DGCK81LNN's fork of the interpreter core with a simple (makeshift) CLI runtime +* [https://github.com/DGCK81LNN/whatlang-interpreter whatlang-interpreter]: [[User:DGCK81LNN|DGCK81LNN]]'s fork of the interpreter core with a simple (makeshift) CLI runtime ** also [https://www.npmjs.com/package/whatlang-interpreter published on npm] * [https://github.com/YufangProbably/koishi-plugins/tree/main/plugins/whatlang/src/ Original interpreter source code] (core and Koishi runtime) * [https://github.com/DGCK81LNN/yufang-koishi-plugins/tree/main/plugins/whatlang DGCK81LNN's fork of the Koishi runtime] * [https://dgck81lnn.github.io/whatlang/ DGCK81LNN's web port of the interpreter] -** and a [http://哼.site/whatlang/ Babel.js transpiled version] which can run on IE 11 and Safari 5 +** and a [http://哼.site/whatlang/ Babel.js transpiled version (outdated)] which can run on IE 11 and Safari 5 * [https://yufangprobably.github.io/whatlang/ Yufang's web port of the interpreter] (includes editor with syntax highlighting, albeit buggy) +* [https://gitee.com/DGCK81LNN/lnnbot-miniplugs/blob/master/plugins/common/-lnnbot-whatapi.js WhatServer source code] [[Category:Languages]] '
New page size (new_size)
47046
Old page size (old_size)
43718
Lines added in edit (added_lines)
[ 0 => '== Implementations ==', 1 => 'Written in TypeScript, its first interpreter can be installed as [https://www.npmjs.com/package/koishi-plugin-whatlang a plugin] for [https://koishi.chat Koishi.js], a bot framework for QQ and other instant messaging platforms, and used by invoking the bot command <code>whatlang</code> or simply sending the code prefixed with a '<code>¿</code>'.', 2 => '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 interactively reading input from the user yet.', 3 => '', 4 => 'There is also a standalone interpreter published [https://www.npmjs.com/package/whatlang-interpreter on npm] which comes with a Node.js exeutable <code>what</code>; the ability to read from standard input and interact with the filesystem are yet to be added, though. The preferred file extension for WhatLang code is <code>.what</code>.', 5 => '', 6 => 'A special runtime created by [[User:DGCK81LNN|DGCK81LNN]], known as '''WhatServer''', is another Koishi.js plugin which handles HTTP requests to <code>/what''(name-without-prefix)''/''(input)''</code> on the Koishi server by executing special [[#WhatCommands|WhatCommands]] whose names start with <code>server </code> (for GET requests), <code>server''(method)'' </code> or <code>serverall </code> (note the space at the end of the prefixes which makes them impossible to invoke using the normal <code>¿¿</code> syntax on messaging platforms). It notably supports WhatNoter and WhatCommands but lacks most of the other Koishi runtime specific functions.', 7 => '', 8 => 'Yufang is 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.', 9 => '| <code>'</code> followed by one character', 10 => 'Used to only take a single encoding unit (not allowing non-BMP characters) until [https://github.com/DGCK81LNN/whatlang-interpreter/commit/8663d565a51a8f7176ac5eb8ece3ac509be2167a Aug 25, 2025].', 11 => '|-', 12 => '| <code>b64@</code>', 13 => '| Pops 1 value, which must be an Array of Numbers which are understood as bytes. Returns the [[w:Base64|Base64]] representation of this sequence of bytes.', 14 => 'Added on [https://github.com/DGCK81LNN/whatlang-interpreter/commit/4a23a8a2cec1577c7ff6110c80c65a3d59430933 Oct 3, 2025].', 15 => '|-', 16 => '| <code>nb64@</code>', 17 => '| Pops 1 value, coerced into a String, and returns the result of decoding it from [[w:Base64|]] into an Array of Bytes.', 18 => '', 19 => 'Added on [https://github.com/DGCK81LNN/whatlang-interpreter/commit/4a23a8a2cec1577c7ff6110c80c65a3d59430933 Oct 3, 2025]. Before decoding, any non-[[w:Base64|Base64]] characters and equal signs are ignored, then the string is padded with equal signs until its length is a multiple of 4.', 20 => '|-', 21 => '| <code>utf8@</code>', 22 => '| Pops 1 value, coerced into a String. Returns an Array of byte Numbers that represent this string in UTF-8.', 23 => 'Added on [https://github.com/DGCK81LNN/whatlang-interpreter/commit/4a23a8a2cec1577c7ff6110c80c65a3d59430933 Oct 3, 2025].', 24 => '|-', 25 => '| <code>nutf8@</code>', 26 => '| 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.', 27 => 'Added on [https://github.com/DGCK81LNN/whatlang-interpreter/commit/4a23a8a2cec1577c7ff6110c80c65a3d59430933 Oct 3, 2025].', 28 => 'Most of these function used to be Koishi runtime specific but may be available in other environments.', 29 => 'Added on [https://github.com/DGCK81LNN/yufang-koishi-plugins/commit/279e74d166c8673a984ffd7ce0b64ac6c597f9bb June 22, 2025].', 30 => 'The name of this function originates from the "cat" command of LNNBot (maintained by [[User:DGCK81LNN|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 <code>pr@</code>.', 31 => 'Added as <code>catb@</code> on May 14, 2025, then renamed as <code>ca@</code> on May 29, 2025, meaning <code>cat@</code> without decoding the body as '''t'''ext.', 32 => 'Added on June 3, 2025.', 33 => 'Added on June 3, 2025. The name means <code>fetch@</code> without decoding the body as '''t'''ext.', 34 => '=== Koishi runtime specific ===', 35 => '* index 4: ID of the user in Koishi's database as a Number', 36 => '', 37 => 'This function is available in WhatServer but the values have different meanings due to the nature of WhatServer, though they attempt to be compatible:', 38 => '', 39 => '* index 0: request method and url, for example, <code>GET /whatfoo/bar</code>. URL-encoded characters without special meanings in the url are decoded.', 40 => '* index 1: random String', 41 => '* index 2 and 3: client IP address', 42 => '* index 4: ID of the user in Koishi's database as a Number if the request is authenticated using the <code>X-Lnnbot-Whatserver-Login-Token</code> request header, or Undefined', 43 => '* index 5: <code>"__WHATSERVER__"</code>', 44 => '* index 6: Undefined', 45 => '|-', 46 => '| <code>outhtml@</code>', 47 => '| Pops 1 value, coerced into a String, renders its content as HTML and prints the result as an image.', 48 => 'Added on [https://github.com/DGCK81LNN/yufang-koishi-plugins/commit/6c98e706c38ca9c2adbc7645bd3ebcb04b7ca524 Oct 3, 2025].', 49 => '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.', 50 => '* [https://github.com/DGCK81LNN/whatlang-interpreter whatlang-interpreter]: [[User:DGCK81LNN|DGCK81LNN]]'s fork of the interpreter core with a simple (makeshift) CLI runtime', 51 => '** and a [http://哼.site/whatlang/ Babel.js transpiled version (outdated)] which can run on IE 11 and Safari 5', 52 => '* [https://gitee.com/DGCK81LNN/lnnbot-miniplugs/blob/master/plugins/common/-lnnbot-whatapi.js WhatServer source code]' ]
Unix timestamp of change (timestamp)
'1759555064'