translator: Add Python 3 support (see issue #2856)

This also fixes incorrect translation of types in capi header comments.
This commit is contained in:
Marshall Greenblatt 2020-01-09 22:22:11 +02:00
parent dbc479e490
commit 1b85022c58
17 changed files with 97 additions and 72 deletions

View File

@ -2,6 +2,8 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from __future__ import print_function
from file_util import *
import os
import re
@ -63,7 +65,7 @@ class cef_api_hash:
objects = []
for filename in filenames:
if self.__verbose:
print "Processing " + filename + "..."
print("Processing " + filename + "...")
content = read_file(os.path.join(self.__headerdir, filename), True)
platforms = list([
p for p in self.platforms if self.__is_platform_filename(filename, p)
@ -101,8 +103,7 @@ class cef_api_hash:
sig = self.__get_final_sig(objects, platform)
if self.__debug_enabled:
self.__write_debug_file(platform + ".sig", sig)
rev = hashlib.sha1(sig).digest()
revstr = ''.join(format(ord(i), '0>2x') for i in rev)
revstr = hashlib.sha1(sig.encode('utf-8')).hexdigest()
revisions[platform] = revstr
return revisions
@ -256,10 +257,10 @@ if __name__ == "__main__":
c_completed_in = time.time() - c_start_time
print "{"
print("{")
for k in sorted(revisions.keys()):
print format("\"" + k + "\"", ">12s") + ": \"" + revisions[k] + "\""
print "}"
print(format("\"" + k + "\"", ">12s") + ": \"" + revisions[k] + "\"")
print("}")
# print
# print 'Completed in: ' + str(c_completed_in)
# print

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from date_util import *
from file_util import *
import os
@ -49,10 +50,10 @@ def get_capi_name(cppname, isclassname, prefix=None):
# add an underscore if the current character is an upper case letter
# and the last character was a lower case letter
if len(result) > 0 and not chr.isdigit() \
and string.upper(chr) == chr \
and not string.upper(lastchr) == lastchr:
and chr.upper() == chr \
and not lastchr.upper() == lastchr:
result += '_'
result += string.lower(chr)
result += chr.lower()
lastchr = chr
if isclassname:
@ -81,7 +82,7 @@ def get_prev_line(body, pos):
""" Retrieve the start and end positions and value for the line immediately
before the line containing the specified position.
"""
end = string.rfind(body, '\n', 0, pos)
end = body.rfind('\n', 0, pos)
start = body.rfind('\n', 0, end) + 1
line = body[start:end]
return {'start': start, 'end': end, 'line': line}
@ -95,12 +96,12 @@ def get_comment(body, name):
in_block_comment = False
while pos > 0:
data = get_prev_line(body, pos)
line = string.strip(data['line'])
line = data['line'].strip()
pos = data['start']
if len(line) == 0:
# check if the next previous line is a comment
prevdata = get_prev_line(body, pos)
prevline = string.strip(prevdata['line'])
prevline = prevdata['line'].strip()
if prevline[0:2] == '//' and prevline[0:3] != '///':
result.append(None)
else:
@ -146,6 +147,11 @@ def validate_comment(file, name, comment):
def format_comment(comment, indent, translate_map=None, maxchars=80):
""" Return the comments array as a formatted string. """
if not translate_map is None:
# Replace longest keys first in translation.
translate_keys = sorted(
translate_map.keys(), key=lambda item: (-len(item), item))
result = ''
wrapme = ''
hasemptyline = False
@ -163,7 +169,7 @@ def format_comment(comment, indent, translate_map=None, maxchars=80):
if len(wrapme) > 0:
if not translate_map is None:
# apply the translation
for key in translate_map.keys():
for key in translate_keys:
wrapme = wrapme.replace(key, translate_map[key])
# output the previous paragraph
result += wrap_text(wrapme, indent + '// ', maxchars)
@ -299,17 +305,17 @@ def str_to_dict(str):
""" Convert a string to a dictionary. If the same key has multiple values
the values will be stored in a list. """
dict = {}
parts = string.split(str, ',')
parts = str.split(',')
for part in parts:
part = string.strip(part)
part = part.strip()
if len(part) == 0:
continue
sparts = string.split(part, '=')
sparts = part.split('=')
if len(sparts) > 2:
raise Exception('Invalid dictionary pair format: ' + part)
name = string.strip(sparts[0])
name = sparts[0].strip()
if len(sparts) == 2:
val = string.strip(sparts[1])
val = sparts[1].strip()
else:
val = True
if name in dict:
@ -339,7 +345,7 @@ def dict_to_str(dict):
# currently a list value
for val in dict[name]:
str.append(name + '=' + val)
return string.join(str, ',')
return ','.join(str)
# regex for matching comment-formatted attributes
@ -656,19 +662,19 @@ class obj_header:
strlist = []
for cls in self.typedefs:
strlist.append(str(cls))
result += string.join(strlist, "\n") + "\n\n"
result += "\n".join(strlist) + "\n\n"
if len(self.funcs) > 0:
strlist = []
for cls in self.funcs:
strlist.append(str(cls))
result += string.join(strlist, "\n") + "\n\n"
result += "\n".join(strlist) + "\n\n"
if len(self.classes) > 0:
strlist = []
for cls in self.classes:
strlist.append(str(cls))
result += string.join(strlist, "\n")
result += "\n".join(strlist)
return result
@ -868,21 +874,21 @@ class obj_class:
strlist = []
for cls in self.typedefs:
strlist.append(str(cls))
result += string.join(strlist, "\n\t")
result += "\n\t".join(strlist)
if len(self.staticfuncs) > 0:
result += "\n\t"
strlist = []
for cls in self.staticfuncs:
strlist.append(str(cls))
result += string.join(strlist, "\n\t")
result += "\n\t".join(strlist)
if len(self.virtualfuncs) > 0:
result += "\n\t"
strlist = []
for cls in self.virtualfuncs:
strlist.append(str(cls))
result += string.join(strlist, "\n\t")
result += "\n\t".join(strlist)
result += "\n};\n"
return result
@ -1090,7 +1096,7 @@ class obj_function:
# build the argument objects
self.arguments = []
arglist = string.split(argval, ',')
arglist = argval.split(',')
argindex = 0
while argindex < len(arglist):
arg = arglist[argindex]
@ -1100,7 +1106,7 @@ class obj_function:
argindex += 1
arg += ',' + arglist[argindex]
arg = string.strip(arg)
arg = arg.strip()
if len(arg) > 0:
argument = obj_argument(self, arg)
if argument.needs_attrib_count_func() and \
@ -1235,7 +1241,7 @@ class obj_function:
""" Return the prototype of the C API function. """
parts = self.get_capi_parts(defined_structs, prefix)
result = parts['retval']+' '+parts['name']+ \
'('+string.join(parts['args'], ', ')+')'
'('+', '.join(parts['args'])+')'
return result
def get_cpp_parts(self, isimpl=False):
@ -1264,7 +1270,7 @@ class obj_function:
result = parts['retval'] + ' '
if not classname is None:
result += classname + '::'
result += parts['name'] + '(' + string.join(parts['args'], ', ') + ')'
result += parts['name'] + '(' + ', '.join(parts['args']) + ')'
if isinstance(self, obj_function_virtual) and self.is_const():
result += ' const'
return result
@ -1395,12 +1401,12 @@ class obj_argument:
name = self.type.get_name()
vals = self.parent.get_attrib_list('count_func')
for val in vals:
parts = string.split(val, ':')
parts = val.split(':')
if len(parts) != 2:
raise Exception("Invalid 'count_func' attribute value for "+ \
self.parent.get_qualified_name()+': '+val)
if string.strip(parts[0]) == name:
return string.strip(parts[1])
if parts[0].strip() == name:
return parts[1].strip()
return None
def needs_attrib_default_retval(self):
@ -1601,7 +1607,7 @@ class obj_analysis:
self.ptr_type = None
# parse the argument string
partlist = string.split(string.strip(value))
partlist = value.strip().split()
if named == True:
# extract the name value
@ -1624,7 +1630,7 @@ class obj_analysis:
raise Exception('Invalid argument value: ' + value)
# combine the data type
self.type = string.join(partlist, ' ')
self.type = ' '.join(partlist)
# extract the last character of the data type
endchar = self.type[-1]
@ -1668,7 +1674,7 @@ class obj_analysis:
# check for vectors
if value.find('std::vector') == 0:
self.result_type = 'vector'
val = string.strip(value[12:-1])
val = value[12:-1].strip()
self.result_value = [self._get_basic(val)]
self.result_value[0]['vector_type'] = val
return True
@ -1676,22 +1682,22 @@ class obj_analysis:
# check for maps
if value.find('std::map') == 0:
self.result_type = 'map'
vals = string.split(value[9:-1], ',')
vals = value[9:-1].split(',')
if len(vals) == 2:
self.result_value = [
self._get_basic(string.strip(vals[0])),
self._get_basic(string.strip(vals[1]))
self._get_basic(vals[0].strip()),
self._get_basic(vals[1].strip())
]
return True
# check for multimaps
if value.find('std::multimap') == 0:
self.result_type = 'multimap'
vals = string.split(value[14:-1], ',')
vals = value[14:-1].split(',')
if len(vals) == 2:
self.result_value = [
self._get_basic(string.strip(vals[0])),
self._get_basic(string.strip(vals[1]))
self._get_basic(vals[0].strip()),
self._get_basic(vals[1].strip())
]
return True

View File

@ -2,6 +2,8 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file
from __future__ import absolute_import
from __future__ import print_function
from exec_util import exec_cmd
import os
import sys
@ -21,9 +23,9 @@ def clang_format(file_name, file_contents):
# -assume-filename is necessary to find the .clang-format file and determine
# the language when specifying contents via stdin.
result = exec_cmd("%s -assume-filename=%s" % (clang_format_exe, file_name), \
root_dir, file_contents)
root_dir, file_contents.encode('utf-8'))
if result['err'] != '':
print "clang-format error: %s" % result['err']
print("clang-format error: %s" % result['err'])
if result['out'] != '':
output = result['out']
if sys.platform == 'win32':

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
import datetime

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from cef_api_hash import cef_api_hash
from cef_parser import *
from file_util import *
@ -53,7 +54,7 @@ CEF_EXPORT const char* cef_api_hash(int entry);
"""
# Substitute hash values for placeholders.
for platform, value in api_hash.iteritems():
for platform, value in api_hash.items():
result = result.replace('$%s$' % platform.upper(), value)
return result
@ -70,7 +71,7 @@ if __name__ == "__main__":
# Verify that the correct number of command-line arguments are provided.
if len(sys.argv) < 2:
sys.stderr.write('Usage: ' + sys.argv[0] + ' <cppheaderdir>')
sys.stderr.write('Usage: ' + sys.argv[0] + ' <cppheaderdir>\n')
sys.exit()
# Dump the result to stdout.

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from cef_parser import *
from date_util import *
@ -32,7 +33,7 @@ def make_capi_member_funcs(funcs, defined_names, translate_map, indent):
result += indent + '// The resulting string must be freed by calling cef_string_userfree_free().\n'
parts = func.get_capi_parts()
result += indent+parts['retval']+' (CEF_CALLBACK *'+parts['name']+ \
')('+string.join(parts['args'], ', ')+');\n'
')('+', '.join(parts['args'])+');\n'
if first:
first = False
return result
@ -195,8 +196,8 @@ extern "C" {
# add the copyright year
result = result.replace('$YEAR$', get_year())
# add the guard string
guard = 'CEF_INCLUDE_CAPI_' + string.upper(
filename.replace('/', '_').replace('.', '_capi_')) + '_'
guard = 'CEF_INCLUDE_CAPI_' + \
filename.replace('/', '_').replace('.', '_capi_').upper() + '_'
result = result.replace('$GUARD$', guard)
return result
@ -214,7 +215,7 @@ if __name__ == "__main__":
# verify that the correct number of command-line arguments are provided
if len(sys.argv) < 2:
sys.stderr.write('Usage: ' + sys.argv[0] + ' <infile>')
sys.stderr.write('Usage: ' + sys.argv[0] + ' <infile>\n')
sys.exit()
# create the header object

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from date_util import *
from file_util import *
from optparse import OptionParser
@ -54,6 +55,7 @@ def check_x11_build(gn_config):
return True
def write_config_header(header, cef_gn_config):
""" Creates the header file for the cef build configuration
if the information has changed or if the file doesn't already exist. """
@ -113,6 +115,7 @@ def write_config_header(header, cef_gn_config):
return True
return False
written = write_config_header(options.header, options.cef_gn_config)
if not options.quiet:
if written:

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from cef_parser import *

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from cef_parser import *
@ -11,7 +12,7 @@ def make_cpptoc_impl_proto(name, func, parts):
else:
proto = 'CEF_EXPORT ' + parts['retval']
proto += ' ' + name + '(' + string.join(parts['args'], ', ') + ')'
proto += ' ' + name + '(' + ', '.join(parts['args']) + ')'
return proto
@ -69,7 +70,7 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
# code could not be auto-generated
result += '\n // BEGIN DELETE BEFORE MODIFYING'
result += '\n // AUTO-GENERATED CONTENT'
result += '\n // COULD NOT IMPLEMENT DUE TO: ' + string.join(invalid, ', ')
result += '\n // COULD NOT IMPLEMENT DUE TO: ' + ', '.join(invalid)
result += '\n #pragma message("Warning: "__FILE__": ' + name + ' is not implemented")'
result += '\n // END DELETE BEFORE MODIFYING'
result += '\n}\n\n'
@ -336,7 +337,7 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
result += func.get_name() + '('
if len(params) > 0:
result += '\n ' + string.join(params, ',\n ')
result += '\n ' + ',\n '.join(params)
result += ');\n'
@ -735,9 +736,10 @@ if __name__ == "__main__":
# read the existing implementation file into memory
try:
f = open(sys.argv[3], 'r')
data = f.read()
except IOError, (errno, strerror):
with open(sys.argv[3], 'r') as f:
data = f.read()
except IOError as e:
(errno, strerror) = e.args
raise Exception('Failed to read file ' + sys.argv[3] + ': ' + strerror)
else:
f.close()

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from cef_parser import *

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from cef_parser import *
@ -20,7 +21,7 @@ def make_ctocpp_impl_proto(clsname, name, func, parts):
proto += '::'
proto += name + '(' + string.join(parts['args'], ', ') + ')' + const
proto += name + '(' + ', '.join(parts['args']) + ')' + const
return proto
@ -102,7 +103,7 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
# code could not be auto-generated
result += '\n // BEGIN DELETE BEFORE MODIFYING'
result += '\n // AUTO-GENERATED CONTENT'
result += '\n // COULD NOT IMPLEMENT DUE TO: ' + string.join(invalid, ', ')
result += '\n // COULD NOT IMPLEMENT DUE TO: ' + ', '.join(invalid)
result += '\n #pragma message("Warning: "__FILE__": ' + name + ' is not implemented")'
result += '\n // END DELETE BEFORE MODIFYING'
result += '\n}\n\n'
@ -354,7 +355,7 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
if len(params) > 0:
if not isinstance(func, obj_function_virtual):
result += '\n '
result += string.join(params, ',\n ')
result += ',\n '.join(params)
result += ');\n'
@ -718,7 +719,7 @@ if __name__ == "__main__":
# verify that the correct number of command-line arguments are provided
if len(sys.argv) < 4:
sys.stderr.write('Usage: ' + sys.argv[0] +
' <infile> <classname> <existing_impl>')
' <infile> <classname> <existing_impl>\n')
sys.exit()
# create the header object
@ -727,12 +728,11 @@ if __name__ == "__main__":
# read the existing implementation file into memory
try:
f = open(sys.argv[3], 'r')
data = f.read()
except IOError, (errno, strerror):
with open(sys.argv[3], 'r') as f:
data = f.read()
except IOError as e:
(errno, strerror) = e.args
raise Exception('Failed to read file ' + sys.argv[3] + ': ' + strerror)
else:
f.close()
# dump the result to stdout
sys.stdout.write(make_ctocpp_class_impl(header, sys.argv[2], data))

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from cef_parser import *
from file_util import *
import os
@ -198,7 +199,7 @@ if __name__ == "__main__":
# Verify that the correct number of command-line arguments are provided.
if len(sys.argv) < 2:
sys.stderr.write('Usage: ' + sys.argv[0] + ' <cpp_header_dir>')
sys.stderr.write('Usage: ' + sys.argv[0] + ' <cpp_header_dir>\n')
sys.exit()
cpp_header_dir = sys.argv[1]

View File

@ -6,6 +6,8 @@
A simple utility function to merge pack resource files into a single resource file.
"""
from __future__ import absolute_import
from __future__ import print_function
from date_util import *
from file_util import *
import os
@ -114,7 +116,7 @@ def MakeFile(output, input):
result = result.replace('$YEAR$', get_year())
# add the guard string
filename = os.path.split(output)[1]
guard = 'CEF_INCLUDE_' + string.upper(filename.replace('.', '_')) + '_'
guard = 'CEF_INCLUDE_' + filename.replace('.', '_').upper() + '_'
result = result.replace('$GUARD$', guard)
if path_exists(output):
@ -131,8 +133,8 @@ def MakeFile(output, input):
def main(argv):
if len(argv) < 3:
print("Usage:\n %s <output_filename> <input_file1> [input_file2] ... " %
argv[0])
print(("Usage:\n %s <output_filename> <input_file1> [input_file2] ... " %
argv[0]))
sys.exit(-1)
MakeFile(argv[1], argv[2:])

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from cef_version import VersionFormatter
from date_util import *
from file_util import *

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from cef_parser import *
from make_ctocpp_impl import *
@ -79,7 +80,7 @@ if __name__ == "__main__":
# Verify that the correct number of command-line arguments are provided.
if len(sys.argv) < 2:
sys.stderr.write('Usage: ' + sys.argv[0] + ' <cpp_header_dir>')
sys.stderr.write('Usage: ' + sys.argv[0] + ' <cpp_header_dir>\n')
sys.exit()
cpp_header_dir = sys.argv[1]

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
from cef_parser import *
@ -37,7 +38,7 @@ if __name__ == "__main__":
# verify that the correct number of command-line arguments are provided
if len(sys.argv) < 2:
sys.stderr.write('Usage: ' + sys.argv[0] + ' <include_dir>')
sys.stderr.write('Usage: ' + sys.argv[0] + ' <include_dir>\n')
sys.exit()
# create the header object

View File

@ -2,6 +2,7 @@
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from __future__ import absolute_import
import sys
from cef_parser import *
from clang_util import clang_format
@ -134,8 +135,7 @@ def update_file(file, newcontents):
oldhash = oldcontents[start + len(hash_start):end]
# Compute the new hash.
rev = hashlib.sha1(newcontents).digest()
newhash = ''.join(format(ord(i), '0>2x') for i in rev)
newhash = hashlib.sha1(newcontents.encode('utf-8')).hexdigest()
if oldhash == newhash:
# Pre-formatted contents have not changed.