[pypy-svn] r45036 - in pypy/dist/pypy/lang/scheme: . test

jlg at codespeak.net jlg at codespeak.net
Fri Jul 13 18:12:00 CEST 2007


Author: jlg
Date: Fri Jul 13 18:12:00 2007
New Revision: 45036

Modified:
   pypy/dist/pypy/lang/scheme/object.py
   pypy/dist/pypy/lang/scheme/test/test_eval.py
Log:
WrongArgType exception; number, float, fixnum refactoring -> r5rs; number predicates

Modified: pypy/dist/pypy/lang/scheme/object.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/object.py	(original)
+++ pypy/dist/pypy/lang/scheme/object.py	Fri Jul 13 18:12:00 2007
@@ -11,6 +11,10 @@
     def __str__(self):
         return "Wrong number of args"
 
+class WrongArgType(SchemeException):
+    def __str__(self):
+        return "Wrong argument type"
+
 class SchemeQuit(SchemeException):
     """raised on (quit) evaluation"""
     pass
@@ -86,43 +90,56 @@
     def __repr__(self):
         return "<W_String " + self.strval + " >"
 
-class W_Fixnum(W_Root):
+class W_Number(W_Root):
+    pass
+
+class W_Float(W_Number):
     def __init__(self, val):
-        self.fixnumval = val
+        self.exact = False
+        self.floatval = val
 
     def to_string(self):
-        return str(self.fixnumval)
+        return str(self.floatval)
 
     def to_number(self):
-        return self.to_fixnum()
+        return self.to_float()
 
     def to_fixnum(self):
-        return self.fixnumval
+        return int(self.floatval)
 
     def to_float(self):
-        return float(self.fixnumval)
+        return self.floatval
+
+    def round(self):
+        int_part = int(self.floatval)
+        if self.floatval > 0:
+            if self.floatval >= (int_part + 0.5):
+                return int_part + 1
+
+            return int_part
 
-    def equal(self, w_obj):
-        return self.fixnumval == w_obj.to_number()
+        else:
+            if self.floatval <= (int_part - 0.5):
+                return int_part - 1
+
+            return int_part
 
-class W_Float(W_Root):
+class W_Fixnum(W_Float):
     def __init__(self, val):
-        self.floatval = val
+        self.fixnumval = val
+        self.exact = True
 
     def to_string(self):
-        return str(self.floatval)
+        return str(self.fixnumval)
 
     def to_number(self):
-        return self.to_float()
+        return self.to_fixnum()
 
     def to_fixnum(self):
-        return int(self.floatval)
+        return self.fixnumval
 
     def to_float(self):
-        return self.floatval
-
-    def equal(self, w_obj):
-        return self.floatval == w_obj.to_number()
+        return float(self.fixnumval)
 
 class W_Pair(W_Root):
     def __init__(self, car, cdr):
@@ -260,16 +277,16 @@
         return acc
 
     def unary_oper(self, x):
-        if isinstance(x, W_Float):
-            return W_Float(self.do_unary_oper(x.to_float()))
-        else:
+        if isinstance(x, W_Fixnum):
             return W_Fixnum(self.do_unary_oper(x.to_fixnum()))
+        else:
+            return W_Float(self.do_unary_oper(x.to_float()))
 
     def oper(self, x, y):
-        if isinstance(x, W_Float) or isinstance(y, W_Float):
-            return W_Float(self.do_oper(x.to_float(), y.to_float()))
-        else:
+        if isinstance(x, W_Fixnum) and isinstance(y, W_Fixnum):
             return W_Fixnum(self.do_oper(x.to_fixnum(), y.to_fixnum()))
+        else:
+            return W_Float(self.do_oper(x.to_float(), y.to_float()))
 
 def create_op_class(oper, unary_oper, title, default_result=None):
     class Op(ListOper):
@@ -317,6 +334,7 @@
 
         prev = lst[0]
         for arg in lst[1:]:
+            assert isinstance(arg, W_Number)
             if prev.to_number() != arg.to_number():
                 return W_Boolean(False)
             prev = arg
@@ -327,6 +345,45 @@
     def procedure(self, ctx, lst):
         return plst2lst(lst)
 
+##
+# Predicate
+##
+class PredicateNumber(W_Procedure):
+    def procedure(self, ctx, lst):
+        if len(lst) != 1:
+            raise WrongArgsNumber
+
+        if not isinstance(lst[0], W_Number):
+            raise WrongArgType
+
+        return W_Boolean(self.predicate(lst[0]))
+
+class IntegerP(PredicateNumber):
+    def predicate(self, w_obj):
+        if not w_obj.exact:
+            return w_obj.to_float() == w_obj.round()
+
+        return True
+
+class RealP(PredicateNumber):
+    def predicate(self, w_obj):
+        return isinstance(w_obj, W_Float)
+
+class NumberP(PredicateNumber):
+    def predicate(self, w_obj):
+        return isinstance(w_obj, W_Number)
+
+class ExactP(PredicateNumber):
+    def predicate(self, w_obj):
+        return w_obj.exact
+
+class InexactP(PredicateNumber):
+    def predicate(self, w_obj):
+        return not w_obj.exact
+
+##
+# Macro
+##
 class Define(W_Macro):
     def call(self, ctx, lst):
         w_identifier = lst.car
@@ -456,6 +513,14 @@
         'quit': Quit,
             #comparisons
         '=': Equal,
+            #predicates
+        'integer?': IntegerP,
+        'rational?': RealP,
+        'real?': RealP,
+        'complex?': NumberP,
+        'number?': NumberP,
+        'exact?': ExactP,
+        'inexact?': InexactP,
             #macros
         'define': Define,
         'set!': Sete,

Modified: pypy/dist/pypy/lang/scheme/test/test_eval.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/test/test_eval.py	(original)
+++ pypy/dist/pypy/lang/scheme/test/test_eval.py	Fri Jul 13 18:12:00 2007
@@ -377,3 +377,29 @@
 def test_quit():
     py.test.raises(SchemeQuit, eval_noctx, "(quit)")
 
+def test_numbers():
+    assert eval_noctx("(integer? 42)").to_boolean()
+    assert eval_noctx("(integer? 42.0)").to_boolean()
+    assert not eval_noctx("(integer? 42.1)").to_boolean()
+
+    assert eval_noctx("(rational? 42)").to_boolean()
+    assert eval_noctx("(rational? 42.1)").to_boolean()
+
+    assert eval_noctx("(real? 42)").to_boolean()
+    assert eval_noctx("(real? 42.1)").to_boolean()
+
+    assert eval_noctx("(complex? 42)").to_boolean()
+    assert eval_noctx("(complex? 42.1)").to_boolean()
+
+    assert eval_noctx("(number? 42)").to_boolean()
+    assert eval_noctx("(number? 42.1)").to_boolean()
+
+    py.test.raises(WrongArgType, eval_noctx, "(number? 'a)" )
+
+def test_exactness():
+    assert eval_noctx("(exact? 42)").to_boolean()
+    assert not eval_noctx("(exact? 42.0)").to_boolean()
+
+    assert not eval_noctx("(inexact? 42)").to_boolean()
+    assert eval_noctx("(inexact? 42.0)").to_boolean()
+



More information about the Pypy-commit mailing list