Files
Sheerka-Old/tests/parsers/test_FunctionParser.py
T
kodjo 89e1f20975 Fixed #131 : Implement ExprToConditions
Fixed #130 : ArithmeticOperatorParser
Fixed #129 : python_wrapper : create_namespace
Fixed #128 : ExpressionParser: Cannot parse func(x) infixed concept 'xxx'
2021-10-13 16:06:57 +02:00

215 lines
9.8 KiB
Python

import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.sheerka.services.SheerkaExecute import ParserInput
from parsers.BaseParser import ErrorSink, UnexpectedTokenParsingError
from parsers.FunctionParser import FunctionParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.parsers.parsers_utils import FN, SCN, SEQ, compute_expected_array, \
get_expr_node_from_test_node, get_test_obj
cmap = {
"one": Concept("one"),
"two": Concept("two"),
"twenties": Concept("twenties", definition="'twenty' (one|two)=unit").def_var("unit"),
"plus": Concept("a plus b").def_var("a").def_var("b"),
}
class TestFunctionParser(TestUsingMemoryBasedSheerka):
shared_ontology = None
@classmethod
def setup_class(cls):
init_test_helper = cls().init_test(cache_only=False, ontology="#TestFunctionParserOld#")
sheerka, context, *updated = init_test_helper.with_concepts(*cmap.values(), create_new=True).unpack()
for i, concept_name in enumerate(cmap):
cmap[concept_name] = updated[i]
cls.shared_ontology = sheerka.get_ontology(context)
sheerka.pop_ontology(context)
def init_parser(self, my_concepts_map=None, strict=True, **kwargs):
if my_concepts_map is None:
sheerka, context = self.init_test().unpack()
sheerka.add_ontology(context, self.shared_ontology)
else:
sheerka, context, *updated = self.init_test().with_concepts(*my_concepts_map.values(), **kwargs).unpack()
for i, pair in enumerate(my_concepts_map):
my_concepts_map[pair] = updated[i]
expr_parser = kwargs.get("expr_parser", None)
parser = FunctionParser(strict, expr_parser=expr_parser)
return sheerka, context, parser
def init_parser_with_source(self, source, strict=True):
sheerka, context, parser = self.init_parser(None, strict)
error_sink = ErrorSink()
parser_input = ParserInput(source)
parser.reset_parser_input(parser_input, error_sink)
return sheerka, context, parser, parser_input, error_sink
def test_i_can_detect_empty_expression(self):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, ParserInput(""))
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_EMPTY)
def test_input_must_be_a_parser_input(self):
sheerka, context, parser = self.init_parser()
parser.parse(context, "not a parser input") is None
def test_i_cannot_parse_when_not_a_function(self):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, ParserInput("not a function"))
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME)
@pytest.mark.parametrize("expression, expected", [
("func()", FN("func")),
("concept(one)", FN("concept", "one")),
("func(one)", FN("func", "one")),
("func(a long two, 'three', ;:$*)", FN("func", "a long two", "'three'", ";:$*")),
("func(func1(one), two, func2(func3(), func4(three)))",
FN("func", "func1(one)", "two", "func2(func3(), func4(three))")),
("func(r:|1:)", FN("func", "r:|1:")),
("func(bar fn(x))", FN("func", "bar fn(x)")),
("func([one, two])", FN("func", "[one, two]")),
("func((one, two))", FN("func", "(one, two)")),
("func({one, two})", FN("func", "{one, two}")),
])
def test_i_can_parse_input_function_when_expr_parser_is_none(self, expression, expected):
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
expected = get_expr_node_from_test_node(expression, expected)
parsed = parser.parse_input(context, parser_input, error_sink)
assert not error_sink.has_error
assert parsed == expected
parser.strict = False
parser.reset_parser_input(parser_input, error_sink)
parsed = parser.parse_input(context, parser_input, error_sink)
assert not error_sink.has_error
assert parsed == expected
def test_i_can_parse_input_when_prefixed_depending_on_strict_mode(self):
expression = "bar fn(x)"
expected = SEQ("bar ", FN("fn", "x"))
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
expected = get_expr_node_from_test_node(expression, expected)
parsed = parser.parse_input(context, parser_input, error_sink)
assert error_sink.has_error
assert parsed is None
assert isinstance(error_sink.sink[0], UnexpectedTokenParsingError)
parser.strict = False
parser.reset_parser_input(parser_input, error_sink)
parsed = parser.parse_input(context, parser_input, error_sink)
assert not error_sink.has_error
assert parsed == expected
def test_i_can_parse_input_when_suffixed_depending_on_strict_mode(self):
expression = "fn(x) bar"
expected = SEQ(FN("fn", "x"), " bar")
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
expected = get_expr_node_from_test_node(expression, expected)
parsed = parser.parse_input(context, parser_input, error_sink)
assert error_sink.has_error
assert parsed is None
assert isinstance(error_sink.sink[0], UnexpectedTokenParsingError)
parser.strict = False
parser.reset_parser_input(parser_input, error_sink)
parsed = parser.parse_input(context, parser_input, error_sink)
assert not error_sink.has_error
assert parsed == expected
def test_i_can_parse_input_when_infixed_and_suffixed(self):
expression = "foo fn(x) bar"
expected = SEQ("foo ", FN("fn", "x"), " bar")
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
expected = get_expr_node_from_test_node(expression, expected)
parser.strict = False
parser.reset_parser_input(parser_input, error_sink)
parsed = parser.parse_input(context, parser_input, error_sink)
assert not error_sink.has_error
assert parsed == expected
@pytest.mark.parametrize("text, expected, objects", [
("func()", SCN("func()"), {}),
(" func()", SCN("func()"), {}),
("func(one)", SCN("func(one)"), {"__o_00__": "one"}),
("func(one, unknown, two)", SCN("func(one, unknown, two)"), {"__o_00__": "one", "__o_01__": "two"}),
("func(one, twenty two)", SCN("func(one, twenty two)"), {"__o_00__": "one", "__o_01__": "twenties"}),
("func(one plus two, three)", SCN("func(one plus two, three)"), {"__o_00__": "plus"}),
("func(func1(one), two)", SCN("func(func1(one), two)"), {"__o_00__": "one", "__o_01__": "two"}),
])
def test_i_can_parse(self, text, expected, objects):
sheerka, context, parser = self.init_parser()
resolved_expected = compute_expected_array(cmap, text, [expected])[0]
res = parser.parse(context, ParserInput(text))
parser_result = res.body
node = res.body.body
assert res.status
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
transformed_expression = get_test_obj(node, resolved_expected)
assert transformed_expression == resolved_expected
assert node.python_node is not None
assert node.return_value is not None
# compare objects
actual_objects = {k: v.id for k, v in node.python_node.objects.items()}
expected_objects = {k: cmap[v].id for k, v in objects.items()}
assert actual_objects == expected_objects
# @pytest.mark.parametrize("text, expected_error_type", [
# ("one", BuiltinConcepts.NOT_FOR_ME), # no function found
# ("$*!", BuiltinConcepts.NOT_FOR_ME), # no function found
# ("func(", BuiltinConcepts.ERROR), # function found, but incomplete
# ("func(one", BuiltinConcepts.ERROR), # function found, but incomplete
# ("func(one, two, ", BuiltinConcepts.ERROR), # function found, but incomplete
# ("func(one) and func(two)", BuiltinConcepts.ERROR), # to many function
# ("one func(one)", BuiltinConcepts.NOT_FOR_ME), # function not found ! (as it is not the first)
# ("func(a=b, c)", BuiltinConcepts.ERROR), # function found, but cannot be parsed
# ("func(one two)", BuiltinConcepts.ERROR), # function found, but cannot be parsed
# ])
# def test_i_cannot_parse(self, text, expected_error_type):
# sheerka, context, parser = self.init_parser()
#
# res = parser.parse(context, ParserInput(text))
#
# assert not res.status
# assert sheerka.isinstance(res.body, expected_error_type)
#
# @pytest.mark.parametrize("sequence, expected", [
# (None, None),
# ([["a"]], [["a"]]),
# ([["a"], ["b", "c"]], [["a"]]),
# ([["b", "c"], ["a"]], [["a"]]),
# ([["b", "c"], ["a"], ["d", "e"], ["f"]], [["a"], ["f"]]),
# ])
# def test_i_can_get_the_longest_concept_sequence(self, sequence, expected):
# assert FunctionParserOld.get_longest_concepts(sequence) == expected
#
# def test_concepts_found_are_fully_initialized(self):
# sheerka, context, parser = self.init_parser()
#
# res = parser.parse(context, ParserInput("func(one plus three)"))
# concept = res.body.body.nodes[0].concept
#
# assert res.status
# assert isinstance(concept.get_compiled()["a"], Concept)
#
# # three is not recognized,
# # so it will be transformed into list of ReturnValueConcept that indicate how to recognized it
# assert isinstance(concept.get_compiled()["b"], list)
# for item in concept.get_compiled()["b"]:
# assert sheerka.isinstance(item, BuiltinConcepts.RETURN_VALUE)