mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	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
		
			
				
	
	
		
			124 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			124 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
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()
 |