diff --git a/mini_builtin.c b/mini_builtin.c index 810125fa2e..2024d5d4a6 100644 --- a/mini_builtin.c +++ b/mini_builtin.c @@ -12,22 +12,16 @@ static struct st_table *loaded_builtin_table; #endif +bool pm_builtin_ast_value(pm_parse_result_t *result, const char *feature_name, VALUE *name_str); VALUE rb_builtin_ast_value(const char *feature_name, VALUE *name_str); static const rb_iseq_t * builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *table) { VALUE name_str = 0; - rb_ast_t *ast; - VALUE ast_value = rb_builtin_ast_value(feature_name, &name_str); - rb_vm_t *vm = GET_VM(); + const rb_iseq_t *iseq; - if (NIL_P(ast_value)) { - rb_fatal("builtin_iseq_load: can not find %s; " - "probably miniprelude.c is out of date", - feature_name); - } - vm->builtin_function_table = table; + rb_vm_t *vm = GET_VM(); static const rb_compile_option_t optimization = { .inline_const_cache = TRUE, .peephole_optimization = TRUE, @@ -40,11 +34,38 @@ builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *ta .coverage_enabled = FALSE, .debug_level = 0, }; - ast = rb_ruby_ast_data_get(ast_value); - const rb_iseq_t *iseq = rb_iseq_new_with_opt(ast_value, name_str, name_str, Qnil, 0, NULL, 0, ISEQ_TYPE_TOP, &optimization, Qnil); - GET_VM()->builtin_function_table = NULL; - rb_ast_dispose(ast); + if (*rb_ruby_prism_ptr()) { + pm_parse_result_t result = { 0 }; + if (!pm_builtin_ast_value(&result, feature_name, &name_str)) { + rb_fatal("builtin_iseq_load: can not find %s; " + "probably miniprelude.c is out of date", + feature_name); + } + + vm->builtin_function_table = table; + iseq = pm_iseq_new_with_opt(&result.node, name_str, name_str, Qnil, 0, NULL, 0, ISEQ_TYPE_TOP, &optimization); + + GET_VM()->builtin_function_table = NULL; + pm_parse_result_free(&result); + } + else { + VALUE ast_value = rb_builtin_ast_value(feature_name, &name_str); + + if (NIL_P(ast_value)) { + rb_fatal("builtin_iseq_load: can not find %s; " + "probably miniprelude.c is out of date", + feature_name); + } + + rb_ast_t *ast = rb_ruby_ast_data_get(ast_value); + + vm->builtin_function_table = table; + iseq = rb_iseq_new_with_opt(ast_value, name_str, name_str, Qnil, 0, NULL, 0, ISEQ_TYPE_TOP, &optimization, Qnil); + + GET_VM()->builtin_function_table = NULL; + rb_ast_dispose(ast); + } // for debug if (0 && strcmp("prelude", feature_name) == 0) { diff --git a/prism_compile.c b/prism_compile.c index 022305effe..9f3a4b5fae 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -987,7 +987,10 @@ pm_compile_conditional(rb_iseq_t *iseq, const pm_line_column_t *line_column, pm_ LABEL *else_label = NEW_LABEL(location.line); LABEL *end_label = NULL; - pm_compile_branch_condition(iseq, ret, predicate, then_label, else_label, false, scope_node); + DECL_ANCHOR(cond_seq); + INIT_ANCHOR(cond_seq); + pm_compile_branch_condition(iseq, cond_seq, predicate, then_label, else_label, false, scope_node); + PUSH_SEQ(ret, cond_seq); rb_code_location_t conditional_location; VALUE branches = Qfalse; @@ -2642,7 +2645,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t const char *name = rb_id2name(id); if (name && strlen(name) > 0 && name[0] != '_') { - COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")", rb_id2str(id)); + COMPILE_ERROR(iseq, location.line, "illegal variable in alternative pattern (%"PRIsVALUE")", rb_id2str(id)); return COMPILE_NG; } } @@ -2990,6 +2993,264 @@ pm_compile_retry_end_label(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *retry } } +static const char * +pm_iseq_builtin_function_name(const pm_scope_node_t *scope_node, const pm_node_t *receiver, ID method_id) +{ + const char *name = rb_id2name(method_id); + static const char prefix[] = "__builtin_"; + const size_t prefix_len = sizeof(prefix) - 1; + + if (receiver == NULL) { + if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) { + // __builtin_foo + return &name[prefix_len]; + } + } + else if (PM_NODE_TYPE_P(receiver, PM_CALL_NODE)) { + if (PM_NODE_FLAG_P(receiver, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { + const pm_call_node_t *cast = (const pm_call_node_t *) receiver; + if (pm_constant_id_lookup(scope_node, cast->name) == rb_intern_const("__builtin")) { + // __builtin.foo + return name; + } + } + } + else if (PM_NODE_TYPE_P(receiver, PM_CONSTANT_READ_NODE)) { + const pm_constant_read_node_t *cast = (const pm_constant_read_node_t *) receiver; + if (pm_constant_id_lookup(scope_node, cast->name) == rb_intern_const("Primitive")) { + // Primitive.foo + return name; + } + } + + return NULL; +} + +// Compile Primitive.attr! :leaf, ... +static int +pm_compile_builtin_attr(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_arguments_node_t *arguments, const pm_line_column_t *node_location) +{ + if (arguments == NULL) { + COMPILE_ERROR(iseq, node_location->line, "attr!: no argument"); + return COMPILE_NG; + } + + const pm_node_t *argument; + PM_NODE_LIST_FOREACH(&arguments->arguments, index, argument) { + if (!PM_NODE_TYPE_P(argument, PM_SYMBOL_NODE)) { + COMPILE_ERROR(iseq, node_location->line, "non symbol argument to attr!: %s", pm_node_type_to_str(PM_NODE_TYPE(argument))); + return COMPILE_NG; + } + + VALUE symbol = pm_static_literal_value(iseq, argument, scope_node); + VALUE string = rb_sym_to_s(symbol); + + if (strcmp(RSTRING_PTR(string), "leaf") == 0) { + ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF; + } + else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) { + ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK; + } + else if (strcmp(RSTRING_PTR(string), "use_block") == 0) { + iseq_set_use_block(iseq); + } + else { + COMPILE_ERROR(iseq, node_location->line, "unknown argument to attr!: %s", RSTRING_PTR(string)); + return COMPILE_NG; + } + } + + return COMPILE_OK; +} + +static int +pm_compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node, const pm_arguments_node_t *arguments, const pm_line_column_t *node_location, int popped) +{ + if (arguments == NULL) { + COMPILE_ERROR(iseq, node_location->line, "arg!: no argument"); + return COMPILE_NG; + } + + if (arguments->arguments.size != 1) { + COMPILE_ERROR(iseq, node_location->line, "arg!: too many argument"); + return COMPILE_NG; + } + + const pm_node_t *argument = arguments->arguments.nodes[0]; + if (!PM_NODE_TYPE_P(argument, PM_SYMBOL_NODE)) { + COMPILE_ERROR(iseq, node_location->line, "non symbol argument to arg!: %s", pm_node_type_to_str(PM_NODE_TYPE(argument))); + return COMPILE_NG; + } + + if (!popped) { + ID name = parse_string_symbol(scope_node, ((const pm_symbol_node_t *) argument)); + int index = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, name); + + debugs("id: %s idx: %d\n", rb_id2name(name), index); + PUSH_GETLOCAL(ret, *node_location, index, get_lvar_level(iseq)); + } + + return COMPILE_OK; +} + +static int +pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_call_node_t *call_node, const pm_line_column_t *node_location) +{ + const pm_node_t *ast_node = scope_node->ast_node; + if (!PM_NODE_TYPE_P(ast_node, PM_DEF_NODE)) { + rb_bug("mandatory_only?: not in method definition"); + return COMPILE_NG; + } + + const pm_def_node_t *def_node = (const pm_def_node_t *) ast_node; + const pm_parameters_node_t *parameters_node = def_node->parameters; + if (parameters_node == NULL) { + rb_bug("mandatory_only?: in method definition with no parameters"); + return COMPILE_NG; + } + + const pm_node_t *body_node = def_node->body; + if (body_node == NULL || !PM_NODE_TYPE_P(body_node, PM_STATEMENTS_NODE) || (((const pm_statements_node_t *) body_node)->body.size != 1) || !PM_NODE_TYPE_P(((const pm_statements_node_t *) body_node)->body.nodes[0], PM_IF_NODE)) { + rb_bug("mandatory_only?: not in method definition with plain statements"); + return COMPILE_NG; + } + + const pm_if_node_t *if_node = (const pm_if_node_t *) ((const pm_statements_node_t *) body_node)->body.nodes[0]; + if (if_node->predicate != ((const pm_node_t *) call_node)) { + rb_bug("mandatory_only?: can't find mandatory node"); + return COMPILE_NG; + } + + pm_parameters_node_t parameters = { + .base = parameters_node->base, + .requireds = parameters_node->requireds + }; + + const pm_def_node_t def = { + .base = def_node->base, + .name = def_node->name, + .receiver = def_node->receiver, + .parameters = ¶meters, + .body = (pm_node_t *) if_node->statements, + .locals = { + .ids = def_node->locals.ids, + .size = parameters_node->requireds.size, + .capacity = def_node->locals.capacity + } + }; + + pm_scope_node_t next_scope_node; + pm_scope_node_init(&def.base, &next_scope_node, scope_node); + + ISEQ_BODY(iseq)->mandatory_only_iseq = pm_iseq_new_with_opt( + &next_scope_node, + rb_iseq_base_label(iseq), + rb_iseq_path(iseq), + rb_iseq_realpath(iseq), + node_location->line, + NULL, + 0, + ISEQ_TYPE_METHOD, + ISEQ_COMPILE_DATA(iseq)->option + ); + + pm_scope_node_destroy(&next_scope_node); + return COMPILE_OK; +} + +static int +pm_compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, const pm_call_node_t *call_node, const pm_line_column_t *node_location, int popped, const rb_iseq_t *parent_block, const char *builtin_func) +{ + const pm_arguments_node_t *arguments = call_node->arguments; + + if (parent_block != NULL) { + COMPILE_ERROR(iseq, node_location->line, "should not call builtins here."); + return COMPILE_NG; + } + +#define BUILTIN_INLINE_PREFIX "_bi" + char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)]; + bool cconst = false; +retry:; + const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func); + + if (bf == NULL) { + if (strcmp("cstmt!", builtin_func) == 0 || strcmp("cexpr!", builtin_func) == 0) { + // ok + } + else if (strcmp("cconst!", builtin_func) == 0) { + cconst = true; + } + else if (strcmp("cinit!", builtin_func) == 0) { + // ignore + return COMPILE_OK; + } + else if (strcmp("attr!", builtin_func) == 0) { + return pm_compile_builtin_attr(iseq, scope_node, arguments, node_location); + } + else if (strcmp("arg!", builtin_func) == 0) { + return pm_compile_builtin_arg(iseq, ret, scope_node, arguments, node_location, popped); + } + else if (strcmp("mandatory_only?", builtin_func) == 0) { + if (popped) { + rb_bug("mandatory_only? should be in if condition"); + } + else if (!LIST_INSN_SIZE_ZERO(ret)) { + rb_bug("mandatory_only? should be put on top"); + } + + PUSH_INSN1(ret, *node_location, putobject, Qfalse); + return pm_compile_builtin_mandatory_only_method(iseq, scope_node, call_node, node_location); + } + else if (1) { + rb_bug("can't find builtin function:%s", builtin_func); + } + else { + COMPILE_ERROR(iseq, node_location->line, "can't find builtin function:%s", builtin_func); + return COMPILE_NG; + } + + int inline_index = node_location->line; + snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index); + builtin_func = inline_func; + arguments = NULL; + goto retry; + } + + if (cconst) { + typedef VALUE(*builtin_func0)(void *, VALUE); + VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil); + PUSH_INSN1(ret, *node_location, putobject, const_val); + return COMPILE_OK; + } + + // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr); + + DECL_ANCHOR(args_seq); + INIT_ANCHOR(args_seq); + + int flags = 0; + struct rb_callinfo_kwarg *keywords = NULL; + int argc = pm_setup_args(arguments, call_node->block, &flags, &keywords, iseq, args_seq, scope_node, node_location); + + if (argc != bf->argc) { + COMPILE_ERROR(iseq, node_location->line, "argc is not match for builtin function:%s (expect %d but %d)", builtin_func, bf->argc, argc); + return COMPILE_NG; + } + + unsigned int start_index; + if (delegate_call_p(iseq, argc, args_seq, &start_index)) { + PUSH_INSN2(ret, *node_location, opt_invokebuiltin_delegate, bf, INT2FIX(start_index)); + } + else { + PUSH_SEQ(ret, args_seq); + PUSH_INSN1(ret, *node_location, invokebuiltin, bf); + } + + if (popped) PUSH_INSN(ret, *node_location, pop); + return COMPILE_OK; +} + /** * Compile a call node into the given iseq. */ @@ -3041,6 +3302,7 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c struct rb_callinfo_kwarg *kw_arg = NULL; int orig_argc = pm_setup_args(call_node->arguments, call_node->block, &flags, &kw_arg, iseq, ret, scope_node, &location); + const rb_iseq_t *previous_block = ISEQ_COMPILE_DATA(iseq)->current_block; const rb_iseq_t *block_iseq = NULL; if (call_node->block != NULL && PM_NODE_TYPE_P(call_node->block, PM_BLOCK_NODE)) { @@ -3111,6 +3373,7 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c } if (popped) PUSH_INSN(ret, location, pop); + ISEQ_COMPILE_DATA(iseq)->current_block = previous_block; } static void @@ -4329,7 +4592,6 @@ pm_compile_ensure(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_line_co ); pm_scope_node_destroy(&next_scope_node); - ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq; erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange; if (estart->link.next != &eend->link) { @@ -4668,7 +4930,7 @@ pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t *node, cons const pm_node_t *element = cast->elements.nodes[index]; if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE)) { - COMPILE_ERROR(ERROR_ARGS "Ractor constant writes do not support **"); + COMPILE_ERROR(iseq, location.line, "Ractor constant writes do not support **"); } const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) element; @@ -5395,7 +5657,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, throw_flag = 0; } else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) { - COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break"); + COMPILE_ERROR(iseq, location.line, "Can't escape from eval with break"); return; } else { @@ -5417,7 +5679,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, return; } - COMPILE_ERROR(ERROR_ARGS "Invalid break"); + COMPILE_ERROR(iseq, location.line, "Invalid break"); } return; } @@ -5431,13 +5693,24 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, // foo.bar() {} // ^^^^^^^^^^^^ const pm_call_node_t *cast = (const pm_call_node_t *) node; - LABEL *start = NEW_LABEL(location.line); + ID method_id = pm_constant_id_lookup(scope_node, cast->name); - if (cast->block) { - PUSH_LABEL(ret, start); + const pm_location_t *message_loc = &cast->message_loc; + if (message_loc->start == NULL) message_loc = &cast->base.location; + + const pm_line_column_t location = PM_LOCATION_START_LINE_COLUMN(scope_node->parser, message_loc); + const char *builtin_func; + + if (UNLIKELY(iseq_has_builtin_function_table(iseq)) && (builtin_func = pm_iseq_builtin_function_name(scope_node, cast->receiver, method_id)) != NULL) { + const pm_string_t *filepath = &scope_node->parser->filepath; + fprintf(stderr, "COMPILING %.*s:%d:%d builtin_func:%s\n", (int) pm_string_length(filepath), pm_string_source(filepath), location.line, location.column, builtin_func); + + pm_compile_builtin_function_call(iseq, ret, scope_node, cast, &location, popped, ISEQ_COMPILE_DATA(iseq)->current_block, builtin_func); + return; } - ID method_id = pm_constant_id_lookup(scope_node, cast->name); + LABEL *start = NEW_LABEL(location.line); + if (cast->block) PUSH_LABEL(ret, start); switch (method_id) { case idUMinus: { @@ -7389,7 +7662,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, break; } else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) { - COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next"); + COMPILE_ERROR(iseq, location.line, "Can't escape from eval with next"); return; } @@ -7407,7 +7680,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, if (popped) PUSH_INSN(ret, location, pop); } else { - COMPILE_ERROR(ERROR_ARGS "Invalid next"); + COMPILE_ERROR(iseq, location.line, "Invalid next"); return; } } @@ -7642,7 +7915,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, break; } else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) { - COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo"); + COMPILE_ERROR(iseq, location.line, "Can't escape from eval with redo"); return; } @@ -7655,7 +7928,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, if (popped) PUSH_INSN(ret, location, pop); } else { - COMPILE_ERROR(ERROR_ARGS "Invalid redo"); + COMPILE_ERROR(iseq, location.line, "Invalid redo"); return; } } @@ -7883,7 +8156,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, if (popped) PUSH_INSN(ret, location, pop); } else { - COMPILE_ERROR(ERROR_ARGS "Invalid retry"); + COMPILE_ERROR(iseq, location.line, "Invalid retry"); return; } return; @@ -8721,7 +8994,9 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, return; } case ISEQ_TYPE_METHOD: { + ISEQ_COMPILE_DATA(iseq)->root_node = (const void *) scope_node->body; PUSH_TRACE(ret, RUBY_EVENT_CALL); + if (scope_node->body) { PM_COMPILE((const pm_node_t *) scope_node->body); } @@ -8729,9 +9004,10 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, PUSH_INSN(ret, location, putnil); } + ISEQ_COMPILE_DATA(iseq)->root_node = (const void *) scope_node->body; PUSH_TRACE(ret, RUBY_EVENT_RETURN); - ISEQ_COMPILE_DATA(iseq)->last_line = body->location.code_location.end_pos.lineno; + ISEQ_COMPILE_DATA(iseq)->last_line = body->location.code_location.end_pos.lineno; break; } case ISEQ_TYPE_RESCUE: { @@ -9075,7 +9351,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, case ISEQ_TYPE_TOP: case ISEQ_TYPE_MAIN: case ISEQ_TYPE_CLASS: - COMPILE_ERROR(ERROR_ARGS "Invalid yield"); + COMPILE_ERROR(iseq, location.line, "Invalid yield"); return; default: /* valid */; } diff --git a/template/prelude.c.tmpl b/template/prelude.c.tmpl index e17a75da79..af493dfaca 100644 --- a/template/prelude.c.tmpl +++ b/template/prelude.c.tmpl @@ -154,6 +154,18 @@ prelude_ast_value(VALUE name, VALUE code, int line) return ast_value; } +static void +pm_prelude_load(pm_parse_result_t *result, VALUE name, VALUE code, int line) +{ + pm_options_line_set(&result->options, line); + VALUE error = pm_parse_string(result, code, name); + + if (!NIL_P(error)) { + pm_parse_result_free(result); + rb_exc_raise(error); + } +} + % end % if @builtin_count > 0 #define PRELUDE_VAST(n, name_str, start_line) \ @@ -176,6 +188,28 @@ rb_builtin_ast_value(const char *feature_name, VALUE *name_str) return ast_value; } +bool +pm_builtin_ast_value(pm_parse_result_t *result, const char *feature_name, VALUE *name_str) +{ + const size_t prefix_len = rb_strlen_lit(") - prefix_len - 2 == namelen) && + (strncmp(prelude_name<%= i %> + prefix_len, feature_name, namelen) == 0) + ) { + *name_str = PRELUDE_NAME(<%= i %>); + pm_prelude_load(result, *name_str, PRELUDE_CODE(<%= i %>), <%= start_line %>); + return true; + } +% end +% end + + return false; +} + % end % if @prelude_count > 0 COMPILER_WARNING_PUSH @@ -198,13 +232,22 @@ prelude_eval(VALUE code, VALUE name, int line) 0, /* int debug_level; */ }; - rb_ast_t *ast; - VALUE ast_value = prelude_ast_value(name, code, line); - ast = rb_ruby_ast_data_get(ast_value); - rb_iseq_eval(rb_iseq_new_with_opt(ast_value, name, name, Qnil, line, - NULL, 0, ISEQ_TYPE_TOP, &optimization, - Qnil)); - rb_ast_dispose(ast); + if (*rb_ruby_prism_ptr()) { + pm_parse_result_t result = { 0 }; + pm_prelude_load(&result, name, code, line); + rb_iseq_eval(pm_iseq_new_with_opt(&result.node, name, name, Qnil, line, + NULL, 0, ISEQ_TYPE_TOP, &optimization)); + pm_parse_result_free(&result); + } + else { + rb_ast_t *ast; + VALUE ast_value = prelude_ast_value(name, code, line); + ast = rb_ruby_ast_data_get(ast_value); + rb_iseq_eval(rb_iseq_new_with_opt(ast_value, name, name, Qnil, line, + NULL, 0, ISEQ_TYPE_TOP, &optimization, + Qnil)); + rb_ast_dispose(ast); + } } COMPILER_WARNING_POP