Re: [PATCH 1/9] ref-filter: implement %(if), %(then), and %(else) atoms
- From
Matthieu Moy <matthieu.moy@grenoble-inp.fr>
- Date
- Oct 3, 2015, 09:39 UTC
- Message-ID
- <vpq8u7kb89o.fsf@grenoble-inp.fr>
- In-Reply-To
- <1443807546-5985-2-git-send-email-Karthik.188@gmail.com>
Karthik Nayak <karthik.188@gmail.com> writes:
> Implement %(if), %(then) and %(else) atoms. Used as > %(if)..%(then)..%(end) or %(if)..%(then)..%(else)..%(end).
I prefer ... to .., which often means "interval" as in HEAD^^..HEAD.
> If there is an atom with value or string literal after the %(if)
I find this explanation hard to read, and ambiguous: what does "atom with value" mean?
> then everything after the %(then) is printed, else if the %(else) atom > is used, then everything after %(else) is printed. If the string > contains only whitespaces, then it is not considered.
"the string" is ambiguous again. I guess it's "what's between %(if) and %(then)", but it could be clearer. And it's not clear what "not considered" means.
My take on it:
Implement %(if), %(then) and %(else) atoms. Used as %(if)...%(then)...%(end) or %(if)...%(then)...%(else)...%(end). If the format string between %(if) and %(then) expands to an empty string, or to only whitespaces, then the string following %(then) is printed. Otherwise, the string following %(else), if any, is printed.
> +When a scripting language specific quoting is in effect,
This may not be immediately clear to the reader. I'd add explicitly:
When a scripting language specific quoting is in effect (i.e. one of `--shell`, `--perl`, `--python`, `--tcl` is used), ...
> EXAMPLES > --------
This is just the context of the patch, but I read it as a hint that we could add some examples with complex --format usage to illustrate the theory above.
> + if (if_then_else->condition_satisfied && if_then_else->else_atom) {// cs && else
> + strbuf_reset(&cur->output);
> + pop_stack_element(&cur);
> + } else if (if_then_else->else_atom) {// !cs && else
> + strbuf_swap(&cur->output, &prev->output); > + strbuf_reset(&cur->output); > + pop_stack_element(&cur); > + } else if (!if_then_else->condition_satisfied)
// !cs && !else
> + strbuf_reset(&cur->output);
This if/else if/else if looks hard to read to me. I had to add the comments above as a note to myself to get the actual full condition for 3 branches.
The reasoning would be clearer to me as:
if (if_then_else->else_atom) {
/*
* There is an %(else) atom: we need to drop one state from the
* stack, either the %(else) branch if the condition is satisfied, or
* the %(then) branch if it isn't.
*/
if (if_then_else->condition_satisfied) {
strbuf_reset(&cur->output);
pop_stack_element(&cur);
} else {
strbuf_swap(&cur->output, &prev->output);
strbuf_reset(&cur->output);
pop_stack_element(&cur);
}
} else if (if_then_else->condition_satisfied)
/*
* No %(else) atom: just drop the %(then) branch if the
* condition is not satisfied.
*/
strbuf_reset(&cur->output);Show 6 quoted lines
> +static void if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
> +{
> + struct ref_formatting_stack *new;
> + struct if_then_else *if_then_else = xcalloc(sizeof(struct if_then_else), 1);
> +
> + if_then_else->if_atom = 1;Do you ever use this "if_atom"? It doesn't seem so in the current patch, and it seems like a tautology to me: if you have a struct if_then_else, then you have seen the %(if).
> +static int is_empty(const char * s){char * s -> char *s
Show 7 quoted lines
> +static void then_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
> +{
> + struct ref_formatting_stack *cur = state->stack;
> + struct if_then_else *if_then_else = (struct if_then_else *)cur->at_end_data;
> +
> + if (!if_then_else)
> + die(_("format: %%(then) atom used without an %%(if) atom"));You've just casted at_end_data to if_then_else. if_then_else being not NULL does not mean that it is properly typed. It can be the at_end_data of another opening atom. What happens if you use %(align)foo%(then)bar%(end)?
One way to be safer would be to check that cur->at_end does point to if_then_else_handler. Or add information to struct ref_formatting_stack (a Boolean is_if_then_else or an enum).
Also, you need to check that if_then_else->then_atom is not 1.
Show 7 quoted lines
> +static void else_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
> +{
> + struct ref_formatting_stack *prev = state->stack;
> + struct if_then_else *if_then_else = (struct if_then_else *)state->stack->at_end_data;
> +
> + if (!if_then_else)
> + die(_("format: %%(else) atom used without an %%(if) atom"));Same as above, I guess (not tested) %(align)...%(else) is accepted.
> + if (!if_then_else->then_atom)
> + die(_("format: %%(else) atom used without a %%(then) atom"));
> + if_then_else->else_atom = 1;
> + push_stack_element(&state->stack);So, while parsing the %(else)...%(end), the stack contains both the %(then)...%(else) part, and the %(else)...%(end).
I'm wondering if we can simplify this. We already know if the condition is satisfied, and if it's not, we can just drop the %(then) part right now, and write to the top of the stack normally (the %(end) atom will only have to pop the string normally). But if the condition is not satisfied, we need to preserve the %(then) part and need to do something about the %(else).
> - current->at_end(current); > + current->at_end(&state->stack); > + > + /* Stack may have been popped, hence reset the current pointer */
I'd say explicitly "... may have been popped within at_end, hence ..."
-- Matthieu Moy http://www-verimag.imag.fr/~moy/