зеркало из https://github.com/github/ruby.git
[PRISM] Support for compiling builtins
This commit is contained in:
Родитель
4558abec02
Коммит
4e36abbab3
|
@ -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) {
|
||||
|
|
310
prism_compile.c
310
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 */;
|
||||
}
|
||||
|
|
|
@ -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("<internal:");
|
||||
size_t namelen = strlen(feature_name);
|
||||
|
||||
% @preludes.each_value do |i, prelude, lines, sub, start_line|
|
||||
% if sub
|
||||
if (
|
||||
(sizeof(prelude_name<%= i %>) - 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
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче