# Hacking tips for the JS backend of NQP # Source layout. src/vm/js/Compiler.nqp - turns QAST into JavaScript code src/vm/js/nqp-runtime - a node module the code we generate uses src/vm/js/bin/run_tests.pl - a list of tests we use # Overview The bulk of the compilation is done by QAST::CompilerJS.as_js($node, :$want). It takes a QAST::Node and produces a Chunk. A chunk is created by Chunk.new($type, $expr, @setup, :$node). $expr represents a sideffect free JavaScript expression. $type describes what the expression evaluates to. $type can be one of $T_OBJ, $T_INT, $T_STR, $T_BOOL, $T_VOID, $T_NONVAL. @setup is the JavaScript code that needs to be run for $expr to be valid. @setup is an array containing either string literals with JavaScript code or other Chunks. $node is a QAST::Node we get line positions from when emitting source maps. Simple chunk examples: Chunk.new($T_STR, "'Hello World'", []); my $foo := Chunk.new($T_STR, "foo", ["var foo = 'Hello World';\n"]); Chunk.new($T_VOID, "", [$foo, "alert({$foo.expr});\n"]); # We don't ever use the $expr of $T_VOID chunks When compiling a QAST::Block we need to keep a bunch of information about it. We store it in a dynamic $*BLOCK variable (which contains a BlockInfo). my $tmp := $*BLOCK.add_tmp(); # that creates a temporary variable in js function we are emitting. my $foo := Chunk.new($T_STR, $tmp, ["$tmp = 'Hello World';\n"]); # NQP op codes QAST::OperationsJS.compile_op(QAST::CompilerJS $compiler, QAST::Node $node, :$want) handles the compilation of QAST::Op nodes The more complex ops are defined using add_op. add_op($op, sub ($comp, $node, :$want) { # this should return a chunk }); The simpler ones are defined using add_simple_op($op, $return_type, @argument_types, $cb, :$sideffects). $cb gets a bunch of .expr parts from the Chunks the op arguments are compiled to. $cb should return a string containing a JavaScript expression. If the op has sideffects the :$sideffects flag needs to be true. Example: add_simple_op('lc', $T_STR, [$T_STR], sub ($string) {"$string.toLowerCase()"}); Looking at src/vm/jvm/runtime/org/raku/nqp/runtime/Ops.java and src/vm/jvm/QAST/Compiler.nqp can provide insight on how the various ops should work. # Reading generated code ./nqp-js --target=js --beautify -e 'say("Hello World")' # t/js JS backend specific tests should placed here