def define_types(self, compiler, statements): """ This is the first compiler stage that defines all types """ definition_count = 0 for stmt in statements: if isinstance(stmt, DefinitionStatement): state = State(compiler, stmt.namespace, stmt) state.add_to_graph(self._graph) definition_count += 1 self._evaluation_queue.add(state) LOGGER.debug("Added %d definition statements." % definition_count) # TODO: add error reporting here if not self._evaluate_statement_list(): for state in self._evaluation_queue: if not state.evaluated: print(state) raise Exception("Unable to define all types") # now query the graph again for statements that cannot resolve for state in self._graph.get_statements(): if isinstance(stmt, DefinitionStatement) and not state.evaluated: local_scope = state.get_local_scope() for _name, type_ref in state._required_types.items(): if not type_ref.is_available(local_scope): self.show_exception(state, "Unable to resolve %s" % type_ref) # call scheduled callbacks for 'after_types' ctx = Context(self._graph, self._graph.root_scope, None, None) CallbackHandler.run_callbacks("after_types", ctx)
def run(self, compiler, statements): """ Evaluate the current graph """ # first evaluate all definitions, this should be done in one iteration self.define_types(compiler, statements) # add all other statements to the graph for stmt in statements: if isinstance(stmt, DynamicStatement): state = DynamicState(compiler, stmt.namespace, stmt) state.add_to_graph(self._graph) # start an evaluation loop i = 0 while i < MAX_ITERATIONS: self._sort_statements() # check if we can stop the execution if len(self._evaluation_queue) == 0 and len(self._wait_queue) == 0: break else: i += 1 LOGGER.debug("Iteration %d (e: %d, w: %d, p: %d)", i, len(self._evaluation_queue), len(self._wait_queue), len(self._problem_list)) # determine which of those can be evaluated, prefer generator and # reference statements over call statements result = False if len(self._evaluation_queue) > 0: LOGGER.debug(" Evaluating normal queue") result = self._evaluate_statement_list() # not everything was evaluated -> try all statements now if not result: LOGGER.debug(" Evaluating waiting queue") # move statements from the waiting queue. Only move statements # that use a list when all of them use a list. current_len = len(self._evaluation_queue) for statement in self._wait_queue.copy(): if statement not in self._problem_list: self._evaluation_queue.add(statement) self._wait_queue.remove(statement) else: if self._problem_list[statement] < 0: self._problem_list[statement] = i if len(self._evaluation_queue) == current_len and len(self._problem_list) > 0: # add the oldest statements from the waiting queue to # the evaluation queue. All statements in this queue are # now statements that we want to postpone as long as # possible. values = sorted(list(self._problem_list.values())) evaluate_value = values[0] LOGGER.debug(" Using problem statements of generation %d", evaluate_value) for stmt in list(self._problem_list.keys()): if self._problem_list[stmt] == evaluate_value: self._evaluation_queue.add(stmt) self._wait_queue.remove(stmt) del self._problem_list[stmt] self._evaluate_statement_list() self._graph.process_un_compared() # end evaluation loop # call post hook ctx = Context(self._graph, self._graph.root_scope, None, None) CallbackHandler.run_callbacks("post", ctx) result = True for state in self._graph.get_statements(): if not state.evaluated: sys.stderr.write("Unable to evaluate %s at %s:%d\n" % (state, state.statement.filename, state.statement.line)) self.print_unresolved(state) result = False # check if all values are set if result: self.check_unset() ctx = Context(self._graph, self._graph.root_scope, None, None) CallbackHandler.run_callbacks("verify", ctx) return result