Add support for squiggly heredocs
MODIFY
AUTHORS
AUTHORS
@@ -45,3 +45,4 @@ of this list.
RIZAL Reckordp
Rory O'Connell
John Bampton
+ Seeker

MODIFY
include/mruby/compile.h
include/mruby/compile.h
@@ -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;

MODIFY
mrbgems/mruby-compiler/core/parse.y
mrbgems/mruby-compiler/core/parse.y
@@ -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);

MODIFY
test/t/literals.rb
test/t/literals.rb
@@ -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

Add support for squiggly heredocs