153 lines
4.3 KiB
Python
153 lines
4.3 KiB
Python
from core.builtin_concepts import BuiltinConcepts, ListConcept
|
|
from core.concept import Concept
|
|
import ast
|
|
import core.utils
|
|
|
|
import logging
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class NodeParent:
|
|
"""
|
|
Class that represent the ancestor of a Node
|
|
For example, the 'For' nodes has three fields (target, iter and body)
|
|
So, for a node under For.iter
|
|
node -> For
|
|
field -> iter
|
|
"""
|
|
|
|
def __init__(self, node, field):
|
|
self.node = node
|
|
self.field = field
|
|
|
|
def __repr__(self):
|
|
if self.node is None:
|
|
return None
|
|
|
|
if self.field is None:
|
|
return self.node.get_node_type()
|
|
|
|
return self.node.get_node_type() + "." + self.field
|
|
|
|
def __eq__(self, other):
|
|
# I can compare with type for simplification
|
|
if isinstance(other, tuple):
|
|
return self.node.get_node_type() == other[0] and self.field == other[1]
|
|
|
|
# normal equals implementation
|
|
if not isinstance(other, NodeParent):
|
|
return False
|
|
|
|
return self.node.get_node_type() == other.node.get_node_type() and self.field == other.field
|
|
|
|
def __hash__(self):
|
|
return hash((self.node.get_node_type(), self.field))
|
|
|
|
|
|
class NodeConcept(Concept):
|
|
def __init__(self, key, node_type, parent: NodeParent):
|
|
super().__init__(key, True, False, key)
|
|
self.parent = parent
|
|
self.node_type = node_type
|
|
|
|
def get_node_type(self):
|
|
return self.node_type
|
|
|
|
|
|
class GenericNodeConcept(NodeConcept):
|
|
def __init__(self, node_type, parent):
|
|
super().__init__(BuiltinConcepts.GENERIC_NODE, node_type, parent)
|
|
|
|
def __repr__(self):
|
|
return "Generic:" + self.node_type
|
|
|
|
def get_node_type(self):
|
|
return self.node_type
|
|
|
|
def get_value(self):
|
|
if self.node_type == "Name":
|
|
return self.get_prop("id")
|
|
|
|
if self.node_type == "arg":
|
|
return self.get_prop("arg")
|
|
|
|
return self.body
|
|
|
|
|
|
class IdentifierNodeConcept(NodeConcept):
|
|
def __init__(self, parent, name):
|
|
super().__init__(BuiltinConcepts.IDENTIFIER_NODE, "Name", parent)
|
|
self.body = name
|
|
|
|
|
|
class CallNodeConcept(NodeConcept):
|
|
def __init__(self, parent=None):
|
|
super().__init__(BuiltinConcepts.IDENTIFIER_NODE, "Call", parent)
|
|
|
|
def get_args_names(self, sheerka):
|
|
return sheerka.get_values(self.get_prop("args"))
|
|
|
|
|
|
def python_to_concept(python_node):
|
|
"""
|
|
Transform Python AST node into concept nodes
|
|
for better usage
|
|
:param python_node:
|
|
:return:
|
|
"""
|
|
|
|
def _transform(node, parent):
|
|
node_type = node.__class__.__name__
|
|
concept = GenericNodeConcept(node_type, parent).init_key()
|
|
for field in node._fields:
|
|
if not hasattr(node, field):
|
|
continue
|
|
|
|
value = getattr(node, field)
|
|
concept.def_prop(field)
|
|
if isinstance(value, list):
|
|
lst = ListConcept().init_key()
|
|
for i in value:
|
|
lst.append(_transform(i, NodeParent(concept, field)))
|
|
concept.set_prop(field, lst)
|
|
elif isinstance(value, ast.AST):
|
|
concept.set_prop(field, _transform(value, NodeParent(concept, field)))
|
|
else:
|
|
concept.set_prop(field, value)
|
|
|
|
concept.metadata.is_evaluated = True
|
|
return concept
|
|
|
|
return _transform(python_node, None)
|
|
|
|
|
|
def concept_to_python(concept_node):
|
|
"""
|
|
Transform back concept_node to Python AST node
|
|
:param concept_node:
|
|
:return:
|
|
"""
|
|
|
|
def _transform(node):
|
|
node_type = node.get_node_type()
|
|
ast_object = core.utils.new_object("_ast." + node_type)
|
|
for field in node.props:
|
|
if field not in ast_object._fields:
|
|
continue
|
|
|
|
value = node.get_prop(field)
|
|
if isinstance(value, list) or isinstance(value, Concept) and value.key == str(BuiltinConcepts.LIST):
|
|
lst = []
|
|
for i in value:
|
|
lst.append(_transform(i))
|
|
setattr(ast_object, field, lst)
|
|
elif isinstance(value, NodeConcept):
|
|
setattr(ast_object, field, _transform(value))
|
|
else:
|
|
setattr(ast_object, field, value)
|
|
return ast_object
|
|
|
|
res = _transform(concept_node)
|
|
return res
|