@@ -396,6 +396,8 @@ static NODE *new_evstr_gen(struct parser_params*,NODE*);
396396#define new_evstr (n ) new_evstr_gen(parser,(n))
397397static NODE *evstr2dstr_gen (struct parser_params *,NODE*);
398398#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))
399401static NODE *splat_array (NODE*);
400402
401403static NODE *call_bin_op_gen (struct parser_params *,NODE*,ID,NODE*);
@@ -525,6 +527,9 @@ static int lvar_defined_gen(struct parser_params*, ID);
525527#define RE_OPTION_MASK 0xff
526528#define RE_OPTION_ARG_ENCODING_NONE 32
527529
530+ #define STR_OPTION_FROZEN 1
531+ #define STR_OPTION_BINARY 0 /* disabled */
532+
528533#define NODE_STRTERM NODE_ZARRAY/* nothing to gc */
529534#define NODE_HEREDOC NODE_ARRAY /* 1, 3 to gc */
530535#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);
749754%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
750755%token <node> tINTEGER tFLOAT tSTRING_CONTENT tCHAR
751756%token <node> tNTH_REF tBACK_REF
752- %token <num> tREGEXP_END
757+ %token <num> tREGEXP_END tSTRING_SUFFIX
753758
754759%type <node> singleton strings string string1 xstring regexp
755760%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);
775780%type <id> fsym keyword_variable user_variable sym symbol operation operation2 operation3
776781%type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_bad_arg
777782%type <id> f_kwrest
783+ %type <num> opt_string_sfx
778784/* %%%*/
779785/* %
780786%type <val> program reswords then do dot_or_colon
@@ -3811,7 +3817,7 @@ literal : numeric
38113817| dsym
38123818;
38133819
3814- strings : string
3820+ strings : string opt_string_sfx
38153821 {
38163822 /* %%%*/
38173823NODE *node = $1;
@@ -3821,6 +3827,7 @@ strings : string
38213827else {
38223828 node = evstr2dstr(node);
38233829}
3830+ node = str_suffix(node, $2);
38243831$$ = node;
38253832 /* %
38263833$$ = $1;
@@ -3850,6 +3857,10 @@ string1 : tSTRING_BEG string_contents tSTRING_END
38503857 }
38513858;
38523859
3860+ opt_string_sfx : tSTRING_SUFFIX
3861+ | /* none */ {$$ = 0;}
3862+ ;
3863+
38533864xstring : tXSTRING_BEG xstring_contents tSTRING_END
38543865 {
38553866 /* %%%*/
@@ -4992,6 +5003,7 @@ none : /* none */
49925003# define yylval (*((YYSTYPE*)(parser->parser_yylval)))
49935004
49945005static int parser_regx_options(struct parser_params*);
5006+ static int parser_str_options(struct parser_params*);
49955007static int parser_tokadd_string(struct parser_params*,int,int,int,long*,rb_encoding**);
49965008static void parser_tokaddmbc(struct parser_params *parser, int c, rb_encoding *enc);
49975009static int parser_parse_string(struct parser_params*,NODE*);
@@ -5007,6 +5019,7 @@ static int parser_here_document(struct parser_params*,NODE*);
50075019# define read_escape(flags,e) parser_read_escape(parser, (flags), (e))
50085020# define tokadd_escape(e) parser_tokadd_escape(parser, (e))
50095021# define regx_options() parser_regx_options(parser)
5022+ # define str_options() parser_str_options(parser)
50105023# define tokadd_string(f,t,p,n,e) parser_tokadd_string(parser,(f),(t),(p),(n),(e))
50115024# define parse_string(n) parser_parse_string(parser,(n))
50125025# 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
55015514#define STR_FUNC_QWORDS 0x08
55025515#define STR_FUNC_SYMBOL 0x10
55035516#define STR_FUNC_INDENT 0x20
5517+ #define STR_FUNC_OPTION 0x40
55045518
55055519enum 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 ),
55085522 str_xquote = (STR_FUNC_EXPAND),
55095523 str_regexp = (STR_FUNC_REGEXP|STR_FUNC_ESCAPE|STR_FUNC_EXPAND),
55105524 str_sword = (STR_FUNC_QWORDS),
@@ -5945,6 +5959,40 @@ parser_regx_options(struct parser_params *parser)
59455959 return options | RE_OPTION_ENCODING(kcode);
59465960}
59475961
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+
59485996static void
59495997dispose_string(VALUE str)
59505998{
@@ -6211,6 +6259,10 @@ parser_parse_string(struct parser_params *parser, NODE *quote)
62116259 rb_encoding *enc = current_enc;
62126260
62136261 if (func == -1) return tSTRING_END;
6262+ if (func == 0) {
6263+ set_yylval_num(term);
6264+ return tSTRING_SUFFIX;
6265+ }
62146266 c = nextc();
62156267 if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
62166268do {c = nextc();} while (ISSPACE(c));
@@ -6219,11 +6271,18 @@ parser_parse_string(struct parser_params *parser, NODE *quote)
62196271 if (c == term && !quote->nd_nest) {
62206272if (func & STR_FUNC_QWORDS) {
62216273 quote->nd_func = -1;
6274+ quote->u2.id = 0;
62226275 return ' ';
62236276}
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;
62276286 }
62286287 if (space) {
62296288pushback(c);
@@ -6852,7 +6911,8 @@ parser_yylex(struct parser_params *parser)
68526911}
68536912else {
68546913 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) {
68566916rb_gc_force_recycle((VALUE)lex_strterm);
68576917lex_strterm = 0;
68586918lex_state = EXPR_END;
@@ -8383,6 +8443,37 @@ evstr2dstr_gen(struct parser_params *parser, NODE *node)
83838443 return node;
83848444}
83858445
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+
83868477static NODE *
83878478new_evstr_gen(struct parser_params *parser, NODE *node)
83888479{
0 commit comments