aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ast.c12
-rw-r--r--compile.c12
-rw-r--r--node.c1
-rw-r--r--parse.y41
-rw-r--r--test/ruby/test_iseq.rb2
5 files changed, 50 insertions, 18 deletions
diff --git a/ast.c b/ast.c
index 87c366550e..2af0b3e530 100644
--- a/ast.c
+++ b/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:
diff --git a/compile.c b/compile.c
index 797a170f5f..0d2d7fbf73 100644
--- a/compile.c
+++ b/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;
}
diff --git a/node.c b/node.c
index 7c291a80ad..936043794a 100644
--- a/node.c
+++ b/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");
diff --git a/parse.y b/parse.y
index 93bc2ef9ff..f8441e867f 100644
--- a/parse.y
+++ b/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)) {
diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb
index 7fb6268f61..51e3fd0391 100644
--- a/test/ruby/test_iseq.rb
+++ b/test/ruby/test_iseq.rb
@@ -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.