diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | compile.c | 7 | ||||
-rw-r--r-- | iseq.c | 56 | ||||
-rw-r--r-- | iseq.h | 1 | ||||
-rw-r--r-- | node.c | 4 | ||||
-rw-r--r-- | node.h | 2 | ||||
-rw-r--r-- | parse.y | 38 | ||||
-rw-r--r-- | test/ruby/test_literal.rb | 13 |
9 files changed, 112 insertions, 26 deletions
@@ -1,3 +1,17 @@ +Sun Sep 27 15:43:59 2015 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * compile.c (iseq_compile_each): override compile option by option + given by pragma. + + * iseq.c (rb_iseq_make_compile_option): extract a function to + overwrite rb_compile_option_t. + + * parse.y (parser_set_compile_option_flag): introduce pragma to + override compile options. + + * parse.y (magic_comments): new pragma "fronzen-string-literal". + [Feature #8976] + Sun Sep 27 08:16:35 2015 Nobuyoshi Nakada <nobu@ruby-lang.org> * lib/ostruct.rb (delete_field): do not raise NameError for @@ -13,6 +13,9 @@ with all sufficient information, see the ChangeLog file. === Language changes +* frozen-string-literal pragma: + * new pragma, frozen-string-literal has been experimentally introduced. + === Core classes updates (outstanding ones only) * ARGF @@ -5588,8 +5588,15 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) break; } case NODE_PRELUDE:{ + const rb_compile_option_t *orig_opt = iseq->compile_data->option; + if (node->nd_orig) { + rb_compile_option_t new_opt = *orig_opt; + rb_iseq_make_compile_option(&new_opt, node->nd_orig); + iseq->compile_data->option = &new_opt; + } COMPILE_POPED(ret, "prelude", node->nd_head); COMPILE_(ret, "body", node->nd_body, poped); + iseq->compile_data->option = orig_opt; break; } case NODE_LAMBDA:{ @@ -345,6 +345,39 @@ static rb_compile_option_t COMPILE_OPTION_DEFAULT = { static const rb_compile_option_t COMPILE_OPTION_FALSE = {0}; static void +set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt) +{ +#define SET_COMPILE_OPTION(o, h, mem) \ + { VALUE flag = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \ + if (flag == Qtrue) { (o)->mem = 1; } \ + else if (flag == Qfalse) { (o)->mem = 0; } \ + } +#define SET_COMPILE_OPTION_NUM(o, h, mem) \ + { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \ + if (!NIL_P(num)) (o)->mem = NUM2INT(num); \ + } + SET_COMPILE_OPTION(option, opt, inline_const_cache); + SET_COMPILE_OPTION(option, opt, peephole_optimization); + SET_COMPILE_OPTION(option, opt, tailcall_optimization); + SET_COMPILE_OPTION(option, opt, specialized_instruction); + SET_COMPILE_OPTION(option, opt, operands_unification); + SET_COMPILE_OPTION(option, opt, instructions_unification); + SET_COMPILE_OPTION(option, opt, stack_caching); + SET_COMPILE_OPTION(option, opt, trace_instruction); + SET_COMPILE_OPTION(option, opt, frozen_string_literal); + SET_COMPILE_OPTION_NUM(option, opt, debug_level); +#undef SET_COMPILE_OPTION +#undef SET_COMPILE_OPTION_NUM +} + +void +rb_iseq_make_compile_option(rb_compile_option_t *option, VALUE opt) +{ + Check_Type(opt, T_HASH); + set_compile_option_from_hash(option, opt); +} + +static void make_compile_option(rb_compile_option_t *option, VALUE opt) { if (opt == Qnil) { @@ -360,28 +393,7 @@ make_compile_option(rb_compile_option_t *option, VALUE opt) } else if (CLASS_OF(opt) == rb_cHash) { *option = COMPILE_OPTION_DEFAULT; - -#define SET_COMPILE_OPTION(o, h, mem) \ - { VALUE flag = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \ - if (flag == Qtrue) { (o)->mem = 1; } \ - else if (flag == Qfalse) { (o)->mem = 0; } \ - } -#define SET_COMPILE_OPTION_NUM(o, h, mem) \ - { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \ - if (!NIL_P(num)) (o)->mem = NUM2INT(num); \ - } - SET_COMPILE_OPTION(option, opt, inline_const_cache); - SET_COMPILE_OPTION(option, opt, peephole_optimization); - SET_COMPILE_OPTION(option, opt, tailcall_optimization); - SET_COMPILE_OPTION(option, opt, specialized_instruction); - SET_COMPILE_OPTION(option, opt, operands_unification); - SET_COMPILE_OPTION(option, opt, instructions_unification); - SET_COMPILE_OPTION(option, opt, stack_caching); - SET_COMPILE_OPTION(option, opt, trace_instruction); - SET_COMPILE_OPTION(option, opt, frozen_string_literal); - SET_COMPILE_OPTION_NUM(option, opt, debug_level); -#undef SET_COMPILE_OPTION -#undef SET_COMPILE_OPTION_NUM + set_compile_option_from_hash(option, opt); } else { rb_raise(rb_eTypeError, "Compile option must be Hash/true/false/nil"); @@ -173,6 +173,7 @@ enum defined_type { }; VALUE rb_iseq_defined_string(enum defined_type type); +void rb_iseq_make_compile_option(struct rb_compile_option_struct *option, VALUE opt); RUBY_SYMBOL_EXPORT_END @@ -804,8 +804,10 @@ dump_node(VALUE buf, VALUE indent, int comment, NODE *node) ANN("format: BEGIN { [nd_head] }; [nd_body]"); ANN("example: bar; BEGIN { foo }"); F_NODE(nd_head, "prelude"); - LAST_NODE; F_NODE(nd_body, "body"); + LAST_NODE; +#define nd_compile_option u3.value + F_LIT(nd_compile_option, "compile_option"); break; case NODE_LAMBDA: @@ -452,7 +452,7 @@ typedef struct RNode { #define NEW_POSTEXE(b) NEW_NODE(NODE_POSTEXE,0,b,0) #define NEW_BMETHOD(b) NEW_NODE(NODE_BMETHOD,0,0,b) #define NEW_ATTRASGN(r,m,a) NEW_NODE(NODE_ATTRASGN,r,m,a) -#define NEW_PRELUDE(p,b) NEW_NODE(NODE_PRELUDE,p,b,0) +#define NEW_PRELUDE(p,b,o) NEW_NODE(NODE_PRELUDE,p,b,o) RUBY_SYMBOL_EXPORT_BEGIN @@ -288,6 +288,7 @@ struct parser_params { unsigned int past_scope_enabled: 1; # endif unsigned int has_err: 1; + unsigned int token_seen: 1; NODE *eval_tree_begin; NODE *eval_tree; @@ -295,6 +296,8 @@ struct parser_params { VALUE coverage; token_info *token_info; + + VALUE compile_option; #else /* Ripper only */ unsigned int toplevel_p: 1; @@ -5506,8 +5509,8 @@ yycompile0(VALUE arg) if (!tree) { tree = NEW_NIL(); } - else if (ruby_eval_tree_begin) { - tree->nd_body = NEW_PRELUDE(ruby_eval_tree_begin, tree->nd_body); + else { + tree->nd_body = NEW_PRELUDE(ruby_eval_tree_begin, tree->nd_body, parser->compile_option); } return (VALUE)tree; } @@ -6887,6 +6890,25 @@ parser_set_token_info(struct parser_params *parser, const char *name, const char if (b >= 0) parser->token_info_enabled = b; } +static void +parser_set_compile_option_flag(struct parser_params *parser, const char *name, const char *val) +{ + int b; + + if (parser->token_seen) { + rb_warningS("`%s' is ignored after any tokens", name); + return; + } + + b = parser_get_bool(parser, name, val); + if (b < 0) return; + + if (!parser->compile_option) + parser->compile_option = rb_ident_hash_new(); + rb_hash_aset(parser->compile_option, ID2SYM(rb_intern(name)), + (b ? Qtrue : Qfalse)); +} + # if WARN_PAST_SCOPE static void parser_set_past_scope(struct parser_params *parser, const char *name, const char *val) @@ -6907,6 +6929,7 @@ static const struct magic_comment magic_comments[] = { {"coding", magic_comment_encoding, parser_encode_length}, {"encoding", magic_comment_encoding, parser_encode_length}, #ifndef RIPPER + {"frozen_string_literal", parser_set_compile_option_flag}, {"warn_indent", parser_set_token_info}, # if WARN_PAST_SCOPE {"warn_past_scope", parser_set_past_scope}, @@ -7861,6 +7884,8 @@ parser_yylex(struct parser_params *parser) enum lex_state_e last_state; #ifdef RIPPER int fallthru = FALSE; +#else + int token_seen = parser->token_seen; #endif if (lex_strterm) { @@ -7891,6 +7916,9 @@ parser_yylex(struct parser_params *parser) } cmd_state = command_start; command_start = FALSE; +#ifndef RIPPER + parser->token_seen = TRUE; +#endif retry: last_state = lex_state; switch (c = nextc()) { @@ -7921,6 +7949,9 @@ parser_yylex(struct parser_params *parser) goto retry; case '#': /* it's a comment */ +#ifndef RIPPER + parser->token_seen = token_seen; +#endif /* no magic_comment in shebang line */ if (!parser_magic_comment(parser, lex_p, lex_pend - lex_p)) { if (comment_at_top(parser)) { @@ -7934,6 +7965,9 @@ parser_yylex(struct parser_params *parser) #endif /* fall through */ case '\n': +#ifndef RIPPER + parser->token_seen = token_seen; +#endif c = (IS_lex_state(EXPR_BEG|EXPR_CLASS|EXPR_FNAME|EXPR_DOT) && !IS_lex_state(EXPR_LABELED)); if (c || IS_lex_state_all(EXPR_ARG|EXPR_LABELED)) { diff --git a/test/ruby/test_literal.rb b/test/ruby/test_literal.rb index 302f487bb6..0d65ebac2c 100644 --- a/test/ruby/test_literal.rb +++ b/test/ruby/test_literal.rb @@ -121,6 +121,19 @@ class TestRubyLiteral < Test::Unit::TestCase assert_equal "foo\n", `echo #{s}` end + def test_frozen_string + all_assertions do |a| + a.for("false") do + str = eval("# -*- frozen-string-literal: false -*-\n""'foo'") + assert_not_predicate(str, :frozen?) + end + a.for("true") do + str = eval("# -*- frozen-string-literal: true -*-\n""'foo'") + assert_predicate(str, :frozen?) + end + end + end + def test_regexp assert_instance_of Regexp, // assert_match(//, 'a') |