Refactored to use cached_asts in Concepts, rather than setting up a value directly

This commit is contained in:
2020-01-12 10:28:44 +01:00
parent 73a6d4e6c2
commit 51fa9629d0
9 changed files with 256 additions and 167 deletions
+13
View File
@@ -293,3 +293,16 @@ class Property:
def __hash__(self):
return hash((self.name, self.value))
@dataclass()
class DoNotResolve:
"""
This class is used to that the metadata (or the prop) of the concept must not be evaluated
thru sheerka.execute
For example, if you want to set a value to the BODY that will not change when
when the concept will be evaluated,
set concept.cached_asts[BODY] to DoNotResolve(value)
"""
value: object
+78 -34
View File
@@ -1,5 +1,5 @@
from core.builtin_concepts import BuiltinConcepts, ErrorConcept, ReturnValueConcept, BuiltinErrors, BuiltinUnique
from core.concept import Concept, ConceptParts, PROPERTIES_FOR_NEW
from core.concept import Concept, ConceptParts, PROPERTIES_FOR_NEW, DoNotResolve
from parsers.BaseParser import BaseParser
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event, SheerkaDataProviderDuplicateKeyError
import core.utils
@@ -551,6 +551,9 @@ class Sheerka(Concept):
"""
steps = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING]
for part_key in ConceptParts:
if part_key in concept.cached_asts:
continue
source = getattr(concept.metadata, part_key.value)
if source is None or not isinstance(source, str) or source == "":
# the only sources that I am sure to parse are strings
@@ -565,6 +568,9 @@ class Sheerka(Concept):
sub_context.add_values(return_values=res)
for prop in concept.props:
if prop in concept.cached_asts:
continue
value = concept.props[prop].value
if value:
if isinstance(value, Concept):
@@ -604,14 +610,65 @@ class Sheerka(Concept):
if concept.metadata.is_evaluated:
return concept
def _resolve(return_value, desc, obj):
def _resolve(to_resolve, current_prop, current_concept):
if isinstance(to_resolve, DoNotResolve):
return to_resolve.value
desc = f"Evaluating {current_prop} (concept={current_concept})"
context.log(logger, desc, self.evaluate_concept.__name__)
with context.push(desc=desc, obj=obj) as sub_context:
with context.push(desc=desc, obj=current_concept) as sub_context:
sub_context.log_new(logger)
r = self.execute(sub_context, return_value, CONCEPT_EVALUATION_STEPS, logger)
one_r = core.builtin_helpers.expect_one(context, r)
sub_context.add_values(return_values=one_r)
return one_r
# when it's a concept, evaluate it
if isinstance(to_resolve, Concept):
evaluated = self.evaluate_concept(sub_context, to_resolve)
sub_context.add_values(return_values=evaluated)
if evaluated.key == to_resolve.key:
return evaluated
else:
error = evaluated
# otherwise, execute all return values to find out what is the value
else:
r = self.execute(sub_context, to_resolve, CONCEPT_EVALUATION_STEPS, logger)
one_r = core.builtin_helpers.expect_one(context, r)
sub_context.add_values(return_values=one_r)
if one_r.status:
return one_r.value
else:
error = one_r.value
return self.new(BuiltinConcepts.CONCEPT_EVAL_ERROR,
body=error,
concept=concept,
property_name=prop_name)
def _resolve_list(sheerka, list_to_resolve, current_prop, current_concept):
"""When dealing with a list, there are two possibilities"""
# It may be a list of ReturnValueConcept to execute (always the case for metadata)
# or a list of single values (may be the case for properties)
# in this latter case, all values are to be processed one by one and a list should be returned
if len(list_to_resolve) == 0:
return []
if sheerka.isinstance(list_to_resolve[0], BuiltinConcepts.RETURN_VALUE):
return _resolve(list_to_resolve, current_prop, current_concept)
res = []
for to_resolve in list_to_resolve:
# sanity check
if sheerka.isinstance(to_resolve, BuiltinConcepts.RETURN_VALUE):
return self.new(BuiltinConcepts.CONCEPT_EVAL_ERROR,
body="Mix between real values and return values",
concept=concept,
property_name=prop_name)
r = _resolve(to_resolve, current_prop, current_concept)
if sheerka.isinstance(r, BuiltinConcepts.CONCEPT_EVAL_ERROR):
return r
res.append(r)
return res
# WHERE condition should already be validated by the parser.
# It's a mandatory condition for the concept before it can be recognized
@@ -620,9 +677,7 @@ class Sheerka(Concept):
# TODO : Validate the PRE condition
#
if len(concept.cached_asts) == 0:
context.log(logger, "concept asts are not initialized. Initializing.", self.evaluate_concept.__name__)
self.initialize_concept_asts(context, concept, logger)
self.initialize_concept_asts(context, concept, logger)
# to make sure of the order, it don't use ConceptParts.get_parts()
# props must be evaluated first
@@ -632,35 +687,24 @@ class Sheerka(Concept):
if metadata_to_eval == "props":
for prop_name in (p for p in concept.props if p in concept.cached_asts):
prop_ast = concept.cached_asts[prop_name]
if isinstance(concept.cached_asts[prop_name], Concept):
context.log(
logger, f"Evaluation prop={prop_name}, value={prop_ast}", self.evaluate_concept.__name__)
with context.push(f"Evaluation property '{prop_name}', value='{prop_ast}'") as sub_context:
sub_context.log_new(logger)
evaluated = self.evaluate_concept(sub_context, prop_ast)
sub_context.add_values(return_values=evaluated)
concept.set_prop(prop_name, evaluated)
if isinstance(prop_ast, list):
resolved = _resolve_list(context.sheerka, prop_ast, prop_name, None)
else:
res = _resolve(prop_ast, f"Evaluating property '{prop_name}'", None)
if res.status:
concept.set_prop(prop_name, res.value)
else:
return self.new(BuiltinConcepts.CONCEPT_EVAL_ERROR,
body=res.value,
concept=concept,
property_name=prop_name)
resolved = _resolve(prop_ast, prop_name, None)
if context.sheerka.isinstance(resolved, BuiltinConcepts.CONCEPT_EVAL_ERROR):
return resolved
else:
concept.set_prop(prop_name, resolved)
else:
part_key = ConceptParts(metadata_to_eval)
if part_key in concept.cached_asts and concept.cached_asts[part_key] is not None:
res = _resolve(concept.cached_asts[part_key], f"Evaluating '{part_key}'", concept)
if res.status:
setattr(concept.metadata, metadata_to_eval, res.value)
metadata_ast = concept.cached_asts[part_key]
resolved = _resolve(metadata_ast, part_key, concept)
if context.sheerka.isinstance(resolved, BuiltinConcepts.CONCEPT_EVAL_ERROR):
return resolved
else:
return self.new(BuiltinConcepts.CONCEPT_EVAL_ERROR,
body=res.value,
concept=concept,
property_name=part_key)
setattr(concept.metadata, metadata_to_eval, resolved)
#
# TODO : Validate the POST condition
+1 -3
View File
@@ -107,9 +107,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
sub_context.add_values(return_values=evaluated)
if evaluated.key == concept.key:
my_locals[name] = evaluated if return_concept else \
evaluated.body if ConceptParts.BODY in evaluated.cached_asts else \
evaluated
my_locals[name] = evaluated if return_concept else context.sheerka.value(evaluated)
if self.locals:
my_locals.update(self.locals)
+10 -8
View File
@@ -9,7 +9,7 @@
from dataclasses import field, dataclass
from collections import defaultdict
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.concept import Concept, ConceptParts, DoNotResolve
from core.tokenizer import TokenKind, Tokenizer, Token
from parsers.BaseParser import BaseParser, Node, ErrorNode
import core.utils
@@ -702,6 +702,9 @@ class ConceptLexerParser(BaseParser):
else:
to_match = node.concept
if to_match not in self.concepts_grammars:
return False
return _is_infinite_recursion(ref_concept, self.concepts_grammars[to_match])
if isinstance(node, OrderedChoice):
@@ -847,17 +850,17 @@ class ConceptLexerParser(BaseParser):
Adds a new entry,
makes a list if the property already exists
"""
if prop_name not in _concept.props or _concept.props[prop_name].value is None:
if prop_name not in _concept.cached_asts or _concept.cached_asts[prop_name] is None:
# new entry
_concept.set_prop(prop_name, value)
_concept.cached_asts[prop_name] = value
else:
# make a list if there was a value
previous_value = _concept.props[prop_name].value
previous_value = _concept.cached_asts[prop_name]
if isinstance(previous_value, list):
previous_value.append(value)
else:
new_value = [previous_value, value]
_concept.set_prop(prop_name, new_value)
_concept.cached_asts[prop_name] = new_value
def _look_for_concept_match(_underlying):
if isinstance(_underlying.parsing_expression, ConceptMatch):
@@ -881,7 +884,7 @@ class ConceptLexerParser(BaseParser):
result = self.finalize_concept(sheerka, ref_tpl, concept_match_node.children[0], init_empty_body)
_underlying_value_cache[id(concept_match_node)] = result
else:
result = _underlying.source
result = DoNotResolve(_underlying.source)
return result
@@ -898,8 +901,7 @@ class ConceptLexerParser(BaseParser):
concept = sheerka.new(key)
if init_empty_body and concept.body is None:
value = _get_underlying_value(underlying)
concept.metadata.body = value
concept.metadata.is_evaluated = True
concept.cached_asts[ConceptParts.BODY] = value
if underlying.parsing_expression.rule_name:
_add_prop(concept, underlying.parsing_expression.rule_name, value)
+59 -71
View File
@@ -1,7 +1,7 @@
import pytest
import core.utils
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.concept import Concept, ConceptParts, DoNotResolve
from core.sheerka import Sheerka, ExecutionContext
from core.tokenizer import Tokenizer, TokenKind, Token
from parsers.ConceptLexerParser import ConceptLexerParser, ConceptNode, Sequence, StrMatch, OrderedChoice, Optional, \
@@ -58,7 +58,20 @@ def get_context():
def get_expected(concept, text=None):
return Concept(name=concept.name, body=text or concept.name).init_key()
c = Concept(name=concept.name)
c.cached_asts[ConceptParts.BODY] = DoNotResolve(text or concept.name)
c.init_key()
return c
def cbody(concept):
"""cbody stands for compiled body"""
return concept.cached_asts[ConceptParts.BODY]
def cprop(concept, prop_name):
"""cbody stands for compiled property"""
return concept.cached_asts[prop_name]
def init(concepts, grammar):
@@ -359,20 +372,15 @@ def test_i_can_use_reference():
assert context.sheerka.isinstance(res[0].value, BuiltinConcepts.PARSER_RESULT)
assert res[0].value.body == [("foo", 0, 2, "one two")]
concept_found_1 = res[0].value.body[0].concept
assert concept_found_1.metadata.is_evaluated
assert concept_found_1.body == "one two"
assert cbody(concept_found_1) == DoNotResolve("one two")
assert res[1].status
assert context.sheerka.isinstance(res[1].value, BuiltinConcepts.PARSER_RESULT)
assert res[1].value.body == [("bar", 0, 2, "one two")]
concept_found_2 = res[1].value.body[0].concept
assert concept_found_2.metadata.is_evaluated
# the body and the prop['foo'] are the same concept 'foo'
assert isinstance(concept_found_2.body, Concept)
assert concept_found_2.body.key == "foo"
assert concept_found_2.body.metadata.is_evaluated
assert concept_found_2.body.body == "one two"
assert id(concept_found_2.props["foo"].value) == id(concept_found_2.body)
assert cbody(concept_found_2) == get_expected(foo, "one two")
assert id(cprop(concept_found_2, "foo")) == id(cbody(concept_found_2))
def test_i_can_use_a_reference_with_a_body():
@@ -394,20 +402,15 @@ def test_i_can_use_a_reference_with_a_body():
assert context.sheerka.isinstance(res[0].value, BuiltinConcepts.PARSER_RESULT)
assert res[0].value.body == [("foo", 0, 2, "one two")]
concept_found_1 = res[0].value.body[0].concept
assert not concept_found_1.metadata.is_evaluated
assert concept_found_1.body == "'foo'"
assert res[1].status
assert context.sheerka.isinstance(res[1].value, BuiltinConcepts.PARSER_RESULT)
assert res[1].value.body == [("bar", 0, 2, "one two")]
concept_found_2 = res[1].value.body[0].concept
assert concept_found_2.metadata.is_evaluated
# the body and the prop['foo'] are the same concept 'foo'
assert isinstance(concept_found_2.body, Concept)
assert concept_found_2.body.key == "foo"
assert not concept_found_2.body.metadata.is_evaluated
assert concept_found_2.body.body == "'foo'"
assert id(concept_found_2.props["foo"].value) == id(concept_found_2.body)
assert cbody(concept_found_2) == foo
assert id(cprop(concept_found_2, "foo")) == id(cbody(concept_found_2))
def test_i_can_use_context_reference_with_multiple_levels():
@@ -429,23 +432,23 @@ def test_i_can_use_context_reference_with_multiple_levels():
assert context.sheerka.isinstance(res[0].value, BuiltinConcepts.PARSER_RESULT)
assert res[0].value.body == [("foo", 0, 2, "one two")]
concept_found_1 = res[0].value.body[0].concept
assert concept_found_1.body == "one two"
assert concept_found_1.metadata.is_evaluated
assert cbody(concept_found_1) == DoNotResolve("one two")
assert res[1].status
assert context.sheerka.isinstance(res[1].value, BuiltinConcepts.PARSER_RESULT)
assert res[1].value.body == [("bar", 0, 2, "one two")]
concept_found_2 = res[1].value.body[0].concept
assert concept_found_2.body == get_expected(foo, "one two")
assert id(concept_found_2.props["foo"].value) == id(concept_found_2.body)
assert cbody(concept_found_2) == get_expected(foo, "one two")
assert id(cprop(concept_found_2, "foo")) == id(cbody(concept_found_2))
assert res[2].status
assert context.sheerka.isinstance(res[2].value, BuiltinConcepts.PARSER_RESULT)
assert res[2].value.body == [("baz", 0, 2, "one two")]
concept_found_3 = res[2].value.body[0].concept
expected_foo = get_expected(foo, "one two")
assert concept_found_3.body == get_expected(bar, expected_foo).set_prop("foo", expected_foo)
assert id(concept_found_3.props["bar"].value) == id(concept_found_3.body)
assert cbody(concept_found_3) == get_expected(bar, expected_foo)
assert cprop(concept_found_3, "foo") == expected_foo
assert id(cprop(concept_found_3, "bar")) == id(cbody(concept_found_3))
def test_order_is_not_important_when_using_references():
@@ -476,26 +479,21 @@ def test_i_can_parse_when_reference():
assert res.status
assert res.value.body == [("bar", 0, 2, "twenty two")]
concept_found = res.value.body[0].concept
assert concept_found.body == "twenty two"
assert concept_found.metadata.is_evaluated
assert concept_found.get_prop("foo") == get_expected(foo, "twenty")
assert concept_found.get_prop("foo").metadata.is_evaluated
assert cbody(concept_found) == DoNotResolve("twenty two")
assert cprop(concept_found, "foo") == get_expected(foo, "twenty")
res = parser.parse(context, "thirty one")
assert res.status
assert res.value.body == [("bar", 0, 2, "thirty one")]
concept_found = res.value.body[0].concept
assert concept_found.body == "thirty one"
assert concept_found.metadata.is_evaluated
assert concept_found.get_prop("foo") == get_expected(foo, "thirty")
assert concept_found.get_prop("foo").metadata.is_evaluated
assert cbody(concept_found) == DoNotResolve("thirty one")
assert cprop(concept_found, "foo") == get_expected(foo, "thirty")
res = parser.parse(context, "twenty")
assert res.status
assert res.value.body == [("foo", 0, 0, "twenty")]
concept_found = res.value.body[0].concept
assert concept_found.body == "twenty"
assert concept_found.metadata.is_evaluated
assert cbody(concept_found) == DoNotResolve("twenty")
def test_i_can_parse_when_reference_has_a_body():
@@ -508,17 +506,14 @@ def test_i_can_parse_when_reference_has_a_body():
assert res.status
assert res.value.body == [("bar", 0, 2, "twenty two")]
concept_found = res.value.body[0].concept
assert concept_found.body == "twenty two"
assert concept_found.metadata.is_evaluated
assert concept_found.get_prop("foo") == get_expected(foo, "'one'")
assert not concept_found.get_prop("foo").metadata.is_evaluated
assert cbody(concept_found) == DoNotResolve("twenty two")
assert cprop(concept_found, "foo") == foo
res = parser.parse(context, "twenty")
assert res.status
assert res.value.body == [("foo", 0, 0, "twenty")]
concept_found = res.value.body[0].concept
assert concept_found.body == "'one'"
assert not concept_found.metadata.is_evaluated
def test_i_can_parse_multiple_results():
@@ -536,16 +531,14 @@ def test_i_can_parse_multiple_results():
assert context.sheerka.isinstance(res[0].value, BuiltinConcepts.PARSER_RESULT)
assert res[0].value.body == [("bar", 0, 2, "one two")]
concept_found_0 = res[0].value.body[0].concept
assert concept_found_0.body == "one two"
assert concept_found_0.metadata.is_evaluated
assert cbody(concept_found_0) == DoNotResolve("one two")
assert len(concept_found_0.props) == 0
assert res[1].status
assert context.sheerka.isinstance(res[1].value, BuiltinConcepts.PARSER_RESULT)
assert res[1].value.body == [("foo", 0, 2, "one two")]
concept_found_1 = res[1].value.body[0].concept
assert concept_found_1.body == "one two"
assert concept_found_1.metadata.is_evaluated
assert cbody(concept_found_1) == DoNotResolve("one two")
assert len(concept_found_1.props) == 0
@@ -617,10 +610,8 @@ def test_i_can_parse_concept_reference_that_is_not_in_grammar():
assert res.status
assert res.value.body == [("foo", 0, 2, "twenty two")]
concept_found = res.value.body[0].concept
assert concept_found.body == "twenty two"
assert concept_found.metadata.is_evaluated
assert concept_found.get_prop("two") == get_expected(two, "two")
assert concept_found.get_prop("two").metadata.is_evaluated
assert cbody(concept_found) == DoNotResolve("twenty two")
assert cprop(concept_found, "two") == get_expected(two, "two")
res = parser.parse(context, "twenty one")
assert res.status
@@ -638,8 +629,7 @@ def test_i_can_parse_zero_or_more():
assert return_value[0].underlying == u(grammar[foo], 0, 2, [u("one", 0, 0), u("one", 2, 2)])
concept_found = return_value[0].concept
assert concept_found.body == "one one"
assert concept_found.metadata.is_evaluated
assert cbody(concept_found) == DoNotResolve("one one")
def test_i_can_parse_sequence_and_zero_or_more():
@@ -1064,8 +1054,8 @@ def test_i_can_get_the_inner_concept_when_possible():
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
assert return_value == [("foo", 0, 0, "one")]
concept_found = return_value[0].concept
assert concept_found.body == get_expected(one, "one")
assert concept_found.get_prop("one") == concept_found.body
assert cbody(concept_found) == get_expected(one, "one")
assert id(cprop(concept_found, "one")) == id(cbody(concept_found))
def test_i_can_get_the_inner_concept_when_possible_with_rule_name():
@@ -1081,11 +1071,11 @@ def test_i_can_get_the_inner_concept_when_possible_with_rule_name():
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
assert return_value == [("foo", 0, 0, "one")]
concept_found = return_value[0].concept
assert concept_found.body == get_expected(one, "one")
assert id(concept_found.get_prop("one")) == id(concept_found.body)
assert id(concept_found.get_prop("zero")) == id(concept_found.body)
assert id(concept_found.get_prop("opt")) == id(concept_found.body)
assert id(concept_found.get_prop("seq")) == id(concept_found.body)
assert cbody(concept_found) == get_expected(one, "one")
assert id(cprop(concept_found, "one")) == id(cbody(concept_found))
assert id(cprop(concept_found, "zero")) == id(cbody(concept_found))
assert id(cprop(concept_found, "opt")) == id(cbody(concept_found))
assert id(cprop(concept_found, "seq")) == id(cbody(concept_found))
def test_i_get_multiple_props_when_zero_or_more():
@@ -1098,15 +1088,14 @@ def test_i_get_multiple_props_when_zero_or_more():
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
assert return_value == [("foo", 0, 4, "one one one")]
concept_found = return_value[0].concept
assert concept_found.body == "one one one"
assert len(concept_found.props) == 1
assert len(concept_found.get_prop("one")) == 3
assert concept_found.get_prop("one")[0] == get_expected(one)
assert concept_found.get_prop("one")[1] == get_expected(one)
assert concept_found.get_prop("one")[2] == get_expected(one)
assert id(concept_found.get_prop("one")[0]) != id(concept_found.get_prop("one")[1])
assert id(concept_found.get_prop("one")[1]) != id(concept_found.get_prop("one")[2])
assert id(concept_found.get_prop("one")[2]) != id(concept_found.get_prop("one")[0])
assert cbody(concept_found) == DoNotResolve("one one one")
assert len(concept_found.cached_asts["one"]) == 3
assert cprop(concept_found, "one")[0] == get_expected(one)
assert cprop(concept_found, "one")[1] == get_expected(one)
assert cprop(concept_found, "one")[2] == get_expected(one)
assert id(cprop(concept_found, "one")[0]) != id(cprop(concept_found, "one")[1])
assert id(cprop(concept_found, "one")[1]) != id(cprop(concept_found, "one")[2])
assert id(cprop(concept_found, "one")[2]) != id(cprop(concept_found, "one")[0])
def test_i_get_multiple_props_when_zero_or_more_and_different_values():
@@ -1119,13 +1108,12 @@ def test_i_get_multiple_props_when_zero_or_more_and_different_values():
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
assert return_value == [("foo", "one ok un ok uno ok")]
concept_found = return_value[0].concept
assert concept_found.get_prop("one")[0] == get_expected(one, "one")
assert concept_found.get_prop("one")[1] == get_expected(one, "un")
assert concept_found.get_prop("one")[2] == get_expected(one, "uno")
assert concept_found.get_prop("seq")[0] == "one ok"
assert concept_found.get_prop("seq")[1] == "un ok"
assert concept_found.get_prop("seq")[2] == "uno ok"
assert cprop(concept_found, "one")[0] == get_expected(one, "one")
assert cprop(concept_found, "one")[1] == get_expected(one, "un")
assert cprop(concept_found, "one")[2] == get_expected(one, "uno")
assert cprop(concept_found, "seq")[0] == DoNotResolve("one ok")
assert cprop(concept_found, "seq")[1] == DoNotResolve("un ok")
assert cprop(concept_found, "seq")[2] == DoNotResolve("uno ok")
#
+3 -3
View File
@@ -1,7 +1,7 @@
import pytest
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
from core.concept import Concept
from core.concept import Concept, ConceptParts, DoNotResolve
from core.sheerka import Sheerka, ExecutionContext
from evaluators.ConceptNodeEvaluator import ConceptNodeEvaluator
from parsers.ConceptLexerParser import ConceptNode, ConceptLexerParser, Sequence, TerminalNode, \
@@ -73,7 +73,7 @@ def test_concept_is_returned_when_only_one_in_the_list():
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 return_value == Concept("foo").init_key()
assert return_value.cached_asts[ConceptParts.BODY] == DoNotResolve("foo")
assert result.parents == [ret_val]
+1 -1
View File
@@ -84,7 +84,7 @@ def test_i_can_eval_module_with_that_references_concepts():
context = get_context()
context.sheerka.add_in_cache(Concept("foo"))
parsed = PythonParser().parse(context, "def a(b):\n return b\na(foo)")
parsed = PythonParser().parse(context, "def a(b):\n return b\na(c:foo:)")
evaluated = PythonEvaluator().eval(context, parsed)
assert evaluated.status
+63 -1
View File
@@ -4,7 +4,7 @@ from os import path
import shutil
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept, ConceptAlreadyInSet
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, Property
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, Property, ConceptParts, DoNotResolve
from core.sheerka import Sheerka, ExecutionContext
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event
@@ -528,6 +528,41 @@ def test_i_can_evaluate_a_concept_with_prop(expr, expected):
assert evaluated.metadata.is_evaluated
def test_i_can_evaluate_metadata_using_do_not_resolve():
sheerka = get_sheerka()
concept = Concept("foo")
concept.cached_asts[ConceptParts.BODY] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.body == "do not resolve"
assert evaluated.metadata.is_evaluated
def test_i_can_evaluate_property_using_do_not_resolve():
sheerka = get_sheerka()
concept = Concept("foo").set_prop("a")
concept.cached_asts["a"] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.get_prop("a") == "do not resolve"
assert evaluated.metadata.is_evaluated
def test_original_value_is_overridden_when_using_do_no_resolve():
sheerka = get_sheerka()
concept = Concept("foo", body="original value").set_prop("a", "original value")
concept.cached_asts["a"] = DoNotResolve("do not resolve")
concept.cached_asts[ConceptParts.BODY] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.body == "do not resolve"
assert evaluated.get_prop("a") == "do not resolve"
assert evaluated.metadata.is_evaluated
def test_props_are_evaluated_before_body():
sheerka = get_sheerka()
@@ -615,6 +650,8 @@ def test_i_can_evaluate_concept_when_properties_reference_others_concepts():
concept = Concept("foo", body="a").set_prop("a", "a").init_key()
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
# first prop a is evaluated to concept_a
# then body is evaluated to prop a -> concept_a
assert evaluated.key == concept.key
assert evaluated.body == concept_a
@@ -647,6 +684,31 @@ def test_i_can_evaluate_concept_when_properties_reference_others_concepts_with_b
assert evaluated.body == 3
def test_i_can_evaluate_concept_when_properties_is_a_concept():
sheerka = get_sheerka()
concept_a = sheerka.add_in_cache(Concept(name="a", body="'a'").init_key())
concept = Concept("foo").set_prop("a", concept_a)
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.get_prop("a") == Concept(name="a", body="a").init_key()
def test_i_can_evaluate_when_property_asts_is_a_list():
sheerka = get_sheerka()
foo = Concept("foo", body="1")
concept = Concept("to_eval").set_prop("prop")
concept.cached_asts["prop"] = [foo, DoNotResolve("1")]
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
props = evaluated.get_prop("prop")
assert len(props) == 2
assert props[0] == Concept("foo", body=1).init_key()
assert props[1] == "1"
def test_i_can_reference_sheerka():
sheerka = get_sheerka()
+28 -46
View File
@@ -413,14 +413,37 @@ def test_i_can_eval_a_mix_with_bnf_and_python():
assert res[0].body == 22
def test_i_can_eval_a_mix_with_bnf_and_python_when_rule_name():
@pytest.mark.parametrize("desc, definitions", [
("Simple form", [
"def concept one as 1",
"def concept two as 2",
"def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit"
]),
("When twenty is a concept", [
"def concept one as 1",
"def concept two as 2",
"def concept twenty as 20",
"def concept twenties from bnf twenty (one|two)=unit as twenty + unit"
]),
("When digit is a concept", [
"def concept one as 1",
"def concept two as 2",
"def concept twenty as 20",
"def concept digit from bnf one|two",
"def concept twenties from bnf twenty digit as twenty + digit"
]),
])
def test_i_can_mix_concept_with_python_to_define_numbers(desc, definitions):
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")
for definition in definitions:
sheerka.evaluate_user_input(definition)
assert sheerka.evaluate_user_input("eval twenty one")[0].body == 21
res = sheerka.evaluate_user_input("twenty one")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "twenties")
assert res[0].body.body == 21
res = sheerka.evaluate_user_input("twenty one + 1")
assert len(res) == 1
@@ -438,47 +461,6 @@ def test_i_can_eval_a_mix_with_bnf_and_python_when_rule_name():
assert res[0].body == 22
def test_i_can_eval_a_mix_with_bnf_and_python_when_rule_name_2():
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 twenty as 20")
sheerka.evaluate_user_input("def concept twenties from bnf twenty (one | two)=unit as twenty + 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
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("twenty one + one")
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")