# HG changeset patch # User Aidan Kehoe # Date 1431128457 -3600 # Node ID 6174848f3e6cff44ec30555d1935c9c2a320ddff # Parent 87e29d93e11b649cdfa966e4447ceba45379af0a Use parse_integer() in read_atom(); support bases with ratios like integers src/ChangeLog addition: 2015-05-08 Aidan Kehoe * data.c (init_errors_once_early): Move the Qunsupported_type here from numbers.c, so it's available when the majority of our types are not supported. * general-slots.h: Add it here, too. * number.c: Remove the definition of Qunsupported_type from here. * lread.c (read_atom): Check if the first character could reflect a rational, if so, call parse_integer(), don't check the syntax of the other characters. This allows us to accept the non-ASCII digit characters too. If that worked partially, but not completely, and the next char is a slash, try to parse as a ratio. If that fails, try isfloat_string(), but only if the first character could plausibly be part of a float. Otherwise, treat as a symbol. * lread.c (read_rational): Rename from read_integer. Handle ratios with the same radix specification as was used for integers. * lread.c (read1): Rename read_integer in this function. Support the Common Lisp #NNNrMMM syntax for parsing a number MMM of arbitrary radix NNN. man/ChangeLog addition: 2015-05-08 Aidan Kehoe * lispref/numbers.texi (Numbers): Describe the newly-supported arbitrary-base syntax for rationals (integers and ratios). Describe that ratios can take the same base specification as integers, something also new. tests/ChangeLog addition: 2015-05-08 Aidan Kehoe * automated/lisp-reader-tests.el: Check the arbitrary-base integer reader syntax support, just added. Check the reader base support for ratios, just added. Check the non-ASCII-digit support in the reader, just added. diff -r 87e29d93e11b -r 6174848f3e6c man/ChangeLog --- a/man/ChangeLog Fri May 08 20:04:42 2015 +0100 +++ b/man/ChangeLog Sat May 09 00:40:57 2015 +0100 @@ -1,3 +1,10 @@ +2015-05-08 Aidan Kehoe + + * lispref/numbers.texi (Numbers): + Describe the newly-supported arbitrary-base syntax for rationals + (integers and ratios). Describe that ratios can take the same base + specification as integers, something also new. + 2015-03-15 Aidan Kehoe * lispref/strings.texi (Character Codes): diff -r 87e29d93e11b -r 6174848f3e6c man/lispref/numbers.texi --- a/man/lispref/numbers.texi Fri May 08 20:04:42 2015 +0100 +++ b/man/lispref/numbers.texi Sat May 09 00:40:57 2015 +0100 @@ -18,12 +18,16 @@ of XEmacs) are whole numbers such as @minus{}3, 0, #b0111, #xFEED, #o744. Their values are exact, and their range is limited. The number prefixes `#b', `#o', and `#x' are supported to represent numbers -in binary, octal, and hexadecimal notation (or radix). Floating point -numbers are numbers with fractional parts, such as @minus{}4.5, 0.0, or -2.71828. They can also be expressed in exponential notation: 1.5e2 -equals 150; in this example, @samp{e2} stands for ten to the second -power, and is multiplied by 1.5. Floating point values are not exact; -they have a fixed, limited amount of precision. +in binary, octal, and hexadecimal notation (or radix). The syntax +`#NNNrNUM' is also supported, allowing a radix to be explicitly +specified; e.g. `#20r15' denotes the fixnum 25, expressed in base +twenty. + + Floating point numbers are numbers with fractional parts, such as +@minus{}4.5, 0.0, or 2.71828. They can also be expressed in exponential +notation: 1.5e2 equals 150; in this example, @samp{e2} stands for ten to +the second power, and is multiplied by 1.5. Floating point values are +not exact; they have a fixed, limited amount of precision. Bignums are arbitrary precision integers. When supported, XEmacs can handle any integral calculations you have enough virtual memory to @@ -33,9 +37,13 @@ automatically converts results of computations from fixnum to bignum, and back, depending on the storage required to represent the number. Thus use of bignums are entirely transparent to the user, except for a -few special applications that expect overflows. Ratios are rational -numbers with arbitrary precision. They are notated in the -usual way with the solidus, for example 5/3 or @minus{}22/7. +few special applications that expect overflows. + + Ratios are rational numbers with arbitrary precision. They are notated +in the usual way with the solidus, for example 5/3 or @minus{}22/7. The +syntax for using a particular radix is the same as that for integers, +so, e.g., @samp{#x8/10} is equivalent to @samp{1/2} and @samp{#30r10/4} +to @samp{15/2}, respectively. Bigfloats are floating point numbers with arbitrary precision, which may be specified by the user (and may be different for different diff -r 87e29d93e11b -r 6174848f3e6c src/ChangeLog --- a/src/ChangeLog Fri May 08 20:04:42 2015 +0100 +++ b/src/ChangeLog Sat May 09 00:40:57 2015 +0100 @@ -1,3 +1,28 @@ +2015-05-08 Aidan Kehoe + + * data.c (init_errors_once_early): + Move the Qunsupported_type here from numbers.c, so it's available + when the majority of our types are not supported. + * general-slots.h: Add it here, too. + * number.c: Remove the definition of Qunsupported_type from here. + + * lread.c (read_atom): + Check if the first character could reflect a rational, if so, call + parse_integer(), don't check the syntax of the other + characters. This allows us to accept the non-ASCII digit + characters too. + If that worked partially, but not completely, and the next char is + a slash, try to parse as a ratio. + If that fails, try isfloat_string(), but only if the first + character could plausibly be part of a float. + Otherwise, treat as a symbol. + * lread.c (read_rational): + Rename from read_integer. Handle ratios with the same radix + specification as was used for integers. + * lread.c (read1): + Rename read_integer in this function. Support the Common Lisp + #NNNrMMM syntax for parsing a number MMM of arbitrary radix NNN. + 2015-05-08 Aidan Kehoe * general-slots.h: Sort the symbols in this file using the Lisp diff -r 87e29d93e11b -r 6174848f3e6c src/data.c --- a/src/data.c Fri May 08 20:04:42 2015 +0100 +++ b/src/data.c Sat May 09 00:40:57 2015 +0100 @@ -1814,10 +1814,9 @@ overflow: #ifndef HAVE_BIGNUM - return Fsignal (Qinvalid_argument, - list3 (build_msg_string ("Integer constant overflow"), - make_string (buf, len), make_fixnum (base))); - + return Fsignal (Qunsupported_type, + list3 (build_ascstring ("bignum"), make_string (buf, len), + make_fixnum (base))); #else /* HAVE_BIGNUM */ result = make_bignum_emacs_uint (onum); @@ -4100,6 +4099,10 @@ DEFERROR (Qsingularity_error, "Arithmetic singularity error", Qdomain_error); DEFERROR (Qoverflow_error, "Arithmetic overflow error", Qdomain_error); DEFERROR (Qunderflow_error, "Arithmetic underflow error", Qdomain_error); + + /* Moved here from number.c, so it's available when none of the new numeric + types are. */ + DEFERROR_STANDARD (Qunsupported_type, Qwrong_type_argument); } void diff -r 87e29d93e11b -r 6174848f3e6c src/general-slots.h --- a/src/general-slots.h Fri May 08 20:04:42 2015 +0100 +++ b/src/general-slots.h Sat May 09 00:40:57 2015 +0100 @@ -307,6 +307,7 @@ SYMBOL (Qunencodable); SYMBOL (Qunicode_registries); SYMBOL (Qunicode_type); +SYMBOL (Qunsupported_type); SYMBOL (Qunimplemented); SYMBOL (Quser_default); SYMBOL_KEYWORD (Q_value); diff -r 87e29d93e11b -r 6174848f3e6c src/lread.c --- a/src/lread.c Fri May 08 20:04:42 2015 +0100 +++ b/src/lread.c Sat May 09 00:40:57 2015 +0100 @@ -1930,62 +1930,123 @@ /* This function can GC */ int saw_a_backslash; Bytecount len = read_atom_0 (readcharfun, firstchar, &saw_a_backslash); - char *read_ptr = (char *) - resizing_buffer_stream_ptr (XLSTREAM (Vread_buffer_stream)); - - /* Is it an integer? */ - if (! (saw_a_backslash || uninterned_symbol)) + Ibyte *read_ptr + = (Ibyte *) resizing_buffer_stream_ptr (XLSTREAM (Vread_buffer_stream)); + + /* Is it an integer? + + If a token had any backslashes in it, it is disqualified from being an + integer or a float. This means that 123\456 is a symbol, as is \123 + (which is the way (intern "123") prints). Also, if token was preceded by + #:, it's always a symbol. */ + + if (!(saw_a_backslash || uninterned_symbol)) { - /* If a token had any backslashes in it, it is disqualified from - being an integer or a float. This means that 123\456 is a - symbol, as is \123 (which is the way (intern "123") prints). - Also, if token was preceded by #:, it's always a symbol. - */ - char *p = read_ptr + len; - char *p1 = read_ptr; - - if (*p1 == '+' || *p1 == '-') p1++; - if (p1 != p) - { - int c; - - while (p1 != p && (c = *p1) >= '0' && c <= '9') - p1++; - /* Integers can have trailing decimal points. */ - if (p1 > read_ptr && p1 < p && *p1 == '.') - p1++; - if (p1 == p) + Lisp_Object got = get_char_table (firstchar, Vdigit_fixnum_map); + Fixnum fixval = FIXNUMP (got) ? XREALFIXNUM (got) : -1; + Boolint starts_like_an_int_p = (fixval > -1 && fixval < 10) + || firstchar == '+' || firstchar == '-'; + Ibyte *endp = NULL; + Lisp_Object num = Qnil; + + /* Attempt to parse as an integer, with :JUNK-ALLOWED t. Do a gross + plausibility check (above) first, though, we'd prefer not to call + parse_integer() on every symbol we see. */ + if (starts_like_an_int_p) + { + num = parse_integer (read_ptr, &endp, len, 10, 1, Qnil); + } + + if (INTEGERP (num)) + { + if (endp == (read_ptr + len)) + { + /* We consumed the whole atom, it's definitely an integer. */ + return num; + } + else if ('.' == itext_ichar (endp)) + { + /* Trailing decimal point is allowed in the Lisp reader, this is + an integer. */ + INC_IBYTEPTR (endp); + if (endp == (read_ptr + len)) + { + return num; + } + } + else if ('/' == itext_ichar (endp)) { - Ibyte *buf_end; - /* It is an integer. */ - if (p1[-1] == '.') + /* Maybe it's a ratio? */ + Lisp_Object denom = Qnil; + + INC_IBYTEPTR (endp); + + if (endp < (read_ptr + len)) { - len -= 1; + Ichar cc = itext_ichar (endp); + /* No leading sign allowed in the denominator, that would + make it a symbol (according to Common Lisp, of course).*/ + if (cc != '+' && cc != '-') + { + denom = parse_integer (endp, &endp, + len - (endp - read_ptr), 10, + 1, Qnil); + } } - return parse_integer ((Ibyte *) read_ptr, &buf_end, len, 10, - 0, Qnil); - } - } -#ifdef HAVE_RATIO - if (isratio_string (read_ptr)) - { - /* GMP ratio_set_string has no effect with initial + sign */ - if (*read_ptr == '+') - read_ptr++; - ratio_set_string (scratch_ratio, read_ptr, 0); - if (bignum_sign (ratio_denominator (scratch_ratio)) != 0) { - ratio_canonicalize (scratch_ratio); - return Fcanonicalize_number (make_ratio_rt (scratch_ratio)); - } - return Fsignal (Qinvalid_read_syntax, - list2 (build_msg_string - ("Invalid ratio constant in reader"), - make_string ((Ibyte *) read_ptr, len))); - } -#endif - if (isfloat_string (read_ptr)) - return make_float (atof (read_ptr)); + if (INTEGERP (denom) && endp == (read_ptr + len)) + { + if (ZEROP (denom)) + { + Fsignal (Qinvalid_read_syntax, + list2 (build_msg_string + ("Invalid ratio constant in reader"), + make_string (read_ptr, len))); + } +#ifndef HAVE_RATIO + /* Support a couple of trivial ratios in the reader to allow + people to test ratio syntax: */ + if (EQ (denom, make_fixnum (1))) + { + return num; + } + if (!NILP (Fequal (num, denom))) + { + return make_fixnum (1); + } + + return Fsignal (Qunsupported_type, + list3 (build_ascstring ("ratio"), + num, denom)); +#else + switch (promote_args (&num, &denom)) + { + case FIXNUM_T: + num = make_ratio (XREALFIXNUM (num), + XREALFIXNUM (denom)); + return Fcanonicalize_number (num); + break; + case BIGNUM_T: + num = make_ratio_bg (XBIGNUM_DATA (num), + XBIGNUM_DATA (denom)); + return Fcanonicalize_number (num); + break; + default: + assert (0); + } +#endif /* HAVE_RATIO */ + } + /* Otherwise, not a ratio or integer, despite that the partial + parse may have succeeded. The trailing junk disqualifies + it. */ + } + } + + if ((starts_like_an_int_p || '.' == firstchar) + && isfloat_string ((char *) read_ptr)) + { + return make_float (atof ((char *) read_ptr)); + } } { @@ -2002,15 +2063,77 @@ } static Lisp_Object -read_integer (Lisp_Object readcharfun, int base) +read_rational (Lisp_Object readcharfun, Fixnum base) { /* This function can GC */ int saw_a_backslash; - Ibyte *buf_end; + Ibyte *buf_end, *buf_ptr, *slash; Bytecount len = read_atom_0 (readcharfun, -1, &saw_a_backslash); - return (parse_integer - (resizing_buffer_stream_ptr (XLSTREAM (Vread_buffer_stream)), - &buf_end, len, base, 0, Qnil)); + Lisp_Object num = Qnil, denom = Qzero; + + buf_ptr = resizing_buffer_stream_ptr (XLSTREAM (Vread_buffer_stream)); + + if ((slash = memchr (buf_ptr, '/', len)) == NULL) + { + /* Can't be a ratio, parse as as an integer. */ + return parse_integer (buf_ptr, &buf_end, len, base, 0, Qnil); + } + + /* No need to call isratio_string, the detailed parsing (and erroring, as + necessary) will be done by parse_integer. */ + num = parse_integer (buf_ptr, &buf_end, slash - buf_ptr, base, 0, Qnil); + + INC_IBYTEPTR (slash); + if (slash < (buf_ptr + len)) + { + Ichar cc = itext_ichar (slash); + if (cc != '+' && cc != '-') + { + denom = parse_integer (slash, &buf_end, len - (slash - buf_ptr), + base, 0, Qnil); + } + } + + if (ZEROP (denom)) + { + /* The denominator was zero, or it had a sign specified; these are + invalid ratios, for slightly different reasons. */ + Fsignal (Qinvalid_read_syntax, + list2 (build_msg_string ("Invalid ratio constant in reader"), + make_string (buf_ptr, len))); + } + +#ifndef HAVE_RATIO + /* Support a couple of trivial ratios in the reader to allow people to test + ratio syntax: */ + if (EQ (denom, make_fixnum (1))) + { + return num; + } + if (!NILP (Fequal (num, denom))) + { + return make_fixnum (1); + } + + return Fsignal (Qunsupported_type, list3 (build_ascstring ("ratio"), + num, denom)); +#else + switch (promote_args (&num, &denom)) + { + case FIXNUM_T: + num = make_ratio (XREALFIXNUM (num), XREALFIXNUM (denom)); + return Fcanonicalize_number (num); + break; + case BIGNUM_T: + num = make_ratio_bg (XBIGNUM_DATA (num), XBIGNUM_DATA (denom)); + return Fcanonicalize_number (num); + break; + default: + assert (0); /* promote_args() with two integers won't give us anything + but fixnums or bignums. */ + return Qnil; + } +#endif } static Lisp_Object @@ -2569,11 +2692,11 @@ /* bit vectors */ case '*': return read_bit_vector (readcharfun); /* #o10 => 8 -- octal constant syntax */ - case 'o': case 'O': return read_integer (readcharfun, 8); + case 'o': case 'O': return read_rational (readcharfun, 8); /* #xdead => 57005 -- hex constant syntax */ - case 'x': case 'X': return read_integer (readcharfun, 16); + case 'x': case 'X': return read_rational (readcharfun, 16); /* #b010 => 2 -- binary constant syntax */ - case 'b': case 'B': return read_integer (readcharfun, 2); + case 'b': case 'B': return read_rational (readcharfun, 2); /* #r"raw\stringt" -- raw string syntax */ case 'r': return read_raw_string(readcharfun); /* #s(foobar key1 val1 key2 val2) -- structure syntax */ @@ -2606,32 +2729,44 @@ #endif case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - /* Reader forms that can reuse previously read objects. */ + hash_digit_syntax: + /* Reader forms that can reuse previously read objects, or the + Common Lisp syntax for a rational of arbitrary base. */ { - Lisp_Object parsed, found; + Lisp_Object got = get_char_table (c, Vdigit_fixnum_map); + Fixnum fixval = FIXNUMP (got) ? XREALFIXNUM (got) : -1; + Lisp_Object parsed, found; Ibyte *buf_end; Lstream_rewind (XLSTREAM (Vread_buffer_stream)); - /* Using read_integer() here is impossible, because it + /* Using read_rational() here is impossible, because it chokes on `='. */ - while (c >= '0' && c <= '9') + while (fixval >= 0 && fixval <= 9) { Lstream_put_ichar (XLSTREAM (Vread_buffer_stream), c); QUIT; c = readchar (readcharfun); + got = get_char_table (c, Vdigit_fixnum_map); + fixval = FIXNUMP (got) ? XREALFIXNUM (got) : -1; } - /* blasted terminating 0 */ - Lstream_put_ichar (XLSTREAM (Vread_buffer_stream), 0); Lstream_flush (XLSTREAM (Vread_buffer_stream)); parsed = parse_integer (resizing_buffer_stream_ptr (XLSTREAM (Vread_buffer_stream)), &buf_end, Lstream_byte_count (XLSTREAM - (Vread_buffer_stream)) - - 1, 10, 0, Qnil); + (Vread_buffer_stream)), + 10, 0, Qnil); + + if ('r' == c || 'R' == c) + { + /* Common Lisp syntax to specify an integer of arbitrary + base. */ + CHECK_FIXNUM (parsed); + return read_rational (readcharfun, XFIXNUM (parsed)); + } found = assoc_no_quit (parsed, Vread_objects); if (c == '=') @@ -2681,6 +2816,14 @@ } default: { + Lisp_Object got = get_char_table (c, Vdigit_fixnum_map); + Fixnum fixval = FIXNUMP (got) ? XREALFIXNUM (got) : -1; + + if (fixval > -1 && fixval < 10) + { + goto hash_digit_syntax; + } + unreadchar (readcharfun, c); return Fsignal (Qinvalid_read_syntax, list1 (build_ascstring ("#"))); diff -r 87e29d93e11b -r 6174848f3e6c src/number.c --- a/src/number.c Fri May 08 20:04:42 2015 +0100 +++ b/src/number.c Sat May 09 00:40:57 2015 +0100 @@ -32,7 +32,6 @@ Lisp_Object Qrationalp, Qfloatingp, Qrealp; Lisp_Object Vdefault_float_precision; -static Lisp_Object Qunsupported_type; static Lisp_Object Vbigfloat_max_prec; static int number_initialized; @@ -811,9 +810,6 @@ DEFSUBR (Frealp); DEFSUBR (Fcanonicalize_number); DEFSUBR (Fcoerce_number); - - /* Errors */ - DEFERROR_STANDARD (Qunsupported_type, Qwrong_type_argument); } void diff -r 87e29d93e11b -r 6174848f3e6c tests/ChangeLog --- a/tests/ChangeLog Fri May 08 20:04:42 2015 +0100 +++ b/tests/ChangeLog Sat May 09 00:40:57 2015 +0100 @@ -1,3 +1,10 @@ +2015-05-08 Aidan Kehoe + + * automated/lisp-reader-tests.el: + Check the arbitrary-base integer reader syntax support, just + added. Check the reader base support for ratios, just added. + Check the non-ASCII-digit support in the reader, just added. + 2015-05-08 Aidan Kehoe * automated/lisp-tests.el: diff -r 87e29d93e11b -r 6174848f3e6c tests/automated/lisp-reader-tests.el --- a/tests/automated/lisp-reader-tests.el Fri May 08 20:04:42 2015 +0100 +++ b/tests/automated/lisp-reader-tests.el Sat May 09 00:40:57 2015 +0100 @@ -217,3 +217,124 @@ 2409984" "-289480223093290488558927462521719769633174961664101410098643960019782\ 82409985"))) + +(macrolet + ((Assert-reading-rationals (&rest details) + (cons + 'progn + (loop + for (guard first . rest) in details + collect `(when ,guard + ,@(loop for value in rest + collect `(Assert (eql ,first + (read ,value)))))))) + (with-digits (ascii alternate &body body) + (let ((tree-alist (list (cons 'old 'new))) + (text-alist (mapcar* #'cons ascii alternate))) + (list* + 'progn + (sublis tree-alist body + :test #'(lambda (new old) + ;; This function replaces any ASCII decimal digits + ;; in any string encountered in the tree with the + ;; non-ASCII digits supplied in ALTERNATE. + (when (and (stringp old) + (find-if #'digit-char-p old)) + (setf (cdar tree-alist) + (concatenate 'string + (sublis text-alist + (append old nil)))) + t)))))) + (with-all-digits (&body body) + (list + 'progn + (list* 'with-digits "0123456789" "0123456789" body) + (when (featurep 'mule) + (cons + 'progn + (loop for (code-point . script) + in '((#x0660 . "Arabic-Indic") + (#x06f0 . "Extended Arabic-Indic") + (#x07c0 . "Nko") + (#x0966 . "Devanagari") + (#x09e6 . "Bengali") + (#x0a66 . "Gurmukhi") + (#x0ae6 . "Gujarati") + (#x0b66 . "Oriya") + (#x0be6 . "Tamil") + (#x0c66 . "Telugu") + (#x0ce6 . "Kannada") + (#x0d66 . "Malayalam") + (#x0de6 . "Sinhala Lith") + (#x0e50 . "Thai") + (#x0ed0 . "Lao") + (#x0f20 . "Tibetan") + (#x1040 . "Myanmar") + (#x1090 . "Myanmar Shan") + (#x17e0 . "Khmer") + (#x1810 . "Mongolian") + (#x1946 . "Limbu") + (#x19d0 . "New Tai Lue") + (#x1a80 . "Tai Tham Hora") + (#x1a90 . "Tai Tham Tham") + (#x1b50 . "Balinese") + (#x1bb0 . "Sundanese") + (#x1c40 . "Lepcha") + (#x1c50 . "Ol Chiki") + (#xa620 . "Vai") + (#xa8d0 . "Saurashtra") + (#xa900 . "Kayah Li") + (#xa9d0 . "Javanese") + (#xa9f0 . "Myanmar Tai Laing") + (#xaa50 . "Cham") + (#xabf0 . "Meetei Mayek") + (#xff10 . "Fullwidth") + (#x000104a0 . "Osmanya") + (#x00011066 . "Brahmi") + (#x000110f0 . "Sora Sompeng") + (#x00011136 . "Chakma") + (#x000111d0 . "Sharada") + (#x000112f0 . "Khudawadi") + (#x000114d0 . "Tirhuta") + (#x00011650 . "Modi") + (#x000116c0 . "Takri") + (#x000118e0 . "Warang Citi") + (#x00016a60 . "Mro") + (#x00016b50 . "Pahawh Hmong") + (#x0001d7ce . "Mathematical Bold") + (#x0001d7d8 . "Mathematical Double-Struck") + (#x0001d7e2 . "Mathematical Sans-Serif") + (#x0001d7ec . "Mathematical Sans-Serif Bold") + (#x0001d7f6 . "Mathematical Monospace")) + collect + (list* 'with-digits "0123456789" + ;; All the Unicode decimal digits have contiguous code + ;; point ranges as documented by the Unicode standard, + ;; we can just increment. + (concat (loop for fixnum from code-point + to (+ code-point 9) + collect (decode-char 'ucs fixnum)) + "") + body))))))) + (with-all-digits + (Assert-reading-rationals + (t 1 "1" "#b1" "#o1" "#x1" "#2r1" "#20r1" "#2000r1") + (t 0 "-0" "#b0" "#o0" "#x0" "#1r0" "#2r0" "#20r0" "#2000r0") + (t -1 "-1" "#b-1" "#o-1" "#x-1" "#2r-1" "#20r-1" "#2000r-1") + (t 1073741823 "#b111111111111111111111111111111" "#o7777777777" + "#x3fffffff" "#32rVVVVVV") + (t -1073741824 "#b-1000000000000000000000000000000" "#o-10000000000" + "#x-40000000" "#32r-1000000") + ((featurep 'ratio) + 1 "1/1" "2/2" "#b1/1" "#o2/2" "#x3/3" "#2r1/1" "#20r2000/2000") + ((featurep 'ratio) + -1 "-1/1" "-2/2" "#b-1/1" "#o-2/2" "#x-3/3" "#2r-1/1" + "#20r-2000/2000")) + (Check-Error invalid-read-syntax (read "1234567/0")) + (Check-Error invalid-read-syntax (read "#x1234567/0")) + (Check-Error invalid-read-syntax (read "#20000r1234567/0")) + ;; Unintuitive, but that's the Common Lisp behaviour. Maybe we should + ;; error. + (Assert (symbolp (read "1234/-123"))))) + +;;; end of lisp-reader-tests.el