BulletML.FromDocument: Type detector. Various setstate bug fixes.
[python-bulletml.git] / bulletml / expr.py
index 3c80b06..a00c99e 100644 (file)
@@ -37,34 +37,44 @@ class NumberDef(object):
             expr = expr.string
         except AttributeError:
             pass
-        self.string = expr
+        self.string = expr = str(expr)
         repl = lambda match: "params[%d]" % (int(match.group()[1:]) - 1)
         expr = re.sub(r"\$\d+", repl, expr.lower())
         self.__expr = expr.replace("$rand", "random()").replace("$rank", "rank")
         try:
             try:
-                self.__value = eval(self.__expr, dict(__builtins__={}))
+                self._value = eval(self.__expr, dict(__builtins__={}))
             except NameError:
                 variables = dict(rank=1, params=[0] * 99)
                 value = eval(self.__expr, self.GLOBALS, variables)
                 if not isinstance(value, (int, float)):
                     raise TypeError(expr)
-                self.__value = None
+                self._value = None
+                self.expr = self.string
+            else:
+                self.expr = self._value
         except Exception:
             raise ExprError(expr)
         self.__expr = compile(self.__expr, __file__, "eval")
 
     def __call__(self, params, rank):
         """Evaluate the expression and return its value."""
-        if self.__value is not None:
-            return self.__value
+        if self._value is not None:
+            return self._value
         variables = { 'rank': rank, 'params': params }
         return eval(self.__expr, self.GLOBALS, variables)
 
     def __repr__(self):
-        return "%s(%r)" % (type(self).__name__, self.string)
+        return "%s(%r)" % (type(self).__name__, self.expr)
 
 class INumberDef(NumberDef):
     """A NumberDef, but returns rounded integer results."""
+    def __init__(self, expr):
+        super(INumberDef, self).__init__(expr)
+        if self._value is not None:
+            self._value = int(round(self._value))
+
     def __call__(self, params, rank):
+        if self._value is not None:
+            return self._value
         return int(round(super(INumberDef, self).__call__(params, rank)))