I've finally gotten my M interpreter project off the ground. M, for those not familiar with it, is the scripting language used by Matlab and Octave, and is oriented towards linear algebra and mathematical modeling. I had started idly working on it back when I was still in school as a way to pass the time on long train rides. I gave it up to focus on Parrot internals work for GSOC, and never went back to it because it felt to me like PCT was changing and evolving too rapidly for me to keep up with it.
Well things are more stable now and I found another interested participant for the project. Things are going very well now, and we're getting far more work done on this now then I was ever able to get done by myself. Blair is working on NCI bindings for the BLAS and LAPACK libraries, which will bring a lot of mathematical muscle to our little compiler and to the Parrot ecosystem as a whole. I've been focusing my attentions lately on getting some of the core syntax and idiosyncratic semantics of M implemented. Some things I've gotten to work now:
1) The ';' is used as a statement terminator like it is in Perl or C. However, it's optional. If ';' is ommitted from the end of a statement, the value of that statement is printed to the console. So writing "x = 5" will print "x = 5". A bare expression "5 + 6" will print "ans = 11". Writing "5 + 6;" will set the value of the default variable "ans" to 11, but won't print anything to the console. This mostly works.
2) Matrix indexing and function dispatching both use parenthesis. So "x(1)" is treated as the first element in array x if x is a variable, or is treated as calling the function x with argument 1 otherwise. This is confusing as hell in the parser, although it's an interesting design decision for the M language. You can interchange a function with a lookup table in M without having to change any calling syntax at all. This is partly implemented, although a few thorns are still standing in my way from getting this right.
3) Functions are typically all defined in their own files, so the function foo() will be defined in "libpath/foo.m". I've written a basic function dispatcher that handles this lookup, if a builtin function hasn't been found. Blair also did some great work refactoring my search path handling to be more correct and less hackish.
4) I've got basic Matrix definition implemented. You declare a matrix like this: x = [1, 2;3, 4] and if you leave the semicolon off, this will be printed:
x =
1 2
3 4
So that's looking good. Matrices are constructed by nesting ResizablePMCArrays, which isn't an ideal solution (especially as the dimensions of the matrix increase above 2, and we try to keep things uniform length).
So that's how things are progressing with Matrixy. I'd like to invite any other interested participants to check out the source code and see what progress we've made so far. There's a lot of work left to do and, especially as pertains to the linear algebra and mathematics work, a lot of features for Matrixy that could benefit the rest of Parrot world.
Matrixy at Googlecode
What happens if you write name(5) and there is a name array that only has 4 elements but there is also a name function?
If it automatically switches to using the function if there is no element at the requested index then you get memoize for free!
fibonacci(n) {
if( n < 2 ) {
fibonacci(n) = 1
else {
fibonacci(n) = fibonacci(n-1) + fibonacci(n-2)
}
return fibonacci(n)
}
Unfortunately, that's not how it works (or at least, I've never seen that effect). It binds to the function earlier then that, so you would probably get an error about the index being out of bounds or something.
My guess is that the name(5) will autovivify and return a value of 0. I need to test this though.