Added first version of DebugManager. Implemented draft of the rule engine

This commit is contained in:
2020-11-20 13:41:45 +01:00
parent cd066881b4
commit 315f8ea09b
156 changed files with 8388 additions and 2852 deletions
+112 -19
View File
@@ -6,6 +6,7 @@ from typing import Set
import core.utils
from core.builtin_concepts import BuiltinConcepts
from core.concept import VARIABLE_PREFIX, Concept, DEFINITION_TYPE_BNF, ConceptParts
from core.rule import Rule
from core.tokenizer import TokenKind, Token
from parsers.BaseParser import Node, BaseParser, ErrorNode
@@ -26,7 +27,7 @@ class LexerNode(Node):
def __post_init__(self):
if self.source is None:
self.source = BaseParser.get_text_from_tokens(self.tokens)
self.source = core.utils.get_text_from_tokens(self.tokens)
def __eq__(self, other):
if not isinstance(other, LexerNode):
@@ -39,7 +40,7 @@ class LexerNode(Node):
def fix_source(self, force=True):
if force or self.source is None:
self.source = BaseParser.get_text_from_tokens(self.tokens)
self.source = core.utils.get_text_from_tokens(self.tokens)
return self
def clone(self):
@@ -151,6 +152,40 @@ class UnrecognizedTokensNode(LexerNode):
return f"UTN('{self.source}')"
class RuleNode(LexerNode):
def __init__(self, rule, start, end, tokens=None, source=None):
super().__init__(start, end, tokens, source)
self.rule = rule
self.fix_source(False)
def __eq__(self, other):
if id(self) == id(other):
return True
if isinstance(other, RN):
return other == self
if not isinstance(other, RuleNode):
return False
return self.rule == other.rule and \
self.start == other.start and \
self.end == other.end and \
self.source == other.source
def __hash__(self):
return hash((self.rule, self.start, self.end, self.source))
def __repr__(self):
return f"RuleNode(rule='{self.rule}', source='{self.source}', start={self.start}, end={self.end})"
def clone(self):
return RuleNode(self.rule, self.start, self.end, self.tokens, self.source)
def to_short_str(self):
return f'RN({self.rule})'
class ConceptNode(LexerNode):
"""
Returned by the BnfNodeParser
@@ -194,7 +229,7 @@ class ConceptNode(LexerNode):
def __repr__(self):
text = f"ConceptNode(concept='{self.concept}', source='{self.source}', start={self.start}, end={self.end}"
if DEBUG_COMPILED:
for k, v in self.concept.compiled.items():
for k, v in self.concept.get_compiled().items():
text += f", {k}='{v}'"
return text + ")"
@@ -213,7 +248,7 @@ class ConceptNode(LexerNode):
bag[k] = v
# if isinstance(self.concept, Concept):
# bag["compiled"] = self.concept.compiled
# bag["compiled"] = self.concept.get_compiled()
return bag
def to_short_str(self):
@@ -607,7 +642,7 @@ class CNC(CN):
It matches with ConceptNode
But focuses on the 'compiled' property of the concept
CNC == ConceptNode if CNC.compiled == ConceptNode.concept.compiled
CNC == ConceptNode if CNC.get_compiled() == ConceptNode.concept.get_compiled()
"""
def __init__(self, concept_key, start=None, end=None, source=None, exclude_body=False, **kwargs):
@@ -634,9 +669,9 @@ class CNC(CN):
if self.source is not None and self.source != other.source:
return False
if self.exclude_body:
to_compare = {k: v for k, v in other.concept.compiled.items() if k != ConceptParts.BODY}
to_compare = {k: v for k, v in other.concept.get_compiled().items() if k != ConceptParts.BODY}
else:
to_compare = other.concept.compiled
to_compare = other.concept.get_compiled()
if self.compiled == to_compare: # expanded form to ease the debug
return True
else:
@@ -675,10 +710,9 @@ class UTN(HelperWithPos):
def __init__(self, source, start=None, end=None):
"""
:param concept: Concept or concept_key (only the key is used anyway)
:param source:
:param start:
:param end:
:param source:
"""
super().__init__(start, end)
self.source = source
@@ -711,6 +745,65 @@ class UTN(HelperWithPos):
return txt + ")"
class RN(HelperWithPos):
"""
Helper class to test RuleNode
"""
def __init__(self, rule, start=None, end=None, source=None):
"""
:param concept: Concept or concept_key (only the key is used anyway)
:param start:
:param end:
:param source:
"""
super().__init__(start, end)
self.rule_id = rule.id if isinstance(rule, Rule) else rule
self.source = source or core.utils.str_concept((None, self.rule_id), prefix="r:")
self.rule = rule if isinstance(rule, Rule) else None
def __eq__(self, other):
if id(self) == id(other):
return True
if isinstance(other, RuleNode):
if other.rule is None:
return False
if other.rule.id != self.rule_id:
return False
if self.start is not None and self.start != other.start:
return False
if self.end is not None and self.end != other.end:
return False
if self.source is not None and self.source != other.source:
return False
return True
if not isinstance(other, RN):
return False
return self.rule_id == other.rule_id and \
self.start == other.start and \
self.end == other.end and \
self.source == other.source
def __hash__(self):
return hash((self.rule_id, self.start, self.end, self.source))
def __repr__(self):
if self.rule:
txt = f"RN(rule='{self.rule}'"
else:
txt = f"RN(rule_id='{self.rule_id}'"
txt += f", source='{self.source}'"
if self.start is not None:
txt += f", start={self.start}"
if self.end is not None:
txt += f", end={self.end}"
return txt + ")"
class BaseNodeParser(BaseParser):
"""
Parser that return LexerNode
@@ -938,10 +1031,10 @@ class BaseNodeParser(BaseParser):
:param concept:
:return:
"""
if concept.bnf:
if concept.get_bnf():
from parsers.BnfNodeParser import BnfNodeFirstTokenVisitor
bnf_visitor = BnfNodeFirstTokenVisitor(sheerka)
bnf_visitor.visit(concept.bnf)
bnf_visitor.visit(concept.get_bnf())
return bnf_visitor.first_tokens
else:
keywords = concept.key.split()
@@ -955,22 +1048,22 @@ class BaseNodeParser(BaseParser):
@staticmethod
def ensure_bnf(context, concept, parser_name="BaseNodeParser"):
if concept.metadata.definition_type == DEFINITION_TYPE_BNF and not concept.bnf:
from parsers.BnfParser import BnfParser
regex_parser = BnfParser()
desc = f"Resolving BNF '{concept.metadata.definition}'"
if concept.get_metadata().definition_type == DEFINITION_TYPE_BNF and not concept.get_bnf():
from parsers.BnfDefinitionParser import BnfDefinitionParser
regex_parser = BnfDefinitionParser()
desc = f"Resolving BNF '{concept.get_metadata().definition}'"
with context.push(BuiltinConcepts.INIT_BNF,
concept,
who=parser_name,
obj=concept,
desc=desc) as sub_context:
sub_context.add_inputs(parser_input=concept.metadata.definition)
bnf_parsing_ret_val = regex_parser.parse(sub_context, concept.metadata.definition)
sub_context.add_inputs(parser_input=concept.get_metadata().definition)
bnf_parsing_ret_val = regex_parser.parse(sub_context, concept.get_metadata().definition)
sub_context.add_values(return_values=bnf_parsing_ret_val)
if not bnf_parsing_ret_val.status:
raise Exception(bnf_parsing_ret_val.value)
concept.bnf = bnf_parsing_ret_val.body.body
concept.set_bnf(bnf_parsing_ret_val.body.body)
if concept.id:
context.sheerka.get_by_id(concept.id).bnf = concept.bnf # update bnf in cache
context.sheerka.get_by_id(concept.id).set_bnf(concept.get_bnf()) # update bnf in cache