Listening To Reason

random musings about technologies by Andy Norris

07 February 2006

Why isn't there a DOM for JavaScript?

I've been working a lot with JavaScript, along with all the other current web building blocks: XHTML, CSS, XmlHttpRequest, etc. And I've really grown to like the HTML DOM as a means of managing the display model for a web application. I've also grown to really like JavaScript, despite the somewhat annoying limitations imposed by trying to keep the size of your code and the number of files the code is in small.

Something I've started wondering about, though, is why there isn't something analogous to the DOM for managing JavaScript code itself. It's not so much a document, so I suppose I ought to call it a Code Object Model -- but given the confusing acronym that would result, let's just call it a Reflection Object Model (ROM). This is a lot like the kind of reflection you can do with Java or C#, of course, but with one important difference: everything important in JavaScript is dynamically bound, so you aren't limited to looking at your code, you can freely modify it.

Of course, JavaScript has reflection already, but it isn't very atomic or friendly to code-level manipulation. You can recover an entire function or replace it with a different one easily enough, but if you want to traverse inside the code, examine an internal variable, and revise it, you'll either have to use regular expressions or parse the code yourself.

What would be more useful is if there were an integrated model that you could use to traverse an operand-tree style model of the code. So your code might look something like this:

var fm = ROM.GetFunctionModel("myfunction");

// iterate through lines of code
foreach (var statement in fm.childNodes) {

   // find statements where the top-level operation is
   //   an assignment
   if (statement.operator && statement.operator ==
         ROM.Operator.Equals) {
      var eq = statement.operator;
   
      // find cases like a = b + c, where the right 
      //   side of the assignment is compound, as
      //   opposed to a = b cases;
      // also, only cases where the operation is addition
      if (eq.childNodes[1].isOperator() &&                   
            eq.childNodes[1] == ROM.Operator.Addition) {
         var add = eq.childNodes[1];

         // find cases where the right side of addition 
         //   operation is the number 2
         if (add.childNodes[1].isNumber() &&
               add.childNodes[1].literal == 2) {

            // replace the number 2 with the number 3
            var newElem = ROM.Number(3);
            add.replaceNode(add.childNodes[1], newElem);
         }
      }
   }
}

This hypothetical syntax probably isn't perfect, but it should give you a pretty good idea of what it would look like to manipulate code programmatically at runtime using a ROM.

By the same token, ROM would have a perfectly good code emitter, as well. Generate code using the ROM, then emit valid JavaScript into an easy-to-download, human-readable file. Statement objects could even have a comment attribute which would insert comments into the code appropriately.

I'll have more on this later.

Tags: , , ,

0 Comments:

Post a Comment

<< Home