import ast import pytest from core.builtin_concepts import ParserResultConcept, ReturnValueConcept, BuiltinConcepts from core.concept import Concept from core.sheerka import Sheerka, ExecutionContext from core.tokenizer import Token, TokenKind, Tokenizer from parsers.ConceptLexerParser import ConceptNode, UnrecognizedTokensNode, SourceCodeNode from parsers.ConceptsWithConceptsParser import ConceptsWithConceptsParser from parsers.MultipleConceptsParser import MultipleConceptsParser from parsers.PythonParser import PythonNode from sdp.sheerkaDataProvider import Event multiple_concepts_parser = MultipleConceptsParser() def get_context(): sheerka = Sheerka(skip_builtins_in_db=True) sheerka.initialize("mem://") return ExecutionContext("test", Event(), sheerka) def get_ret_from(*args): result = [] index = 0 source = "" for item in args: if isinstance(item, Concept): tokens = [Token(TokenKind.IDENTIFIER, item.name, 0, 0, 0)] result.append(ConceptNode(item, index, index, tokens, item.name)) index += 1 source += item.name elif isinstance(item, PythonNode): tokens = list(Tokenizer(item.source))[:-1] # strip trailing EOF result.append(SourceCodeNode(item, index, index + len(tokens) - 1, tokens, item.source)) index += len(tokens) source += item.source else: tokens = list(Tokenizer(item))[:-1] # strip trailing EOF result.append(UnrecognizedTokensNode(index, index + len(tokens) - 1, tokens)) index += len(tokens) source += item return ReturnValueConcept( "who", False, ParserResultConcept(parser=multiple_concepts_parser, value=result, source=source)) def init(concepts, inputs): context = get_context() for concept in concepts: context.sheerka.create_new_concept(context, concept) return context, get_ret_from(*inputs) def execute(concepts, inputs): context, input_return_values = init(concepts, inputs) parser = ConceptsWithConceptsParser() result = parser.parse(context, input_return_values.body) wrapper = result.body return_value = result.body.body return context, parser, result, wrapper, return_value @pytest.mark.parametrize("text, interested", [ ("not parser result", False), (ParserResultConcept(parser="not multiple_concepts_parser"), False), (ParserResultConcept(parser=multiple_concepts_parser, value=[]), True), ]) def test_not_interested(text, interested): context = get_context() res = ConceptsWithConceptsParser().parse(context, text) if interested: assert res is not None else: assert res is None def test_i_can_parse_composition_of_concepts(): foo = Concept("foo") bar = Concept("bar") plus = Concept("a plus b").def_prop("a").def_prop("b") context, parser, result, wrapper, return_value = execute([foo, bar, plus], [foo, " plus ", bar]) assert result.status assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT) assert result.who == wrapper.parser.name assert wrapper.source == "foo plus bar" assert context.sheerka.isinstance(return_value, plus) assert return_value.compiled["a"] == foo assert return_value.compiled["b"] == bar # sanity check, I can evaluate the result evaluated = context.sheerka.evaluate_concept(context, return_value) assert evaluated.key == return_value.key assert evaluated.get_prop("a") == foo.init_key() assert evaluated.get_prop("b") == bar.init_key() def test_i_can_parse_when_composition_of_source_code(): plus = Concept("a plus b", body="a + b").def_prop("a").def_prop("b") left = PythonNode("1+1", ast.parse("1+1", mode="eval")) right = PythonNode("2+2", ast.parse("2+2", mode="eval")) context, parser, result, wrapper, return_value = execute([plus], [left, " plus ", right]) assert result.status assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT) assert result.who == wrapper.parser.name assert wrapper.source == "1+1 plus 2+2" assert context.sheerka.isinstance(return_value, plus) left_parser_result = ParserResultConcept(parser=parser, source="1+1", value=left) right_parser_result = ParserResultConcept(parser=parser, source="2+2", value=right) assert return_value.compiled["a"] == [ReturnValueConcept(parser.name, True, left_parser_result)] assert return_value.compiled["b"] == [ReturnValueConcept(parser.name, True, right_parser_result)] # sanity check, I can evaluate the result evaluated = context.sheerka.evaluate_concept(context, return_value) assert evaluated.key == return_value.key assert evaluated.get_prop("a") == 2 assert evaluated.get_prop("b") == 4 assert evaluated.body == 6 def test_i_can_parse_when_mix_of_concept_and_code(): plus = Concept("a plus b").def_prop("a").def_prop("b") code = PythonNode("1+1", ast.parse("1+1", mode="eval")) foo = Concept("foo") context, parser, result, wrapper, return_value = execute([plus, foo], [foo, " plus ", code]) assert result.status assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT) assert result.who == wrapper.parser.name assert wrapper.source == "foo plus 1+1" assert context.sheerka.isinstance(return_value, plus) code_parser_result = ParserResultConcept(parser=parser, source="1+1", value=code) assert return_value.compiled["a"] == foo assert return_value.compiled["b"] == [ReturnValueConcept(parser.name, True, code_parser_result)] # sanity check, I can evaluate the result evaluated = context.sheerka.evaluate_concept(context, return_value) assert evaluated.key == return_value.key assert evaluated.get_prop("a") == foo.init_key() assert evaluated.get_prop("b") == 2 def test_i_can_parse_when_multiple_concepts_are_recognized(): foo = Concept("foo") bar = Concept("bar") plus_1 = Concept("a plus b", body="body1").def_prop("a").def_prop("b") plus_2 = Concept("a plus b", body="body2").def_prop("a").def_prop("b") context, input_return_values = init([foo, bar, plus_1, plus_2], [foo, " plus ", bar]) parser = ConceptsWithConceptsParser() result = parser.parse(context, input_return_values.body) assert len(result) == 2 res = result[0] wrapper = res.value return_value = res.value.value assert res.status assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT) assert res.who == wrapper.parser.name assert wrapper.source == "foo plus bar" assert context.sheerka.isinstance(return_value, plus_1) assert return_value.compiled["a"] == foo assert return_value.compiled["b"] == bar res = result[1] wrapper = res.value return_value = res.value.value assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT) assert res.who == wrapper.parser.name assert wrapper.source == "foo plus bar" assert context.sheerka.isinstance(return_value, plus_2) assert return_value.compiled["a"] == foo assert return_value.compiled["b"] == bar def test_i_cannot_parse_when_unknown_concept(): foo = Concept("foo") bar = Concept("bar") context, input_return_values = init([foo, bar], [foo, " plus ", bar]) parser = ConceptsWithConceptsParser() result = parser.parse(context, input_return_values.body) wrapper = result.body return_value = result.body.body assert not result.status assert context.sheerka.isinstance(wrapper, BuiltinConcepts.NOT_FOR_ME) assert result.who == parser.name assert return_value == input_return_values.body.body