Compiling Perl 6 to JavaScript
Why would we want to run stuff on JS?
JS is in the browser

JS is getting everywhere else

Internet of Things

React.native

node.js
Inline-Perl5 will work on node.js...

...so you can use both left-pad and CGI.pm

...or something more reasonable

node.js mainly runs on the v8

...but not only

node.js also runs on ChakraCore
Time travel debugging
Step back to see why your test failed
Graal.js - node.js on the JVM
A second JVM backend for free :)

Electron

Some editors are extendable with JS

V8 is embedded in the UE4 game engine
A lot cooler then SDL
Why not just use raw JS?

Transpilers

People compile stuff to JS so much we have a weird name for it

People are even compiling JS to JS

JS is not fun for a lot of people

(I like JS, Perl 6 is just more awesome)
Fun matters.
Both front end and backend in the same language
"Isomorphic Perl 6"
Sharing code between backend and frontend
How?
Implementating Perl 6 on your own is a ton of work
I tried that before :/
Solution: A backend for Rakudo
A tale of two languages
  • NQP
  • Perl 6
  • NQP ---> QAST
  • Perl6 ---> QAST
QAST ---> JS
  
  is_qast(
      QAST::Block.new(
          QAST::Op.new(
              :op('if'),
              QAST::IVal.new(:value(1)),
              QAST::IVal.new(:value(2))
          )
      ),
      2,
      'if with IVal, 2-operand');
  
  
nqp:: ops
  
  say(nqp::add_i(12, 3));
  
  
  
    nqp::setinvokespec(Foo,Foo,'$!code_ref',nqp::null());
  
  
  
  QAST::Op.new(
      :op('add_i'),
      QAST::IVal.new(:value(12)),
      QAST::IVal.new(:value(3))
  )
  
  
I try to write tests before implementing stuff
Hopefully that helps future backends
  
is(nqp::div_i(9, -4), -3, 'nqp::div_i rounds down');
  
  

Sometimes once building blocks are done, stuff works

Junctions mostly worked that way.

If I misunderstand some small detail...

Source maps
Support for them designed from the start
We generate an intermediate format with that info
Native types
  
  my int $c = 100 + 200;
  
  
  nqp::add_i(100, 200)
  
Compiled as:
  
  (100+200)|0
  
Continuations
One shot continuation
They are commonly known as coroutines
my $list = gather {
  say "#1";
  take 123;
  say "#2";
  take 456;
  say "#3";
  take 789;
};

say($list[1]);
say($list[2]);
say($list[3]);
#1
123
#2
456
#3
789
  
On node.js we have fibers
In the browser we sprinkle await/async
  
      async function onEveryBlock() {
        let ret = await foo.everyMethod();
      }
  
  
  
  function suspendExecution() {
    return new Promise(function(resolve, reject) {
      //when we want to resume the coroutine we call resolve
    });
  
  

JavaScript is evolving

towards becoming a better Perl 6 target

What's done?
We pass 55+% of roast test files on node.js
A few tricky lexical scope bugs break random tests

Closure shenanigans are the suspect

I need to fix that

A bunch of assorted bugs
Challenges
Performance is the big one
It's the biggest problem of other backends too
I want to fully undestand whag's needed before I start bending stuff
Performance of the compiler and user programs are two different things
NQP vs Perl 6
NQP can be tweaked
Perl 6 can't/shouldn't
For browser delivery code size matters

Tree shaking solves the problem for other languages

Make a graph of what uses what and get rid of the dead code

Extra
Why not target WebASM (or asm.js)?
Currently it's designed as a target for C/C++
Perl 6 needs a VM for GC etc.
Currently it's like directly targeting a simple CPU

Get Involved

#perl6 on freenode.org