Programming Languages Through The Years
2013 - Dogescript
Dogescript is a language created in 2013 by Zach Bruggeman. It is nothing more than a syntax-replacement for Javascript to make it read like the internal monologues of memetic Shiba Inus.
Hello doge
console dose loge with "Dogescript was made in 2013!"
ASCII Art
such N much N
much i as 0 next i smaller N next i more 1
very doge is ("N" + " ".repeat(N-2) + "N").split('')
s[i] is "N";
console dose loge with doge.join('')
wow
wow
GCD
such gcd_doge much doge, dooge
rly dooge
gcd_doge(dooge, doge % dooge)
but
rly doge smaller 0
-doge
but
doge
wow
wow
2015 - Retina
Retina is a regex-based programming language, which I wrote to be able to compete in PPCG challenges with regex-only answers, without having the unnecessary overhead of calling the regex in some host language. Retina is Turing-complete. To prove it I've implemented a 2-tag system solver as well as Rule 110. It is written in C#, hence it supports both the .NET flavour (by default) and the ECMAScript flavour (via a flag).
Retina can operate in multiple modes, but the most relevant one for computations (and the Turing-complete one) is Replace mode. In Replace mode you give Retina an even number of source files. These are then paired, the first of each pair being a regex, and the second a replacement. These are then executed in order, manipulating the input step by step. The regex can also be preceded by a configuration (delimited with `
). The most important option (which makes Retina Turing-complete) is +
, which makes Retina apply the replacement in a loop until the result stops changing. In the following examples, I'm also using ;
, which suppresses output on intermediate stages.
In each of the following submissions, each line goes in a separate source file. (Alternatively, you can use the new -s
option and put all lines into a single file.) Empty files/lines are represented as <empty>
. Files/lines containing a single space are represented as <space>
.
The explanations are quite long, so I've moved them to the end of the post.
The Programs
"Hello, World!" Variant
<empty>
Retina was made in 2015!
ASCII Art N
This assumes that STDIN is terminated with a newline.
;`^
#
;+`(\d*)#(?:(((((((((9)|8)|7)|6)|5)|4)|3)|2)|1)|0)
$1$1$1$1$1$1$1$1$1$1$2$3$4$5$6$7$8$9$10#
;`#
<empty>
;`\d
N
;`.(?<=(?=(.*\n)).*)|\n
$1
;`N(?=N\n.*\n.*\n`$)
<space>
;+`N(?=.?(.)+\n.* (?<-1>.)+(?(1)!)\n)
<space>
;`(?<=^.*\n.*\nN)N
S
;+`(?<=\n(?(1)!)(?<-1>.)+S.*\n(.)+N?)N
S
S
<space>
GCD
This requires that STDIN is not terminated with a newline.
;`\b(?=\d)
#
;+`(\d*)#(?:(((((((((9)|8)|7)|6)|5)|4)|3)|2)|1)|0)
$1$1$1$1$1$1$1$1$1$1$2$3$4$5$6$7$8$9$10#
;`#
<empty>
;`\d
1
;`^(.+)\1* \1+$
$1
;`$
#:0123456789
;+`^(?=1)(1*)\1{9}(#(?=.*(0))|1#(?=.*(?<3>1))|11#(?=.*(?<3>2))|111#(?=.*(?<3>3))|1111#(?=.*(?<3>4))|11111#(?=.*(?<3>5))|111111#(?=.*(?<3>6))|1111111#(?=.*(?<3>7))|11111111#(?=.*(?<3>8))|111111111#(?=.*(?<3>9)))
$1#$3
#|:.*
<empty>
Explanations
"Hello, World!" Variant
This is fairly trivial. It takes no input (i.e. an empty string), matches nothing and replaces it with Retina was made in 2015!
. One can also make it work for arbitrary input, by replacing the pattern with [\s\S]*
for instance. That would slurp STDIN and replace all of it with the output.
ASCII Art N
This has quite a lot of stages. The idea is to convert the input to unary, create an N x N block of N
s and then "carve out" two triangles. Let's go through the individual stages. Remember that ;
merely suppresses intermediate outputs, but +
causes the replacement to be applied in a loop.
;`^
#
Simple: prepend a #
to the input. This will be used as a marker in the conversion to unary.
;+`(\d*)#(?:(((((((((9)|8)|7)|6)|5)|4)|3)|2)|1)|0)
$1$1$1$1$1$1$1$1$1$1$2$3$4$5$6$7$8$9$10#
This converts one digit to unary. It takes the digits already converted (\d*)
and repeats them 10 times. And then it takes the next digit and appends the appropriate number of digits. The actual value of the digits is irrelevant at this stage. When the #
reaches the end of the number, the regex no longer matches, and the conversion is done. As an example, the number 127
will be processed as
#127
1#27
111111111122#7
1111111111221111111111221111111111221111111111221111111111221111111111221111111111221111111111221111111111221111111111227777777#
where the last line contains exactly 127 digit characters.
;`#
<empty>
;`\d
N
Two simple stages which get rid of that #
and then convert all the digits to N
. In the following I'll use input 7
as an example. So now we've got
NNNNNNN
The next stage
;`.(?<=(?=(.*\n)).*)|\n
$1
replaces each N
with the entire string (remember that it contains a trailing newline), and also removes the trailing newline itself. Hence, this turns the single row into a square grid:
NNNNNNN
NNNNNNN
NNNNNNN
NNNNNNN
NNNNNNN
NNNNNNN
NNNNNNN
Now the upper triangle. First, we start things off by turning the N in the lower right corner into a space:
;`N(?=N\n.*\n.*\n`$)
<space>
The lookahead ensures that we're modifying the correct N
. This gives
NNNNNNN
NNNNNNN
NNNNNNN
NNNNNNN
NNNNN N
NNNNNNN
NNNNNNN
And now
;+`N(?=.?(.)+\n.* (?<-1>.)+(?(1)!)\n)
<space>
is a regex which matches an N
which is above or at the top left corner of a space character, and replaces it with a space. Because the replacement is repeated, this is essentially a flood-fill, which turns the 3rd octant from the initial space into more spaces:
N N
NN N
NNN N
NNNN N
NNNNN N
NNNNNNN
NNNNNNN
And finally, we repeat the same thing with the bottom triangle, but we use a different character, so the already existing spaces don't cause a wrong flood fill:
;`(?<=^.*\n.*\nN)N
S
sets the seed:
N N
NN N
NSN N
NNNN N
NNNNN N
NNNNNNN
NNNNNNN
Then
;+`(?<=\n(?(1)!)(?<-1>.)+S.*\n(.)+N?)N
S
does the flood-fill.
N N
NN N
NSN N
NSSN N
NSSSN N
NSSSSNN
NSSSSSN
And finally
S
<space>
Turns those S
into spaces and we're done:
N N
NN N
N N N
N N N
N N N
N NN
N N
GCD
GCD in unary is actually very trivial with regex. Most of this consists of the decimal to unary and unary to decimal conversion. This could be done more compactly, but this isn't a code golf, so...
;`\b(?=\d)
#
;+`(\d*)#(?:(((((((((9)|8)|7)|6)|5)|4)|3)|2)|1)|0)
$1$1$1$1$1$1$1$1$1$1$2$3$4$5$6$7$8$9$10#
;`#
<empty>
;`\d
1
These stages are essentially the same as above, except that both input numbers are converted, and the result uses 1
s instead of N
s (not that it matters). So if the input was 18 24
, then this would produce
111111111111111111 111111111111111111111111
Now
;`^(.+)\1* \1+$
$1
is the entire GCD computation. We match a common divisor by capturing a number of 1
s, and then using backreferences to ensure that both numbers can be written by repeating that string (and nothing else). Due to how backtracking works in the regex engine (i.e. that .+
is greedy), this will always yield the greatest common divisor automatically. Since the match covers the entire string, we simply write back the first capturing group to get our GCD.
Finally, the unary to decimal conversion...
;`$
#:0123456789
Append a marker #
, a delimiter :
and all digits to the string. This is necessary, because you can't produce new characters conditionally in a regex replacement. If you want conditional replacement, you need to pull the characters from the string itself, so we put them there.
;+`^(?=1)(1*)\1{9}(#(?=.*(0))|1#(?=.*(?<3>1))|11#(?=.*(?<3>2))|111#(?=.*(?<3>3))|1111#(?=.*(?<3>4))|11111#(?=.*(?<3>5))|111111#(?=.*(?<3>6))|1111111#(?=.*(?<3>7))|11111111#(?=.*(?<3>8))|111111111#(?=.*(?<3>9)))
$1#$3
This is the inverse of the unary expansion earlier. We find the largest multiple of 10 that fits into the current string. Then we choose the next digit based on the remainder, and divide the multiple by 10, while moving the marker through the digits.
#|:.*
<empty>
And lastly just a cleanup step to get rid of the marker, delimiter and the helper digits.
2013 - Snap!
Snap! is a language based on Scratch, made at Berkeley University. It is an upgrade to Scratch featuring first-class data and custom blocks (functions). Like Scratch, it is not text based, but rather done by visual "blocks" that snap together.
Snap!, written in JavaScript, is the successor to BYOB, which was written in Squeak Smalltalk. Snap! was beta released for public consumption in March 2013.
Snap! is actually not an esoteric language. It is used as the programming language for the Beauty and Joy of Computing (BJC) AP CS course at Berkeley and others.
I helped out with testing and stuff.
"Hello World" variant
ASCII Art "N"
This uses the stdlib for some of the blocks.
Pretty basic looping here. Takes an input. Then we just add it all together and say it (result for n=5):
I took the liberty here to just use 2 spaces instead of 1, because Snap! doesn't say stuff in monospace.
GCD
The Euclidean algorithm isn't very fast, but it works, and is pretty simple. (Sorry, i made a typo in the block name. Now i closed the tab without saving. It'll just have to stay.)
This function definition will then produce this block: