11import ast
22import inspect
33from copy import copy
4+ from functools import partial
45from pythonwhat .parsing import TargetVars , FunctionParser , ObjectAccessParser , parser_dict
56from pythonwhat .Reporter import Reporter
67from pythonwhat .Feedback import Feedback
@@ -120,7 +121,7 @@ def to_child_state(self, student_subtree, solution_subtree,
120121 student_context = None , solution_context = None ,
121122 student_parts = None , solution_parts = None ,
122123 highlight = None ,
123- append_message = "" ):
124+ append_message = "" , node_name = "" ):
124125 """Dive into nested tree.
125126
126127 Set the current state as a state with a subtree of this syntax tree as
@@ -154,7 +155,8 @@ def to_child_state(self, student_subtree, solution_subtree,
154155 student_parts = student_parts , solution_parts = solution_parts ,
155156 highlight = highlight , messages = messages )
156157
157- child = State (student_code = utils_ast .extract_text_from_node (self .full_student_code , student_subtree ),
158+ klass = State if not node_name else self .SUBCLASSES [node_name ]
159+ child = klass (student_code = utils_ast .extract_text_from_node (self .full_student_code , student_subtree ),
158160 full_student_code = self .full_student_code ,
159161 pre_exercise_code = self .pre_exercise_code ,
160162 student_context = student_context ,
@@ -238,8 +240,6 @@ def parse_int(x):
238240# @property
239241# def student_withs(self): ...
240242# when defining the State class.
241- from functools import partial
242-
243243def getx (tree_name , Parser , ext_attr , self ):
244244 """getter for Parser outputs"""
245245 # return cached output if possible
@@ -249,26 +249,18 @@ def getx(tree_name, Parser, ext_attr, self):
249249 else :
250250 # otherwise, run parser over tree
251251 p = Parser ()
252+ # set mappings for parsers that inspect attribute access
253+ if ext_attr != 'mappings' and Parser in [FunctionParser , ObjectAccessParser ]:
254+ p .mappings = self .pre_exercise_mappings .copy ()
255+ # run parser
252256 p .visit (getattr (self , tree_name ))
253257 # cache
254258 self ._parser_cache [cache_key ] = p
255259 return getattr (p , ext_attr )
256260
257- def get_func_map (tree_name , ext_attr , self ):
258- """getter for FunctionParser outputs, uses pre_exercise_mappings"""
259- cache_key = tree_name + FunctionParser .__name__
260- if self ._parser_cache .get (cache_key ):
261- p = self ._parser_cache [cache_key ]
262- else :
263- p = FunctionParser ()
264- p .mappings = self .pre_exercise_mappings .copy ()
265- p .visit (getattr (self , tree_name ))
266- self ._parser_cache [cache_key ] = p
267- return getattr (p , ext_attr )
268-
269261# put a property getter on state for each parsed ast tree output.
270262# since the getter takes only one argument, self, partial functions
271- # are used to set all other arguments on getx and get_func_map
263+ # are used to set all other arguments on getx
272264for s in ['student' , 'solution' ]:
273265 tree_name = s + '_tree'
274266 for k , Parser in parser_dict .items ():
@@ -278,17 +270,16 @@ def get_func_map(tree_name, ext_attr, self):
278270 prop_oa_map = property (partial (getx , tree_name , ObjectAccessParser , 'mappings' ))
279271 setattr (State , s + '_oa_mappings' , prop_oa_map )
280272
281- # Getters for FunctionParser -----
282- # calls
283- prop_calls = property (partial (get_func_map , tree_name , 'calls' ))
284- setattr (State , s + '_function_calls' , prop_calls )
285- # mappings
286- prop_map = property (partial (get_func_map , tree_name , 'mappings' ))
273+ # mappings from FunctionParser
274+ prop_map = property (partial (getx , tree_name , FunctionParser , 'mappings' ))
287275 setattr (State , s + '_mappings' , prop_map )
288276
277+ # mappings for pre exercise code from FunctionParser
289278pec_prop_map = property (partial (getx , 'pre_exercise_tree' , FunctionParser , 'mappings' ))
290279setattr (State , 'pre_exercise_mappings' , pec_prop_map )
291280
281+ # State subclasses based on parsed output -------------------------------------
282+ State .SUBCLASSES = {node_name : type (node_name , (State ,), {}) for node_name in parser_dict }
292283
293284# global setters on State -----------------------------------------------------
294285def set_converter (key , fundef ):
0 commit comments