ruby-changes:42115
From: nobu <ko1@a...>
Date: Sat, 19 Mar 2016 14:46:27 +0900 (JST)
Subject: [ruby-changes:42115] nobu:r54189 (trunk): SyntaxError message at iseq compile
nobu 2016-03-19 14:46:20 +0900 (Sat, 19 Mar 2016) New Revision: 54189 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=54189 Log: SyntaxError message at iseq compile * iseq.c (rb_iseq_compile_with_option): make the parser in mild error. * load.c (rb_load_internal0): ditto. * parse.y (yycompile0): return the error message within the error to be raised. [Feature #11951] * parse.y (parser_compile_error): accumulate error messages in the error_buffer. Modified files: trunk/ChangeLog trunk/error.c trunk/internal.h trunk/iseq.c trunk/load.c trunk/parse.y trunk/ruby.c trunk/test/ruby/test_iseq.rb trunk/vm_core.h trunk/vm_eval.c Index: vm_eval.c =================================================================== --- vm_eval.c (revision 54188) +++ vm_eval.c (revision 54189) @@ -1284,7 +1284,6 @@ eval_string_with_cref(VALUE self, VALUE https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1284 rb_env_t *env = NULL; rb_block_t block, *base_block; volatile int parse_in_eval; - volatile int mild_compile_error; volatile VALUE file; volatile int line; @@ -1292,7 +1291,6 @@ eval_string_with_cref(VALUE self, VALUE https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1291 line = lineno; parse_in_eval = th->parse_in_eval; - mild_compile_error = th->mild_compile_error; TH_PUSH_TAG(th); if ((state = TH_EXEC_TAG()) == 0) { rb_cref_t *cref = cref_arg; @@ -1343,9 +1341,7 @@ eval_string_with_cref(VALUE self, VALUE https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1341 /* make eval iseq */ th->parse_in_eval++; - th->mild_compile_error++; iseq = rb_iseq_compile_with_option(src, fname, absolute_path, INT2FIX(line), base_block, Qnil); - th->mild_compile_error--; th->parse_in_eval--; if (!cref && base_block->iseq) { @@ -1373,7 +1369,6 @@ eval_string_with_cref(VALUE self, VALUE https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1369 result = vm_exec(th); } TH_POP_TAG(); - th->mild_compile_error = mild_compile_error; th->parse_in_eval = parse_in_eval; if (state) { Index: error.c =================================================================== --- error.c (revision 54188) +++ error.c (revision 54189) @@ -94,88 +94,53 @@ compile_snprintf(rb_encoding *enc, const https://github.com/ruby/ruby/blob/trunk/error.c#L94 return str; } -static void -compile_err_append(VALUE mesg) +VALUE +rb_compile_err_append(VALUE buffer, VALUE mesg) { rb_thread_t *th = GET_THREAD(); - VALUE err = th->errinfo; rb_block_t *prev_base_block = th->base_block; th->base_block = 0; /* base_block should be zero while normal Ruby execution */ /* after this line, any Ruby code *can* run */ - if (th->mild_compile_error) { - if (RTEST(err)) { - VALUE str = rb_obj_as_string(err); - - rb_str_cat2(str, "\n"); - rb_str_append(str, mesg); - mesg = str; - } - err = rb_exc_new3(rb_eSyntaxError, mesg); - th->errinfo = err; - } - else { - if (!RTEST(err)) { - err = rb_exc_new2(rb_eSyntaxError, "compile error"); - th->errinfo = err; - } + if (!buffer) { rb_str_cat2(mesg, "\n"); rb_write_error_str(mesg); } + else if (NIL_P(buffer)) { + buffer = mesg; + } + else { + rb_str_cat2(buffer, "\n"); + rb_str_append(buffer, mesg); + } /* returned to the parser world */ th->base_block = prev_base_block; + return buffer; } void rb_compile_error_with_enc(const char *file, int line, void *enc, const char *fmt, ...) { - va_list args; - VALUE str; - - va_start(args, fmt); - str = compile_snprintf(enc, NULL, file, line, fmt, args); - va_end(args); - compile_err_append(str); } void rb_compile_error(const char *file, int line, const char *fmt, ...) { - va_list args; - VALUE str; - - va_start(args, fmt); - str = compile_snprintf(NULL, NULL, file, line, fmt, args); - va_end(args); - compile_err_append(str); } -void -rb_compile_error_str(VALUE file, int line, void *enc, const char *fmt, ...) +VALUE +rb_error_vsprintf(VALUE file, int line, void *enc, const char *fmt, va_list args) { - va_list args; - VALUE str; - - va_start(args, fmt); - str = compile_snprintf(enc, NULL, - NIL_P(file) ? NULL : RSTRING_PTR(file), line, - fmt, args); - va_end(args); - compile_err_append(str); + return compile_snprintf(enc, NULL, + NIL_P(file) ? NULL : RSTRING_PTR(file), line, + fmt, args); } void rb_compile_error_append(const char *fmt, ...) { - va_list args; - VALUE str; - - va_start(args, fmt); - str = rb_vsprintf(fmt, args); - va_end(args); - compile_err_append(str); } static void Index: ruby.c =================================================================== --- ruby.c (revision 54188) +++ ruby.c (revision 54189) @@ -1948,6 +1948,14 @@ rb_load_file_str(VALUE fname_v) https://github.com/ruby/ruby/blob/trunk/ruby.c#L1948 return load_file(rb_parser_new(), fname_v, 0, cmdline_options_init(&opt)); } +void * +rb_parser_load_file(VALUE parser, VALUE fname_v) +{ + struct cmdline_options opt; + + return load_file(parser, fname_v, 0, cmdline_options_init(&opt)); +} + /* * call-seq: * Process.argv0 -> frozen_string Index: internal.h =================================================================== --- internal.h (revision 54188) +++ internal.h (revision 54189) @@ -1074,6 +1074,8 @@ struct RBasicRaw { https://github.com/ruby/ruby/blob/trunk/internal.h#L1074 #endif VALUE rb_parser_get_yydebug(VALUE); VALUE rb_parser_set_yydebug(VALUE, VALUE); +VALUE rb_parser_mild_error(VALUE parser); +void *rb_parser_load_file(VALUE parser, VALUE name); int rb_is_const_name(VALUE name); int rb_is_class_name(VALUE name); int rb_is_global_name(VALUE name); Index: iseq.c =================================================================== --- iseq.c (revision 54188) +++ iseq.c (revision 54189) @@ -627,11 +627,13 @@ rb_iseq_compile_with_option(VALUE src, V https://github.com/ruby/ruby/blob/trunk/iseq.c#L627 const INITIALIZED VALUE label = parent ? parent->body->location.label : rb_fstring_cstr("<compiled>"); + VALUE parser = rb_parser_new(); + rb_parser_mild_error(parser); th->base_block = base_block; TH_PUSH_TAG(th); if ((state = EXEC_TAG()) == 0) { - NODE *node = (*parse)(rb_parser_new(), file, src, ln); + NODE *node = (*parse)(parser, file, src, ln); if (node) { /* TODO: check err */ iseq = rb_iseq_new_with_opt(node, label, file, absolute_path, line, parent, type, &option); Index: load.c =================================================================== --- load.c (revision 54188) +++ load.c (revision 54189) @@ -583,7 +583,6 @@ rb_load_internal0(rb_thread_t *th, VALUE https://github.com/ruby/ruby/blob/trunk/load.c#L583 int state; volatile VALUE wrapper = th->top_wrapper; volatile VALUE self = th->top_self; - volatile int mild_compile_error; #if !defined __GNUC__ rb_thread_t *volatile th0 = th; #endif @@ -600,7 +599,6 @@ rb_load_internal0(rb_thread_t *th, VALUE https://github.com/ruby/ruby/blob/trunk/load.c#L599 rb_extend_object(th->top_self, th->top_wrapper); } - mild_compile_error = th->mild_compile_error; TH_PUSH_TAG(th); state = EXEC_TAG(); if (state == 0) { @@ -611,10 +609,10 @@ rb_load_internal0(rb_thread_t *th, VALUE https://github.com/ruby/ruby/blob/trunk/load.c#L609 /* OK */ } else { - th->mild_compile_error++; - node = (NODE *)rb_load_file_str(fname); + VALUE parser = rb_parser_new(); + rb_parser_mild_error(parser); + node = (NODE *)rb_parser_load_file(parser, fname); iseq = rb_iseq_new_top(node, rb_str_new2("<top (required)>"), fname, rb_realpath_internal(Qnil, fname, 1), NULL); - th->mild_compile_error--; } rb_iseq_eval(iseq); } @@ -624,7 +622,6 @@ rb_load_internal0(rb_thread_t *th, VALUE https://github.com/ruby/ruby/blob/trunk/load.c#L622 th = th0; fname = RB_GC_GUARD(fname); #endif - th->mild_compile_error = mild_compile_error; th->top_self = self; th->top_wrapper = wrapper; Index: ChangeLog =================================================================== --- ChangeLog (revision 54188) +++ ChangeLog (revision 54189) @@ -1,3 +1,16 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sat Mar 19 14:46:18 2016 Nobuyoshi Nakada <nobu@r...> + + * iseq.c (rb_iseq_compile_with_option): make the parser in mild + error. + + * load.c (rb_load_internal0): ditto. + + * parse.y (yycompile0): return the error message within the error + to be raised. [Feature #11951] + + * parse.y (parser_compile_error): accumulate error messages in the + error_buffer. + Sat Mar 19 03:57:13 2016 NARUSE, Yui <naruse@r...> * time.c (LOCALTIME): organize #ifdefs. Index: test/ruby/test_iseq.rb =================================================================== --- test/ruby/test_iseq.rb (revision 54188) +++ test/ruby/test_iseq.rb (revision 54189) @@ -214,4 +214,25 @@ class TestISeq < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iseq.rb#L214 at_exit { assert_equal([:n, :x], Segfault.new.segfault.sort) } end; end + + def test_syntax_error_message + feature11951 = '[Feature #11951]' + + src, line = <<-'end;', __LINE__+1 + def x@;end + def y@;end + end; + e1 = e2 = nil + m1 = EnvUtil.verbose_warning do + e1 = assert_raise(SyntaxError) do + eval(src, nil, __FILE__, line) + end + end + m2 = EnvUtil.verbose_warning do + e2 = assert_raise(SyntaxError) do + ISeq.new(src, __FILE__, __FILE__, line) + end + end + assert_equal([m1, e1.message], [m2, e2.message], feature11951) + end end Index: vm_core.h =================================================================== --- vm_core.h (revision 54188) +++ vm_core.h (revision 54189) @@ -750,12 +750,6 @@ typedef struct rb_thread_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L750 */ int parse_in_eval; - /*! Thread-local state of compiling context. - * - * If non-zero, the parser does not automatically print error messages to - * stderr. */ - int mild_compile_error; - /* storage */ st_table *local_storage; VALUE local_storage_recursive_hash; Index: parse.y =================================================================== --- parse.y (revision 54188) +++ parse.y (revision 54189) @@ -312,6 +312,7 @@ struct parser_params { https://github.com/ruby/ruby/blob/trunk/parse.y#L312 NODE *eval_tree_begin; NODE *eval_tree; + VALUE error_buffer; VALUE debug_lines; VALUE coverage; #else @@ -740,7 +741,6 @@ static ID id_warn, id_warning; https://github.com/ruby/ruby/blob/trunk/parse.y#L741 # define WARNING_ARGS_L(l, fmt,n) WARNING_ARGS(fmt,n) # define WARNING_CALL rb_funcall static void ripper_compile_error(struct parser_params*, const char *fmt, ...); -# define rb_compile_error ripper_compile_error # define compile_error ripper_compile_error # define PARSER_ARG parser, #else @@ -753,9 +753,9 @@ static void ripper_compile_error(struct https://github.com/ruby/ruby/blob/trunk/parse.y#L753 # define WARNING_ARGS(fmt,n) WARN_ARGS(fmt,n) # define WARNING_ARGS_L(l,fmt,n) WARN_ARGS_L(l,fmt,n) # define WARNING_CALL rb_compile_warning -# define rb_compile_error rb_compile_error_str -# define compile_error (parser->error_p = 1),rb_compile_error_str -# define PARSER_ARG ruby_sourcefile_string, ruby_sourceline, (void *)current_enc, +static void parser_compile_error(struct parser_params*, const char *fmt, ...); +# define compile_error parser_compile_error +# define PARSER_ARG parser, #endif /* Older versions of Yacc set YYMAXDEPTH to a very low value by default (150, @@ -5559,6 +5559,9 @@ yycompile0(VALUE arg) https://github.com/ruby/ruby/blob/trunk/parse.y#L5559 lex_p = lex_pbeg = lex_pend = 0; lex_lastline = lex_nextline = 0; if (parser->error_p) { + VALUE mesg = parser->error_buffer; + if (!mesg) mesg = rb_fstring_cstr("compile error"); + rb_set_errinfo(rb_exc_new_str(rb_eSyntaxError, mesg)); return 0; } tree = ruby_eval_tree; @@ -10792,6 +10795,8 @@ parser_initialize(struct parser_params * https://github.com/ruby/ruby/blob/trunk/parse.y#L10795 parser->delayed = Qnil; parser->result = Qnil; parser->parsing_thread = Qnil; +#else + parser->error_buffer = Qfalse; #endif parser->debug_buffer = Qnil; parser->enc = rb_utf8_encoding(); @@ -10818,6 +10823,7 @@ parser_mark(void *ptr) https://github.com/ruby/ruby/blob/trunk/parse.y#L10823 rb_gc_mark((VALUE)ruby_eval_tree); rb_gc_mark(ruby_debug_lines); rb_gc_mark(parser->compile_option); + rb_gc_mark(parser->error_buffer); #else rb_gc_mark(parser->delayed); rb_gc_mark(parser->value); @@ -10901,6 +10907,16 @@ rb_parser_new(void) https://github.com/ruby/ruby/blob/trunk/parse.y#L10907 parser_initialize(p); return parser; } + +VALUE +rb_parser_mild_error(VALUE vparser) +{ + struct parser_params *parser; + + TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, parser); + parser->error_buffer = Qnil; + return vparser; +} #endif #ifdef RIPPER @@ -11069,6 +11085,23 @@ rb_parser_printf(struct parser_params *p https://github.com/ruby/ruby/blob/trunk/parse.y#L11085 parser->debug_buffer = Qnil; } } + +extern VALUE rb_error_vsprintf(VALUE, int, void *, const char *, va_list); +extern VALUE rb_compile_err_append(VALUE buffer, VALUE mesg); + +static void +parser_compile_error(struct parser_params *parser, const char *fmt, ...) +{ + VALUE str; + va_list ap; + + parser->error_p = 1; + va_start(ap, fmt); + str = rb_error_vsprintf(ruby_sourcefile_string, ruby_sourceline, + (void *)current_enc, fmt, ap); + va_end(ap); + parser->error_buffer = rb_compile_err_append(parser->error_buffer, str); +} #endif #ifdef RIPPER -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/