Home | History | Annotate | Line # | Download | only in indent
debug.c revision 1.64
      1  1.64  rillig /*	$NetBSD: debug.c,v 1.64 2023/06/16 11:48:32 rillig Exp $	*/
      2   1.1  rillig 
      3   1.1  rillig /*-
      4   1.1  rillig  * Copyright (c) 2023 The NetBSD Foundation, Inc.
      5   1.1  rillig  * All rights reserved.
      6   1.1  rillig  *
      7   1.1  rillig  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1  rillig  * by Roland Illig <rillig (at) NetBSD.org>.
      9   1.1  rillig  *
     10   1.1  rillig  * Redistribution and use in source and binary forms, with or without
     11   1.1  rillig  * modification, are permitted provided that the following conditions
     12   1.1  rillig  * are met:
     13   1.1  rillig  * 1. Redistributions of source code must retain the above copyright
     14   1.1  rillig  *    notice, this list of conditions and the following disclaimer.
     15   1.1  rillig  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1  rillig  *    notice, this list of conditions and the following disclaimer in the
     17   1.1  rillig  *    documentation and/or other materials provided with the distribution.
     18   1.1  rillig  *
     19   1.1  rillig  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1  rillig  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1  rillig  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1  rillig  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1  rillig  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1  rillig  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1  rillig  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1  rillig  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1  rillig  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1  rillig  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1  rillig  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1  rillig  */
     31   1.1  rillig 
     32   1.1  rillig #include <sys/cdefs.h>
     33  1.64  rillig __RCSID("$NetBSD: debug.c,v 1.64 2023/06/16 11:48:32 rillig Exp $");
     34   1.6  rillig 
     35   1.6  rillig #include <stdarg.h>
     36  1.47  rillig #include <string.h>
     37   1.1  rillig 
     38   1.1  rillig #include "indent.h"
     39   1.1  rillig 
     40   1.1  rillig #ifdef debug
     41   1.7  rillig 
     42  1.47  rillig static struct {
     43  1.58  rillig 	// false	show only the changes to the parser state
     44  1.58  rillig 	// true		show unchanged parts of the parser state as well
     45  1.47  rillig 	bool full_parser_state;
     46  1.47  rillig } config = {
     47  1.47  rillig 	.full_parser_state = false,
     48  1.47  rillig };
     49   1.7  rillig 
     50   1.1  rillig const char *const lsym_name[] = {
     51  1.13  rillig 	"eof",
     52  1.13  rillig 	"preprocessing",
     53  1.13  rillig 	"newline",
     54  1.13  rillig 	"comment",
     55  1.26  rillig 	"lparen",
     56  1.43  rillig 	"rparen",
     57  1.26  rillig 	"lbracket",
     58  1.26  rillig 	"rbracket",
     59  1.13  rillig 	"lbrace",
     60  1.13  rillig 	"rbrace",
     61  1.13  rillig 	"period",
     62  1.13  rillig 	"unary_op",
     63  1.43  rillig 	"sizeof",
     64  1.43  rillig 	"offsetof",
     65  1.43  rillig 	"postfix_op",
     66  1.13  rillig 	"binary_op",
     67  1.13  rillig 	"question",
     68  1.45  rillig 	"question_colon",
     69  1.13  rillig 	"comma",
     70  1.13  rillig 	"typedef",
     71  1.29  rillig 	"modifier",
     72  1.43  rillig 	"tag",
     73  1.13  rillig 	"type_outside_parentheses",
     74  1.13  rillig 	"type_in_parentheses",
     75  1.43  rillig 	"word",
     76  1.43  rillig 	"funcname",
     77  1.45  rillig 	"label_colon",
     78  1.45  rillig 	"other_colon",
     79  1.43  rillig 	"semicolon",
     80  1.30  rillig 	"case",
     81  1.30  rillig 	"default",
     82  1.13  rillig 	"do",
     83  1.13  rillig 	"else",
     84  1.13  rillig 	"for",
     85  1.13  rillig 	"if",
     86  1.13  rillig 	"switch",
     87  1.13  rillig 	"while",
     88  1.13  rillig 	"return",
     89   1.1  rillig };
     90   1.1  rillig 
     91   1.1  rillig const char *const psym_name[] = {
     92  1.33  rillig 	"-",
     93  1.36  rillig 	"{block",
     94  1.36  rillig 	"{struct",
     95  1.36  rillig 	"{union",
     96  1.36  rillig 	"{enum",
     97  1.36  rillig 	"}",
     98  1.13  rillig 	"decl",
     99  1.13  rillig 	"stmt",
    100  1.13  rillig 	"for_exprs",
    101  1.13  rillig 	"if_expr",
    102  1.13  rillig 	"if_expr_stmt",
    103  1.13  rillig 	"if_expr_stmt_else",
    104  1.13  rillig 	"else",
    105  1.13  rillig 	"switch_expr",
    106  1.13  rillig 	"do",
    107  1.13  rillig 	"do_stmt",
    108  1.13  rillig 	"while_expr",
    109   1.1  rillig };
    110   1.1  rillig 
    111   1.9  rillig static const char *const declaration_name[] = {
    112  1.13  rillig 	"no",
    113  1.13  rillig 	"begin",
    114  1.13  rillig 	"end",
    115   1.3  rillig };
    116   1.3  rillig 
    117   1.9  rillig const char *const paren_level_cast_name[] = {
    118  1.13  rillig 	"(unknown cast)",
    119  1.13  rillig 	"(maybe cast)",
    120  1.13  rillig 	"(no cast)",
    121   1.9  rillig };
    122   1.9  rillig 
    123  1.19  rillig const char *const line_kind_name[] = {
    124  1.16  rillig 	"other",
    125  1.20  rillig 	"blank",
    126  1.16  rillig 	"#if",
    127  1.16  rillig 	"#endif",
    128  1.64  rillig 	"#other",
    129  1.20  rillig 	"stmt head",
    130  1.17  rillig 	"}",
    131  1.18  rillig 	"block comment",
    132  1.27  rillig 	"case/default",
    133  1.16  rillig };
    134  1.16  rillig 
    135  1.35  rillig static const char *const extra_expr_indent_name[] = {
    136  1.35  rillig 	"no",
    137  1.41  rillig 	"maybe",
    138  1.35  rillig 	"last",
    139  1.35  rillig };
    140  1.35  rillig 
    141  1.47  rillig static struct {
    142  1.47  rillig 	struct parser_state prev_ps;
    143  1.47  rillig 	bool ps_first;
    144  1.47  rillig 	const char *heading;
    145  1.48  rillig 	unsigned wrote_newlines;
    146  1.47  rillig } state = {
    147  1.47  rillig 	.ps_first = true,
    148  1.47  rillig 	.wrote_newlines = 1,
    149  1.47  rillig };
    150  1.37  rillig 
    151   1.6  rillig void
    152   1.6  rillig debug_printf(const char *fmt, ...)
    153   1.6  rillig {
    154  1.13  rillig 	FILE *f = output == stdout ? stderr : stdout;
    155  1.13  rillig 	va_list ap;
    156   1.6  rillig 
    157  1.47  rillig 	if (state.heading != NULL) {
    158  1.47  rillig 		fprintf(f, "%s\n", state.heading);
    159  1.47  rillig 		state.heading = NULL;
    160  1.47  rillig 	}
    161  1.13  rillig 	va_start(ap, fmt);
    162  1.13  rillig 	vfprintf(f, fmt, ap);
    163  1.13  rillig 	va_end(ap);
    164  1.47  rillig 	state.wrote_newlines = 0;
    165   1.6  rillig }
    166   1.6  rillig 
    167   1.6  rillig void
    168   1.6  rillig debug_println(const char *fmt, ...)
    169   1.6  rillig {
    170  1.13  rillig 	FILE *f = output == stdout ? stderr : stdout;
    171  1.13  rillig 	va_list ap;
    172   1.6  rillig 
    173  1.47  rillig 	if (state.heading != NULL) {
    174  1.47  rillig 		fprintf(f, "%s\n", state.heading);
    175  1.47  rillig 		state.heading = NULL;
    176  1.47  rillig 		state.wrote_newlines = 1;
    177  1.47  rillig 	}
    178  1.13  rillig 	va_start(ap, fmt);
    179  1.13  rillig 	vfprintf(f, fmt, ap);
    180  1.13  rillig 	va_end(ap);
    181  1.13  rillig 	fprintf(f, "\n");
    182  1.47  rillig 	state.wrote_newlines = fmt[0] == '\0' ? state.wrote_newlines + 1 : 1;
    183  1.22  rillig }
    184  1.22  rillig 
    185  1.22  rillig void
    186  1.22  rillig debug_blank_line(void)
    187  1.22  rillig {
    188  1.47  rillig 	while (state.wrote_newlines < 2)
    189  1.22  rillig 		debug_println("");
    190   1.6  rillig }
    191   1.6  rillig 
    192   1.6  rillig void
    193  1.58  rillig debug_vis_range(const char *s, size_t len)
    194   1.6  rillig {
    195  1.58  rillig 	debug_printf("\"");
    196  1.13  rillig 	for (size_t i = 0; i < len; i++) {
    197  1.13  rillig 		const char *p = s + i;
    198  1.13  rillig 		if (*p == '\\' || *p == '"')
    199  1.13  rillig 			debug_printf("\\%c", *p);
    200  1.13  rillig 		else if (isprint((unsigned char)*p))
    201  1.13  rillig 			debug_printf("%c", *p);
    202  1.13  rillig 		else if (*p == '\n')
    203  1.13  rillig 			debug_printf("\\n");
    204  1.13  rillig 		else if (*p == '\t')
    205  1.13  rillig 			debug_printf("\\t");
    206  1.13  rillig 		else
    207  1.13  rillig 			debug_printf("\\x%02x", (unsigned char)*p);
    208  1.13  rillig 	}
    209  1.58  rillig 	debug_printf("\"");
    210   1.6  rillig }
    211   1.6  rillig 
    212  1.25  rillig void
    213   1.1  rillig debug_print_buf(const char *name, const struct buffer *buf)
    214   1.1  rillig {
    215  1.13  rillig 	if (buf->len > 0) {
    216  1.22  rillig 		debug_printf(" %s ", name);
    217  1.58  rillig 		debug_vis_range(buf->s, buf->len);
    218  1.13  rillig 	}
    219   1.1  rillig }
    220   1.1  rillig 
    221   1.1  rillig void
    222   1.1  rillig debug_buffers(void)
    223   1.1  rillig {
    224  1.22  rillig 	debug_print_buf("label", &lab);
    225  1.22  rillig 	debug_print_buf("code", &code);
    226  1.22  rillig 	debug_print_buf("comment", &com);
    227  1.48  rillig 	debug_blank_line();
    228   1.1  rillig }
    229   1.1  rillig 
    230  1.47  rillig static void
    231  1.58  rillig debug_ps_bool_member(const char *name, bool prev, bool curr)
    232  1.47  rillig {
    233  1.52  rillig 	if (!state.ps_first && curr != prev) {
    234  1.47  rillig 		char diff = " -+x"[(prev ? 1 : 0) + (curr ? 2 : 0)];
    235  1.47  rillig 		debug_println("        [%c]  ps.%s", diff, name);
    236  1.47  rillig 	} else if (config.full_parser_state || state.ps_first)
    237  1.47  rillig 		debug_println("        [%c]  ps.%s", curr ? 'x' : ' ', name);
    238  1.47  rillig }
    239  1.47  rillig 
    240  1.47  rillig static void
    241  1.58  rillig debug_ps_int_member(const char *name, int prev, int curr)
    242  1.47  rillig {
    243  1.52  rillig 	if (!state.ps_first && curr != prev)
    244  1.47  rillig 		debug_println(" %3d -> %3d  ps.%s", prev, curr, name);
    245  1.47  rillig 	else if (config.full_parser_state || state.ps_first)
    246  1.47  rillig 		debug_println("        %3d  ps.%s", curr, name);
    247  1.47  rillig }
    248  1.47  rillig 
    249  1.47  rillig static void
    250  1.58  rillig debug_ps_enum_member(const char *name, const char *prev, const char *curr)
    251  1.47  rillig {
    252  1.52  rillig 	if (!state.ps_first && strcmp(prev, curr) != 0)
    253  1.47  rillig 		debug_println(" %3s -> %3s  ps.%s", prev, curr, name);
    254  1.47  rillig 	else if (config.full_parser_state || state.ps_first)
    255  1.47  rillig 		debug_println(" %10s  ps.%s", curr, name);
    256  1.47  rillig }
    257   1.1  rillig 
    258   1.1  rillig static bool
    259  1.59  rillig paren_stack_equal(const struct paren_stack *a, const struct paren_stack *b)
    260   1.1  rillig {
    261  1.59  rillig 	if (a->len != b->len)
    262  1.59  rillig 		return false;
    263   1.1  rillig 
    264  1.59  rillig 	for (size_t i = 0, n = a->len; i < n; i++)
    265  1.59  rillig 		if (a->item[i].indent != b->item[i].indent
    266  1.59  rillig 		    || a->item[i].cast != b->item[i].cast)
    267  1.13  rillig 			return true;
    268  1.13  rillig 	return false;
    269   1.1  rillig }
    270   1.1  rillig 
    271   1.1  rillig static void
    272  1.47  rillig debug_ps_paren(void)
    273   1.1  rillig {
    274  1.59  rillig 	if (!config.full_parser_state
    275  1.59  rillig 	    && paren_stack_equal(&state.prev_ps.paren, &ps.paren)
    276  1.47  rillig 	    && !state.ps_first)
    277  1.13  rillig 		return;
    278   1.1  rillig 
    279  1.36  rillig 	debug_printf("             ps.paren:");
    280  1.59  rillig 	for (size_t i = 0; i < ps.paren.len; i++) {
    281  1.13  rillig 		debug_printf(" %s%d",
    282  1.59  rillig 		    paren_level_cast_name[ps.paren.item[i].cast],
    283  1.59  rillig 		    ps.paren.item[i].indent);
    284  1.13  rillig 	}
    285  1.59  rillig 	if (ps.paren.len == 0)
    286  1.13  rillig 		debug_printf(" none");
    287  1.49  rillig 	debug_println("");
    288   1.1  rillig }
    289   1.1  rillig 
    290  1.15  rillig static bool
    291  1.47  rillig ps_di_stack_has_changed(void)
    292  1.15  rillig {
    293  1.47  rillig 	if (state.prev_ps.decl_level != ps.decl_level)
    294  1.15  rillig 		return true;
    295  1.15  rillig 	for (int i = 0; i < ps.decl_level; i++)
    296  1.47  rillig 		if (state.prev_ps.di_stack[i] != ps.di_stack[i])
    297  1.15  rillig 			return true;
    298  1.15  rillig 	return false;
    299  1.15  rillig }
    300  1.15  rillig 
    301  1.15  rillig static void
    302  1.47  rillig debug_ps_di_stack(void)
    303  1.15  rillig {
    304  1.47  rillig 	bool changed = ps_di_stack_has_changed();
    305  1.47  rillig 	if (!config.full_parser_state && !changed && !state.ps_first)
    306  1.15  rillig 		return;
    307  1.15  rillig 
    308  1.36  rillig 	debug_printf("     %s      ps.di_stack:", changed ? "->" : "  ");
    309  1.15  rillig 	for (int i = 0; i < ps.decl_level; i++)
    310  1.15  rillig 		debug_printf(" %d", ps.di_stack[i]);
    311  1.15  rillig 	if (ps.decl_level == 0)
    312  1.15  rillig 		debug_printf(" none");
    313  1.49  rillig 	debug_println("");
    314  1.15  rillig }
    315  1.15  rillig 
    316  1.47  rillig #define debug_ps_bool(name) \
    317  1.58  rillig 	debug_ps_bool_member(#name, state.prev_ps.name, ps.name)
    318  1.47  rillig #define debug_ps_int(name) \
    319  1.58  rillig 	debug_ps_int_member(#name, state.prev_ps.name, ps.name)
    320  1.47  rillig #define debug_ps_enum(name, names) \
    321  1.58  rillig         debug_ps_enum_member(#name, (names)[state.prev_ps.name], \
    322  1.58  rillig 	    (names)[ps.name])
    323  1.47  rillig 
    324   1.1  rillig void
    325  1.22  rillig debug_parser_state(void)
    326   1.1  rillig {
    327  1.22  rillig 	debug_blank_line();
    328  1.35  rillig 
    329  1.47  rillig 	state.heading = "token classification";
    330  1.52  rillig 	debug_ps_enum(prev_lsym, lsym_name);
    331  1.35  rillig 	debug_ps_bool(in_stmt_or_decl);
    332  1.35  rillig 	debug_ps_bool(in_decl);
    333  1.44  rillig 	debug_ps_bool(in_var_decl);
    334  1.44  rillig 	debug_ps_bool(in_init);
    335  1.44  rillig 	debug_ps_int(init_level);
    336  1.46  rillig 	debug_ps_bool(line_has_func_def);
    337  1.35  rillig 	debug_ps_bool(in_func_def_params);
    338  1.44  rillig 	debug_ps_bool(line_has_decl);
    339  1.44  rillig 	debug_ps_enum(lbrace_kind, psym_name);
    340  1.44  rillig 	debug_ps_enum(spaced_expr_psym, psym_name);
    341  1.35  rillig 	debug_ps_bool(seen_case);
    342  1.42  rillig 	debug_ps_bool(prev_paren_was_cast);
    343  1.44  rillig 	debug_ps_int(quest_level);
    344  1.13  rillig 
    345  1.47  rillig 	state.heading = "indentation of statements and declarations";
    346  1.13  rillig 	debug_ps_int(ind_level);
    347  1.13  rillig 	debug_ps_int(ind_level_follow);
    348  1.62  rillig 	debug_ps_bool(line_is_stmt_cont);
    349  1.13  rillig 	debug_ps_int(decl_level);
    350  1.47  rillig 	debug_ps_di_stack();
    351  1.13  rillig 	debug_ps_bool(decl_indent_done);
    352  1.13  rillig 	debug_ps_int(decl_ind);
    353  1.13  rillig 	debug_ps_bool(tabs_to_var);
    354  1.35  rillig 	debug_ps_enum(extra_expr_indent, extra_expr_indent_name);
    355  1.13  rillig 
    356  1.50  rillig 	// The parser symbol stack is printed in debug_psyms_stack instead.
    357  1.35  rillig 
    358  1.47  rillig 	state.heading = "spacing inside a statement or declaration";
    359  1.35  rillig 	debug_ps_bool(next_unary);
    360  1.35  rillig 	debug_ps_bool(want_blank);
    361  1.53  rillig 	debug_ps_int(ind_paren_level);
    362  1.47  rillig 	debug_ps_paren();
    363  1.35  rillig 
    364  1.57  rillig 	state.heading = "indentation of comments";
    365  1.57  rillig 	debug_ps_int(comment_ind);
    366  1.57  rillig 	debug_ps_int(comment_shift);
    367  1.63  rillig 	debug_ps_bool(comment_cont);
    368  1.35  rillig 
    369  1.47  rillig 	state.heading = "vertical spacing";
    370  1.35  rillig 	debug_ps_bool(break_after_comma);
    371  1.61  rillig 	debug_ps_bool(want_newline);
    372  1.35  rillig 	debug_ps_enum(declaration, declaration_name);
    373  1.35  rillig 	debug_ps_bool(blank_line_after_decl);
    374   1.1  rillig 
    375  1.47  rillig 	state.heading = NULL;
    376  1.22  rillig 	debug_blank_line();
    377   1.1  rillig 
    378  1.47  rillig 	state.prev_ps = ps;
    379  1.47  rillig 	state.ps_first = false;
    380   1.1  rillig }
    381   1.1  rillig 
    382   1.1  rillig void
    383  1.50  rillig debug_psyms_stack(const char *situation)
    384   1.1  rillig {
    385  1.38  rillig 	debug_printf("parse stack %s:", situation);
    386  1.39  rillig 	const struct psym_stack *psyms = &ps.psyms;
    387  1.60  rillig 	for (size_t i = 0; i < psyms->len; ++i)
    388  1.39  rillig 		debug_printf(" %d %s",
    389  1.39  rillig 		    psyms->ind_level[i], psym_name[psyms->sym[i]]);
    390  1.51  rillig 	debug_println("");
    391   1.1  rillig }
    392   1.1  rillig #endif
    393