Unverified Commit 5424640f authored by Yukihiro "Matz" Matsumoto's avatar Yukihiro "Matz" Matsumoto Committed by GitHub

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

String literal concatenation
parents 6962d0dd f9a568ad
......@@ -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) {
......
......@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment