summaryrefslogtreecommitdiffstats
path: root/Tools/scripts
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2022-01-27 18:06:09 (GMT)
committerGitHub <noreply@github.com>2022-01-27 18:06:09 (GMT)
commit247480a21cb165efdacc346a2d589dfc27e18283 (patch)
tree1c7b57e6ed3f527000d8440138483f7b299eb4de /Tools/scripts
parent183f8d57fa5959e7578e7f470edc364edb23caca (diff)
downloadcpython-247480a21cb165efdacc346a2d589dfc27e18283.zip
cpython-247480a21cb165efdacc346a2d589dfc27e18283.tar.gz
cpython-247480a21cb165efdacc346a2d589dfc27e18283.tar.bz2
bpo-46541: Generate the global objects initializer. (gh-30941)
This change is a prerequisite for generating code for other global objects (like strings in gh-30928). (We borrowed some code from Tools/scripts/deepfreeze.py.) https://bugs.python.org/issue46541
Diffstat (limited to 'Tools/scripts')
-rw-r--r--Tools/scripts/generate_global_objects.py124
1 files changed, 124 insertions, 0 deletions
diff --git a/Tools/scripts/generate_global_objects.py b/Tools/scripts/generate_global_objects.py
new file mode 100644
index 0000000..a06d201
--- /dev/null
+++ b/Tools/scripts/generate_global_objects.py
@@ -0,0 +1,124 @@
+import argparse
+import ast
+import builtins
+import collections
+import contextlib
+import os.path
+import sys
+
+
+assert os.path.isabs(__file__), __file__
+ROOT = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
+INTERNAL = os.path.join(ROOT, 'Include', 'internal')
+
+
+#######################################
+# helpers
+
+def iter_to_marker(lines, marker):
+ for line in lines:
+ if line.rstrip() == marker:
+ break
+ yield line
+
+
+class Printer:
+
+ def __init__(self, file):
+ self.level = 0
+ self.file = file
+ self.continuation = [False]
+
+ @contextlib.contextmanager
+ def indent(self):
+ save_level = self.level
+ try:
+ self.level += 1
+ yield
+ finally:
+ self.level = save_level
+
+ def write(self, arg):
+ eol = '\n'
+ if self.continuation[-1]:
+ eol = f' \\{eol}' if arg else f'\\{eol}'
+ self.file.writelines((" "*self.level, arg, eol))
+
+ @contextlib.contextmanager
+ def block(self, prefix, suffix="", *, continuation=None):
+ if continuation is None:
+ continuation = self.continuation[-1]
+ self.continuation.append(continuation)
+
+ self.write(prefix + " {")
+ with self.indent():
+ yield
+ self.continuation.pop()
+ self.write("}" + suffix)
+
+
+#######################################
+# the global objects
+
+START = '/* The following is auto-generated by Tools/scripts/generate_global_objects.py. */'
+END = '/* End auto-generated code */'
+
+
+def generate_runtime_init():
+ # First get some info from the declarations.
+ nsmallposints = None
+ nsmallnegints = None
+ with open(os.path.join(INTERNAL, 'pycore_global_objects.h')) as infile:
+ for line in infile:
+ if line.startswith('#define _PY_NSMALLPOSINTS'):
+ nsmallposints = int(line.split()[-1])
+ elif line.startswith('#define _PY_NSMALLNEGINTS'):
+ nsmallnegints = int(line.split()[-1])
+ break
+ else:
+ raise NotImplementedError
+ assert nsmallposints and nsmallnegints
+
+ # Then target the runtime initializer.
+ filename = os.path.join(INTERNAL, 'pycore_runtime_init.h')
+
+ # Read the non-generated part of the file.
+ with open(filename) as infile:
+ before = ''.join(iter_to_marker(infile, START))[:-1]
+ for _ in iter_to_marker(infile, END):
+ pass
+ after = infile.read()[:-1]
+
+ # Generate the file.
+ with open(filename, 'w', encoding='utf-8') as outfile:
+ printer = Printer(outfile)
+ printer.write(before)
+ printer.write(START)
+ with printer.block('#define _Py_global_objects_INIT', continuation=True):
+ with printer.block('.singletons =', ','):
+ # Global int objects.
+ with printer.block('.small_ints =', ','):
+ for i in range(-nsmallnegints, nsmallposints):
+ printer.write(f'_PyLong_DIGIT_INIT({i}),')
+ printer.write('')
+ # Global bytes objects.
+ printer.write('.bytes_empty = _PyBytes_SIMPLE_INIT(0, 0),')
+ with printer.block('.bytes_characters =', ','):
+ for i in range(256):
+ printer.write(f'_PyBytes_CHAR_INIT({i}),')
+ printer.write(END)
+ printer.write(after)
+
+
+#######################################
+# the script
+
+def main() -> None:
+ generate_runtime_init()
+
+
+if __name__ == '__main__':
+ argv = sys.argv[1:]
+ if argv:
+ sys.exit(f'ERROR: got unexpected args {argv}')
+ main()