[m-rev.] for review: fix a bug in duration parsing
Julien Fischer
jfischer at opturion.com
Tue Jul 7 01:38:25 AEST 2026
On Mon, 6 Jul 2026 at 17:42, Zoltan Somogyi <zoltan.somogyi at runbox.com> wrote:
>
>
> On Mon, 6 Jul 2026 16:53:50 +1000, Julien Fischer <jfischer at opturion.com> wrote:
> > +:- pred read_char(char::out, list(char)::in, list(char)::out) is semidet.
> > +
> > +read_char(Char, [Char | Rest], Rest).
>
> I would call this pred read_NEXT_char, because you later have
> predicates that look for just a SPECIFIC char.
Done.
> > +:- pred read_int_and_num_chars(int::out, int::out,
> > + list(char)::in, list(char)::out) is det.
>
> This does not read num chars beyond reading ints.
> I would rename it to read_int_and_return_{num_char,len}.
>
> > +read_int_and_num_chars(Val, N, !Chars) :-
> > + read_int_and_num_chars_2(0, Val, 0, N, !Chars).
I went with read_int_and_return_num_digits
> N should be something like Len, because Val and N are thoroughly
> confusable. Or NumDigits, which you use later.
Renamed to NumDigits. Val is renamed to Int to match the code further below.
> > +:- pred read_int_and_num_chars_2(int::in, int::out, int::in, int::out,
> > + list(char)::in, list(char)::out) is det.
>
> This pred name should be something like read_int_and_return_len_loop.
Renamed to read_int_and_return_num_digits_loop.
> > +read_int_and_num_chars_2(!Val, !N, !Chars) :-
> > + ( if
> > + !.Chars = [Char | Rest],
> > + decimal_digit_to_int(Char, Digit)
> > + then
> > + !:Val = !.Val * 10 + Digit,
> > + read_int_and_num_chars_2(!Val, !.N + 1, !:N, Rest, !:Chars)
> > + else
> > + true
> > + ).
>
> I think that having both state variables and non-state variables
> representing the different parts of a list (or any data structure)
> is a recipe for confusion. Here, I think Rest could be just the next
> value of !.Chars.
Done.
> In later predicates, I think it should be all separate
> named variables.
Actually, the non-state variables can similarly be eliminated in
the later predicates. (And in a few other parts of this module
not included in this version of the diff.)
> > + % Read an optional leading minus sign. Sign is -1 if one is present (and is
> > + % consumed), and 1 otherwise (consuming nothing).
> > + %
> > :- pred read_sign(int::out, list(char)::in, list(char)::out) is det.
>
> s/Sign is/Set Sign to/
Done.
> > read_days(Days, !Chars) :-
> > read_int_and_char_or_zero(Days, 'D', !Chars).
>
> I would flip the order of the first two args. 'D' is input; Days is output.
> I think that is more important than following the order in the date string,
> which is in the name anyway.
Done.
> Also, I think a name such as read_int_and_GIVEN_char_or_RETURN_zero
> would be clearer.
Done.
> > -:- pred read_hours(int::out, list(char)::in, list(char)::out) is det.
> > +:- pred read_hours(int::out, list(char)::in, list(char)::out) is semidet.
> >
> > read_hours(Hours, !Chars) :-
> > read_int_and_char_or_zero(Hours, 'H', !Chars).
> >
> > -:- pred read_minutes(int::out, list(char)::in, list(char)::out) is det.
> > +:- pred read_minutes(int::out, list(char)::in, list(char)::out) is semidet.
> >
> > read_minutes(Minutes, !Chars) :-
> > read_int_and_char_or_zero(Minutes, 'M', !Chars).
> >
> > + % read_int_and_char_or_zero(Int, Char, !Chars):
> > + %
> > + % Read one optional "<integer><Char>" duration component from the front of
> > + % !.Chars, where <integer> is a run of decimal digits.
> > + % If !.Chars begins with Char preceded by at least one digit, then set Int
> > + % to the value of those digits and !:Chars to the characters after Char.
> > + % If !.Chars begins with Char with no digits before it, then fail.
> > + % Otherwise, set Int to zero and leave !:Chars unchanged.
> > + %
> > +:- pred read_int_and_char_or_zero(int::out, char::in,
> > + list(char)::in, list(char)::out) is semidet.
> > +
> > +read_int_and_char_or_zero(Int, Char, !Chars) :-
> > + ( if
> > + read_int_and_num_chars(Int0, NumDigits, !.Chars, Chars1),
> > + Chars1 = [Char | Rest]
> > + then
> > + NumDigits > 0,
> > + !:Chars = Rest,
> > + Int = Int0
> > + else
> > + Int = 0
> > + ).
>
> This is an example where I think the state var !Chars hurts more than helps.
The non-state variables are unnecessary here; I have simplified the above
accordingly.
> Apart from the above, the diff is fine.
Thanks for that.
Julien.
More information about the reviews
mailing list