Commits

Sven Hager  committed 0f061a5

implement W_SingleFloatNoNA vector class

  • Participants
  • Parent commits 4472f55

Comments (0)

Files changed (7)

File rapydo/objspace/objspace.py

                                     W_AbstractFloatVector, W_AbstractComplexVector, 
                                     W_AbstractStringVector, W_SingleFloat, 
                                     W_SingleComplex, abstracts, NA_BOOL,
-                                    W_MultipleFloatsNoNA, W_LazyVector)
+                                    W_MultipleFloatsNoNA, W_LazyVector,
+                                    W_SingleFloatNoNA)
 from rapydo.objspace.objmodel import (W_Symbol,
                                       W_Missing, W_Pairlist, W_Call,
                                       W_Promise,
     def float_single(self, floatval, w_attrs=None):
         return W_SingleFloat(floatval, self, w_attrs)
 
+    def float_single_no_na(self, floatval, w_attrs=None):
+        return W_SingleFloatNoNA(floatval, self, w_attrs)
+
     def float_vector(self, floatvals, w_attrs=None):
         return W_AbstractFloatVector.factory(floatvals, self, w_attrs)
 

File rapydo/objspace/test/test_objspace.py

 import py
 from rapydo.objspace.objspace import ObjSpace, abstract_to_type
 from rapydo.objspace.environment import W_Environment
-from rapydo.test.helper import bv, iv, sv, fv
+from rapydo.test.helper import bv, iv, sv, fv, sfn, is_fvn
 import rapydo.objspace.types as types
 from rapydo.objspace.vector import (W_AbstractBoolVector, W_AbstractIntVector,
                                     W_AbstractFloatVector, W_AbstractComplexVector,
         imports, exports = space.parse_namespace(namespace)
         assert imports == {"a": None, "abc": None, "e": None}
         assert exports == {}
+
+
+
+
+# --------------- misc -------------------
+
+def test_float_single_no_na():
+    space = ObjSpace()
+    w_res = space.float_single_no_na(1) 
+    assert w_res == sfn(1)
+    assert is_fvn(w_res)

File rapydo/objspace/test/test_vector.py

 import py
 from rapydo.test.helper import (bv, iv, fv, cv, sv, sb, si, 
                                 sf, sc, ss, null, iterate, fvn,
-                                lv)
+                                lv, sfn, is_fvn)
 from rapydo.objspace.vector     import (NA_INT, INF_FLOAT, NAN_FLOAT, NEG_INF_FLOAT,
                                         NA_BOOL, NA_FLOAT, is_na_float, NA_COMPLEX,
                                         NA_STRING, is_na_complex, W_LazyVector,
-                                        make_opleaf, TO)
+                                        make_opleaf, TO, W_AbstractFloatVector,
+                                        W_AbstractFloatVectorNoNA,
+                                        W_SingleFloatNoNA, W_MultipleFloatsNoNA)
 from rapydo.objspace.objspace import ObjSpace
 from rapydo.objspace.types import (NULLTYPE, BOOLTYPE, INTTYPE, FLOATTYPE,
                                    FLOATTYPE_NO_NA, COMPLEXTYPE)
         assert w_v.coerce_complex() == cv((1, 0), (2, 0))
         assert isinstance(w_v.coerce_string(), W_MultipleStrings)
 
+    # --- introduction of W_AbstractFloatVectorNoNA and W_SingleFloatNoNA ---
+
+    def test_class_structure(self):
+        assert W_AbstractFloatVectorNoNA.__mro__[1] == W_AbstractFloatVector
+        assert W_MultipleFloatsNoNA.__mro__[1] == W_AbstractFloatVectorNoNA
+        assert W_SingleFloatNoNA.__mro__[1] == W_AbstractFloatVectorNoNA
+
+    def test_W_SingleFloatNoNA_init(self):
+        w_s = W_SingleFloatNoNA(1, None)
+        assert w_s.value == 1
+        assert w_s.space is None
+
+    def test_get_type(self):
+        assert sfn(1).get_type() == FLOATTYPE_NO_NA 
+        assert fvn(1, 2).get_type() == FLOATTYPE_NO_NA
+
+    def test_W_AbstractFloatVectorNoNA_factory(self):
+        w_res = W_AbstractFloatVectorNoNA.factory([1], space)
+        assert w_res == sfn(1)
+        assert is_fvn(w_res)
+
+        w_res = W_AbstractFloatVectorNoNA.factory([1, 2], space)
+        assert w_res == fvn(1, 2)
+        assert is_fvn(w_res)
+
+    def test_W_SingleFloatNoNA_add(self):
+        w_res = sfn(1).add(sfn(2))
+        assert w_res == sfn(3)
+        assert is_fvn(w_res)
+
+        w_res = sfn(1).add(sf(2))
+        assert w_res == sf(3)
+        assert not is_fvn(w_res)
+
+        w_res = sf(1).add(sfn(2))
+        assert w_res == sf(3)
+        assert not is_fvn(w_res)
+
+        w_res = sfn(1).add(iv(2, 3))
+        assert w_res == fv(3, 4)
+        assert not is_fvn(w_res)
+
+        w_res = iv(2, 3).add(sfn(1))
+        assert w_res == fv(3, 4)
+        assert not is_fvn(w_res)
+
+        w_res = fvn(2, 3).add(sfn(1))
+        assert w_res == fvn(3, 4)
+        assert is_fvn(w_res)
+
+        w_res = sfn(1).add(fvn(2, 3))
+        assert w_res == fvn(3, 4)
+        assert is_fvn(w_res)
+
+    def test_W_SingleFloatNoNA_sub(self):
+        w_res = sfn(1).sub(sfn(2))
+        assert w_res == sfn(-1)
+        assert is_fvn(w_res)
+
+        w_res = sfn(1).sub(sf(2))
+        assert w_res == sf(-1)
+        assert not is_fvn(w_res)
+
+        w_res = sf(1).sub(sfn(2))
+        assert w_res == sf(-1)
+        assert not is_fvn(w_res)
+
+        w_res = sfn(1).sub(iv(2, 3))
+        assert w_res == fv(-1, -2)
+        assert not is_fvn(w_res)
+
+        w_res = iv(2, 3).sub(sfn(1))
+        assert w_res == fv(1, 2)
+        assert not is_fvn(w_res)
+
+        w_res = fvn(2, 3).sub(sfn(1))
+        assert w_res == fvn(1, 2)
+        assert is_fvn(w_res)
+
+        w_res = sfn(1).sub(fvn(2, 3))
+        assert w_res == fvn(-1, -2)
+        assert is_fvn(w_res)
+
+    def test_W_SingleFloatNoNA_mul(self):
+        w_res = sfn(1).mul(sfn(2))
+        assert w_res == sfn(2)
+        assert is_fvn(w_res)
+
+        w_res = sfn(1).mul(sf(2))
+        assert w_res == sf(2)
+        assert not is_fvn(w_res)
+
+        w_res = sf(1).mul(sfn(2))
+        assert w_res == sf(2)
+        assert not is_fvn(w_res)
+
+        w_res = sfn(1).mul(iv(2, 3))
+        assert w_res == fv(2, 3)
+        assert not is_fvn(w_res)
+
+        w_res = iv(2, 3).mul(sfn(1))
+        assert w_res == fv(2, 3)
+        assert not is_fvn(w_res)
+
+        w_res = fvn(2, 3).mul(sfn(1))
+        assert w_res == fvn(2, 3)
+        assert is_fvn(w_res)
+
+        w_res = sfn(1).mul(fvn(2, 3))
+        assert w_res == fvn(2, 3)
+        assert is_fvn(w_res)
+
+    def test_W_SingleFloatNoNA_div(self):
+        w_res = sfn(2).div(sfn(1))
+        assert w_res == sfn(2)
+        assert is_fvn(w_res)
+
+        w_res = sfn(1).div(sf(2))
+        assert w_res == sf(0.5)
+        assert not is_fvn(w_res)
+
+        w_res = sf(1).div(sfn(2))
+        assert w_res == sf(0.5)
+        assert not is_fvn(w_res)
+
+        w_res = sfn(1).div(iv(2, 3))
+        assert w_res == fv(0.5, 1.0/3)
+        assert not is_fvn(w_res)
+
+        w_res = iv(2, 3).div(sfn(1))
+        assert w_res == fv(2, 3)
+        assert not is_fvn(w_res)
+
+        w_res = fvn(2, 3).div(sfn(1))
+        assert w_res == fvn(2, 3)
+        assert is_fvn(w_res)
+
+        w_res = sfn(1).div(fvn(2, 3))
+        assert w_res == fvn(0.5, 1.0/3)
+        assert is_fvn(w_res)
+
+    def test_W_SingleFloatNoNA_pow(self):
+        w_res = sfn(2).pow_(sfn(3))
+        assert w_res == sfn(8)
+        assert is_fvn(w_res)
+
+        w_res = sfn(2).pow_(sf(3))
+        assert w_res == sf(8)
+        assert not is_fvn(w_res)
+
+        w_res = sf(2).pow_(sfn(3))
+        assert w_res == sf(8)
+        assert not is_fvn(w_res)
+
+        w_res = sfn(1).pow_(iv(2, 3))
+        assert w_res == fv(1, 1)
+        assert not is_fvn(w_res)
+
+        w_res = iv(2, 3).pow_(sfn(1))
+        assert w_res == fv(2, 3)
+        assert not is_fvn(w_res)
+
+        w_res = fvn(2, 3).pow_(sfn(1))
+        assert w_res == fvn(2, 3)
+        assert is_fvn(w_res)
+
+        w_res = sfn(1).pow_(fvn(2, 3))
+        assert w_res == fvn(1, 1)
+        assert is_fvn(w_res)
+
+    def test_W_SingleFloatNoNA_and_NULL_arithmetic(self):
+        w_res = sfn(1).add(null())
+        assert w_res == fv()
+        assert is_fvn(w_res)
+
+        w_res = null().add(sfn(1))
+        assert w_res == fv()
+        assert is_fvn(w_res)
+
+    def test_assignment_to_W_SingleFloatNoNA(self):
+        w_res = sfn(1).index_assign(si(2), sfn(3), mutate=False)
+        assert w_res == fvn(1, 3)
+        assert is_fvn(w_res)
+
+        w_res = sfn(1).index_assign(si(2), sf(3), mutate=False)
+        assert w_res == fv(1, 3)
+        assert not is_fvn(w_res)
+
+    def test_assign_W_SingleFloatNoNA_to_W_MultipleFloatsNoNA(self):
+        w_res = fvn(1, 2, 3).index_assign(si(2), sfn(5), mutate=False)
+        assert w_res == fvn(1, 5, 3)
+        assert is_fvn(w_res)
+
+        w_left = fvn(1, 2, 3)
+        w_res = w_left.index_assign(si(2), sfn(5), mutate=True)
+        assert w_res == fvn(1, 5, 3)
+        assert is_fvn(w_res)
+        assert w_res is w_left
+
+    def test_W_SingleFloatNoNA_not(self):
+        assert sfn(1).not_() == sb(0)
+        assert sfn(-1).not_() == sb(0)
+        assert sfn(0).not_() == sb(1)
+
+    def test_W_SingleFloatsNoNA_unary_minus(self):
+        w_res = sfn(1).unary_minus()
+        assert w_res == sfn(-1)
+        assert is_fvn(w_res)
 
 ###########################################################
 ##################### L A Z Y N E S S #####################

File rapydo/objspace/vector.py

             currlen += addlen
         return "".join(buff)
 
+class W_AbstractFloatVectorNoNA(W_AbstractFloatVector):
+
+    @staticmethod
+    def factory(values, space, w_attrs=None):
+        if len(values) == 1:
+            return W_SingleFloatNoNA(values[0], space, w_attrs)
+        return W_MultipleFloatsNoNA(values, space, w_attrs)
+    
+    def get_type(self):
+        return FLOATTYPE_NO_NA
+
+    def to_bool(self, value):
+        if isnan(value):
+            return NA_BOOL
+        if value == 0:
+            return 0
+        return 1
+
+    def to_int(self, value):
+        if isnan(value):
+            return NA_INT
+        return int(value)
+
+    def to_complex(self, value):
+        if isnan(value):
+            return NA_COMPLEX
+        return (value, 0.0)
+
+    def to_string(self, value):
+        if isnan(value):
+            return "NaN"
+        s = "%f" % value
+        return s.rstrip("0")
+
+    def is_na(self):
+        return False
+
 class W_AbstractComplexVector(W_NonNullVector):
     default = (0.0, 0.0)
     NA = (W_AbstractFloatVector.NA, 0.0)
             return "%d" % intval
         return "%f" % self.value
 
+class W_SingleFloatNoNA(W_AbstractFloatVectorNoNA):
+
+    def get_float_no_na_value(self, i):
+        return self.value
+
+    def coerce_float(self):
+        return W_SingleFloatNoNA(self.value, self.space, self.w_attrs)
+
+    def not_(self):
+        if self.value == 0:
+            return self.space.w_TRUE
+        return self.space.w_FALSE
+
+    def unary_minus(self):
+        return W_SingleFloatNoNA(-self.value, self.space, self.w_attrs)
+
+    def str(self):
+        intval = int(self.value)
+        if abs(intval - self.value) == 0:
+            return "%d" % intval
+        return "%f" % self.value
+
 class W_SingleComplex(W_AbstractComplexVector):
     
     _immutable_fields_ = ["value"]
                 l[i] = 0 if self.values[i] != 0 else 1
         return self.space.bool_vector(l)
 
-class W_MultipleFloatsNoNA(W_AbstractFloatVector):
+class W_MultipleFloatsNoNA(W_AbstractFloatVectorNoNA):
 
-    @staticmethod
-    def factory(values, space, w_attrs=None):
-        if len(values) == 1:
-            return W_SingleFloat(values[0], space, w_attrs)
-        return W_MultipleFloatsNoNA(values, space, w_attrs)
-
-    def get_type(self):
-        return FLOATTYPE_NO_NA
-    
     def istrue(self):
         return self.get_first_float() != 0
 
             l[i] = 0 if self.values[i] != 0 else 1
         return self.space.bool_vector(l)
 
-    def to_bool(self, value):
-        if isnan(value):
-            return NA_BOOL
-        if value == 0:
-            return 0
-        return 1
-
-    def to_int(self, value):
-        if isnan(value):
-            return NA_INT
-        return int(value)
-
-    def to_complex(self, value):
-        if isnan(value):
-            return NA_COMPLEX
-        return (value, 0.0)
-
-    def to_string(self, value):
-        if isnan(value):
-            return "NaN"
-        s = "%f" % value
-        return s.rstrip("0")
-
-    def is_na(self):
-        return False
-
     def get_float_no_na_value(self, i):
         return self.values[i]
 
     BOOLTYPE:           W_AbstractBoolVector,
     INTTYPE:            W_AbstractIntVector,
     FLOATTYPE:          W_AbstractFloatVector,
-    FLOATTYPE_NO_NA:    W_MultipleFloatsNoNA,
+    FLOATTYPE_NO_NA:    W_AbstractFloatVectorNoNA,
     COMPLEXTYPE:        W_AbstractComplexVector,
     STRINGTYPE:         W_AbstractStringVector,
 }
     W_AbstractFloatVector:      FLOATTYPE,
     W_AbstractComplexVector:    COMPLEXTYPE,
     W_AbstractStringVector:     STRINGTYPE,
-    W_MultipleFloatsNoNA:       FLOATTYPE_NO_NA
+    W_MultipleFloatsNoNA:       FLOATTYPE_NO_NA,
+    W_SingleFloatNoNA:          FLOATTYPE_NO_NA
 }
 
 type_to_singles_and_multiples = {
 %s.coerce_%s = coerce_%s
 """
 
-for W_class in singles:
+for W_class in singles + [W_SingleFloatNoNA]:
     for W_class_2 in singles:
+        # for non-NA floats ...
+        if W_class == W_SingleFloatNoNA and W_class_2 == W_SingleFloat:
+            continue
         to_type = class_to_type[W_class_2.__mro__[1]]
         to_name = W_class_2.__name__
         from_name = W_class.__name__
 %(klass)s.is_writesafe = is_writesafe
 """
 
-for W_class, _type in zip(singles + multiples + [W_MultipleFloatsNoNA],
-                          types * 2 + [FLOATTYPE]):
-    if W_class in singles:
-        def __init__(self, value, space, w_attrs=None):
-            self.value = value
-            self.refcount = 0
-            W_Object.__init__(self, space, w_attrs)
-
+for W_class, _type in zip(singles + multiples + [W_SingleFloatNoNA, W_MultipleFloatsNoNA],
+                          types * 2 + [FLOATTYPE, FLOATTYPE]):
+    if W_class in singles or W_class == W_SingleFloatNoNA:
         def length(self):
             return 1
 
+        if W_class == W_SingleFloatNoNA:
+            def __init__(self, value, space, w_attrs=None):
+                if not we_are_translated():
+                    assert not is_na_float(value)
+                self.value = value
+                W_Object.__init__(self, space, w_attrs)
+        else:
+            def __init__(self, value, space, w_attrs=None):
+                self.value = value
+                W_Object.__init__(self, space, w_attrs)
+
         klass = W_class.__name__
         # define conversion
         for t in types:
         if W_class == W_SingleFloat:
             def __eq__(self, other):
                 """ NOT_RPYTHON """
-                assert isinstance(other, self.__class__)
+                assert isinstance(other, self.__class__)\
+                        or isinstance(other, W_SingleFloatNoNA)
+                if is_nan_float(self.value):
+                    if is_na_float(self.value):
+                        return is_na_float(float(other.value))
+                    return is_nan_float(float(other.value))
+                return self.value == other.value
+
+        elif W_class == W_SingleFloatNoNA:
+            def __eq__(self, other):
+                """ NOT_RPYTHON """
+                assert isinstance(other, self.__class__)\
+                        or isinstance(other, W_SingleFloat)
                 if is_nan_float(self.value):
                     if is_na_float(self.value):
                         return is_na_float(float(other.value))
     def f(w_arg1, w_arg2):
         if is_cmp:
             return w_arg1.get_space().bool_vector([])
-        return w_arg1.get_space().float_vector([])
+        return w_arg1.get_space().float_no_na_vector([])
     return f
 
 COMPLEX_MSG = "Comparison of complex numbers is not defined"
             setattr(W_class, "%s_%s" % (op, _type), method)
 
 # specialcase: non-NA float vectors
-for op in ["add", "sub", "mul", "div", "pow_"]:
-    exec_list.append(arith_func_str % (op, op, FLOATTYPE_NO_NA,
-            "W_MultipleFloatsNoNA", op, op))
-    for _type in types[:-1] + [NULLTYPE, FLOATTYPE_NO_NA]:
-        method = arith_func(op, FLOATTYPE_NO_NA, _type)
-        setattr(W_MultipleFloatsNoNA, "%s_%s" % (op, _type), method)
+for W_no_na_class in [W_SingleFloatNoNA, W_MultipleFloatsNoNA]:
+    for op in ["add", "sub", "mul", "div", "pow_"]:
+        exec_list.append(arith_func_str % (op, op, FLOATTYPE_NO_NA,
+                W_no_na_class.__name__, op, op))
+        for _type in types[:-1] + [NULLTYPE, FLOATTYPE_NO_NA]:
+            method = arith_func(op, FLOATTYPE_NO_NA, _type)
+            setattr(W_no_na_class, "%s_%s" % (op, _type), method)
 
-    for W_class in [W_AbstractBoolVector, W_AbstractIntVector,
-                    W_AbstractFloatVector, W_AbstractComplexVector,
-                    W_Null]:
-        method = getattr(W_class, "%s_float" % op)
-        setattr(W_class, "%s_%s" % (op, FLOATTYPE_NO_NA), method)
+        for W_class in [W_AbstractBoolVector, W_AbstractIntVector,
+                        W_AbstractFloatVector, W_AbstractComplexVector,
+                        W_Null]:
+            method = getattr(W_class, "%s_float" % op)
+            setattr(W_class, "%s_%s" % (op, FLOATTYPE_NO_NA), method)
 
-for W_class in abstracts + [W_Null, W_MultipleFloatsNoNA]:
+for W_class in abstracts + [W_Null, W_SingleFloatNoNA, W_MultipleFloatsNoNA]:
     type1 = class_to_type[W_class]
     exec_list.append(index_assign_str % 
             {"type": type1, "klass": W_class.__name__})

File rapydo/parser/parser.py

             src = self._kill_int_qualifier(src)
             floatval = float(src)
             if int(floatval) != floatval:
-                return self.space.float_single(floatval)
+                return self.space.float_single_no_na(floatval)
             intval = int(src)
             return self.space.int_single(intval)
         else:
             floatval = float(src)
-            return self.space.float_single(floatval)
+            return self.space.float_single_no_na(floatval)
  
     def _kill_int_qualifier(self, s):
         if s.endswith("L"):

File rapydo/test/helper.py

                                     W_SingleInt, W_SingleFloat,
                                     W_SingleComplex, W_SingleString,
                                     W_MultipleFloatsNoNA, is_na_float,
-                                    W_LazyVector)
+                                    W_LazyVector, W_SingleFloatNoNA,
+                                    W_AbstractFloatVectorNoNA)
 from rapydo.objspace.objspace import ObjSpace
 from rapydo.objspace.objmodel import W_Symbol, W_Missing
 from rapydo.objspace.environment import W_Environment
     return W_MultipleFloatsNoNA([float(x) for x in floatlist], ObjSpace())
 
 def is_fvn(w_vector):
-    return isinstance(w_vector, W_MultipleFloatsNoNA)
+    return isinstance(w_vector, W_AbstractFloatVectorNoNA)
 
 def cv(*complexlist):
     return W_MultipleComplex([(float(a), float(b)) for a, b in complexlist],
 def sf(arg):
     return W_SingleFloat(float(arg), ObjSpace())
 
+def sfn(arg):
+    return W_SingleFloatNoNA(float(arg), ObjSpace())
+
 def sc(real, imag):
     return W_SingleComplex((float(real), float(imag)), ObjSpace())
 

File rapydo/test/test_interpreter.py

 from rapydo.primitive import (Primitive, ReturnException, ForLoopError, 
                               UseMethodNoDefaultError, NextMethodError,
                               NO_METHOD, StopError)
-from rapydo.test.helper import iv, bv, sv, sf, fv, env, s, l
+from rapydo.test.helper import iv, bv, sv, sf, fv, env, s, l, sfn, is_fvn, fvn
 from rapydo.objspace.list import W_List
 from rapydo.interpreter import DotSymbolInterpError
 from rapydo.path import RAPYDO_PATH
     def test_empty_program(self):
         self.interpret_and_check("", [])
 
+    def test_float_no_na_single(self):
+        src = """
+            x <- 1
+            y <- c(1, 2, x)
+            z <- c(1, 2, 3)
+            z[2] <- x
+        """
+        self.interpret_and_check(src, [], new_builtin=False)
+        w_x = self.w_env.get_obj("x")
+        w_y = self.w_env.get_obj("y")
+        w_z = self.w_env.get_obj("z")
+        assert w_x == sfn(1)
+        assert is_fvn(w_x)
+
+        assert w_y == fvn(1, 2, 1)
+        assert is_fvn(w_y)
+
+        assert w_z == fvn(1, 1, 3)
+        assert is_fvn(w_z)
+
 class TestScoping(TestParseAndInterpret):
 
     def test_basic_scope(self):