ruby-changes:63219
From: Nobuyoshi <ko1@a...>
Date: Wed, 30 Sep 2020 23:49:56 +0900 (JST)
Subject: [ruby-changes:63219] 7b2bea42a2 (master): Unfreeze string-literal-only interpolated string-literal
https://git.ruby-lang.org/ruby.git/commit/?id=7b2bea42a2 From 7b2bea42a245f2e80b5d2700963fd6b143f6d6b8 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada <nobu@r...> Date: Wed, 2 Sep 2020 23:12:22 +0900 Subject: Unfreeze string-literal-only interpolated string-literal [Feature #17104] diff --git a/ast.c b/ast.c index 87c3665..2af0b3e 100644 --- a/ast.c +++ b/ast.c @@ -485,9 +485,15 @@ node_children(rb_ast_t *ast, const NODE *node) https://github.com/ruby/ruby/blob/trunk/ast.c#L485 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: diff --git a/compile.c b/compile.c index 797a170..0d2d7fb 100644 --- a/compile.c +++ b/compile.c @@ -3828,8 +3828,16 @@ static int https://github.com/ruby/ruby/blob/trunk/compile.c#L3828 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; } diff --git a/node.c b/node.c index 7c291a8..9360437 100644 --- a/node.c +++ b/node.c @@ -741,6 +741,7 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node) https://github.com/ruby/ruby/blob/trunk/node.c#L741 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"); diff --git a/parse.y b/parse.y index 93bc2ef..f8441e8 100644 --- a/parse.y +++ b/parse.y @@ -9871,12 +9871,24 @@ literal_concat0(struct parser_params *p, VALUE head, VALUE tail) https://github.com/ruby/ruby/blob/trunk/parse.y#L9871 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 https://github.com/ruby/ruby/blob/trunk/parse.y#L9911 } 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 https://github.com/ruby/ruby/blob/trunk/parse.y#L9942 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) https://github.com/ruby/ruby/blob/trunk/parse.y#L9989 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) https://github.com/ruby/ruby/blob/trunk/parse.y#L10288 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)) { diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb index 7fb6268..51e3fd0 100644 --- a/test/ruby/test_iseq.rb +++ b/test/ruby/test_iseq.rb @@ -188,7 +188,7 @@ class TestISeq < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iseq.rb#L188 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. -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/