Merge pull request #4303 from dearblue/string-literal-concatenation

String literal concatenation
This commit is contained in:
Yukihiro "Matz" Matsumoto
2019-02-28 07:05:08 +09:00
committed by GitHub
2 changed files with 98 additions and 3 deletions
+91 -3
View File
@@ -852,6 +852,87 @@ new_dstr(parser_state *p, node *a)
return cons((node*)NODE_DSTR, a);
}
static int
string_node_p(node *n)
{
return (int)((enum node_type)(intptr_t)n->car == NODE_STR);
}
static node*
composite_string_node(parser_state *p, node *a, node *b)
{
size_t newlen = (size_t)a->cdr + (size_t)b->cdr;
char *str = (char*)mrb_pool_realloc(p->pool, a->car, (size_t)a->cdr + 1, newlen + 1);
memcpy(str + (size_t)a->cdr, b->car, (size_t)b->cdr);
str[newlen] = '\0';
a->car = (node*)str;
a->cdr = (node*)newlen;
cons_free(b);
return a;
}
static node*
concat_string(parser_state *p, node *a, node *b)
{
if (string_node_p(a)) {
if (string_node_p(b)) {
/* a == NODE_STR && b == NODE_STR */
composite_string_node(p, a->cdr, b->cdr);
cons_free(b);
return a;
}
else {
/* a == NODE_STR && b == NODE_DSTR */
if (string_node_p(b->cdr->car)) {
/* a == NODE_STR && b->[NODE_STR, ...] */
composite_string_node(p, a->cdr, b->cdr->car->cdr);
cons_free(b->cdr->car);
b->cdr->car = a;
return b;
}
}
}
else if (string_node_p(b)) {
/* a == NODE_DSTR && b == NODE_STR */
node *c;
for (c = a; c->cdr != NULL; c = c->cdr) ;
if (string_node_p(c->car)) {
/* a->[..., NODE_STR] && b == NODE_STR */
composite_string_node(p, c->car->cdr, b->cdr);
cons_free(b);
return a;
}
push(a, b);
return a;
}
else {
/* a == NODE_DSTR && b == NODE_DSTR */
node *c, *d;
for (c = a; c->cdr != NULL; c = c->cdr) ;
if (string_node_p(c->car) && string_node_p(b->cdr->car)) {
/* a->[..., NODE_STR] && b->[NODE_STR, ...] */
d = b->cdr;
cons_free(b);
composite_string_node(p, c->car->cdr, d->car->cdr);
cons_free(d->car);
c->cdr = d->cdr;
cons_free(d);
return a;
}
else {
c->cdr = b->cdr;
cons_free(b);
return a;
}
}
return new_dstr(p, list2(a, b));
}
/* (:str . (s . len)) */
static node*
new_xstr(parser_state *p, const char *s, int len)
@@ -1200,7 +1281,7 @@ heredoc_end(parser_state *p)
%token <nd> tNTH_REF tBACK_REF
%token <num> tREGEXP_END
%type <nd> singleton string string_rep string_interp xstring regexp
%type <nd> singleton string string_fragment string_rep string_interp xstring regexp
%type <nd> literal numeric cpath symbol
%type <nd> top_compstmt top_stmts top_stmt
%type <nd> bodystmt compstmt stmts stmt expr arg primary command command_call method_call
@@ -2852,7 +2933,14 @@ literal : numeric
| symbols
;
string : tCHAR
string : string_fragment
| string string_fragment
{
$$ = concat_string(p, $1, $2);
}
;
string_fragment : tCHAR
| tSTRING
| tSTRING_BEG tSTRING
{
@@ -3478,7 +3566,7 @@ assoc : arg tASSOC arg
void_expr_error(p, $3);
$$ = cons(new_sym(p, $1), $3);
}
| string tLABEL_TAG arg
| string_fragment tLABEL_TAG arg
{
void_expr_error(p, $3);
if ($1->car == (node*)NODE_DSTR) {
+7
View File
@@ -713,3 +713,10 @@ assert('String#freeze') do
assert_raise(RuntimeError) { str.upcase! }
end
assert('String literal concatenation') do
assert_equal 2, ("A" "B").size
assert_equal 3, ('A' "B" 'C').size
assert_equal 3, (?A "#{?B}C").size
assert_equal 4, (%(A) "B#{?C}" "D").size
end