D to Javascript converter (a hacked up dmd)

Adam D. Ruppe destructionator at gmail.com
Sat Mar 17 22:04:48 PDT 2012


This is still alive:

https://github.com/adamdruppe/dmd/tree/dtojs

Merging in DMD changes as they happen has been fairly
easy, so we have things like UFCS in there.

I'm pretty happy with the core setup, though it still
isn't finished. Enough of the D language works like
you expect that you can do a lot of things with it
naturally.

Thus, I've moved on to libraries. I previously
talked about the jslang and browser packages. These
provide zero-overhead, direct access to javascript
built-ins.

You can also use a good chunk of the real Phobos in
here if you want.


But now, I'm adding minimal overhead nicer libraries,
including a port of my dom.d, adopted to try to
cover some browser incompatibilities. (The browser
package, being zero overhead, makes no attempt at
this. It just provides the tools to DIY.)


The trick is though, doing it with as lean code as
possible. Here's my domtest.d:

import arsd.dom;
import browser.window;

void main() {
	Element e = document.getElementById("cool");
	e.addClass("sweet");
	e.style = "font-weight: bold;";
	e.style.fontSize = "30px";
	e.innerText = e.style;
	window.alert(e.parentNode.tagName);
	e.removeFromTree();
}


It generates about 2 kb of javascript, libraries
included, after you strip unused functions and
reduce the variable name length. (NOT gzipped!)

Let's talk about one line at a time:

	Element e = document.getElementById("cool");

In browser.document, there are JSElement and JSDocument
classes defined. Here, though, I'm using a custom
type: Element.

The implementation for this uses zero overhead forwarding
to native methods, unless I override them, in which case
it is implemented as a free function.

Many functions are now mixin templates in browser.document
so I don't have to repeat them, even if changing types.

Using alias this, these are compatible with the native
types as well.


	e.addClass("sweet");

Is a new function in class Element. It manipulates the
native className property and in the resulting .js file
is a free function.

	e.style = "font-weight: bold;";

The style object is defined in browser.document and has
a  long list of properties. It maps directly to native
code, but with one addition:

    alias cssText this;


style.cssText in Javascript is the attribute as a string.
In my dom.d, Element.style can be treated as a string or
a struct, and I wanted that here too.

alias this accomplishes that goal with zero overhead.
e.style = ""; translates simply to e.style.cssText = "";

	e.style.fontSize = "30px";

The property is a native one, nothing special here.

	e.innerText = e.style;

innerText, while a property on some browsers, isn't present
on all of them.

Thus, class Element defines it itself. This generates a free
function (with a mangled D name, so no conflict) that is
called using D property syntax.

The generated code looks like this:
     _D_mangled_innerText(e.style.cssText, e);



This is the general pattern I'll do for browser compatibility.
Use the real name in D, but let it implement as free functions
with mangled names.

	window.alert(e.parentNode.tagName);


The browser.window module defines some things that are global
in JS, including alert(). e.parentNode returns an Element,
thanks to a mixin that can specialize on types with zero overhead.


tagName, while a native property, is actually a function here.
The reason is dom.d uses lowercase tag names, but Javascript
uses uppercase.

Thus, this is implemented:

@property string tagName() { return 
__js_this.tagName.toLowerCase(); }


and the above line calls a D function. Some overhead, but very
little.

	e.removeFromTree();


Finally, this is just a regular function. I'm thinking about
changing it to UFCS though so it can check for null on e too.

(It does:

  if(parentNode) parentNode.removeChild(this);

the idea being to just ensure it isn't in the tree without
needing an external null check.

If this is null, it is also not in the tree, so its contract
is satisified anyway, so it might as well succeed. Currently,
though, it will not work since the Element invariant will
segfault it.)




But, there's a rundown of what I'm doing with libraries.
Beautiful D code, compatible implementations, minimal
overhead.


I'll be posting the library soon, and then this will
be sharable.


More information about the Digitalmars-d-announce mailing list