Snowman language documentation
September 13, 2016 ยท View on GitHub
This is the documentation page for the Snowman esoteric programming language.
Design goals
- Be as confusing as possible.1
1: while still being feasible to learn and write a simple program in a few minutes.
Snowman was named as such because it has 8 variables, and a snowman looks like an 8. (It's also a golf term, and I was introduced to esolangs via Programming Puzzles & Code Golf Stack Exchange.)
Variables
Snowman has eight "normal" variables. They can be visualized as follows:
a b c
d e
f g h
The variable operators work according to this "layout."
Variables can be of the following types:
- undefined (all 8 initially start out as this)
- number
- block
- array
Additionally, zero or more variables are marked as "active variables." The effect of this will be covered in more detail later. Initially, there are no active variables.
Variable operators
These are operators that have to do with manipulating the 8 variables in Snowman. They are all ASCII characters that are not upper- or lowercase letters.
Rotation operators
/: cf\: ah_: fh[: af]: ch|: bg-: de': bd`: be,: eg.: dg^: dbe>: aef<: cdh
These operators rotate variables; for example, / switches the c variable
with the f variable. They are all symbols that consist of only straight lines
that can be drawn in one stroke.
Rotation is done clockwise. For example, > causes the e variable to take on
the previous value of the a variable, f becomes what e was, and a
becomes what f was.
Active variable operators
(: af): ch{: bdg}: beg~: invert all (abcdefgh)@: rotate (done clockwise, abcehgfd -> bcehgfda)%: reflect (abcehgfd -> hgfdabce)?: mark all as inactive$: save current state&: restore saved state
These operators toggle which variables are marked as "active;" for example, (
will mark variables a and f as active if they are currently inactive, and
inactive if they are active. They are all symbols that have curvy lines.
Permavar operators
*: retrieve a value, set the current permavar's value to this#: store the current permavar's value
These operators have to do with permavars. These are variables that you can freely store to / retrieve from.
Note: in the preceding documentation, "store" is defined as follows: place in first undefined active variable slot. A "store" operation does nothing if all active variables are full or there are no active variables.
Similarly, a "retrieve" does the opposite. It selects the first active variable, and errors if it's undefined. Otherwise it sets it to undefined and returns what its value was.
To switch the current permavar, use the =+! characters. Permavar names are
zero or more =, then a + or !. So, possible peramvar names are +, !,
=+, =!, ==+, ==!, ===+, etc. The permavar starts as + by default.
The following operators have to do with literals:
:...;: store literal block (can be nested)"...": store literal string-array ("strings" are just arrays of ASCII codes; use\"to include quotes within string literals)- (one or more digits): store literal number
Literal arrays don't exist. You can create empty arrays with "" and append to
them with letter operators.
Letter operators
Letter operators are all either two or three letters long. They are listed in the following format:
foo(args) -> rtn: desc
where foo is the operator, (args) is a list of the types of the arguments the
operator takes (n = number, b = block, a = array, * = any, - = void),
rtn is a list of the types of the operator's return values, and desc is a short
description.
Arguments to a letter operator are the list of the first n active variables, where n is the number of arguments. If any of these are undefined, it is an error. If there are less than n non-undefined active variables, it is also an error.
Different capitalization invokes different effects when calling a letter-operator. This is documented in the table below:
aB -> 2-letter, consume
ab -> 2-letter, do not consume
AbC -> 3-letter, consume
ABc -> 3-letter, do not consume
Letter operators called with the "do-not-consume" strategy return values by placing them in order inside the undefined active variable slots. If there are not enough or too many undefined active variables, undefined behavior is invoked.
This means that if you are calling a letter operator via "do-not-consume" that takes two arguments and returns one value, you must have at least three active variables.
If you call a letter operator with the "consume" strategy, it will consume its arguments (set them to undefined) before returning a value. This allows you to call a letter operator that takes two arguments and returns one value with only two active variable slots, although you will lose the original variables. In this case, the second active variable slot remains undefined and there is no error.
If there is a type mismatch (if you give arguments of the wrong type to the operator), it is an error.
Number operators
nde(n) -> n: decrementnin(n) -> n: incrementnab(n) -> n: absolute valuenf(n) -> n: floornc(n) -> n: ceilingnro(n) -> n: roundnbn(n) -> n: bitwise NOTnbo(nn) -> n: bitwise ORnba(nn) -> n: bitwise ANDnbx(nn) -> n: bitwise XORna(nn) -> n: additionns(nn) -> n: subtractionnm(nn) -> n: multiplicationnd(nn) -> n: divisionnmo(nn) -> n: modulonl(nn) -> n: less thanng(nn) -> n: greater thannr(nn) -> a: rangenp(nn) -> n: powernb(nn) -> a: to base
Array operators
aso(a) -> a: sortasb(ab) -> a: sort byaf(ab) -> *: foldac(aa) -> a: concatenate arraysad(aa) -> a: array/set differenceaor(aa) -> a: setwise oraan(aa) -> a: setwise andar(an) -> a: array repeataj(aa) -> a: array joinas(aa) -> a: splitag(an) -> a: split array in groups of sizeae(ab) -> -: eacham(ab) -> a: mapan(an) -> a: every nth element (negative n = reverse)ase(ab) -> a: selectasi(ab) -> n: select by index / index of / find indexaal(an) -> a: elements at indeces less than naag(an) -> a: elements at indeces greater than naa(an) -> *: element at indexal(a) -> n: array lengthaz(a) -> a: zip/transposeasp(anna) -> a: splice (first argument is array to splice, second is start index, third is length, fourth is what to replace with)afl(an) -> a: flatten (number is how many "layers" to flatten; 0 means completely flatten the array)ash(a) -> a: shuffle array
"String" operators
sb(an) -> n: from-base from array-"string"sp(a) -> -: print an array-"string"sm(aa) -> a: regex match; first array-"string" is search text, second array-"string" is regexsr(aaa) -> a: regex replace; first array-"string" is string to operate on, second array-"string" is regex, third is replacement textsrb(aab) -> a: same assrbut with a block instead of array-"string"
Block operators
br(bn) -> -: repeatbw(bb) -> -: while ("returned" value from second block is simply first non-undefined active variable, which is set to undefined after reading it)bi(bb*) -> -: if/elsebd(b) -> -: do (:...;bDis basically the same as:;:...;bW)be(b) -> -: execute / evaluate
(Any type) operators
no(*) -> n: boolean/logical not (returns1for0 :; [],0otherwise)wr(*) -> a: wrap in arrayts(*) -> a: to array-"string"bo(**) -> n: boolean/logical and ("bo" = "both" because "an," "ad," and "nd" are all takenor(**) -> n: boolean/logical oreq(**) -> n: equal?du(*) -> **: duplicate
"Void" operators
vn(-) -> -: no-op (do nothing)vg(-) -> a: get line of input (as an array-"string")vr(-) -> n: random number [0,1)vt(-) -> n: time (seconds since epoch)va(-) -> a: get command line args
Other characters
Whitespace and non-printable-ASCII characters are all stripped before
processing your Snowman program. This means that 1 1 will not have the
desired effect (it will store 11). To store two 1's, use 1vn1 or 1vN1.
Two slashes in a row (//) normally have no effect, so this represents a
comment (that continues until a newline character).
Two brackets in a row ([[ and ]]) normally have no effect, so these
represent inline comments (the comment goes from the [[ to the ]]).
Two parentheses in a row ((( and ))) normally have no effect, so these
represent subroutines. Any code wrapped in ((...)) will be executed in an
entirely new "environment." This means that all variables (and which ones are
active) are reset. Permavars and the active permavar are kept the same. These
can be nested.
Example programs
You can find some examples of Snowman programs in the examples
directory.