once I made a programming language. Written an interpreter and stuff. I made the language to be quit hard.
Every line was a set of tokens (tokens may consist of anything but tabs and newlines), separated by tabs. The meaning of the line was defined by the number of tabs before the first token:
- 0 means a function definition, the first token being the function name, the ones that followed the parameters
- 1 means a function body: an instruction, the first token being the function name to call and the rest the arguments to call it with.
- 2 means an include file. The token is a filename that will be inserted similar to C's #include.
Now, there's one trick: every variable was a list of either an empty or a list of other lists. I called the language LiMa (List Mania, and it happened to be the name of a city I drove through on my road-trip through the US). But I never published the language.
There are no integers. No strings. Everything lists. But completely turing complete.
A few special functions:
">", with two tokens A and B, would insert A into the list B.
"<", with two tokens A and B, would get the last inserted element from B into A, or make A an empty list B was an empty list.
"|", with one token A, would display a single character, namely the one with as ASCII value being the number of items in the list A.
"||", with one token A, would input a single character and make A a list with the number of items being the ASCII value of the character.
Some more rules:
- An unused variable starts as an empty list.
- A line of a function body may start with a "?", followed by a tab, followed by an identifier A. The function of the rest of the line would only be executed if the list A was not empty.
- The function main is called upon start of the program.
- The arguments of a function will first be copied, and then copied back from left to right. So not really called by reference, but call by copy-back.
I studied this language for way too long, and found some tricks I never imagined. I even wrote a fully working Dijkstra implementation once. True, it was really slow. But it worked. And it looks great.
// This comment is actually a function name, way too long. We could theoretically call it.
// But we won't. That's what kind of makes this a comment.
// In functions, we make comments by simply calling a function that does nothing. I declared the function # for that.
// We can use as many parameters as we want, they're simply not used. And the variables will be just texts, being identifiers for empty lists.
> * a
> IAmEmpty a
# Clean the list, then add 64, then add 1
# We clean the list because * is an empty list. So a becomes empty as well.
# Then we push an empty list to a.
< a *
> * a
# First, write 'A' to the screen
# Then B
> * a
# Then a newline
# Just an example of how to use the "?" functionality. It will never actually run, but still:
? EmptyList main
Imagine a dijkstra in such a language.
Imagine a program that inputs an integer and displays it in base 10. Several hundreds of lines of code.
Now yet another puzzle: Make up a method to store integers (there are two proper ones I know of; one being a lot easier to implement but way slower), and write an addition function for it.
Of if you don't have much time on your hands: make up something simple. Like a NOT function.