aboutsummaryrefslogtreecommitdiffstats
path: root/parse.y
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-04-24 06:17:54 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-04-24 06:17:54 +0000
commit978b1f6ecca934687a9be242655c621241ea7d9c (patch)
tree4a9a53f4a9107da433f7713e39014e57b98debea /parse.y
parentad02b1da3a68f8667207ea740c57026534a04ce0 (diff)
downloadruby-978b1f6ecca934687a9be242655c621241ea7d9c.tar.gz
parse.y: rb_parser_fatal
* parse.y (rb_parser_fatal): abort compilation on internal parser error. rb_bug() is generic use but not useful for debugging the parser. this function dumps internal states, and continues with enabling yydebug output to stderr for the parser stack dump. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58465 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'parse.y')
-rw-r--r--parse.y248
1 files changed, 158 insertions, 90 deletions
diff --git a/parse.y b/parse.y
index 8c7cb50e75..11cab865a2 100644
--- a/parse.y
+++ b/parse.y
@@ -152,82 +152,6 @@ struct local_vars {
#define DVARS_SPECIAL_P(tbl) (!POINTER_P(tbl))
#define POINTER_P(val) ((VALUE)(val) & ~(VALUE)3)
-static int
-vtable_size(const struct vtable *tbl)
-{
- if (POINTER_P(tbl)) {
- return tbl->pos;
- }
- else {
- return 0;
- }
-}
-
-#define VTBL_DEBUG 0
-
-static struct vtable *
-vtable_alloc(struct vtable *prev)
-{
- struct vtable *tbl = ALLOC(struct vtable);
- tbl->pos = 0;
- tbl->capa = 8;
- tbl->tbl = ALLOC_N(ID, tbl->capa);
- tbl->prev = prev;
- if (VTBL_DEBUG) printf("vtable_alloc: %p\n", (void *)tbl);
- return tbl;
-}
-
-static void
-vtable_free(struct vtable *tbl)
-{
- if (VTBL_DEBUG)printf("vtable_free: %p\n", (void *)tbl);
- if (POINTER_P(tbl)) {
- if (tbl->tbl) {
- xfree(tbl->tbl);
- }
- xfree(tbl);
- }
-}
-
-static void
-vtable_add(struct vtable *tbl, ID id)
-{
- if (!POINTER_P(tbl)) {
- rb_bug("vtable_add: vtable is not allocated (%p)", (void *)tbl);
- }
- if (VTBL_DEBUG) printf("vtable_add: %p, %"PRIsVALUE"\n", (void *)tbl, rb_id2str(id));
-
- if (tbl->pos == tbl->capa) {
- tbl->capa = tbl->capa * 2;
- REALLOC_N(tbl->tbl, ID, tbl->capa);
- }
- tbl->tbl[tbl->pos++] = id;
-}
-
-#ifndef RIPPER
-static void
-vtable_pop(struct vtable *tbl, int n)
-{
- if (tbl->pos < n) rb_bug("vtable_pop: unreachable");
- tbl->pos -= n;
-}
-#endif
-
-static int
-vtable_included(const struct vtable * tbl, ID id)
-{
- int i;
-
- if (POINTER_P(tbl)) {
- for (i = 0; i < tbl->pos; i++) {
- if (tbl->tbl[i] == id) {
- return i+1;
- }
- }
- }
- return 0;
-}
-
typedef struct token_info {
const char *token;
int linenum;
@@ -284,6 +208,7 @@ struct parser_params {
VALUE compile_option;
VALUE debug_buffer;
+ VALUE debug_output;
ID cur_arg;
@@ -472,7 +397,8 @@ static NODE *new_args_tail_gen(struct parser_params*,NODE*,ID,ID);
#define new_args_tail(k,kr,b) new_args_tail_gen(parser, (k),(kr),(b))
#define new_kw_arg(k) ((k) ? NEW_KW_ARG(0, (k)) : 0)
-static VALUE negate_lit(VALUE);
+static VALUE negate_lit_gen(struct parser_params*, VALUE);
+#define negate_lit(lit) negate_lit_gen(parser, lit)
static NODE *ret_args_gen(struct parser_params*,NODE*);
#define ret_args(node) ret_args_gen(parser, (node))
static NODE *arg_blk_pass(NODE*,NODE*);
@@ -861,6 +787,7 @@ PRINTF_ARGS(static void parser_compile_error(struct parser_params*, const char *
# define compile_error parser_compile_error
# define PARSER_ARG parser,
#endif
+PRINTF_ARGS(void rb_parser_fatal(struct parser_params *parser, const char *fmt, ...), 2, 3);
/* Older versions of Yacc set YYMAXDEPTH to a very low value by default (150,
for instance). This is too low for Ruby to parse some files, such as
@@ -5144,6 +5071,107 @@ parser_yyerror(struct parser_params *parser, const char *msg)
return 0;
}
+static int
+vtable_size(const struct vtable *tbl)
+{
+ if (POINTER_P(tbl)) {
+ return tbl->pos;
+ }
+ else {
+ return 0;
+ }
+}
+
+static struct vtable *
+vtable_alloc_gen(struct parser_params *parser, int line, struct vtable *prev)
+{
+ struct vtable *tbl = ALLOC(struct vtable);
+ tbl->pos = 0;
+ tbl->capa = 8;
+ tbl->tbl = ALLOC_N(ID, tbl->capa);
+ tbl->prev = prev;
+#ifndef RIPPER
+ if (yydebug) {
+ rb_parser_printf(parser, "vtable_alloc:%d: %p\n", line, tbl);
+ }
+#endif
+ return tbl;
+}
+#define vtable_alloc(prev) vtable_alloc_gen(parser, __LINE__, prev)
+
+static void
+vtable_free_gen(struct parser_params *parser, int line, const char *name,
+ struct vtable *tbl)
+{
+#ifndef RIPPER
+ if (yydebug) {
+ rb_parser_printf(parser, "vtable_free:%d: %s(%p)\n", line, name, tbl);
+ }
+#endif
+ if (POINTER_P(tbl)) {
+ if (tbl->tbl) {
+ xfree(tbl->tbl);
+ }
+ xfree(tbl);
+ }
+}
+#define vtable_free(tbl) vtable_free_gen(parser, __LINE__, #tbl, tbl)
+
+static void
+vtable_add_gen(struct parser_params *parser, int line, const char *name,
+ struct vtable *tbl, ID id)
+{
+#ifndef RIPPER
+ if (yydebug) {
+ rb_parser_printf(parser, "vtable_add:%d: %s(%p), %s\n",
+ line, name, tbl, rb_id2name(id));
+ }
+#endif
+ if (!POINTER_P(tbl)) {
+ rb_parser_fatal(parser, "vtable_add: vtable is not allocated (%p)", (void *)tbl);
+ return;
+ }
+ if (tbl->pos == tbl->capa) {
+ tbl->capa = tbl->capa * 2;
+ REALLOC_N(tbl->tbl, ID, tbl->capa);
+ }
+ tbl->tbl[tbl->pos++] = id;
+}
+#define vtable_add(tbl, id) vtable_add_gen(parser, __LINE__, #tbl, tbl, id)
+
+#ifndef RIPPER
+static void
+vtable_pop_gen(struct parser_params *parser, int line, const char *name,
+ struct vtable *tbl, int n)
+{
+ if (yydebug) {
+ rb_parser_printf(parser, "vtable_pop:%d: %s(%p), %d\n",
+ line, name, tbl, n);
+ }
+ if (tbl->pos < n) {
+ rb_parser_fatal(parser, "vtable_pop: unreachable (%d < %d)", tbl->pos, n);
+ return;
+ }
+ tbl->pos -= n;
+}
+#define vtable_pop(tbl, n) vtable_pop_gen(parser, __LINE__, #tbl, tbl, n)
+#endif
+
+static int
+vtable_included(const struct vtable * tbl, ID id)
+{
+ int i;
+
+ if (POINTER_P(tbl)) {
+ for (i = 0; i < tbl->pos; i++) {
+ if (tbl->tbl[i] == id) {
+ return i+1;
+ }
+ }
+ }
+ return 0;
+}
+
static void parser_prepare(struct parser_params *parser);
#ifndef RIPPER
@@ -9061,7 +9089,7 @@ append_lex_state_name(enum lex_state_e state, VALUE buf)
}
static void
-flush_debug_buffer(struct parser_params *parser, VALUE out)
+flush_debug_buffer(struct parser_params *parser, VALUE out, VALUE str)
{
VALUE mesg = parser->debug_buffer;
@@ -9069,6 +9097,9 @@ flush_debug_buffer(struct parser_params *parser, VALUE out)
parser->debug_buffer = Qnil;
rb_io_puts(1, &mesg, out);
}
+ if (!NIL_P(str) && RSTRING_LEN(str)) {
+ rb_io_write(parser->debug_output, str);
+ }
}
enum lex_state_e
@@ -9081,16 +9112,13 @@ rb_parser_trace_lex_state(struct parser_params *parser, enum lex_state_e from,
rb_str_cat_cstr(mesg, " -> ");
append_lex_state_name(to, mesg);
rb_str_catf(mesg, " at line %d\n", line);
- flush_debug_buffer(parser, rb_stdout);
- rb_io_write(rb_stdout, mesg);
+ flush_debug_buffer(parser, parser->debug_output, mesg);
return to;
}
-void
-rb_parser_show_bitstack(struct parser_params *parser, stack_type stack,
- const char *name, int line)
+static void
+append_bitstack_value(stack_type stack, VALUE mesg)
{
- VALUE mesg = rb_sprintf("%s: ", name);
if (stack == 0) {
rb_str_cat_cstr(mesg, "0");
}
@@ -9099,9 +9127,47 @@ rb_parser_show_bitstack(struct parser_params *parser, stack_type stack,
for (; mask && !(stack & mask); mask >>= 1) continue;
for (; mask; mask >>= 1) rb_str_cat(mesg, stack & mask ? "1" : "0", 1);
}
+}
+
+void
+rb_parser_show_bitstack(struct parser_params *parser, stack_type stack,
+ const char *name, int line)
+{
+ VALUE mesg = rb_sprintf("%s: ", name);
+ append_bitstack_value(stack, mesg);
rb_str_catf(mesg, " at line %d\n", line);
- flush_debug_buffer(parser, rb_stdout);
- rb_io_write(rb_stdout, mesg);
+ flush_debug_buffer(parser, parser->debug_output, mesg);
+}
+
+void
+rb_parser_fatal(struct parser_params *parser, const char *fmt, ...)
+{
+ va_list ap;
+ VALUE mesg = rb_str_new_cstr("internal parser error: ");
+
+ va_start(ap, fmt);
+ rb_str_vcatf(mesg, fmt, ap);
+ va_end(ap);
+#ifndef RIPPER
+ parser_yyerror(parser, RSTRING_PTR(mesg));
+ RB_GC_GUARD(mesg);
+#else
+ dispatch1(parse_error, mesg);
+ ripper_error();
+#endif /* !RIPPER */
+
+ mesg = rb_str_new(0, 0);
+ append_lex_state_name(lex_state, mesg);
+ compile_error(PARSER_ARG "lex_state: %"PRIsVALUE, mesg);
+ rb_str_resize(mesg, 0);
+ append_bitstack_value(cond_stack, mesg);
+ compile_error(PARSER_ARG "cond_stack: %"PRIsVALUE, mesg);
+ rb_str_resize(mesg, 0);
+ append_bitstack_value(cmdarg_stack, mesg);
+ compile_error(PARSER_ARG "cmdarg_stack: %"PRIsVALUE, mesg);
+ if (parser->debug_output == rb_stdout)
+ parser->debug_output = rb_stderr;
+ yydebug = TRUE;
}
#endif /* !RIPPER */
@@ -9823,7 +9889,7 @@ new_yield_gen(struct parser_params *parser, NODE *node)
}
static VALUE
-negate_lit(VALUE lit)
+negate_lit_gen(struct parser_params *parser, VALUE lit)
{
int type = TYPE(lit);
switch (type) {
@@ -9851,7 +9917,7 @@ negate_lit(VALUE lit)
RFLOAT(lit)->float_value = -RFLOAT_VALUE(lit);
break;
default:
- rb_bug("unknown literal type (%d) passed to negate_lit", type);
+ rb_parser_fatal(parser, "unknown literal type (%d) passed to negate_lit", type);
break;
}
return lit;
@@ -10169,7 +10235,7 @@ warn_unused_var(struct parser_params *parser, struct local_vars *local)
u = local->used->tbl;
cnt = local->used->pos;
if (cnt != local->vars->pos) {
- rb_bug("local->used->pos != local->vars->pos");
+ rb_parser_fatal(parser, "local->used->pos != local->vars->pos");
}
for (i = 0; i < cnt; ++i) {
if (!v[i] || (u[i] & LVAR_USED)) continue;
@@ -10651,6 +10717,7 @@ parser_initialize(struct parser_params *parser)
parser->error_buffer = Qfalse;
#endif
parser->debug_buffer = Qnil;
+ parser->debug_output = rb_stdout;
parser->enc = rb_utf8_encoding();
}
@@ -10682,6 +10749,7 @@ parser_mark(void *ptr)
rb_gc_mark(parser->parsing_thread);
#endif
rb_gc_mark(parser->debug_buffer);
+ rb_gc_mark(parser->debug_output);
#ifdef YYMALLOC
rb_gc_mark((VALUE)parser->heap);
#endif
@@ -10934,7 +11002,7 @@ rb_parser_printf(struct parser_params *parser, const char *fmt, ...)
rb_str_vcatf(mesg, fmt, ap);
va_end(ap);
if (RSTRING_END(mesg)[-1] == '\n') {
- rb_io_write(rb_stdout, mesg);
+ rb_io_write(parser->debug_output, mesg);
parser->debug_buffer = Qnil;
}
}