from core.builtin_concepts import BuiltinConcepts from parsers.BaseParser import BaseParser from parsers.ConceptLexerParser import ConceptNode from parsers.MultipleConceptsParser import MultipleConceptsParser from parsers.PythonParser import PythonParser multiple_concepts_parser = MultipleConceptsParser() class PythonWithConceptsParser(BaseParser): def __init__(self, **kwargs): super().__init__("PythonWithConcepts", 20) self.identifiers = None self.identifiers_key = None @staticmethod def sanitize(identifier): res = "" for c in identifier: res += c if c.isalnum() else "0" return res def parse(self, context, text): sheerka = context.sheerka if not sheerka.isinstance(text, BuiltinConcepts.PARSER_RESULT): return None if not text.parser == multiple_concepts_parser: return None nodes = text.body source = "" to_parse = "" identifiers = {} identifiers_key = {} python_ids_mappings = {} def _get_identifier(c): """ Get an identifier for a concept. Make sure to return the same identifier if the same concept Make sure to return a different identifier if same name but different concept Internal function because I don't want identifiers, identifiers_key and python_ids_mappings to be instance variables I would like to keep this parser as stateless as possible :param c: :return: """ if id(c) in identifiers: return identifiers[id(c)] identifier = "__C__" + self.sanitize(c.key or c.name) if c.id: identifier += "__" + c.id if identifier in identifiers_key: identifiers_key[identifier] += 1 identifier += f"_{identifiers_key[identifier]}" else: identifiers_key[identifier] = 0 identifier += "__C__" identifiers[id(c)] = identifier return identifier for node in nodes: if isinstance(node, ConceptNode): source += node.source if to_parse: to_parse += " " concept = node.concept python_id = _get_identifier(concept) to_parse += python_id python_ids_mappings[python_id] = concept else: source += node.source to_parse += node.source with context.push(self, "Trying Python for '" + to_parse + "'") as sub_context: python_parser = PythonParser() result = python_parser.parse(sub_context, to_parse) if result.status: python_node = result.body.body python_node.source = source python_node.concepts = python_ids_mappings return sheerka.ret( self.name, True, sheerka.new( BuiltinConcepts.PARSER_RESULT, parser=self, source=source, body=result.body.body, try_parsed=None)) else: return sheerka.ret( self.name, False, result.body)