385b31b5ab1d8fc1122d1f903f076a938876ba69
1 """BulletML expression evaluator.
3 http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/index_e.html
6 # BulletML assumes 1/2 = 0.5.
7 from __future__
import division
12 from bulletml
.errors
import Error
14 __all__
= ["ExprError", "NumberDef", "INumberDef"]
16 class ExprError(Error
):
17 """Raised when an invalid expression is evaluated/compiled."""
20 class NumberDef(object):
21 """BulletML numeric expression.
23 This translates BulletML numeric expressions into Python expressions.
34 GLOBALS
= dict(random
=random
.random
, __builtins__
={})
36 def __init__(self
, expr
):
39 except AttributeError:
41 self
.string
= expr
= str(expr
)
42 repl
= lambda match
: "params[%d]" % (int(match
.group()[1:]) - 1)
43 expr
= re
.sub(r
"\$\d+", repl
, expr
.lower())
44 self
.__expr
= expr
.replace("$rand", "random()").replace("$rank", "rank")
47 self
._value
= eval(self
.__expr
, dict(__builtins__
={}))
49 variables
= dict(rank
=1, params
=[0] * 99)
50 value
= eval(self
.__expr
, self
.GLOBALS
, variables
)
51 if not isinstance(value
, (int, float)):
54 self
.expr
= self
.string
56 self
.expr
= self
._value
59 self
.__expr
= compile(self
.__expr
, __file__
, "eval")
61 def __call__(self
, params
, rank
):
62 """Evaluate the expression and return its value."""
63 if self
._value
is not None:
65 variables
= { 'rank': rank
, 'params': params
}
66 return eval(self
.__expr
, self
.GLOBALS
, variables
)
69 return "%s(%r)" % (type(self
).__name
__, self
.expr
)
71 class INumberDef(NumberDef
):
72 """A NumberDef, but returns rounded integer results."""
73 def __init__(self
, expr
):
74 super(INumberDef
, self
).__init
__(expr
)
75 if self
._value
is not None:
76 self
._value
= int(round(self
._value
))
78 def __call__(self
, params
, rank
):
79 # Avoid int(round(__call__())) overhead for constants.
80 if self
._value
is not None:
82 return int(round(super(INumberDef
, self
).__call
__(params
, rank
)))