зеркало из https://github.com/github/ruby.git
Compile more YARP node types (#8322)
* Add several more node simple types to YARP's compiler: Nodes include: DefinedNode, EmbeddedStatementsNode, LocalVariableReadNode, LocalVariableWriteNode, MultiWriteNode, OptionalParameterNode, SplatNode, YieldNode * Add AssocSplatNode, RangeNode * Add RangeNode, other helpers for future nodes * Add ArrayNode, HashNode, static literal helpers * Add branch conditionals * Add IfNode, UnlessNode * Add ScopeNode * NEW_ISEQ and NEW_CHILD_ISEQ implemented for YARP * Add nodes that depend on ScopeNode * Addressed PR comments
This commit is contained in:
Родитель
b435161404
Коммит
80dc570a45
46
iseq.c
46
iseq.c
|
@ -944,6 +944,52 @@ rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE rea
|
|||
|
||||
VALUE rb_iseq_compile_yarp_node(rb_iseq_t * iseq, const yp_node_t * yarp_pointer, yp_parser_t *parser);
|
||||
|
||||
rb_iseq_t *
|
||||
yp_iseq_new_with_opt(yp_node_t *node, yp_parser_t *parser, VALUE name, VALUE path, VALUE realpath,
|
||||
int first_lineno, const rb_iseq_t *parent, int isolated_depth,
|
||||
enum rb_iseq_type type, const rb_compile_option_t *option)
|
||||
{
|
||||
rb_iseq_t *iseq = iseq_alloc();
|
||||
rb_compile_option_t new_opt;
|
||||
|
||||
if (option) {
|
||||
new_opt = *option;
|
||||
}
|
||||
else {
|
||||
new_opt = COMPILE_OPTION_DEFAULT;
|
||||
}
|
||||
|
||||
VALUE script_lines = Qnil;
|
||||
|
||||
rb_code_location_t code_loc;
|
||||
|
||||
if (node) {
|
||||
yp_line_column_t start_line_col = yp_newline_list_line_column(&(parser->newline_list), node->location.start);
|
||||
yp_line_column_t end_line_col= yp_newline_list_line_column(&(parser->newline_list), node->location.end);
|
||||
code_loc = (rb_code_location_t) {
|
||||
.beg_pos = {
|
||||
.lineno = (int)start_line_col.line,
|
||||
.column = (int)start_line_col.column
|
||||
},
|
||||
.end_pos = {
|
||||
.lineno = (int)end_line_col.line,
|
||||
.column = (int)end_line_col.column
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: node_id
|
||||
int node_id = -1;
|
||||
prepare_iseq_build(iseq, name, path, realpath, first_lineno, &code_loc, node_id,
|
||||
parent, isolated_depth, type, script_lines, &new_opt);
|
||||
|
||||
rb_iseq_compile_yarp_node(iseq, node, parser);
|
||||
|
||||
finish_iseq_build(iseq);
|
||||
|
||||
return iseq_translate(iseq);
|
||||
}
|
||||
|
||||
rb_iseq_t *
|
||||
rb_iseq_new_with_callback(
|
||||
const struct rb_iseq_new_with_callback_callback_func * ifunc,
|
||||
|
|
|
@ -1,5 +1,22 @@
|
|||
#include "yarp.h"
|
||||
|
||||
#define OLD_ISEQ NEW_ISEQ
|
||||
#undef NEW_ISEQ
|
||||
|
||||
#define NEW_ISEQ(node, name, type, line_no) \
|
||||
yp_new_child_iseq(iseq, (node), parser, rb_fstring(name), 0, (type), (line_no))
|
||||
|
||||
#define OLD_CHILD_ISEQ NEW_CHILD_ISEQ
|
||||
#undef NEW_CHILD_ISEQ
|
||||
|
||||
#define NEW_CHILD_ISEQ(node, name, type, line_no) \
|
||||
yp_new_child_iseq(iseq, (node), parser, rb_fstring(name), iseq, (type), (line_no))
|
||||
|
||||
rb_iseq_t *
|
||||
yp_iseq_new_with_opt(yp_scope_node_t *node, yp_parser_t *parser, VALUE name, VALUE path, VALUE realpath,
|
||||
int first_lineno, const rb_iseq_t *parent, int isolated_depth,
|
||||
enum rb_iseq_type type, const rb_compile_option_t *option);
|
||||
|
||||
static VALUE
|
||||
parse_number(const yp_node_t *node) {
|
||||
const char *start = node->location.start;
|
||||
|
@ -42,6 +59,265 @@ parse_location_symbol(yp_location_t *location) {
|
|||
return parse_symbol(location->start, location->end);
|
||||
}
|
||||
|
||||
static int
|
||||
yp_optimizable_range_item_p(yp_node_t *node)
|
||||
{
|
||||
return (!node || node->type == YP_NODE_INTEGER_NODE || node->type == YP_NODE_NIL_NODE);
|
||||
}
|
||||
|
||||
static bool
|
||||
yp_static_node_literal_p(yp_node_t *node)
|
||||
{
|
||||
switch(node->type) {
|
||||
case YP_NODE_FALSE_NODE:
|
||||
case YP_NODE_FLOAT_NODE:
|
||||
case YP_NODE_IMAGINARY_NODE:
|
||||
case YP_NODE_INTEGER_NODE:
|
||||
case YP_NODE_NIL_NODE:
|
||||
case YP_NODE_RATIONAL_NODE:
|
||||
case YP_NODE_SELF_NODE:
|
||||
case YP_NODE_STRING_NODE:
|
||||
case YP_NODE_SOURCE_ENCODING_NODE:
|
||||
case YP_NODE_SOURCE_FILE_NODE:
|
||||
case YP_NODE_SOURCE_LINE_NODE:
|
||||
case YP_NODE_SYMBOL_NODE:
|
||||
case YP_NODE_TRUE_NODE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
yp_static_literal_value(yp_node_t *node)
|
||||
{
|
||||
switch(node->type) {
|
||||
case YP_NODE_NIL_NODE:
|
||||
return Qnil;
|
||||
case YP_NODE_TRUE_NODE:
|
||||
return Qtrue;
|
||||
case YP_NODE_FALSE_NODE:
|
||||
return Qfalse;
|
||||
// TODO: Implement this method for the other literal nodes described above
|
||||
default:
|
||||
rb_bug("This node type doesn't have a literal value");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
yp_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const yp_node_t *cond,
|
||||
LABEL *then_label, LABEL *else_label, const char *src, bool popped, yp_compile_context_t *compile_context);
|
||||
|
||||
static void
|
||||
yp_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, yp_node_t *cond,
|
||||
LABEL *then_label, LABEL *else_label, const char *src, bool popped, yp_compile_context_t *compile_context)
|
||||
{
|
||||
yp_parser_t *parser = compile_context->parser;
|
||||
yp_newline_list_t newline_list = parser->newline_list;
|
||||
int lineno = (int)yp_newline_list_line_column(&newline_list, cond->location.start).line;
|
||||
NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
|
||||
|
||||
DECL_ANCHOR(seq);
|
||||
INIT_ANCHOR(seq);
|
||||
LABEL *label = NEW_LABEL(lineno);
|
||||
if (!then_label) then_label = label;
|
||||
else if (!else_label) else_label = label;
|
||||
|
||||
yp_compile_branch_condition(iseq, seq, cond, then_label, else_label, src, popped, compile_context);
|
||||
|
||||
if (LIST_INSN_SIZE_ONE(seq)) {
|
||||
INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
|
||||
if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
|
||||
return;
|
||||
}
|
||||
if (!label->refcnt) {
|
||||
ADD_INSN(seq, &dummy_line_node, putnil);
|
||||
}
|
||||
else {
|
||||
ADD_LABEL(seq, label);
|
||||
}
|
||||
ADD_SEQ(ret, seq);
|
||||
return;
|
||||
}
|
||||
|
||||
static void yp_compile_node(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret, const char * src, bool popped, yp_compile_context_t *context);
|
||||
|
||||
static void
|
||||
yp_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const yp_node_t *cond,
|
||||
LABEL *then_label, LABEL *else_label, const char *src, bool popped, yp_compile_context_t *compile_context)
|
||||
{
|
||||
yp_parser_t *parser = compile_context->parser;
|
||||
yp_newline_list_t newline_list = parser->newline_list;
|
||||
int lineno = (int) yp_newline_list_line_column(&newline_list, cond->location.start).line;
|
||||
NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
|
||||
|
||||
again:
|
||||
switch (YP_NODE_TYPE(cond)) {
|
||||
case YP_NODE_AND_NODE: {
|
||||
yp_and_node_t *and_node = (yp_and_node_t *)cond;
|
||||
yp_compile_logical(iseq, ret, and_node->left, NULL, else_label, src, popped, compile_context);
|
||||
cond = and_node->right;
|
||||
goto again;
|
||||
}
|
||||
case YP_NODE_OR_NODE: {
|
||||
yp_or_node_t *or_node = (yp_or_node_t *)cond;
|
||||
yp_compile_logical(iseq, ret, or_node->left, then_label, NULL, src, popped, compile_context);
|
||||
cond = or_node->right;
|
||||
goto again;
|
||||
}
|
||||
case YP_NODE_FALSE_NODE:
|
||||
case YP_NODE_NIL_NODE:
|
||||
ADD_INSNL(ret, &dummy_line_node, jump, else_label);
|
||||
return;
|
||||
case YP_NODE_FLOAT_NODE:
|
||||
case YP_NODE_IMAGINARY_NODE:
|
||||
case YP_NODE_INTEGER_NODE:
|
||||
case YP_NODE_LAMBDA_NODE:
|
||||
case YP_NODE_RATIONAL_NODE:
|
||||
case YP_NODE_REGULAR_EXPRESSION_NODE:
|
||||
case YP_NODE_STRING_NODE:
|
||||
case YP_NODE_SYMBOL_NODE:
|
||||
case YP_NODE_TRUE_NODE:
|
||||
ADD_INSNL(ret, &dummy_line_node, jump, then_label);
|
||||
return;
|
||||
// TODO: Several more nodes in this case statement
|
||||
default:
|
||||
{
|
||||
DECL_ANCHOR(cond_seq);
|
||||
INIT_ANCHOR(cond_seq);
|
||||
|
||||
yp_compile_node(iseq, cond, cond_seq, src, Qfalse, compile_context);
|
||||
ADD_SEQ(ret, cond_seq);
|
||||
}
|
||||
break;
|
||||
}
|
||||
ADD_INSNL(ret, &dummy_line_node, branchunless, else_label);
|
||||
ADD_INSNL(ret, &dummy_line_node, jump, then_label);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
yp_compile_if(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret, const char * src, bool popped, yp_compile_context_t *compile_context) {
|
||||
yp_parser_t *parser = compile_context->parser;
|
||||
yp_statements_node_t *node_body;
|
||||
yp_node_t *node_else;
|
||||
yp_node_t *predicate;
|
||||
|
||||
if (node->type == YP_NODE_IF_NODE) {
|
||||
yp_if_node_t *if_node = (yp_if_node_t *)node;
|
||||
node_body = if_node->statements;
|
||||
node_else = if_node->consequent;
|
||||
predicate = if_node->predicate;
|
||||
}
|
||||
else {
|
||||
yp_unless_node_t *unless_node = (yp_unless_node_t *)node;
|
||||
node_body = unless_node->statements;
|
||||
node_else = (yp_node_t *)(unless_node->consequent);
|
||||
predicate = unless_node->predicate;
|
||||
}
|
||||
|
||||
const int line = (int)yp_newline_list_line_column(&(parser->newline_list), node->location.start).line;
|
||||
NODE line_node = generate_dummy_line_node(line, line);
|
||||
|
||||
DECL_ANCHOR(cond_seq);
|
||||
|
||||
LABEL *then_label, *else_label, *end_label;
|
||||
|
||||
INIT_ANCHOR(cond_seq);
|
||||
then_label = NEW_LABEL(line);
|
||||
else_label = NEW_LABEL(line);
|
||||
end_label = 0;
|
||||
|
||||
yp_compile_branch_condition(iseq, cond_seq, predicate, then_label, else_label, src, popped, compile_context);
|
||||
ADD_SEQ(ret, cond_seq);
|
||||
|
||||
if (then_label->refcnt) {
|
||||
ADD_LABEL(ret, then_label);
|
||||
|
||||
DECL_ANCHOR(then_seq);
|
||||
INIT_ANCHOR(then_seq);
|
||||
if (node_body) {
|
||||
yp_compile_node(iseq, (yp_node_t *)node_body, then_seq, src, popped, compile_context);
|
||||
}
|
||||
else {
|
||||
if (!popped) {
|
||||
ADD_INSN(ret, &line_node, putnil);
|
||||
}
|
||||
}
|
||||
|
||||
if (else_label->refcnt) {
|
||||
end_label = NEW_LABEL(line);
|
||||
ADD_INSNL(then_seq, &line_node, jump, end_label);
|
||||
if (!popped) {
|
||||
ADD_INSN(then_seq, &line_node, pop);
|
||||
}
|
||||
}
|
||||
ADD_SEQ(ret, then_seq);
|
||||
}
|
||||
|
||||
if (else_label->refcnt) {
|
||||
ADD_LABEL(ret, else_label);
|
||||
|
||||
DECL_ANCHOR(else_seq);
|
||||
INIT_ANCHOR(else_seq);
|
||||
if (node_else) {
|
||||
yp_compile_node(iseq, (yp_node_t *)(((yp_else_node_t *)node_else)->statements), else_seq, src, popped, compile_context);
|
||||
}
|
||||
else {
|
||||
if (!popped) {
|
||||
ADD_INSN(ret, &line_node, putnil);
|
||||
}
|
||||
}
|
||||
|
||||
ADD_SEQ(ret, else_seq);
|
||||
}
|
||||
|
||||
if (end_label) {
|
||||
ADD_LABEL(ret, end_label);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static rb_iseq_t *
|
||||
yp_new_child_iseq(rb_iseq_t *iseq, yp_scope_node_t * node, yp_parser_t *parser,
|
||||
VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
|
||||
{
|
||||
debugs("[new_child_iseq]> ---------------------------------------\n");
|
||||
int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
|
||||
rb_iseq_t * ret_iseq = yp_iseq_new_with_opt(node, parser, name,
|
||||
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
|
||||
line_no, parent,
|
||||
isolated_depth ? isolated_depth + 1 : 0,
|
||||
type, ISEQ_COMPILE_DATA(iseq)->option);
|
||||
debugs("[new_child_iseq]< ---------------------------------------\n");
|
||||
return ret_iseq;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
yp_compile_class_path(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const yp_node_t *constant_path_node, const NODE *line_node)
|
||||
{
|
||||
if (constant_path_node->type == YP_NODE_CONSTANT_PATH_NODE) {
|
||||
if (((yp_constant_path_node_t *)constant_path_node)->parent) {
|
||||
/* Bar::Foo */
|
||||
// TODO: yp_compile_node(ret, "nd_else->nd_head", cpath->nd_head));
|
||||
return VM_DEFINECLASS_FLAG_SCOPED;
|
||||
}
|
||||
else {
|
||||
/* toplevel class ::Foo */
|
||||
ADD_INSN1(ret, line_node, putobject, rb_cObject);
|
||||
return VM_DEFINECLASS_FLAG_SCOPED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* class at cbase Foo */
|
||||
ADD_INSN1(ret, line_node, putspecialobject,
|
||||
INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compiles a YARP node into instruction sequences
|
||||
*
|
||||
|
@ -97,12 +373,46 @@ yp_compile_node(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret,
|
|||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_ARRAY_NODE: {
|
||||
yp_array_node_t *array_node = (yp_array_node_t *) node;
|
||||
yp_node_list_t elements = array_node->elements;
|
||||
if (elements.size == 1 && yp_static_node_literal_p(elements.nodes[0])) {
|
||||
VALUE ary = rb_ary_hidden_new(1);
|
||||
rb_ary_push(ary, yp_static_literal_value(elements.nodes[0]));
|
||||
OBJ_FREEZE(ary);
|
||||
|
||||
ADD_INSN1(ret, &dummy_line_node, duparray, ary);
|
||||
}
|
||||
else {
|
||||
for (size_t index = 0; index < elements.size; index++) {
|
||||
yp_compile_node(iseq, elements.nodes[index], ret, src, popped, compile_context);
|
||||
}
|
||||
|
||||
if (!popped) {
|
||||
ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(elements.size));
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case YP_NODE_ASSOC_NODE: {
|
||||
yp_assoc_node_t *assoc_node = (yp_assoc_node_t *) node;
|
||||
yp_compile_node(iseq, assoc_node->key, ret, src, popped, compile_context);
|
||||
yp_compile_node(iseq, assoc_node->value, ret, src, popped, compile_context);
|
||||
return;
|
||||
}
|
||||
case YP_NODE_ASSOC_SPLAT_NODE: {
|
||||
yp_assoc_splat_node_t *assoc_splat_node = (yp_assoc_splat_node_t *)node;
|
||||
yp_compile_node(iseq, assoc_splat_node->value, ret, src, popped, compile_context);
|
||||
|
||||
// TODO: Not sure this is accurate, look at FLUSH_CHUNK in the compiler
|
||||
ADD_INSN1(ret, &dummy_line_node, newarraykwsplat, INT2FIX(0));
|
||||
|
||||
if (popped) {
|
||||
ADD_INSN(ret, &dummy_line_node, pop);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_BEGIN_NODE: {
|
||||
yp_begin_node_t *begin_node = (yp_begin_node_t *) node;
|
||||
if (begin_node->statements) {
|
||||
|
@ -110,6 +420,87 @@ yp_compile_node(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret,
|
|||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_CALL_NODE: {
|
||||
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
||||
|
||||
ID mid = parse_string_symbol(&call_node->name);
|
||||
int flags = 0;
|
||||
int orig_argc = 0;
|
||||
|
||||
if (call_node->receiver == NULL) {
|
||||
ADD_INSN(ret, &dummy_line_node, putself);
|
||||
} else {
|
||||
yp_compile_node(iseq, call_node->receiver, ret, src, popped, compile_context);
|
||||
}
|
||||
|
||||
if (call_node->arguments == NULL) {
|
||||
if (flags & VM_CALL_FCALL) {
|
||||
flags |= VM_CALL_VCALL;
|
||||
}
|
||||
} else {
|
||||
yp_arguments_node_t *arguments = call_node->arguments;
|
||||
yp_compile_node(iseq, (yp_node_t *) arguments, ret, src, popped, compile_context);
|
||||
orig_argc = (int)arguments->arguments.size;
|
||||
}
|
||||
|
||||
VALUE block_iseq = Qnil;
|
||||
if (call_node->block != NULL) {
|
||||
// Scope associated with the block
|
||||
yp_scope_node_t scope_node;
|
||||
yp_scope_node_init((yp_node_t *)call_node->block, &scope_node);
|
||||
|
||||
const rb_iseq_t *block_iseq = NEW_CHILD_ISEQ(&scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
|
||||
ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq;
|
||||
ADD_SEND_WITH_BLOCK(ret, &dummy_line_node, mid, INT2FIX(orig_argc), block_iseq);
|
||||
}
|
||||
else {
|
||||
if (block_iseq == Qnil && flags == 0) {
|
||||
flags |= VM_CALL_ARGS_SIMPLE;
|
||||
}
|
||||
|
||||
if (call_node->receiver == NULL) {
|
||||
flags |= VM_CALL_FCALL;
|
||||
|
||||
if (block_iseq == Qnil && call_node->arguments == NULL) {
|
||||
flags |= VM_CALL_VCALL;
|
||||
}
|
||||
}
|
||||
|
||||
ADD_SEND_WITH_FLAG(ret, &dummy_line_node, mid, INT2NUM(orig_argc), INT2FIX(flags));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_CLASS_NODE: {
|
||||
yp_class_node_t *class_node = (yp_class_node_t *)node;
|
||||
yp_scope_node_t scope_node;
|
||||
yp_scope_node_init((yp_node_t *)class_node, &scope_node);
|
||||
|
||||
ID class_id = parse_string_symbol(&class_node->name);
|
||||
|
||||
VALUE class_name = rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(class_id)));
|
||||
|
||||
const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(&scope_node, class_name, ISEQ_TYPE_CLASS, lineno);
|
||||
|
||||
// TODO: Once we merge constant path nodes correctly, fix this flag
|
||||
const int flags = VM_DEFINECLASS_TYPE_CLASS |
|
||||
(class_node->superclass ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
|
||||
yp_compile_class_path(ret, iseq, class_node->constant_path, &dummy_line_node);
|
||||
|
||||
if (class_node->superclass) {
|
||||
yp_compile_node(iseq, class_node->superclass, ret, src, popped, compile_context);
|
||||
}
|
||||
else {
|
||||
ADD_INSN(ret, &dummy_line_node, putnil);
|
||||
}
|
||||
|
||||
ADD_INSN3(ret, &dummy_line_node, defineclass, ID2SYM(class_id), class_iseq, INT2FIX(flags));
|
||||
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
|
||||
|
||||
if (popped) {
|
||||
ADD_INSN(ret, &dummy_line_node, pop);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_CLASS_VARIABLE_READ_NODE:
|
||||
if (!popped) {
|
||||
ID cvar_name = parse_node_symbol((yp_node_t *)node);
|
||||
|
@ -176,6 +567,41 @@ yp_compile_node(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret,
|
|||
ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(constant_name));
|
||||
return;
|
||||
}
|
||||
case YP_NODE_DEF_NODE: {
|
||||
yp_def_node_t *def_node = (yp_def_node_t *) node;
|
||||
ID method_name = parse_location_symbol(&def_node->name_loc);
|
||||
yp_scope_node_t scope_node;
|
||||
yp_scope_node_init((yp_node_t *)def_node, &scope_node);
|
||||
rb_iseq_t *method_iseq = NEW_ISEQ(&scope_node, rb_id2str(method_name), ISEQ_TYPE_METHOD, lineno);
|
||||
|
||||
ADD_INSN2(ret, &dummy_line_node, definemethod, ID2SYM(method_name), method_iseq);
|
||||
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
|
||||
|
||||
if (!popped) {
|
||||
ADD_INSN1(ret, &dummy_line_node, putobject, ID2SYM(method_name));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_DEFINED_NODE: {
|
||||
ADD_INSN(ret, &dummy_line_node, putself);
|
||||
yp_defined_node_t *defined_node = (yp_defined_node_t *)node;
|
||||
// TODO: Correct defined_type
|
||||
enum defined_type dtype = DEFINED_CONST;
|
||||
VALUE sym;
|
||||
|
||||
sym = parse_number(defined_node->value);
|
||||
|
||||
ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(dtype), sym, rb_iseq_defined_string(dtype));
|
||||
return;
|
||||
}
|
||||
case YP_NODE_EMBEDDED_STATEMENTS_NODE: {
|
||||
yp_embedded_statements_node_t *embedded_statements_node = (yp_embedded_statements_node_t *)node;
|
||||
|
||||
if (embedded_statements_node->statements)
|
||||
yp_compile_node(iseq, (yp_node_t *) (embedded_statements_node->statements), ret, src, popped, compile_context);
|
||||
// TODO: Concatenate the strings that exist here
|
||||
return;
|
||||
}
|
||||
case YP_NODE_EMBEDDED_VARIABLE_NODE: {
|
||||
yp_embedded_variable_node_t *embedded_node = (yp_embedded_variable_node_t *)node;
|
||||
yp_compile_node(iseq, embedded_node->variable, ret, src, popped, compile_context);
|
||||
|
@ -186,6 +612,47 @@ yp_compile_node(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret,
|
|||
ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
|
||||
}
|
||||
return;
|
||||
case YP_NODE_FLIP_FLOP_NODE: {
|
||||
// TODO: The labels here are wrong, figure out why.....
|
||||
yp_flip_flop_node_t *flip_flop_node = (yp_flip_flop_node_t *)node;
|
||||
|
||||
LABEL *lend = NEW_LABEL(lineno);
|
||||
LABEL *then_label = NEW_LABEL(lineno);
|
||||
LABEL *else_label = NEW_LABEL(lineno);
|
||||
//TODO: int again = type == NODE_FLIP2;
|
||||
int again = 0;
|
||||
|
||||
rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
|
||||
+ VM_SVAR_FLIPFLOP_START;
|
||||
VALUE key = INT2FIX(cnt);
|
||||
|
||||
ADD_INSN2(ret, &dummy_line_node, getspecial, key, INT2FIX(0));
|
||||
ADD_INSNL(ret, &dummy_line_node, branchif, lend);
|
||||
|
||||
yp_compile_node(iseq, flip_flop_node->left, ret, src, popped, compile_context);
|
||||
/* *flip == 0 */
|
||||
ADD_INSNL(ret, &dummy_line_node, branchunless, else_label);
|
||||
ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
|
||||
ADD_INSN1(ret, &dummy_line_node, setspecial, key);
|
||||
if (!again) {
|
||||
ADD_INSNL(ret, &dummy_line_node, jump, then_label);
|
||||
}
|
||||
|
||||
/* *flip == 1 */
|
||||
ADD_LABEL(ret, lend);
|
||||
yp_compile_node(iseq, flip_flop_node->right, ret, src, popped, compile_context);
|
||||
ADD_INSNL(ret, &dummy_line_node, branchunless, then_label);
|
||||
ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
|
||||
ADD_INSN1(ret, &dummy_line_node, setspecial, key);
|
||||
ADD_INSNL(ret, &dummy_line_node, jump, then_label);
|
||||
ADD_LABEL(ret, then_label);
|
||||
ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
|
||||
ADD_INSNL(ret, &dummy_line_node, jump, lend);
|
||||
ADD_LABEL(ret, else_label);
|
||||
ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
|
||||
ADD_LABEL(ret, lend);
|
||||
return;
|
||||
}
|
||||
case YP_NODE_FLOAT_NODE: {
|
||||
if (!popped) {
|
||||
ADD_INSN1(ret, &dummy_line_node, putobject, parse_number(node));
|
||||
|
@ -208,6 +675,37 @@ yp_compile_node(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret,
|
|||
ADD_INSN1(ret, &dummy_line_node, setglobal, ID2SYM(ivar_name));
|
||||
return;
|
||||
}
|
||||
case YP_NODE_HASH_NODE: {
|
||||
yp_hash_node_t *hash_node = (yp_hash_node_t *) node;
|
||||
yp_node_list_t elements = hash_node->elements;
|
||||
|
||||
if (elements.size == 1) {
|
||||
assert(elements.nodes[0]->type == YP_NODE_ASSOC_NODE);
|
||||
yp_assoc_node_t *assoc_node = (yp_assoc_node_t *) elements.nodes[0];
|
||||
|
||||
if (yp_static_node_literal_p(assoc_node->key) &&
|
||||
yp_static_node_literal_p(assoc_node->value)) {
|
||||
VALUE hash = rb_hash_new_with_size(1);
|
||||
hash = rb_obj_hide(hash);
|
||||
OBJ_FREEZE(hash);
|
||||
ADD_INSN1(ret, &dummy_line_node, duphash, hash);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < elements.size; index++) {
|
||||
yp_compile_node(iseq, elements.nodes[index], ret, src, popped, compile_context);
|
||||
}
|
||||
|
||||
if (!popped) {
|
||||
ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(elements.size * 2));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_IF_NODE: {
|
||||
yp_compile_if(iseq, node, ret, src, popped, compile_context);
|
||||
return;
|
||||
}
|
||||
case YP_NODE_IMAGINARY_NODE: {
|
||||
if (!popped) {
|
||||
ADD_INSN1(ret, &dummy_line_node, putobject, parse_number(node));
|
||||
|
@ -312,10 +810,110 @@ yp_compile_node(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret,
|
|||
ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(elements.size * 2));
|
||||
return;
|
||||
}
|
||||
case YP_NODE_LAMBDA_NODE: {
|
||||
yp_scope_node_t scope_node;
|
||||
yp_scope_node_init((yp_node_t *)node, &scope_node);
|
||||
|
||||
const rb_iseq_t *block = NEW_CHILD_ISEQ(&scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
|
||||
VALUE argc = INT2FIX(0);
|
||||
|
||||
ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
|
||||
ADD_CALL_WITH_BLOCK(ret, &dummy_line_node, idLambda, argc, block);
|
||||
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
|
||||
|
||||
if (popped) {
|
||||
ADD_INSN(ret, &dummy_line_node, pop);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
|
||||
yp_local_variable_read_node_t *local_read_node = (yp_local_variable_read_node_t *) node;
|
||||
|
||||
yp_constant_id_t constant_id = local_read_node->name;
|
||||
st_data_t local_index;
|
||||
|
||||
for(uint32_t i = 0; i < local_read_node->depth; i++) {
|
||||
compile_context = compile_context->previous;
|
||||
iseq = (rb_iseq_t *)ISEQ_BODY(iseq)->parent_iseq;
|
||||
}
|
||||
|
||||
int num_params = ISEQ_BODY(iseq)->param.size;
|
||||
|
||||
if (!st_lookup(compile_context->index_lookup_table, constant_id, &local_index)) {
|
||||
rb_bug("This local does not exist");
|
||||
}
|
||||
|
||||
int index = num_params - (int)local_index;
|
||||
|
||||
if (!popped) {
|
||||
ADD_GETLOCAL(ret, &dummy_line_node, index, local_read_node->depth);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_LOCAL_VARIABLE_WRITE_NODE: {
|
||||
yp_local_variable_write_node_t *local_write_node = (yp_local_variable_write_node_t *) node;
|
||||
yp_compile_node(iseq, local_write_node->value, ret, src, false, compile_context);
|
||||
|
||||
if (!popped) {
|
||||
ADD_INSN(ret, &dummy_line_node, dup);
|
||||
}
|
||||
|
||||
yp_constant_id_t constant_id = local_write_node->name;
|
||||
size_t stack_index;
|
||||
|
||||
if (!st_lookup(compile_context->index_lookup_table, constant_id, &stack_index)) {
|
||||
rb_bug("This local doesn't exist");
|
||||
}
|
||||
|
||||
unsigned int num_params = ISEQ_BODY(iseq)->param.size;
|
||||
size_t index = num_params - stack_index;
|
||||
|
||||
ADD_SETLOCAL(ret, &dummy_line_node, (int)index, local_write_node->depth);
|
||||
return;
|
||||
}
|
||||
case YP_NODE_MISSING_NODE: {
|
||||
rb_bug("A yp_missing_node_t should not exist in YARP's AST.");
|
||||
return;
|
||||
}
|
||||
case YP_NODE_MODULE_NODE: {
|
||||
yp_module_node_t *module_node = (yp_module_node_t *)node;
|
||||
yp_scope_node_t scope_node;
|
||||
yp_scope_node_init((yp_node_t *)module_node, &scope_node);
|
||||
|
||||
ID module_id = parse_string_symbol(&module_node->name);
|
||||
VALUE module_name = rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(module_id)));
|
||||
|
||||
const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(&scope_node, module_name, ISEQ_TYPE_CLASS, lineno);
|
||||
|
||||
const int flags = VM_DEFINECLASS_TYPE_MODULE |
|
||||
yp_compile_class_path(ret, iseq, module_node->constant_path, &dummy_line_node);
|
||||
|
||||
ADD_INSN (ret, &dummy_line_node, putnil);
|
||||
ADD_INSN3(ret, &dummy_line_node, defineclass, ID2SYM(module_id), module_iseq, INT2FIX(flags));
|
||||
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
|
||||
|
||||
if (popped) {
|
||||
ADD_INSN(ret, &dummy_line_node, pop);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_MULTI_WRITE_NODE: {
|
||||
yp_multi_write_node_t *multi_write_node = (yp_multi_write_node_t *)node;
|
||||
yp_compile_node(iseq, multi_write_node->value, ret, src, popped, compile_context);
|
||||
|
||||
// TODO: int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
|
||||
int flag = 0x00;
|
||||
|
||||
ADD_INSN(ret, &dummy_line_node, dup);
|
||||
ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(multi_write_node->targets.size), INT2FIX(flag));
|
||||
yp_node_list_t node_list = multi_write_node->targets;
|
||||
|
||||
for (size_t index = 0; index < node_list.size; index++) {
|
||||
yp_compile_node(iseq, node_list.nodes[index], ret, src, popped, compile_context);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case YP_NODE_NIL_NODE:
|
||||
if (!popped) {
|
||||
ADD_INSN(ret, &dummy_line_node, putnil);
|
||||
|
@ -340,6 +938,24 @@ yp_compile_node(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret,
|
|||
|
||||
return;
|
||||
}
|
||||
case YP_NODE_OPTIONAL_PARAMETER_NODE: {
|
||||
yp_optional_parameter_node_t *optional_parameter_node = (yp_optional_parameter_node_t *)node;
|
||||
yp_compile_node(iseq, optional_parameter_node->value, ret, src, false, compile_context);
|
||||
|
||||
yp_constant_id_t constant_id = optional_parameter_node->name;
|
||||
|
||||
size_t param_number;
|
||||
if (!st_lookup(compile_context->index_lookup_table, constant_id, ¶m_number)) {
|
||||
rb_bug("This local doesn't exist");
|
||||
}
|
||||
|
||||
unsigned int num_params = ISEQ_BODY(iseq)->param.size;
|
||||
int index = (int) (num_params - param_number);
|
||||
|
||||
ADD_SETLOCAL(ret, &dummy_line_node, index, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
case YP_NODE_PARENTHESES_NODE: {
|
||||
yp_parentheses_node_t *parentheses_node = (yp_parentheses_node_t *) node;
|
||||
|
||||
|
@ -363,6 +979,42 @@ yp_compile_node(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret,
|
|||
ADD_INSN(ret, &dummy_line_node, leave);
|
||||
return;
|
||||
}
|
||||
case YP_NODE_RANGE_NODE: {
|
||||
yp_range_node_t *range_node = (yp_range_node_t *) node;
|
||||
bool exclusive = (range_node->operator_loc.end - range_node->operator_loc.start) == 3;
|
||||
|
||||
if (yp_optimizable_range_item_p(range_node->left) && yp_optimizable_range_item_p(range_node->right)) {
|
||||
if (!popped) {
|
||||
yp_node_t *left = range_node->left;
|
||||
yp_node_t *right = range_node->right;
|
||||
VALUE val = rb_range_new(
|
||||
left && left->type == YP_NODE_INTEGER_NODE ? parse_number(left) : Qnil,
|
||||
right && right->type == YP_NODE_INTEGER_NODE ? parse_number(right) : Qnil,
|
||||
exclusive
|
||||
);
|
||||
ADD_INSN1(ret, &dummy_line_node, putobject, val);
|
||||
RB_OBJ_WRITTEN(iseq, Qundef, val);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (range_node->left == NULL) {
|
||||
ADD_INSN(ret, &dummy_line_node, putnil);
|
||||
} else {
|
||||
yp_compile_node(iseq, range_node->left, ret, src, popped, compile_context);
|
||||
}
|
||||
|
||||
if (range_node->right == NULL) {
|
||||
ADD_INSN(ret, &dummy_line_node, putnil);
|
||||
} else {
|
||||
yp_compile_node(iseq, range_node->right, ret, src, popped, compile_context);
|
||||
}
|
||||
|
||||
if (!popped) {
|
||||
ADD_INSN1(ret, &dummy_line_node, newrange, INT2FIX(exclusive));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_RETURN_NODE: {
|
||||
yp_arguments_node_t *arguments = ((yp_return_node_t *)node)->arguments;
|
||||
|
||||
|
@ -381,9 +1033,154 @@ yp_compile_node(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret,
|
|||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_SCOPE_NODE: {
|
||||
yp_scope_node_t *scope_node = (yp_scope_node_t *)node;
|
||||
yp_constant_id_list_t locals = scope_node->locals;
|
||||
|
||||
yp_parameters_node_t *parameters_node = (yp_parameters_node_t *)scope_node->parameters;
|
||||
yp_node_list_t requireds_list = YP_EMPTY_NODE_LIST;
|
||||
yp_node_list_t optionals_list = YP_EMPTY_NODE_LIST;
|
||||
|
||||
|
||||
if (parameters_node) {
|
||||
requireds_list = parameters_node->requireds;
|
||||
optionals_list = parameters_node->optionals;
|
||||
}
|
||||
|
||||
size_t size = locals.size;
|
||||
|
||||
// Index lookup table buffer size is only the number of the locals
|
||||
st_table *index_lookup_table = st_init_numtable();
|
||||
|
||||
VALUE idtmp = 0;
|
||||
rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + size * sizeof(ID));
|
||||
tbl->size = (int)size;
|
||||
|
||||
// First param gets 0, second param 1, param n...
|
||||
// Calculate the local index for all locals
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
yp_constant_id_t constant_id = locals.ids[i];
|
||||
ID local = compile_context->constants[constant_id - 1];
|
||||
tbl->ids[i] = local;
|
||||
st_insert(index_lookup_table, constant_id, i);
|
||||
}
|
||||
|
||||
yp_compile_context_t scope_compile_context = {
|
||||
.parser = parser,
|
||||
.previous = compile_context,
|
||||
.constants = compile_context->constants,
|
||||
.index_lookup_table = index_lookup_table
|
||||
};
|
||||
|
||||
ISEQ_BODY(iseq)->param.lead_num = (int)requireds_list.size;
|
||||
ISEQ_BODY(iseq)->param.opt_num = (int)optionals_list.size;
|
||||
// TODO: Set all the other nums (good comment by lead_num illustrating what they are)
|
||||
ISEQ_BODY(iseq)->param.size = (unsigned int)size;
|
||||
|
||||
if (optionals_list.size) {
|
||||
LABEL **opt_table = (LABEL **)ALLOC_N(VALUE, optionals_list.size + 1);
|
||||
LABEL *label;
|
||||
|
||||
// TODO: Should we make an api for NEW_LABEL where you can pass
|
||||
// a pointer to the label it should fill out? We already
|
||||
// have a list of labels allocated above so it seems wasteful
|
||||
// to do the copies.
|
||||
for (size_t i = 0; i < optionals_list.size; i++) {
|
||||
label = NEW_LABEL(lineno);
|
||||
opt_table[i] = label;
|
||||
ADD_LABEL(ret, label);
|
||||
yp_node_t *optional_node = optionals_list.nodes[i];
|
||||
yp_compile_node(iseq, optional_node, ret, src, false, &scope_compile_context);
|
||||
}
|
||||
|
||||
// Set the last label
|
||||
label = NEW_LABEL(lineno);
|
||||
opt_table[optionals_list.size] = label;
|
||||
ADD_LABEL(ret, label);
|
||||
|
||||
ISEQ_BODY(iseq)->param.flags.has_opt = TRUE;
|
||||
ISEQ_BODY(iseq)->param.opt_table = (const VALUE *)opt_table;
|
||||
}
|
||||
|
||||
iseq_set_local_table(iseq, tbl);
|
||||
|
||||
switch (ISEQ_BODY(iseq)->type) {
|
||||
case ISEQ_TYPE_BLOCK:
|
||||
{
|
||||
LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
|
||||
LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
|
||||
|
||||
start->rescued = LABEL_RESCUE_BEG;
|
||||
end->rescued = LABEL_RESCUE_END;
|
||||
|
||||
ADD_TRACE(ret, RUBY_EVENT_B_CALL);
|
||||
NODE dummy_line_node = generate_dummy_line_node(ISEQ_BODY(iseq)->location.first_lineno, -1);
|
||||
ADD_INSN (ret, &dummy_line_node, nop);
|
||||
ADD_LABEL(ret, start);
|
||||
|
||||
yp_compile_node(iseq, (yp_node_t *)(scope_node->body), ret, src, popped, &scope_compile_context);
|
||||
|
||||
ADD_LABEL(ret, end);
|
||||
ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
|
||||
ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
|
||||
|
||||
/* wide range catch handler must put at last */
|
||||
ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
|
||||
ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (scope_node->body) {
|
||||
yp_compile_node(iseq, (yp_node_t *)(scope_node->body), ret, src, popped, &scope_compile_context);
|
||||
}
|
||||
else {
|
||||
ADD_INSN(ret, &dummy_line_node, putnil);
|
||||
}
|
||||
}
|
||||
|
||||
free(index_lookup_table);
|
||||
|
||||
ADD_INSN(ret, &dummy_line_node, leave);
|
||||
return;
|
||||
}
|
||||
case YP_NODE_SELF_NODE:
|
||||
ADD_INSN(ret, &dummy_line_node, putself);
|
||||
return;
|
||||
case YP_NODE_SINGLETON_CLASS_NODE: {
|
||||
yp_singleton_class_node_t *singleton_class_node = (yp_singleton_class_node_t *)node;
|
||||
yp_scope_node_t scope_node;
|
||||
yp_scope_node_init((yp_node_t *)singleton_class_node, &scope_node);
|
||||
|
||||
const rb_iseq_t *singleton_class = NEW_ISEQ(&scope_node, rb_fstring_lit("singleton class"),
|
||||
ISEQ_TYPE_CLASS, lineno);
|
||||
|
||||
yp_compile_node(iseq, singleton_class_node->expression, ret, src, popped, compile_context);
|
||||
ADD_INSN(ret, &dummy_line_node, putnil);
|
||||
ID singletonclass;
|
||||
CONST_ID(singletonclass, "singletonclass");
|
||||
|
||||
ADD_INSN3(ret, &dummy_line_node, defineclass,
|
||||
ID2SYM(singletonclass), singleton_class,
|
||||
INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
|
||||
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
|
||||
|
||||
if (popped) {
|
||||
ADD_INSN(ret, &dummy_line_node, pop);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case YP_NODE_SPLAT_NODE: {
|
||||
yp_splat_node_t *splat_node = (yp_splat_node_t *)node;
|
||||
yp_compile_node(iseq, splat_node->expression, ret, src, popped, compile_context);
|
||||
|
||||
ADD_INSN1(ret, &dummy_line_node, splatarray, Qtrue);
|
||||
|
||||
if (popped) {
|
||||
ADD_INSN(ret, &dummy_line_node, pop);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case YP_NODE_STATEMENTS_NODE: {
|
||||
yp_statements_node_t *statements_node = (yp_statements_node_t *) node;
|
||||
yp_node_list_t node_list = statements_node->body;
|
||||
|
@ -436,6 +1233,80 @@ yp_compile_node(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret,
|
|||
|
||||
return;
|
||||
}
|
||||
case YP_NODE_UNLESS_NODE: {
|
||||
yp_compile_if(iseq, node, ret, src, popped, compile_context);
|
||||
return;
|
||||
}
|
||||
case YP_NODE_WHILE_NODE: {
|
||||
yp_while_node_t *while_node = (yp_while_node_t *)node;
|
||||
|
||||
LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
|
||||
LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
|
||||
LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
|
||||
int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
|
||||
|
||||
// TODO: Deal with ensures in here
|
||||
LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(lineno); /* next */
|
||||
LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(lineno); /* redo */
|
||||
LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(lineno); /* break */
|
||||
LABEL *end_label = NEW_LABEL(lineno);
|
||||
LABEL *adjust_label = NEW_LABEL(lineno);
|
||||
|
||||
LABEL *next_catch_label = NEW_LABEL(lineno);
|
||||
LABEL *tmp_label = NULL;
|
||||
|
||||
ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
|
||||
|
||||
// begin; end while true
|
||||
if (while_node->base.flags & YP_LOOP_FLAGS_BEGIN_MODIFIER) {
|
||||
ADD_INSNL(ret, &dummy_line_node, jump, next_label);
|
||||
}
|
||||
else {
|
||||
// while true; end
|
||||
tmp_label = NEW_LABEL(lineno);
|
||||
ADD_INSNL(ret, &dummy_line_node, jump, tmp_label);
|
||||
}
|
||||
|
||||
ADD_LABEL(ret, adjust_label);
|
||||
ADD_INSN(ret, &dummy_line_node, putnil);
|
||||
ADD_LABEL(ret, next_catch_label);
|
||||
ADD_INSN(ret, &dummy_line_node, pop);
|
||||
ADD_INSNL(ret, &dummy_line_node, jump, next_label);
|
||||
if (tmp_label) ADD_LABEL(ret, tmp_label);
|
||||
|
||||
ADD_LABEL(ret, redo_label);
|
||||
if (while_node->statements) {
|
||||
yp_compile_node(iseq, (yp_node_t *)while_node->statements, ret, src, Qfalse, compile_context);
|
||||
}
|
||||
|
||||
ADD_LABEL(ret, next_label);
|
||||
|
||||
yp_compile_branch_condition(iseq, ret, while_node->predicate, redo_label, end_label, src, popped, compile_context);
|
||||
|
||||
ADD_LABEL(ret, end_label);
|
||||
ADD_ADJUST_RESTORE(ret, adjust_label);
|
||||
|
||||
ADD_INSN(ret, &dummy_line_node, putnil);
|
||||
|
||||
ADD_LABEL(ret, break_label);
|
||||
|
||||
if (popped) {
|
||||
ADD_INSN(ret, &dummy_line_node, pop);
|
||||
}
|
||||
|
||||
ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
|
||||
break_label);
|
||||
ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
|
||||
next_catch_label);
|
||||
ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
|
||||
ISEQ_COMPILE_DATA(iseq)->redo_label);
|
||||
|
||||
ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
|
||||
ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
|
||||
ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
|
||||
ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
|
||||
return;
|
||||
}
|
||||
case YP_NODE_X_STRING_NODE: {
|
||||
yp_x_string_node_t *xstring_node = (yp_x_string_node_t *) node;
|
||||
ADD_INSN(ret, &dummy_line_node, putself);
|
||||
|
@ -443,6 +1314,28 @@ yp_compile_node(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret,
|
|||
ADD_SEND_WITH_FLAG(ret, &dummy_line_node, rb_intern("`"), INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
|
||||
return;
|
||||
}
|
||||
case YP_NODE_YIELD_NODE: {
|
||||
unsigned int flag = 0;
|
||||
struct rb_callinfo_kwarg *keywords = NULL;
|
||||
|
||||
VALUE argc = INT2FIX(0);
|
||||
|
||||
ADD_INSN1(ret, &dummy_line_node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
|
||||
|
||||
if (popped) {
|
||||
ADD_INSN(ret, &dummy_line_node, pop);
|
||||
}
|
||||
|
||||
int level = 0;
|
||||
const rb_iseq_t *tmp_iseq = iseq;
|
||||
for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
|
||||
tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
|
||||
}
|
||||
|
||||
if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
|
||||
|
||||
return;
|
||||
}
|
||||
default:
|
||||
rb_raise(rb_eNotImpError, "node type %s not implemented", yp_node_type_to_str(node->type));
|
||||
return;
|
||||
|
@ -457,6 +1350,11 @@ rb_translate_yarp(rb_iseq_t *iseq, const yp_node_t *node, LINK_ANCHOR *const ret
|
|||
|
||||
yp_compile_node(iseq, node, ret, node->location.start, false, compile_context);
|
||||
iseq_set_sequence(iseq, ret);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
#undef NEW_ISEQ
|
||||
#define NEW_ISEQ OLD_ISEQ
|
||||
|
||||
#undef NEW_CHILD_ISEQ
|
||||
#define NEW_CHILD_ISEQ OLD_CHILD_ISEQ
|
||||
|
|
Загрузка…
Ссылка в новой задаче