Enhanced complex concepts handling
This commit is contained in:
@@ -108,26 +108,34 @@ def test_that_the_source_is_correctly_set():
|
||||
assert created_concept.metadata.definition == "hello a"
|
||||
|
||||
|
||||
def test_that_the_ast_is_correctly_initialized():
|
||||
context = get_context()
|
||||
def_concept_return_value = get_concept(
|
||||
name="hello a",
|
||||
definition=get_concept_definition("hello a", Sequence(StrMatch("hello"), StrMatch("a"))),
|
||||
where="isinstance(a, str )",
|
||||
pre="a is not None",
|
||||
body="print('hello' + a)")
|
||||
|
||||
evaluated = AddConceptEvaluator().eval(context, def_concept_return_value)
|
||||
|
||||
assert evaluated.status
|
||||
assert context.sheerka.isinstance(evaluated.body, BuiltinConcepts.NEW_CONCEPT)
|
||||
|
||||
created_concept = evaluated.body.body
|
||||
|
||||
assert ConceptParts.WHERE in created_concept.cached_asts
|
||||
assert ConceptParts.PRE in created_concept.cached_asts
|
||||
assert ConceptParts.BODY in created_concept.cached_asts
|
||||
assert ConceptParts.POST not in created_concept.cached_asts
|
||||
# def test_that_the_ast_is_correctly_initialized():
|
||||
# """
|
||||
# When I parse the definition of a concept, I evaluate the metadata (like the body)
|
||||
# I wanted to keep in cache these evaluation for further utilisation but I have
|
||||
# a serialization issue.
|
||||
# So I had to comment concept.add_codes(def_concept_node.get_asts()) around line 85
|
||||
# So this test is now irrelevant
|
||||
# :return:
|
||||
# """
|
||||
# context = get_context()
|
||||
# def_concept_return_value = get_concept(
|
||||
# name="hello a",
|
||||
# definition=get_concept_definition("hello a", Sequence(StrMatch("hello"), StrMatch("a"))),
|
||||
# where="isinstance(a, str )",
|
||||
# pre="a is not None",
|
||||
# body="print('hello' + a)")
|
||||
#
|
||||
# evaluated = AddConceptEvaluator().eval(context, def_concept_return_value)
|
||||
#
|
||||
# assert evaluated.status
|
||||
# assert context.sheerka.isinstance(evaluated.body, BuiltinConcepts.NEW_CONCEPT)
|
||||
#
|
||||
# created_concept = evaluated.body.body
|
||||
#
|
||||
# assert ConceptParts.WHERE in created_concept.cached_asts
|
||||
# assert ConceptParts.PRE in created_concept.cached_asts
|
||||
# assert ConceptParts.BODY in created_concept.cached_asts
|
||||
# assert ConceptParts.POST not in created_concept.cached_asts
|
||||
|
||||
|
||||
def test_that_the_new_concept_is_correctly_saved():
|
||||
|
||||
@@ -108,12 +108,12 @@ def test_i_can_use_the_result_of_regex_parsing_to_parse_a_text():
|
||||
|
||||
res = concept_parser.parse(context, "twenty two")
|
||||
assert res.status
|
||||
assert res.value.body == [(bar, 0, 2, "twenty two")]
|
||||
assert res.value.body == [("bar", 0, 2, "twenty two")]
|
||||
|
||||
res = concept_parser.parse(context, "thirty one")
|
||||
assert res.status
|
||||
assert res.value.body == [(bar, 0, 2, "thirty one")]
|
||||
assert res.value.body == [("bar", 0, 2, "thirty one")]
|
||||
|
||||
res = concept_parser.parse(context, "twenty")
|
||||
assert res.status
|
||||
assert res.value.body == [(foo, 0, 0, "twenty")]
|
||||
assert res.value.body == [("foo", 0, 0, "twenty")]
|
||||
|
||||
@@ -1,128 +1,128 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept
|
||||
from core.concept import Concept
|
||||
from core.sheerka import Sheerka, ExecutionContext
|
||||
from evaluators.BaseEvaluator import BaseEvaluator
|
||||
from evaluators.ConceptComposerEvaluator import ConceptComposerEvaluator
|
||||
from parsers.BaseParser import BaseParser
|
||||
from parsers.ConceptLexerParser import ConceptNode, ConceptLexerParser, Sequence
|
||||
from sdp.sheerkaDataProvider import Event
|
||||
|
||||
concept_lexer_name = ConceptLexerParser().name
|
||||
|
||||
|
||||
def get_context():
|
||||
sheerka = Sheerka(skip_builtins_in_db=True)
|
||||
sheerka.initialize("mem://")
|
||||
return ExecutionContext("test", Event(), sheerka)
|
||||
|
||||
|
||||
def get_return_values(context, grammar, expression):
|
||||
parser = ConceptLexerParser()
|
||||
parser.initialize(context, grammar)
|
||||
|
||||
ret_val = parser.parse(context, expression)
|
||||
assert not ret_val.status
|
||||
return [ret_val]
|
||||
|
||||
|
||||
def init(concepts, grammar, expression):
|
||||
context = get_context()
|
||||
for c in concepts:
|
||||
context.sheerka.add_in_cache(c)
|
||||
return_values = get_return_values(context, grammar, expression)
|
||||
|
||||
return context, return_values
|
||||
|
||||
|
||||
@pytest.mark.parametrize("return_values, expected", [
|
||||
([
|
||||
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "in error"),
|
||||
ReturnValueConcept(concept_lexer_name, False, ParserResultConcept(value=[ConceptNode(Concept(), 0, 0)])),
|
||||
ReturnValueConcept("not a parser", True, "some value"),
|
||||
], True),
|
||||
([
|
||||
ReturnValueConcept(concept_lexer_name, False, ParserResultConcept(value=[ConceptNode(Concept(), 0, 0)])),
|
||||
], True),
|
||||
([
|
||||
ReturnValueConcept(BaseParser.PREFIX + "some_name", True, "not in error"),
|
||||
ReturnValueConcept(concept_lexer_name, False, ParserResultConcept(value=[ConceptNode(Concept(), 0, 0)])),
|
||||
], False),
|
||||
([
|
||||
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "in error"),
|
||||
ReturnValueConcept(concept_lexer_name, True, ParserResultConcept(value=[ConceptNode(Concept(), 0, 0)])),
|
||||
], False),
|
||||
([
|
||||
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "in error"),
|
||||
ReturnValueConcept(concept_lexer_name, False, "some value"),
|
||||
], False),
|
||||
([
|
||||
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "in error"),
|
||||
ReturnValueConcept(concept_lexer_name, False, ParserResultConcept(value=["not a concept"])),
|
||||
], False),
|
||||
([
|
||||
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", False, "evaluator in error"),
|
||||
ReturnValueConcept(concept_lexer_name, False, ParserResultConcept(value=[ConceptNode(Concept(), 0, 0)])),
|
||||
ReturnValueConcept("not a parser", True, "some value"),
|
||||
], False),
|
||||
([
|
||||
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, "evaluator"),
|
||||
ReturnValueConcept(concept_lexer_name, False, ParserResultConcept(value=[ConceptNode(Concept(), 0, 0)])),
|
||||
ReturnValueConcept("not a parser", True, "some value"),
|
||||
], False),
|
||||
])
|
||||
def test_i_can_match(return_values, expected):
|
||||
context = get_context()
|
||||
assert ConceptComposerEvaluator().matches(context, return_values) == expected
|
||||
|
||||
|
||||
def test_i_can_eval_simple_concepts():
|
||||
foo = Concept("foo", body="'foo'")
|
||||
bar = Concept("bar", body="'bar'")
|
||||
grammar = {}
|
||||
context, return_values = init([foo, bar], grammar, "bar foo")
|
||||
|
||||
composer = ConceptComposerEvaluator()
|
||||
assert composer.matches(context, return_values)
|
||||
|
||||
ret_val = composer.eval(context, return_values)
|
||||
assert ret_val.status
|
||||
assert ret_val.who == composer.name
|
||||
assert ret_val.value == [Concept("bar", body="bar").init_key(), Concept("foo", body="foo").init_key()]
|
||||
assert ret_val.value[0].metadata.is_evaluated
|
||||
assert ret_val.value[1].metadata.is_evaluated
|
||||
assert ret_val.parents == [return_values[0]]
|
||||
|
||||
|
||||
def test_i_can_eval_simple_concepts_when_some_are_bnf():
|
||||
foo = Concept("foo", body="'foo'")
|
||||
bar = Concept("bar", body="'bar'")
|
||||
grammar = {foo: "foo"}
|
||||
context, return_values = init([foo, bar], grammar, "bar foo")
|
||||
|
||||
composer = ConceptComposerEvaluator()
|
||||
assert composer.matches(context, return_values)
|
||||
|
||||
ret_val = composer.eval(context, return_values)
|
||||
assert ret_val.status
|
||||
assert ret_val.who == composer.name
|
||||
assert ret_val.value == [Concept("bar", body="bar").init_key(), Concept("foo", body="foo").init_key()]
|
||||
assert ret_val.value[0].metadata.is_evaluated
|
||||
assert ret_val.value[1].metadata.is_evaluated
|
||||
assert ret_val.parents == [return_values[0]]
|
||||
|
||||
|
||||
def test_i_can_eval_simple_concept_and_text():
|
||||
foo = Concept("foo", body="'foo'")
|
||||
grammar = {}
|
||||
context, return_values = init([foo], grammar, "'bar' foo")
|
||||
|
||||
composer = ConceptComposerEvaluator()
|
||||
assert composer.matches(context, return_values)
|
||||
|
||||
ret_val = composer.eval(context, return_values)
|
||||
assert ret_val.status
|
||||
assert ret_val.who == composer.name
|
||||
assert ret_val.value == "bar foo"
|
||||
assert ret_val.parents == [return_values[0]]
|
||||
# import pytest
|
||||
#
|
||||
# from core.builtin_concepts import ReturnValueConcept, ParserResultConcept
|
||||
# from core.concept import Concept
|
||||
# from core.sheerka import Sheerka, ExecutionContext
|
||||
# from evaluators.BaseEvaluator import BaseEvaluator
|
||||
# from evaluators.ConceptComposerEvaluator import ConceptComposerEvaluator
|
||||
# from parsers.BaseParser import BaseParser
|
||||
# from parsers.ConceptLexerParser import ConceptNode, ConceptLexerParser, Sequence
|
||||
# from sdp.sheerkaDataProvider import Event
|
||||
#
|
||||
# concept_lexer_name = ConceptLexerParser().name
|
||||
#
|
||||
#
|
||||
# def get_context():
|
||||
# sheerka = Sheerka(skip_builtins_in_db=True)
|
||||
# sheerka.initialize("mem://")
|
||||
# return ExecutionContext("test", Event(), sheerka)
|
||||
#
|
||||
#
|
||||
# def get_return_values(context, grammar, expression):
|
||||
# parser = ConceptLexerParser()
|
||||
# parser.initialize(context, grammar)
|
||||
#
|
||||
# ret_val = parser.parse(context, expression)
|
||||
# assert not ret_val.status
|
||||
# return [ret_val]
|
||||
#
|
||||
#
|
||||
# def init(concepts, grammar, expression):
|
||||
# context = get_context()
|
||||
# for c in concepts:
|
||||
# context.sheerka.add_in_cache(c)
|
||||
# return_values = get_return_values(context, grammar, expression)
|
||||
#
|
||||
# return context, return_values
|
||||
#
|
||||
#
|
||||
# @pytest.mark.parametrize("return_values, expected", [
|
||||
# ([
|
||||
# ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "in error"),
|
||||
# ReturnValueConcept(concept_lexer_name, False, ParserResultConcept(value=[ConceptNode(Concept(), 0, 0)])),
|
||||
# ReturnValueConcept("not a parser", True, "some value"),
|
||||
# ], True),
|
||||
# ([
|
||||
# ReturnValueConcept(concept_lexer_name, False, ParserResultConcept(value=[ConceptNode(Concept(), 0, 0)])),
|
||||
# ], True),
|
||||
# ([
|
||||
# ReturnValueConcept(BaseParser.PREFIX + "some_name", True, "not in error"),
|
||||
# ReturnValueConcept(concept_lexer_name, False, ParserResultConcept(value=[ConceptNode(Concept(), 0, 0)])),
|
||||
# ], False),
|
||||
# ([
|
||||
# ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "in error"),
|
||||
# ReturnValueConcept(concept_lexer_name, True, ParserResultConcept(value=[ConceptNode(Concept(), 0, 0)])),
|
||||
# ], False),
|
||||
# ([
|
||||
# ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "in error"),
|
||||
# ReturnValueConcept(concept_lexer_name, False, "some value"),
|
||||
# ], False),
|
||||
# ([
|
||||
# ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "in error"),
|
||||
# ReturnValueConcept(concept_lexer_name, False, ParserResultConcept(value=["not a concept"])),
|
||||
# ], False),
|
||||
# ([
|
||||
# ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", False, "evaluator in error"),
|
||||
# ReturnValueConcept(concept_lexer_name, False, ParserResultConcept(value=[ConceptNode(Concept(), 0, 0)])),
|
||||
# ReturnValueConcept("not a parser", True, "some value"),
|
||||
# ], False),
|
||||
# ([
|
||||
# ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, "evaluator"),
|
||||
# ReturnValueConcept(concept_lexer_name, False, ParserResultConcept(value=[ConceptNode(Concept(), 0, 0)])),
|
||||
# ReturnValueConcept("not a parser", True, "some value"),
|
||||
# ], False),
|
||||
# ])
|
||||
# def test_i_can_match(return_values, expected):
|
||||
# context = get_context()
|
||||
# assert ConceptComposerEvaluator().matches(context, return_values) == expected
|
||||
#
|
||||
#
|
||||
# def test_i_can_eval_simple_concepts():
|
||||
# foo = Concept("foo", body="'foo'")
|
||||
# bar = Concept("bar", body="'bar'")
|
||||
# grammar = {}
|
||||
# context, return_values = init([foo, bar], grammar, "bar foo")
|
||||
#
|
||||
# composer = ConceptComposerEvaluator()
|
||||
# assert composer.matches(context, return_values)
|
||||
#
|
||||
# ret_val = composer.eval(context, return_values)
|
||||
# assert ret_val.status
|
||||
# assert ret_val.who == composer.name
|
||||
# assert ret_val.value == [Concept("bar", body="bar").init_key(), Concept("foo", body="foo").init_key()]
|
||||
# assert ret_val.value[0].metadata.is_evaluated
|
||||
# assert ret_val.value[1].metadata.is_evaluated
|
||||
# assert ret_val.parents == [return_values[0]]
|
||||
#
|
||||
#
|
||||
# def test_i_can_eval_simple_concepts_when_some_are_bnf():
|
||||
# foo = Concept("foo", body="'foo'")
|
||||
# bar = Concept("bar", body="'bar'")
|
||||
# grammar = {foo: "foo"}
|
||||
# context, return_values = init([foo, bar], grammar, "bar foo")
|
||||
#
|
||||
# composer = ConceptComposerEvaluator()
|
||||
# assert composer.matches(context, return_values)
|
||||
#
|
||||
# ret_val = composer.eval(context, return_values)
|
||||
# assert ret_val.status
|
||||
# assert ret_val.who == composer.name
|
||||
# assert ret_val.value == [Concept("bar", body="bar").init_key(), Concept("foo", body="foo").init_key()]
|
||||
# assert ret_val.value[0].metadata.is_evaluated
|
||||
# assert ret_val.value[1].metadata.is_evaluated
|
||||
# assert ret_val.parents == [return_values[0]]
|
||||
#
|
||||
#
|
||||
# def test_i_can_eval_simple_concept_and_text():
|
||||
# foo = Concept("foo", body="'foo'")
|
||||
# grammar = {}
|
||||
# context, return_values = init([foo], grammar, "'bar' foo")
|
||||
#
|
||||
# composer = ConceptComposerEvaluator()
|
||||
# assert composer.matches(context, return_values)
|
||||
#
|
||||
# ret_val = composer.eval(context, return_values)
|
||||
# assert ret_val.status
|
||||
# assert ret_val.who == composer.name
|
||||
# assert ret_val.value == "bar foo"
|
||||
# assert ret_val.parents == [return_values[0]]
|
||||
|
||||
+477
-369
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept
|
||||
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.sheerka import Sheerka, ExecutionContext
|
||||
from evaluators.ConceptNodeEvaluator import ConceptNodeEvaluator
|
||||
@@ -15,7 +15,7 @@ def get_context():
|
||||
return ExecutionContext("test", Event(), sheerka)
|
||||
|
||||
|
||||
def get_return_value(context, grammar, expression):
|
||||
def from_parsing(context, grammar, expression):
|
||||
parser = ConceptLexerParser()
|
||||
parser.initialize(context, grammar)
|
||||
|
||||
@@ -31,7 +31,7 @@ def init(concept, grammar, text):
|
||||
context.sheerka.add_in_cache(c)
|
||||
else:
|
||||
context.sheerka.add_in_cache(concept)
|
||||
ret_val = get_return_value(context, grammar, text)
|
||||
ret_val = from_parsing(context, grammar, text)
|
||||
node = ret_val.value.value[0]
|
||||
|
||||
return context, node
|
||||
@@ -56,172 +56,24 @@ def test_i_can_match(ret_val, expected):
|
||||
assert ConceptNodeEvaluator().matches(context, ret_val) == expected
|
||||
|
||||
|
||||
def test_parser_result_of_concept_is_returned_when_list_of_one_concept_node():
|
||||
def test_concept_is_returned_when_only_one_in_the_list():
|
||||
foo = Concept("foo")
|
||||
context = get_context()
|
||||
context.sheerka.add_in_cache(foo)
|
||||
|
||||
evaluator = ConceptNodeEvaluator()
|
||||
ret_val = get_return_value(context, {foo: StrMatch("foo")}, "foo")
|
||||
ret_val = from_parsing(context, {foo: StrMatch("foo")}, "foo")
|
||||
|
||||
result = evaluator.eval(context, ret_val)
|
||||
wrapper = result.body
|
||||
return_value = result.body.body
|
||||
|
||||
assert result.who == evaluator.name
|
||||
assert result.status
|
||||
assert result.value == ParserResultConcept(
|
||||
evaluator,
|
||||
"foo",
|
||||
Concept("foo", body="'foo'").init_key(),
|
||||
None)
|
||||
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
assert wrapper.parser == evaluator
|
||||
assert wrapper.source == "foo"
|
||||
assert return_value == Concept("foo", body="foo").init_key()
|
||||
assert return_value.metadata.is_evaluated
|
||||
assert result.parents == [ret_val]
|
||||
|
||||
|
||||
def test_concept_property_is_correctly_updated_for_str_match():
|
||||
foo = Concept("foo")
|
||||
grammar = {foo: StrMatch("foo", rule_name="variable")}
|
||||
context, node = init(foo, grammar, "foo")
|
||||
|
||||
updated = ConceptNodeEvaluator().finalize_concept(context.sheerka, node.concept, node.underlying)
|
||||
|
||||
assert "variable" in updated.props
|
||||
assert updated.props["variable"].value == "'foo'"
|
||||
assert updated.body == "'foo'"
|
||||
|
||||
|
||||
def test_concept_property_is_correctly_updated_for_sequence():
|
||||
foo = Concept("foo")
|
||||
grammar = {foo: Sequence("one", "two", rule_name="variable")}
|
||||
context, node = init(foo, grammar, "one two")
|
||||
|
||||
updated = ConceptNodeEvaluator().finalize_concept(
|
||||
context.sheerka,
|
||||
context.sheerka.new(node.concept.key),
|
||||
node.underlying)
|
||||
|
||||
assert "variable" in updated.props
|
||||
assert updated.props["variable"].value == "'one two'"
|
||||
assert updated.body == "'one two'"
|
||||
|
||||
|
||||
def test_concept_property_is_updated_for_str_in_sequence():
|
||||
foo = Concept("foo")
|
||||
grammar = {foo: Sequence(StrMatch("one", rule_name="s1"), StrMatch("two", rule_name="s2"), rule_name="variable")}
|
||||
context, node = init(foo, grammar, "one two")
|
||||
|
||||
updated = ConceptNodeEvaluator().finalize_concept(
|
||||
context.sheerka,
|
||||
context.sheerka.new(node.concept.key),
|
||||
node.underlying)
|
||||
|
||||
assert updated.props["variable"].value == "'one two'"
|
||||
assert updated.props["s1"].value == "'one'"
|
||||
assert updated.props["s2"].value == "'two'"
|
||||
assert updated.body == "'one two'"
|
||||
|
||||
|
||||
def test_concept_property_is_correctly_updated_for_optional():
|
||||
foo = Concept("foo")
|
||||
grammar = {foo: Sequence("one", Optional("two", rule_name="o"), rule_name="variable")}
|
||||
context, node = init(foo, grammar, "one two")
|
||||
|
||||
updated = ConceptNodeEvaluator().finalize_concept(
|
||||
context.sheerka,
|
||||
context.sheerka.new(node.concept.key),
|
||||
node.underlying)
|
||||
|
||||
assert "variable" in updated.props
|
||||
assert updated.props["variable"].value == "'one two'"
|
||||
assert updated.props["o"].value == "'two'"
|
||||
assert updated.body == "'one two'"
|
||||
|
||||
|
||||
def test_concept_property_is_correctly_updated_for_zero_or_more():
|
||||
foo = Concept("foo")
|
||||
grammar = {foo: ZeroOrMore("one", rule_name="variable")}
|
||||
context, node = init(foo, grammar, "one one one")
|
||||
|
||||
updated = ConceptNodeEvaluator().finalize_concept(
|
||||
context.sheerka,
|
||||
context.sheerka.new(node.concept.key),
|
||||
node.underlying)
|
||||
|
||||
assert "variable" in updated.props
|
||||
assert updated.props["variable"].value == "'one one one'"
|
||||
assert updated.body == "'one one one'"
|
||||
|
||||
|
||||
def test_concept_property_is_correctly_updated_when_list_of_properties():
|
||||
foo = Concept("foo")
|
||||
grammar = {foo: Sequence(StrMatch("one", rule_name="s"), StrMatch("two", rule_name="s"), rule_name="variable")}
|
||||
context, node = init(foo, grammar, "one two")
|
||||
|
||||
updated = ConceptNodeEvaluator().finalize_concept(
|
||||
context.sheerka,
|
||||
context.sheerka.new(node.concept.key),
|
||||
node.underlying)
|
||||
|
||||
assert updated.props["variable"].value == "'one two'"
|
||||
assert updated.props["s"].value == ["'one'", "'two'"]
|
||||
assert updated.body == "'one two'"
|
||||
|
||||
|
||||
def test_concept_property_is_correctly_updated_when_another_concept():
|
||||
foo = Concept("foo")
|
||||
bar = Concept("bar")
|
||||
grammar = {
|
||||
foo: Sequence("one", "two", rule_name="var"),
|
||||
bar: Sequence(foo, "three", "four", rule_name="var")}
|
||||
context, node = init([foo, bar], grammar, "one two three four")
|
||||
|
||||
updated = ConceptNodeEvaluator().finalize_concept(
|
||||
context.sheerka,
|
||||
context.sheerka.new(node.concept.key),
|
||||
node.underlying)
|
||||
|
||||
assert updated.body == "foo 'three four'"
|
||||
assert updated.props["var"].value == "foo 'three four'"
|
||||
assert updated.props["foo"].value == Concept("foo", body="'one two'").set_prop("var", "'one two'").init_key()
|
||||
|
||||
|
||||
def test_concept_property_is_correctly_updated_when_concept_recursion_using_optional():
|
||||
number = Concept("number")
|
||||
add = Concept("add")
|
||||
grammar = {
|
||||
number: OrderedChoice("one", "two"),
|
||||
add: Sequence(number, Optional(Sequence(OrderedChoice("plus", "minus", rule_name="op"), add)))
|
||||
}
|
||||
context, node = init([number, add], grammar, "one plus two")
|
||||
|
||||
updated = ConceptNodeEvaluator().finalize_concept(
|
||||
context.sheerka,
|
||||
context.sheerka.new(node.concept.key),
|
||||
node.underlying)
|
||||
|
||||
assert updated.props["number"].value == Concept("number", body="'one'").init_key()
|
||||
assert updated.props["op"].value == "'plus'"
|
||||
expected_add = Concept("add", body="number"). \
|
||||
set_prop("number", Concept("number", body="'two'").init_key()). \
|
||||
init_key()
|
||||
assert updated.props["add"].value == expected_add
|
||||
|
||||
|
||||
def test_concept_property_is_correctly_updated_when_concept_recursion_using_zero_or_more():
|
||||
number = Concept("number")
|
||||
add = Concept("add")
|
||||
grammar = {
|
||||
number: OrderedChoice("one", "two", 'three'),
|
||||
add: Sequence(number, ZeroOrMore(Sequence(OrderedChoice("plus", "minus", rule_name="op"), number)))
|
||||
}
|
||||
context, node = init([number, add], grammar, "one plus two minus three")
|
||||
|
||||
updated = ConceptNodeEvaluator().finalize_concept(
|
||||
context.sheerka,
|
||||
context.sheerka.new(node.concept.key),
|
||||
node.underlying,
|
||||
init_empty_body=True)
|
||||
|
||||
assert updated.props["number"].value == [Concept("number", body="'one'").init_key(),
|
||||
Concept("number", body="'two'").init_key(),
|
||||
Concept("number", body="'three'").init_key()]
|
||||
assert updated.props["op"].value == ["'plus'", "'minus'"]
|
||||
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
from core.builtin_concepts import ParserResultConcept, BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.sheerka import Sheerka, ExecutionContext
|
||||
from parsers.ConceptLexerParser import ConceptLexerParser, ConceptNode, Sequence, UnrecognizedTokensNode
|
||||
from parsers.MultipleConceptsParser import MultipleConceptsParser
|
||||
from sdp.sheerkaDataProvider import Event
|
||||
|
||||
|
||||
def get_context():
|
||||
sheerka = Sheerka(skip_builtins_in_db=True)
|
||||
sheerka.initialize("mem://")
|
||||
return ExecutionContext("test", Event(), sheerka)
|
||||
|
||||
|
||||
def get_return_value(context, grammar, expression):
|
||||
parser = ConceptLexerParser()
|
||||
parser.initialize(context, grammar)
|
||||
|
||||
ret_val = parser.parse(context, expression)
|
||||
assert not ret_val.status
|
||||
return ret_val
|
||||
|
||||
|
||||
def init(concepts, grammar, expression):
|
||||
context = get_context()
|
||||
for c in concepts:
|
||||
context.sheerka.create_new_concept(context, c)
|
||||
return_value = get_return_value(context, grammar, expression)
|
||||
|
||||
return context, return_value
|
||||
|
||||
|
||||
def test_not_interested_if_not_parser_result():
|
||||
context = get_context()
|
||||
text = "not parser result"
|
||||
|
||||
res = MultipleConceptsParser().parse(context, text)
|
||||
assert res is None
|
||||
|
||||
|
||||
def test_not_interested_if_not_from_concept_lexer_parser():
|
||||
context = get_context()
|
||||
text = ParserResultConcept(parser="not concept lexer", value="some value")
|
||||
|
||||
res = MultipleConceptsParser().parse(context, text)
|
||||
assert res is None
|
||||
|
||||
|
||||
def test_i_can_parse_exact_concepts():
|
||||
foo = Concept("foo", body="'foo'")
|
||||
bar = Concept("bar", body="'bar'")
|
||||
baz = Concept("baz", body="'baz'")
|
||||
grammar = {}
|
||||
context, return_value = init([foo, bar, baz], grammar, "bar foo baz")
|
||||
|
||||
parser = MultipleConceptsParser()
|
||||
ret_val = parser.parse(context, return_value.body)
|
||||
|
||||
assert ret_val.status
|
||||
assert ret_val.who == parser.name
|
||||
assert context.sheerka.isinstance(ret_val.value, BuiltinConcepts.PARSER_RESULT)
|
||||
assert ret_val.value.value == [
|
||||
ConceptNode(bar, 0, 0, source="bar"),
|
||||
ConceptNode(foo, 2, 2, source="foo"),
|
||||
ConceptNode(baz, 4, 4, source="baz")]
|
||||
assert ret_val.value.source == "bar foo baz"
|
||||
|
||||
|
||||
def test_i_can_parse_when_ending_with_bnf():
|
||||
foo = Concept("foo", body="'foo'")
|
||||
bar = Concept("bar", body="'bar'")
|
||||
grammar = {foo: Sequence("foo1", "foo2", "foo3")}
|
||||
context, return_value = init([foo, bar], grammar, "bar foo1 foo2 foo3")
|
||||
|
||||
parser = MultipleConceptsParser()
|
||||
ret_val = parser.parse(context, return_value.body)
|
||||
|
||||
assert ret_val.status
|
||||
assert ret_val.who == parser.name
|
||||
assert context.sheerka.isinstance(ret_val.value, BuiltinConcepts.PARSER_RESULT)
|
||||
assert ret_val.value.value == [("bar", 0, 0, "bar"), ("foo", 2, 6, "foo1 foo2 foo3")]
|
||||
assert ret_val.value.source == "bar foo1 foo2 foo3"
|
||||
|
||||
|
||||
def test_i_can_parse_when_starting_with_bnf():
|
||||
foo = Concept("foo", body="'foo'")
|
||||
bar = Concept("bar", body="'bar'")
|
||||
grammar = {foo: Sequence("foo1", "foo2", "foo3")}
|
||||
context, return_value = init([foo, bar], grammar, "foo1 foo2 foo3 bar")
|
||||
|
||||
parser = MultipleConceptsParser()
|
||||
ret_val = parser.parse(context, return_value.body)
|
||||
|
||||
assert ret_val.status
|
||||
assert ret_val.who == parser.name
|
||||
assert context.sheerka.isinstance(ret_val.value, BuiltinConcepts.PARSER_RESULT)
|
||||
assert ret_val.value.value == [("foo", 0, 4, "foo1 foo2 foo3"), ("bar", 6, 6, "bar")]
|
||||
assert ret_val.value.source == "foo1 foo2 foo3 bar"
|
||||
|
||||
|
||||
def test_i_can_parse_when_concept_are_mixed():
|
||||
foo = Concept("foo")
|
||||
bar = Concept("bar")
|
||||
baz = Concept("baz")
|
||||
grammar = {foo: Sequence("foo1", "foo2", "foo3")}
|
||||
context, return_value = init([foo, bar, baz], grammar, "baz foo1 foo2 foo3 bar")
|
||||
|
||||
parser = MultipleConceptsParser()
|
||||
ret_val = parser.parse(context, return_value.body)
|
||||
|
||||
assert ret_val.status
|
||||
assert ret_val.who == parser.name
|
||||
assert context.sheerka.isinstance(ret_val.value, BuiltinConcepts.PARSER_RESULT)
|
||||
assert ret_val.value.value == [
|
||||
("baz", 0, 0, "baz"),
|
||||
("foo", 2, 6, "foo1 foo2 foo3"),
|
||||
("bar", 8, 8, "bar")]
|
||||
assert ret_val.value.source == "baz foo1 foo2 foo3 bar"
|
||||
|
||||
|
||||
def test_i_can_parse_when_multiple_concept_are_matching():
|
||||
foo = Concept("foo")
|
||||
bar = Concept("bar", body="bar1")
|
||||
baz = Concept("bar", body="bar2")
|
||||
grammar = {foo: "foo"}
|
||||
context, return_value = init([foo, bar, baz], grammar, "foo bar")
|
||||
|
||||
parser = MultipleConceptsParser()
|
||||
ret_val = parser.parse(context, return_value.body)
|
||||
|
||||
assert len(ret_val) == 2
|
||||
assert ret_val[0].status
|
||||
assert ret_val[0].value.value == [("foo", 0, 0, "foo"), ("bar", 2, 2, "bar")]
|
||||
assert ret_val[0].value.source == "foo bar"
|
||||
assert ret_val[0].value.value[1].concept.body == "bar1"
|
||||
|
||||
assert ret_val[1].status
|
||||
assert ret_val[1].value.value == [("foo", 0, 0, "foo"), ("bar", 2, 2, "bar")]
|
||||
assert ret_val[1].value.source == "foo bar"
|
||||
assert ret_val[1].value.value[1].concept.body == "bar2"
|
||||
|
||||
|
||||
def test_i_cannot_parse_when_unrecognized_token():
|
||||
twenty_two = Concept("twenty two")
|
||||
one = Concept("one")
|
||||
grammar = {twenty_two: Sequence("twenty", "two")}
|
||||
context, return_value = init([twenty_two, one], grammar, "twenty two + one")
|
||||
|
||||
parser = MultipleConceptsParser()
|
||||
ret_val = parser.parse(context, return_value.body)
|
||||
|
||||
assert not ret_val.status
|
||||
assert ret_val.who == parser.name
|
||||
assert context.sheerka.isinstance(ret_val.value, BuiltinConcepts.PARSER_RESULT)
|
||||
assert ret_val.value.value == [
|
||||
("twenty two", 0, 2, "twenty two"),
|
||||
(3, 5, " + "),
|
||||
("one", 6, 6, "one")
|
||||
]
|
||||
assert ret_val.value.source == "twenty two + one"
|
||||
@@ -126,3 +126,26 @@ def test_i_can_eval_concept_token():
|
||||
|
||||
assert not evaluated.status
|
||||
assert evaluated.body.body.args[0] == "'int' object has no attribute 'name'"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("text, concept_key, concept_id, use_concept", [
|
||||
("__C__key__C__", "key", None, False),
|
||||
("__C__key__id__C__", "key", "id", False),
|
||||
("__C__USE_CONCEPT__key__id__C__", "key", "id", True),
|
||||
("__C__USE_CONCEPT__key__id__C__", "key", "id", True),
|
||||
])
|
||||
def test_i_can_resolve_name(text, concept_key, concept_id, use_concept):
|
||||
context = get_context()
|
||||
assert PythonEvaluator().resolve_name(context, text) == (concept_key, concept_id, use_concept)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("text", [
|
||||
"__C__",
|
||||
"__C__key",
|
||||
"__C__key____",
|
||||
"__C____",
|
||||
"__C__USE_CONCEPT__",
|
||||
])
|
||||
def test_i_cannot_resolve_name(text):
|
||||
context = get_context()
|
||||
assert PythonEvaluator().resolve_name(context, text) is None
|
||||
|
||||
@@ -86,4 +86,4 @@ def test_i_can_parse_a_concept():
|
||||
assert res
|
||||
assert res.value.value == PythonNode(
|
||||
"c:concept_name: + 1",
|
||||
ast.parse("__C__concept_name__C__+1", mode="eval"))
|
||||
ast.parse("__C__USE_CONCEPT__concept_name__C__+1", mode="eval"))
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
import ast
|
||||
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import ParserResultConcept, BuiltinConcepts, ReturnValueConcept
|
||||
from core.concept import Concept
|
||||
from core.sheerka import Sheerka, ExecutionContext
|
||||
from core.tokenizer import Token, TokenKind, Tokenizer
|
||||
from parsers.ConceptLexerParser import ConceptNode, UnrecognizedTokensNode
|
||||
from parsers.PythonParser import PythonNode, PythonErrorNode
|
||||
from parsers.PythonWithConceptsParser import PythonWithConceptsParser
|
||||
from sdp.sheerkaDataProvider import Event
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
else:
|
||||
tokens = list(Tokenizer(item))
|
||||
result.append(UnrecognizedTokensNode(index, index + len(tokens) - 1, tokens))
|
||||
index += len(tokens)
|
||||
|
||||
return ReturnValueConcept("who", False, ParserResultConcept(parser="name", value=result))
|
||||
|
||||
|
||||
def to_str_ast(expression):
|
||||
return PythonNode.get_dump(ast.parse(expression, mode="eval"))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("text", [
|
||||
"not parser result",
|
||||
ParserResultConcept(value="not a list"),
|
||||
ParserResultConcept(value=[]),
|
||||
ParserResultConcept(value=["not a Node"]),
|
||||
])
|
||||
def test_not_interested(text):
|
||||
context = get_context()
|
||||
|
||||
res = PythonWithConceptsParser().parse(context, text)
|
||||
assert res is None
|
||||
|
||||
|
||||
def test_i_can_parse_concepts_and_python():
|
||||
context = get_context()
|
||||
foo = Concept("foo")
|
||||
input_return_value = get_ret_from(foo, " + 1")
|
||||
|
||||
parser = PythonWithConceptsParser()
|
||||
result = parser.parse(context, input_return_value.body)
|
||||
wrapper = result.value
|
||||
return_value = result.value.value
|
||||
|
||||
assert result.status
|
||||
assert result.who == parser.name
|
||||
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
assert wrapper.source == "foo + 1"
|
||||
assert isinstance(return_value, PythonNode)
|
||||
assert return_value.source == "foo + 1"
|
||||
assert return_value.get_dump(return_value.ast_) == to_str_ast("__C__foo__C__ + 1")
|
||||
assert return_value.concepts["__C__foo__C__"] == foo
|
||||
|
||||
|
||||
def test_i_can_parse_concepts_and_python_when_concept_is_known():
|
||||
context = get_context()
|
||||
foo = Concept("foo")
|
||||
foo = context.sheerka.create_new_concept(context, foo).body.body
|
||||
input_return_value = get_ret_from(foo, " + 1")
|
||||
|
||||
parser = PythonWithConceptsParser()
|
||||
result = parser.parse(context, input_return_value.body)
|
||||
wrapper = result.value
|
||||
return_value = result.value.value
|
||||
|
||||
assert result.status
|
||||
assert result.who == parser.name
|
||||
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
assert wrapper.source == "foo + 1"
|
||||
assert isinstance(return_value, PythonNode)
|
||||
assert return_value.source == "foo + 1"
|
||||
assert return_value.get_dump(return_value.ast_) == to_str_ast("__C__foo__1001__C__ + 1")
|
||||
assert return_value.concepts["__C__foo__1001__C__"] == foo
|
||||
|
||||
|
||||
def test_i_can_parse_when_concept_name_has_invalid_characters():
|
||||
context = get_context()
|
||||
foo = Concept("foo et > (,")
|
||||
foo = context.sheerka.create_new_concept(context, foo).body.body
|
||||
input_return_value = get_ret_from(foo, " + 1")
|
||||
|
||||
parser = PythonWithConceptsParser()
|
||||
result = parser.parse(context, input_return_value.body)
|
||||
return_value = result.value.value
|
||||
|
||||
assert result.status
|
||||
assert return_value.concepts["__C__foo0et000000__1001__C__"] == foo
|
||||
|
||||
|
||||
def test_python_ids_mappings_are_correct_when_concepts_with_the_same_name():
|
||||
context = get_context()
|
||||
foo1 = Concept("foo")
|
||||
foo2 = Concept("foo")
|
||||
foo3 = context.sheerka.create_new_concept(context, Concept("foo", body="foo3")).body.body
|
||||
foo4 = context.sheerka.create_new_concept(context, Concept("foo", body="foo4")).body.body
|
||||
|
||||
input_return_value = get_ret_from(foo1, "+", foo2, "+", foo3, "+", foo4)
|
||||
|
||||
parser = PythonWithConceptsParser()
|
||||
result = parser.parse(context, input_return_value.body)
|
||||
return_value = result.value.value
|
||||
|
||||
assert result.status
|
||||
assert return_value.concepts["__C__foo__C__"] == foo1
|
||||
assert return_value.concepts["__C__foo_1__C__"] == foo2
|
||||
assert return_value.concepts["__C__foo__1001__C__"] == foo3
|
||||
assert return_value.concepts["__C__foo__1002__C__"] == foo4
|
||||
|
||||
|
||||
def test_i_cannot_parse_if_syntax_error():
|
||||
context = get_context()
|
||||
foo = Concept("foo")
|
||||
foo = context.sheerka.create_new_concept(context, foo).body.body
|
||||
input_return_value = get_ret_from(foo, " + ")
|
||||
|
||||
parser = PythonWithConceptsParser()
|
||||
result = parser.parse(context, input_return_value.body)
|
||||
wrapper = result.value
|
||||
return_value = result.value.value
|
||||
|
||||
assert not result.status
|
||||
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(return_value[0], PythonErrorNode)
|
||||
+48
-1
@@ -144,7 +144,7 @@ def test_i_can_get_a_builtin_concept_by_their_enum_or_the_string():
|
||||
assert sheerka.get(str(key)) is not None
|
||||
|
||||
|
||||
def test_i_can_get_new_concept():
|
||||
def test_i_can_get_a_newly_created_concept():
|
||||
sheerka = get_sheerka()
|
||||
concept = get_default_concept()
|
||||
|
||||
@@ -324,6 +324,21 @@ def test_i_can_instantiate_a_concept():
|
||||
assert new.props["b"].value == "value"
|
||||
|
||||
|
||||
def test_i_can_instantiate_with_the_name_and_the_id():
|
||||
sheerka = get_sheerka()
|
||||
sheerka.create_new_concept(get_context(sheerka), Concept("foo", body="foo1"))
|
||||
sheerka.create_new_concept(get_context(sheerka), Concept("foo", body="foo2"))
|
||||
|
||||
concepts = sheerka.new("foo")
|
||||
assert len(concepts) == 2
|
||||
|
||||
foo1 = sheerka.new(("foo", "1001"))
|
||||
assert foo1.body == "foo1"
|
||||
|
||||
foo2 = sheerka.new(("foo", "1002"))
|
||||
assert foo2.body == "foo2"
|
||||
|
||||
|
||||
def test_instances_are_different_when_asking_for_new():
|
||||
sheerka = get_sheerka()
|
||||
concept = get_default_concept()
|
||||
@@ -357,6 +372,38 @@ def test_i_cannot_instantiate_an_unknown_concept():
|
||||
assert new.body == "fake_concept"
|
||||
|
||||
|
||||
def test_i_cannot_instantiate_with_invalid_id():
|
||||
sheerka = get_sheerka()
|
||||
sheerka.create_new_concept(get_context(sheerka), Concept("foo", body="foo1"))
|
||||
sheerka.create_new_concept(get_context(sheerka), Concept("foo", body="foo2"))
|
||||
|
||||
new = sheerka.new(("foo", "invalid_id"))
|
||||
|
||||
assert sheerka.isinstance(new, BuiltinConcepts.UNKNOWN_CONCEPT)
|
||||
assert new.body == "foo"
|
||||
|
||||
|
||||
def test_i_cannot_instantiate_with_invalid_key():
|
||||
sheerka = get_sheerka()
|
||||
sheerka.create_new_concept(get_context(sheerka), Concept("foo", body="foo1"))
|
||||
sheerka.create_new_concept(get_context(sheerka), Concept("foo", body="foo2"))
|
||||
|
||||
new = sheerka.new(("invalid_key", "1001"))
|
||||
|
||||
assert sheerka.isinstance(new, BuiltinConcepts.UNKNOWN_CONCEPT)
|
||||
assert new.body == "invalid_key"
|
||||
|
||||
|
||||
def test_concept_id_is_irrelevant_when_only_one_concept():
|
||||
sheerka = get_sheerka()
|
||||
sheerka.create_new_concept(get_context(sheerka), Concept("foo", body="foo1"))
|
||||
|
||||
new = sheerka.new(("foo", "invalid_id"))
|
||||
|
||||
assert sheerka.isinstance(new, "foo")
|
||||
assert new.body == "foo1"
|
||||
|
||||
|
||||
def test_i_cannot_instantiate_when_properties_are_not_recognized():
|
||||
sheerka = get_sheerka()
|
||||
concept = get_default_concept()
|
||||
|
||||
@@ -401,6 +401,48 @@ def test_i_can_eval_bnf_definitions_from_separate_instances():
|
||||
assert res[0].value.props["a"] == Property("a", sheerka.new(concept_a.key, body="one two").init_key())
|
||||
|
||||
|
||||
def test_i_can_eval_a_mix_with_bnf_and_python():
|
||||
sheerka = get_sheerka()
|
||||
|
||||
sheerka.evaluate_user_input("def concept one as 1")
|
||||
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' one as 20 + one")
|
||||
|
||||
res = sheerka.evaluate_user_input("twenty one + 1")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].body == 22
|
||||
|
||||
|
||||
def test_i_can_eval_a_mix_with_bnf_and_python_when_rule_name():
|
||||
sheerka = get_sheerka()
|
||||
|
||||
sheerka.evaluate_user_input("def concept one as 1")
|
||||
sheerka.evaluate_user_input("def concept two as 2")
|
||||
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit")
|
||||
|
||||
assert sheerka.evaluate_user_input("eval twenty one")[0].body == 21
|
||||
|
||||
res = sheerka.evaluate_user_input("twenty one + 1")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].body == 22
|
||||
|
||||
|
||||
def test_i_can_eval_a_more_complicated_mix_with_bnf_and_python():
|
||||
sheerka = get_sheerka()
|
||||
|
||||
sheerka.evaluate_user_input("def concept one as 1")
|
||||
sheerka.evaluate_user_input("def concept two as 2")
|
||||
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit")
|
||||
|
||||
assert sheerka.evaluate_user_input("eval twenty one")[0].body == 21
|
||||
|
||||
res = sheerka.evaluate_user_input("twenty one + twenty two")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].body == 43
|
||||
|
||||
|
||||
def test_i_can_say_that_a_concept_isa_another_concept():
|
||||
sheerka = get_sheerka()
|
||||
sheerka.evaluate_user_input("def concept foo")
|
||||
|
||||
Reference in New Issue
Block a user