def __init__(self,extern_scope=None): self.specials = {} self.modules = [] self.problems = [] self.visited_ast_nodes=[] self.breakpoint = None if extern_scope is None: #f = open("inf/inference/externs.py", "r") curr_location = os.path.dirname(os.path.realpath(__file__)) f = open(curr_location+'/externs.py', 'r') source = f.read() f.close() node = ast.parse(source, filename = 'externs.py', mode = 'exec') logger.info('parsing externs') self.extern_scope = Scope(is_root = True) self.root_scope = Scope(parent = self.extern_scope) self.eval_code(node, self.extern_scope) logger.info('!!!externs parsed') #print('externs parsed') else: self.extern_scope = extern_scope self.root_scope = Scope(parent = self.extern_scope) self.modules = [] self.problems = []
def setUp(self): scope = Scope(is_root=True) scope['a'] = 'a' scope['b'] = 'b' child_scope = Scope(parent=scope) child_scope['c'] = 'c' self.scope = scope self.child_scope = child_scope
def setUp(self): pr_num = Typez(kind = 'obj', node = ast.Num(), klass_name = 'num') pr_str = Typez(kind = 'obj', node = ast.Str(), klass_name = 'str') self.scope = Scope(is_root = True) self.scope.update({'xxx':pr_str}) scope1 = Scope(parent = self.scope) scope1.update({'a': pr_num, 'b': pr_str}) self.type1 = Typez(kind = 'obj', scope = scope1) scope2 = Scope(parent = self.scope) scope2.update({'c': pr_num, 'd': pr_str}) self.type2 = Typez(kind = 'obj', scope = scope2) self.type2 = scope2 scope12 = Scope(parent = self.scope) scope12.update({'a':self.type1, 'b': self.type2}) self.type12 = Typez(kind = 'obj', scope = scope12) self.scope.update({'type1':self.type1, 'type2': self.type2, 'type12': self.type12})
class TestResolve(InferTestCase): #{{{ def setUp(self): num_class = Typez(kind='classdef') num_class.scope['__add__'] = Typez(kind='funcdef') pr_num = Typez(kind='pr_num', __class__=num_class) pr_str = Typez(kind='pr_str') self.scope = Scope(is_root=True) self.scope.update({'xxx': pr_str}) scope1 = Scope(parent=self.scope) scope1.update({'a': pr_num, 'b': pr_str}) self.type1 = Typez(kind='obj', scope=scope1) scope2 = Scope(parent=self.scope) scope2.update({'c': pr_num, 'd': pr_str}) self.type2 = Typez(kind='obj', scope=scope2) self.type2 = scope2 scope12 = Scope(parent=self.scope) scope12.update({'a': self.type1, 'b': self.type2}) self.type12 = Typez(kind='obj', scope=scope12) self.scope.update({ 'type1': self.type1, 'type2': self.type2, 'type12': self.type12 }) def test_resolve_type1_in_scope(self): res = self.scope.resolve('type1', 'straight') self.assertEqual(res, self.type1) def test_resolve_in_type(self): res = self.type1.resolve('a', 'straight') self.assertEqual(res.kind, 'pr_num') self.assertEqual(self.scope.resolve('c'), None) def test_resolve_cascade(self): self.assertRaises(Exception, self.type1.resolve, 'xxx', 'cascade') res1 = self.type1.scope.resolve('xxx', 'cascade') res2 = self.scope.resolve('xxx', 'straight') self.assertEqual(res1, res2) def test_resolve_class(self): num = self.type1.resolve('a', 'straight') self.assertRaises(Exception, num.resolve, '__add__', 'cascade') add = num.resolve('__add__', 'straight') self.assertEqual(add, None) add = num.resolve('__add__', 'class') self.assertIsInstance(add, Typez) self.assertEqual(add.kind, 'funcdef')
def setUp(self): num_class = Typez(kind = 'classdef') num_class.scope['__add__'] = Typez(kind = 'funcdef') pr_num = Typez(kind = 'pr_num', __class__ = num_class ) pr_str = Typez(kind = 'pr_str') self.scope = Scope(is_root = True) self.scope.update({'xxx':pr_str}) scope1 = Scope(parent = self.scope) scope1.update({'a': pr_num, 'b': pr_str}) self.type1 = Typez(kind = 'obj', scope = scope1) scope2 = Scope(parent = self.scope) scope2.update({'c': pr_num, 'd': pr_str}) self.type2 = Typez(kind = 'obj', scope = scope2) self.type2 = scope2 scope12 = Scope(parent = self.scope) scope12.update({'a':self.type1, 'b': self.type2}) self.type12 = Typez(kind = 'obj', scope = scope12) self.scope.update({'type1':self.type1, 'type2': self.type2, 'type12': self.type12})
class TestResolve(InferTestCase): #{{{ def setUp(self): num_class = Typez(kind = 'classdef') num_class.scope['__add__'] = Typez(kind = 'funcdef') pr_num = Typez(kind = 'pr_num', __class__ = num_class ) pr_str = Typez(kind = 'pr_str') self.scope = Scope(is_root = True) self.scope.update({'xxx':pr_str}) scope1 = Scope(parent = self.scope) scope1.update({'a': pr_num, 'b': pr_str}) self.type1 = Typez(kind = 'obj', scope = scope1) scope2 = Scope(parent = self.scope) scope2.update({'c': pr_num, 'd': pr_str}) self.type2 = Typez(kind = 'obj', scope = scope2) self.type2 = scope2 scope12 = Scope(parent = self.scope) scope12.update({'a':self.type1, 'b': self.type2}) self.type12 = Typez(kind = 'obj', scope = scope12) self.scope.update({'type1':self.type1, 'type2': self.type2, 'type12': self.type12}) def test_resolve_type1_in_scope(self): res = self.scope.resolve('type1', 'straight') self.assertEqual(res, self.type1) def test_resolve_in_type(self): res = self.type1.resolve('a', 'straight') self.assertEqual(res.kind,'pr_num') self.assertEqual(self.scope.resolve('c'), None) def test_resolve_cascade(self): self.assertRaises(Exception, self.type1.resolve, 'xxx','cascade') res1 = self.type1.scope.resolve('xxx','cascade') res2 = self.scope.resolve('xxx','straight') self.assertEqual(res1,res2) def test_resolve_class(self): num = self.type1.resolve('a', 'straight') self.assertRaises(Exception, num.resolve, '__add__', 'cascade') add = num.resolve('__add__', 'straight') self.assertEqual(add, None) add = num.resolve('__add__', 'class') self.assertIsInstance(add, Typez) self.assertEqual(add.kind, 'funcdef')
class TestResolve(unittest.TestCase): #{{{ def setUp(self): pr_num = Typez(kind = 'obj', node = ast.Num(), klass_name = 'num') pr_str = Typez(kind = 'obj', node = ast.Str(), klass_name = 'str') self.scope = Scope(is_root = True) self.scope.update({'xxx':pr_str}) scope1 = Scope(parent = self.scope) scope1.update({'a': pr_num, 'b': pr_str}) self.type1 = Typez(kind = 'obj', scope = scope1) scope2 = Scope(parent = self.scope) scope2.update({'c': pr_num, 'd': pr_str}) self.type2 = Typez(kind = 'obj', scope = scope2) self.type2 = scope2 scope12 = Scope(parent = self.scope) scope12.update({'a':self.type1, 'b': self.type2}) self.type12 = Typez(kind = 'obj', scope = scope12) self.scope.update({'type1':self.type1, 'type2': self.type2, 'type12': self.type12}) def test_resolve_type1_in_scope(self): res = self.scope.resolve('type1', 'straight') self.assertEqual(res, self.type1) def test_resolve_in_type(self): res = self.type1.resolve('a', 'straight') self.assertEqual(res.kind,'obj') self.assertIsInstance(res.node, ast.Num) self.assertEqual(self.scope.resolve('c'), None) def test_resolve_cascade(self): self.assertRaises(Exception, self.type1.resolve, 'xxx','cascade') res1 = self.type1.scope.resolve('xxx','cascade') res2 = self.scope.resolve('xxx','straight') self.assertEqual(res1,res2) def test_resolve_class(self): num = self.type1.resolve('a', 'straight') self.assertRaises(Exception, num.resolve, '__add__', 'cascade') add = num.resolve('__add__', 'straight') self.assertEqual(add, None) add = num.resolve('__add__', 'class') self.assertIsInstance(add, Typez) self.assertEqual(add.kind, 'func') self.assertIsInstance(add.node, ast.FunctionDef)
def exec_ClassDef(self, node, scope): ''' Method that executes the definition of class. Bases are stored in Typez object and furthermore 'object' is added to bases. Every node inside node.body is recursively executed. ''' class_scope = Scope(parent = scope) scope[node.name] = Typez(kind='classdef', node = node, scope = class_scope) #docstrings if isinstance(node.body[0],ast.Expr) and isinstance(node.body[0].value,ast.Str): scope[node.name].docstring = node.body[0].value.s for _node in node.body: self.eval_code(_node, class_scope) bases = [self.eval_code(base, scope) for base in node.bases] obj = self.extern_scope['object'] bases.append(obj) class_scope['__bases__'] = bases
def _exec_fun(self, fun_type, args, keywords, scope, create_scope = True, node = None): """ executes function with given args in the given scope. When create_scope is True, it creates new scope for the function executing with parameter scope as its parent. Otherwise, it executes function in the given scope. """ #if we dont know the fun_type, return any_type if fun_type.kind=='any': return any_type from random import randint if fun_type == self.extern_scope['inf_hasattr']: a=args[0] b=args[1] if b.value is not None: res = a.resolve(b.value) if res is None: return Typez(kind='const', value = False, __class__ = self.extern_scope['bool']) else: return Typez(kind='const', value = True, __class__ = self.extern_scope['bool']) self.nondet=True bit = randint(0,1) if bit: return Typez(kind='const', value = True, __class__ = self.extern_scope['bool']) else: return Typez(kind='const', value = False, __class__ = self.extern_scope['bool']) if fun_type == self.extern_scope['inf_random']: self.nondet=True bit = randint(0,1) if bit: return Typez(kind='const', value = 1, __class__ = self.extern_scope['num']) else: return Typez(kind='const', value = 0, __class__ = self.extern_scope['num']) if fun_type == self.extern_scope['inf_equal']: a=args[0] b=args[1] if a.value is not None and b.value is not None: left = a.value right = b.value if isinstance(a.value, bool): if a.value: left = 1 else: left = 0 if isinstance(b.value, bool): if b.value: right = 1 else: right = 0 if left==right: return Typez(kind='const', value = True, __class__ = self.extern_scope['bool']) else: return Typez(kind='const', value = False, __class__ = self.extern_scope['bool']) else: self.nondet=True bit = randint(0,1) if bit: return Typez(kind='const', value = True, __class__ = self.extern_scope['bool']) else: return Typez(kind='const', value = False, __class__ = self.extern_scope['bool']) if fun_type == self.extern_scope['inf_is']: #we truly determine only if the statement is in form - smth is None if is_none(args[1]): if is_none(args[0]): return Typez(kind='const', value = True, __class__ = self.extern_scope['bool']) else: return Typez(kind='const', value = False, __class__ = self.extern_scope['bool']) else: self.nondet=True bit = randint(0,1) if bit: return Typez(kind='const', value = True, __class__ = self.extern_scope['bool']) else: return Typez(kind='const', value = False, __class__ = self.extern_scope['bool']) if fun_type == self.extern_scope['isinstance']: if isinstance(args[0],Typez) and isinstance(args[1],Typez): instance = args[0] clazz = args[1] res = instance.resolve_class(clazz) if not res is None: return Typez(kind='const', value = True, __class__ = self.extern_scope['bool']) else: return Typez(kind='const', value = False, __class__ = self.extern_scope['bool']) else: self.warn(node, symbol = 'isinstance error', message = 'isinstance bad arguments') if fun_type == self.extern_scope['inf_setattr']: attr = args[1] if isinstance(attr, Typez) and isinstance(attr.value, str): attr = attr.value if isinstance(attr, str): args[0].scope[attr] = args[2] if create_scope: fun_scope = Scope(parent = scope) else: fun_scope = scope def_args = fun_type.node.args.args def_default_args = fun_type.node.args.defaults def_args_names = [arg.arg for arg in def_args] count_given_args = len(args)+len(keywords) if count_given_args > len(def_args) or count_given_args+len(def_default_args)< len(def_args): symbol = not_none(safe_resolve(node, 'func.attr'), safe_resolve(node, 'func.id')) self.warn(node, symbol = symbol, message = 'bad number of arguments (%d given, %d expected)'%(len(args), len(def_args))) for keyword in keywords: if not keyword in def_args_names: symbol = not_none(safe_resolve(node, 'func.attr'), safe_resolve(node, 'func.id')) self.warn(node, symbol = symbol, message = 'unexpected keyword argument %s'%(keyword)) for i,arg in enumerate(def_args): if i<len(args): if arg.arg in keywords: symbol = not_none(safe_resolve(node, 'func.attr'), safe_resolve(node, 'func.id')) self.warn(node, symbol = symbol, message = 'multiple arguments for keyword argument %s'%(arg.arg)) fun_scope[arg.arg] = args[i] else: found=False for j,key in enumerate(keywords): if key==arg.arg: found=True fun_scope[arg.arg]=keywords[key] if not found: lengthFromEnd = len(def_args)-i if len(def_default_args) >= lengthFromEnd: fun_scope[arg.arg]=self.eval_code(def_default_args[-lengthFromEnd],scope) else: fun_scope[arg.arg] = any_type try: for _node in fun_type.node.body: self.eval_code(_node, fun_scope) except ReturnException as e: res=e.res if isinstance(res, Typez) and "__class__" in res.scope and (res.scope["__class__"] == self.extern_scope['ProblemException']): error = res.scope["error"] message = res.scope["message"] #symbol = res.scope["symbol"] symbol = None for key,val in scope.items(): if val==error: symbol = key #when error is caused by constant, symbol is its type if symbol is None: if hasattr(error.scope['__class__'].node, 'name'): symbol = error.scope['__class__'].node.name else: #default symbol symbol = 'Type error' if is_none(message): #default message because it is very often used message_value = "unsupported operand type" else: message_value = message.value self.warn(node, message_value, symbol) return any_type if isinstance(res, Typez) and "__class__" in res.scope and (res.scope["__class__"] == self.extern_scope['TypeContainer']): gen_type=res.scope["T"] result = Typez(kind='const',__class__ = gen_type) return result return res if fun_type.kind == 'classdef': return args[0]
def setUp(self): num_class = Typez(kind='classdef') num_class.scope['__add__'] = Typez(kind='funcdef') pr_num = Typez(kind='pr_num', __class__=num_class) pr_str = Typez(kind='pr_str') self.scope = Scope(is_root=True) self.scope.update({'xxx': pr_str}) scope1 = Scope(parent=self.scope) scope1.update({'a': pr_num, 'b': pr_str}) self.type1 = Typez(kind='obj', scope=scope1) scope2 = Scope(parent=self.scope) scope2.update({'c': pr_num, 'd': pr_str}) self.type2 = Typez(kind='obj', scope=scope2) self.type2 = scope2 scope12 = Scope(parent=self.scope) scope12.update({'a': self.type1, 'b': self.type2}) self.type12 = Typez(kind='obj', scope=scope12) self.scope.update({ 'type1': self.type1, 'type2': self.type2, 'type12': self.type12 })