@@ -396,6 +396,8 @@ static NODE *new_evstr_gen(struct parser_params*,NODE*);
396
396
#define new_evstr (n ) new_evstr_gen(parser,(n))
397
397
static NODE *evstr2dstr_gen (struct parser_params *,NODE*);
398
398
#define evstr2dstr (n ) evstr2dstr_gen(parser,(n))
399
+ static NODE *str_suffix_gen (struct parser_params *, NODE*, long );
400
+ #define str_suffix (n,o ) str_suffix_gen(parser,(n),(o))
399
401
static NODE *splat_array (NODE*);
400
402
401
403
static NODE *call_bin_op_gen (struct parser_params *,NODE*,ID,NODE*);
@@ -525,6 +527,9 @@ static int lvar_defined_gen(struct parser_params*, ID);
525
527
#define RE_OPTION_MASK 0xff
526
528
#define RE_OPTION_ARG_ENCODING_NONE 32
527
529
530
+ #define STR_OPTION_FROZEN 1
531
+ #define STR_OPTION_BINARY 0 /* disabled */
532
+
528
533
#define NODE_STRTERM NODE_ZARRAY /* nothing to gc */
529
534
#define NODE_HEREDOC NODE_ARRAY /* 1, 3 to gc */
530
535
#define SIGN_EXTEND (x,n ) (((1 <<(n)-1 )^((x)&~(~0 <<(n))))-(1 <<(n)-1 ))
@@ -749,7 +754,7 @@ static void token_info_pop(struct parser_params*, const char *token);
749
754
%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
750
755
%token <node> tINTEGER tFLOAT tSTRING_CONTENT tCHAR
751
756
%token <node> tNTH_REF tBACK_REF
752
- %token <num> tREGEXP_END
757
+ %token <num> tREGEXP_END tSTRING_SUFFIX
753
758
754
759
%type <node> singleton strings string string1 xstring regexp
755
760
%type <node> string_contents xstring_contents regexp_contents string_content
@@ -775,6 +780,7 @@ static void token_info_pop(struct parser_params*, const char *token);
775
780
%type <id> fsym keyword_variable user_variable sym symbol operation operation2 operation3
776
781
%type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_bad_arg
777
782
%type <id> f_kwrest
783
+ %type <num> opt_string_sfx
778
784
/* %%%*/
779
785
/* %
780
786
%type <val> program reswords then do dot_or_colon
@@ -3811,7 +3817,7 @@ literal : numeric
3811
3817
| dsym
3812
3818
;
3813
3819
3814
- strings : string
3820
+ strings : string opt_string_sfx
3815
3821
{
3816
3822
/* %%%*/
3817
3823
NODE *node = $1;
@@ -3821,6 +3827,7 @@ strings : string
3821
3827
else {
3822
3828
node = evstr2dstr(node);
3823
3829
}
3830
+ node = str_suffix(node, $2);
3824
3831
$$ = node;
3825
3832
/* %
3826
3833
$$ = $1;
@@ -3850,6 +3857,10 @@ string1 : tSTRING_BEG string_contents tSTRING_END
3850
3857
}
3851
3858
;
3852
3859
3860
+ opt_string_sfx : tSTRING_SUFFIX
3861
+ | /* none */ {$$ = 0;}
3862
+ ;
3863
+
3853
3864
xstring : tXSTRING_BEG xstring_contents tSTRING_END
3854
3865
{
3855
3866
/* %%%*/
@@ -4992,6 +5003,7 @@ none : /* none */
4992
5003
# define yylval (*((YYSTYPE*)(parser->parser_yylval)))
4993
5004
4994
5005
static int parser_regx_options(struct parser_params*);
5006
+ static int parser_str_options(struct parser_params*);
4995
5007
static int parser_tokadd_string(struct parser_params*,int,int,int,long*,rb_encoding**);
4996
5008
static void parser_tokaddmbc(struct parser_params *parser, int c, rb_encoding *enc);
4997
5009
static int parser_parse_string(struct parser_params*,NODE*);
@@ -5007,6 +5019,7 @@ static int parser_here_document(struct parser_params*,NODE*);
5007
5019
# define read_escape(flags,e) parser_read_escape(parser, (flags), (e))
5008
5020
# define tokadd_escape(e) parser_tokadd_escape(parser, (e))
5009
5021
# define regx_options() parser_regx_options(parser)
5022
+ # define str_options() parser_str_options(parser)
5010
5023
# define tokadd_string(f,t,p,n,e) parser_tokadd_string(parser,(f),(t),(p),(n),(e))
5011
5024
# define parse_string(n) parser_parse_string(parser,(n))
5012
5025
# define tokaddmbc(c, enc) parser_tokaddmbc(parser, (c), (enc))
@@ -5501,10 +5514,11 @@ rb_parser_compile_file(volatile VALUE vparser, const char *f, VALUE file, int st
5501
5514
#define STR_FUNC_QWORDS 0x08
5502
5515
#define STR_FUNC_SYMBOL 0x10
5503
5516
#define STR_FUNC_INDENT 0x20
5517
+ #define STR_FUNC_OPTION 0x40
5504
5518
5505
5519
enum string_type {
5506
- str_squote = (0 ),
5507
- str_dquote = (STR_FUNC_EXPAND),
5520
+ str_squote = (STR_FUNC_OPTION ),
5521
+ str_dquote = (STR_FUNC_EXPAND|STR_FUNC_OPTION ),
5508
5522
str_xquote = (STR_FUNC_EXPAND),
5509
5523
str_regexp = (STR_FUNC_REGEXP|STR_FUNC_ESCAPE|STR_FUNC_EXPAND),
5510
5524
str_sword = (STR_FUNC_QWORDS),
@@ -5945,6 +5959,40 @@ parser_regx_options(struct parser_params *parser)
5945
5959
return options | RE_OPTION_ENCODING(kcode);
5946
5960
}
5947
5961
5962
+ static int
5963
+ parser_str_options(struct parser_params *parser)
5964
+ {
5965
+ int c, options = 0;
5966
+
5967
+ newtok();
5968
+ while (c = nextc(), ISALPHA(c)) {
5969
+ switch (c) {
5970
+ #if STR_OPTION_FROZEN
5971
+ case 'f':
5972
+ options |= STR_OPTION_FROZEN;
5973
+ break;
5974
+ #endif
5975
+ #if STR_OPTION_BINARY
5976
+ case 'b':
5977
+ options |= STR_OPTION_BINARY;
5978
+ break;
5979
+ #endif
5980
+ default :
5981
+ tokadd (c );
5982
+ break;
5983
+ }
5984
+ }
5985
+ pushback(c);
5986
+
5987
+ if (toklen()) {
5988
+ tokfix();
5989
+ compile_error(PARSER_ARG "unknown string option%s - %s",
5990
+ toklen() > 1 ? "s" : "", tok());
5991
+ }
5992
+
5993
+ return options;
5994
+ }
5995
+
5948
5996
static void
5949
5997
dispose_string(VALUE str)
5950
5998
{
@@ -6211,6 +6259,10 @@ parser_parse_string(struct parser_params *parser, NODE *quote)
6211
6259
rb_encoding *enc = current_enc;
6212
6260
6213
6261
if (func == -1) return tSTRING_END;
6262
+ if (func == 0) {
6263
+ set_yylval_num(term);
6264
+ return tSTRING_SUFFIX;
6265
+ }
6214
6266
c = nextc();
6215
6267
if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
6216
6268
do {c = nextc();} while (ISSPACE(c));
@@ -6219,11 +6271,18 @@ parser_parse_string(struct parser_params *parser, NODE *quote)
6219
6271
if (c == term && !quote->nd_nest) {
6220
6272
if (func & STR_FUNC_QWORDS) {
6221
6273
quote->nd_func = -1;
6274
+ quote->u2.id = 0;
6222
6275
return ' ';
6223
6276
}
6224
- if (!(func & STR_FUNC_REGEXP)) return tSTRING_END;
6225
- set_yylval_num(regx_options());
6226
- return tREGEXP_END;
6277
+ if (func & STR_FUNC_REGEXP) {
6278
+ set_yylval_num(regx_options());
6279
+ return tREGEXP_END;
6280
+ }
6281
+ if ((func & STR_FUNC_OPTION) && (func = str_options()) != 0) {
6282
+ quote->nd_func = 0;
6283
+ quote->u2.id = func;
6284
+ }
6285
+ return tSTRING_END;
6227
6286
}
6228
6287
if (space) {
6229
6288
pushback(c);
@@ -6852,7 +6911,8 @@ parser_yylex(struct parser_params *parser)
6852
6911
}
6853
6912
else {
6854
6913
token = parse_string(lex_strterm);
6855
- if (token == tSTRING_END || token == tREGEXP_END) {
6914
+ if ((token == tSTRING_END && lex_strterm->nd_func) ||
6915
+ token == tSTRING_SUFFIX || token == tREGEXP_END) {
6856
6916
rb_gc_force_recycle((VALUE)lex_strterm);
6857
6917
lex_strterm = 0;
6858
6918
lex_state = EXPR_END;
@@ -8383,6 +8443,37 @@ evstr2dstr_gen(struct parser_params *parser, NODE *node)
8383
8443
return node;
8384
8444
}
8385
8445
8446
+ static NODE *
8447
+ str_suffix_gen(struct parser_params *parser, NODE *node, long opt)
8448
+ {
8449
+ if (nd_type(node) == NODE_STR) {
8450
+ #if STR_OPTION_BINARY
8451
+ if (opt & STR_OPTION_BINARY) {
8452
+ rb_enc_associate_index(node->nd_lit, ENCINDEX_ASCII);
8453
+ }
8454
+ #endif
8455
+ #if STR_OPTION_FROZEN
8456
+ if (opt & STR_OPTION_FROZEN) {
8457
+ OBJ_FREEZE(node->nd_lit);
8458
+ nd_set_type(node, NODE_LIT);
8459
+ }
8460
+ #endif
8461
+ }
8462
+ else {
8463
+ #if STR_OPTION_BINARY
8464
+ if (opt & STR_OPTION_BINARY) {
8465
+ node = NEW_CALL(node, rb_intern("b"), 0);
8466
+ }
8467
+ #endif
8468
+ #if STR_OPTION_FROZEN
8469
+ if (opt & STR_OPTION_FROZEN) {
8470
+ node = NEW_CALL(node, rb_intern("freeze"), 0);
8471
+ }
8472
+ #endif
8473
+ }
8474
+ return node;
8475
+ }
8476
+
8386
8477
static NODE *
8387
8478
new_evstr_gen(struct parser_params *parser, NODE *node)
8388
8479
{
0 commit comments