Separate element constructors from regular constructors.
[python-bulletml.git] / bulletml / expr.py
index 8022476..3c80b06 100644 (file)
@@ -29,22 +29,24 @@ class NumberDef(object):
     (2+$1)*0.3
 
     """
+
+    GLOBALS = dict(random=random.random, __builtins__={})
+
     def __init__(self, expr):
         try:
-            expr = expr.__original
+            expr = expr.string
         except AttributeError:
             pass
-        self.__original = expr
+        self.string = expr
         repl = lambda match: "params[%d]" % (int(match.group()[1:]) - 1)
         expr = re.sub(r"\$\d+", repl, expr.lower())
-        self.__expr = expr.replace("$rand", "rand").replace("$rank", "rank")
+        self.__expr = expr.replace("$rand", "random()").replace("$rank", "rank")
         try:
             try:
                 self.__value = eval(self.__expr, dict(__builtins__={}))
             except NameError:
-                fake = [0] * 99
-                variables = dict(rand=1, rank=1, params=fake, __builtins__={})
-                value = eval(self.__expr, variables)
+                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
@@ -56,9 +58,13 @@ class NumberDef(object):
         """Evaluate the expression and return its value."""
         if self.__value is not None:
             return self.__value
-        rand = random.random()
-        variables = dict(rand=rand, rank=rank, params=params)
-        return eval(self.__expr, variables)
+        variables = { 'rank': rank, 'params': params }
+        return eval(self.__expr, self.GLOBALS, variables)
 
     def __repr__(self):
-        return "%s(%r)" % (type(self).__name__, self.__original)
+        return "%s(%r)" % (type(self).__name__, self.string)
+
+class INumberDef(NumberDef):
+    """A NumberDef, but returns rounded integer results."""
+    def __call__(self, params, rank):
+        return int(round(super(INumberDef, self).__call__(params, rank)))