grep: teach --debug option to dump the parse tree
Our "grep" allows complex boolean expressions to be formed to match each individual line with operators like --and, '(', ')' and --not. Introduce the "--debug" option to show the parse tree to help people who want to debug and enhance it. Also "log" learns "--grep-debug" option to do the same. The command line parser to the log family is a lot more limited than the general "git grep" parser, but it has special handling for header matching (e.g. "--author"), and a parse tree is valuable when working on it. Note that "--all-match" is *not* any individual node in the parse tree. It is an instruction to the evaluator to check all the nodes in the top-level backbone have matched and reject a document as non-matching otherwise. Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
92
grep.c
92
grep.c
@ -332,6 +332,87 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
|
||||
return compile_pattern_or(list);
|
||||
}
|
||||
|
||||
static void indent(int in)
|
||||
{
|
||||
while (in-- > 0)
|
||||
fputc(' ', stderr);
|
||||
}
|
||||
|
||||
static void dump_grep_pat(struct grep_pat *p)
|
||||
{
|
||||
switch (p->token) {
|
||||
case GREP_AND: fprintf(stderr, "*and*"); break;
|
||||
case GREP_OPEN_PAREN: fprintf(stderr, "*(*"); break;
|
||||
case GREP_CLOSE_PAREN: fprintf(stderr, "*)*"); break;
|
||||
case GREP_NOT: fprintf(stderr, "*not*"); break;
|
||||
case GREP_OR: fprintf(stderr, "*or*"); break;
|
||||
|
||||
case GREP_PATTERN: fprintf(stderr, "pattern"); break;
|
||||
case GREP_PATTERN_HEAD: fprintf(stderr, "pattern_head"); break;
|
||||
case GREP_PATTERN_BODY: fprintf(stderr, "pattern_body"); break;
|
||||
}
|
||||
|
||||
switch (p->token) {
|
||||
default: break;
|
||||
case GREP_PATTERN_HEAD:
|
||||
fprintf(stderr, "<head %d>", p->field); break;
|
||||
case GREP_PATTERN_BODY:
|
||||
fprintf(stderr, "<body>"); break;
|
||||
}
|
||||
switch (p->token) {
|
||||
default: break;
|
||||
case GREP_PATTERN_HEAD:
|
||||
case GREP_PATTERN_BODY:
|
||||
case GREP_PATTERN:
|
||||
fprintf(stderr, "%.*s", (int)p->patternlen, p->pattern);
|
||||
break;
|
||||
}
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
static void dump_grep_expression_1(struct grep_expr *x, int in)
|
||||
{
|
||||
indent(in);
|
||||
switch (x->node) {
|
||||
case GREP_NODE_TRUE:
|
||||
fprintf(stderr, "true\n");
|
||||
break;
|
||||
case GREP_NODE_ATOM:
|
||||
dump_grep_pat(x->u.atom);
|
||||
break;
|
||||
case GREP_NODE_NOT:
|
||||
fprintf(stderr, "(not\n");
|
||||
dump_grep_expression_1(x->u.unary, in+1);
|
||||
indent(in);
|
||||
fprintf(stderr, ")\n");
|
||||
break;
|
||||
case GREP_NODE_AND:
|
||||
fprintf(stderr, "(and\n");
|
||||
dump_grep_expression_1(x->u.binary.left, in+1);
|
||||
dump_grep_expression_1(x->u.binary.right, in+1);
|
||||
indent(in);
|
||||
fprintf(stderr, ")\n");
|
||||
break;
|
||||
case GREP_NODE_OR:
|
||||
fprintf(stderr, "(or\n");
|
||||
dump_grep_expression_1(x->u.binary.left, in+1);
|
||||
dump_grep_expression_1(x->u.binary.right, in+1);
|
||||
indent(in);
|
||||
fprintf(stderr, ")\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void dump_grep_expression(struct grep_opt *opt)
|
||||
{
|
||||
struct grep_expr *x = opt->pattern_expression;
|
||||
|
||||
if (opt->all_match)
|
||||
fprintf(stderr, "[all-match]\n");
|
||||
dump_grep_expression_1(x, 0);
|
||||
fflush(NULL);
|
||||
}
|
||||
|
||||
static struct grep_expr *grep_true_expr(void)
|
||||
{
|
||||
struct grep_expr *z = xcalloc(1, sizeof(*z));
|
||||
@ -395,7 +476,7 @@ static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
|
||||
return header_expr;
|
||||
}
|
||||
|
||||
void compile_grep_patterns(struct grep_opt *opt)
|
||||
static void compile_grep_patterns_real(struct grep_opt *opt)
|
||||
{
|
||||
struct grep_pat *p;
|
||||
struct grep_expr *header_expr = prep_header_patterns(opt);
|
||||
@ -415,7 +496,7 @@ void compile_grep_patterns(struct grep_opt *opt)
|
||||
|
||||
if (opt->all_match || header_expr)
|
||||
opt->extended = 1;
|
||||
else if (!opt->extended)
|
||||
else if (!opt->extended && !opt->debug)
|
||||
return;
|
||||
|
||||
p = opt->pattern_list;
|
||||
@ -435,6 +516,13 @@ void compile_grep_patterns(struct grep_opt *opt)
|
||||
opt->all_match = 1;
|
||||
}
|
||||
|
||||
void compile_grep_patterns(struct grep_opt *opt)
|
||||
{
|
||||
compile_grep_patterns_real(opt);
|
||||
if (opt->debug)
|
||||
dump_grep_expression(opt);
|
||||
}
|
||||
|
||||
static void free_pattern_expr(struct grep_expr *x)
|
||||
{
|
||||
switch (x->node) {
|
||||
|
Reference in New Issue
Block a user