For starters, note that Spitewaste is a strict superset of Whitespace (assembly) insofar as it doesn't add anything to the instruction set. That is, what we ultimately have to work with are a stack, a "heap" (hash, dictionary) of integer key-value pairs, and these 24 instructions:
stack manipulation | |
push n |
Push the value n onto the stack. |
pop |
Remove the value at the top of the stack. |
dup |
Duplicate the value at the top of the stack. |
swap |
Swap the top two values of the stack. |
copy n |
Place a copy of the nth value at the top of the stack.copy 0 is a funny way to write dup |
slide n |
Remove n values from the top of the stack, but preserve the top. |
control flow | |
label n |
Mark a position in the program and name it n. |
jump n |
Unconditionally jump to label n. |
jz n |
Pop the stack and jump to label n if the popped value was zero. |
jn n |
Pop the stack and jump to label n if the popped value was negative. |
call n |
Jump to label n, expecting it to ret in order to return to this call site.
|
ret |
Return to the most recent call site. |
exit |
Halt execution immediately. |
arithmetic | |
add |
Pop the top two values of the stack and push their sum. |
sub |
Pop the top two values of the stack and push their difference. The top gets subtracted, so push 3 push 5 sub leaves -2 on the stack. |
mul |
Pop the top two values of the stack and push their product. |
div |
Pop the top two values of the stack and push their quotient. Note: floored, truncating division so -5 / 2 == -3 |
mod |
Pop the top two values of the stack and push their modulus. Note:-1 % 4 == 3 |
heap access | |
store |
Pop the value then the key and store the pair in the heap.push 4 push 2 store => {4: 2} |
load |
Pop the key and push the associated heap value. Note: Undefined heap slots have an implicit value of 0. |
input/output | |
ichr |
Read a character (byte) from stdin , pop a key from the top of the stack, and store the byte in the heap at that key. |
inum |
Read a number from stdin , pop a key from the top of the stack, and store the byte in the heap at that key. |
ochr |
Pop the top of the stack and print it (as a character) to stdout . |
onum |
Pop the top of the stack and print it (as a number) to stdout . |
A standard library! Writing a Whitespace program from scratch can be a daunting endeavor. TODO: more here.
Pretty much every program needs strings, and Spitewaste has 'em! But how? Well, a string is ultimately just a sequence of bytes, and we can use the power of exponents to smush multiple numbers into a single value. If we had the numbers 3, 9, and 4, we could easily encode them as a single base-10 number: 3 × 102 + 9 × 101 + 4 × 100 = 394. Strings in Spitewaste are similarly encoded, except backwards (as an implementation detail) and in base-128 rather than decimal.
When you say push "ABC"
, the assembler transforms it into push 1106241
, the value of: 67 ('C') × 1282 + 66 × 1281 + 65 × 1280. Whitespace interpreters SHOULD (and many do) support arbitrarily large integers, so we don't have to worry about these representations not fitting into 64 bits. Once we're able to pass strings around as individual values, a plethora of possibilities opens up, and the standard library contains many string functions to reflect this.