[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