%% -*- prolog -*-

%% June 2012, Göran Weinholt.

%% This program generates an instance of every possible R6RS Scheme
%% number syntax. It can be used to check if an implementation of
%% string->number is complete. Some notations have been commented out
%% in order to make the output more managable. Example invocation with
%% SWI-Prolog:

%% August 2013, Göran Weinholt.

%% Addendum: the previous version included non-decimal numbers with
%% decimal points in them. The R6RS BNF allows this, but the prose
%% preceding it does not. This program was also updated to look more
%% like the BNF.

%% Another omission in the R6RS BNF, which is actually replicated
%% here, is polar complex numbers with non-finite arguments. These
%% don't make any sense, so nobody is coming after you if your reader
%% can't handle them.

%% How to use it to compute "every" number:

%% $ swipl -s every-number-revised.pl
%% ?- forall(scheme_number(X,[]), writef("%s\n", [X])).
%% #b1010
%% #b1010/1010
%% #b+1010
%% ...

%% If you uncomment all the lines below, then you should also be also
%% to use it to determine if an arbitrary string is a valid R6RS
%% number:

%% $ swipl -s every-number-revised.pl
%% ?- scheme_number("#b+11110i",[]).
%% true .
%% ?- scheme_number("#x+inf.0",[]).
%% false.

scheme_number --> (num(2); num(8); num(10); num(16)).

num(R) --> prefix(R), complex(R).

complex(R) --> (real(R);
		real(R), "@", real(R);
		real(R), "+", ureal(R), "i";
		real(R), "-", ureal(R), "i";
		real(R), "+", naninf(R), "i";
		real(R), "-", naninf(R), "i";
		real(R), "+i";
		real(R), "-i";
		"+", ureal(R), "i";
		"-", ureal(R), "i";
		"+", naninf(R), "i";
		"-", naninf(R), "i";
		"+i";
		"-i").

real(R) --> (sign, ureal(R);
	     "+", naninf(R);
	     "-", naninf(R)).

naninf(10) --> ("nan.0"; "inf.0").

ureal(R) --> (uinteger(R);
	      uinteger(R), "/", uinteger(R);
	      decimal(R), mantissa_width).

decimal(10) --> (uinteger(10), suffix;
		 ".", digits(10), suffix;
		 digits(10), ".", digits0(10), suffix;
		 digits(10), ".", suffix).

uinteger(R) --> digits(R).

prefix(R) --> (radix(R), exactness;
	       exactness, radix(R)).

suffix --> ("";
	    exponent_marker, sign, digits(10)).
% exponent_marker --> ("e";"E";"s";"S";"f";"F";"d";"D";"l";"L").
% mantissa_width --> (""; "|", digits(10)).
sign --> (""; "+"; "-").
% exactness --> (""; "#i"; "#I"; "#e"; "#E").

% radix(2) --> ("#b"; "#B").
% radix(8) --> ("#o"; "#O").
% radix(10) --> (""; "#d"; "#D").
% radix(16) --> ("#x"; "#X").

digit(2) --> ("0";"1").
digit(8) --> ("0";"1";"2";"3";"4";"5";"6";"7").
digit(10) --> ("0";"1";"2";"3";"4";"5";"6";"7";"8";"9").
digit(16) --> ("0";"1";"2";"3";"4";"5";"6";"7";"8";"9";
	       "a";"b";"c";"d";"e";"f";
	       "A";"B";"C";"D";"E";"F").

% digits(R) --> (digit(R);
% 	       digit(R), digits(R)).

%% These replacements are for generating "all" numbers.
exponent_marker --> "e".
mantissa_width --> (""; "|53").
exactness --> (""; "#i"; "#e").
radix(2) --> "#b".
radix(8) --> "#o".
radix(10) --> (""; "#d").
radix(16) --> "#x".
uinteger(2) --> "1010".
uinteger(8) --> "0755".
uinteger(10) --> "19".
uinteger(16) --> "abcd".
digits(10) --> "49".
digits0(10) --> "83".
digits0(10) --> "".
