66
66
expressions .update (keywords )
67
67
68
68
any_keyword = pp .MatchFirst (keywords .values ())
69
+ # noinspection PyUnresolvedReferences
69
70
IN_RANGE_FROM = (IN + RANGE + FROM ).addParseAction ('_' .join )
71
+ # noinspection PyUnresolvedReferences
70
72
TRUE .addParseAction (lambda : True )
73
+ # noinspection PyUnresolvedReferences
71
74
FALSE .addParseAction (lambda : False )
72
75
73
76
FunctionSpec = namedtuple ("FunctionSpec" , "method arity" )
74
77
75
78
_numeric_type = (int , float , complex )
76
79
77
80
# 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 )
84
93
85
94
86
95
@contextmanager
@@ -111,7 +120,7 @@ def collapse_operands(seq, eps=1e-15):
111
120
if cur [i ] == 0 :
112
121
# print(i, cur)
113
122
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 ]
115
124
else :
116
125
cur [i - 2 :] = [1 ]
117
126
break
@@ -167,7 +176,7 @@ def safe_str_mult(a, b):
167
176
if isinstance (a , str ):
168
177
if b <= 0 :
169
178
return ''
170
- if len (a ) * abs (b ) > 1e7 :
179
+ if len (a ) * abs (b ) > 1e7 :
171
180
raise MemoryError ("expression creates too large a string" )
172
181
a , b = b , a
173
182
return a * b
@@ -200,7 +209,7 @@ def left_associative_evaluate(self, oper_fn_map):
200
209
201
210
def __repr__ (self ):
202
211
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 ))
204
213
205
214
206
215
class LiteralNode (ArithNode ):
@@ -248,6 +257,8 @@ def __repr__(self):
248
257
249
258
250
259
class TernaryNode (ArithNode ):
260
+ opns_map = {}
261
+
251
262
def left_associative_evaluate (self , oper_fn_map ):
252
263
operands = self .tokens
253
264
ret = operands [0 ].evaluate ()
@@ -342,6 +353,7 @@ def evaluate(self):
342
353
343
354
class ArithmeticUnaryPostOp (UnaryNode ):
344
355
opns_map = {}
356
+
345
357
def evaluate (self ):
346
358
with _trimming_exception_traceback ():
347
359
return self .left_associative_evaluate (self .opns_map )
@@ -411,7 +423,7 @@ def __init__(self):
411
423
self ._added_operator_specs = []
412
424
self ._added_function_specs = {}
413
425
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 ()
415
427
self ._base_function_map = {
416
428
'sgn' : FunctionSpec ((lambda x : - 1 if x < 0 else 1 if x > 0 else 0 ), 1 ),
417
429
'abs' : FunctionSpec (abs , 1 ),
@@ -484,19 +496,16 @@ def customize(self):
484
496
pass
485
497
486
498
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 }})
500
509
self ._added_operator_specs .insert (0 , (operator_expr , arity , assoc , operator_node_class ))
501
510
502
511
def initialize_variable (self , vname , vvalue , as_formula = False ):
@@ -637,6 +646,7 @@ def evaluate(self):
637
646
638
647
identifier_node_class = type ('Identifier' , (self .IdentifierNode ,), {'_assigned_vars' : self ._variable_map })
639
648
var_name .addParseAction (identifier_node_class )
649
+ # noinspection PyUnresolvedReferences
640
650
base_operator_specs = [
641
651
('**' , 2 , pp .opAssoc .LEFT , self .ExponentBinaryOp ),
642
652
('-' , 1 , pp .opAssoc .RIGHT , self .ArithmeticUnaryOp ),
@@ -652,11 +662,13 @@ def evaluate(self):
652
662
]
653
663
ABS_VALUE_VERT = pp .Suppress ("|" )
654
664
abs_value_expression = ABS_VALUE_VERT + arith_operand + ABS_VALUE_VERT
665
+
655
666
def cvt_to_function_call (tokens ):
656
667
ret = pp .ParseResults (['abs' ]) + tokens
657
668
ret ['fn_name' ] = 'abs'
658
669
ret ['args' ] = tokens
659
670
return [ret ]
671
+
660
672
abs_value_expression .addParseAction (cvt_to_function_call , function_node_class )
661
673
662
674
arith_operand <<= pp .infixNotation ((function_expression
@@ -670,7 +682,9 @@ def cvt_to_function_call(tokens):
670
682
rvalue .setName ("arithmetic expression" )
671
683
lvalue = var_name ()
672
684
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" ))
674
688
675
689
def eval_and_store_value (tokens ):
676
690
if len (tokens .lhs ) > len (tokens .rhs ):
@@ -765,7 +779,9 @@ def customize(self):
765
779
self .add_function ('rnd' , 0 , random .random )
766
780
self .add_function ('randint' , 2 , random .randint )
767
781
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 )
769
785
self .add_operator ("⁻¹" , 1 , ArithmeticParser .LEFT , lambda x : 1 / x )
770
786
self .add_operator ("²" , 1 , ArithmeticParser .LEFT , lambda x : safe_pow ((x , 2 )))
771
787
self .add_operator ("³" , 1 , ArithmeticParser .LEFT , lambda x : safe_pow ((x , 3 )))
0 commit comments