from itertools import product from core.builtin_concepts_ids import BuiltinConcepts from core.sheerka.services.sheerka_service import FailedToCompileError from core.tokenizer import TokenKind from parsers.BaseExpressionParser import AndNode, ListComprehensionNode, NameExprNode, VariableNode, \ end_parenthesis_mapping, open_parenthesis_mapping from sheerkapython.BaseExprTransform import BaseExprTransform, ExprTransformHints, do_not_eval_source_hint, \ is_a_question_hint, not_a_question_hint, wrap_concept_call_hint class PythonExprVisitor(BaseExprTransform): def __init__(self, context, obj_counter=0): super().__init__(context, obj_counter) def compile(self, expr_node, hint=None): eval_question = self.context.in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED) hint = hint or ExprTransformHints(eval_source=True, eval_question=eval_question) try: visitor_objects = self.visit(expr_node, hint) except FailedToCompileError: return None results = [] for obj in visitor_objects: ret = self.context.sheerka.parse_python(self.context, obj.source) if ret.status: ret.body.source = obj.text ret.body.body.original_source = obj.text ret.body.body.objects = obj.objects results.append(ret) else: self.errors[obj.text] = self.context.sheerka.get_error_cause(ret.body) return results def visit_ListComprehensionNode(self, expr_node: ListComprehensionNode, hint: ExprTransformHints): """ :param expr_node: :param hint: :return: """ def _get_variables_names_from_target(target): return [token.strip() for token in target.get_source().split(",")] visitor_objects = [] source = expr_node.get_source() product_inputs = [] # add parenthesis around the element if needed # test case test_ExprToPython.test_i_can_compile_when_element_is_missing_its_parenthesis() if expr_node.element.first is None and len(expr_node.element.items) > 1: expr_node.element.first = NameExprNode(-1, -1, [open_parenthesis_mapping[TokenKind.LPAR]]) expr_node.element.last = NameExprNode(-1, -1, [end_parenthesis_mapping[TokenKind.LPAR]]) element_variables = set() for comp in expr_node.generators: comprehension_variables = _get_variables_names_from_target(comp.target) element_variables.update(comprehension_variables) # target target_objs = self.visit(comp.target, do_not_eval_source_hint) # iter iter_hint = not_a_question_hint.copy() iter_hint.variables = comprehension_variables iter_objs = self.visit(comp.iterable, not_a_question_hint) # if if comp.if_expr: # parse it using PythonConditionExprVisitor res = self.context.sheerka.parse_expression(self.context, comp.if_expr.get_source()) if not res.status: self.errors[comp.if_expr.get_source()] = res.body return None if_expr_hint = is_a_question_hint.copy() if_expr_hint.variables = comprehension_variables if_expr_objs = self.visit(res.body.body, if_expr_hint) else: if_expr_objs = [None] product_inputs.extend([target_objs, iter_objs, if_expr_objs]) hint = wrap_concept_call_hint.copy() hint.variables = element_variables element_objs = self.visit(expr_node.element, hint) product_inputs.insert(0, element_objs) for items in product(*product_inputs): obj = self.create_list_comprehension(source, *items) obj.variables -= element_variables visitor_objects.append(obj) return visitor_objects def visit_VariableNode(self, expr_node: VariableNode, hint: ExprTransformHints): source = expr_node.get_source() return self.parse_source_code(source, hint.eval_question, hint.wrap_concept_call, hint.variables) if hint.eval_source else \ self.do_not_parse_source_code(source) def visit_NameExprNode(self, expr_node: NameExprNode, hint: ExprTransformHints): """ create visitor objects from NameExprNode :param expr_node: :param hint: :return: """ source = expr_node.get_source() return self.parse_source_code(source, hint.eval_question, hint.wrap_concept_call, hint.variables) if hint.eval_source else \ self.do_not_parse_source_code(source) def visit_OrNode(self, expr_node: AndNode, hint: ExprTransformHints): """ :param expr_node: :param hint: :return: """ return self.visit_or_or_and_node("or", expr_node, hint)