Commit 54bfcaf1 authored by Seeker's avatar Seeker

Add support for squiggly heredocs

parent dad43359
......@@ -45,3 +45,4 @@ of this list.
RIZAL Reckordp
Rory O'Connell
John Bampton
Seeker
......@@ -99,6 +99,7 @@ enum mrb_string_type {
/* heredoc structure */
struct mrb_parser_heredoc_info {
mrb_bool allow_indent:1;
mrb_bool remove_indent:1;
mrb_bool line_head:1;
enum mrb_string_type type;
const char *term;
......
......@@ -1351,6 +1351,55 @@ heredoc_treat_nextline(parser_state *p)
static void
heredoc_end(parser_state *p)
{
parser_heredoc_info *info = parsing_heredoc_inf(p);
if (info->remove_indent) {
mrb_bool counting = TRUE;
size_t indent = -1;
node *list = info->doc;
node *list2 = NULL;
while (list) {
if (list->car->car == NODE_STR) {
node *pair = list->car->cdr;
const char *str = (char*) pair->car;
size_t len = (size_t) pair->cdr;
if (counting) {
list2 = push(list2, pair);
}
size_t spaces = 0;
for (size_t i = 0; i < len; i++) {
if (counting) {
if (ISSPACE(str[i])) {
++spaces;
}
else {
counting = FALSE;
if (indent == -1 || spaces < indent) {
indent = spaces;
}
}
}
if (str[i] == '\n') {
counting = TRUE;
break;
}
}
}
else {
counting = FALSE;
}
list = list->cdr;
}
if (indent > 0) {
while (list2) {
node *pair = list2->car;
const char *str = (char*) pair->car;
size_t len = (size_t) pair->cdr;
pair->car = (node*) (str + indent);
pair->cdr = (node*) (len - indent);
list2 = list2->cdr;
}
}
}
p->parsing_heredoc = p->parsing_heredoc->cdr;
if (p->parsing_heredoc == NULL) {
p->lstate = EXPR_BEG;
......@@ -1499,7 +1548,7 @@ heredoc_end(parser_state *p)
%token tANDDOT /* &. */
%token tSYMBEG tREGEXP_BEG tWORDS_BEG tSYMBOLS_BEG
%token tSTRING_BEG tXSTRING_BEG tSTRING_DVAR tLAMBEG
%token <nd> tHEREDOC_BEG /* <<, <<- */
%token <nd> tHEREDOC_BEG /* <<, <<-, <<~ */
%token tHEREDOC_END tLITERAL_DELIM tHD_LITERAL_DELIM
%token <nd> tHD_STRING_PART tHD_STRING_MID
......@@ -4906,6 +4955,7 @@ heredoc_identifier(parser_state *p)
int c;
int type = str_heredoc;
mrb_bool indent = FALSE;
mrb_bool squiggly = FALSE;
mrb_bool quote = FALSE;
node *newnode;
parser_heredoc_info *info;
......@@ -4915,8 +4965,11 @@ heredoc_identifier(parser_state *p)
pushback(p, c);
return 0;
}
if (c == '-') {
if (c == '-' || c == '~') {
if (c == '-')
indent = TRUE;
if (c == '~')
squiggly = TRUE;
c = nextc(p);
}
if (c == '\'' || c == '"') {
......@@ -4943,6 +4996,7 @@ heredoc_identifier(parser_state *p)
if (! identchar(c)) {
pushback(p, c);
if (indent) pushback(p, '-');
if (squiggly) pushback(p, '~');
return 0;
}
newtok(p);
......@@ -4959,7 +5013,8 @@ heredoc_identifier(parser_state *p)
if (! quote)
type |= STR_FUNC_EXPAND;
info->type = (string_type)type;
info->allow_indent = indent;
info->allow_indent = indent || squiggly;
info->remove_indent = squiggly;
info->line_head = TRUE;
info->doc = NULL;
p->heredocs_from_nextline = push(p->heredocs_from_nextline, newnode);
......
......@@ -162,6 +162,26 @@ qq
QQ2
"o")
r = <<~RRR
rrr
rrr
RRR
s = <<~"SSS"
sss
sss
SSS
t = <<~'TTT'
ttt
ttt
TTT
u = [<<~UUU1 , <<~"UUU2" , <<~'UUU3' ]
u#{1}u
UUU1
u#{2}u
UUU2
u#{3}u
UUU3
w = %W( 1 #{<<WWW} 3
www
WWW
......@@ -197,6 +217,10 @@ ZZZ
assert_equal [1, "nn1\n", 3, 4], n
assert_equal "a $ q\n $ c $ d", q1
assert_equal "l $ mqq\nn $ o", q2
assert_equal "rrr\n rrr\n", r
assert_equal "sss\n sss\n", s
assert_equal "ttt\n ttt\n", t
assert_equal ["u1u\n", "u2u\n", "u\#{3}u\n"], u
assert_equal ["1", "www\n", "3", "4", "5"], w
assert_equal [1, "foo 222 333\n 444\n5\n bar\n6\n", 9], x
assert_equal "", z
......
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