mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			202 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
| #!/usr/bin/env python3
 | |
| # This script converts a C file to use the PEP 384 type definition API
 | |
| # Usage: abitype.py < old_code > new_code
 | |
| import re, sys
 | |
| 
 | |
| ###### Replacement of PyTypeObject static instances ##############
 | |
| 
 | |
| # classify each token, giving it a one-letter code:
 | |
| # S: static
 | |
| # T: PyTypeObject
 | |
| # I: ident
 | |
| # W: whitespace
 | |
| # =, {, }, ; : themselves
 | |
| def classify():
 | |
|     res = []
 | |
|     for t,v in tokens:
 | |
|         if t == 'other' and v in "={};":
 | |
|             res.append(v)
 | |
|         elif t == 'ident':
 | |
|             if v == 'PyTypeObject':
 | |
|                 res.append('T')
 | |
|             elif v == 'static':
 | |
|                 res.append('S')
 | |
|             else:
 | |
|                 res.append('I')
 | |
|         elif t == 'ws':
 | |
|             res.append('W')
 | |
|         else:
 | |
|             res.append('.')
 | |
|     return ''.join(res)
 | |
| 
 | |
| # Obtain a list of fields of a PyTypeObject, in declaration order,
 | |
| # skipping ob_base
 | |
| # All comments are dropped from the variable (which are typically
 | |
| # just the slot names, anyway), and information is discarded whether
 | |
| # the original type was static.
 | |
| def get_fields(start, real_end):
 | |
|     pos = start
 | |
|     # static?
 | |
|     if tokens[pos][1] == 'static':
 | |
|         pos += 2
 | |
|     # PyTypeObject
 | |
|     pos += 2
 | |
|     # name
 | |
|     name = tokens[pos][1]
 | |
|     pos += 1
 | |
|     while tokens[pos][1] != '{':
 | |
|         pos += 1
 | |
|     pos += 1
 | |
|     # PyVarObject_HEAD_INIT
 | |
|     while tokens[pos][0] in ('ws', 'comment'):
 | |
|         pos += 1
 | |
|     if tokens[pos][1] != 'PyVarObject_HEAD_INIT':
 | |
|         raise Exception('%s has no PyVarObject_HEAD_INIT' % name)
 | |
|     while tokens[pos][1] != ')':
 | |
|         pos += 1
 | |
|     pos += 1
 | |
|     # field definitions: various tokens, comma-separated
 | |
|     fields = []
 | |
|     while True:
 | |
|         while tokens[pos][0] in ('ws', 'comment'):
 | |
|             pos += 1
 | |
|         end = pos
 | |
|         while tokens[end][1] not in ',}':
 | |
|             if tokens[end][1] == '(':
 | |
|                 nesting = 1
 | |
|                 while nesting:
 | |
|                     end += 1
 | |
|                     if tokens[end][1] == '(': nesting+=1
 | |
|                     if tokens[end][1] == ')': nesting-=1
 | |
|             end += 1
 | |
|         assert end < real_end
 | |
|         # join field, excluding separator and trailing ws
 | |
|         end1 = end-1
 | |
|         while tokens[end1][0] in ('ws', 'comment'):
 | |
|             end1 -= 1
 | |
|         fields.append(''.join(t[1] for t in tokens[pos:end1+1]))
 | |
|         if tokens[end][1] == '}':
 | |
|             break
 | |
|         pos = end+1
 | |
|     return name, fields
 | |
| 
 | |
| # List of type slots as of Python 3.2, omitting ob_base
 | |
| typeslots = [
 | |
|     'tp_name',
 | |
|     'tp_basicsize',
 | |
|     'tp_itemsize',
 | |
|     'tp_dealloc',
 | |
|     'tp_print',
 | |
|     'tp_getattr',
 | |
|     'tp_setattr',
 | |
|     'tp_reserved',
 | |
|     'tp_repr',
 | |
|     'tp_as_number',
 | |
|     'tp_as_sequence',
 | |
|     'tp_as_mapping',
 | |
|     'tp_hash',
 | |
|     'tp_call',
 | |
|     'tp_str',
 | |
|     'tp_getattro',
 | |
|     'tp_setattro',
 | |
|     'tp_as_buffer',
 | |
|     'tp_flags',
 | |
|     'tp_doc',
 | |
|     'tp_traverse',
 | |
|     'tp_clear',
 | |
|     'tp_richcompare',
 | |
|     'tp_weaklistoffset',
 | |
|     'tp_iter',
 | |
|     'iternextfunc',
 | |
|     'tp_methods',
 | |
|     'tp_members',
 | |
|     'tp_getset',
 | |
|     'tp_base',
 | |
|     'tp_dict',
 | |
|     'tp_descr_get',
 | |
|     'tp_descr_set',
 | |
|     'tp_dictoffset',
 | |
|     'tp_init',
 | |
|     'tp_alloc',
 | |
|     'tp_new',
 | |
|     'tp_free',
 | |
|     'tp_is_gc',
 | |
|     'tp_bases',
 | |
|     'tp_mro',
 | |
|     'tp_cache',
 | |
|     'tp_subclasses',
 | |
|     'tp_weaklist',
 | |
|     'tp_del',
 | |
|     'tp_version_tag',
 | |
| ]
 | |
| 
 | |
| # Generate a PyType_Spec definition
 | |
| def make_slots(name, fields):
 | |
|     res = []
 | |
|     res.append('static PyType_Slot %s_slots[] = {' % name)
 | |
|     # defaults for spec
 | |
|     spec = { 'tp_itemsize':'0' }
 | |
|     for i, val in enumerate(fields):
 | |
|         if val.endswith('0'):
 | |
|             continue
 | |
|         if typeslots[i] in ('tp_name', 'tp_doc', 'tp_basicsize',
 | |
|                          'tp_itemsize', 'tp_flags'):
 | |
|             spec[typeslots[i]] = val
 | |
|             continue
 | |
|         res.append('    {Py_%s, %s},' % (typeslots[i], val))
 | |
|     res.append('};')
 | |
|     res.append('static PyType_Spec %s_spec = {' % name)
 | |
|     res.append('    %s,' % spec['tp_name'])
 | |
|     res.append('    %s,' % spec['tp_basicsize'])
 | |
|     res.append('    %s,' % spec['tp_itemsize'])
 | |
|     res.append('    %s,' % spec['tp_flags'])
 | |
|     res.append('    %s_slots,' % name)
 | |
|     res.append('};\n')
 | |
|     return '\n'.join(res)
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
| 
 | |
|     ############ Simplistic C scanner ##################################
 | |
|     tokenizer = re.compile(
 | |
|         r"(?P<preproc>#.*\n)"
 | |
|         r"|(?P<comment>/\*.*?\*/)"
 | |
|         r"|(?P<ident>[a-zA-Z_][a-zA-Z0-9_]*)"
 | |
|         r"|(?P<ws>[ \t\n]+)"
 | |
|         r"|(?P<other>.)",
 | |
|         re.MULTILINE)
 | |
| 
 | |
|     tokens = []
 | |
|     source = sys.stdin.read()
 | |
|     pos = 0
 | |
|     while pos != len(source):
 | |
|         m = tokenizer.match(source, pos)
 | |
|         tokens.append([m.lastgroup, m.group()])
 | |
|         pos += len(tokens[-1][1])
 | |
|         if tokens[-1][0] == 'preproc':
 | |
|             # continuation lines are considered
 | |
|             # only in preprocess statements
 | |
|             while tokens[-1][1].endswith('\\\n'):
 | |
|                 nl = source.find('\n', pos)
 | |
|                 if nl == -1:
 | |
|                     line = source[pos:]
 | |
|                 else:
 | |
|                     line = source[pos:nl+1]
 | |
|                 tokens[-1][1] += line
 | |
|                 pos += len(line)
 | |
| 
 | |
|     # Main loop: replace all static PyTypeObjects until
 | |
|     # there are none left.
 | |
|     while 1:
 | |
|         c = classify()
 | |
|         m = re.search('(SW)?TWIW?=W?{.*?};', c)
 | |
|         if not m:
 | |
|             break
 | |
|         start = m.start()
 | |
|         end = m.end()
 | |
|         name, fields = get_fields(start, end)
 | |
|         tokens[start:end] = [('',make_slots(name, fields))]
 | |
| 
 | |
|     # Output result to stdout
 | |
|     for t, v in tokens:
 | |
|         sys.stdout.write(v)
 | 
