$ESOLANG

From Esolang
Jump to navigation Jump to search

$ESOLANG is an esoteric programming language made by User:Astaryuu in July 2025. It is an extended joke at the expense of Web3, NFTs, and cryptocurrency.

"True web3 fans know how to use $ESOLANG" - nobody, ever

Characteristics

$ESOLANG is based on a "bytechain", or chain for short. A chain is the same kind of structure as a stack, but $ESOLANG has no popping operations. This means that memory leaks occur by design. Unlike many stack-based esolangs, $ESOLANG can put objects of any type on the chain. However, this requires the object's definition to be placed on the chain unless it is a primitive, and therefore eats up a lot of memory.

$ESOLANG aims to be a Turing complete programming language. It technically is, but requires significantly more memory to do things than standard languages like Python or Ruby. Regardless, it is object-based, like Java, for what that's worth. When an object needs to be located, the interpreter runs down the entire chain until it finds a matching object. This eats CPU time exponentially as memory is used, much like how minting crypto (ideally) requires more computing power the more coins are minted.

Classes

Primitives

There are only four primitive classes in $ESOLANG: Byte, Boolean, Null, and Wallet. A Byte holds one byte, which is by default an unsigned 8-bit integer, written using either binary, decimal, or hexadecimal. Boolean and Null are exactly what they sound like. A Wallet is effectively an array. All objects, including the above, have an "owner" tag (64 bytes long) that specifies what Wallet they belong to; a Wallet contains an object if its owner tag matches that of the other object. Wallets are effectively a generic Object class.

An initial Wallet is defined at runtime: the Main wallet (ID 0), which is the only one allowed to "mint" objects. Minting an object requires its class identifier, any arguments needed to construct the wallet, and its ID. Minting adds the object and, if not present, their definitions to the chain. Wallets also have to be minted, of course. Technically, nothing stops a Wallet from owning another Wallet, but unless it is a Byte or Boolean, Wallets contained within another Wallet are considered to be Tokens instead of Wallets unless in the scope of the Main wallet.

Wallets by default have the ability to transfer information to other Wallets. More functions can be programmed by the programmer, but these require the Main wallet to mint a function and transfer it to the Wallet. The Main wallet can also clone a Wallet, including all of its functions.

Standard library

There are only two other items in the standard library: Integers and Strings. They have literals, but can also be defined like Wallets. Both are a set of Bytes treated as one object. Integers are defined using $[n]x, where x is the value of the integer (or 0 if not present), and n is the number of bytes that should be allocated. Strings are defined using @x, where x is the string to input. Spaces are treated as the end of a string literal, so if you want your string to contain a space, you have to escape it using the sequence \_. All literals, including those for Bytes and Booleans (Null only becomes a permanent object if explicitly defined), automatically set the ID to the lowest unused value.

Operations

These are all the operations a Wallet supports:

  • mint({class}, Integer[32], *args): If the operator has ID 0, mints an object of type {class} with the Integer as its ID. Even if the integer has some number of bytes that isn't 32, it's cast to 32 bytes in the minting process.
  • clientmint({class}, Integer[32], *args) - Takes text input from the user, attempts to cast it to {class}, and mints it with the Integer as its ID. Even if the integer has some number of bytes that isn't 32, it's cast to 32 bytes in the minting process.
  • flaunt(Token) - If the operator owns the token, prints it to the screen.
  • transfer(Token, Integer[32]) - If the operator owns the token, sets its owner field to the Integer. Even if the integer has some number of bytes that isn't 32, it's cast to 32 bytes.
  • zero(Token, proc {}) - If Token is a Byte or Integer, only runs the code in "proc {}" if it's zero. If Token is a Boolean, only runs that code if it's false.
  • spend(Token, proc {}) - Same as zero(), but the code in "proc {}" is run until a loop ends with Token zero or false as above.

There are no return statements, as the results of all functions are locatable on the chain. The function simply ends once the function's end bracket is reached, going out to the function that called it if one exists, or ending processing if none exists.

Bytes and Integers support the basic arithmetic operators, but they have to be written as functions instead of literals because Web3 is all about unnecessary bloatware to accomplish stuff that we figured out 20 years ago. Strings use add(x, y) to concatenate, and bsl or bsr to remove the first or last byte of the string respectively. All Integers involved in the operation are cast to the highest number of bytes used in the arguments, but they're truncated to the lowest Byte if a Byte is involved in the operation. bsl and bsr mean bit-shift left and right respectively.

  • add(x, y), sub(x, y), mult(x, y), div(x, y), mod(x, y), bsl(x), bsr(x)

Bytes, Integers, and Booleans support basic logic operators; for the first two, these are performed bitwise.

  • not(x), and(x, y), or(x, y), xor(x, y)

At runtime, the interpreter will create the Main wallet and attempt to run its constructor; this is where the code the program will run should be located. This also means the code files need to start by declaring the Main wallet; other wallets can (and will) be created in the same file, of course.