Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ePYt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
from ePYt.epytlib import graph
from ePYt.epytlib import preanalysis
from ePYt.epytlib import analysis
from ePYt.epytlib import annotator
4 changes: 1 addition & 3 deletions ePYt/epytlib/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion ePYt/epytlib/annotator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions ePYt/epytlib/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__()
21 changes: 14 additions & 7 deletions ePYt/epytlib/semantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down Expand Up @@ -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)
Expand Down
15 changes: 12 additions & 3 deletions ePYt/epytlib/type_inferrer.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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):
Expand Down
7 changes: 4 additions & 3 deletions sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)