mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Unfreeze string-literal-only interpolated string-literal
[Feature #17104]
This commit is contained in:
parent
65e8a29389
commit
7b2bea42a2
5 changed files with 50 additions and 18 deletions
12
ast.c
12
ast.c
|
@ -485,9 +485,15 @@ node_children(rb_ast_t *ast, const NODE *node)
|
|||
case NODE_DXSTR:
|
||||
case NODE_DREGX:
|
||||
case NODE_DSYM:
|
||||
return rb_ary_new_from_args(3, node->nd_lit,
|
||||
NEW_CHILD(ast, node->nd_next->nd_head),
|
||||
NEW_CHILD(ast, node->nd_next->nd_next));
|
||||
{
|
||||
NODE *n = node->nd_next;
|
||||
VALUE head = Qnil, next = Qnil;
|
||||
if (n) {
|
||||
head = NEW_CHILD(ast, n->nd_head);
|
||||
next = NEW_CHILD(ast, n->nd_next);
|
||||
}
|
||||
return rb_ary_new_from_args(3, node->nd_lit, head, next);
|
||||
}
|
||||
case NODE_EVSTR:
|
||||
return rb_ary_new_from_node_args(ast, 1, node->nd_body);
|
||||
case NODE_ARGSCAT:
|
||||
|
|
12
compile.c
12
compile.c
|
@ -3828,8 +3828,16 @@ static int
|
|||
compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
|
||||
{
|
||||
int cnt;
|
||||
CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
|
||||
ADD_INSN1(ret, nd_line(node), concatstrings, INT2FIX(cnt));
|
||||
if (!node->nd_next) {
|
||||
VALUE lit = rb_fstring(node->nd_lit);
|
||||
const int line = (int)nd_line(node);
|
||||
ADD_INSN1(ret, line, putstring, lit);
|
||||
RB_OBJ_WRITTEN(iseq, Qundef, lit);
|
||||
}
|
||||
else {
|
||||
CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
|
||||
ADD_INSN1(ret, nd_line(node), concatstrings, INT2FIX(cnt));
|
||||
}
|
||||
return COMPILE_OK;
|
||||
}
|
||||
|
||||
|
|
1
node.c
1
node.c
|
@ -741,6 +741,7 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
|
|||
ANN("example: :\"foo#{ bar }baz\"");
|
||||
dlit:
|
||||
F_LIT(nd_lit, "preceding string");
|
||||
if (!node->nd_next) return;
|
||||
F_NODE(nd_next->nd_head, "interpolation");
|
||||
LAST_NODE;
|
||||
F_NODE(nd_next->nd_next, "tailing strings");
|
||||
|
|
41
parse.y
41
parse.y
|
@ -9871,12 +9871,24 @@ literal_concat0(struct parser_params *p, VALUE head, VALUE tail)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
string_literal_head(enum node_type htype, NODE *head)
|
||||
{
|
||||
if (htype != NODE_DSTR) return Qfalse;
|
||||
if (head->nd_next) {
|
||||
head = head->nd_next->nd_end->nd_head;
|
||||
if (!head || nd_type(head) != NODE_STR) return Qfalse;
|
||||
}
|
||||
const VALUE lit = head->nd_lit;
|
||||
ASSUME(lit != Qfalse);
|
||||
return lit;
|
||||
}
|
||||
|
||||
/* concat two string literals */
|
||||
static NODE *
|
||||
literal_concat(struct parser_params *p, NODE *head, NODE *tail, const YYLTYPE *loc)
|
||||
{
|
||||
enum node_type htype;
|
||||
NODE *headlast;
|
||||
VALUE lit;
|
||||
|
||||
if (!head) return tail;
|
||||
|
@ -9899,10 +9911,8 @@ literal_concat(struct parser_params *p, NODE *head, NODE *tail, const YYLTYPE *l
|
|||
}
|
||||
switch (nd_type(tail)) {
|
||||
case NODE_STR:
|
||||
if (htype == NODE_DSTR && (headlast = head->nd_next->nd_end->nd_head) &&
|
||||
nd_type(headlast) == NODE_STR) {
|
||||
if ((lit = string_literal_head(htype, head)) != Qfalse) {
|
||||
htype = NODE_STR;
|
||||
lit = headlast->nd_lit;
|
||||
}
|
||||
else {
|
||||
lit = head->nd_lit;
|
||||
|
@ -9932,13 +9942,16 @@ literal_concat(struct parser_params *p, NODE *head, NODE *tail, const YYLTYPE *l
|
|||
else if (NIL_P(tail->nd_lit)) {
|
||||
append:
|
||||
head->nd_alen += tail->nd_alen - 1;
|
||||
head->nd_next->nd_end->nd_next = tail->nd_next;
|
||||
head->nd_next->nd_end = tail->nd_next->nd_end;
|
||||
if (!head->nd_next) {
|
||||
head->nd_next = tail->nd_next;
|
||||
}
|
||||
else if (tail->nd_next) {
|
||||
head->nd_next->nd_end->nd_next = tail->nd_next;
|
||||
head->nd_next->nd_end = tail->nd_next->nd_end;
|
||||
}
|
||||
rb_discard_node(p, tail);
|
||||
}
|
||||
else if (htype == NODE_DSTR && (headlast = head->nd_next->nd_end->nd_head) &&
|
||||
nd_type(headlast) == NODE_STR) {
|
||||
lit = headlast->nd_lit;
|
||||
else if ((lit = string_literal_head(htype, head)) != Qfalse) {
|
||||
if (!literal_concat0(p, lit, tail->nd_lit))
|
||||
goto error;
|
||||
tail->nd_lit = Qnil;
|
||||
|
@ -9976,7 +9989,9 @@ new_evstr(struct parser_params *p, NODE *node, const YYLTYPE *loc)
|
|||
|
||||
if (node) {
|
||||
switch (nd_type(node)) {
|
||||
case NODE_STR: case NODE_DSTR: case NODE_EVSTR:
|
||||
case NODE_STR:
|
||||
nd_set_type(node, NODE_DSTR);
|
||||
case NODE_DSTR: case NODE_EVSTR:
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
@ -10273,8 +10288,10 @@ new_regexp(struct parser_params *p, NODE *node, int options, const YYLTYPE *loc)
|
|||
node->nd_cflag = options & RE_OPTION_MASK;
|
||||
if (!NIL_P(node->nd_lit)) reg_fragment_check(p, node->nd_lit, options);
|
||||
for (list = (prev = node)->nd_next; list; list = list->nd_next) {
|
||||
if (nd_type(list->nd_head) == NODE_STR) {
|
||||
VALUE tail = list->nd_head->nd_lit;
|
||||
NODE *frag = list->nd_head;
|
||||
enum node_type type = nd_type(frag);
|
||||
if (type == NODE_STR || (type == NODE_DSTR && !frag->nd_next)) {
|
||||
VALUE tail = frag->nd_lit;
|
||||
if (reg_fragment_check(p, tail, options) && prev && !NIL_P(prev->nd_lit)) {
|
||||
VALUE lit = prev == node ? prev->nd_lit : prev->nd_head->nd_lit;
|
||||
if (!literal_concat0(p, lit, tail)) {
|
||||
|
|
|
@ -188,7 +188,7 @@ class TestISeq < Test::Unit::TestCase
|
|||
assert_predicate(s1, :frozen?)
|
||||
assert_predicate(s2, :frozen?)
|
||||
assert_not_predicate(s3, :frozen?)
|
||||
assert_predicate(s4, :frozen?) # should probably not be frozen, but unrealistic code
|
||||
assert_not_predicate(s4, :frozen?)
|
||||
end
|
||||
|
||||
# Safe call chain is not optimized when Coverage is running.
|
||||
|
|
Loading…
Reference in a new issue