Code.py 92 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523
  1. # cython: language_level = 2
  2. #
  3. # Code output module
  4. #
  5. from __future__ import absolute_import
  6. import cython
  7. cython.declare(os=object, re=object, operator=object, textwrap=object,
  8. Template=object, Naming=object, Options=object, StringEncoding=object,
  9. Utils=object, SourceDescriptor=object, StringIOTree=object,
  10. DebugFlags=object, basestring=object, defaultdict=object,
  11. closing=object, partial=object)
  12. import os
  13. import re
  14. import shutil
  15. import sys
  16. import operator
  17. import textwrap
  18. from string import Template
  19. from functools import partial
  20. from contextlib import closing
  21. from collections import defaultdict
  22. try:
  23. import hashlib
  24. except ImportError:
  25. import md5 as hashlib
  26. from . import Naming
  27. from . import Options
  28. from . import DebugFlags
  29. from . import StringEncoding
  30. from . import Version
  31. from .. import Utils
  32. from .Scanning import SourceDescriptor
  33. from ..StringIOTree import StringIOTree
  34. try:
  35. from __builtin__ import basestring
  36. except ImportError:
  37. from builtins import str as basestring
  38. KEYWORDS_MUST_BE_BYTES = sys.version_info < (2, 7)
  39. non_portable_builtins_map = {
  40. # builtins that have different names in different Python versions
  41. 'bytes' : ('PY_MAJOR_VERSION < 3', 'str'),
  42. 'unicode' : ('PY_MAJOR_VERSION >= 3', 'str'),
  43. 'basestring' : ('PY_MAJOR_VERSION >= 3', 'str'),
  44. 'xrange' : ('PY_MAJOR_VERSION >= 3', 'range'),
  45. 'raw_input' : ('PY_MAJOR_VERSION >= 3', 'input'),
  46. }
  47. basicsize_builtins_map = {
  48. # builtins whose type has a different tp_basicsize than sizeof(...)
  49. 'PyTypeObject': 'PyHeapTypeObject',
  50. }
  51. uncachable_builtins = [
  52. # Global/builtin names that cannot be cached because they may or may not
  53. # be available at import time, for various reasons:
  54. ## - Py3.7+
  55. 'breakpoint', # might deserve an implementation in Cython
  56. ## - Py3.4+
  57. '__loader__',
  58. '__spec__',
  59. ## - Py3+
  60. 'BlockingIOError',
  61. 'BrokenPipeError',
  62. 'ChildProcessError',
  63. 'ConnectionAbortedError',
  64. 'ConnectionError',
  65. 'ConnectionRefusedError',
  66. 'ConnectionResetError',
  67. 'FileExistsError',
  68. 'FileNotFoundError',
  69. 'InterruptedError',
  70. 'IsADirectoryError',
  71. 'ModuleNotFoundError',
  72. 'NotADirectoryError',
  73. 'PermissionError',
  74. 'ProcessLookupError',
  75. 'RecursionError',
  76. 'ResourceWarning',
  77. #'StopAsyncIteration', # backported
  78. 'TimeoutError',
  79. '__build_class__',
  80. 'ascii', # might deserve an implementation in Cython
  81. #'exec', # implemented in Cython
  82. ## - Py2.7+
  83. 'memoryview',
  84. ## - platform specific
  85. 'WindowsError',
  86. ## - others
  87. '_', # e.g. used by gettext
  88. ]
  89. special_py_methods = set([
  90. '__cinit__', '__dealloc__', '__richcmp__', '__next__',
  91. '__await__', '__aiter__', '__anext__',
  92. '__getreadbuffer__', '__getwritebuffer__', '__getsegcount__',
  93. '__getcharbuffer__', '__getbuffer__', '__releasebuffer__'
  94. ])
  95. modifier_output_mapper = {
  96. 'inline': 'CYTHON_INLINE'
  97. }.get
  98. is_self_assignment = re.compile(r" *(\w+) = (\1);\s*$").match
  99. class IncludeCode(object):
  100. """
  101. An include file and/or verbatim C code to be included in the
  102. generated sources.
  103. """
  104. # attributes:
  105. #
  106. # pieces {order: unicode}: pieces of C code to be generated.
  107. # For the included file, the key "order" is zero.
  108. # For verbatim include code, the "order" is the "order"
  109. # attribute of the original IncludeCode where this piece
  110. # of C code was first added. This is needed to prevent
  111. # duplication if the same include code is found through
  112. # multiple cimports.
  113. # location int: where to put this include in the C sources, one
  114. # of the constants INITIAL, EARLY, LATE
  115. # order int: sorting order (automatically set by increasing counter)
  116. # Constants for location. If the same include occurs with different
  117. # locations, the earliest one takes precedense.
  118. INITIAL = 0
  119. EARLY = 1
  120. LATE = 2
  121. counter = 1 # Counter for "order"
  122. def __init__(self, include=None, verbatim=None, late=True, initial=False):
  123. self.order = self.counter
  124. type(self).counter += 1
  125. self.pieces = {}
  126. if include:
  127. if include[0] == '<' and include[-1] == '>':
  128. self.pieces[0] = u'#include {0}'.format(include)
  129. late = False # system include is never late
  130. else:
  131. self.pieces[0] = u'#include "{0}"'.format(include)
  132. if verbatim:
  133. self.pieces[self.order] = verbatim
  134. if initial:
  135. self.location = self.INITIAL
  136. elif late:
  137. self.location = self.LATE
  138. else:
  139. self.location = self.EARLY
  140. def dict_update(self, d, key):
  141. """
  142. Insert `self` in dict `d` with key `key`. If that key already
  143. exists, update the attributes of the existing value with `self`.
  144. """
  145. if key in d:
  146. other = d[key]
  147. other.location = min(self.location, other.location)
  148. other.pieces.update(self.pieces)
  149. else:
  150. d[key] = self
  151. def sortkey(self):
  152. return self.order
  153. def mainpiece(self):
  154. """
  155. Return the main piece of C code, corresponding to the include
  156. file. If there was no include file, return None.
  157. """
  158. return self.pieces.get(0)
  159. def write(self, code):
  160. # Write values of self.pieces dict, sorted by the keys
  161. for k in sorted(self.pieces):
  162. code.putln(self.pieces[k])
  163. def get_utility_dir():
  164. # make this a function and not global variables:
  165. # http://trac.cython.org/cython_trac/ticket/475
  166. Cython_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  167. return os.path.join(Cython_dir, "Utility")
  168. class UtilityCodeBase(object):
  169. """
  170. Support for loading utility code from a file.
  171. Code sections in the file can be specified as follows:
  172. ##### MyUtility.proto #####
  173. [proto declarations]
  174. ##### MyUtility.init #####
  175. [code run at module initialization]
  176. ##### MyUtility #####
  177. #@requires: MyOtherUtility
  178. #@substitute: naming
  179. [definitions]
  180. for prototypes and implementation respectively. For non-python or
  181. -cython files backslashes should be used instead. 5 to 30 comment
  182. characters may be used on either side.
  183. If the @cname decorator is not used and this is a CythonUtilityCode,
  184. one should pass in the 'name' keyword argument to be used for name
  185. mangling of such entries.
  186. """
  187. is_cython_utility = False
  188. _utility_cache = {}
  189. @classmethod
  190. def _add_utility(cls, utility, type, lines, begin_lineno, tags=None):
  191. if utility is None:
  192. return
  193. code = '\n'.join(lines)
  194. if tags and 'substitute' in tags and tags['substitute'] == set(['naming']):
  195. del tags['substitute']
  196. try:
  197. code = Template(code).substitute(vars(Naming))
  198. except (KeyError, ValueError) as e:
  199. raise RuntimeError("Error parsing templated utility code of type '%s' at line %d: %s" % (
  200. type, begin_lineno, e))
  201. # remember correct line numbers at least until after templating
  202. code = '\n' * begin_lineno + code
  203. if type == 'proto':
  204. utility[0] = code
  205. elif type == 'impl':
  206. utility[1] = code
  207. else:
  208. all_tags = utility[2]
  209. if KEYWORDS_MUST_BE_BYTES:
  210. type = type.encode('ASCII')
  211. all_tags[type] = code
  212. if tags:
  213. all_tags = utility[2]
  214. for name, values in tags.items():
  215. if KEYWORDS_MUST_BE_BYTES:
  216. name = name.encode('ASCII')
  217. all_tags.setdefault(name, set()).update(values)
  218. @classmethod
  219. def load_utilities_from_file(cls, path):
  220. utilities = cls._utility_cache.get(path)
  221. if utilities:
  222. return utilities
  223. filename = os.path.join(get_utility_dir(), path)
  224. _, ext = os.path.splitext(path)
  225. if ext in ('.pyx', '.py', '.pxd', '.pxi'):
  226. comment = '#'
  227. strip_comments = partial(re.compile(r'^\s*#.*').sub, '')
  228. rstrip = StringEncoding._unicode.rstrip
  229. else:
  230. comment = '/'
  231. strip_comments = partial(re.compile(r'^\s*//.*|/\*[^*]*\*/').sub, '')
  232. rstrip = partial(re.compile(r'\s+(\\?)$').sub, r'\1')
  233. match_special = re.compile(
  234. (r'^%(C)s{5,30}\s*(?P<name>(?:\w|\.)+)\s*%(C)s{5,30}|'
  235. r'^%(C)s+@(?P<tag>\w+)\s*:\s*(?P<value>(?:\w|[.:])+)') %
  236. {'C': comment}).match
  237. match_type = re.compile('(.+)[.](proto(?:[.]\S+)?|impl|init|cleanup)$').match
  238. with closing(Utils.open_source_file(filename, encoding='UTF-8')) as f:
  239. all_lines = f.readlines()
  240. utilities = defaultdict(lambda: [None, None, {}])
  241. lines = []
  242. tags = defaultdict(set)
  243. utility = type = None
  244. begin_lineno = 0
  245. for lineno, line in enumerate(all_lines):
  246. m = match_special(line)
  247. if m:
  248. if m.group('name'):
  249. cls._add_utility(utility, type, lines, begin_lineno, tags)
  250. begin_lineno = lineno + 1
  251. del lines[:]
  252. tags.clear()
  253. name = m.group('name')
  254. mtype = match_type(name)
  255. if mtype:
  256. name, type = mtype.groups()
  257. else:
  258. type = 'impl'
  259. utility = utilities[name]
  260. else:
  261. tags[m.group('tag')].add(m.group('value'))
  262. lines.append('') # keep line number correct
  263. else:
  264. lines.append(rstrip(strip_comments(line)))
  265. if utility is None:
  266. raise ValueError("Empty utility code file")
  267. # Don't forget to add the last utility code
  268. cls._add_utility(utility, type, lines, begin_lineno, tags)
  269. utilities = dict(utilities) # un-defaultdict-ify
  270. cls._utility_cache[path] = utilities
  271. return utilities
  272. @classmethod
  273. def load(cls, util_code_name, from_file=None, **kwargs):
  274. """
  275. Load utility code from a file specified by from_file (relative to
  276. Cython/Utility) and name util_code_name. If from_file is not given,
  277. load it from the file util_code_name.*. There should be only one
  278. file matched by this pattern.
  279. """
  280. if '::' in util_code_name:
  281. from_file, util_code_name = util_code_name.rsplit('::', 1)
  282. if not from_file:
  283. utility_dir = get_utility_dir()
  284. prefix = util_code_name + '.'
  285. try:
  286. listing = os.listdir(utility_dir)
  287. except OSError:
  288. # XXX the code below assumes as 'zipimport.zipimporter' instance
  289. # XXX should be easy to generalize, but too lazy right now to write it
  290. import zipfile
  291. global __loader__
  292. loader = __loader__
  293. archive = loader.archive
  294. with closing(zipfile.ZipFile(archive)) as fileobj:
  295. listing = [os.path.basename(name)
  296. for name in fileobj.namelist()
  297. if os.path.join(archive, name).startswith(utility_dir)]
  298. files = [filename for filename in listing
  299. if filename.startswith(prefix)]
  300. if not files:
  301. raise ValueError("No match found for utility code " + util_code_name)
  302. if len(files) > 1:
  303. raise ValueError("More than one filename match found for utility code " + util_code_name)
  304. from_file = files[0]
  305. utilities = cls.load_utilities_from_file(from_file)
  306. proto, impl, tags = utilities[util_code_name]
  307. if tags:
  308. orig_kwargs = kwargs.copy()
  309. for name, values in tags.items():
  310. if name in kwargs:
  311. continue
  312. # only pass lists when we have to: most argument expect one value or None
  313. if name == 'requires':
  314. if orig_kwargs:
  315. values = [cls.load(dep, from_file, **orig_kwargs)
  316. for dep in sorted(values)]
  317. else:
  318. # dependencies are rarely unique, so use load_cached() when we can
  319. values = [cls.load_cached(dep, from_file)
  320. for dep in sorted(values)]
  321. elif not values:
  322. values = None
  323. elif len(values) == 1:
  324. values = list(values)[0]
  325. kwargs[name] = values
  326. if proto is not None:
  327. kwargs['proto'] = proto
  328. if impl is not None:
  329. kwargs['impl'] = impl
  330. if 'name' not in kwargs:
  331. kwargs['name'] = util_code_name
  332. if 'file' not in kwargs and from_file:
  333. kwargs['file'] = from_file
  334. return cls(**kwargs)
  335. @classmethod
  336. def load_cached(cls, utility_code_name, from_file=None, __cache={}):
  337. """
  338. Calls .load(), but using a per-type cache based on utility name and file name.
  339. """
  340. key = (cls, from_file, utility_code_name)
  341. try:
  342. return __cache[key]
  343. except KeyError:
  344. pass
  345. code = __cache[key] = cls.load(utility_code_name, from_file)
  346. return code
  347. @classmethod
  348. def load_as_string(cls, util_code_name, from_file=None, **kwargs):
  349. """
  350. Load a utility code as a string. Returns (proto, implementation)
  351. """
  352. util = cls.load(util_code_name, from_file, **kwargs)
  353. proto, impl = util.proto, util.impl
  354. return util.format_code(proto), util.format_code(impl)
  355. def format_code(self, code_string, replace_empty_lines=re.compile(r'\n\n+').sub):
  356. """
  357. Format a code section for output.
  358. """
  359. if code_string:
  360. code_string = replace_empty_lines('\n', code_string.strip()) + '\n\n'
  361. return code_string
  362. def __str__(self):
  363. return "<%s(%s)>" % (type(self).__name__, self.name)
  364. def get_tree(self, **kwargs):
  365. pass
  366. class UtilityCode(UtilityCodeBase):
  367. """
  368. Stores utility code to add during code generation.
  369. See GlobalState.put_utility_code.
  370. hashes/equals by instance
  371. proto C prototypes
  372. impl implementation code
  373. init code to call on module initialization
  374. requires utility code dependencies
  375. proto_block the place in the resulting file where the prototype should
  376. end up
  377. name name of the utility code (or None)
  378. file filename of the utility code file this utility was loaded
  379. from (or None)
  380. """
  381. def __init__(self, proto=None, impl=None, init=None, cleanup=None, requires=None,
  382. proto_block='utility_code_proto', name=None, file=None):
  383. # proto_block: Which code block to dump prototype in. See GlobalState.
  384. self.proto = proto
  385. self.impl = impl
  386. self.init = init
  387. self.cleanup = cleanup
  388. self.requires = requires
  389. self._cache = {}
  390. self.specialize_list = []
  391. self.proto_block = proto_block
  392. self.name = name
  393. self.file = file
  394. def __hash__(self):
  395. return hash((self.proto, self.impl))
  396. def __eq__(self, other):
  397. if self is other:
  398. return True
  399. self_type, other_type = type(self), type(other)
  400. if self_type is not other_type and not (isinstance(other, self_type) or isinstance(self, other_type)):
  401. return False
  402. self_proto = getattr(self, 'proto', None)
  403. other_proto = getattr(other, 'proto', None)
  404. return (self_proto, self.impl) == (other_proto, other.impl)
  405. def none_or_sub(self, s, context):
  406. """
  407. Format a string in this utility code with context. If None, do nothing.
  408. """
  409. if s is None:
  410. return None
  411. return s % context
  412. def specialize(self, pyrex_type=None, **data):
  413. # Dicts aren't hashable...
  414. if pyrex_type is not None:
  415. data['type'] = pyrex_type.empty_declaration_code()
  416. data['type_name'] = pyrex_type.specialization_name()
  417. key = tuple(sorted(data.items()))
  418. try:
  419. return self._cache[key]
  420. except KeyError:
  421. if self.requires is None:
  422. requires = None
  423. else:
  424. requires = [r.specialize(data) for r in self.requires]
  425. s = self._cache[key] = UtilityCode(
  426. self.none_or_sub(self.proto, data),
  427. self.none_or_sub(self.impl, data),
  428. self.none_or_sub(self.init, data),
  429. self.none_or_sub(self.cleanup, data),
  430. requires,
  431. self.proto_block)
  432. self.specialize_list.append(s)
  433. return s
  434. def inject_string_constants(self, impl, output):
  435. """Replace 'PYIDENT("xyz")' by a constant Python identifier cname.
  436. """
  437. if 'PYIDENT(' not in impl and 'PYUNICODE(' not in impl:
  438. return False, impl
  439. replacements = {}
  440. def externalise(matchobj):
  441. key = matchobj.groups()
  442. try:
  443. cname = replacements[key]
  444. except KeyError:
  445. str_type, name = key
  446. cname = replacements[key] = output.get_py_string_const(
  447. StringEncoding.EncodedString(name), identifier=str_type == 'IDENT').cname
  448. return cname
  449. impl = re.sub(r'PY(IDENT|UNICODE)\("([^"]+)"\)', externalise, impl)
  450. assert 'PYIDENT(' not in impl and 'PYUNICODE(' not in impl
  451. return bool(replacements), impl
  452. def inject_unbound_methods(self, impl, output):
  453. """Replace 'UNBOUND_METHOD(type, "name")' by a constant Python identifier cname.
  454. """
  455. if 'CALL_UNBOUND_METHOD(' not in impl:
  456. return False, impl
  457. utility_code = set()
  458. def externalise(matchobj):
  459. type_cname, method_name, obj_cname, args = matchobj.groups()
  460. args = [arg.strip() for arg in args[1:].split(',')] if args else []
  461. assert len(args) < 3, "CALL_UNBOUND_METHOD() does not support %d call arguments" % len(args)
  462. return output.cached_unbound_method_call_code(obj_cname, type_cname, method_name, args)
  463. impl = re.sub(
  464. r'CALL_UNBOUND_METHOD\('
  465. r'([a-zA-Z_]+),' # type cname
  466. r'\s*"([^"]+)",' # method name
  467. r'\s*([^),]+)' # object cname
  468. r'((?:,\s*[^),]+)*)' # args*
  469. r'\)', externalise, impl)
  470. assert 'CALL_UNBOUND_METHOD(' not in impl
  471. for helper in sorted(utility_code):
  472. output.use_utility_code(UtilityCode.load_cached(helper, "ObjectHandling.c"))
  473. return bool(utility_code), impl
  474. def wrap_c_strings(self, impl):
  475. """Replace CSTRING('''xyz''') by a C compatible string
  476. """
  477. if 'CSTRING(' not in impl:
  478. return impl
  479. def split_string(matchobj):
  480. content = matchobj.group(1).replace('"', '\042')
  481. return ''.join(
  482. '"%s\\n"\n' % line if not line.endswith('\\') or line.endswith('\\\\') else '"%s"\n' % line[:-1]
  483. for line in content.splitlines())
  484. impl = re.sub(r'CSTRING\(\s*"""([^"]*(?:"[^"]+)*)"""\s*\)', split_string, impl)
  485. assert 'CSTRING(' not in impl
  486. return impl
  487. def put_code(self, output):
  488. if self.requires:
  489. for dependency in self.requires:
  490. output.use_utility_code(dependency)
  491. if self.proto:
  492. writer = output[self.proto_block]
  493. writer.putln("/* %s.proto */" % self.name)
  494. writer.put_or_include(
  495. self.format_code(self.proto), '%s_proto' % self.name)
  496. if self.impl:
  497. impl = self.format_code(self.wrap_c_strings(self.impl))
  498. is_specialised1, impl = self.inject_string_constants(impl, output)
  499. is_specialised2, impl = self.inject_unbound_methods(impl, output)
  500. writer = output['utility_code_def']
  501. writer.putln("/* %s */" % self.name)
  502. if not (is_specialised1 or is_specialised2):
  503. # no module specific adaptations => can be reused
  504. writer.put_or_include(impl, '%s_impl' % self.name)
  505. else:
  506. writer.put(impl)
  507. if self.init:
  508. writer = output['init_globals']
  509. writer.putln("/* %s.init */" % self.name)
  510. if isinstance(self.init, basestring):
  511. writer.put(self.format_code(self.init))
  512. else:
  513. self.init(writer, output.module_pos)
  514. writer.putln(writer.error_goto_if_PyErr(output.module_pos))
  515. writer.putln()
  516. if self.cleanup and Options.generate_cleanup_code:
  517. writer = output['cleanup_globals']
  518. writer.putln("/* %s.cleanup */" % self.name)
  519. if isinstance(self.cleanup, basestring):
  520. writer.put_or_include(
  521. self.format_code(self.cleanup),
  522. '%s_cleanup' % self.name)
  523. else:
  524. self.cleanup(writer, output.module_pos)
  525. def sub_tempita(s, context, file=None, name=None):
  526. "Run tempita on string s with given context."
  527. if not s:
  528. return None
  529. if file:
  530. context['__name'] = "%s:%s" % (file, name)
  531. elif name:
  532. context['__name'] = name
  533. from ..Tempita import sub
  534. return sub(s, **context)
  535. class TempitaUtilityCode(UtilityCode):
  536. def __init__(self, name=None, proto=None, impl=None, init=None, file=None, context=None, **kwargs):
  537. if context is None:
  538. context = {}
  539. proto = sub_tempita(proto, context, file, name)
  540. impl = sub_tempita(impl, context, file, name)
  541. init = sub_tempita(init, context, file, name)
  542. super(TempitaUtilityCode, self).__init__(
  543. proto, impl, init=init, name=name, file=file, **kwargs)
  544. @classmethod
  545. def load_cached(cls, utility_code_name, from_file=None, context=None, __cache={}):
  546. context_key = tuple(sorted(context.items())) if context else None
  547. assert hash(context_key) is not None # raise TypeError if not hashable
  548. key = (cls, from_file, utility_code_name, context_key)
  549. try:
  550. return __cache[key]
  551. except KeyError:
  552. pass
  553. code = __cache[key] = cls.load(utility_code_name, from_file, context=context)
  554. return code
  555. def none_or_sub(self, s, context):
  556. """
  557. Format a string in this utility code with context. If None, do nothing.
  558. """
  559. if s is None:
  560. return None
  561. return sub_tempita(s, context, self.file, self.name)
  562. class LazyUtilityCode(UtilityCodeBase):
  563. """
  564. Utility code that calls a callback with the root code writer when
  565. available. Useful when you only have 'env' but not 'code'.
  566. """
  567. __name__ = '<lazy>'
  568. requires = None
  569. def __init__(self, callback):
  570. self.callback = callback
  571. def put_code(self, globalstate):
  572. utility = self.callback(globalstate.rootwriter)
  573. globalstate.use_utility_code(utility)
  574. class FunctionState(object):
  575. # return_label string function return point label
  576. # error_label string error catch point label
  577. # continue_label string loop continue point label
  578. # break_label string loop break point label
  579. # return_from_error_cleanup_label string
  580. # label_counter integer counter for naming labels
  581. # in_try_finally boolean inside try of try...finally
  582. # exc_vars (string * 3) exception variables for reraise, or None
  583. # can_trace boolean line tracing is supported in the current context
  584. # scope Scope the scope object of the current function
  585. # Not used for now, perhaps later
  586. def __init__(self, owner, names_taken=set(), scope=None):
  587. self.names_taken = names_taken
  588. self.owner = owner
  589. self.scope = scope
  590. self.error_label = None
  591. self.label_counter = 0
  592. self.labels_used = set()
  593. self.return_label = self.new_label()
  594. self.new_error_label()
  595. self.continue_label = None
  596. self.break_label = None
  597. self.yield_labels = []
  598. self.in_try_finally = 0
  599. self.exc_vars = None
  600. self.current_except = None
  601. self.can_trace = False
  602. self.gil_owned = True
  603. self.temps_allocated = [] # of (name, type, manage_ref, static)
  604. self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
  605. self.temps_used_type = {} # name -> (type, manage_ref)
  606. self.temp_counter = 0
  607. self.closure_temps = None
  608. # This is used to collect temporaries, useful to find out which temps
  609. # need to be privatized in parallel sections
  610. self.collect_temps_stack = []
  611. # This is used for the error indicator, which needs to be local to the
  612. # function. It used to be global, which relies on the GIL being held.
  613. # However, exceptions may need to be propagated through 'nogil'
  614. # sections, in which case we introduce a race condition.
  615. self.should_declare_error_indicator = False
  616. self.uses_error_indicator = False
  617. # labels
  618. def new_label(self, name=None):
  619. n = self.label_counter
  620. self.label_counter = n + 1
  621. label = "%s%d" % (Naming.label_prefix, n)
  622. if name is not None:
  623. label += '_' + name
  624. return label
  625. def new_yield_label(self, expr_type='yield'):
  626. label = self.new_label('resume_from_%s' % expr_type)
  627. num_and_label = (len(self.yield_labels) + 1, label)
  628. self.yield_labels.append(num_and_label)
  629. return num_and_label
  630. def new_error_label(self):
  631. old_err_lbl = self.error_label
  632. self.error_label = self.new_label('error')
  633. return old_err_lbl
  634. def get_loop_labels(self):
  635. return (
  636. self.continue_label,
  637. self.break_label)
  638. def set_loop_labels(self, labels):
  639. (self.continue_label,
  640. self.break_label) = labels
  641. def new_loop_labels(self):
  642. old_labels = self.get_loop_labels()
  643. self.set_loop_labels(
  644. (self.new_label("continue"),
  645. self.new_label("break")))
  646. return old_labels
  647. def get_all_labels(self):
  648. return (
  649. self.continue_label,
  650. self.break_label,
  651. self.return_label,
  652. self.error_label)
  653. def set_all_labels(self, labels):
  654. (self.continue_label,
  655. self.break_label,
  656. self.return_label,
  657. self.error_label) = labels
  658. def all_new_labels(self):
  659. old_labels = self.get_all_labels()
  660. new_labels = []
  661. for old_label, name in zip(old_labels, ['continue', 'break', 'return', 'error']):
  662. if old_label:
  663. new_labels.append(self.new_label(name))
  664. else:
  665. new_labels.append(old_label)
  666. self.set_all_labels(new_labels)
  667. return old_labels
  668. def use_label(self, lbl):
  669. self.labels_used.add(lbl)
  670. def label_used(self, lbl):
  671. return lbl in self.labels_used
  672. # temp handling
  673. def allocate_temp(self, type, manage_ref, static=False):
  674. """
  675. Allocates a temporary (which may create a new one or get a previously
  676. allocated and released one of the same type). Type is simply registered
  677. and handed back, but will usually be a PyrexType.
  678. If type.is_pyobject, manage_ref comes into play. If manage_ref is set to
  679. True, the temp will be decref-ed on return statements and in exception
  680. handling clauses. Otherwise the caller has to deal with any reference
  681. counting of the variable.
  682. If not type.is_pyobject, then manage_ref will be ignored, but it
  683. still has to be passed. It is recommended to pass False by convention
  684. if it is known that type will never be a Python object.
  685. static=True marks the temporary declaration with "static".
  686. This is only used when allocating backing store for a module-level
  687. C array literals.
  688. A C string referring to the variable is returned.
  689. """
  690. if type.is_const and not type.is_reference:
  691. type = type.const_base_type
  692. elif type.is_reference and not type.is_fake_reference:
  693. type = type.ref_base_type
  694. if not type.is_pyobject and not type.is_memoryviewslice:
  695. # Make manage_ref canonical, so that manage_ref will always mean
  696. # a decref is needed.
  697. manage_ref = False
  698. freelist = self.temps_free.get((type, manage_ref))
  699. if freelist is not None and freelist[0]:
  700. result = freelist[0].pop()
  701. freelist[1].remove(result)
  702. else:
  703. while True:
  704. self.temp_counter += 1
  705. result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter)
  706. if result not in self.names_taken: break
  707. self.temps_allocated.append((result, type, manage_ref, static))
  708. self.temps_used_type[result] = (type, manage_ref)
  709. if DebugFlags.debug_temp_code_comments:
  710. self.owner.putln("/* %s allocated (%s) */" % (result, type))
  711. if self.collect_temps_stack:
  712. self.collect_temps_stack[-1].add((result, type))
  713. return result
  714. def release_temp(self, name):
  715. """
  716. Releases a temporary so that it can be reused by other code needing
  717. a temp of the same type.
  718. """
  719. type, manage_ref = self.temps_used_type[name]
  720. freelist = self.temps_free.get((type, manage_ref))
  721. if freelist is None:
  722. freelist = ([], set()) # keep order in list and make lookups in set fast
  723. self.temps_free[(type, manage_ref)] = freelist
  724. if name in freelist[1]:
  725. raise RuntimeError("Temp %s freed twice!" % name)
  726. freelist[0].append(name)
  727. freelist[1].add(name)
  728. if DebugFlags.debug_temp_code_comments:
  729. self.owner.putln("/* %s released */" % name)
  730. def temps_in_use(self):
  731. """Return a list of (cname,type,manage_ref) tuples of temp names and their type
  732. that are currently in use.
  733. """
  734. used = []
  735. for name, type, manage_ref, static in self.temps_allocated:
  736. freelist = self.temps_free.get((type, manage_ref))
  737. if freelist is None or name not in freelist[1]:
  738. used.append((name, type, manage_ref and type.is_pyobject))
  739. return used
  740. def temps_holding_reference(self):
  741. """Return a list of (cname,type) tuples of temp names and their type
  742. that are currently in use. This includes only temps of a
  743. Python object type which owns its reference.
  744. """
  745. return [(name, type)
  746. for name, type, manage_ref in self.temps_in_use()
  747. if manage_ref and type.is_pyobject]
  748. def all_managed_temps(self):
  749. """Return a list of (cname, type) tuples of refcount-managed Python objects.
  750. """
  751. return [(cname, type)
  752. for cname, type, manage_ref, static in self.temps_allocated
  753. if manage_ref]
  754. def all_free_managed_temps(self):
  755. """Return a list of (cname, type) tuples of refcount-managed Python
  756. objects that are not currently in use. This is used by
  757. try-except and try-finally blocks to clean up temps in the
  758. error case.
  759. """
  760. return [(cname, type)
  761. for (type, manage_ref), freelist in self.temps_free.items() if manage_ref
  762. for cname in freelist[0]]
  763. def start_collecting_temps(self):
  764. """
  765. Useful to find out which temps were used in a code block
  766. """
  767. self.collect_temps_stack.append(set())
  768. def stop_collecting_temps(self):
  769. return self.collect_temps_stack.pop()
  770. def init_closure_temps(self, scope):
  771. self.closure_temps = ClosureTempAllocator(scope)
  772. class NumConst(object):
  773. """Global info about a Python number constant held by GlobalState.
  774. cname string
  775. value string
  776. py_type string int, long, float
  777. value_code string evaluation code if different from value
  778. """
  779. def __init__(self, cname, value, py_type, value_code=None):
  780. self.cname = cname
  781. self.value = value
  782. self.py_type = py_type
  783. self.value_code = value_code or value
  784. class PyObjectConst(object):
  785. """Global info about a generic constant held by GlobalState.
  786. """
  787. # cname string
  788. # type PyrexType
  789. def __init__(self, cname, type):
  790. self.cname = cname
  791. self.type = type
  792. cython.declare(possible_unicode_identifier=object, possible_bytes_identifier=object,
  793. replace_identifier=object, find_alphanums=object)
  794. possible_unicode_identifier = re.compile(br"(?![0-9])\w+$".decode('ascii'), re.U).match
  795. possible_bytes_identifier = re.compile(r"(?![0-9])\w+$".encode('ASCII')).match
  796. replace_identifier = re.compile(r'[^a-zA-Z0-9_]+').sub
  797. find_alphanums = re.compile('([a-zA-Z0-9]+)').findall
  798. class StringConst(object):
  799. """Global info about a C string constant held by GlobalState.
  800. """
  801. # cname string
  802. # text EncodedString or BytesLiteral
  803. # py_strings {(identifier, encoding) : PyStringConst}
  804. def __init__(self, cname, text, byte_string):
  805. self.cname = cname
  806. self.text = text
  807. self.escaped_value = StringEncoding.escape_byte_string(byte_string)
  808. self.py_strings = None
  809. self.py_versions = []
  810. def add_py_version(self, version):
  811. if not version:
  812. self.py_versions = [2, 3]
  813. elif version not in self.py_versions:
  814. self.py_versions.append(version)
  815. def get_py_string_const(self, encoding, identifier=None,
  816. is_str=False, py3str_cstring=None):
  817. py_strings = self.py_strings
  818. text = self.text
  819. is_str = bool(identifier or is_str)
  820. is_unicode = encoding is None and not is_str
  821. if encoding is None:
  822. # unicode string
  823. encoding_key = None
  824. else:
  825. # bytes or str
  826. encoding = encoding.lower()
  827. if encoding in ('utf8', 'utf-8', 'ascii', 'usascii', 'us-ascii'):
  828. encoding = None
  829. encoding_key = None
  830. else:
  831. encoding_key = ''.join(find_alphanums(encoding))
  832. key = (is_str, is_unicode, encoding_key, py3str_cstring)
  833. if py_strings is not None:
  834. try:
  835. return py_strings[key]
  836. except KeyError:
  837. pass
  838. else:
  839. self.py_strings = {}
  840. if identifier:
  841. intern = True
  842. elif identifier is None:
  843. if isinstance(text, bytes):
  844. intern = bool(possible_bytes_identifier(text))
  845. else:
  846. intern = bool(possible_unicode_identifier(text))
  847. else:
  848. intern = False
  849. if intern:
  850. prefix = Naming.interned_prefixes['str']
  851. else:
  852. prefix = Naming.py_const_prefix
  853. if encoding_key:
  854. encoding_prefix = '_%s' % encoding_key
  855. else:
  856. encoding_prefix = ''
  857. pystring_cname = "%s%s%s_%s" % (
  858. prefix,
  859. (is_str and 's') or (is_unicode and 'u') or 'b',
  860. encoding_prefix,
  861. self.cname[len(Naming.const_prefix):])
  862. py_string = PyStringConst(
  863. pystring_cname, encoding, is_unicode, is_str, py3str_cstring, intern)
  864. self.py_strings[key] = py_string
  865. return py_string
  866. class PyStringConst(object):
  867. """Global info about a Python string constant held by GlobalState.
  868. """
  869. # cname string
  870. # py3str_cstring string
  871. # encoding string
  872. # intern boolean
  873. # is_unicode boolean
  874. # is_str boolean
  875. def __init__(self, cname, encoding, is_unicode, is_str=False,
  876. py3str_cstring=None, intern=False):
  877. self.cname = cname
  878. self.py3str_cstring = py3str_cstring
  879. self.encoding = encoding
  880. self.is_str = is_str
  881. self.is_unicode = is_unicode
  882. self.intern = intern
  883. def __lt__(self, other):
  884. return self.cname < other.cname
  885. class GlobalState(object):
  886. # filename_table {string : int} for finding filename table indexes
  887. # filename_list [string] filenames in filename table order
  888. # input_file_contents dict contents (=list of lines) of any file that was used as input
  889. # to create this output C code. This is
  890. # used to annotate the comments.
  891. #
  892. # utility_codes set IDs of used utility code (to avoid reinsertion)
  893. #
  894. # declared_cnames {string:Entry} used in a transition phase to merge pxd-declared
  895. # constants etc. into the pyx-declared ones (i.e,
  896. # check if constants are already added).
  897. # In time, hopefully the literals etc. will be
  898. # supplied directly instead.
  899. #
  900. # const_cnames_used dict global counter for unique constant identifiers
  901. #
  902. # parts {string:CCodeWriter}
  903. # interned_strings
  904. # consts
  905. # interned_nums
  906. # directives set Temporary variable used to track
  907. # the current set of directives in the code generation
  908. # process.
  909. directives = {}
  910. code_layout = [
  911. 'h_code',
  912. 'filename_table',
  913. 'utility_code_proto_before_types',
  914. 'numeric_typedefs', # Let these detailed individual parts stay!,
  915. 'complex_type_declarations', # as the proper solution is to make a full DAG...
  916. 'type_declarations', # More coarse-grained blocks would simply hide
  917. 'utility_code_proto', # the ugliness, not fix it
  918. 'module_declarations',
  919. 'typeinfo',
  920. 'before_global_var',
  921. 'global_var',
  922. 'string_decls',
  923. 'decls',
  924. 'late_includes',
  925. 'all_the_rest',
  926. 'pystring_table',
  927. 'cached_builtins',
  928. 'cached_constants',
  929. 'init_globals',
  930. 'init_module',
  931. 'cleanup_globals',
  932. 'cleanup_module',
  933. 'main_method',
  934. 'utility_code_def',
  935. 'end'
  936. ]
  937. def __init__(self, writer, module_node, code_config, common_utility_include_dir=None):
  938. self.filename_table = {}
  939. self.filename_list = []
  940. self.input_file_contents = {}
  941. self.utility_codes = set()
  942. self.declared_cnames = {}
  943. self.in_utility_code_generation = False
  944. self.code_config = code_config
  945. self.common_utility_include_dir = common_utility_include_dir
  946. self.parts = {}
  947. self.module_node = module_node # because some utility code generation needs it
  948. # (generating backwards-compatible Get/ReleaseBuffer
  949. self.const_cnames_used = {}
  950. self.string_const_index = {}
  951. self.pyunicode_ptr_const_index = {}
  952. self.num_const_index = {}
  953. self.py_constants = []
  954. self.cached_cmethods = {}
  955. writer.set_global_state(self)
  956. self.rootwriter = writer
  957. def initialize_main_c_code(self):
  958. rootwriter = self.rootwriter
  959. for part in self.code_layout:
  960. self.parts[part] = rootwriter.insertion_point()
  961. if not Options.cache_builtins:
  962. del self.parts['cached_builtins']
  963. else:
  964. w = self.parts['cached_builtins']
  965. w.enter_cfunc_scope()
  966. w.putln("static int __Pyx_InitCachedBuiltins(void) {")
  967. w = self.parts['cached_constants']
  968. w.enter_cfunc_scope()
  969. w.putln("")
  970. w.putln("static int __Pyx_InitCachedConstants(void) {")
  971. w.put_declare_refcount_context()
  972. w.put_setup_refcount_context("__Pyx_InitCachedConstants")
  973. w = self.parts['init_globals']
  974. w.enter_cfunc_scope()
  975. w.putln("")
  976. w.putln("static int __Pyx_InitGlobals(void) {")
  977. if not Options.generate_cleanup_code:
  978. del self.parts['cleanup_globals']
  979. else:
  980. w = self.parts['cleanup_globals']
  981. w.enter_cfunc_scope()
  982. w.putln("")
  983. w.putln("static void __Pyx_CleanupGlobals(void) {")
  984. code = self.parts['utility_code_proto']
  985. code.putln("")
  986. code.putln("/* --- Runtime support code (head) --- */")
  987. code = self.parts['utility_code_def']
  988. if self.code_config.emit_linenums:
  989. code.write('\n#line 1 "cython_utility"\n')
  990. code.putln("")
  991. code.putln("/* --- Runtime support code --- */")
  992. def finalize_main_c_code(self):
  993. self.close_global_decls()
  994. #
  995. # utility_code_def
  996. #
  997. code = self.parts['utility_code_def']
  998. util = TempitaUtilityCode.load_cached("TypeConversions", "TypeConversion.c")
  999. code.put(util.format_code(util.impl))
  1000. code.putln("")
  1001. def __getitem__(self, key):
  1002. return self.parts[key]
  1003. #
  1004. # Global constants, interned objects, etc.
  1005. #
  1006. def close_global_decls(self):
  1007. # This is called when it is known that no more global declarations will
  1008. # declared.
  1009. self.generate_const_declarations()
  1010. if Options.cache_builtins:
  1011. w = self.parts['cached_builtins']
  1012. w.putln("return 0;")
  1013. if w.label_used(w.error_label):
  1014. w.put_label(w.error_label)
  1015. w.putln("return -1;")
  1016. w.putln("}")
  1017. w.exit_cfunc_scope()
  1018. w = self.parts['cached_constants']
  1019. w.put_finish_refcount_context()
  1020. w.putln("return 0;")
  1021. if w.label_used(w.error_label):
  1022. w.put_label(w.error_label)
  1023. w.put_finish_refcount_context()
  1024. w.putln("return -1;")
  1025. w.putln("}")
  1026. w.exit_cfunc_scope()
  1027. w = self.parts['init_globals']
  1028. w.putln("return 0;")
  1029. if w.label_used(w.error_label):
  1030. w.put_label(w.error_label)
  1031. w.putln("return -1;")
  1032. w.putln("}")
  1033. w.exit_cfunc_scope()
  1034. if Options.generate_cleanup_code:
  1035. w = self.parts['cleanup_globals']
  1036. w.putln("}")
  1037. w.exit_cfunc_scope()
  1038. if Options.generate_cleanup_code:
  1039. w = self.parts['cleanup_module']
  1040. w.putln("}")
  1041. w.exit_cfunc_scope()
  1042. def put_pyobject_decl(self, entry):
  1043. self['global_var'].putln("static PyObject *%s;" % entry.cname)
  1044. # constant handling at code generation time
  1045. def get_cached_constants_writer(self):
  1046. return self.parts['cached_constants']
  1047. def get_int_const(self, str_value, longness=False):
  1048. py_type = longness and 'long' or 'int'
  1049. try:
  1050. c = self.num_const_index[(str_value, py_type)]
  1051. except KeyError:
  1052. c = self.new_num_const(str_value, py_type)
  1053. return c
  1054. def get_float_const(self, str_value, value_code):
  1055. try:
  1056. c = self.num_const_index[(str_value, 'float')]
  1057. except KeyError:
  1058. c = self.new_num_const(str_value, 'float', value_code)
  1059. return c
  1060. def get_py_const(self, type, prefix='', cleanup_level=None):
  1061. # create a new Python object constant
  1062. const = self.new_py_const(type, prefix)
  1063. if cleanup_level is not None \
  1064. and cleanup_level <= Options.generate_cleanup_code:
  1065. cleanup_writer = self.parts['cleanup_globals']
  1066. cleanup_writer.putln('Py_CLEAR(%s);' % const.cname)
  1067. return const
  1068. def get_string_const(self, text, py_version=None):
  1069. # return a C string constant, creating a new one if necessary
  1070. if text.is_unicode:
  1071. byte_string = text.utf8encode()
  1072. else:
  1073. byte_string = text.byteencode()
  1074. try:
  1075. c = self.string_const_index[byte_string]
  1076. except KeyError:
  1077. c = self.new_string_const(text, byte_string)
  1078. c.add_py_version(py_version)
  1079. return c
  1080. def get_pyunicode_ptr_const(self, text):
  1081. # return a Py_UNICODE[] constant, creating a new one if necessary
  1082. assert text.is_unicode
  1083. try:
  1084. c = self.pyunicode_ptr_const_index[text]
  1085. except KeyError:
  1086. c = self.pyunicode_ptr_const_index[text] = self.new_const_cname()
  1087. return c
  1088. def get_py_string_const(self, text, identifier=None,
  1089. is_str=False, unicode_value=None):
  1090. # return a Python string constant, creating a new one if necessary
  1091. py3str_cstring = None
  1092. if is_str and unicode_value is not None \
  1093. and unicode_value.utf8encode() != text.byteencode():
  1094. py3str_cstring = self.get_string_const(unicode_value, py_version=3)
  1095. c_string = self.get_string_const(text, py_version=2)
  1096. else:
  1097. c_string = self.get_string_const(text)
  1098. py_string = c_string.get_py_string_const(
  1099. text.encoding, identifier, is_str, py3str_cstring)
  1100. return py_string
  1101. def get_interned_identifier(self, text):
  1102. return self.get_py_string_const(text, identifier=True)
  1103. def new_string_const(self, text, byte_string):
  1104. cname = self.new_string_const_cname(byte_string)
  1105. c = StringConst(cname, text, byte_string)
  1106. self.string_const_index[byte_string] = c
  1107. return c
  1108. def new_num_const(self, value, py_type, value_code=None):
  1109. cname = self.new_num_const_cname(value, py_type)
  1110. c = NumConst(cname, value, py_type, value_code)
  1111. self.num_const_index[(value, py_type)] = c
  1112. return c
  1113. def new_py_const(self, type, prefix=''):
  1114. cname = self.new_const_cname(prefix)
  1115. c = PyObjectConst(cname, type)
  1116. self.py_constants.append(c)
  1117. return c
  1118. def new_string_const_cname(self, bytes_value):
  1119. # Create a new globally-unique nice name for a C string constant.
  1120. value = bytes_value.decode('ASCII', 'ignore')
  1121. return self.new_const_cname(value=value)
  1122. def new_num_const_cname(self, value, py_type):
  1123. if py_type == 'long':
  1124. value += 'L'
  1125. py_type = 'int'
  1126. prefix = Naming.interned_prefixes[py_type]
  1127. cname = "%s%s" % (prefix, value)
  1128. cname = cname.replace('+', '_').replace('-', 'neg_').replace('.', '_')
  1129. return cname
  1130. def new_const_cname(self, prefix='', value=''):
  1131. value = replace_identifier('_', value)[:32].strip('_')
  1132. used = self.const_cnames_used
  1133. name_suffix = value
  1134. while name_suffix in used:
  1135. counter = used[value] = used[value] + 1
  1136. name_suffix = '%s_%d' % (value, counter)
  1137. used[name_suffix] = 1
  1138. if prefix:
  1139. prefix = Naming.interned_prefixes[prefix]
  1140. else:
  1141. prefix = Naming.const_prefix
  1142. return "%s%s" % (prefix, name_suffix)
  1143. def get_cached_unbound_method(self, type_cname, method_name):
  1144. key = (type_cname, method_name)
  1145. try:
  1146. cname = self.cached_cmethods[key]
  1147. except KeyError:
  1148. cname = self.cached_cmethods[key] = self.new_const_cname(
  1149. 'umethod', '%s_%s' % (type_cname, method_name))
  1150. return cname
  1151. def cached_unbound_method_call_code(self, obj_cname, type_cname, method_name, arg_cnames):
  1152. # admittedly, not the best place to put this method, but it is reused by UtilityCode and ExprNodes ...
  1153. utility_code_name = "CallUnboundCMethod%d" % len(arg_cnames)
  1154. self.use_utility_code(UtilityCode.load_cached(utility_code_name, "ObjectHandling.c"))
  1155. cache_cname = self.get_cached_unbound_method(type_cname, method_name)
  1156. args = [obj_cname] + arg_cnames
  1157. return "__Pyx_%s(&%s, %s)" % (
  1158. utility_code_name,
  1159. cache_cname,
  1160. ', '.join(args),
  1161. )
  1162. def add_cached_builtin_decl(self, entry):
  1163. if entry.is_builtin and entry.is_const:
  1164. if self.should_declare(entry.cname, entry):
  1165. self.put_pyobject_decl(entry)
  1166. w = self.parts['cached_builtins']
  1167. condition = None
  1168. if entry.name in non_portable_builtins_map:
  1169. condition, replacement = non_portable_builtins_map[entry.name]
  1170. w.putln('#if %s' % condition)
  1171. self.put_cached_builtin_init(
  1172. entry.pos, StringEncoding.EncodedString(replacement),
  1173. entry.cname)
  1174. w.putln('#else')
  1175. self.put_cached_builtin_init(
  1176. entry.pos, StringEncoding.EncodedString(entry.name),
  1177. entry.cname)
  1178. if condition:
  1179. w.putln('#endif')
  1180. def put_cached_builtin_init(self, pos, name, cname):
  1181. w = self.parts['cached_builtins']
  1182. interned_cname = self.get_interned_identifier(name).cname
  1183. self.use_utility_code(
  1184. UtilityCode.load_cached("GetBuiltinName", "ObjectHandling.c"))
  1185. w.putln('%s = __Pyx_GetBuiltinName(%s); if (!%s) %s' % (
  1186. cname,
  1187. interned_cname,
  1188. cname,
  1189. w.error_goto(pos)))
  1190. def generate_const_declarations(self):
  1191. self.generate_cached_methods_decls()
  1192. self.generate_string_constants()
  1193. self.generate_num_constants()
  1194. self.generate_object_constant_decls()
  1195. def generate_object_constant_decls(self):
  1196. consts = [(len(c.cname), c.cname, c)
  1197. for c in self.py_constants]
  1198. consts.sort()
  1199. decls_writer = self.parts['decls']
  1200. for _, cname, c in consts:
  1201. decls_writer.putln(
  1202. "static %s;" % c.type.declaration_code(cname))
  1203. def generate_cached_methods_decls(self):
  1204. if not self.cached_cmethods:
  1205. return
  1206. decl = self.parts['decls']
  1207. init = self.parts['init_globals']
  1208. cnames = []
  1209. for (type_cname, method_name), cname in sorted(self.cached_cmethods.items()):
  1210. cnames.append(cname)
  1211. method_name_cname = self.get_interned_identifier(StringEncoding.EncodedString(method_name)).cname
  1212. decl.putln('static __Pyx_CachedCFunction %s = {0, &%s, 0, 0, 0};' % (
  1213. cname, method_name_cname))
  1214. # split type reference storage as it might not be static
  1215. init.putln('%s.type = (PyObject*)&%s;' % (
  1216. cname, type_cname))
  1217. if Options.generate_cleanup_code:
  1218. cleanup = self.parts['cleanup_globals']
  1219. for cname in cnames:
  1220. cleanup.putln("Py_CLEAR(%s.method);" % cname)
  1221. def generate_string_constants(self):
  1222. c_consts = [(len(c.cname), c.cname, c) for c in self.string_const_index.values()]
  1223. c_consts.sort()
  1224. py_strings = []
  1225. decls_writer = self.parts['string_decls']
  1226. for _, cname, c in c_consts:
  1227. conditional = False
  1228. if c.py_versions and (2 not in c.py_versions or 3 not in c.py_versions):
  1229. conditional = True
  1230. decls_writer.putln("#if PY_MAJOR_VERSION %s 3" % (
  1231. (2 in c.py_versions) and '<' or '>='))
  1232. decls_writer.putln('static const char %s[] = "%s";' % (
  1233. cname, StringEncoding.split_string_literal(c.escaped_value)))
  1234. if conditional:
  1235. decls_writer.putln("#endif")
  1236. if c.py_strings is not None:
  1237. for py_string in c.py_strings.values():
  1238. py_strings.append((c.cname, len(py_string.cname), py_string))
  1239. for c, cname in sorted(self.pyunicode_ptr_const_index.items()):
  1240. utf16_array, utf32_array = StringEncoding.encode_pyunicode_string(c)
  1241. if utf16_array:
  1242. # Narrow and wide representations differ
  1243. decls_writer.putln("#ifdef Py_UNICODE_WIDE")
  1244. decls_writer.putln("static Py_UNICODE %s[] = { %s };" % (cname, utf32_array))
  1245. if utf16_array:
  1246. decls_writer.putln("#else")
  1247. decls_writer.putln("static Py_UNICODE %s[] = { %s };" % (cname, utf16_array))
  1248. decls_writer.putln("#endif")
  1249. if py_strings:
  1250. self.use_utility_code(UtilityCode.load_cached("InitStrings", "StringTools.c"))
  1251. py_strings.sort()
  1252. w = self.parts['pystring_table']
  1253. w.putln("")
  1254. w.putln("static __Pyx_StringTabEntry %s[] = {" % Naming.stringtab_cname)
  1255. for c_cname, _, py_string in py_strings:
  1256. if not py_string.is_str or not py_string.encoding or \
  1257. py_string.encoding in ('ASCII', 'USASCII', 'US-ASCII',
  1258. 'UTF8', 'UTF-8'):
  1259. encoding = '0'
  1260. else:
  1261. encoding = '"%s"' % py_string.encoding.lower()
  1262. decls_writer.putln(
  1263. "static PyObject *%s;" % py_string.cname)
  1264. if py_string.py3str_cstring:
  1265. w.putln("#if PY_MAJOR_VERSION >= 3")
  1266. w.putln("{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
  1267. py_string.cname,
  1268. py_string.py3str_cstring.cname,
  1269. py_string.py3str_cstring.cname,
  1270. '0', 1, 0,
  1271. py_string.intern
  1272. ))
  1273. w.putln("#else")
  1274. w.putln("{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
  1275. py_string.cname,
  1276. c_cname,
  1277. c_cname,
  1278. encoding,
  1279. py_string.is_unicode,
  1280. py_string.is_str,
  1281. py_string.intern
  1282. ))
  1283. if py_string.py3str_cstring:
  1284. w.putln("#endif")
  1285. w.putln("{0, 0, 0, 0, 0, 0, 0}")
  1286. w.putln("};")
  1287. init_globals = self.parts['init_globals']
  1288. init_globals.putln(
  1289. "if (__Pyx_InitStrings(%s) < 0) %s;" % (
  1290. Naming.stringtab_cname,
  1291. init_globals.error_goto(self.module_pos)))
  1292. def generate_num_constants(self):
  1293. consts = [(c.py_type, c.value[0] == '-', len(c.value), c.value, c.value_code, c)
  1294. for c in self.num_const_index.values()]
  1295. consts.sort()
  1296. decls_writer = self.parts['decls']
  1297. init_globals = self.parts['init_globals']
  1298. for py_type, _, _, value, value_code, c in consts:
  1299. cname = c.cname
  1300. decls_writer.putln("static PyObject *%s;" % cname)
  1301. if py_type == 'float':
  1302. function = 'PyFloat_FromDouble(%s)'
  1303. elif py_type == 'long':
  1304. function = 'PyLong_FromString((char *)"%s", 0, 0)'
  1305. elif Utils.long_literal(value):
  1306. function = 'PyInt_FromString((char *)"%s", 0, 0)'
  1307. elif len(value.lstrip('-')) > 4:
  1308. function = "PyInt_FromLong(%sL)"
  1309. else:
  1310. function = "PyInt_FromLong(%s)"
  1311. init_globals.putln('%s = %s; %s' % (
  1312. cname, function % value_code,
  1313. init_globals.error_goto_if_null(cname, self.module_pos)))
  1314. # The functions below are there in a transition phase only
  1315. # and will be deprecated. They are called from Nodes.BlockNode.
  1316. # The copy&paste duplication is intentional in order to be able
  1317. # to see quickly how BlockNode worked, until this is replaced.
  1318. def should_declare(self, cname, entry):
  1319. if cname in self.declared_cnames:
  1320. other = self.declared_cnames[cname]
  1321. assert str(entry.type) == str(other.type)
  1322. assert entry.init == other.init
  1323. return False
  1324. else:
  1325. self.declared_cnames[cname] = entry
  1326. return True
  1327. #
  1328. # File name state
  1329. #
  1330. def lookup_filename(self, source_desc):
  1331. entry = source_desc.get_filenametable_entry()
  1332. try:
  1333. index = self.filename_table[entry]
  1334. except KeyError:
  1335. index = len(self.filename_list)
  1336. self.filename_list.append(source_desc)
  1337. self.filename_table[entry] = index
  1338. return index
  1339. def commented_file_contents(self, source_desc):
  1340. try:
  1341. return self.input_file_contents[source_desc]
  1342. except KeyError:
  1343. pass
  1344. source_file = source_desc.get_lines(encoding='ASCII',
  1345. error_handling='ignore')
  1346. try:
  1347. F = [u' * ' + line.rstrip().replace(
  1348. u'*/', u'*[inserted by cython to avoid comment closer]/'
  1349. ).replace(
  1350. u'/*', u'/[inserted by cython to avoid comment start]*'
  1351. )
  1352. for line in source_file]
  1353. finally:
  1354. if hasattr(source_file, 'close'):
  1355. source_file.close()
  1356. if not F: F.append(u'')
  1357. self.input_file_contents[source_desc] = F
  1358. return F
  1359. #
  1360. # Utility code state
  1361. #
  1362. def use_utility_code(self, utility_code):
  1363. """
  1364. Adds code to the C file. utility_code should
  1365. a) implement __eq__/__hash__ for the purpose of knowing whether the same
  1366. code has already been included
  1367. b) implement put_code, which takes a globalstate instance
  1368. See UtilityCode.
  1369. """
  1370. if utility_code and utility_code not in self.utility_codes:
  1371. self.utility_codes.add(utility_code)
  1372. utility_code.put_code(self)
  1373. def use_entry_utility_code(self, entry):
  1374. if entry is None:
  1375. return
  1376. if entry.utility_code:
  1377. self.use_utility_code(entry.utility_code)
  1378. if entry.utility_code_definition:
  1379. self.use_utility_code(entry.utility_code_definition)
  1380. def funccontext_property(name):
  1381. attribute_of = operator.attrgetter(name)
  1382. def get(self):
  1383. return attribute_of(self.funcstate)
  1384. def set(self, value):
  1385. setattr(self.funcstate, name, value)
  1386. return property(get, set)
  1387. class CCodeConfig(object):
  1388. # emit_linenums boolean write #line pragmas?
  1389. # emit_code_comments boolean copy the original code into C comments?
  1390. # c_line_in_traceback boolean append the c file and line number to the traceback for exceptions?
  1391. def __init__(self, emit_linenums=True, emit_code_comments=True, c_line_in_traceback=True):
  1392. self.emit_code_comments = emit_code_comments
  1393. self.emit_linenums = emit_linenums
  1394. self.c_line_in_traceback = c_line_in_traceback
  1395. class CCodeWriter(object):
  1396. """
  1397. Utility class to output C code.
  1398. When creating an insertion point one must care about the state that is
  1399. kept:
  1400. - formatting state (level, bol) is cloned and used in insertion points
  1401. as well
  1402. - labels, temps, exc_vars: One must construct a scope in which these can
  1403. exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for
  1404. sanity checking and forward compatibility). Created insertion points
  1405. looses this scope and cannot access it.
  1406. - marker: Not copied to insertion point
  1407. - filename_table, filename_list, input_file_contents: All codewriters
  1408. coming from the same root share the same instances simultaneously.
  1409. """
  1410. # f file output file
  1411. # buffer StringIOTree
  1412. # level int indentation level
  1413. # bol bool beginning of line?
  1414. # marker string comment to emit before next line
  1415. # funcstate FunctionState contains state local to a C function used for code
  1416. # generation (labels and temps state etc.)
  1417. # globalstate GlobalState contains state global for a C file (input file info,
  1418. # utility code, declared constants etc.)
  1419. # pyclass_stack list used during recursive code generation to pass information
  1420. # about the current class one is in
  1421. # code_config CCodeConfig configuration options for the C code writer
  1422. globalstate = code_config = None
  1423. def __init__(self, create_from=None, buffer=None, copy_formatting=False):
  1424. if buffer is None: buffer = StringIOTree()
  1425. self.buffer = buffer
  1426. self.last_pos = None
  1427. self.last_marked_pos = None
  1428. self.pyclass_stack = []
  1429. self.funcstate = None
  1430. self.level = 0
  1431. self.call_level = 0
  1432. self.bol = 1
  1433. if create_from is not None:
  1434. # Use same global state
  1435. self.set_global_state(create_from.globalstate)
  1436. self.funcstate = create_from.funcstate
  1437. # Clone formatting state
  1438. if copy_formatting:
  1439. self.level = create_from.level
  1440. self.bol = create_from.bol
  1441. self.call_level = create_from.call_level
  1442. self.last_pos = create_from.last_pos
  1443. self.last_marked_pos = create_from.last_marked_pos
  1444. def create_new(self, create_from, buffer, copy_formatting):
  1445. # polymorphic constructor -- very slightly more versatile
  1446. # than using __class__
  1447. result = CCodeWriter(create_from, buffer, copy_formatting)
  1448. return result
  1449. def set_global_state(self, global_state):
  1450. assert self.globalstate is None # prevent overwriting once it's set
  1451. self.globalstate = global_state
  1452. self.code_config = global_state.code_config
  1453. def copyto(self, f):
  1454. self.buffer.copyto(f)
  1455. def getvalue(self):
  1456. return self.buffer.getvalue()
  1457. def write(self, s):
  1458. # also put invalid markers (lineno 0), to indicate that those lines
  1459. # have no Cython source code correspondence
  1460. cython_lineno = self.last_marked_pos[1] if self.last_marked_pos else 0
  1461. self.buffer.markers.extend([cython_lineno] * s.count('\n'))
  1462. self.buffer.write(s)
  1463. def insertion_point(self):
  1464. other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(), copy_formatting=True)
  1465. return other
  1466. def new_writer(self):
  1467. """
  1468. Creates a new CCodeWriter connected to the same global state, which
  1469. can later be inserted using insert.
  1470. """
  1471. return CCodeWriter(create_from=self)
  1472. def insert(self, writer):
  1473. """
  1474. Inserts the contents of another code writer (created with
  1475. the same global state) in the current location.
  1476. It is ok to write to the inserted writer also after insertion.
  1477. """
  1478. assert writer.globalstate is self.globalstate
  1479. self.buffer.insert(writer.buffer)
  1480. # Properties delegated to function scope
  1481. label_counter = funccontext_property("label_counter")
  1482. return_label = funccontext_property("return_label")
  1483. error_label = funccontext_property("error_label")
  1484. labels_used = funccontext_property("labels_used")
  1485. continue_label = funccontext_property("continue_label")
  1486. break_label = funccontext_property("break_label")
  1487. return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label")
  1488. yield_labels = funccontext_property("yield_labels")
  1489. # Functions delegated to function scope
  1490. def new_label(self, name=None): return self.funcstate.new_label(name)
  1491. def new_error_label(self): return self.funcstate.new_error_label()
  1492. def new_yield_label(self, *args): return self.funcstate.new_yield_label(*args)
  1493. def get_loop_labels(self): return self.funcstate.get_loop_labels()
  1494. def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels)
  1495. def new_loop_labels(self): return self.funcstate.new_loop_labels()
  1496. def get_all_labels(self): return self.funcstate.get_all_labels()
  1497. def set_all_labels(self, labels): return self.funcstate.set_all_labels(labels)
  1498. def all_new_labels(self): return self.funcstate.all_new_labels()
  1499. def use_label(self, lbl): return self.funcstate.use_label(lbl)
  1500. def label_used(self, lbl): return self.funcstate.label_used(lbl)
  1501. def enter_cfunc_scope(self, scope=None):
  1502. self.funcstate = FunctionState(self, scope=scope)
  1503. def exit_cfunc_scope(self):
  1504. self.funcstate = None
  1505. # constant handling
  1506. def get_py_int(self, str_value, longness):
  1507. return self.globalstate.get_int_const(str_value, longness).cname
  1508. def get_py_float(self, str_value, value_code):
  1509. return self.globalstate.get_float_const(str_value, value_code).cname
  1510. def get_py_const(self, type, prefix='', cleanup_level=None):
  1511. return self.globalstate.get_py_const(type, prefix, cleanup_level).cname
  1512. def get_string_const(self, text):
  1513. return self.globalstate.get_string_const(text).cname
  1514. def get_pyunicode_ptr_const(self, text):
  1515. return self.globalstate.get_pyunicode_ptr_const(text)
  1516. def get_py_string_const(self, text, identifier=None,
  1517. is_str=False, unicode_value=None):
  1518. return self.globalstate.get_py_string_const(
  1519. text, identifier, is_str, unicode_value).cname
  1520. def get_argument_default_const(self, type):
  1521. return self.globalstate.get_py_const(type).cname
  1522. def intern(self, text):
  1523. return self.get_py_string_const(text)
  1524. def intern_identifier(self, text):
  1525. return self.get_py_string_const(text, identifier=True)
  1526. def get_cached_constants_writer(self):
  1527. return self.globalstate.get_cached_constants_writer()
  1528. # code generation
  1529. def putln(self, code="", safe=False):
  1530. if self.last_pos and self.bol:
  1531. self.emit_marker()
  1532. if self.code_config.emit_linenums and self.last_marked_pos:
  1533. source_desc, line, _ = self.last_marked_pos
  1534. self.write('\n#line %s "%s"\n' % (line, source_desc.get_escaped_description()))
  1535. if code:
  1536. if safe:
  1537. self.put_safe(code)
  1538. else:
  1539. self.put(code)
  1540. self.write("\n")
  1541. self.bol = 1
  1542. def mark_pos(self, pos, trace=True):
  1543. if pos is None:
  1544. return
  1545. if self.last_marked_pos and self.last_marked_pos[:2] == pos[:2]:
  1546. return
  1547. self.last_pos = (pos, trace)
  1548. def emit_marker(self):
  1549. pos, trace = self.last_pos
  1550. self.last_marked_pos = pos
  1551. self.last_pos = None
  1552. self.write("\n")
  1553. if self.code_config.emit_code_comments:
  1554. self.indent()
  1555. self.write("/* %s */\n" % self._build_marker(pos))
  1556. if trace and self.funcstate and self.funcstate.can_trace and self.globalstate.directives['linetrace']:
  1557. self.indent()
  1558. self.write('__Pyx_TraceLine(%d,%d,%s)\n' % (
  1559. pos[1], not self.funcstate.gil_owned, self.error_goto(pos)))
  1560. def _build_marker(self, pos):
  1561. source_desc, line, col = pos
  1562. assert isinstance(source_desc, SourceDescriptor)
  1563. contents = self.globalstate.commented_file_contents(source_desc)
  1564. lines = contents[max(0, line-3):line] # line numbers start at 1
  1565. lines[-1] += u' # <<<<<<<<<<<<<<'
  1566. lines += contents[line:line+2]
  1567. return u'"%s":%d\n%s\n' % (source_desc.get_escaped_description(), line, u'\n'.join(lines))
  1568. def put_safe(self, code):
  1569. # put code, but ignore {}
  1570. self.write(code)
  1571. self.bol = 0
  1572. def put_or_include(self, code, name):
  1573. include_dir = self.globalstate.common_utility_include_dir
  1574. if include_dir and len(code) > 1024:
  1575. include_file = "%s_%s.h" % (
  1576. name, hashlib.md5(code.encode('utf8')).hexdigest())
  1577. path = os.path.join(include_dir, include_file)
  1578. if not os.path.exists(path):
  1579. tmp_path = '%s.tmp%s' % (path, os.getpid())
  1580. with closing(Utils.open_new_file(tmp_path)) as f:
  1581. f.write(code)
  1582. shutil.move(tmp_path, path)
  1583. code = '#include "%s"\n' % path
  1584. self.put(code)
  1585. def put(self, code):
  1586. if is_self_assignment(code):
  1587. return
  1588. fix_indent = False
  1589. if "{" in code:
  1590. dl = code.count("{")
  1591. else:
  1592. dl = 0
  1593. if "}" in code:
  1594. dl -= code.count("}")
  1595. if dl < 0:
  1596. self.level += dl
  1597. elif dl == 0 and code[0] == "}":
  1598. # special cases like "} else {" need a temporary dedent
  1599. fix_indent = True
  1600. self.level -= 1
  1601. if self.bol:
  1602. self.indent()
  1603. self.write(code)
  1604. self.bol = 0
  1605. if dl > 0:
  1606. self.level += dl
  1607. elif fix_indent:
  1608. self.level += 1
  1609. def putln_tempita(self, code, **context):
  1610. from ..Tempita import sub
  1611. self.putln(sub(code, **context))
  1612. def put_tempita(self, code, **context):
  1613. from ..Tempita import sub
  1614. self.put(sub(code, **context))
  1615. def increase_indent(self):
  1616. self.level += 1
  1617. def decrease_indent(self):
  1618. self.level -= 1
  1619. def begin_block(self):
  1620. self.putln("{")
  1621. self.increase_indent()
  1622. def end_block(self):
  1623. self.decrease_indent()
  1624. self.putln("}")
  1625. def indent(self):
  1626. self.write(" " * self.level)
  1627. def get_py_version_hex(self, pyversion):
  1628. return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]
  1629. def put_label(self, lbl):
  1630. if lbl in self.funcstate.labels_used:
  1631. self.putln("%s:;" % lbl)
  1632. def put_goto(self, lbl):
  1633. self.funcstate.use_label(lbl)
  1634. self.putln("goto %s;" % lbl)
  1635. def put_var_declaration(self, entry, storage_class="",
  1636. dll_linkage=None, definition=True):
  1637. #print "Code.put_var_declaration:", entry.name, "definition =", definition ###
  1638. if entry.visibility == 'private' and not (definition or entry.defined_in_pxd):
  1639. #print "...private and not definition, skipping", entry.cname ###
  1640. return
  1641. if entry.visibility == "private" and not entry.used:
  1642. #print "...private and not used, skipping", entry.cname ###
  1643. return
  1644. if storage_class:
  1645. self.put("%s " % storage_class)
  1646. if not entry.cf_used:
  1647. self.put('CYTHON_UNUSED ')
  1648. self.put(entry.type.declaration_code(
  1649. entry.cname, dll_linkage=dll_linkage))
  1650. if entry.init is not None:
  1651. self.put_safe(" = %s" % entry.type.literal_code(entry.init))
  1652. elif entry.type.is_pyobject:
  1653. self.put(" = NULL")
  1654. self.putln(";")
  1655. def put_temp_declarations(self, func_context):
  1656. for name, type, manage_ref, static in func_context.temps_allocated:
  1657. decl = type.declaration_code(name)
  1658. if type.is_pyobject:
  1659. self.putln("%s = NULL;" % decl)
  1660. elif type.is_memoryviewslice:
  1661. from . import MemoryView
  1662. self.putln("%s = %s;" % (decl, MemoryView.memslice_entry_init))
  1663. else:
  1664. self.putln("%s%s;" % (static and "static " or "", decl))
  1665. if func_context.should_declare_error_indicator:
  1666. if self.funcstate.uses_error_indicator:
  1667. unused = ''
  1668. else:
  1669. unused = 'CYTHON_UNUSED '
  1670. # Initialize these variables to silence compiler warnings
  1671. self.putln("%sint %s = 0;" % (unused, Naming.lineno_cname))
  1672. self.putln("%sconst char *%s = NULL;" % (unused, Naming.filename_cname))
  1673. self.putln("%sint %s = 0;" % (unused, Naming.clineno_cname))
  1674. def put_generated_by(self):
  1675. self.putln("/* Generated by Cython %s */" % Version.watermark)
  1676. self.putln("")
  1677. def put_h_guard(self, guard):
  1678. self.putln("#ifndef %s" % guard)
  1679. self.putln("#define %s" % guard)
  1680. def unlikely(self, cond):
  1681. if Options.gcc_branch_hints:
  1682. return 'unlikely(%s)' % cond
  1683. else:
  1684. return cond
  1685. def build_function_modifiers(self, modifiers, mapper=modifier_output_mapper):
  1686. if not modifiers:
  1687. return ''
  1688. return '%s ' % ' '.join([mapper(m,m) for m in modifiers])
  1689. # Python objects and reference counting
  1690. def entry_as_pyobject(self, entry):
  1691. type = entry.type
  1692. if (not entry.is_self_arg and not entry.type.is_complete()
  1693. or entry.type.is_extension_type):
  1694. return "(PyObject *)" + entry.cname
  1695. else:
  1696. return entry.cname
  1697. def as_pyobject(self, cname, type):
  1698. from .PyrexTypes import py_object_type, typecast
  1699. return typecast(py_object_type, type, cname)
  1700. def put_gotref(self, cname):
  1701. self.putln("__Pyx_GOTREF(%s);" % cname)
  1702. def put_giveref(self, cname):
  1703. self.putln("__Pyx_GIVEREF(%s);" % cname)
  1704. def put_xgiveref(self, cname):
  1705. self.putln("__Pyx_XGIVEREF(%s);" % cname)
  1706. def put_xgotref(self, cname):
  1707. self.putln("__Pyx_XGOTREF(%s);" % cname)
  1708. def put_incref(self, cname, type, nanny=True):
  1709. if nanny:
  1710. self.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname, type))
  1711. else:
  1712. self.putln("Py_INCREF(%s);" % self.as_pyobject(cname, type))
  1713. def put_decref(self, cname, type, nanny=True):
  1714. self._put_decref(cname, type, nanny, null_check=False, clear=False)
  1715. def put_var_gotref(self, entry):
  1716. if entry.type.is_pyobject:
  1717. self.putln("__Pyx_GOTREF(%s);" % self.entry_as_pyobject(entry))
  1718. def put_var_giveref(self, entry):
  1719. if entry.type.is_pyobject:
  1720. self.putln("__Pyx_GIVEREF(%s);" % self.entry_as_pyobject(entry))
  1721. def put_var_xgotref(self, entry):
  1722. if entry.type.is_pyobject:
  1723. self.putln("__Pyx_XGOTREF(%s);" % self.entry_as_pyobject(entry))
  1724. def put_var_xgiveref(self, entry):
  1725. if entry.type.is_pyobject:
  1726. self.putln("__Pyx_XGIVEREF(%s);" % self.entry_as_pyobject(entry))
  1727. def put_var_incref(self, entry, nanny=True):
  1728. if entry.type.is_pyobject:
  1729. if nanny:
  1730. self.putln("__Pyx_INCREF(%s);" % self.entry_as_pyobject(entry))
  1731. else:
  1732. self.putln("Py_INCREF(%s);" % self.entry_as_pyobject(entry))
  1733. def put_var_xincref(self, entry):
  1734. if entry.type.is_pyobject:
  1735. self.putln("__Pyx_XINCREF(%s);" % self.entry_as_pyobject(entry))
  1736. def put_decref_clear(self, cname, type, nanny=True, clear_before_decref=False):
  1737. self._put_decref(cname, type, nanny, null_check=False,
  1738. clear=True, clear_before_decref=clear_before_decref)
  1739. def put_xdecref(self, cname, type, nanny=True, have_gil=True):
  1740. self._put_decref(cname, type, nanny, null_check=True,
  1741. have_gil=have_gil, clear=False)
  1742. def put_xdecref_clear(self, cname, type, nanny=True, clear_before_decref=False):
  1743. self._put_decref(cname, type, nanny, null_check=True,
  1744. clear=True, clear_before_decref=clear_before_decref)
  1745. def _put_decref(self, cname, type, nanny=True, null_check=False,
  1746. have_gil=True, clear=False, clear_before_decref=False):
  1747. if type.is_memoryviewslice:
  1748. self.put_xdecref_memoryviewslice(cname, have_gil=have_gil)
  1749. return
  1750. prefix = '__Pyx' if nanny else 'Py'
  1751. X = 'X' if null_check else ''
  1752. if clear:
  1753. if clear_before_decref:
  1754. if not nanny:
  1755. X = '' # CPython doesn't have a Py_XCLEAR()
  1756. self.putln("%s_%sCLEAR(%s);" % (prefix, X, cname))
  1757. else:
  1758. self.putln("%s_%sDECREF(%s); %s = 0;" % (
  1759. prefix, X, self.as_pyobject(cname, type), cname))
  1760. else:
  1761. self.putln("%s_%sDECREF(%s);" % (
  1762. prefix, X, self.as_pyobject(cname, type)))
  1763. def put_decref_set(self, cname, rhs_cname):
  1764. self.putln("__Pyx_DECREF_SET(%s, %s);" % (cname, rhs_cname))
  1765. def put_xdecref_set(self, cname, rhs_cname):
  1766. self.putln("__Pyx_XDECREF_SET(%s, %s);" % (cname, rhs_cname))
  1767. def put_var_decref(self, entry):
  1768. if entry.type.is_pyobject:
  1769. self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
  1770. def put_var_xdecref(self, entry, nanny=True):
  1771. if entry.type.is_pyobject:
  1772. if nanny:
  1773. self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
  1774. else:
  1775. self.putln("Py_XDECREF(%s);" % self.entry_as_pyobject(entry))
  1776. def put_var_decref_clear(self, entry):
  1777. self._put_var_decref_clear(entry, null_check=False)
  1778. def put_var_xdecref_clear(self, entry):
  1779. self._put_var_decref_clear(entry, null_check=True)
  1780. def _put_var_decref_clear(self, entry, null_check):
  1781. if entry.type.is_pyobject:
  1782. if entry.in_closure:
  1783. # reset before DECREF to make sure closure state is
  1784. # consistent during call to DECREF()
  1785. self.putln("__Pyx_%sCLEAR(%s);" % (
  1786. null_check and 'X' or '',
  1787. entry.cname))
  1788. else:
  1789. self.putln("__Pyx_%sDECREF(%s); %s = 0;" % (
  1790. null_check and 'X' or '',
  1791. self.entry_as_pyobject(entry),
  1792. entry.cname))
  1793. def put_var_decrefs(self, entries, used_only = 0):
  1794. for entry in entries:
  1795. if not used_only or entry.used:
  1796. if entry.xdecref_cleanup:
  1797. self.put_var_xdecref(entry)
  1798. else:
  1799. self.put_var_decref(entry)
  1800. def put_var_xdecrefs(self, entries):
  1801. for entry in entries:
  1802. self.put_var_xdecref(entry)
  1803. def put_var_xdecrefs_clear(self, entries):
  1804. for entry in entries:
  1805. self.put_var_xdecref_clear(entry)
  1806. def put_incref_memoryviewslice(self, slice_cname, have_gil=False):
  1807. from . import MemoryView
  1808. self.globalstate.use_utility_code(MemoryView.memviewslice_init_code)
  1809. self.putln("__PYX_INC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil)))
  1810. def put_xdecref_memoryviewslice(self, slice_cname, have_gil=False):
  1811. from . import MemoryView
  1812. self.globalstate.use_utility_code(MemoryView.memviewslice_init_code)
  1813. self.putln("__PYX_XDEC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil)))
  1814. def put_xgiveref_memoryviewslice(self, slice_cname):
  1815. self.put_xgiveref("%s.memview" % slice_cname)
  1816. def put_init_to_py_none(self, cname, type, nanny=True):
  1817. from .PyrexTypes import py_object_type, typecast
  1818. py_none = typecast(type, py_object_type, "Py_None")
  1819. if nanny:
  1820. self.putln("%s = %s; __Pyx_INCREF(Py_None);" % (cname, py_none))
  1821. else:
  1822. self.putln("%s = %s; Py_INCREF(Py_None);" % (cname, py_none))
  1823. def put_init_var_to_py_none(self, entry, template = "%s", nanny=True):
  1824. code = template % entry.cname
  1825. #if entry.type.is_extension_type:
  1826. # code = "((PyObject*)%s)" % code
  1827. self.put_init_to_py_none(code, entry.type, nanny)
  1828. if entry.in_closure:
  1829. self.put_giveref('Py_None')
  1830. def put_pymethoddef(self, entry, term, allow_skip=True):
  1831. if entry.is_special or entry.name == '__getattribute__':
  1832. if entry.name not in special_py_methods:
  1833. if entry.name == '__getattr__' and not self.globalstate.directives['fast_getattr']:
  1834. pass
  1835. # Python's typeobject.c will automatically fill in our slot
  1836. # in add_operators() (called by PyType_Ready) with a value
  1837. # that's better than ours.
  1838. elif allow_skip:
  1839. return
  1840. from .TypeSlots import method_coexist
  1841. if entry.doc:
  1842. doc_code = entry.doc_cname
  1843. else:
  1844. doc_code = 0
  1845. method_flags = entry.signature.method_flags()
  1846. if method_flags:
  1847. if entry.is_special:
  1848. method_flags += [method_coexist]
  1849. self.putln(
  1850. '{"%s", (PyCFunction)%s, %s, %s}%s' % (
  1851. entry.name,
  1852. entry.func_cname,
  1853. "|".join(method_flags),
  1854. doc_code,
  1855. term))
  1856. # GIL methods
  1857. def put_ensure_gil(self, declare_gilstate=True, variable=None):
  1858. """
  1859. Acquire the GIL. The generated code is safe even when no PyThreadState
  1860. has been allocated for this thread (for threads not initialized by
  1861. using the Python API). Additionally, the code generated by this method
  1862. may be called recursively.
  1863. """
  1864. self.globalstate.use_utility_code(
  1865. UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
  1866. if self.globalstate.directives['fast_gil']:
  1867. self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
  1868. else:
  1869. self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
  1870. self.putln("#ifdef WITH_THREAD")
  1871. if not variable:
  1872. variable = '__pyx_gilstate_save'
  1873. if declare_gilstate:
  1874. self.put("PyGILState_STATE ")
  1875. self.putln("%s = __Pyx_PyGILState_Ensure();" % variable)
  1876. self.putln("#endif")
  1877. def put_release_ensured_gil(self, variable=None):
  1878. """
  1879. Releases the GIL, corresponds to `put_ensure_gil`.
  1880. """
  1881. if self.globalstate.directives['fast_gil']:
  1882. self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
  1883. else:
  1884. self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
  1885. if not variable:
  1886. variable = '__pyx_gilstate_save'
  1887. self.putln("#ifdef WITH_THREAD")
  1888. self.putln("__Pyx_PyGILState_Release(%s);" % variable)
  1889. self.putln("#endif")
  1890. def put_acquire_gil(self, variable=None):
  1891. """
  1892. Acquire the GIL. The thread's thread state must have been initialized
  1893. by a previous `put_release_gil`
  1894. """
  1895. if self.globalstate.directives['fast_gil']:
  1896. self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
  1897. else:
  1898. self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
  1899. self.putln("#ifdef WITH_THREAD")
  1900. self.putln("__Pyx_FastGIL_Forget();")
  1901. if variable:
  1902. self.putln('_save = %s;' % variable)
  1903. self.putln("Py_BLOCK_THREADS")
  1904. self.putln("#endif")
  1905. def put_release_gil(self, variable=None):
  1906. "Release the GIL, corresponds to `put_acquire_gil`."
  1907. if self.globalstate.directives['fast_gil']:
  1908. self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
  1909. else:
  1910. self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
  1911. self.putln("#ifdef WITH_THREAD")
  1912. self.putln("PyThreadState *_save;")
  1913. self.putln("Py_UNBLOCK_THREADS")
  1914. if variable:
  1915. self.putln('%s = _save;' % variable)
  1916. self.putln("__Pyx_FastGIL_Remember();")
  1917. self.putln("#endif")
  1918. def declare_gilstate(self):
  1919. self.putln("#ifdef WITH_THREAD")
  1920. self.putln("PyGILState_STATE __pyx_gilstate_save;")
  1921. self.putln("#endif")
  1922. # error handling
  1923. def put_error_if_neg(self, pos, value):
  1924. # return self.putln("if (unlikely(%s < 0)) %s" % (value, self.error_goto(pos))) # TODO this path is almost _never_ taken, yet this macro makes is slower!
  1925. return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos)))
  1926. def put_error_if_unbound(self, pos, entry, in_nogil_context=False):
  1927. from . import ExprNodes
  1928. if entry.from_closure:
  1929. func = '__Pyx_RaiseClosureNameError'
  1930. self.globalstate.use_utility_code(
  1931. ExprNodes.raise_closure_name_error_utility_code)
  1932. elif entry.type.is_memoryviewslice and in_nogil_context:
  1933. func = '__Pyx_RaiseUnboundMemoryviewSliceNogil'
  1934. self.globalstate.use_utility_code(
  1935. ExprNodes.raise_unbound_memoryview_utility_code_nogil)
  1936. else:
  1937. func = '__Pyx_RaiseUnboundLocalError'
  1938. self.globalstate.use_utility_code(
  1939. ExprNodes.raise_unbound_local_error_utility_code)
  1940. self.putln('if (unlikely(!%s)) { %s("%s"); %s }' % (
  1941. entry.type.check_for_null_code(entry.cname),
  1942. func,
  1943. entry.name,
  1944. self.error_goto(pos)))
  1945. def set_error_info(self, pos, used=False):
  1946. self.funcstate.should_declare_error_indicator = True
  1947. if used:
  1948. self.funcstate.uses_error_indicator = True
  1949. if self.code_config.c_line_in_traceback:
  1950. cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro)
  1951. else:
  1952. cinfo = ""
  1953. return "%s = %s[%s]; %s = %s;%s" % (
  1954. Naming.filename_cname,
  1955. Naming.filetable_cname,
  1956. self.lookup_filename(pos[0]),
  1957. Naming.lineno_cname,
  1958. pos[1],
  1959. cinfo)
  1960. def error_goto(self, pos):
  1961. lbl = self.funcstate.error_label
  1962. self.funcstate.use_label(lbl)
  1963. return "__PYX_ERR(%s, %s, %s)" % (
  1964. self.lookup_filename(pos[0]),
  1965. pos[1],
  1966. lbl)
  1967. def error_goto_if(self, cond, pos):
  1968. return "if (%s) %s" % (self.unlikely(cond), self.error_goto(pos))
  1969. def error_goto_if_null(self, cname, pos):
  1970. return self.error_goto_if("!%s" % cname, pos)
  1971. def error_goto_if_neg(self, cname, pos):
  1972. return self.error_goto_if("%s < 0" % cname, pos)
  1973. def error_goto_if_PyErr(self, pos):
  1974. return self.error_goto_if("PyErr_Occurred()", pos)
  1975. def lookup_filename(self, filename):
  1976. return self.globalstate.lookup_filename(filename)
  1977. def put_declare_refcount_context(self):
  1978. self.putln('__Pyx_RefNannyDeclarations')
  1979. def put_setup_refcount_context(self, name, acquire_gil=False):
  1980. if acquire_gil:
  1981. self.globalstate.use_utility_code(
  1982. UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
  1983. self.putln('__Pyx_RefNannySetupContext("%s", %d);' % (name, acquire_gil and 1 or 0))
  1984. def put_finish_refcount_context(self):
  1985. self.putln("__Pyx_RefNannyFinishContext();")
  1986. def put_add_traceback(self, qualified_name, include_cline=True):
  1987. """
  1988. Build a Python traceback for propagating exceptions.
  1989. qualified_name should be the qualified name of the function.
  1990. """
  1991. format_tuple = (
  1992. qualified_name,
  1993. Naming.clineno_cname if include_cline else 0,
  1994. Naming.lineno_cname,
  1995. Naming.filename_cname,
  1996. )
  1997. self.funcstate.uses_error_indicator = True
  1998. self.putln('__Pyx_AddTraceback("%s", %s, %s, %s);' % format_tuple)
  1999. def put_unraisable(self, qualified_name, nogil=False):
  2000. """
  2001. Generate code to print a Python warning for an unraisable exception.
  2002. qualified_name should be the qualified name of the function.
  2003. """
  2004. format_tuple = (
  2005. qualified_name,
  2006. Naming.clineno_cname,
  2007. Naming.lineno_cname,
  2008. Naming.filename_cname,
  2009. self.globalstate.directives['unraisable_tracebacks'],
  2010. nogil,
  2011. )
  2012. self.funcstate.uses_error_indicator = True
  2013. self.putln('__Pyx_WriteUnraisable("%s", %s, %s, %s, %d, %d);' % format_tuple)
  2014. self.globalstate.use_utility_code(
  2015. UtilityCode.load_cached("WriteUnraisableException", "Exceptions.c"))
  2016. def put_trace_declarations(self):
  2017. self.putln('__Pyx_TraceDeclarations')
  2018. def put_trace_frame_init(self, codeobj=None):
  2019. if codeobj:
  2020. self.putln('__Pyx_TraceFrameInit(%s)' % codeobj)
  2021. def put_trace_call(self, name, pos, nogil=False):
  2022. self.putln('__Pyx_TraceCall("%s", %s[%s], %s, %d, %s);' % (
  2023. name, Naming.filetable_cname, self.lookup_filename(pos[0]), pos[1], nogil, self.error_goto(pos)))
  2024. def put_trace_exception(self):
  2025. self.putln("__Pyx_TraceException();")
  2026. def put_trace_return(self, retvalue_cname, nogil=False):
  2027. self.putln("__Pyx_TraceReturn(%s, %d);" % (retvalue_cname, nogil))
  2028. def putln_openmp(self, string):
  2029. self.putln("#ifdef _OPENMP")
  2030. self.putln(string)
  2031. self.putln("#endif /* _OPENMP */")
  2032. def undef_builtin_expect(self, cond):
  2033. """
  2034. Redefine the macros likely() and unlikely to no-ops, depending on
  2035. condition 'cond'
  2036. """
  2037. self.putln("#if %s" % cond)
  2038. self.putln(" #undef likely")
  2039. self.putln(" #undef unlikely")
  2040. self.putln(" #define likely(x) (x)")
  2041. self.putln(" #define unlikely(x) (x)")
  2042. self.putln("#endif")
  2043. def redef_builtin_expect(self, cond):
  2044. self.putln("#if %s" % cond)
  2045. self.putln(" #undef likely")
  2046. self.putln(" #undef unlikely")
  2047. self.putln(" #define likely(x) __builtin_expect(!!(x), 1)")
  2048. self.putln(" #define unlikely(x) __builtin_expect(!!(x), 0)")
  2049. self.putln("#endif")
  2050. class PyrexCodeWriter(object):
  2051. # f file output file
  2052. # level int indentation level
  2053. def __init__(self, outfile_name):
  2054. self.f = Utils.open_new_file(outfile_name)
  2055. self.level = 0
  2056. def putln(self, code):
  2057. self.f.write("%s%s\n" % (" " * self.level, code))
  2058. def indent(self):
  2059. self.level += 1
  2060. def dedent(self):
  2061. self.level -= 1
  2062. class PyxCodeWriter(object):
  2063. """
  2064. Can be used for writing out some Cython code. To use the indenter
  2065. functionality, the Cython.Compiler.Importer module will have to be used
  2066. to load the code to support python 2.4
  2067. """
  2068. def __init__(self, buffer=None, indent_level=0, context=None, encoding='ascii'):
  2069. self.buffer = buffer or StringIOTree()
  2070. self.level = indent_level
  2071. self.context = context
  2072. self.encoding = encoding
  2073. def indent(self, levels=1):
  2074. self.level += levels
  2075. return True
  2076. def dedent(self, levels=1):
  2077. self.level -= levels
  2078. def indenter(self, line):
  2079. """
  2080. Instead of
  2081. with pyx_code.indenter("for i in range(10):"):
  2082. pyx_code.putln("print i")
  2083. write
  2084. if pyx_code.indenter("for i in range(10);"):
  2085. pyx_code.putln("print i")
  2086. pyx_code.dedent()
  2087. """
  2088. self.putln(line)
  2089. self.indent()
  2090. return True
  2091. def getvalue(self):
  2092. result = self.buffer.getvalue()
  2093. if isinstance(result, bytes):
  2094. result = result.decode(self.encoding)
  2095. return result
  2096. def putln(self, line, context=None):
  2097. context = context or self.context
  2098. if context:
  2099. line = sub_tempita(line, context)
  2100. self._putln(line)
  2101. def _putln(self, line):
  2102. self.buffer.write("%s%s\n" % (self.level * " ", line))
  2103. def put_chunk(self, chunk, context=None):
  2104. context = context or self.context
  2105. if context:
  2106. chunk = sub_tempita(chunk, context)
  2107. chunk = textwrap.dedent(chunk)
  2108. for line in chunk.splitlines():
  2109. self._putln(line)
  2110. def insertion_point(self):
  2111. return PyxCodeWriter(self.buffer.insertion_point(), self.level,
  2112. self.context)
  2113. def named_insertion_point(self, name):
  2114. setattr(self, name, self.insertion_point())
  2115. class ClosureTempAllocator(object):
  2116. def __init__(self, klass):
  2117. self.klass = klass
  2118. self.temps_allocated = {}
  2119. self.temps_free = {}
  2120. self.temps_count = 0
  2121. def reset(self):
  2122. for type, cnames in self.temps_allocated.items():
  2123. self.temps_free[type] = list(cnames)
  2124. def allocate_temp(self, type):
  2125. if type not in self.temps_allocated:
  2126. self.temps_allocated[type] = []
  2127. self.temps_free[type] = []
  2128. elif self.temps_free[type]:
  2129. return self.temps_free[type].pop(0)
  2130. cname = '%s%d' % (Naming.codewriter_temp_prefix, self.temps_count)
  2131. self.klass.declare_var(pos=None, name=cname, cname=cname, type=type, is_cdef=True)
  2132. self.temps_allocated[type].append(cname)
  2133. self.temps_count += 1
  2134. return cname