6666expressions .update (keywords )
6767
6868any_keyword = pp .MatchFirst (keywords .values ())
69+ # noinspection PyUnresolvedReferences
6970IN_RANGE_FROM = (IN + RANGE + FROM ).addParseAction ('_' .join )
71+ # noinspection PyUnresolvedReferences
7072TRUE .addParseAction (lambda : True )
73+ # noinspection PyUnresolvedReferences
7174FALSE .addParseAction (lambda : False )
7275
7376FunctionSpec = namedtuple ("FunctionSpec" , "method arity" )
7477
7578_numeric_type = (int , float , complex )
7679
7780# define special versions of lt, le, etc. to comprehend "is close"
78- _lt = lambda a , b , eps : a < b and not math .isclose (a , b , abs_tol = eps ) if isinstance (a , _numeric_type ) and isinstance (b , _numeric_type ) else a < b
79- _le = lambda a , b , eps : a <= b or math .isclose (a , b , abs_tol = eps ) if isinstance (a , _numeric_type ) and isinstance (b , _numeric_type ) else a <= b
80- _gt = lambda a , b , eps : a > b and not math .isclose (a , b , abs_tol = eps ) if isinstance (a , _numeric_type ) and isinstance (b , _numeric_type ) else a > b
81- _ge = lambda a , b , eps : a >= b or math .isclose (a , b , abs_tol = eps ) if isinstance (a , _numeric_type ) and isinstance (b , _numeric_type ) else a >= b
82- _eq = lambda a , b , eps : a == b or math .isclose (a , b , abs_tol = eps ) if isinstance (a , _numeric_type ) and isinstance (b , _numeric_type ) else a == b
83- _ne = lambda a , b , eps : not math .isclose (a , b , abs_tol = eps ) if isinstance (a , _numeric_type ) and isinstance (b , _numeric_type ) else a != b
81+ _lt = lambda a , b , eps : (a < b and not math .isclose (a , b , abs_tol = eps )
82+ if isinstance (a , _numeric_type ) and isinstance (b , _numeric_type ) else a < b )
83+ _le = lambda a , b , eps : (a <= b or math .isclose (a , b , abs_tol = eps )
84+ if isinstance (a , _numeric_type ) and isinstance (b , _numeric_type ) else a <= b )
85+ _gt = lambda a , b , eps : (a > b and not math .isclose (a , b , abs_tol = eps )
86+ if isinstance (a , _numeric_type ) and isinstance (b , _numeric_type ) else a > b )
87+ _ge = lambda a , b , eps : (a >= b or math .isclose (a , b , abs_tol = eps )
88+ if isinstance (a , _numeric_type ) and isinstance (b , _numeric_type ) else a >= b )
89+ _eq = lambda a , b , eps : (a == b or math .isclose (a , b , abs_tol = eps )
90+ if isinstance (a , _numeric_type ) and isinstance (b , _numeric_type ) else a == b )
91+ _ne = lambda a , b , eps : (not math .isclose (a , b , abs_tol = eps )
92+ if isinstance (a , _numeric_type ) and isinstance (b , _numeric_type ) else a != b )
8493
8594
8695@contextmanager
@@ -111,7 +120,7 @@ def collapse_operands(seq, eps=1e-15):
111120 if cur [i ] == 0 :
112121 # print(i, cur)
113122 if cur [i + 1 ] < 0 and (i == len (cur )- 2 or cur [i + 2 ] % 2 != 0 ):
114- 0 ** cur [i + 1 ]
123+ unused = 0 ** cur [i + 1 ]
115124 else :
116125 cur [i - 2 :] = [1 ]
117126 break
@@ -167,7 +176,7 @@ def safe_str_mult(a, b):
167176 if isinstance (a , str ):
168177 if b <= 0 :
169178 return ''
170- if len (a ) * abs (b ) > 1e7 :
179+ if len (a ) * abs (b ) > 1e7 :
171180 raise MemoryError ("expression creates too large a string" )
172181 a , b = b , a
173182 return a * b
@@ -200,7 +209,7 @@ def left_associative_evaluate(self, oper_fn_map):
200209
201210 def __repr__ (self ):
202211 return type (self ).__name__ + '/' + (", " .join (repr (t ) for t in self .tokens )
203- if self .iterable_tokens else repr (self .tokens ))
212+ if self .iterable_tokens else repr (self .tokens ))
204213
205214
206215class LiteralNode (ArithNode ):
@@ -248,6 +257,8 @@ def __repr__(self):
248257
249258
250259class TernaryNode (ArithNode ):
260+ opns_map = {}
261+
251262 def left_associative_evaluate (self , oper_fn_map ):
252263 operands = self .tokens
253264 ret = operands [0 ].evaluate ()
@@ -342,6 +353,7 @@ def evaluate(self):
342353
343354 class ArithmeticUnaryPostOp (UnaryNode ):
344355 opns_map = {}
356+
345357 def evaluate (self ):
346358 with _trimming_exception_traceback ():
347359 return self .left_associative_evaluate (self .opns_map )
@@ -411,7 +423,7 @@ def __init__(self):
411423 self ._added_operator_specs = []
412424 self ._added_function_specs = {}
413425 self ._base_operators = ("** * / mod × ÷ + - < > <= >= == != ≠ ≤ ≥ between-and within-and"
414- " in-range-from-to not and ∧ or ∨ ?:" ).split ()
426+ " in-range-from-to not and ∧ or ∨ ?:" ).split ()
415427 self ._base_function_map = {
416428 'sgn' : FunctionSpec ((lambda x : - 1 if x < 0 else 1 if x > 0 else 0 ), 1 ),
417429 'abs' : FunctionSpec (abs , 1 ),
@@ -484,19 +496,16 @@ def customize(self):
484496 pass
485497
486498 def add_operator (self , operator_expr , arity , assoc , parse_action ):
487- if isinstance (operator_expr , str ) and callable (parse_action ):
488- operator_node_superclass = {
489- (1 , pp .opAssoc .LEFT ): self .ArithmeticUnaryPostOp ,
490- (1 , pp .opAssoc .RIGHT ): self .ArithmeticUnaryOp ,
491- (2 , pp .opAssoc .LEFT ): self .ArithmeticBinaryOp ,
492- (2 , pp .opAssoc .RIGHT ): self .ArithmeticBinaryOp ,
493- (3 , pp .opAssoc .LEFT ): TernaryNode ,
494- (3 , pp .opAssoc .RIGHT ): TernaryNode ,
495- }[arity , assoc ]
496- operator_node_class = type ('' , (operator_node_superclass ,),
497- {'opns_map' : {operator_expr : parse_action }})
498- else :
499- operator_node_class = parse_action
499+ operator_node_superclass = {
500+ (1 , pp .opAssoc .LEFT ): self .ArithmeticUnaryPostOp ,
501+ (1 , pp .opAssoc .RIGHT ): self .ArithmeticUnaryOp ,
502+ (2 , pp .opAssoc .LEFT ): self .ArithmeticBinaryOp ,
503+ (2 , pp .opAssoc .RIGHT ): self .ArithmeticBinaryOp ,
504+ (3 , pp .opAssoc .LEFT ): TernaryNode ,
505+ (3 , pp .opAssoc .RIGHT ): TernaryNode ,
506+ }[arity , assoc ]
507+ operator_node_class = type ('' , (operator_node_superclass ,),
508+ {'opns_map' : {str (operator_expr ): parse_action }})
500509 self ._added_operator_specs .insert (0 , (operator_expr , arity , assoc , operator_node_class ))
501510
502511 def initialize_variable (self , vname , vvalue , as_formula = False ):
@@ -637,6 +646,7 @@ def evaluate(self):
637646
638647 identifier_node_class = type ('Identifier' , (self .IdentifierNode ,), {'_assigned_vars' : self ._variable_map })
639648 var_name .addParseAction (identifier_node_class )
649+ # noinspection PyUnresolvedReferences
640650 base_operator_specs = [
641651 ('**' , 2 , pp .opAssoc .LEFT , self .ExponentBinaryOp ),
642652 ('-' , 1 , pp .opAssoc .RIGHT , self .ArithmeticUnaryOp ),
@@ -652,11 +662,13 @@ def evaluate(self):
652662 ]
653663 ABS_VALUE_VERT = pp .Suppress ("|" )
654664 abs_value_expression = ABS_VALUE_VERT + arith_operand + ABS_VALUE_VERT
665+
655666 def cvt_to_function_call (tokens ):
656667 ret = pp .ParseResults (['abs' ]) + tokens
657668 ret ['fn_name' ] = 'abs'
658669 ret ['args' ] = tokens
659670 return [ret ]
671+
660672 abs_value_expression .addParseAction (cvt_to_function_call , function_node_class )
661673
662674 arith_operand <<= pp .infixNotation ((function_expression
@@ -670,7 +682,9 @@ def cvt_to_function_call(tokens):
670682 rvalue .setName ("arithmetic expression" )
671683 lvalue = var_name ()
672684
673- value_assignment_statement = pp .delimitedList (lvalue )("lhs" ) + pp .oneOf ("<- =" ) + pp .delimitedList (rvalue )("rhs" )
685+ value_assignment_statement = (pp .delimitedList (lvalue )("lhs" )
686+ + pp .oneOf ("<- =" )
687+ + pp .delimitedList (rvalue )("rhs" ))
674688
675689 def eval_and_store_value (tokens ):
676690 if len (tokens .lhs ) > len (tokens .rhs ):
@@ -765,7 +779,9 @@ def customize(self):
765779 self .add_function ('rnd' , 0 , random .random )
766780 self .add_function ('randint' , 2 , random .randint )
767781 self .add_operator ('°' , 1 , ArithmeticParser .LEFT , math .radians )
768- self .add_operator ("!" , 1 , ArithmeticParser .LEFT , constrained_factorial )
782+ # avoid clash with '!=' operator
783+ factorial_operator = (~ pp .Literal ("!=" ) + "!" ).setName ("!" )
784+ self .add_operator (factorial_operator , 1 , ArithmeticParser .LEFT , constrained_factorial )
769785 self .add_operator ("⁻¹" , 1 , ArithmeticParser .LEFT , lambda x : 1 / x )
770786 self .add_operator ("²" , 1 , ArithmeticParser .LEFT , lambda x : safe_pow ((x , 2 )))
771787 self .add_operator ("³" , 1 , ArithmeticParser .LEFT , lambda x : safe_pow ((x , 3 )))
0 commit comments