1""" This module contains all classes used to model intrinsics behavior. """ 2 3from pythran.conversion import to_ast 4from pythran.interval import UNKNOWN_RANGE, bool_values 5from pythran.types.signature import extract_combiner 6from pythran.typing import Any, Union, Fun, Generator 7 8import gast as ast 9 10 11class UnboundValueType(object): 12 ''' 13 Represents a new location, bound to no identifier 14 ''' 15 16 17UnboundValue = UnboundValueType() 18 19# FIXME: we should find a better way to implement default behavior 20DefaultArgNum = 20 21 22 23class UpdateEffect(object): 24 pass 25 26 27class ReadEffect(object): 28 pass 29 30 31class ReadOnceEffect(ReadEffect): 32 pass 33 34 35class Intrinsic(object): 36 37 """ 38 Model any Method/Function. 39 40 Its member variables are: 41 42 - argument_effects that describes the effect of the function on its 43 argument (either UpdateEffect, ReadEffect or ReadOnceEffect) 44 - global_effects that describes whether the function has side effects 45 - return_alias that describes the aliasing between the return value 46 and the parameters. The lambda returns an ast expression, generally 47 depending on the node arguments (see dict.setdefault) 48 - args that describes the name and default value of each arg, using the 49 same representation as ast.FunctionDef, i.e. ast.arguments 50 """ 51 52 def __init__(self, **kwargs): 53 self.argument_effects = kwargs.get('argument_effects', 54 (UpdateEffect(),) * DefaultArgNum) 55 self.global_effects = kwargs.get('global_effects', False) 56 self.return_alias = kwargs.get('return_alias', 57 lambda x: {UnboundValue}) 58 self.args = ast.arguments( 59 [ast.Name(n, ast.Param(), None, None) 60 for n in kwargs.get('args', [])], 61 [], None, 62 [ast.Name(n, ast.Param(), None, None) 63 for n in kwargs.get('kwonlyargs', [])], 64 [], None, 65 [to_ast(d) for d in kwargs.get('defaults', [])]) 66 self.return_range = kwargs.get("return_range", 67 lambda call: UNKNOWN_RANGE) 68 self.return_range_content = kwargs.get("return_range_content", 69 lambda c: UNKNOWN_RANGE) 70 71 def isliteral(self): 72 return False 73 74 def isfunction(self): 75 return False 76 77 def isstaticfunction(self): 78 return False 79 80 def ismethod(self): 81 return False 82 83 def isattribute(self): 84 return False 85 86 def isconst(self): 87 return not any( 88 isinstance(x, UpdateEffect) for x in self.argument_effects 89 ) and not self.global_effects 90 91 def isreadonce(self, n): 92 return isinstance(self.argument_effects[n], ReadOnceEffect) 93 94 def combiner(self, s, node): 95 pass 96 97 98class FunctionIntr(Intrinsic): 99 def __init__(self, **kwargs): 100 kwargs.setdefault('combiners', ()) 101 super(FunctionIntr, self).__init__(**kwargs) 102 self.combiners = kwargs['combiners'] 103 if 'signature' in kwargs: 104 self.signature = kwargs['signature'] 105 deduced_combiner = extract_combiner(self.signature) 106 if deduced_combiner is not None: 107 self.combiners += deduced_combiner, 108 if 'return_range' not in kwargs: 109 if isinstance(self.signature, Union): 110 if all(r.__args__[-1] is bool 111 for r in self.signature.__args__): 112 self.return_range = bool_values 113 elif isinstance(self.signature, Generator): 114 if self.signature.__args__[0] is bool: 115 self.return_range = bool_values 116 elif isinstance(self.signature, Fun): 117 if self.signature.__args__[-1] is bool: 118 self.return_range = bool_values 119 else: 120 self.signature = Any 121 if 'immediate_arguments' in kwargs: 122 self.immediate_arguments = kwargs['immediate_arguments'] 123 else: 124 self.immediate_arguments = [] 125 126 def isfunction(self): 127 return True 128 129 def isstaticfunction(self): 130 return True 131 132 def add_combiner(self, _combiner): 133 self.combiners += (_combiner,) 134 135 def combiner(self, s, node): 136 for comb in self.combiners: 137 comb(s, node) 138 139 140class UserFunction(FunctionIntr): 141 def __init__(self, *combiners, **kwargs): 142 kwargs['combiners'] = combiners 143 super(UserFunction, self).__init__(**kwargs) 144 145 146class ConstFunctionIntr(FunctionIntr): 147 def __init__(self, **kwargs): 148 kwargs.setdefault('argument_effects', 149 (ReadEffect(),) * DefaultArgNum) 150 super(ConstFunctionIntr, self).__init__(**kwargs) 151 152 153class ConstExceptionIntr(ConstFunctionIntr): 154 def __init__(self, **kwargs): 155 kwargs.setdefault('argument_effects', 156 (ReadEffect(),) * DefaultArgNum) 157 super(ConstExceptionIntr, self).__init__(**kwargs) 158 159 160class ReadOnceFunctionIntr(ConstFunctionIntr): 161 def __init__(self, **kwargs): 162 super(ReadOnceFunctionIntr, self).__init__( 163 argument_effects=(ReadOnceEffect(),) * DefaultArgNum, **kwargs) 164 165 166class MethodIntr(FunctionIntr): 167 def __init__(self, *combiners, **kwargs): 168 kwargs.setdefault('argument_effects', 169 (UpdateEffect(),) + (ReadEffect(),) * DefaultArgNum) 170 kwargs['combiners'] = combiners 171 super(MethodIntr, self).__init__(**kwargs) 172 173 def ismethod(self): 174 return True 175 176 def isstaticfunction(self): 177 return False 178 179 180class ConstMethodIntr(MethodIntr): 181 def __init__(self, *combiners, **kwargs): 182 kwargs.setdefault('argument_effects', (ReadEffect(),) * DefaultArgNum) 183 super(ConstMethodIntr, self).__init__(*combiners, **kwargs) 184 185 186class ReadOnceMethodIntr(ConstMethodIntr): 187 def __init__(self, **kwargs): 188 super(ReadOnceMethodIntr, self).__init__( 189 argument_effects=(ReadOnceEffect(),) * DefaultArgNum, **kwargs) 190 191 192class AttributeIntr(Intrinsic): 193 194 """ 195 Internal representation for any attributes. 196 197 Examples 198 -------- 199 >> a.real 200 """ 201 202 def __init__(self, **kwargs): 203 """ Forward arguments. """ 204 super(AttributeIntr, self).__init__(**kwargs) 205 if 'signature' in kwargs: 206 self.signature = kwargs['signature'] 207 else: 208 self.signature = Any 209 210 def isattribute(self): 211 """ Mark this intrinsic as an attribute. """ 212 return True 213 214 215class ConstantIntr(Intrinsic): 216 217 """ 218 Internal representation for any constant. 219 220 Examples 221 -------- 222 >> math.pi 223 """ 224 225 def __init__(self, **kwargs): 226 """ Forward arguments and remove arguments effects. """ 227 kwargs["argument_effects"] = () 228 super(ConstantIntr, self).__init__(**kwargs) 229 230 def isliteral(self): 231 """ Mark this intrinsic as a literal. """ 232 return True 233 234 235class Class(Intrinsic): 236 def __init__(self, d, *args, **kwargs): 237 super(Class, self).__init__(*args, **kwargs) 238 self.fields = d 239 240 def __getitem__(self, key): 241 return self.fields[key] 242 243 def __iter__(self): 244 return self.fields.__iter__() 245 246 def __contains__(self, key): 247 """ Forward key content to aliased module. """ 248 return key in self.fields 249 250 251class ClassWithReadOnceConstructor(Class, ReadOnceFunctionIntr): 252 def __init__(self, d, *args, **kwargs): 253 super(ClassWithReadOnceConstructor, self).__init__(d, *args, **kwargs) 254 255 256class ClassWithConstConstructor(Class, ConstFunctionIntr): 257 def __init__(self, d, *args, **kwargs): 258 super(ClassWithConstConstructor, self).__init__(d, *args, **kwargs) 259 260 261class ExceptionClass(Class, ConstExceptionIntr): 262 def __init__(self, d, *args, **kwargs): 263 super(ExceptionClass, self).__init__(d, *args, **kwargs) 264 265 266class UFunc(Class, ConstFunctionIntr): 267 """ Representation of ufunc from numpy. """ 268