Before I start, a bit of background. I am the developer of the IWL widget library. Think Gtk+ (actually, my inspiration), but targeted for the Web. I developed the first version as an in-house solution three or four years ago, to get rid of all the nasty html that was present in the Perl code. Then my employer allowed me to release the code to CPAN.

Now, half a year ago, I saw an interesting post on the Ajaxian blog. It was about Google's GWT, which I was aware of, but didn't know it existed when I started my work on IWL. There was a snippet of code, which showed something quite interesting: they were writing everything in Java, even the code that I though must only be written in JavaScript. Basically, the developers wrote Java handlers for DOM events, which were translated by GWT into JavaScript. I wanted something like this for my own library, but CPAN didn't provide anything. So, I set out and wrote my own.

P2JS

I've been writing this piece of code on a need-to-have basis. Only what I needed at some point in time is incorporated. But so far, I have a pretty good coverage of the basics of the Perl language. It also ties in well with my IWL library: where I usually pass strings of JavaScript code, I now pass coderefs, which are automatically converted, and if an IWL method is called in the subref, I change it so the corresponding JS function is called instead. As a proof of concept, I also use it on my (quite empty) homepage (might not be up, as it is hosted from my own home). The entire code for that page is this:
#!/usr/bin/perl use strict; use IWL::Page; use IWL::Container; use IWL::Image; use IWL::Anchor; use IWL::Break; use IWL::P2JS; my $page = IWL::Page->new->setTitle('Б Л О К & +#1040;'); my $container = IWL::Container->new(id => 'main_container', style => { +visibility => 'hidden'}); my $anchor = IWL::Anchor->new->setHref('http://code.google.com/p/iwl') +; my $logo = IWL::Image->new(id => 'logo')->set('/skin/images/logo.jpg') +; my $description = IWL::Container->new(id => 'description', inline => 1 +); my @images = ( IWL::Image->new(class => 'description', id => 'perl', src => '/ski +n/images/perl.jpg'), IWL::Image->new(class => 'description', id => 'widget', src => '/s +kin/images/widget.jpg'), IWL::Image->new(class => 'description', id => 'library', src => '/ +skin/images/library.jpg'), IWL::Image->new(class => 'description', id => 'for', src => '/skin +/images/for.jpg'), IWL::Image->new(class => 'description', id => 'the', src => '/skin +/images/the.jpg'), IWL::Image->new(class => 'description', id => 'web', src => '/skin +/images/web.jpg'), ); my ($script, $tracker) = (IWL::Script->new, IWL::Script->new); $page->appendHeader(IWL::Page::Link->newLinkToCSS('/skin/bloka.css')); $page->appendChild($container); $description->appendChild(@images); $anchor->appendChild($logo, IWL::Break->new, $description); $container->appendChild($anchor, $tracker, $script); $script->setScript(sub { my $path = '/skin/images/'; $container->setStyle(visibility => 'visible', display => 'none'); $container->positionAtCenter->appear({duration => 4}); foreach (['perl', 61], ['widget', 66], ['library', 69], ['for', 44 +], ['the', 34], ['web', 52]) { S($_->[0])->signalConnect(mouseover => (sub { my ($args) = @_; $this->{downEffect}->cancel if $this->{downEffect}; $this->{upEffect} = Effect::Morph->new($this, {style => {w +idth => $args->[1] * 2 . 'px', height =>'74px'}, duration => 0.2, bef +oreStart => $this->{writeAttribute}->bind($this, {src => "${path}$arg +s->[0]2.jpg"})}) })->bind(S($_->[0]), $_))->signalConnect(mouseout => (sub { my ($args) = @_; $this->{upEffect}->cancel if $this->{upEffect}; $this->{downEffect} = Effect::Morph->new($this, {style => +{width => $args->[1] . 'px', height => '37px'}, duration => 0.2, afte +rFinish => $this->{writeAttribute}->bind($this, {src => "${path}$args +->[0].jpg"})}) })->bind(S($_->[0]), $_)); } my $pageTracker = _gat::_getTracker('UA-2846284-2'); $pageTracker->_initData; $pageTracker->_trackPageview; }); $tracker->setSrc('http://www.google-analytics.com/ga.js'); $page->send(type => 'html', static => 1);
Where the lonely subref, passed as a parameter of the setScript method, is the one getting converted to JavaScript, doing the whole bouncy magic.

The thing that bothers me is that, my colleagues think that this is a waste of time, and will not be useful. I am currently responsible for more than 90% of the JavaScript code, and it is my opinion that large chunks of code should go in JavaScript files, but for small things like DOM event handlers, one'd have to inline JavaScript code as a string into the Perl code.

What do the Perl Monks think? If it is worthwile, should I continue working on this little side project, or should I stop now, and waste my time with something else?

Replies are listed 'Best First'.
Re: Translating Perl into JavaScript
by dragonchild (Archbishop) on Jun 02, 2008 at 17:04 UTC
    Audrey was talking about doing something similar with the web portion of Jifty. This was a couple years ago - we talked about it at YAPC::NA::2006. You might want to check out what she and Jesse have been doing.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

      CLKao (of svk fame) wrote a B level opcode -> JS converter that I think handles a wide portion of both languages pretty decently. I am not sure of the current state though.

      -stvn
Re: Translating Perl into JavaScript
by moritz (Cardinal) on Jun 02, 2008 at 15:53 UTC
    I hope you know that your chances are very slim to actually port full p5 to javascript, even if you consider only these parts that aren't inherently impossible in Javascript (some I/O, system calls).

    But that shouldn't stop you from doing this stuff, especially if it's fun.

    The major problem could be that once you use this in production code, you have to be very clear about what works and what doesn't. (Just a few keywords: tie, overload, local, type globs - how much of them will work, if any?)

      Oh I know. Complex Perl code can never be translated into JavaScript, since ES3 is quite limited anyway. Furthermore, more complex JavaScript code should definitely go in its own file, for multiple reasons which are not even related to features that cannot be translated from p5 to js. That's why I only consider this worthwhile using, if its uses are limited to small (and simple) sliced of code, like the one I posted above.

      That's the whole thing actually, this module (and most likely anything else) will never be able to cover all of p5, but it'd be nice if it covers all the basic stuff.
      There is a compiler called Perlito that can convert a subset of Perl into JavaScript.
        IIRC last time I tried it out (some years ago but after 2012's talk from Flavio) I wasn't able to use s/// or m// for regexes.

        Did this change?

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!