Beeswax

beeswax is a stack-based 2 dimensional esoteric programming language developed by user:Albedo (Manuel Lohmann). Beeswax draws inspiration from bees moving around on a honeycomb, and is partly inspired by languages like Cardinal etc. and the abstract board game Hive which uses hexagonal game pieces. The instruction pointers (bees) move around on a 2D hexagonal grid (the honeycomb). beeswax programs can manipulate their own source code, change the program size, and can read and write files.

>      NN      p > d#_8~2~(P~3~.~1~>{` bottles of beer on the wall, `{` bottles of beer.`q d`.llaw eht no reeb fo selttob `{pLM` ,dnuora ti ssap dna nwod eno ekaT`N< q`.llaw eht no reeb fo elttob ` {< >        NN       >{` bottle of beer on the wall, `{` bottle of beer.`N  q pN `.llaw eht no reeb fo selttob erom on ,dnuora ti ssap dna nwod eno ekaT`< >N`No more bottles of beer on the wall, no more bottles of beer.`N  q beeswax example program: 99 bottles of beer
 * `.llaw eht no reeb fo selttob 99 ,erom emos yub dna erots eht ot oG`<

Honeycomb structure and source code layout
The programming language draws inspiration from bees and honeycombs, so the instruction pointers (“bees”) travel through the program (“honeycomb”) along a hexagonal grid. Every honeycomb location has 6 neighbors.

Honeycomb structure
a — b — c — d  \ / \ / \ / \ e — f — g — h    \ / \ / \ / \ i — j — k — l

Beeswax programs are stored in a rectangular format. A program using the layout of the honeycomb structure above would look like this:

abcd efgh ijkl

Movement directions
Bees (IPs) can move in one of 6 directions that are determined like below:

( marks the IP/bee)

2 — 1  / \ / \  3 — β — 0 \ / \ /   4 — 5

The analogous neighborhood layout in a beeswax program looks like this:

21 3β0 45

Local stacks
Every bee has a “personal” fixed size stack, carrying three  values, called local stack or. Every local stack is initialized to  at the start of the program. marks the top of the stack.

Global stacks
To store bigger amounts of data there is also a global stack available where bees can drop values onto and pick up values from.

The global stack is not limited in size and only allows basic stack operations.

All arithmetic, bit manipulation and other operations have to be executed by bees on their local stacks. So, before any data on the global stack can be used for calculations etc. a bee has to pick up values from the global stack. After executing the instructions the resulting values can be put back onto the global stack.

Source code manipulations, self modification, coordinate system
Bees can also drop values anywhere in the source code, and can pick up values from anywhere (analogous to flying to a location and manipulating certain cells in the honeycomb). So, self-modifying source code can be realized.

Source code coordinate system
The origin of the coordinate system [row,column] = [1,1] is in the upper left corner. beeswax uses 1-based indexing. Bees that step outside the given honeycomb area are deleted, unless they are dropping values to cells that lie outside the current area of the honeycomb, which would let the honeycomb grow to the proper dimensions.

Positive growth of the honeycomb
*PF((F(D

The command  increments the top value of lstack.

[0,0,1]•

Then  sets all lstack values to the top value.

[1,1,1]•

executes two arithmetic shifts left.

[1,1,4]•

sets all lstack values to the top value again.

[4,4,4]•

The next  executes 4 arithmetic shifts, because the 2nd lstack value is 4 now.

[4,4,64]•

And the final  drops the lstack top value (its according character) to [row,column] = lstack[2nd,3rd].

So, the value 64 (its associated unicode character ) is dropped at (row,column)=(4,4). This extends the source code to a rectangle encompassing all code: *PF((F(D   @

“Negative” growth of honeycomb, coordinate system reset
Because the coordinate indices of the honeycomb are 1-based, growth in negative direction (‘up’ and ‘left’ in the source code) is only possible if the 2nd and/or 3rd local stack values are set to zero. Growth in negative direction can only be realized by steps of 1. The coordinate origin of the resulting source code is reset to (row,column) = (1,1) again:

*4F(@0~0@D

results in

@  *4F(@0~0@D

The new coordinate origin (1,1) of the honeycomb is set to the new upper left corner, where the  was put.

Available instructions in beeswax
Beeswax makes use of almost the entire range of printable ASCII characters for instructions.

Initial pointer creation
These instructions only get active at the beginning of the program.

Important notes about bee creation and bee execution order
At the beginning of a beeswax program, during initialization, bees are created in a fixed order as follows:

First, the interpreter reads in the program code and creates the according honeycomb. Then, the honeycomb is scanned for the initial bee creation instructions,  ,   and. The honeycomb is scanned column-wise, starting with the leftmost column. The column is scanned from top to bottom, then the process is continued in the next column, until the whole honeycomb is scanned.

Each of the instructions creates a set of bees, which are pushed on a pointer/bee stack in order of creation. For each creation instruction, the standard creation order of bees always follows the pattern below, in a counterclockwise fashion, starting at the lowest number. This always leaves the bee that was created last on top of the pointer stack:

2  1  3   β   0 4  5

In the following examples  marks the top of the stack.

→ [... 0 1 2 3 4 5]•

→ [... 2 5]•

→ [... 1 4]•

→ [... 0 3]•

During program execution, the instructions are executed according to the order of the bees on the pointer stack, from top to bottom. The last created bee is always on top of the stack and, every tick, its instruction is always executed first.

The cloning instructions,  ,   and   create bees in an analogous fashion, always leaving out the opposite direction the bee is coming from:

If the original bee is moving in the opposite direction, don’t create a clone. For every other position, clone the original bee and set its direction to the appropriate direction and push it on the pointer stack.

If the original bee is moving in one of these directions, just let the bee move on and don’t create a clone. If the original bee is coming from any different direction, change the direction of the original bee to 0, push a clone of that bee on the pointer stack, moving in direction 3.

If the original bee is moving in one of these directions, just let the bee move on and don’t create a clone. If the original bee is coming from any different direction, change the direction of the original bee to 1, push a clone of that bee on the pointer stack, moving in direction 4.

If the original bee is moving in one of these directions, just let the bee move on and don’t create a clone. If the original bee is coming from any different direction, change the direction of the original bee to 2, push a clone of that bee on the pointer stack, moving in direction 5.

Here is a beeswax example program that prints  to the console. This should demonstrate quite nicely how the bees that are created during initialization end up on the pointer stack. I leave it to the user to figure out the details. It shouldn’t be too hard:

W o   l   ` ``    e  H   `*`r`#`l`_`ld! ``     \/   , o

If a bee leaves the honeycomb during program execution, it gets marked as dead. Once all instructions of the pointer stack are executed, the dead bees get deleted, and the stack gets cleaned up, leaving the general orders of bees intact.

Pick up/drop values in the honeycomb (code manipulation)
[r,c] describes the [row,column] of a honeycomb cell.

Relative addressing
As everyone knows, bees don’t have a concept of negative numbers, but they discovered that they can use the most significant bit of an address to get around that. Thus, coordinates relative to a bee’s position are realized by the [two’s complements](https://en.wikipedia.org/wiki/Two's_complement) of the coordinates. This way, half of the 64-bit address space is available for local addressing without wraparound in each direction.

The maximum positve 64-bit two’s complement address is  or   in 64 bit hex. All values from 0 up to this value translate identically to the same 64 bit value. All values  in the opposite (negative) direction translate to. For example: is addressed by. is addressed by.

Always keep the UInt64 wrap-around in mind!

Local and global stack manipulations

 * marks the top of the stack.

Global stack (gstack) instructions
inside lstack stands for irrelevant values for executing an instruction.

File related I/O
The file bytes are reinterpreted as UInt64 words (big-endian). If the byte count of the file does not add up to full 64-bit words, the end of the file is padded to the next full 64-bit word length with  zero bytes. The UInt8 stream is reinterpreted as UInt64 words and pushed on top of gstack, 64-bit word by 64-bit word.

The 64 bit words are reinterpreted as groups of 8 bytes in big-endian order! UInt64[0x11000000000000ff] is reinterpreted as UInt8[0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x11]•

Cat program
_,}

Hello world
_`Hello, World!

Infinite output of '1's
_P~P{J

Squaring an entered number, return the result to STDOUT
_`Enter number:`TN{` squared=`~+.{

Output numbers from 1 to 100
*3~5~(~4+~0>P{Kp             b N<

Return n-th Fibonacci number
Clear version

#>'#{; _`enter n: `TN`Fib(`{`)=`X  ~P~K#{;    >@{; #>~P~L#MM@>+@"dM@~p                                    d       <

Compact version

;{#'<>~P~L#MM@>+@'p@{; _`n`TN`F(`{`)=`X~P~K#{; d~@M<

= Proof of Turing completeness =

By translating brainfuck instructions to beeswax.

Initialize the cells
Use the gstack to simulate the cells. For example, initialize gstack to hold 32768 cells:

_8F(~4~(   lstack[8,4,32768]

append loop to create the gstack:

>~0f~M'p    b     <

resulting in the full construct:

_8F(~4~(>~0f~M'p            b     <

Then put translated brainfuck code after the.

instructions
<      1~0h    if used for multiple instances, every following < in this group of <’s is appended as beeswax instruction h    >       1~0y    if used for multiple instances, every following > in this group of >’s is appended as beeswax instruction y

alternatively, for multiple instances:

<      ✔~0h    with ✔ being the number of <’s >      ✔~0y    with ✔ being the number of >’s

The stack wraps around in both directions.

For 64 bit cell size
+      g?Pf -      g?Mf

alternatively, for multiple instances:

+      ✔~g?+f      ✔ being the number of +’s in the bf code -      ✔~g?-f      ✔ being the number of -’s in the bf code

For 8 bit cell size
If we want to emulate 8 bit cells, we prepare the cells like below:

8F(~4~(>~0f~M'pz5~8(@          d      <

In this case, the translated bf code is appended after the.

Take the result after each  or   instruction %256 for 8 bit brainfuck emulation. In the examples below,  =256, which is equivalent to 8 shifted left 5 times.

This ensures that the value  is readily available for +/- instructions and does not have to be created from scratch everytime, which also shortens the beeswax program.

Single instance:

+      @Fg?P%f -      @Fg?M%f

Multiple instances:

+      ✔~g?+~@~%f~@      ✔ being the number of +’s in the bf code -      ✔~g?-~@~%f~@      ✔ being the number of -’s in the bf code

If we use the preparation routine from the beginning, we have to create the value  everytime we use the   or   instructions:

+      5~8(~g?P%f    -       5~8(~g?M%f

Alternatively, for multiple instances:

+      5~8(@✔~g?+~@~%f   ✔ being the number of +’s in the bf code    -       5~8(@✔~g?-~@~%f   ✔ being the number of -’s in the bf code

[ and ] instructions
Translate the loop instructions to actual beeswax loops, using its 2d capabilities ;)

>   [       >g"d                       bee enters at the leftmost >            d

p   ]       g'p>                       bee enters at the g              <

The examples have to be adjusted for the rank of the loop. The examples shown demonstrate the innermost loop, equivalent to a brainfuck structure like, using only one pair of brackets. Outer brackets grow larger in beeswax.

A brainfuck construct like  would look like:

>                       p            >    p    >    p    >g"d >g"d g'p> >g"d g'p> g'p>         d      <  d      <    d                          <

So, brainfuck loops become visibly loops in the beeswax translation.

. and, instructions
.      C

,      ,?f

External Resources

 * GitHub repository containing reference implementation in Julia, example programs and language specification