87cab44fb8
Fixed #135: Change services service priorities Fixed #136: ErrorManager: Implement recognize_error Fixed #137: BNFNodeParser : Error when parsing regex with sub parsers Fixed #138: get_last_errors(): real errors sources are lost Fixed #139: OneError return value removes the origin of the error Fixed #140: Concept variables are not correctly handled when parsing sub expression Fixed #143: Implement has_unknown_concepts()
131 lines
5.1 KiB
Python
131 lines
5.1 KiB
Python
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)
|