Skip to content

Commit 9abc63c

Browse files
committed
[js] Implement nqp::throwpayloadlexcaller.
1 parent 1789b85 commit 9abc63c

File tree

3 files changed

+58
-3
lines changed

3 files changed

+58
-3
lines changed

src/vm/js/Compiler.nqp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
5151

5252
has %!statevars;
5353

54+
has $!pass_on_exceptions;
55+
5456
method new($qast, $outer) {
5557
my $obj := nqp::create(self);
5658
$obj.BUILD($qast, $outer);
@@ -74,6 +76,15 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
7476
%!lexicalref_types := nqp::hash();
7577
@!var_setup := nqp::list();
7678
%!statevars := nqp::hash();
79+
$!pass_on_exceptions := 0;
80+
}
81+
82+
method pass_on_exceptions() {
83+
$!pass_on_exceptions;
84+
}
85+
86+
method use_passing_on_of_exceptions() {
87+
$!pass_on_exceptions := 1;
7788
}
7889

7990
method add_var_setup($setup) {
@@ -1024,6 +1035,21 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
10241035

10251036
my $first_time_marker := $*BLOCK.maybe_first_time_marker;
10261037

1038+
my $pass_exceptions_start := '';
1039+
my $pass_exceptions_end := '';
1040+
1041+
if $*BLOCK.pass_on_exceptions {
1042+
$pass_exceptions_start := "try \{\n";
1043+
$pass_exceptions_end :=
1044+
~ "\} catch (e) \{\n"
1045+
~ "if (e instanceof nqp.PassExceptionToCaller) \{\n"
1046+
~ "throw e.exception;\n"
1047+
~ "\} else \{"
1048+
~ "throw e;\n"
1049+
~ "\}"
1050+
~ "\}";
1051+
}
1052+
10271053
my @function := [
10281054
"function({$sig.expr}) \{\n" ,
10291055
$first_time_marker ?? "$first_time_marker = 1;\n" !! '',
@@ -1034,8 +1060,10 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
10341060
$sig,
10351061
self.clone_inners($*BLOCK),
10361062
self.capture_inners($*BLOCK),
1063+
$pass_exceptions_start,
10371064
$stmts,
10381065
"return {$stmts.expr};\n",
1066+
$pass_exceptions_end,
10391067
"\}"
10401068
];
10411069
%*BLOCKS_DONE{$node.cuid} := Chunk.void("(", |@function, ")");

src/vm/js/Operations.nqp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,7 +1298,8 @@ class QAST::OperationsJS {
12981298

12991299
my $protected := $comp.as_js(:want($T_OBJ), $node[0]);
13001300

1301-
if $*RETURN.is_used {
1301+
# HACK - we assume how return is used on the nqp backend and avoid handling some exceptions
1302+
if $*HLL ne 'nqp' || $*RETURN.is_used {
13021303
my $handle_result := $comp.as_js(:want($T_OBJ), $node[2]);
13031304

13041305
Chunk.new($T_OBJ, $result, [
@@ -1321,11 +1322,16 @@ class QAST::OperationsJS {
13211322

13221323
});
13231324

1325+
my sub is_CONTROL_RETURN($category) {
1326+
$category ~~ QAST::IVal && $category.value == nqp::const::CONTROL_RETURN
1327+
|| $category ~~ QAST::Op && $category.op eq 'const' && $category.name eq 'CONTROL_RETURN';
1328+
}
1329+
13241330
add_op('throwpayloadlex', :!inlinable, sub ($comp, $node, :$want, :$cps) {
13251331
my $category := $node[0];
13261332
my $payload := $comp.as_js(:want($T_OBJ), $node[1]);
13271333

1328-
unless $category ~~ QAST::IVal && $category.value == nqp::const::CONTROL_RETURN {
1334+
unless is_CONTROL_RETURN($category) {
13291335
return $comp.NYI("throwpayloadlex with something else then a CONTROL_RETURN literal");
13301336
}
13311337

@@ -1345,6 +1351,22 @@ class QAST::OperationsJS {
13451351
]);
13461352
});
13471353

1354+
add_op('throwpayloadlexcaller', :!inlinable, sub ($comp, $node, :$want, :$cps) {
1355+
my $category := $node[0];
1356+
my $payload := $comp.as_js(:want($T_OBJ), $node[1]);
1357+
1358+
unless is_CONTROL_RETURN($category) {
1359+
return $comp.NYI("throwpayloadlexcaller with something else then a CONTROL_RETURN literal");
1360+
}
1361+
1362+
$*BLOCK.use_passing_on_of_exceptions();
1363+
1364+
Chunk.new($T_VOID, "", [
1365+
$payload,
1366+
"throw new nqp.PassExceptionToCaller(new nqp.ControlReturn({$payload.expr}));\n"
1367+
]);
1368+
});
1369+
13481370
add_simple_op('lastexpayload', $T_OBJ, [], sub () { '$$e.payload' }, :!inlinable, :sideffects);
13491371

13501372

src/vm/js/nqp-runtime/runtime.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,14 +355,19 @@ exports.wrapException = function(e) {
355355
function ControlReturn(payload) {
356356
this.payload = payload;
357357
}
358+
exports.ControlReturn = ControlReturn;
359+
360+
function PassExceptionToCaller(exception) {
361+
this.exception = exception;
362+
}
363+
exports.PassExceptionToCaller = PassExceptionToCaller;
358364

359365
exports.setCodeRefHLL = function(codeRefs, hllName) {
360366
for (var i = 0; i < codeRefs.length; i++) {
361367
codeRefs[i].hll = hll.hllConfigs[hllName];
362368
}
363369
};
364370

365-
exports.ControlReturn = ControlReturn;
366371

367372
/* TODO - make monkey patching builtin things optional */
368373

0 commit comments

Comments
 (0)