We can now use concept sets in BNF definitions

This commit is contained in:
2020-01-19 21:48:43 +01:00
parent a7b239c167
commit 821614a6c4
16 changed files with 643 additions and 93 deletions
+72 -6
View File
@@ -1,5 +1,6 @@
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.sheerka import Sheerka, ExecutionContext
from core.tokenizer import Tokenizer, TokenKind, LexerError
@@ -17,6 +18,11 @@ def get_context():
return ExecutionContext("sheerka", Event(), sheerka)
class ClassWithName():
def __init__(self, name):
self.name = name
@pytest.mark.parametrize("expression, expected", [
("'str'", StrMatch("str")),
("1", StrMatch("1")),
@@ -41,12 +47,6 @@ def get_context():
("(1|*) +", Sequence(OrderedChoice(StrMatch("1"), StrMatch("*")), StrMatch("+"))),
("1, :&", Sequence(StrMatch("1"), StrMatch(","), StrMatch(":"), StrMatch("&"))),
("(1 )", StrMatch("1")),
("foo", ConceptExpression("foo")),
("foo*", ZeroOrMore(ConceptExpression("foo"))),
("foo 'and' bar+", Sequence(ConceptExpression("foo"), StrMatch("and"), OneOrMore(ConceptExpression("bar")))),
("foo | bar?", OrderedChoice(ConceptExpression("foo"), Optional(ConceptExpression("bar")))),
("'str' = var", Sequence(StrMatch("str"), StrMatch("="), ConceptExpression("var"))),
("'str''='var", Sequence(StrMatch("str"), StrMatch("="), ConceptExpression("var"))),
("'str'=var", StrMatch("str", rule_name="var")),
("'foo'?=var", Optional(StrMatch("foo"), rule_name="var")),
("('foo'?)=var", Optional(StrMatch("foo"), rule_name="var")),
@@ -75,6 +75,47 @@ def test_i_can_parse_regex(expression, expected):
assert res.value.source == expression
@pytest.mark.parametrize("expression, expected", [
("foo", Concept("foo").init_key()),
("foo*", ZeroOrMore(Concept("foo").init_key())),
("foo 'and' bar+", Sequence(Concept("foo").init_key(), StrMatch("and"), OneOrMore(Concept("bar").init_key()))),
("foo | bar?", OrderedChoice(Concept("foo").init_key(), Optional(Concept("bar").init_key()))),
("'str' = var", Sequence(StrMatch("str"), StrMatch("="), Concept("var").init_key())),
("'str''='var", Sequence(StrMatch("str"), StrMatch("="), Concept("var").init_key())),
])
def test_i_can_parse_regex_with_concept(expression, expected):
foo = Concept("foo")
bar = Concept("bar")
var = Concept("var")
context = get_context()
for c in (foo, bar, var):
context.sheerka.add_in_cache(c)
parser = BnfParser()
res = parser.parse(context, Tokenizer(expression))
assert not parser.has_error
assert res.status
assert res.value.value == expected
assert res.value.source == expression
def test_i_can_parse_regex_with_concept_when_the_concept_is_still_under_definition():
expression = "foo"
expected = ConceptExpression("foo")
context = get_context()
context.obj = ClassWithName("foo")
parser = BnfParser()
res = parser.parse(context, Tokenizer(expression))
assert not parser.has_error
assert res.status
assert res.value.value == expected
assert res.value.source == expression
@pytest.mark.parametrize("expression, error", [
("1 ", UnexpectedEndOfFileError()),
("1|", UnexpectedEndOfFileError()),
@@ -117,3 +158,28 @@ def test_i_can_use_the_result_of_regex_parsing_to_parse_a_text():
res = concept_parser.parse(context, "twenty")
assert res.status
assert res.value.body == [cnode("foo", 0, 0, "twenty")]
def test_i_cannot_parse_when_too_many_concepts():
foo1 = Concept(name="foo", body="1")
foo2 = Concept(name="foo", body="2")
context = get_context()
context.sheerka.cache_by_key["foo"] = [foo1, foo2]
regex_parser = BnfParser()
res = regex_parser.parse(context, "foo")
assert not res.status
assert context.sheerka.isinstance(res.value, BuiltinConcepts.CANNOT_RESOLVE_CONCEPT)
assert res.value.body == ('key', 'foo')
def test_i_cannot_parse_when_unknown_concept():
context = get_context()
regex_parser = BnfParser()
res = regex_parser.parse(get_context(), "foo")
assert not res.status
assert context.sheerka.isinstance(res.value, BuiltinConcepts.UNKNOWN_CONCEPT)
assert res.value.body == ('key', 'foo')
+41 -3
View File
@@ -61,6 +61,7 @@ def get_expected(concept, text=None):
c = Concept(name=concept.name)
c.compiled[ConceptParts.BODY] = DoNotResolve(text or concept.name)
c.init_key()
c.metadata.id = concept.id
return c
@@ -606,9 +607,6 @@ def test_i_can_parse_concept_reference_that_is_not_in_grammar():
grammar = {foo: Sequence("twenty", OrderedChoice(one, two))}
context, parser = init([one, two, foo], grammar)
parser = ConceptLexerParser()
parser.initialize(context, grammar)
res = parser.parse(context, "twenty two")
assert res.status
assert res.value.body == [cnode("foo", 0, 2, "twenty two")]
@@ -621,6 +619,46 @@ def test_i_can_parse_concept_reference_that_is_not_in_grammar():
assert res.value.body == [cnode("foo", 0, 2, "twenty one")]
def test_i_can_parse_concept_reference_that_is_group():
"""
if one is number, then number is a 'group'
a group can be found under the sdp entry 'all_<group_name>'
"""
context = get_context()
one = Concept(name="one")
two = Concept(name="two")
number = Concept(name="number")
foo = Concept(name="foo")
for c in [one, two, number, foo]:
context.sheerka.set_id_if_needed(c, False)
context.sheerka.add_in_cache(c)
context.sheerka.add_concept_to_set(context, one, number)
context.sheerka.add_concept_to_set(context, two, number)
grammar = {foo: Sequence("twenty", number)}
parser = ConceptLexerParser()
parser.initialize(context, grammar)
res = parser.parse(context, "twenty two")
assert res.status
assert res.value.body == [cnode("foo", 0, 2, "twenty two")]
concept_found = res.value.body[0].concept
assert cbody(concept_found) == DoNotResolve("twenty two")
assert cprop(concept_found, "two") == get_expected(two, "two")
assert cprop(concept_found, "number") == get_expected(number, get_expected(two, "two"))
res = parser.parse(context, "twenty one")
assert res.status
assert res.value.body == [cnode("foo", 0, 2, "twenty one")]
concept_found = res.value.body[0].concept
assert cbody(concept_found) == DoNotResolve("twenty one")
assert cprop(concept_found, "one") == get_expected(one, "one")
assert cprop(concept_found, "number") == get_expected(number, get_expected(one, "one"))
def test_i_can_parse_zero_or_more():
foo = Concept(name="foo")
grammar = {foo: ZeroOrMore("one")}
+33 -6
View File
@@ -2,6 +2,7 @@ import pytest
import ast
from core.builtin_concepts import ParserResultConcept, BuiltinConcepts, ReturnValueConcept
from core.concept import Concept
from core.sheerka import Sheerka, ExecutionContext
from parsers.ConceptLexerParser import OrderedChoice, StrMatch, ConceptExpression
from parsers.PythonParser import PythonParser, PythonNode
@@ -191,8 +192,7 @@ def concept add one to a as
return_value = res.value
assert not res.status
assert isinstance(return_value, ParserResultConcept)
assert sheerka.isinstance(return_value.value[0], BuiltinConcepts.TOO_MANY_ERRORS)
assert context.sheerka.isinstance(return_value, BuiltinConcepts.TOO_MANY_ERRORS)
def test_name_is_mandatory():
@@ -239,8 +239,7 @@ def test_i_can_detect_error_in_declaration(text):
return_value = res.value
assert not res.status
assert isinstance(return_value, ParserResultConcept)
assert sheerka.isinstance(return_value.value[0], BuiltinConcepts.TOO_MANY_ERRORS)
assert sheerka.isinstance(return_value, BuiltinConcepts.TOO_MANY_ERRORS)
def test_new_line_is_not_allowed_in_the_name():
@@ -255,11 +254,15 @@ def test_new_line_is_not_allowed_in_the_name():
def test_i_can_parse_def_concept_from_regex():
context = get_context()
a_concept = Concept("a_concept")
context.sheerka.add_in_cache(a_concept)
text = "def concept name from bnf a_concept | 'a_string' as __definition[0]"
parser = DefaultParser()
res = parser.parse(get_context(), text)
res = parser.parse(context, text)
node = res.value.value
definition = OrderedChoice(ConceptExpression("a_concept"), StrMatch("a_string"))
definition = OrderedChoice(a_concept, StrMatch("a_string"))
parser_result = ParserResultConcept(BnfParser(), "a_concept | 'a_string'", definition, definition)
expected = get_def_concept(name="name", body="__definition[0]", definition=parser_result)
@@ -270,6 +273,18 @@ def test_i_can_parse_def_concept_from_regex():
assert node == expected
def test_i_can_parse_def_concept_where_bnf_references_itself():
context = get_context()
a_concept = Concept("a_concept")
context.sheerka.add_in_cache(a_concept)
text = "def concept name from bnf 'a' + name?"
parser = DefaultParser()
parser.parse(context, text)
assert not parser.has_error
def test_i_can_detect_empty_bnf_declaration():
text = "def concept name from bnf as __definition[0]"
@@ -339,3 +354,15 @@ def test_i_cannot_parse_when_tokenizer_fails(text, error_msg, error_text):
assert isinstance(res.body.body[0], LexerError)
assert res.body.body[0].message == error_msg
assert res.body.body[0].text == error_text
def test_i_cannot_parse_bnf_definition_referencing_unknown_concept():
context = get_context()
text = "def concept name from bnf unknown"
parser = DefaultParser()
res = parser.parse(context, text)
assert not res.status
assert context.sheerka.isinstance(res.value, BuiltinConcepts.UNKNOWN_CONCEPT)
assert res.value.body == ("key", "unknown")
+1 -1
View File
@@ -90,7 +90,7 @@ def test_i_can_recognize_a_concept_with_variables():
def test_i_can_recognize_a_concept_with_duplicate_variables():
context = get_context()
concept = get_concept("a + b + a", ["a", "b"])
context.sheerka.concepts_cache[concept.key] = concept
context.sheerka.cache_by_key[concept.key] = concept
source = "10 + 5 + 10"
results = ExactConceptParser().parse(context, source)
-2
View File
@@ -50,8 +50,6 @@ def test_i_can_parse_from_tokens(text, expected):
"foo = 'name"
])
def test_i_can_detect_error(text):
text = "1+"
parser = PythonParser()
res = parser.parse(get_context(), text)
+99 -17
View File
@@ -76,13 +76,13 @@ def test_i_can_list_builtin_concepts():
def test_builtin_concepts_are_initialized():
sheerka = get_sheerka(skip_builtins_in_db=False)
assert len(sheerka.concepts_cache) == len(BuiltinConcepts)
assert len(sheerka.cache_by_key) == len(BuiltinConcepts)
for concept_name in BuiltinConcepts:
assert str(concept_name) in sheerka.concepts_cache
assert str(concept_name) in sheerka.cache_by_key
assert sheerka.sdp.get_safe(sheerka.CONCEPTS_ENTRY, str(concept_name)) is not None
for key, concept_class in sheerka.get_builtins_classes_as_dict().items():
assert isinstance(sheerka.concepts_cache[key], concept_class)
assert isinstance(sheerka.cache_by_key[key], concept_class)
def test_builtin_concepts_can_be_updated():
@@ -113,7 +113,8 @@ def test_i_can_add_a_concept():
assert concept_found.key == "__var__0 + __var__1"
assert concept_found.id == "1001"
assert concept.key in sheerka.concepts_cache
assert concept.key in sheerka.cache_by_key
assert concept.id in sheerka.cache_by_id
assert sheerka.sdp.io.exists(
sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_found.get_digest()))
@@ -154,7 +155,10 @@ def test_i_can_get_a_newly_created_concept():
from_cache = sheerka.get(concept.key)
assert from_cache is not None
assert from_cache.key == concept.key
assert from_cache == concept
from_cache = sheerka.get_by_id(concept.id)
assert from_cache is not None
assert from_cache == concept
@@ -163,7 +167,7 @@ def test_i_first_look_in_local_cache():
concept = get_default_concept()
sheerka.create_new_concept(get_context(sheerka), concept)
sheerka.concepts_cache[concept.key].pre = "I have modified the concept in cache"
sheerka.cache_by_key[concept.key].pre = "I have modified the concept in cache"
from_cache = sheerka.get(concept.key)
assert from_cache is not None
@@ -180,12 +184,29 @@ def test_i_can_get_a_known_concept_when_not_in_cache():
concept = get_default_concept()
sheerka.create_new_concept(get_context(sheerka), concept)
sheerka.concepts_cache = {} # reset the cache
sheerka.cache_by_key = {} # reset the cache
loaded = sheerka.get(concept.key)
assert loaded is not None
assert loaded == concept
# I can also get it by its id
loaded = sheerka.sdp.get(sheerka.CONCEPTS_BY_ID_ENTRY, concept.id)
assert loaded is not None
assert loaded == concept
def test_i_can_get_a_concept_by_its_id():
sheerka = get_sheerka()
concept = get_default_concept()
sheerka.create_new_concept(get_context(sheerka), concept)
sheerka.cache_by_key = {} # reset the cache
loaded = sheerka.get_by_id(concept.id)
assert loaded is not None
assert loaded == concept
def test_i_can_get_list_of_concept_when_same_key_when_no_cache():
sheerka = get_sheerka()
@@ -198,7 +219,7 @@ def test_i_can_get_list_of_concept_when_same_key_when_no_cache():
assert res1.value.body.key == res2.value.body.key # same key
sheerka.concepts_cache = {} # reset the cache
sheerka.cache_by_key = {} # reset the cache
result = sheerka.get(concept1.key)
assert len(result) == 2
@@ -217,7 +238,7 @@ def test_i_can_get_list_of_concept_when_same_key_when_cache():
assert res1.value.body.key == res2.value.body.key # same key
# sheerka.concepts_cache = {} # Do not reset the cache
# sheerka.cache_by_key = {} # Do not reset the cache
result = sheerka.get(concept1.key)
assert len(result) == 2
@@ -280,14 +301,25 @@ def test_i_cannot_get_when_key_is_none():
assert res.body == "Concept key is undefined."
def test_unknown_concept_is_return_when_the_concept_is_not_found():
def test_unknown_concept_is_return_when_the_concept_key_is_not_found():
sheerka = get_sheerka()
loaded = sheerka.get("concept_that_does_not_exist")
loaded = sheerka.get("key_that_does_not_exist")
assert loaded is not None
assert sheerka.isinstance(loaded, BuiltinConcepts.UNKNOWN_CONCEPT)
assert loaded.body == "concept_that_does_not_exist"
assert loaded.body == ("key", "key_that_does_not_exist")
assert loaded.metadata.is_evaluated
def test_unknown_concept_is_return_when_the_concept_id_is_not_found():
sheerka = get_sheerka()
loaded = sheerka.get_by_id("id_that_does_not_exist")
assert loaded is not None
assert sheerka.isinstance(loaded, BuiltinConcepts.UNKNOWN_CONCEPT)
assert loaded.body == ("id", "id_that_does_not_exist")
assert loaded.metadata.is_evaluated
@@ -372,7 +404,7 @@ def test_i_cannot_instantiate_an_unknown_concept():
new = sheerka.new("fake_concept")
assert sheerka.isinstance(new, BuiltinConcepts.UNKNOWN_CONCEPT)
assert new.body == "fake_concept"
assert new.body == ('key', 'fake_concept')
def test_i_cannot_instantiate_with_invalid_id():
@@ -383,7 +415,7 @@ def test_i_cannot_instantiate_with_invalid_id():
new = sheerka.new(("foo", "invalid_id"))
assert sheerka.isinstance(new, BuiltinConcepts.UNKNOWN_CONCEPT)
assert new.body == "foo"
assert new.body == [('key', 'foo'), ('id', 'invalid_id')]
def test_i_cannot_instantiate_with_invalid_key():
@@ -394,7 +426,7 @@ def test_i_cannot_instantiate_with_invalid_key():
new = sheerka.new(("invalid_key", "1001"))
assert sheerka.isinstance(new, BuiltinConcepts.UNKNOWN_CONCEPT)
assert new.body == "invalid_key"
assert new.body == [('key', 'invalid_key'), ('id', '1001')]
def test_concept_id_is_irrelevant_when_only_one_concept():
@@ -457,8 +489,8 @@ def test_list_of_concept_is_sorted_by_id():
@pytest.mark.parametrize("body, expected", [
(None, None),
("", ""),
# (None, None),
# ("", ""),
("1", 1),
("1+1", 2),
("'one'", "one"),
@@ -871,3 +903,53 @@ def test_i_cannot_add_the_same_concept_twice_in_a_set():
all_entries = sheerka.sdp.get("All_" + all_foos.id, None, False)
assert len(all_entries) == 1
assert foo.id in all_entries
def test_i_get_elements_from_a_set():
sheerka = get_sheerka(False, False)
one = Concept("one")
two = Concept("two")
three = Concept("three")
number = Concept("number")
for c in [one, two, three, number]:
sheerka.set_id_if_needed(c, False)
sheerka.add_in_cache(c)
context = get_context(sheerka)
for c in [one, two, three]:
sheerka.add_concept_to_set(context, c, number)
elements = sheerka.get_set_elements(number)
assert set(elements) == set([one, two, three])
def test_i_cannot_get_elements_if_not_a_set():
sheerka = get_sheerka(False, False)
one = Concept("one")
sheerka.set_id_if_needed(one, False)
sheerka.add_in_cache(one)
error = sheerka.get_set_elements(one)
assert sheerka.isinstance(error, BuiltinConcepts.NOT_A_SET)
assert error.body == one
def test_isa_and_isa_group():
sheerka = get_sheerka()
group = Concept("group").init_key()
group.metadata.id = "1001"
assert not sheerka.isagroup(group)
foo = Concept("foo").init_key()
foo.metadata.id = "1002"
assert not sheerka.isa(foo, group)
context = get_context(sheerka)
sheerka.add_concept_to_set(context, foo, group)
assert sheerka.isagroup(group)
assert sheerka.isa(foo, group)
+90 -1
View File
@@ -164,7 +164,7 @@ class ObjWithDigestWithKey:
return hash((self.a, self.b))
def __eq__(self, obj):
return isinstance(obj, ObjNoKey) and \
return isinstance(obj, ObjWithDigestWithKey) and \
self.a == obj.a and \
self.b == obj.b
@@ -529,6 +529,44 @@ def test_i_can_add_obj_with_key_to_a_list(root):
assert loaded == ["foo", "bar", ObjWithKey("a", "b")]
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_add_a_reference(root):
sdp = SheerkaDataProvider(root)
sdp.serializer.register(PickleSerializer(lambda o: isinstance(o, ObjWithDigestWithKey)))
obj1 = ObjWithDigestWithKey(1, "foo")
sdp.add(evt_digest, "entry", obj1, use_ref=True)
sdp.add(evt_digest, "entry_by_value", {obj1.b: obj1.get_digest()}, is_ref=True)
# another object
obj2 = ObjWithDigestWithKey(2, "bar")
sdp.add(evt_digest, "entry", obj2, use_ref=True)
sdp.add(evt_digest, "entry_by_value", {obj2.b: obj2.get_digest()}, is_ref=True)
state = sdp.load_state(sdp.get_snapshot())
assert state.data == {
"entry": {
"1": '##REF##:' + obj1.get_digest(),
"2": '##REF##:' + obj2.get_digest(),
},
"entry_by_value": {
"foo": '##REF##:' + obj1.get_digest(),
"bar": '##REF##:' + obj2.get_digest()
},
}
# sanity check, make sure that I can load back
loaded1 = sdp.get("entry_by_value", "foo")
assert loaded1 == ObjWithDigestWithKey(1, "foo")
assert getattr(loaded1, Serializer.ORIGIN) == obj1.get_digest()
loaded2 = sdp.get("entry_by_value", "bar")
assert loaded2 == ObjWithDigestWithKey(2, "bar")
assert getattr(loaded2, Serializer.ORIGIN) == obj2.get_digest()
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
@@ -650,6 +688,20 @@ def test_i_cannot_add_the_same_digest_twice_in_the_same_entry4(root):
assert error.value.args[0] == "Duplicate object."
def test_i_cannot_add_using_use_ref_and_is_ref():
sdp = SheerkaDataProvider("mem://")
with pytest.raises(SheerkaDataProviderError) as error:
sdp.add(evt_digest, "entry", ObjWithDigestWithKey("a", "b"), use_ref=True, is_ref=True)
def test_i_cannot_add_using_is_ref_if_obj_is_not_a_dictionary():
sdp = SheerkaDataProvider("mem://")
with pytest.raises(SheerkaDataProviderError) as error:
sdp.add(evt_digest, "entry", ObjWithDigestWithKey("a", "b"), is_ref=True)
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
@@ -782,6 +834,43 @@ def test_i_can_set_using_reference(root):
assert getattr(loaded, Serializer.ORIGIN) == "95b5cbab545dded0b90b57a3d15a157b9a559fb586ee2f8d6ccbc6d2491f1268"
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_set_a_reference(root):
sdp = SheerkaDataProvider(root)
sdp.serializer.register(PickleSerializer(lambda o: isinstance(o, ObjWithDigestWithKey)))
obj = ObjWithDigestWithKey(1, "foo")
sdp.add(evt_digest, "entry", obj, use_ref=True)
sdp.set(evt_digest, "entry_by_value", {obj.b: obj.get_digest()}, is_ref=True)
state = sdp.load_state(sdp.get_snapshot())
assert state.data == {
"entry": {"1": '##REF##:' + obj.get_digest()},
"entry_by_value": {"foo": '##REF##:' + obj.get_digest()},
}
# sanity check, make sure that I can load back
loaded = sdp.get("entry_by_value", "foo")
assert loaded == ObjWithDigestWithKey(1, "foo")
assert getattr(loaded, Serializer.ORIGIN) == obj.get_digest()
def test_i_cannot_set_using_use_ref_and_is_ref():
sdp = SheerkaDataProvider("mem://")
with pytest.raises(SheerkaDataProviderError) as error:
sdp.set(evt_digest, "entry", ObjWithDigestWithKey("a", "b"), use_ref=True, is_ref=True)
def test_i_cannot_set_using_is_ref_if_obj_is_not_a_dictionary():
sdp = SheerkaDataProvider("mem://")
with pytest.raises(SheerkaDataProviderError) as error:
sdp.set(evt_digest, "entry", ObjWithDigestWithKey("a", "b"), is_ref=True)
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
+2 -2
View File
@@ -18,8 +18,8 @@ def get_context(sheerka):
def get_ret_val(sheerka, concept, who="who"):
concept.init_key()
if concept.key not in sheerka.concepts_cache:
sheerka.concepts_cache[concept.key] = concept
if concept.key not in sheerka.cache_by_key:
sheerka.cache_by_key[concept.key] = concept
return sheerka.ret(who, True, sheerka.new(concept.key))
+66 -4
View File
@@ -152,7 +152,8 @@ as:
for prop in PROPERTIES_TO_SERIALIZE:
assert getattr(concept_saved.metadata, prop) == getattr(expected.metadata, prop)
assert concept_saved.key in sheerka.concepts_cache
assert concept_saved.key in sheerka.cache_by_key
assert concept_saved.id in sheerka.cache_by_id
assert sheerka.sdp.io.exists(
sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_saved.get_digest()))
@@ -182,7 +183,8 @@ def test_i_can_eval_def_concept_part_when_one_part_is_a_ref_of_another_concept()
for prop in PROPERTIES_TO_SERIALIZE:
assert getattr(concept_saved.metadata, prop) == getattr(expected.metadata, prop)
assert concept_saved.key in sheerka.concepts_cache
assert concept_saved.key in sheerka.cache_by_key
assert concept_saved.id in sheerka.cache_by_id
assert sheerka.sdp.io.exists(
sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_saved.get_digest()))
@@ -331,8 +333,7 @@ def test_i_can_create_concept_with_bnf_definition():
saved_definitions = sheerka.sdp.get_safe(sheerka.CONCEPTS_DEFINITIONS_ENTRY)
expected_bnf = Sequence(
ConceptExpression("a", rule_name="a"),
Optional(Sequence(StrMatch("plus"), ConceptExpression("plus", rule_name="plus"))))
a, Optional(Sequence(StrMatch("plus"), ConceptExpression("plus", rule_name="plus"))))
assert saved_definitions[saved_concept] == expected_bnf
new_concept = res[0].value.body
@@ -421,6 +422,23 @@ def test_i_can_eval_bnf_definitions_from_separate_instances():
"def concept digit from bnf one|two",
"def concept twenties from bnf twenty digit as twenty + digit"
]),
("When using isa and concept twenty", [
"def concept one as 1",
"def concept two as 2",
"def concept number",
"one isa number",
"two isa number",
"def concept twenties from bnf 'twenty' number as 20 + number"
]),
("When using isa and concept twenty", [
"def concept one as 1",
"def concept two as 2",
"def concept twenty as 20",
"def concept number",
"one isa number",
"two isa number",
"def concept twenties from bnf twenty number as 20 + number"
]),
])
def test_i_can_mix_concept_with_python_to_define_numbers(desc, definitions):
sheerka = get_sheerka()
@@ -460,6 +478,50 @@ def test_i_can_mix_concept_with_python_to_define_numbers(desc, definitions):
assert res[0].body == 23
def test_i_can_mix_bnf_and_isa():
"""
if 'one' isa 'number, twenty number should be recognized
:return:
"""
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 number")
sheerka.evaluate_user_input("one isa number")
sheerka.evaluate_user_input("two isa number")
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' number as 20 + number")
res = sheerka.evaluate_user_input("twenty one")
assert len(res) == 1
assert res[0].status
assert res[0].body == simplec("twenties", 21)
res = sheerka.evaluate_user_input("twenty one + 1")
assert len(res) == 1
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("twenty one + one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("twenty one + twenty two")
assert len(res) == 1
assert res[0].status
assert res[0].body == 43
res = sheerka.evaluate_user_input("1 + twenty one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("1 + 1 + twenty one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 23
def test_i_can_mix_concept_of_concept():
sheerka = get_sheerka()