Files
Sheerka-Old/evaluators/AddConceptEvaluator.py
T

131 lines
4.7 KiB
Python

from core.ast.nodes import python_to_concept
from core.builtin_concepts import ParserResultConcept, ReturnValueConcept
from core.builtin_helpers import get_names
from core.concept import Concept
from evaluators.BaseEvaluator import OneReturnValueEvaluator
from parsers.ConceptLexerParser import ParsingExpression, ParsingExpressionVisitor
from parsers.DefaultParser import DefConceptNode
from parsers.PythonParser import PythonNode
class ConceptOrRuleNameVisitor(ParsingExpressionVisitor):
"""
Gets the concepts referenced by BNF
If a rule_name is given, it will also be considered as a potential property
"""
def __init__(self):
self.names = set()
def visit_ConceptMatch(self, node):
if node.rule_name:
self.names.add(node.rule_name)
elif isinstance(node.concept, Concept):
self.names.add(node.concept.name)
else:
self.names.add(node.concept)
def visit_all(self, node):
if node.rule_name:
self.names.add(node.rule_name)
class AddConceptEvaluator(OneReturnValueEvaluator):
"""
Used to add a new concept
"""
NAME = "AddNewConcept"
def __init__(self):
super().__init__(self.NAME, 50)
def matches(self, context, return_value):
return return_value.status and \
isinstance(return_value.value, ParserResultConcept) and \
isinstance(return_value.value.value, DefConceptNode)
def eval(self, context, return_value):
context.log(self.log, "Adding a new concept", self.name)
def_concept_node = return_value.value.value
sheerka = context.sheerka
# validate the node
props_found = set()
concept = Concept(def_concept_node.name)
for prop in ("definition", "where", "pre", "post", "body"):
# put back the sources
part_ret_val = getattr(def_concept_node, prop)
if not isinstance(part_ret_val, ReturnValueConcept) or not part_ret_val.status:
continue # not quite sure that it's possible
# update the parts
source = self.get_source(part_ret_val)
setattr(concept.metadata, prop, source)
# try to find what can be a property
concept_name = [part.value for part in def_concept_node.name.tokens]
for p in self.get_props(sheerka, part_ret_val, concept_name):
props_found.add(p)
# add props order by appearance when possible
for token in def_concept_node.name.tokens:
if token.value in props_found:
concept.set_prop(token.value, None)
# add the remaining properties
for p in props_found:
if p not in concept.props:
concept.set_prop(p, None)
# finish initialisation
concept.init_key(def_concept_node.name.tokens)
concept.add_codes(def_concept_node.get_asts())
if sheerka.is_success(def_concept_node.definition):
concept.bnf = def_concept_node.definition.value.value
ret = sheerka.create_new_concept(context, concept)
if not ret.status:
error_cause = sheerka.value(ret.body)
context.log(self.log, f"Failed to add concept '{concept.name}'. Reason: {error_cause}", self.name)
return sheerka.ret(self.name, ret.status, ret.value, parents=[return_value])
@staticmethod
def get_source(ret_value):
return ret_value.value.source
@staticmethod
def get_props(sheerka, ret_value, concept_name):
"""
Try to find out the variables
This function can only be a draft, as there may be tons of different situations
I guess that it can only be complete when will we have access to Sheerka memory
"""
#
# Case of python code
#
if isinstance(ret_value.value, ParserResultConcept) and isinstance(ret_value.value.value, PythonNode):
python_node = ret_value.value.value
as_concept_node = python_to_concept(python_node.ast_)
variables = get_names(sheerka, as_concept_node)
variables = filter(lambda x: x in concept_name, variables)
return list(variables)
#
# case of concept
#
if isinstance(ret_value.value, ParserResultConcept) and isinstance(ret_value.value.value, Concept):
return list(ret_value.value.value.props.keys())
#
# case of BNF
#
if isinstance(ret_value.value, ParserResultConcept) and isinstance(ret_value.value.value, ParsingExpression):
visitor = ConceptOrRuleNameVisitor()
visitor.visit(ret_value.value.value)
return sorted(list(visitor.names))
return []