Added ExactConceptParser

This commit is contained in:
2019-11-09 17:29:50 +01:00
parent a636198222
commit 576ce77740
12 changed files with 603 additions and 169 deletions
+42 -20
View File
@@ -1,9 +1,9 @@
from dataclasses import dataclass
from core.concept import Concept, ErrorConcept, Property, TooManySuccessConcept, ReturnValueConcept
from parsers.PythonParser import PythonParser, PythonGetNamesVisitor, PythonNode
from parsers.PythonParser import PythonGetNamesVisitor, PythonNode
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event, SheerkaDataProviderDuplicateKeyError
from parsers.DefaultParser import DefaultParser, DefConceptNode
from parsers.DefaultParser import DefConceptNode, DefaultParser
import core.utils
import logging
@@ -50,6 +50,7 @@ class Sheerka(Concept):
NAME = "Sheerka"
UNKNOWN_CONCEPT_NAME = "Unknown Concept"
SUCCESS_CONCEPT_NAME = "Success"
CONCEPT_TOO_LONG_CONCEPT_NAME = "Concept too long"
CONCEPTS_ENTRY = "All_Concepts"
BUILTIN_CONCEPTS_KEYS = "Builtins_Concepts"
@@ -60,6 +61,8 @@ class Sheerka(Concept):
super().__init__(Sheerka.NAME)
# cache of the most used concepts
# Note that these are only templates
# They are used as a footprint for instantiation
self.concepts_cache = {}
# a concept can be instantiated
@@ -91,8 +94,9 @@ class Sheerka(Concept):
try:
self.init_logging()
self.sdp = SheerkaDataProvider(root_folder)
self.parsers.append(lambda text: DefaultParser(text, PythonParser))
self.parsers.append(lambda text: PythonParser(text))
self.parsers.append(core.utils.get_class("parsers.DefaultParser.DefaultParser"))
self.parsers.append(core.utils.get_class("parsers.PythonParser.PythonParser"))
#self.parsers.append(core.utils.get_class("parsers.ExactConceptParser.ExactConceptParser"))
self.evaluators.append(core.utils.get_object("evaluators.DefaultEvaluator.DefaultEvaluator"))
self.evaluators.append(core.utils.get_object("evaluators.AddConceptEvaluator.AddConceptEvaluator"))
@@ -103,7 +107,7 @@ class Sheerka(Concept):
self.create_builtin_concepts()
except IOError as e:
return ReturnValue(self, False, self.get(Sheerka.ERROR_CONCEPT_NAME), e)
return ReturnValue(self, False, self.get(ErrorConcept.NAME), e)
return ReturnValue(self, True, self.get(Sheerka.SUCCESS_CONCEPT_NAME))
@@ -129,12 +133,15 @@ class Sheerka(Concept):
self,
Concept(Sheerka.UNKNOWN_CONCEPT_NAME, key=Sheerka.UNKNOWN_CONCEPT_NAME),
Concept(Sheerka.SUCCESS_CONCEPT_NAME, key=Sheerka.SUCCESS_CONCEPT_NAME),
Concept(Sheerka.CONCEPT_TOO_LONG_CONCEPT_NAME, key=Sheerka.CONCEPT_TOO_LONG_CONCEPT_NAME),
ErrorConcept(),
TooManySuccessConcept(),
ReturnValueConcept(),
]
for concept in builtins:
self.add_in_cache(concept)
from_db = self.sdp.get_safe(self.CONCEPTS_ENTRY, concept.key)
if from_db is None:
log.debug(f"'{concept.name}' concept is not found. Adding.")
@@ -143,7 +150,6 @@ class Sheerka(Concept):
else:
log.debug(f"Found concept '{from_db}'. Updating.")
concept.update_from(from_db)
self.concepts_cache[concept.key] = concept
def init_logging(self):
if self.debug:
@@ -158,7 +164,7 @@ class Sheerka(Concept):
def eval(self, text):
evt_digest = self.sdp.save_event(Event(text))
exec_context = ExecutionContext(self, evt_digest)
return_values = self.try_parse(text)
return_values = self.try_parse(exec_context, text)
return_values = self.try_eval(exec_context, return_values)
# return_values = []
@@ -172,17 +178,17 @@ class Sheerka(Concept):
return return_values
def try_parse(self, text):
def try_parse(self, context, text):
result = []
log.debug(f"Parsing '{text}'")
for parser in self.parsers:
p = parser(text)
p = parser()
# try:
# tree = p.parse()
# result.append((p.name, tree))
# except Exception as e:
# result.append((p.name, e))
tree = p.parse()
tree = p.parse(context, text)
result.append(ReturnValue(p.name, not p.has_error, p.error_sink if p.has_error else tree))
return result
@@ -235,11 +241,12 @@ class Sheerka(Concept):
setattr(concept, prop, source)
# try to find variables (eg props)
# Note that with this method, the variables will be created in the order of appearance
for token in def_concept_node.tokens["name"]:
if token.value in get_names_visitor.names:
concept.props.append(Property(token.value, None))
concept.set_prop(token.value, None)
concept.key = DefaultParser.get_concept_name(def_concept_node.tokens["name"], [p.name for p in concept.props])
concept.init_key(def_concept_node.tokens["name"])
concept.add_codes(def_concept_node.get_codes())
self.set_id_if_needed(concept, False)
@@ -249,22 +256,34 @@ class Sheerka(Concept):
return ReturnValue(self.add_concept.__name__, False, ErrorConcept(body=error), error.args[0])
return ReturnValue(self.add_concept.__name__, True, concept)
def get(self, concept_name):
def add_in_cache(self, concept):
"""
Adds a concept template in cache.
The cache is used as a proxy before looking at sdp
:param concept:
:return:
"""
self.concepts_cache[concept.key] = concept
def get(self, concept_key):
"""
Tries to find a concept
:param concept_name:
TODO: how to manage single vs multiple instances
:param concept_key:
:return:
"""
# first search in cache
if concept_name in self.concepts_cache:
return self.concepts_cache[concept_name]
if concept_key in self.concepts_cache:
return self.concepts_cache[concept_key]
return self.sdp.get(self.CONCEPTS_ENTRY, concept_name)
return self.sdp.get_safe(self.CONCEPTS_ENTRY, concept_key) or \
self.new(self.UNKNOWN_CONCEPT_NAME, body=concept_key)
def new(self, concept, **kwargs):
"""
Returns an instance of a new concept
TODO: Checks if the concept is supposed to be unique (ex Sheerka, or the number 'one' for example)
:param concept:
:param kwargs:
:return:
@@ -287,11 +306,14 @@ class Sheerka(Concept):
:return:
"""
if not isinstance(a, Concept) or not isinstance(b, Concept):
return False
if not isinstance(a, Concept):
raise SyntaxError("The first parameter of isinstance MUST be a concept")
b_key = b if isinstance(b, str) else b.key
# TODO : manage when a is the list of all possible b
return a.key == b.key
# for example, if a is a color, it will be found the entry 'All_Colors'
return a.key == b_key
@staticmethod
def test():