From e7576a777c32fdf04f6e014a225025b5e2b45553 Mon Sep 17 00:00:00 2001
From: nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Fri, 26 Oct 2012 04:24:29 +0000
Subject: [PATCH] parse.y: concatenated literals

* parse.y (literal_concat_gen): merge fixed strings across
  concatenated literals, after an interpolation.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37331 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
---
 ChangeLog |  5 +++++
 parse.y   | 22 +++++++++++++++++++++-
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 60de2f6399..67ebd79fa2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Fri Oct 26 13:24:20 2012  Nobuyoshi Nakada  <nobu@ruby-lang.org>
+
+	* parse.y (literal_concat_gen): merge fixed strings across
+	  concatenated literals, after an interpolation.
+
 Thu Oct 25 17:48:54 2012  NAKAMURA Usaku  <usa@ruby-lang.org>
 
 	* win32/win32.c (has_redirection): should use shell (cmd.exe) when
diff --git a/parse.y b/parse.y
index 7eaab6b1b8..8549cb1378 100644
--- a/parse.y
+++ b/parse.y
@@ -8246,6 +8246,8 @@ static NODE *
 literal_concat_gen(struct parser_params *parser, NODE *head, NODE *tail)
 {
     enum node_type htype;
+    NODE *headlast;
+    VALUE lit;
 
     if (!head) return tail;
     if (!tail) return head;
@@ -8254,11 +8256,20 @@ literal_concat_gen(struct parser_params *parser, NODE *head, NODE *tail)
     if (htype == NODE_EVSTR) {
 	NODE *node = NEW_DSTR(Qnil);
 	head = list_append(node, head);
+	htype = NODE_DSTR;
     }
     switch (nd_type(tail)) {
       case NODE_STR:
+	if (htype == NODE_DSTR && (headlast = head->nd_next->nd_end->nd_head) &&
+	    nd_type(headlast) == NODE_STR) {
+	    htype = NODE_STR;
+	    lit = headlast->nd_lit;
+	}
+	else {
+	    lit = head->nd_lit;
+	}
 	if (htype == NODE_STR) {
-	    if (!literal_concat0(parser, head->nd_lit, tail->nd_lit)) {
+	    if (!literal_concat0(parser, lit, tail->nd_lit)) {
 	      error:
 		rb_gc_force_recycle((VALUE)head);
 		rb_gc_force_recycle((VALUE)tail);
@@ -8280,11 +8291,20 @@ literal_concat_gen(struct parser_params *parser, NODE *head, NODE *tail)
 	    head = tail;
 	}
 	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;
 	    rb_gc_force_recycle((VALUE)tail);
 	}
+	else if (htype == NODE_DSTR && (headlast = head->nd_next->nd_end->nd_head) &&
+		 nd_type(headlast) == NODE_STR) {
+	    lit = headlast->nd_lit;
+	    if (!literal_concat0(parser, lit, tail->nd_lit))
+		goto error;
+	    tail->nd_lit = Qnil;
+	    goto append;
+	}
 	else {
 	    nd_set_type(tail, NODE_ARRAY);
 	    tail->nd_head = NEW_STR(tail->nd_lit);