Fixed #131 : Implement ExprToConditions

Fixed #130 : ArithmeticOperatorParser
Fixed #129 : python_wrapper : create_namespace
Fixed #128 : ExpressionParser: Cannot parse func(x) infixed concept 'xxx'
This commit is contained in:
2021-10-13 16:06:57 +02:00
parent a61a1c0d2b
commit 89e1f20975
76 changed files with 5867 additions and 3206 deletions
+123 -3
View File
@@ -2,14 +2,16 @@ import functools
from dataclasses import dataclass
import core.builtin_helpers
from core.ast_helpers import UnreferencedVariablesVisitor
from core.builtin_concepts import ReturnValueConcept
from core.builtin_concepts_ids import BuiltinConcepts
from core.concept import Concept
from core.global_symbols import SyaAssociativity, NotFound, NotInit, ErrorObj
from core.concept import AllConceptParts, Concept
from core.global_symbols import ErrorObj, NotFound, NotInit, SyaAssociativity
from core.rule import Rule
from core.sheerka.ExecutionContext import ExecutionContext
from core.sheerka.services.SheerkaAdmin import SheerkaAdmin
from core.tokenizer import Token, TokenKind
from core.utils import sheerka_hasattr, sheerka_getattr
from core.utils import get_inner_set, sheerka_getattr, sheerka_hasattr
from core.var_ref import VariableRef
TO_DISABLED = ["breakpoint", "callable", "compile", "delattr", "eval", "exec", "exit", "input", "locals", "open",
@@ -277,3 +279,121 @@ def create_namespace(context, who, names, sheerka_names, objects, expression_onl
result[name] = obj
return result
def get_variables_from_concept_asts(context, concept, known_variables, parameters_only=True):
"""
From a given concept that is already compiled,
browse the compiled to see if there is any symbol that is unknown, eg variable
:param context:
:param concept:
:param known_variables:
:param parameters_only: only return concept variables that are also parameters
:return:
"""
if not concept.get_hints().is_instance and not known_variables:
return {}
core.builtin_helpers.ensure_asts(context, concept)
variables = {}
for prop_name, prop_value in concept.get_compiled().items():
if isinstance(prop_value, Concept):
prop_value_vars = get_variables_from_concept_asts(context,
prop_value,
known_variables,
parameters_only)
inner_variables = get_inner_set(prop_value_vars)
if inner_variables:
variables[prop_name] = inner_variables
else:
return_values = [prop_value] if not isinstance(prop_value, list) else prop_value
unreferenced_names_visitor = UnreferencedVariablesVisitor(context)
for ret_val in [r for r in return_values if isinstance(r, ReturnValueConcept)]:
if isinstance(ret_val.body.body, list) and len(ret_val.body.body) != 1:
continue
elif isinstance(ret_val.body.body, list) and len(ret_val.body.body) == 1:
body = ret_val.body.body[0]
else:
body = ret_val.body.body
if hasattr(body, "get_python_node"):
node = body.get_python_node()
possibles_vars = unreferenced_names_visitor.get_names(node.ast_)
variables_found = {v for v in possibles_vars if is_concept_variable(context,
concept,
v,
prop_name,
known_variables)}
if variables_found:
variables.setdefault(prop_name, set()).update(variables_found)
elif hasattr(body, "get_concept"):
sub_concept = body.get_concept()
if sub_concept.name in known_variables:
variables.setdefault(prop_name, set()).add(sub_concept.name)
elif hasattr(body, "get_expr_node"):
expr_node = body.get_expr_node()
for compiled in expr_node.compiled:
variables.setdefault(prop_name, set()).update(compiled.variables)
if prop_name not in variables:
# add an empty entry to handle cases like '__o_00__ + 1'
# No variable is required, but the property must be computed
variables[prop_name] = set()
if parameters_only:
variables = {k: v for k, v in variables.items() if k in concept.get_metadata().parameters}
return variables
def is_variable(context, name):
"""
tells whether or not the name can be a variable
:param context:
:param name:
:return:
"""
if not name.isidentifier():
return False
if context.sheerka.is_a_concept_name(name):
return False
try:
eval(name, sheerka_globals)
except:
return True
return False
def is_concept_variable(context, concept, variable, current_property, known_variables):
"""
Tells whether or not a symbol is unknown for the concept
ie, Can the concept be evaluated without resolving this symbol ?
First the variable must be a valid variable (variable name + not a concept)
Plus it must not be the name of a concept parameter
:param context:
:param concept:
:param known_variables:
:param variable:
:param current_property:
:return:
"""
if variable in known_variables:
# forced variable
return True
if not is_variable(context, variable):
# not a valid identifier or may be a known concept name
return False
if current_property not in AllConceptParts:
# variable referencing other variable
return True
return variable not in concept.variables()