darjeeling - a roundabout routeWell by now if you follow Ruby much you've probably noticed the whole Will Rubinius be an acceptable Lisp ponderings or brainstormings or whatever you want to call it. And if you know me at all, you'd be aware that the union of such concepts is exactly the kind of thing that would excite me.
So I meddled around a bit with ParseTree. Honestly, it's ridiculous; the Ruby side of this kind of thing has been made more or less trivial by Ryan's great work:
require 'rubygems' require 'parse_tree' class Infuser def self.brew(klass) lisp(ParseTree.new.parse_tree(klass)).sub(/\(\(/, '(class Object (') end def self.lisp(leaf) leaf.respond_to?(: map) ? "(#{leaf.map{|l| lisp(l)}.join(' ')})" : leaf end end
Would you look at that. Like I said; pretty trivial. While we're on the subject of trivial, consider this:
class Foo def bar 1 + 1 end end
Infuser.brew Foo gives us this:
(class Object (class Foo (const Object) (defn bar (scope (block (args) (call (lit 1) + (array (lit 1))))))))
At this point you may be tempted to think yourself, "Hey, that looks like lisp! Run it through the compiler and see what it does." Unfortunately Ruby's object model is wildly divergent from Common Lisp's. (Though you could say that's very fortunate depending on your opinion of CLOS—I won't go there.) The point is, running the above code would require getting a subset of Ruby's object model running in Common Lisp. Running nontrivial code would basically require getting it completely ported.
Now that sounds hugely daunting task. It probably is. But I've got this wild idea that you'd only have to actually implement a fairly small subset of this in CL itself. The rest could be translated over from Ruby. I'm thinking all the portions of the implementation currently written in C would need to be redone in CL, and if the port is accurate enough then the portions of Ruby-the-implementation which are written in Ruby-the-language will be able to be translated through the infuser shown above. Now I know that the official Ruby has gobs and gobs of stuff implemented in C, but it seems to be a stated goal of Rubinius to decrease the C-to-Ruby ratio. That may be something that could be leveraged here. (Note to self: need to check out MetaRuby as well.)
There's another hiccup though—it seems there's no solid BDD framework for Common Lisp. A few weeks back I started writing behave.el for Emacs Lisp. The pieces are all coming together in my head, so it seems the thing to do at this point would be to finish it, port it to CL, and then start porting the Rubinius specs to it.
Have you looked at RLisp?
It runs its interpreter on top of the CRuby interpreter, so all the Ruby object stuff gets tossed right to real Ruby.
“You can do fancy stuff with your comment.”
Lies!
Evan: I’ve looked at that; yeah. It looks really cool, but it seems to mostly be cosmetic; it doesn’t support any of the cool Lispy things that Ruby lacks.
That’s basically the converse of what I’m trying to do. I’d like to leverage the years and years of head start that Lisp has had in the compiler arena and put a more easily-grokkable Rubylicious face on it. Obviously to support things like macros, the dialect will have to be a superset of Ruby, but that’s getting ahead of myself.
Gah! No fancy stuff?! Will remedy immediately.
Writing in Common Lisp a compiler with full Ruby language semantics is quite some work.
I did it for Ruby’s neighbour Python (project CLPython). Language-wise, Python is a subset of CL, in the sense that a big part of the effort is “connecting dots” between the two. Conceptually easy, just a lot of work : )
I think a CL compiler for Ruby will require similar effort.