On Thu, Mar 2, 2017 at 1:23 AM, Fabien COELHO <coe...@cri.ensmp.fr> wrote:

>
> Hello Corey,
>
> That is accurate. The only positive it has is that the user only
>> experiences one error, and it's the first error that was encountered if
>> reading top-to-bottom, left to right. It is an issue of which we
>> prioritize
>> - user experience or simpler code.
>>
>
> Hmmm. The last simpler structure I suggested, which is basically the one
> used in your code before the update, does check for the structure error
> first. The only drawback is that the condition is only evaluated when
> needed, which is an issue we can cope with, IMO.


Tom was pretty adamant that invalid commands are not executed. So in a case
like this, with ON_ERROR_STOP off:

\if false
\echo 'a'
\elif true
\echo 'b'
\elif invalid
\echo 'c'
\endif

Both 'b' and 'c' should print, because "\elif invalid" should not execute.
The code I had before was simpler, but it missed that.


>
> Now if you want to require committer opinion on this one, fine with me.
>>>
>>
>> Rather than speculate on what a committer thinks of this edge case (and
>> making a patch for each possible theory), I'd rather just ask them what
>> their priorities are and which user experience they favor.
>>
>
> ISTM that the consistent message by Robert & Tom was to provide simpler
> code even if the user experience is somehow degraded, as they required that
> user-friendly features were removed (eg trying to be nicer about structural
> syntax errors, barking in interactive mode so that the user always knows
> the current status, providing a detailed status indicator in the prompt...).
>

Ok, so here's one idea I tossed around, maybe this will strike the right
balance for you.

If I create a function like this:

static boolean
is_valid_else_context(IfState if_state, const char *cmd)
{
    /* check for invalid \else / \elif contexts */

    switch (if_state)

    {
        case IFSTATE_NONE:
            /* not in an \if block */
            psql_error("\\%s: no matching \\if\n", cmd);
            return false;
            break;
        case IFSTATE_ELSE_TRUE:
        case IFSTATE_ELSE_FALSE:
            psql_error("\\%s: cannot occur after \\else\n", cmd);
            return false;
            break;
        default:
            break;
    }
    return true;
}



Then the elif block looks something like this:

    else if (strcmp(cmd, "elif") == 0)
    {
        ifState if_state = conditional_stack_peek(cstack);

        if (is_valid_else_context(if_state, "elif"))
        {
            /*
             * valid \elif context, check for valid expression
             */
            bool elif_true = false;
            success = read_boolean_expression(scan_state, "\\elif <expr>",
                                                &elif_true);
            if (success)
            {
                /*
                 * got a valid boolean, what to do with it depends on
current
                 * state
                 */
                switch (if_state)
                {
                    case IFSTATE_IGNORED:
                        /*
                         * inactive branch, do nothing.
                         * either if-endif already had a true block,
                         * or whole parent block is false.
                         */
                        break;
                    case IFSTATE_TRUE:
                        /*
                         * just finished true section of this if-endif,
                         * must ignore the rest until \endif
                         */
                        conditional_stack_poke(cstack, IFSTATE_IGNORED);
                        break;
                    case IFSTATE_FALSE:
                        /*
                         * have not yet found a true block in this if-endif,
                         * this might be the first.
                         */
                        if (elif_true)
                            conditional_stack_poke(cstack, IFSTATE_TRUE);
                        break;
                    default:
                        /* error cases all previously ruled out */
                        break;
                }
            }
        }
        else
            success = false;
        psql_scan_reset(scan_state);
    }


This is functionally the same as my latest patch, but the ugliness of
switching twice on if_state is hidden.

As an added benefit, the "else"-handling code gets pretty simple because it
can leverage that same function.

Does that handle your objections?

p.s.  do we try to avoid constructs like    if (success = my_function(var1,
var2))   ?

Reply via email to