1111from operator import neg , add , sub , mul , truediv
1212
1313
14- class Atom :
14+ class Expression :
15+ """
16+ the root of all expression classes
17+ useful for type checking - search for isinstance below
18+
19+ in this second version we take advantage of this class to factorize
20+ this type-checking oriented snippet
21+ """
22+
23+ def check_is_expression (self , expression ):
24+ classname = self .__class__ .__name__
25+ if not isinstance (expression , Expression ):
26+ raise TypeError (f"passing a non-Expression object in { classname } is not supported" )
27+
28+
29+ class Atom (Expression ):
1530 """
1631 a class to implement an atomic value,
1732 like an int, a float, a str, ...
1833
1934 in order to be able to use this,
20- child classes need to provide self.type
21- that should be a class like int or float
35+ child classes need to provide self.implementation_type
36+ that should be a Python class - like typically int or float
2237 or similar whose constructor expects one arg
2338 """
2439 def __init__ (self , value ):
25- self .value = self .type (value )
40+ # convert the argument into the specific class implementation type
41+ self .value = self .implementation_type (value )
2642
2743 def eval (self , env ):
2844 return self .value
2945
3046
3147
32- class Unary :
48+ class Unary ( Expression ) :
3349 """
3450 the mother of all unary operators
3551
@@ -38,6 +54,7 @@ class Unary:
3854 which is expected to be a 1-parameter function
3955 """
4056 def __init__ (self , operand ):
57+ self .check_is_expression (operand )
4158 self .operand = operand
4259
4360 def eval (self , env ):
@@ -56,7 +73,7 @@ def eval(self, env):
5673# we can factor true binary (minus and divide) with n-ary (plus and mult)
5774# if we're a little careful about how we do the evaluation
5875
59- class MultiAry :
76+ class MultiAry ( Expression ) :
6077 """
6178 the mother of all binary or n-ary operators
6279
@@ -73,6 +90,8 @@ def __init__(self, *children):
7390 classname = self .__class__ .__name__
7491 if not self .arg_checker (nargs ):
7592 raise TypeError (f"passing { nargs } arguments in { classname } is not supported" )
93+ for child in children :
94+ self .check_is_expression (child )
7695 self .children = children
7796
7897 def eval (self , env ):
@@ -104,10 +123,10 @@ class Nary(MultiAry):
104123# and with all that in place the code for adding new operators becomes
105124
106125class Integer (Atom ):
107- type = int
126+ implementation_type = int
108127
109128class Float (Atom ):
110- type = float
129+ implementation_type = float
111130
112131
113132class Negative (Unary ):
@@ -142,7 +161,7 @@ class Divide(Binary):
142161
143162# and the new guys
144163
145- class Variable :
164+ class Variable ( Expression ) :
146165 def __init__ (self , name ):
147166 self .name = name
148167
@@ -153,10 +172,12 @@ def eval(self, env):
153172 return env [self .name ]
154173
155174
156- class Expressions :
175+ class Expressions ( Expression ) :
157176 # make sure there is at least one expression
158177 def __init__ (self , mandatory , * others ):
159178 self .children = (mandatory , * others )
179+ for child in self .children :
180+ self .check_is_expression (child )
160181
161182 def eval (self , env ):
162183 """
@@ -167,10 +188,11 @@ def eval(self, env):
167188 return result
168189
169190
170- class Assignment :
191+ class Assignment ( Expression ) :
171192 def __init__ (self , name , expr ):
172193 self .name = name
173194 self .expr = expr
195+ self .check_is_expression (expr )
174196
175197 def eval (self , env ):
176198 """
0 commit comments