First line is, obviously, just a comment, second one is the actual code, and the rest are test cases – when you run your code in test mode, it will run for input 0 and check if the output is 1, then run for 1 and expect 1 as output, and so on. Notice, in the last case, how simply can a function be applied to every element of a whole array.
We put on the stack the variable a and the number 1. Function > takes them off and compares. If a > 1, it puts 1 (true) back on the stack, and 0 (false) otherwise. So, that would be our while condition.
Then we have aa2%a3*1+a2/▲= which is basically a = a % 2 ? 3*a+1 : a/2, but written with Reverse Polish notation and with ▲ function acting as a teranry operator.
After the while loop is finished, we put the length of array A (A↹) on the stack. This is return value of our function. Of course, we could return the whole array (A) or its concatenated content (AS⥋).
Writing the QC interpreter was really fun! But writing its documentation is not gonna be so, I suppose... And hardly anybody is gonna read it anyway... So please, don't blame me for not being too thorough with it. I'll try to be concise here (nomen omen), but to still cover everything important.
Composer is a powerful package manager for PHP. It takes care of all the dependencies and stuff. To install it, simply run this command in your console.
Well... It's all about the stack. If you're still reading at this point, you're probably one of those people, who already know, what stack is. And the Reverse Polish notation, of course.
Every variable and literal (string, number, regex), when it's read by the interpreter, gets put on stack. Every function, on the other hand, pops some given (fixed!) number of elements from the stack and executes some operation on them, then puting its result back on the stack
For instance: what we'd normally write down as (2 + 4) * 3, in QC is: 2 4+3*. We put 2 on stack, then 4, and then we execute + function. It takes two arguments from the stack, adds them together, and puts the result, 6 back. We put 3 on top of that, and then * function comes in, taking those two values off, but giving 18 back. That's what we end up with at the top of the stack, so that's our result.
Note how 2 and 4 are separated by a space. Otherwise it would be understood as one number, 24. The space wouldn't be necessary if, for instance, we had a variable that's equal to 4. Let's say I. Then our code becomes just 2I+3*.
Btw, I just happens to be a predefined variable equal to whatever you provided your program with as input data. We have a couple of predefined variables, all listed at the end of this documentation, in Reference section. Actually, a lot of other stuff is listed there. Take a look, really. I'm not gonna explain everything here.
All the english letters, upper- and lowercase, are QC's variables. For the functions, we use other characters: either normal stuff like + or %, or something more fancy, like ☉, √, ⩲. Get used to it.
I know, there could be much trouble regarding Unicode usage. Not every console supports it, some websites might break it, blah blah... Oh c'mon, Unicode isn't magic, it isn't some freaky non-standard conceit! It's not my fault, if some tools you might be using don't support the XXI century.
When providing some input straight to QC as a PHP value, everything is fine, it knows exaclty what you meant. However, in the console or online interpreter, things get a bit more complicated. Writing 2 doesn't tell QC, if you mean a number 2, or a string with one character "2". So, the deal is:
if it's numeric, we parse it as a number; having a dot, makes it a float: 7. means 7.0, .7 means 0.7; and 7 means 7, the integer
debug info: a step-by-step list of which token is handled now and how does the stack look at that point,
Those types of data are handled by the AsideOutput object that you pass to $qc->run(). Of course, you can implement your own one, if you need to.
That's it. We put a string literal on the stack. Whatever is at the top of the stack at the end of the execution, is our output. We could also print it on the screen, instead of just returning it, if we use the ! function:
The Champernowne constant is equal to 0.1234567891011121314.... And the program below finds the first appearance of a given number (I variable) in its decimal expansion:
So what happens there in the code? First, we add I to T: IT+. I is our input, let's say 17, and T is predefined variable equal to ten. So now we have 27 on the stack. The ₁ function creates a range from 1 to its argument. So now our stack top is an array: [1 2 3 ... 26 27]. The whole "adding ten" thing is necessary for the 0 case.
abΦ finds the position of the first occurance of b in the string/array a. In our case: the position of I=17 in string 1234...2627. Which is 23, because Φ starts indexing at 0. To get the 1-based response, we have to increment. 23‡ is 24 – and that's our answer.
We make m steps, each lasting n seconds, and we randomly move to the left or to the right either by -2, -1, 0, 1 or 2 fields. Going below 0 or above 39 is not allowed.
abc⩥ – make sure a is between b and c. Here, we make sure that X is not less than Z=0 and not greater than 39.
SX*D+ – multiply S=" " times X (so we get X consecutive spaces), and then add D=".". "Add" means "concatenate", if we're talking about string, of course. In QC one function can do different things depending on the type of its arguments.
Now, we just print (!) our string and wait (ƶ) for b seconds. After the loop we put a null (·) on the stack, to make sure the program doesn't return anything.
If you read the example in Readme, you should already be able to understand this code. What's different here, is that we use recursive calls. Easy thing, right?
Oh, and by the way: we don't have to calculate factorial like that. There's an in-build function for it:
QC is open source, available on Gitlab. Feel free to check out the code, fork, sumbit pull requests, whatever. I'd appreciate!
QC is written in PHP, and the libraries have to be as well. Library is just a set of functions that extend QC's default function set. Registering them is easy:
Those classes must extend AbstractFunction, i.e. define their arity, some description string, and what they actually do. They can do anything. They have access to the stack, all the variables, and the aside output.
☉ ArrayToVars 1 Iterates over $a (or I if stack is empty) and sets its values as variables a, b, c, ... consecutively
☍ StringArray\FindSubrange 3 Subarray of $a starting with $b (negative $b means counting from the end) of length $c