@@ -5177,6 +5177,7 @@ static int parser_tokadd_string(struct parser_params*,int,int,int,long*,rb_encod
5177
5177
static void parser_tokaddmbc (struct parser_params *parser, int c, rb_encoding *enc);
5178
5178
static int parser_parse_string (struct parser_params *,NODE*);
5179
5179
static int parser_here_document (struct parser_params *,NODE*);
5180
+ static VALUE parser_heredoc_dedent (VALUE);
5180
5181
5181
5182
5182
5183
# define nextc () parser_nextc(parser)
@@ -5699,6 +5700,7 @@ rb_parser_compile_file_path(volatile VALUE vparser, VALUE fname, VALUE file, int
5699
5700
#define STR_FUNC_QWORDS 0x08
5700
5701
#define STR_FUNC_SYMBOL 0x10
5701
5702
#define STR_FUNC_INDENT 0x20
5703
+ #define STR_FUNC_DEDENT 0x40
5702
5704
5703
5705
enum string_type {
5704
5706
str_squote = (0 ),
@@ -5725,6 +5727,10 @@ parser_str_new(const char *p, long n, rb_encoding *enc, int func, rb_encoding *e
5725
5727
}
5726
5728
}
5727
5729
5730
+ if (func & STR_FUNC_DEDENT) {
5731
+ return parser_heredoc_dedent (str);
5732
+ }
5733
+
5728
5734
return str;
5729
5735
}
5730
5736
@@ -6478,7 +6484,11 @@ parser_heredoc_identifier(struct parser_params *parser)
6478
6484
if (c == ' -' ) {
6479
6485
c = nextc ();
6480
6486
func = STR_FUNC_INDENT;
6487
+ } else if (c == ' ~' ) {
6488
+ c = nextc ();
6489
+ func = STR_FUNC_INDENT | STR_FUNC_DEDENT;
6481
6490
}
6491
+
6482
6492
switch (c) {
6483
6493
case ' \' ' :
6484
6494
func |= str_squote; goto quoted;
@@ -6502,7 +6512,9 @@ parser_heredoc_identifier(struct parser_params *parser)
6502
6512
default :
6503
6513
if (!parser_is_identchar ()) {
6504
6514
pushback (c);
6505
- if (func & STR_FUNC_INDENT) {
6515
+ if (func & STR_FUNC_DEDENT) {
6516
+ pushback (' ~' );
6517
+ } else if (func & STR_FUNC_INDENT) {
6506
6518
pushback (' -' );
6507
6519
}
6508
6520
return 0 ;
@@ -6550,6 +6562,44 @@ parser_heredoc_restore(struct parser_params *parser, NODE *here)
6550
6562
ripper_flush (parser);
6551
6563
}
6552
6564
6565
+ static VALUE
6566
+ parser_heredoc_dedent (VALUE input)
6567
+ {
6568
+ char *str = RSTRING_PTR (input), *p, *out_p;
6569
+ int len = RSTRING_LEN (input), indent = len, line_indent = 0 , lines = 0 ;
6570
+ char *end = &str[len];
6571
+ VALUE output;
6572
+
6573
+ p = str;
6574
+ while (p < end) {
6575
+ lines++;
6576
+ line_indent = 0 ;
6577
+ while (p < end && (*p == ' ' || *p == ' \t ' )) {
6578
+ line_indent++;
6579
+ p++;
6580
+ }
6581
+ if (p < end && line_indent < indent) indent = line_indent;
6582
+ if (indent == 0 ) break ;
6583
+
6584
+ while (p < end && *p != ' \r ' && *p != ' \n ' ) p++;
6585
+ if (p < end && *p == ' \r ' ) p++;
6586
+ if (p < end && *p == ' \n ' ) p++;
6587
+ }
6588
+
6589
+ output = rb_str_new (0 , len - (lines * indent));
6590
+ out_p = RSTRING_PTR (output);
6591
+
6592
+ p = str;
6593
+ while (p < end) {
6594
+ p = p + indent;
6595
+ while (p < end && *p != ' \r ' && *p != ' \n ' ) *out_p++ = *p++;
6596
+ if (p < end && *p == ' \r ' ) *out_p++ = *p++;
6597
+ if (p < end && *p == ' \n ' ) *out_p++ = *p++;
6598
+ }
6599
+
6600
+ return output;
6601
+ }
6602
+
6553
6603
static int
6554
6604
parser_whole_match_p (struct parser_params *parser,
6555
6605
const char *eos, long len, int indent)
0 commit comments