1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
# 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
|