From 2e1e64f1f8076dd21a5ea1e7f8af6dbb74946d57 Mon Sep 17 00:00:00 2001 From: Joe Wreschnig Date: Sun, 14 Mar 2010 22:46:54 -0700 Subject: [PATCH] Expression evaluator. --- bulletml/__init__.py | 0 bulletml/errors.py | 3 +++ bulletml/expr.py | 64 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 bulletml/__init__.py create mode 100644 bulletml/errors.py create mode 100644 bulletml/expr.py diff --git a/bulletml/__init__.py b/bulletml/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bulletml/errors.py b/bulletml/errors.py new file mode 100644 index 0000000..16b7106 --- /dev/null +++ b/bulletml/errors.py @@ -0,0 +1,3 @@ +class Error(Exception): + pass + diff --git a/bulletml/expr.py b/bulletml/expr.py new file mode 100644 index 0000000..8022476 --- /dev/null +++ b/bulletml/expr.py @@ -0,0 +1,64 @@ +"""BulletML expression evaluator. + +http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/index_e.html +""" + +# BulletML assumes 1/2 = 0.5. +from __future__ import division + +import random +import re + +from bulletml.errors import Error + +class ExprError(Error): + """Raised when an invalid expression is evaluated/compiled.""" + pass + +class NumberDef(object): + """BulletML numeric expression. + + This translates BulletML numeric expressions into Python expressions. + The + + Examples: + 35 + 360/16 + 0.7 + 0.9*$rand + 180-$rank*20 + (2+$1)*0.3 + + """ + def __init__(self, expr): + try: + expr = expr.__original + except AttributeError: + pass + self.__original = 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") + 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) + if not isinstance(value, (int, float)): + raise TypeError(expr) + self.__value = None + 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 + rand = random.random() + variables = dict(rand=rand, rank=rank, params=params) + return eval(self.__expr, variables) + + def __repr__(self): + return "%s(%r)" % (type(self).__name__, self.__original) -- 2.20.1