Posts Tagged ‘compiler’

Just a little bit of progress

Thursday, January 22nd, 2009

Well, its been somewhat slower going for the implementation of Fire lately. The interpreter I’m implementing is fairly simple, just an AST and direct interpretation of that, kind of like a Lisp meta-circular evaluator, but it has been surprisingly difficult to get around the complexity of the interpreter. I’m starting to thing this project may take a little longer than I originally expected, but that’s OK, it’s still been quite a lot of fun so far.

The biggest hurdle I’ve stumbled on over the past couple of weeks is getting the actual interpreter doing anything at all. There’s plenty of code sitting in the modules, but none of it can actually work since I haven’t quite managed to finish the implementation based on the design in use.

So Fire is basically just a heavily modified Smalltalk (or Self.) Most of the semantics are the same, with the significant exclusion of directly modifiable variables—but even those are supplemented with transaction variables and more functional programming facilities. At least that’s the design of the language so far.

The problem is that Fire, like Smalltalk, uses strict evaluation and at least some of the methods may need to, gasp, perform IO! To actually implement something like this, I have to implement the strict evaluation using the IO monad, even if it’s only by composing monads (or similar.) The story doesn’t quite end there though.

Programmers can also define local methods within a method in Fire. These methods are part of the lexical context, and correlate to the respective extension to the message send syntax. This means that the lexical context must be threaded through the evaluation of statement in a method.

Also, not all method calls return successfully. The return operator is also a variation of the normal return from a message send. The design of Fire here, calls for the usage of an Either return value, where the Left constructor provides a Fire exception object.

We would essentially like to hide the general flow using a monad for these two so that implementing methods for Fire in Haskell is as straight-forward as possible, not to mention the implementation of the interpreter itself.

So the decision I’m going with at the moment is to ignore any direct IO, which may eventually have to be reified back in later on, as well as transactions which should be a little simpler to put back in, and create a monad that captures both pieces of information. In theory, maybe it’s possible to implement this by combining monads—but the truth is, I’m just not that good yet. For that matter, this will be the first monad I’ve implemented (besides simple examples.)

Before I attempt the new design for the interpreter however, I also have another task I’m looking at which should be the topic of my next post. Testing Parsec parsers. All I’m going to say for now is that it involves QuickCheck, possibly because I haven’t actually finished writing the code yet. Until then, back to coding for me.

– Lorenz

The Prototype Pattern and Extensible Compilers

Saturday, November 1st, 2008

During some of the early design work on the Mention programming language, I recognized that a fixed parser would be unable to deal with a great number of interesting language problems. Things like embedded SQL and other DSL language, or perhaps even a unit notation.

All of these things could be added into a syntax, I believe, with a carefully constructed extensible parser. Each extension would become a libraries (modules) adding or replacing function points in the existing parser later reusing some of them as part of the extended syntax. (The actual parser would be based on Parsec and other similar combinator parsers. OMeta is also related to this parser architecture.)

The problem with adding new syntaxes to a language isn’t just the parser implementation however. Most of the really tricky problems actually come from the rest of the tool chain. Things like the compiler, debugger, profilers, editor, and a bunch of other potential tools. It had become clear to me that I wasn’t just working on an extensible parser, but rather an extensible language, and that meant an extensible compiler architecture.

Basically I thinking about a completely extensible intermediate language, which would power a set of semi-extensible libraries for implementing the bulk of the tool-chain. These libraries will take the leg-work out of processing the source code, and will allow the tools to manipulate or interact with the code in its intermediate form (this includes editors and analytical tools). The only problem I saw was that I had absolutely no idea how to construct such an intermediate language, little own how to write tools and libraries to interact with it.

Anyway, recently I run into the latest (at the time) Steve Yegge post, with a somewhat inspiring discussion about the Prototype Pattern (The Universal Design Pattern). After musing about pattern (again) for a couple of days, it finally hit me, I had the architecture all wrong. This isn’t just some extensible compiler or parser…this was the Self programming language…redesigned, implemented and tailored for the task of compiler writing. The AST is simply a specialized variation of the Prototype pattern, or more succinctly, a compiler is just a constrained dialect of Self, designed for compiler tasks.

So this my proposal is this, use the prototype pattern for Mentions AST and build a framework of libraries and tools designed to aid in the maintenance and development of an AST and the compilers, parsers, debugger, et cetera, which depend on it.

There are already a few pitfalls that I can imagine coming out of this system. For one, a good namespace or typing system will probably be required to prevent name conflicts. That is, each extension or collection of extensions would add only private collections of attributes, while a smaller group of shared public attribute interfaces would be used to facilitate cooperation between extensions. And then there’s still the issue of expected behavior, which may be complicated by the potential for different combinations of compiler extensions to inadvertently interact in unexpected ways.

In any case, I believe that this will be one of the key features of the core Mention programming language and it may even make some of the more complicated features like type systems easier to implement and experiment with later on. At the very least, you can expect to see some follow up material on this when I start to get further into the implementation of the Mention.

– Lorenz