`__FILE__` was managed by `NODE_STR` with `String` object.
This commit introduces `NODE_FILE` and `struct rb_parser_string` so that

1. `__FILE__` is detectable from AST Node
2. Reduce dependency ruby object
This commit is contained in:
yui-knk 2023-12-29 22:34:35 +09:00 коммит произвёл Yuichiro Kaneko
Родитель 91a0d1c437
Коммит 7a050638b1
12 изменённых файлов: 185 добавлений и 37 удалений

2
ast.c
Просмотреть файл

@ -694,6 +694,8 @@ node_children(rb_ast_t *ast, const NODE *node)
}
case NODE_LINE:
return rb_ary_new_from_args(1, rb_node_line_lineno_val(node));
case NODE_FILE:
return rb_ary_new_from_args(1, rb_node_file_path_val(node));
case NODE_ERROR:
return rb_ary_new_from_node_args(ast, 0);
case NODE_ARGS_AUX:

Просмотреть файл

@ -10495,6 +10495,7 @@ node_dump.$(OBJEXT): $(top_srcdir)/internal/compilers.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/gc.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/hash.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/imemo.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/serial.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/variable.h

Просмотреть файл

@ -819,7 +819,6 @@ get_nd_vid(const NODE *node)
}
}
static NODE *
get_nd_value(const NODE *node)
{
@ -833,6 +832,19 @@ get_nd_value(const NODE *node)
}
}
static VALUE
get_string_value(const NODE *node)
{
switch (nd_type(node)) {
case NODE_STR:
return RNODE_STR(node)->nd_lit;
case NODE_FILE:
return rb_node_file_path_val(node);
default:
rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
}
}
VALUE
rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
{
@ -4282,7 +4294,7 @@ all_string_result_p(const NODE *node)
{
if (!node) return FALSE;
switch (nd_type(node)) {
case NODE_STR: case NODE_DSTR:
case NODE_STR: case NODE_DSTR: case NODE_FILE:
return TRUE;
case NODE_IF: case NODE_UNLESS:
if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
@ -4493,6 +4505,7 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
goto again;
case NODE_LIT: /* NODE_LIT is always true */
case NODE_LINE:
case NODE_FILE:
case NODE_TRUE:
case NODE_STR:
case NODE_ZLIST:
@ -4658,6 +4671,7 @@ static_literal_node_p(const NODE *node, const rb_iseq_t *iseq)
case NODE_FALSE:
return TRUE;
case NODE_STR:
case NODE_FILE:
return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal;
default:
return FALSE;
@ -4676,16 +4690,17 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq)
return Qfalse;
case NODE_LINE:
return rb_node_line_lineno_val(node);
case NODE_FILE:
case NODE_STR:
if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
VALUE lit;
VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node)));
lit = rb_str_dup(RNODE_STR(node)->nd_lit);
lit = rb_str_dup(get_string_value(node));
rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
return rb_str_freeze(lit);
}
else {
return rb_fstring(RNODE_STR(node)->nd_lit);
return rb_fstring(get_string_value(node));
}
case NODE_LIT:
return RNODE_LIT(node)->nd_lit;
@ -5067,6 +5082,8 @@ rb_node_case_when_optimizable_literal(const NODE *const node)
return rb_node_line_lineno_val(node);
case NODE_STR:
return rb_fstring(RNODE_STR(node)->nd_lit);
case NODE_FILE:
return rb_fstring(rb_node_file_path_val(node));
}
return Qundef;
}
@ -5086,9 +5103,9 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
}
if (nd_type_p(val, NODE_STR)) {
debugp_param("nd_lit", RNODE_STR(val)->nd_lit);
lit = rb_fstring(RNODE_STR(val)->nd_lit);
if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
debugp_param("nd_lit", get_string_value(val));
lit = rb_fstring(get_string_value(val));
ADD_INSN1(cond_seq, val, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
}
@ -5692,6 +5709,7 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
case NODE_STR:
case NODE_LIT:
case NODE_LINE:
case NODE_FILE:
case NODE_ZLIST:
case NODE_AND:
case NODE_OR:
@ -7105,6 +7123,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
}
case NODE_LIT:
case NODE_LINE:
case NODE_FILE:
case NODE_STR:
case NODE_XSTR:
case NODE_DSTR:
@ -8321,12 +8340,13 @@ compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE
/* optimization shortcut
* "literal".freeze -> opt_str_freeze("literal")
*/
if (get_nd_recv(node) && nd_type_p(get_nd_recv(node), NODE_STR) &&
if (get_nd_recv(node) &&
(nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
(get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
get_nd_args(node) == NULL &&
ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
VALUE str = rb_fstring(RNODE_STR(get_nd_recv(node))->nd_lit);
VALUE str = rb_fstring(get_string_value(get_nd_recv(node)));
if (get_node_call_nd_mid(node) == idUMinus) {
ADD_INSN2(ret, line_node, opt_str_uminus, str,
new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
@ -8346,11 +8366,11 @@ compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE
*/
if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_STR) &&
(nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_FILE)) &&
ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
VALUE str = rb_fstring(RNODE_STR(RNODE_LIST(get_nd_args(node))->nd_head)->nd_lit);
VALUE str = rb_fstring(get_string_value(RNODE_LIST(get_nd_args(node))->nd_head));
CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
ADD_INSN2(ret, line_node, opt_aref_with, str,
new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
@ -9697,12 +9717,12 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
*/
if (mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) &&
(nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_FILE)) &&
ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
{
VALUE str = rb_fstring(RNODE_STR(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head)->nd_lit);
VALUE str = rb_fstring(get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head));
CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
if (!popped) {
@ -10134,10 +10154,11 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
break;
}
case NODE_FILE:
case NODE_STR:{
debugp_param("nd_lit", RNODE_STR(node)->nd_lit);
debugp_param("nd_lit", get_string_value(node));
if (!popped) {
VALUE lit = RNODE_STR(node)->nd_lit;
VALUE lit = get_string_value(node);
if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
lit = rb_fstring(lit);
ADD_INSN1(ret, node, putstring, lit);

Просмотреть файл

@ -68,4 +68,5 @@ enum lex_state_e {
};
VALUE rb_node_line_lineno_val(const NODE *);
VALUE rb_node_file_path_val(const NODE *);
#endif /* INTERNAL_RUBY_PARSE_H */

Просмотреть файл

@ -457,6 +457,8 @@ class RbInspector(LLDBInterface):
self._append_expression("*(struct RNode_ERROR *) %0#x" % val.GetValueAsUnsigned())
elif nd_type == self.ruby_globals["NODE_LINE"]:
self._append_expression("*(struct RNode_LINE *) %0#x" % val.GetValueAsUnsigned())
elif nd_type == self.ruby_globals["NODE_FILE"]:
self._append_expression("*(struct RNode_FILE *) %0#x" % val.GetValueAsUnsigned())
elif nd_type == self.ruby_globals["NODE_RIPPER"]:
self._append_expression("*(struct RNode_RIPPER *) %0#x" % val.GetValueAsUnsigned())
elif nd_type == self.ruby_globals["NODE_RIPPER_VALUES"]:

9
node.c
Просмотреть файл

@ -169,10 +169,19 @@ struct rb_ast_local_table_link {
// }
};
static void
parser_string_free(rb_ast_t *ast, rb_parser_string_t *str)
{
xfree(str);
}
static void
free_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
{
switch (nd_type(node)) {
case NODE_FILE:
parser_string_free(ast, RNODE_FILE(node)->path);
break;
default:
break;
}

Просмотреть файл

@ -11,6 +11,7 @@
#include "internal.h"
#include "internal/hash.h"
#include "internal/ruby_parser.h"
#include "internal/variable.h"
#include "ruby/ruby.h"
#include "vm_core.h"
@ -64,6 +65,7 @@
#define F_INT(name, type, ann) SIMPLE_FIELD1(#name, ann) A_INT(type(node)->name)
#define F_LONG(name, type, ann) SIMPLE_FIELD1(#name, ann) A_LONG(type(node)->name)
#define F_LIT(name, type, ann) SIMPLE_FIELD1(#name, ann) A_LIT(type(node)->name)
#define F_VALUE(name, val, ann) SIMPLE_FIELD1(#name, ann) A_LIT(val)
#define F_MSG(name, ann, desc) SIMPLE_FIELD1(#name, ann) A(desc)
#define F_NODE(name, type, ann) \
@ -1105,6 +1107,13 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
ANN("example: __LINE__");
return;
case NODE_FILE:
ANN("line");
ANN("format: [path]");
ANN("example: __FILE__");
F_VALUE(path, rb_node_file_path_val(node), "path");
return;
case NODE_ERROR:
ANN("Broken input recovered by Error Tolerant mode");
return;

76
parse.y
Просмотреть файл

@ -954,6 +954,7 @@ static rb_node_aryptn_t *rb_node_aryptn_new(struct parser_params *p, NODE *pre_a
static rb_node_hshptn_t *rb_node_hshptn_new(struct parser_params *p, NODE *nd_pconst, NODE *nd_pkwargs, NODE *nd_pkwrestarg, const YYLTYPE *loc);
static rb_node_fndptn_t *rb_node_fndptn_new(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc);
static rb_node_line_t *rb_node_line_new(struct parser_params *p, const YYLTYPE *loc);
static rb_node_file_t *rb_node_file_new(struct parser_params *p, VALUE str, const YYLTYPE *loc);
static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE *loc);
#define NEW_SCOPE(a,b,loc) (NODE *)rb_node_scope_new(p,a,b,loc)
@ -1056,6 +1057,7 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE
#define NEW_HSHPTN(c,kw,kwrest,loc) (NODE *)rb_node_hshptn_new(p,c,kw,kwrest,loc)
#define NEW_FNDPTN(pre,a,post,loc) (NODE *)rb_node_fndptn_new(p,pre,a,post,loc)
#define NEW_LINE(loc) (NODE *)rb_node_line_new(p,loc)
#define NEW_FILE(str,loc) (NODE *)rb_node_file_new(p,str,loc)
#define NEW_ERROR(loc) (NODE *)rb_node_error_new(p,loc)
#endif
@ -1911,6 +1913,56 @@ get_nd_args(struct parser_params *p, NODE *node)
}
}
#endif
#ifndef RIPPER
static rb_parser_string_t *
rb_parser_string_new(rb_parser_t *p, const char *ptr, long len)
{
size_t size;
rb_parser_string_t *str;
if (len < 0) {
rb_bug("negative string size (or size too big): %ld", len);
}
size = offsetof(rb_parser_string_t, ptr) + len + 1;
str = xcalloc(1, size);
if (ptr) {
memcpy(str->ptr, ptr, len);
}
str->len = len;
str->ptr[len] = '\0';
return str;
}
static rb_parser_string_t *
rb_parser_encoding_string_new(rb_parser_t *p, const char *ptr, long len, rb_encoding *enc)
{
rb_parser_string_t *str = rb_parser_string_new(p, ptr, len);
str->enc = enc;
return str;
}
long
rb_parser_string_length(rb_parser_string_t *str)
{
return str->len;
}
char *
rb_parser_string_pointer(rb_parser_string_t *str)
{
return str->ptr;
}
static rb_parser_string_t *
rb_str_to_parser_encoding_string(rb_parser_t *p, VALUE str)
{
/* Type check */
return rb_parser_encoding_string_new(p, RSTRING_PTR(str), RSTRING_LEN(str), rb_enc_get(str));
}
#endif
%}
%expect 0
@ -6599,6 +6651,7 @@ singleton : var_ref
case NODE_DREGX:
case NODE_LIT:
case NODE_LINE:
case NODE_FILE:
case NODE_DSYM:
case NODE_LIST:
case NODE_ZLIST:
@ -12186,6 +12239,15 @@ rb_node_line_new(struct parser_params *p, const YYLTYPE *loc)
return n;
}
static rb_node_file_t *
rb_node_file_new(struct parser_params *p, VALUE str, const YYLTYPE *loc)
{
rb_node_file_t *n = NODE_NEWNODE(NODE_FILE, rb_node_file_t, loc);
n->path = rb_str_to_parser_encoding_string(p, str);
return n;
}
static rb_node_cdecl_t *
rb_node_cdecl_new(struct parser_params *p, ID nd_vid, NODE *nd_value, NODE *nd_else, const YYLTYPE *loc)
{
@ -12786,10 +12848,7 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
VALUE file = p->ruby_sourcefile_string;
if (NIL_P(file))
file = rb_str_new(0, 0);
else
file = rb_str_dup(file);
node = NEW_STR(file, loc);
RB_OBJ_WRITTEN(p->ast, Qnil, file);
node = NEW_FILE(file, loc);
}
return node;
case keyword__LINE__:
@ -13691,6 +13750,12 @@ shareable_literal_constant(struct parser_params *p, enum shareability shareable,
RB_OBJ_WRITE(p->ast, &RNODE_LIT(value)->nd_lit, lit);
return value;
case NODE_FILE:
lit = rb_fstring(rb_node_file_path_val(value));
value = NEW_LIT(lit, loc);
RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(value)->nd_lit);
return value;
case NODE_ZLIST:
lit = rb_ary_new();
OBJ_FREEZE_RAW(lit);
@ -13985,6 +14050,7 @@ void_expr(struct parser_params *p, NODE *node)
break;
case NODE_LIT:
case NODE_LINE:
case NODE_FILE:
case NODE_STR:
case NODE_DSTR:
case NODE_DREGX:
@ -14123,6 +14189,7 @@ is_static_content(NODE *node)
} while ((node = RNODE_LIST(node)->nd_next) != 0);
case NODE_LIT:
case NODE_LINE:
case NODE_FILE:
case NODE_STR:
case NODE_NIL:
case NODE_TRUE:
@ -14208,6 +14275,7 @@ cond0(struct parser_params *p, NODE *node, enum cond_type type, const YYLTYPE *l
case NODE_DSTR:
case NODE_EVSTR:
case NODE_STR:
case NODE_FILE:
SWITCH_BY_COND_TYPE(type, warn, "string ");
break;

Просмотреть файл

@ -4,12 +4,6 @@
#include "rubyparser.h"
VALUE
rb_node_line_lineno_val(const NODE *node)
{
return INT2FIX(node->nd_loc.beg_pos.lineno);
}
#ifdef UNIVERSAL_PARSER
#include "internal.h"
@ -920,3 +914,16 @@ rb_parser_set_yydebug(VALUE vparser, VALUE flag)
return flag;
}
#endif
VALUE
rb_node_line_lineno_val(const NODE *node)
{
return INT2FIX(node->nd_loc.beg_pos.lineno);
}
VALUE
rb_node_file_path_val(const NODE *node)
{
rb_parser_string_t *str = RNODE_FILE(node)->path;
return rb_enc_str_new(str->ptr, str->len, str->enc);
}

Просмотреть файл

@ -22,6 +22,29 @@
#endif
#ifndef FLEX_ARY_LEN
/* From internal/compilers.h */
/* A macro for defining a flexible array, like: VALUE ary[FLEX_ARY_LEN]; */
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
# define FLEX_ARY_LEN /* VALUE ary[]; */
#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
# define FLEX_ARY_LEN 0 /* VALUE ary[0]; */
#else
# define FLEX_ARY_LEN 1 /* VALUE ary[1]; */
#endif
#endif
/*
* Parser String
*/
typedef struct rb_parser_string {
rb_encoding *enc;
/* Length of the string, not including terminating NUL character. */
long len;
/* Pointer to the contents of the string. */
char ptr[FLEX_ARY_LEN];
} rb_parser_string_t;
/*
* AST Node
*/
@ -131,23 +154,12 @@ enum node_type {
NODE_FNDPTN,
NODE_ERROR,
NODE_LINE,
NODE_FILE,
NODE_RIPPER,
NODE_RIPPER_VALUES,
NODE_LAST
};
#ifndef FLEX_ARY_LEN
/* From internal/compilers.h */
/* A macro for defining a flexible array, like: VALUE ary[FLEX_ARY_LEN]; */
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
# define FLEX_ARY_LEN /* VALUE ary[]; */
#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
# define FLEX_ARY_LEN 0 /* VALUE ary[0]; */
#else
# define FLEX_ARY_LEN 1 /* VALUE ary[1]; */
#endif
#endif
typedef struct rb_ast_id_table {
int size;
ID ids[FLEX_ARY_LEN];
@ -936,6 +948,12 @@ typedef struct RNode_LINE {
NODE node;
} rb_node_line_t;
typedef struct RNode_FILE {
NODE node;
struct rb_parser_string *path;
} rb_node_file_t;
typedef struct RNode_ERROR {
NODE node;
} rb_node_error_t;
@ -1046,6 +1064,7 @@ typedef struct RNode_ERROR {
#define RNODE_HSHPTN(node) ((struct RNode_HSHPTN *)(node))
#define RNODE_FNDPTN(node) ((struct RNode_FNDPTN *)(node))
#define RNODE_LINE(node) ((struct RNode_LINE *)(node))
#define RNODE_FILE(node) ((struct RNode_FILE *)(node))
#ifdef RIPPER
typedef struct RNode_RIPPER {
@ -1406,6 +1425,10 @@ void rb_ruby_parser_config_free(rb_parser_config_t *config);
rb_parser_t *rb_ruby_parser_allocate(rb_parser_config_t *config);
rb_parser_t *rb_ruby_parser_new(rb_parser_config_t *config);
#endif
long rb_parser_string_length(rb_parser_string_t *str);
char *rb_parser_string_pointer(rb_parser_string_t *str);
RUBY_SYMBOL_EXPORT_END
#endif /* RUBY_RUBYPARSER_H */

Просмотреть файл

@ -582,8 +582,10 @@ class TestRubyOptions < Test::Unit::TestCase
t.rewind
t.truncate(0)
t.puts "if a = __LINE__; end"
t.puts "if a = __FILE__; end"
t.flush
err = ["#{t.path}:1:#{warning}",
"#{t.path}:2:#{warning}",
]
assert_in_out_err(["-w", t.path], "", [], err)
assert_in_out_err(["-wr", t.path, "-e", ""], "", [], err)

Просмотреть файл

@ -1210,6 +1210,9 @@ eom
assert_warn(/string literal in condition/) do
eval('1 if ""')
end
assert_warning(/string literal in condition/) do
eval('1 if __FILE__')
end
assert_warn(/regex literal in condition/) do
eval('1 if //')
end