mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54189 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
22198f9d3c
commit
bc343b851d
10 changed files with 103 additions and 73 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
Sat Mar 19 14:46:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* 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@ruby-lang.org>
|
||||
|
||||
* time.c (LOCALTIME): organize #ifdefs.
|
||||
|
|
67
error.c
67
error.c
|
@ -94,88 +94,53 @@ compile_snprintf(rb_encoding *enc, const char *pre, const char *file, int line,
|
|||
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
|
||||
|
|
|
@ -1074,6 +1074,8 @@ struct RBasicRaw {
|
|||
#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);
|
||||
|
|
4
iseq.c
4
iseq.c
|
@ -627,11 +627,13 @@ rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE absolute_path, VALUE li
|
|||
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);
|
||||
|
|
9
load.c
9
load.c
|
@ -583,7 +583,6 @@ rb_load_internal0(rb_thread_t *th, VALUE fname, int wrap)
|
|||
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 fname, int wrap)
|
|||
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 fname, int wrap)
|
|||
/* 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 fname, int wrap)
|
|||
th = th0;
|
||||
fname = RB_GC_GUARD(fname);
|
||||
#endif
|
||||
th->mild_compile_error = mild_compile_error;
|
||||
th->top_self = self;
|
||||
th->top_wrapper = wrapper;
|
||||
|
||||
|
|
41
parse.y
41
parse.y
|
@ -312,6 +312,7 @@ struct parser_params {
|
|||
|
||||
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;
|
|||
# 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 parser_params*, const char *fmt, ...);
|
|||
# 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)
|
|||
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 *parser)
|
|||
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)
|
|||
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)
|
|||
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 *parser, const char *fmt, ...)
|
|||
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
|
||||
|
|
8
ruby.c
8
ruby.c
|
@ -1948,6 +1948,14 @@ rb_load_file_str(VALUE fname_v)
|
|||
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
|
||||
|
|
|
@ -214,4 +214,25 @@ class TestISeq < Test::Unit::TestCase
|
|||
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
|
||||
|
|
|
@ -750,12 +750,6 @@ typedef struct rb_thread_struct {
|
|||
*/
|
||||
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;
|
||||
|
|
|
@ -1284,7 +1284,6 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, rb_cref_t *const cref_
|
|||
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 src, VALUE scope, rb_cref_t *const cref_
|
|||
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 src, VALUE scope, rb_cref_t *const cref_
|
|||
|
||||
/* 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 src, VALUE scope, rb_cref_t *const cref_
|
|||
result = vm_exec(th);
|
||||
}
|
||||
TH_POP_TAG();
|
||||
th->mild_compile_error = mild_compile_error;
|
||||
th->parse_in_eval = parse_in_eval;
|
||||
|
||||
if (state) {
|
||||
|
|
Loading…
Reference in a new issue