diff --git a/ePYt/__init__.py b/ePYt/__init__.py index c8cbfae..0bf7ff6 100644 --- a/ePYt/__init__.py +++ b/ePYt/__init__.py @@ -2,3 +2,4 @@ from ePYt.epytlib import graph from ePYt.epytlib import preanalysis from ePYt.epytlib import analysis +from ePYt.epytlib import annotator diff --git a/ePYt/epytlib/analysis.py b/ePYt/epytlib/analysis.py index bf25c60..01f6fe9 100644 --- a/ePYt/epytlib/analysis.py +++ b/ePYt/epytlib/analysis.py @@ -2,7 +2,7 @@ from copy import deepcopy from itertools import chain from pathlib import Path -from . import domain, graph, type_inferrer +from . import graph, type_inferrer class FuncDef: @@ -50,8 +50,6 @@ def __init__(self, script_path): class Analyzer: - prim_types = [*map(domain.PrimitiveType, domain.PrimitiveType.prim_types)] - def __init__(self, dir_path): self.dir_path = Path(dir_path) self.type_inferrer = type_inferrer.TypeInferrer(self.dir_path) diff --git a/ePYt/epytlib/annotator.py b/ePYt/epytlib/annotator.py index 617319a..fb28c26 100644 --- a/ePYt/epytlib/annotator.py +++ b/ePYt/epytlib/annotator.py @@ -22,7 +22,9 @@ def annotate_FunctionDef(self, node, class_name=None): if class_name is None: func_defs = self.analyzed_file.func_defs else: - class_def = self.analyzed_file.class_defs[class_name] + class_def = self.analyzed_file.class_defs.get(class_name, None) + if class_def is None: + return node func_defs = class_def.func_defs func_def = func_defs.get(node.name, None) if func_def is None: diff --git a/ePYt/epytlib/domain.py b/ePYt/epytlib/domain.py index 0ed5c77..eea7646 100644 --- a/ePYt/epytlib/domain.py +++ b/ePYt/epytlib/domain.py @@ -111,11 +111,11 @@ def __str__(self): class PrimitiveType(Typed): # TODO: To be filled - prim_types = [int, str, float, bool, list, dict] + prim_types = ["int", "str", "float", "bool", "list", "dict"] def __init__(self, type_): if type_ in self.prim_types: - super().__init__(preanalysis.TypeDef(type_)) + super().__init__(preanalysis.TypeDef(eval(type_))) def __str__(self): return f"Primitive " + super().__str__() diff --git a/ePYt/epytlib/semantic.py b/ePYt/epytlib/semantic.py index ed2145d..158c19c 100644 --- a/ePYt/epytlib/semantic.py +++ b/ePYt/epytlib/semantic.py @@ -47,21 +47,20 @@ class Lifter(ast.NodeVisitor): op_to_method = { ast.UAdd: '__pos__', ast.USub: '__neg__', ast.Invert: '__invert__', - ast.Not: '__not__', ast.Is: '__is__', ast.IsNot: '__isnot__', ast.Add: '__add__', ast.Sub: '__sub__', ast.Mult: '__mul__', - ast.Div: '__div__', ast.Mod: '__mod__', ast.Pow: '__pow__', + ast.Div: 'truediv', ast.Mod: '__mod__', ast.Pow: '__pow__', ast.LShift: '__lshift__', ast.RShift: '__rshift__', ast.BitOr: '__or__', ast.BitXor: '__xor__', ast.BitAnd: '__and__', ast.Eq: '__eq__', ast.NotEq: '__ne__', ast.Lt: '__lt__', ast.LtE: '__le__', ast.Gt: '__gt__', ast.GtE: '__ge__', - ast.In: '__contains__', ast.NotIn: '__contains__'} + ast.In: '__contains__', ast.NotIn: '__contains__', + ast.FloorDiv: 'floordiv'} func_to_method = { 'abs': '__abs__', 'len': '__len__', 'int': '__int__', 'oct': '__oct__', 'float': '__float__', 'complex': '__complex__', 'str': '__str__', 'hex': '__hex__', 'bool': '__nonzero__', 'dir': '__dir__', - 'repr': '__repr__', 'unicode': '__unicode__', 'size': '__sizeof__', - 'hash': '__hash__'} + 'repr': '__repr__', 'hash': '__hash__', 'divmod': 'divmod'} def __init__(self, args): self.lifted_values = [] @@ -102,8 +101,16 @@ def visit_BinOp(self, node): def visit_Compare(self, node): self.generic_visit(node) arg_key = ast.unparse(node.left) - if arg_key in self.args: - self._add_method(arg_key, self.op_to_method[type(node.ops[0])]) + for i in range(len(node.ops)): + # except ast.In and ast.NotIn + if arg_key in self.args: + if not (isinstance(node.ops[i], ast.In) or isinstance(node.ops[i], ast.NotIn)): + self._add_method(arg_key, self.op_to_method[type(node.ops[i])]) + # for ast.In and ast.NotIn + arg_key = ast.unparse(node.comparators[i]) + if arg_key in self.args: + if isinstance(node.ops[i], ast.In) or isinstance(node.ops[i], ast.NotIn): + self._add_method(arg_key, self.op_to_method(node.ops[i])) def visit_Call(self, node): fun_name = ast.unparse(node.func) diff --git a/ePYt/epytlib/type_inferrer.py b/ePYt/epytlib/type_inferrer.py index 4f96c44..2cfece8 100644 --- a/ePYt/epytlib/type_inferrer.py +++ b/ePYt/epytlib/type_inferrer.py @@ -1,10 +1,17 @@ -from . import preanalysis, semantic, memory +from . import preanalysis, semantic, memory, domain from functools import reduce class TypeInferrer: + prim_types = [*map(domain.PrimitiveType, domain.PrimitiveType.prim_types)] + def __init__(self, dir_path): - self.user_types = preanalysis.get_typedefs(dir_path) + self.prim_type_dicts = {} + for prim_type in domain.PrimitiveType.prim_types: + v = domain.PrimitiveType(prim_type) + self.prim_type_dicts[prim_type] = v.typedef + self.type_candidates = preanalysis.get_typedefs(dir_path) + self.type_candidates.update(self.prim_type_dicts) self.table = None @staticmethod @@ -18,11 +25,13 @@ def infer_table(self, table): memory.Memory()) inferred_user_types = {} for arg_key, lifted_value in joined_memory.memory.items(): + if arg_key == 'self': + continue inferred_user_types[arg_key] = list( filter( lambda x: self.match(x.type.attributes, lifted_value.attributes), - self.user_types.values())) + self.type_candidates.values())) return inferred_user_types def infer(self, func_def): diff --git a/sample.py b/sample.py index 55dcfb5..8bfd0da 100644 --- a/sample.py +++ b/sample.py @@ -11,6 +11,7 @@ def method(self): print(self.prop) -analysis_result = ePYt.analysis.Analyzer("./sample_target") -print(analysis_result.table) -_ = input() +a = ePYt.analysis.Analyzer("./sample_target") +print(a.table) +analyzed_files = a.analyze(a.file_infos) +ePYt.annotator.Annotator.annotate_dir(a.dir_path, analyzed_files)