/nuitka/build/include/nuitka/variables_shared.hpp

https://bitbucket.org/pombredanne/nuitka · C++ Header · 321 lines · 240 code · 61 blank · 20 comment · 29 complexity · ae870407cd32ab6624be7df276e92e57 MD5 · raw file

  1. // Copyright 2013, Kay Hayen, mailto:kay.hayen@gmail.com
  2. //
  3. // Part of "Nuitka", an optimizing Python compiler that is compatible and
  4. // integrates with CPython, but also works on its own.
  5. //
  6. // Licensed under the Apache License, Version 2.0 (the "License");
  7. // you may not use this file except in compliance with the License.
  8. // You may obtain a copy of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS,
  14. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. // See the License for the specific language governing permissions and
  16. // limitations under the License.
  17. //
  18. #ifndef __NUITKA_VARIABLES_SHARED_H__
  19. #define __NUITKA_VARIABLES_SHARED_H__
  20. class PyObjectSharedStorage
  21. {
  22. public:
  23. explicit PyObjectSharedStorage( PyObject *var_name, PyObject *object, bool free_value )
  24. {
  25. assert( object == NULL || Py_REFCNT( object ) > 0 );
  26. this->var_name = var_name;
  27. this->object = object;
  28. this->free_value = free_value;
  29. this->ref_count = 1;
  30. }
  31. ~PyObjectSharedStorage()
  32. {
  33. if ( this->free_value )
  34. {
  35. Py_DECREF( this->object );
  36. }
  37. }
  38. void assign0( PyObject *object )
  39. {
  40. assertObject( object );
  41. if ( this->free_value )
  42. {
  43. PyObject *old_object = this->object;
  44. this->object = INCREASE_REFCOUNT( object );
  45. // Free old value if any available and owned.
  46. Py_DECREF( old_object );
  47. }
  48. else
  49. {
  50. this->object = INCREASE_REFCOUNT( object );
  51. this->free_value = true;
  52. }
  53. }
  54. void assign1( PyObject *object )
  55. {
  56. assertObject( object );
  57. if ( this->free_value )
  58. {
  59. PyObject *old_object = this->object;
  60. this->object = object;
  61. // Free old value if any available and owned.
  62. Py_DECREF( old_object );
  63. }
  64. else
  65. {
  66. this->object = object;
  67. this->free_value = true;
  68. }
  69. }
  70. #if PYTHON_VERSION >= 300
  71. void del( bool tolerant )
  72. {
  73. if ( this->free_value )
  74. {
  75. // Free old value if any available and owned.
  76. Py_DECREF( this->object );
  77. }
  78. else if ( !tolerant )
  79. {
  80. PyErr_Format( PyExc_NameError, "free variable '%s' referenced before assignment in enclosing scope", Nuitka_String_AsString( this->var_name ) );
  81. throw PythonException();
  82. }
  83. this->object = NULL;
  84. this->free_value = false;
  85. }
  86. #endif
  87. inline PyObject *getVarName() const
  88. {
  89. return this->var_name;
  90. }
  91. PyObject *var_name;
  92. PyObject *object;
  93. bool free_value;
  94. int ref_count;
  95. private:
  96. PyObjectSharedStorage( const PyObjectSharedStorage & ) { assert( false ); };
  97. };
  98. class PyObjectSharedLocalVariable
  99. {
  100. public:
  101. explicit PyObjectSharedLocalVariable( PyObject *var_name, PyObject *object = NULL, bool free_value = false )
  102. {
  103. this->storage = new PyObjectSharedStorage( var_name, object, free_value );
  104. }
  105. explicit PyObjectSharedLocalVariable() {
  106. this->storage = NULL;
  107. };
  108. ~PyObjectSharedLocalVariable()
  109. {
  110. if ( this->storage )
  111. {
  112. assert( this->storage->ref_count > 0 );
  113. this->storage->ref_count -= 1;
  114. if (this->storage->ref_count == 0)
  115. {
  116. delete this->storage;
  117. }
  118. }
  119. }
  120. void setVariableNameAndValue( PyObject *var_name, PyObject *object )
  121. {
  122. this->setVariableName( var_name );
  123. this->assign1( object );
  124. }
  125. void setVariableName( PyObject *var_name )
  126. {
  127. assert( this->storage == NULL );
  128. this->storage = new PyObjectSharedStorage( var_name, NULL, false );
  129. }
  130. void shareWith( const PyObjectSharedLocalVariable &other )
  131. {
  132. assert( this->storage == NULL );
  133. assert( other.storage != NULL );
  134. this->storage = other.storage;
  135. this->storage->ref_count += 1;
  136. }
  137. void assign0( PyObject *object ) const
  138. {
  139. this->storage->assign0( object );
  140. }
  141. void assign1( PyObject *object ) const
  142. {
  143. this->storage->assign1( object );
  144. }
  145. #if PYTHON_VERSION >= 300
  146. void del( bool tolerant ) const
  147. {
  148. this->storage->del( tolerant );
  149. }
  150. #endif
  151. PyObject *asObject() const
  152. {
  153. assert( this->storage );
  154. if ( this->storage->object == NULL )
  155. {
  156. PyErr_Format(
  157. PyExc_UnboundLocalError,
  158. "free variable '%s' referenced before assignment in enclosing scope",
  159. Nuitka_String_AsString( this->storage->getVarName() )
  160. );
  161. throw PythonException();
  162. }
  163. if ( Py_REFCNT( this->storage->object ) == 0 )
  164. {
  165. PyErr_Format(
  166. PyExc_UnboundLocalError,
  167. "free variable '%s' referenced after its finalization in enclosing scope",
  168. Nuitka_String_AsString( this->storage->getVarName() )
  169. );
  170. throw PythonException();
  171. }
  172. return this->storage->object;
  173. }
  174. PyObject *asObject1() const
  175. {
  176. return INCREASE_REFCOUNT( this->asObject() );
  177. }
  178. bool isInitialized() const
  179. {
  180. return this->storage->object != NULL;
  181. }
  182. PyObject *getVariableName() const
  183. {
  184. return this->storage->var_name;
  185. }
  186. PyObject *updateLocalsDict( PyObject *locals_dict ) const
  187. {
  188. if ( this->isInitialized() )
  189. {
  190. #if PYTHON_VERSION < 300
  191. int status = PyDict_SetItem(
  192. #else
  193. int status = PyObject_SetItem(
  194. #endif
  195. locals_dict,
  196. this->getVariableName(),
  197. this->asObject()
  198. );
  199. if (unlikely( status == -1 ))
  200. {
  201. throw PythonException();
  202. }
  203. }
  204. return locals_dict;
  205. }
  206. PyObject *updateLocalsDir( PyObject *locals_list ) const
  207. {
  208. assert( PyList_Check( locals_list ) );
  209. if ( this->isInitialized() )
  210. {
  211. int status = PyList_Append(
  212. locals_list,
  213. this->getVariableName()
  214. );
  215. if (unlikely( status == -1 ))
  216. {
  217. throw PythonException();
  218. }
  219. }
  220. return locals_list;
  221. }
  222. protected:
  223. PyObjectSharedStorage *storage;
  224. private:
  225. PyObjectSharedLocalVariable( const PyObjectSharedLocalVariable & ) { assert( false ); };
  226. };
  227. class PyObjectClosureVariable : public PyObjectSharedLocalVariable
  228. {
  229. public:
  230. explicit PyObjectClosureVariable()
  231. {
  232. this->storage = NULL;
  233. }
  234. PyObject *asObject() const
  235. {
  236. assert( this->storage );
  237. if ( this->storage->object == NULL )
  238. {
  239. PyErr_Format(
  240. PyExc_NameError,
  241. "free variable '%s' referenced before assignment in enclosing scope",
  242. Nuitka_String_AsString( this->storage->getVarName() )
  243. );
  244. throw PythonException();
  245. }
  246. if ( Py_REFCNT( this->storage->object ) == 0 )
  247. {
  248. PyErr_Format(
  249. PyExc_UnboundLocalError,
  250. "free variable '%s' referenced after its finalization in enclosing scope",
  251. Nuitka_String_AsString( this->storage->getVarName() )
  252. );
  253. throw PythonException();
  254. }
  255. return this->storage->object;
  256. }
  257. protected:
  258. PyObjectClosureVariable( const PyObjectClosureVariable & ) { assert( false ); }
  259. };
  260. #endif