summaryrefslogtreecommitdiff
path: root/prism_compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'prism_compile.c')
-rw-r--r--prism_compile.c123
1 files changed, 112 insertions, 11 deletions
diff --git a/prism_compile.c b/prism_compile.c
index 5efe391922..ff730411df 100644
--- a/prism_compile.c
+++ b/prism_compile.c
@@ -1408,6 +1408,12 @@ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_
scope->locals = cast->locals;
break;
}
+ case PM_RESCUE_NODE: {
+ pm_rescue_node_t *cast = (pm_rescue_node_t *)node;
+ scope->body = (pm_node_t *)cast->statements;
+ scope->local_depth_offset += 1;
+ break;
+ }
case PM_SINGLETON_CLASS_NODE: {
pm_singleton_class_node_t *cast = (pm_singleton_class_node_t *) node;
scope->body = cast->body;
@@ -1809,24 +1815,23 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
rb_iseq_t *child_iseq;
LABEL *lstart = NEW_LABEL(lineno);
LABEL *lend = NEW_LABEL(lineno);
-
- ADD_LABEL(ret, lstart);
- if (begin_node->statements) {
- PM_COMPILE((pm_node_t *)begin_node->statements);
- }
- else {
- PM_PUTNIL_UNLESS_POPPED;
- }
- ADD_LABEL(ret, lend);
+ LABEL *lcont = NEW_LABEL(lineno);
if (begin_node->ensure_clause) {
+ ADD_LABEL(ret, lstart);
+ if (begin_node->statements) {
+ PM_COMPILE((pm_node_t *)begin_node->statements);
+ }
+ else {
+ PM_PUTNIL_UNLESS_POPPED;
+ }
+ ADD_LABEL(ret, lend);
pm_statements_node_t *statements = begin_node->ensure_clause->statements;
if (statements) {
PM_COMPILE((pm_node_t *)statements);
PM_POP_UNLESS_POPPED;
}
- LABEL *lcont = NEW_LABEL(lineno);
struct ensure_range er;
struct iseq_compile_data_ensure_node_stack enl;
struct ensure_range *erange;
@@ -1853,6 +1858,53 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
}
}
}
+
+ if (begin_node->rescue_clause) {
+ pm_scope_node_t rescue_scope_node;
+ pm_scope_node_init((pm_node_t *)begin_node->rescue_clause, &rescue_scope_node, scope_node, parser);
+
+ rb_iseq_t *rescue_iseq = NEW_CHILD_ISEQ(rescue_scope_node,
+ rb_str_concat(rb_str_new2("rescue in"),
+ ISEQ_BODY(iseq)->location.label),
+ ISEQ_TYPE_RESCUE, 1);
+ lstart->rescued = LABEL_RESCUE_BEG;
+ lend->rescued = LABEL_RESCUE_END;
+ ADD_LABEL(ret, lstart);
+
+ bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
+ ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
+ if (begin_node->statements) {
+ PM_COMPILE_NOT_POPPED((pm_node_t *)begin_node->statements);
+ }
+ else {
+ PM_PUTNIL;
+ }
+ ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
+
+ if (begin_node->else_clause) {
+ PM_POP_UNLESS_POPPED;
+ PM_COMPILE((pm_node_t *)begin_node->else_clause);
+ }
+
+ ADD_LABEL(ret, lend);
+ ADD_INSN(ret, &dummy_line_node, nop);
+ ADD_LABEL(ret, lcont);
+
+ PM_POP_IF_POPPED;
+ ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue_iseq, lcont);
+ ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
+ }
+
+ if (!begin_node->rescue_clause && !begin_node->ensure_clause) {
+ ADD_LABEL(ret, lstart);
+ if (begin_node->statements) {
+ PM_COMPILE((pm_node_t *)begin_node->statements);
+ }
+ else {
+ PM_PUTNIL_UNLESS_POPPED;
+ }
+ ADD_LABEL(ret, lend);
+ }
return;
}
case PM_BLOCK_ARGUMENT_NODE: {
@@ -1881,7 +1933,6 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
ID method_id = pm_constant_id_lookup(scope_node, call_node->name);
int flags = 0;
struct rb_callinfo_kwarg *kw_arg = NULL;
-
if (call_node->receiver == NULL) {
PM_PUTSELF;
} else {
@@ -3573,6 +3624,49 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
}
return;
}
+ case PM_RESCUE_NODE: {
+ LABEL *excep_match = NEW_LABEL(lineno);
+ LABEL *rescue_end = NEW_LABEL(lineno);
+
+ pm_rescue_node_t *rescue_node = (pm_rescue_node_t *)node;
+ iseq_set_exception_local_table(iseq);
+
+ pm_node_list_t exception_list = rescue_node->exceptions;
+ if (exception_list.size > 0) {
+ for (size_t i = 0; i < exception_list.size; i++) {
+ ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
+ PM_COMPILE(exception_list.nodes[i]);
+ ADD_INSN1(ret, &dummy_line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
+ ADD_INSN1(ret, &dummy_line_node, branchif, excep_match);
+ }
+ } else {
+ ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
+ ADD_INSN1(ret, &dummy_line_node, putobject, rb_eStandardError);
+ ADD_INSN1(ret, &dummy_line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
+ ADD_INSN1(ret, &dummy_line_node, branchif, excep_match);
+ }
+ ADD_INSN1(ret, &dummy_line_node, jump, rescue_end);
+
+ ADD_LABEL(ret, excep_match);
+ ADD_TRACE(ret, RUBY_EVENT_RESCUE);
+ if (rescue_node->reference) {
+ ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
+ PM_COMPILE((pm_node_t *)rescue_node->reference);
+ }
+ if (rescue_node->statements) {
+ PM_COMPILE((pm_node_t *)rescue_node->statements);
+ }
+ ADD_INSN(ret, &dummy_line_node, leave);
+ ADD_LABEL(ret, rescue_end);
+
+ if (rescue_node->consequent) {
+ PM_COMPILE((pm_node_t *)rescue_node->consequent);
+ } else {
+ ADD_GETLOCAL(ret, &dummy_line_node, 1, 0);
+ }
+
+ return;
+ }
case PM_RETURN_NODE: {
pm_arguments_node_t *arguments = ((pm_return_node_t *)node)->arguments;
@@ -3871,6 +3965,13 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0));
return;
}
+ case ISEQ_TYPE_RESCUE: {
+ iseq_set_exception_local_table(iseq);
+ PM_COMPILE((pm_node_t *)scope_node->ast_node);
+ ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0));
+
+ return;
+ }
default:
if (scope_node->body) {
PM_COMPILE((pm_node_t *)scope_node->body);