mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Merge pull request #4303 from dearblue/string-literal-concatenation
String literal concatenation
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user