diff --git a/lumbda.py b/lumbda.py index c8a8d04..a6bcc92 100644 --- a/lumbda.py +++ b/lumbda.py @@ -399,12 +399,18 @@ def _atom(t): if t.startswith('"'): return (t[1:-1].replace('\\"', '"').replace('\\n', '\n') .replace('\\t', '\t').replace('\\\\', '\\').replace('\\r', '\r')) - for conv in (int, float): - try: return conv(t) - except (ValueError, OverflowError): pass + try: return int(t) + except (ValueError, OverflowError): pass + # Float parse: gate against Python's float() accepting bare 'inf', + # 'infinity', 'nan' as IEEE specials — R7RS spells those +inf.0 / + # -inf.0 / +nan.0 explicitly. Without this guard, '(infinity) reads + # as (+inf.0) and '(nan) reads as (+nan.0). if t == '+inf.0': return math.inf if t == '-inf.0': return -math.inf if t in ('+nan.0', '-nan.0'): return float('nan') + if re.fullmatch(r'[+-]?(\d+\.\d*|\.\d+|\d+)([eE][+-]?\d+)?', t): + try: return float(t) + except (ValueError, OverflowError): pass # Rational literal n/d (e.g. 1/3, -2/5) if re.fullmatch(r'-?\d+/-?\d+', t): try: @@ -2946,7 +2952,7 @@ def make_global_env(): n = float(n) / float(x) return n d(S('/'), _div) - d(S('quotient'), lambda a, _: int(_num(a[0]) / _num(a[1]))) + d(S('quotient'), lambda a, _: (lambda x, y: -(abs(int(x)) // abs(int(y))) if (x < 0) != (y < 0) else abs(int(x)) // abs(int(y)))(_num(a[0]), _num(a[1]))) d(S('remainder'), lambda a, _: int(_num(a[0])) % int(_num(a[1])) * (1 if _num(a[0]) >= 0 else -1)) d(S('modulo'), lambda a, _: int(_num(a[0])) % int(_num(a[1]))) d(S('expt'), lambda a, _: _num(a[0]) ** _num(a[1]))