I was made aware of the supposed existence of a pony programming language (FiM-based, obviously) by a friend of mine in lecture one morning. He said he found it on reddit, but after many, many Google searches I was only able to find a barren, empty Google Code repository with no details or implementations. I was deeply disappointed for a few minutes before I realized I could write the damn thing myself. It probably wouldn't be good, complete, or usable in the sense that anyone could write an interpreter for it (dear past self: it isn't good at all), but I felt like validating my in-progress degree to some extent. I am also a fan of jokes that go on for far too long.
And so, ladies and gentlecolts, I present to you the rough syntax of what I'm dubbing FiM++.
EDIT: Here is a sample implementation of the 99 Bottles of Beer algorithm by DeftCrow using my syntax. He includes a more formal syntax in the description.
You can also check the comments section for more discussion on where this spec is workable and where it is lacking (which I may fix later) and some more example programs like Hello World.
FiM++ is a dynamically-typed, interpreted, object-oriented language that takes the form of the pony of your choice (I used Twilight for my specification) writing a letter to Princess Celestia. Functions in the language are formatted as paragraphs of the letter. It is intended to be read easily and as in-order as possible, to emulate a letter format. Each letter takes the form of a class, and each program can consist of multiple letters if one so chooses, but the minimum interpreted unit is the class, much like Java. The language does not support libraries- because we are sending a letter the code must be as lightweight as possible. Therefore, all features of the language are packaged with the base interpreter. Datatypes can be enforced if the user desires.
Each class begins with the header, which always appears thusly:
Dear Princess Celestia: Letter One
Brackets for delimiting code blocks are discouraged, because this breaks the letter format, but can be used if the user desires. They will not be used for the remainder of the specification - whitespace will be used in its place, much like Python. Princess Celestia is the reserved keyword for class creation and thus must always be the first recipient. 'Letter One' is the name of the class.
Interfaces can be added to the class header by extending the opening line thusly, using commas to delimit the interfaces:
Dear Princess Celestia, and Princess Luna, and Princess Cadance: Letter One
Each interface can define certain paragraphs (functions) that must be filled out in the class. Keep in mind that interfaces, not being classes, do not need to have Celestia as their first recipient. One instantiates and calls a regular class thusly:
I wrote you another letter! It's titled Letter Two.
'Letter Two' is now an instantiated object and can be used as such; for example, it can be used to insert a paragraph (function) from the new class into the current class. One can also declare an object and instantiate it later in the code:
I wrote you another letter!
Oh, about that other letter. It's titled Letter Two!
The main function is defined thusly:
Today I learned
Your faithful student, Twilight Sparkle.
The main method will never take any arguments, such as command line args, for ease of use. Also, letters do not have a command line, so that would be silly. The proper return value for the main method would consist of the 'your faithful student' line, with the return argument being the name. This return is not strictly necessary but may vary depending on your interpreter.
Functions aside from the main function begin thusly:
I learned about ducks
Functions are called by their tag: in this case, 'friendship'. Return values from functions are not strictly necessary and can be void. One can optionally add arguments to these regular functions like so:
I learned about friendship with Spike and Rarity
Spike and Rarity are now usable in that function. All arguments are passed by magic- that is, by reference.
There is a keyword 'I' which works like most languages' 'self' operator. Instead of referring to the class instance, it refers to the writer of the letter. This must be declared elsewhere.
Variable assignment is handled thusly:
Did you know that Spike is a dragon?
In this case, this is assigning the string value ‘dragon’ to the variable name ‘Spike’. Spike could have also been any other value, with the exact datatype being determined at runtime.
Although the language is dynamically typed, certain checks are still done on operations between two invalid variables. If one were to write something about Pinkie Pie going on a date with a number, the interpreter should throw an exception- in this case, a RidiculousException.
Loops are also supported in FiM++. The syntax for a simple loop is thus:
I did this 100 times…
Froward-thinking as the writer of this specification was, a version of try-catch-finally blocks are also implemented:
I did this 100 times, keeping a close eye out.
// codeIt didn't work, but I knew why.
// codeIn the end, I did this instead.
That should be enough to get an interpreter writer started on implementing this language. One final note: the reserved keyword 'friendship' should always be interpreted as 'magic', otherwise you risk tearing apart the very fabric of the universe strands that Equestria resides on.
The task is up to you. Good luck. We're all counting on you.