[m-rev.] for review: allow string.base_string_to_int to parse int.min_int literals

Ian MacLarty maclarty at csse.unimelb.edu.au
Wed Jan 13 16:46:26 AEDT 2010


Change string.base_string_to_int so that it doesn't fail if the base is 10 and
the integer is int.min_int.  The previous behaviour seems unintuitive and means
we can't use the literal -2147483648 in Mercury programs on 32 bit machines,
even though that number can be represented in 32 bits.

library/string.m:
    If the integer to be parsed is negative, then use a negative accumulator,
    so that if the number is int.min_int it doesn't cause an overflow.

tests/general/base_string_to_int_test.exp:
tests/general/base_string_to_int_test.m:
    Test it.

Index: library/string.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/string.m,v
retrieving revision 1.292
diff -u -r1.292 string.m
--- library/string.m	14 Oct 2009 05:28:53 -0000	1.292
+++ library/string.m	13 Jan 2010 05:32:48 -0000
@@ -351,14 +351,14 @@
     % preceded by a plus or minus sign. For bases > 10, digits 10 to 35
     % are represented by the letters A-Z or a-z. If the string does not match
     % this syntax or the base is 10 and the number is not in the range
-    % [int.min_int+1, int.max_int], the predicate fails.
+    % [int.min_int, int.max_int], the predicate fails.
     %
 :- pred string.base_string_to_int(int::in, string::in, int::out) is semidet.
 
     % Converts a signed base N string to an int; throws an exception
     % if the string argument is not precisely an optional sign followed by
     % a non-empty string of base N digits and, if the base is 10, the number
-    % is in the range [int.min_int+1, int.max_int].
+    % is in the range [int.min_int, int.max_int].
     %
 :- func string.det_base_string_to_int(int, string) = int.
 
@@ -947,15 +947,13 @@
     Len = string.length(String),
     ( Char = ('-') ->
         Len > 1,
-        foldl_substring(accumulate_int(Base), String, 1, Len - 1, 0, N),
-        Int = -N
+        foldl_substring(accumulate_negative_int(Base), String, 1,
+            Len - 1, 0, Int)
     ; Char = ('+') ->
         Len > 1,
-        foldl_substring(accumulate_int(Base), String, 1, Len - 1, 0, N),
-        Int = N
+        foldl_substring(accumulate_int(Base), String, 1, Len - 1, 0, Int)
     ;
-        foldl_substring(accumulate_int(Base), String, 0, Len, 0, N),
-        Int = N
+        foldl_substring(accumulate_int(Base), String, 0, Len, 0, Int)
     ).
 
 :- pred accumulate_int(int::in, char::in, int::in, int::out) is semidet.
@@ -966,6 +964,15 @@
     N = (Base * N0) + M,
     ( N0 =< N ; Base \= 10 ).           % Fail on overflow for base 10 numbers.
 
+:- pred accumulate_negative_int(int::in, char::in,
+    int::in, int::out) is semidet.
+
+accumulate_negative_int(Base, Char, N0, N) :-
+    char.digit_to_int(Char, M),
+    M < Base,
+    N = (Base * N0) - M,
+    ( N =< N0 ; Base \= 10 ).       % Fail on underflow for base 10 numbers.
+
 % It is important to inline string.index and string.index_det.
 % so that the compiler can do loop invariant hoisting
 % on calls to string.length that occur in loops.
Index: tests/general/base_string_to_int_test.exp
===================================================================
RCS file: /home/mercury1/repository/tests/general/base_string_to_int_test.exp,v
retrieving revision 1.1
diff -u -r1.1 base_string_to_int_test.exp
--- tests/general/base_string_to_int_test.exp	1 Jul 2004 06:20:14 -0000	1.1
+++ tests/general/base_string_to_int_test.exp	13 Jan 2010 05:32:49 -0000
@@ -8,3 +8,4 @@
 string.base_string_to_int(10, "abc", _) failed.
 string.base_string_to_int(10, "+abc", _) failed.
 string.base_string_to_int(10, "-abc", _) failed.
+string.base_string_to_int(10, "-2147483648", -2147483648).
Index: tests/general/base_string_to_int_test.m
===================================================================
RCS file: /home/mercury1/repository/tests/general/base_string_to_int_test.m,v
retrieving revision 1.1
diff -u -r1.1 base_string_to_int_test.m
--- tests/general/base_string_to_int_test.m	1 Jul 2004 06:20:14 -0000	1.1
+++ tests/general/base_string_to_int_test.m	13 Jan 2010 05:32:49 -0000
@@ -35,7 +35,8 @@
     test("123abc", !IO),
     test("abc", !IO),
     test("+abc", !IO),
-    test("-abc", !IO).
+    test("-abc", !IO),
+    test("-2147483648", !IO).
 
 
 :- pred test(string::in, io::di, io::uo) is det.
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list