web/lib/arch/osx/jcc/cpp.py
changeset 29 cc9b7e14412b
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
       
     1 #   Licensed under the Apache License, Version 2.0 (the "License");
       
     2 #   you may not use this file except in compliance with the License.
       
     3 #   You may obtain a copy of the License at
       
     4 #
       
     5 #       http://www.apache.org/licenses/LICENSE-2.0
       
     6 #
       
     7 #   Unless required by applicable law or agreed to in writing, software
       
     8 #   distributed under the License is distributed on an "AS IS" BASIS,
       
     9 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    10 #   See the License for the specific language governing permissions and
       
    11 #   limitations under the License.
       
    12 
       
    13 import os, sys, zipfile, _jcc
       
    14 
       
    15 python_ver = '%d.%d.%d' %(sys.version_info[0:3])
       
    16 if python_ver < '2.4':
       
    17     from sets import Set as set
       
    18 
       
    19     def split_pkg(string, sep):
       
    20         parts = string.split(sep)
       
    21         if len(parts) > 1:
       
    22             return sep.join(parts[:-1]), parts[-1]
       
    23         return parts
       
    24 
       
    25     def sort(list, fn=None, key=None):
       
    26         if fn:
       
    27             list.sort(fn)
       
    28         elif key:
       
    29             def fn(x, y):
       
    30                 return cmp(key(x), key(y))
       
    31             list.sort(fn)
       
    32         else:
       
    33             list.sort()
       
    34 
       
    35 else:
       
    36     def split_pkg(string, sep):
       
    37         return string.rsplit(sep, 1)
       
    38 
       
    39     def sort(list, fn=None, key=None):
       
    40         if fn:
       
    41             list.sort(cmp=fn)
       
    42         elif key:
       
    43             list.sort(key=key)
       
    44         else:
       
    45             list.sort()
       
    46 
       
    47 
       
    48 class JavaError(Exception):
       
    49 
       
    50     def getJavaException(self):
       
    51         return self.args[0]
       
    52 
       
    53     def __str__(self):
       
    54         writer = StringWriter()
       
    55         self.getJavaException().printStackTrace(PrintWriter(writer))
       
    56 
       
    57         return '\n'.join((super(JavaError, self).__str__(),
       
    58                           "Java stacktrace:", str(writer)))
       
    59 
       
    60 
       
    61 class InvalidArgsError(Exception):
       
    62     pass
       
    63 
       
    64 
       
    65 _jcc._set_exception_types(JavaError, InvalidArgsError)
       
    66 from _jcc import *
       
    67 
       
    68 
       
    69 INDENT = '    '
       
    70 HALF_INDENT = '  '
       
    71 
       
    72 PRIMITIVES = { 'boolean': 'Z',
       
    73                'byte': 'B',
       
    74                'char': 'C',
       
    75                'double': 'D',
       
    76                'float': 'F',
       
    77                'int': 'I',
       
    78                'long': 'J',
       
    79                'short': 'S',
       
    80                'void': 'V' }
       
    81 
       
    82 RESERVED = set(['delete', 'and', 'or', 'not', 'xor', 'union', 'NULL',
       
    83                 'register', 'const', 'bool', 'operator', 'typeof'])
       
    84 
       
    85 def cppname(name):
       
    86 
       
    87     if name in RESERVED:
       
    88         return name + '$'
       
    89 
       
    90     return name
       
    91 
       
    92 
       
    93 def cppnames(names):
       
    94 
       
    95     return [cppname(name) for name in names]
       
    96 
       
    97 
       
    98 def typename(cls, current, const):
       
    99 
       
   100     if cls.isArray():
       
   101         componentType = cls.getComponentType()
       
   102         if componentType.isArray():
       
   103             name = 'JArray< %s >' %(typename(componentType, current, False))
       
   104         else:
       
   105             name = 'JArray<%s>' %(typename(componentType, current, False))
       
   106 
       
   107     elif cls.isPrimitive():
       
   108         name = cls.getName()
       
   109         if name != 'void':
       
   110             name = 'j' + name
       
   111         const = False
       
   112 
       
   113     elif cls == current:
       
   114         name = cppname(cls.getName().split('.')[-1])
       
   115 
       
   116     else:
       
   117         name = '::'.join([cppname(name) for name in cls.getName().split('.')])
       
   118 
       
   119     if const:
       
   120         return "const %s&" %(name)
       
   121 
       
   122     return name
       
   123 
       
   124 
       
   125 def argnames(params, cls):
       
   126 
       
   127     if not params:
       
   128         return '', ''
       
   129 
       
   130     count = len(params)
       
   131     decls = ', '.join(["%s a%d" %(typename(params[i], cls, True), i)
       
   132                        for i in xrange(count)])
       
   133     args = ', '.join(['a%d%s' %(i, not params[i].isPrimitive() and '.this$' or '')
       
   134                       for i in xrange(count)])
       
   135 
       
   136     return decls, ', ' + args
       
   137 
       
   138 
       
   139 def line(out, indent=0, string='', *args):
       
   140 
       
   141     out.write(INDENT * indent)
       
   142     out.write(string % args)
       
   143     out.write('\n')
       
   144 
       
   145 
       
   146 def known(cls, typeset, declares, packages, excludes, generics):
       
   147 
       
   148     if generics:
       
   149         if Class.instance_(cls):
       
   150             cls = Class.cast_(cls)
       
   151         elif ParameterizedType.instance_(cls):
       
   152             pt = ParameterizedType.cast_(cls)
       
   153             if not known(pt.getRawType(), typeset, declares, packages, excludes,
       
   154                          True):
       
   155                 return False
       
   156             for ta in pt.getActualTypeArguments():
       
   157                 if TypeVariable.instance_(ta):
       
   158                     continue
       
   159                 if not known(ta, typeset, declares, packages, excludes, True):
       
   160                     return False
       
   161             return True
       
   162         elif WildcardType.instance_(cls):
       
   163             wc = WildcardType.cast_(cls)
       
   164             for ub in wc.getUpperBounds():
       
   165                 if not known(ub, typeset, declares, packages, excludes, True):
       
   166                     return False
       
   167             return True
       
   168         elif TypeVariable.instance_(cls):
       
   169             for bounds in TypeVariable.cast_(cls).getBounds():
       
   170                 if not known(bounds, typeset, declares, packages, excludes,
       
   171                              True):
       
   172                     return False
       
   173             return True
       
   174         elif GenericArrayType.instance_(cls):
       
   175             return known(GenericArrayType.cast_(cls).getGenericComponentType(),
       
   176                          typeset, declares, packages, excludes, True)
       
   177         else:
       
   178             raise TypeError, (cls, cls.getClass())
       
   179 
       
   180     while cls.isArray():
       
   181         cls = cls.getComponentType()
       
   182 
       
   183     className = cls.getName()
       
   184     if className in excludes:
       
   185         return False
       
   186 
       
   187     if cls.isPrimitive():
       
   188         return True
       
   189 
       
   190     if cls in typeset:
       
   191         declares.add(cls)
       
   192         return True
       
   193 
       
   194     if split_pkg(className, '.')[0] in packages:
       
   195         typeset.add(cls)
       
   196         declares.add(cls)
       
   197         cls = cls.getSuperclass()
       
   198         while cls and cls not in typeset:
       
   199             typeset.add(cls)
       
   200             cls = cls.getSuperclass()
       
   201         return True
       
   202 
       
   203     return False
       
   204 
       
   205 
       
   206 def find_method(cls, name, params):
       
   207 
       
   208     declared = False
       
   209     while True:
       
   210         try:
       
   211             if declared:
       
   212                 method = cls.getDeclaredMethod(name, params)
       
   213             else:
       
   214                 method = cls.getMethod(name, params)
       
   215             break
       
   216         except JavaError, e:
       
   217             if (e.getJavaException().getClass().getName() == 'java.lang.NoSuchMethodException'):
       
   218                 if not declared:
       
   219                     declared = True
       
   220                 else:
       
   221                     cls = cls.getSuperclass()
       
   222                     if not cls:
       
   223                         return None
       
   224                 continue
       
   225             raise
       
   226 
       
   227     modifiers = method.getModifiers()
       
   228     if Modifier.isAbstract(modifiers):
       
   229         return None
       
   230     if Modifier.isPrivate(modifiers):
       
   231         return None
       
   232 
       
   233     return method
       
   234 
       
   235 
       
   236 def signature(fn, argsOnly=False):
       
   237 
       
   238     def typename(cls):
       
   239         array = ''
       
   240         while cls.isArray():
       
   241             array += '['
       
   242             cls = cls.getComponentType()
       
   243         if cls.isPrimitive():
       
   244             return array + PRIMITIVES[cls.getName()]
       
   245         return '%sL%s;' %(array, cls.getName().replace('.', '/'))
       
   246         
       
   247     if isinstance(fn, Constructor):
       
   248         returnType = 'V'
       
   249     elif isinstance(fn, Method):
       
   250         returnType = typename(fn.getReturnType())
       
   251     elif isinstance(fn, Field):
       
   252         return typename(fn.getType())
       
   253 
       
   254     if argsOnly:
       
   255         return '(%s)' %(''.join([typename(param)
       
   256                                  for param in fn.getParameterTypes()]))
       
   257 
       
   258     return '(%s)%s' %(''.join([typename(param)
       
   259                                for param in fn.getParameterTypes()]),
       
   260                        returnType)
       
   261 
       
   262 
       
   263 def forward(out, namespace, indent):
       
   264 
       
   265     for name, entries in namespace.iteritems():
       
   266         if entries is True:
       
   267             line(out, indent, 'class %s;', cppname(name))
       
   268         else:
       
   269             line(out, indent, 'namespace %s {', cppname(name))
       
   270             forward(out, entries, indent + 1)
       
   271             line(out, indent, '}')
       
   272 
       
   273 
       
   274 def expandjar(path):
       
   275 
       
   276     jar = zipfile.ZipFile(path, 'r')
       
   277 
       
   278     for member in jar.infolist():
       
   279         f = member.filename
       
   280         if f.endswith('.class'):
       
   281             yield f.split('.')[0].replace('/', '.')
       
   282 
       
   283     jar.close()
       
   284 
       
   285 
       
   286 def jcc(args):
       
   287 
       
   288     classNames = set()
       
   289     packages = set()
       
   290     jars = []
       
   291     classpath = []
       
   292     libpath = []
       
   293     vmargs = ['-Djava.awt.headless=true']
       
   294     moduleName = None
       
   295     modules = []
       
   296     build = False
       
   297     install = False
       
   298     recompile = False
       
   299     output = 'build'
       
   300     debug = False
       
   301     excludes = []
       
   302     version = ''
       
   303     mappings = {}
       
   304     sequences = {}
       
   305     renames = {}
       
   306     env = None
       
   307     wrapperFiles = 1
       
   308     prefix = None
       
   309     root = None
       
   310     install_dir = None
       
   311     home_dir = None
       
   312     use_distutils = False
       
   313     shared = False
       
   314     dist = False
       
   315     wininst = False
       
   316     compiler = None
       
   317     generics = hasattr(_jcc, "Type")
       
   318     arch = []
       
   319 
       
   320     i = 1
       
   321     while i < len(args):
       
   322         arg = args[i]
       
   323         if arg.startswith('-'):
       
   324             if arg == '--jar':
       
   325                 i += 1
       
   326                 classpath.append(args[i])
       
   327                 classNames.update(expandjar(args[i]))
       
   328                 jars.append(args[i])
       
   329             elif arg == '--include':
       
   330                 i += 1
       
   331                 classpath.append(args[i])
       
   332                 jars.append(args[i])
       
   333             elif arg == '--package':
       
   334                 i += 1
       
   335                 packages.add(args[i])
       
   336             elif arg == '--classpath':
       
   337                 i += 1
       
   338                 classpath.append(args[i])
       
   339             elif arg == '--libpath':
       
   340                 i += 1
       
   341                 libpath.append(args[i])
       
   342             elif arg == '--vmarg':
       
   343                 i += 1
       
   344                 vmargs.append(args[i])
       
   345             elif arg == '--python':
       
   346                 from python import python, module
       
   347                 i += 1
       
   348                 moduleName = args[i]
       
   349             elif arg == '--module':
       
   350                 i += 1
       
   351                 modules.append(args[i])
       
   352             elif arg == '--build':
       
   353                 from python import compile
       
   354                 build = True
       
   355             elif arg == '--install':
       
   356                 from python import compile
       
   357                 install = True
       
   358             elif arg == '--compile':
       
   359                 from python import compile
       
   360                 recompile = True
       
   361             elif arg == '--output':
       
   362                 i += 1
       
   363                 output = args[i]
       
   364             elif arg == '--debug':
       
   365                 debug = True
       
   366             elif arg == '--exclude':
       
   367                 i += 1
       
   368                 excludes.append(args[i])
       
   369             elif arg == '--version':
       
   370                 i += 1
       
   371                 version = args[i]
       
   372             elif arg == '--mapping':
       
   373                 mappings[args[i + 1]] = args[i + 2]
       
   374                 i += 2
       
   375             elif arg == '--sequence':
       
   376                 sequences[args[i + 1]] = (args[i + 2], args[i + 3])
       
   377                 i += 3
       
   378             elif arg == '--rename':
       
   379                 i += 1
       
   380                 renames.update(dict([arg.split('=')
       
   381                                      for arg in args[i].split(',')]))
       
   382             elif arg == '--files':
       
   383                 i += 1
       
   384                 wrapperFiles = args[i]
       
   385                 if wrapperFiles != 'separate':
       
   386                     wrapperFiles = int(wrapperFiles)
       
   387             elif arg == '--prefix':
       
   388                 i += 1
       
   389                 prefix = args[i]
       
   390             elif arg == '--root':
       
   391                 i += 1
       
   392                 root = args[i]
       
   393             elif arg == '--install-dir':
       
   394                 i += 1
       
   395                 install_dir = args[i]
       
   396             elif arg == '--home':
       
   397                 i += 1
       
   398                 home_dir = args[i]
       
   399             elif arg == '--use-distutils':
       
   400                 use_distutils = True
       
   401             elif arg == '--shared':
       
   402                 shared = True
       
   403             elif arg == '--bdist':
       
   404                 from python import compile
       
   405                 dist = True
       
   406             elif arg == '--wininst':
       
   407                 from python import compile
       
   408                 wininst = True
       
   409                 dist = True
       
   410             elif arg == '--compiler':
       
   411                 i += 1
       
   412                 compiler = args[i]
       
   413             elif arg == '--reserved':
       
   414                 i += 1
       
   415                 RESERVED.update(args[i].split(','))
       
   416             elif arg == '--arch':
       
   417                 i += 1
       
   418                 arch.append(args[i])
       
   419             elif arg == '--no-generics':
       
   420                 generics = False
       
   421             else:
       
   422                 raise ValueError, "Invalid argument: %s" %(arg)
       
   423         else:
       
   424             classNames.add(arg)
       
   425         i += 1
       
   426 
       
   427     if libpath:
       
   428         vmargs.append('-Djava.library.path=' + os.pathsep.join(libpath))
       
   429 
       
   430     env = initVM(os.pathsep.join(classpath) or None,
       
   431                  maxstack='512k', vmargs=' '.join(vmargs))
       
   432 
       
   433     typeset = set()
       
   434     excludes = set(excludes)
       
   435 
       
   436     if recompile or not build and (install or dist):
       
   437         if moduleName is None:
       
   438             raise ValueError, 'module name not specified (use --python)'
       
   439         else:
       
   440             compile(env, os.path.dirname(args[0]), output, moduleName,
       
   441                     install, dist, debug, jars, version,
       
   442                     prefix, root, install_dir, home_dir, use_distutils,
       
   443                     shared, compiler, modules, wininst, arch, generics)
       
   444     else:
       
   445         for className in classNames:
       
   446             if className in excludes:
       
   447                 continue
       
   448             cls = findClass(className.replace('.', '/'))
       
   449             if cls is None:
       
   450                 raise ValueError, className
       
   451             if Modifier.isPublic(cls.getModifiers()):
       
   452                 typeset.add(cls)
       
   453                 cls = cls.getSuperclass()
       
   454                 while cls and cls not in typeset:
       
   455                     typeset.add(cls)
       
   456                     cls = cls.getSuperclass()
       
   457         typeset.add(findClass('java/lang/Class'))
       
   458         typeset.add(findClass('java/lang/String'))
       
   459         typeset.add(findClass('java/lang/Throwable'))
       
   460         typeset.add(findClass('java/lang/Exception'))
       
   461         typeset.add(findClass('java/lang/RuntimeException'))
       
   462         if moduleName:
       
   463             typeset.add(findClass('java/lang/Number'))
       
   464             typeset.add(findClass('java/lang/Boolean'))
       
   465             typeset.add(findClass('java/lang/Integer'))
       
   466             typeset.add(findClass('java/lang/Long'))
       
   467             typeset.add(findClass('java/lang/Double'))
       
   468             typeset.add(findClass('java/util/Iterator'))
       
   469             typeset.add(findClass('java/util/Enumeration'))
       
   470             typeset.add(findClass('java/io/StringWriter'))
       
   471             typeset.add(findClass('java/io/PrintWriter'))
       
   472             typeset.add(findClass('java/io/Writer'))
       
   473             packages.add('java.lang')
       
   474 
       
   475         if moduleName:
       
   476             cppdir = os.path.join(output, '_%s' %(moduleName))
       
   477         else:
       
   478             cppdir = output
       
   479 
       
   480         allInOne = wrapperFiles != 'separate'
       
   481         if allInOne:
       
   482             if not os.path.isdir(cppdir):
       
   483                 os.makedirs(cppdir)
       
   484             if wrapperFiles <= 1:
       
   485                 out_cpp = file(os.path.join(cppdir, '__wrap__.cpp'), 'w')
       
   486             else:
       
   487                 fileCount = 1
       
   488                 fileName = '__wrap%02d__.cpp' %(fileCount)
       
   489                 out_cpp = file(os.path.join(cppdir, fileName), 'w')
       
   490 
       
   491         done = set()
       
   492         todo = typeset - done
       
   493 	if allInOne and wrapperFiles > 1:
       
   494             classesPerFile = max(1, len(todo) / wrapperFiles)
       
   495         classCount = 0
       
   496         while todo:
       
   497             for cls in todo:
       
   498                 classCount += 1
       
   499                 className = cls.getName()
       
   500                 names = className.split('.')
       
   501                 dir = os.path.join(cppdir, *names[:-1])
       
   502                 if not os.path.isdir(dir):
       
   503                     os.makedirs(dir)
       
   504 
       
   505                 fileName = os.path.join(dir, names[-1])
       
   506                 out_h = file(fileName + '.h', "w")
       
   507                 line(out_h, 0, '#ifndef %s_H', '_'.join(names))
       
   508                 line(out_h, 0, '#define %s_H', '_'.join(names))
       
   509 
       
   510                 (superCls, constructors, methods, protectedMethods,
       
   511                  fields, instanceFields, declares) = \
       
   512                     header(env, out_h, cls, typeset, packages, excludes,
       
   513                            generics)
       
   514 
       
   515                 if not allInOne:
       
   516                     out_cpp = file(fileName + '.cpp', 'w')
       
   517                 names, superNames = code(env, out_cpp,
       
   518                                          cls, superCls, constructors,
       
   519                                          methods, protectedMethods,
       
   520                                          fields, instanceFields, 
       
   521                                          declares, typeset)
       
   522                 if moduleName:
       
   523                     python(env, out_h, out_cpp,
       
   524                            cls, superCls, names, superNames,
       
   525                            constructors, methods, protectedMethods,
       
   526                            fields, instanceFields,
       
   527                            mappings.get(className), sequences.get(className),
       
   528                            renames.get(className),
       
   529                            declares, typeset, moduleName, generics)
       
   530 
       
   531                 line(out_h)
       
   532                 line(out_h, 0, '#endif')
       
   533                 out_h.close()
       
   534 
       
   535                 if not allInOne:
       
   536                     out_cpp.close()
       
   537                 elif wrapperFiles > 1:
       
   538                     if classCount >= classesPerFile:
       
   539                         out_cpp.close()
       
   540 	                fileCount += 1
       
   541 	                fileName = '__wrap%02d__.cpp' %(fileCount)
       
   542 	                out_cpp = file(os.path.join(cppdir, fileName), 'w')
       
   543                         classCount = 0
       
   544                         
       
   545             done.update(todo)
       
   546             todo = typeset - done
       
   547 
       
   548         if allInOne:
       
   549             out_cpp.close()
       
   550 
       
   551         if moduleName:
       
   552             out = file(os.path.join(cppdir, moduleName) + '.cpp', 'w')
       
   553             module(out, allInOne, done, cppdir, moduleName, shared, generics)
       
   554             out.close()
       
   555             if build or install or dist:
       
   556                 compile(env, os.path.dirname(args[0]), output, moduleName,
       
   557                         install, dist, debug, jars, version,
       
   558                         prefix, root, install_dir, home_dir, use_distutils,
       
   559                         shared, compiler, modules, wininst, arch, generics)
       
   560 
       
   561 
       
   562 def header(env, out, cls, typeset, packages, excludes, generics):
       
   563 
       
   564     names = cls.getName().split('.')
       
   565     superCls = cls.getSuperclass()
       
   566     declares = set([cls.getClass()])
       
   567 
       
   568     interfaces = []
       
   569     for interface in cls.getInterfaces():
       
   570         if superCls and interface.isAssignableFrom(superCls):
       
   571             continue
       
   572         if known(interface, typeset, declares, packages, excludes, False):
       
   573             interfaces.append(interface)
       
   574 
       
   575     if cls.isInterface():
       
   576         if interfaces:
       
   577             superCls = interfaces.pop(0)
       
   578         else:
       
   579             superCls = findClass('java/lang/Object')
       
   580         superClsName = superCls.getName()
       
   581     elif superCls:
       
   582         superClsName = superCls.getName()
       
   583     else:
       
   584         superClsName = 'JObject'
       
   585 
       
   586     constructors = []
       
   587     for constructor in cls.getDeclaredConstructors():
       
   588         if Modifier.isPublic(constructor.getModifiers()):
       
   589             if generics:
       
   590                 params = constructor.getGenericParameterTypes()
       
   591                 if len(params) == 1:
       
   592                     if params[0] == cls:
       
   593                         continue
       
   594                     if ParameterizedType.instance_(params[0]):
       
   595                         param = ParameterizedType.cast_(params[0])
       
   596                         if param.getRawType() == cls:
       
   597                             continue
       
   598             else:
       
   599                 params = constructor.getParameterTypes()
       
   600                 if len(params) == 1 and params[0] == cls:
       
   601                     continue
       
   602             for param in params:
       
   603                 if not known(param, typeset, declares, packages, excludes,
       
   604                              generics):
       
   605                     break
       
   606             else:
       
   607                 constructors.append(constructor)
       
   608     sort(constructors, key=lambda x: len(x.getParameterTypes()))
       
   609 
       
   610     methods = {}
       
   611     protectedMethods = []
       
   612     for method in cls.getDeclaredMethods():
       
   613         modifiers = method.getModifiers()
       
   614         if Modifier.isPublic(modifiers):
       
   615             if generics:
       
   616                 returnType = method.getGenericReturnType()
       
   617             else:
       
   618                 returnType = method.getReturnType()
       
   619             if not known(returnType, typeset, declares, packages, excludes,
       
   620                          generics):
       
   621                 continue
       
   622             sig = "%s:%s" %(method.getName(), signature(method, True))
       
   623             if sig in methods and returnType != cls:
       
   624                 continue
       
   625             if generics:
       
   626                 params = method.getGenericParameterTypes()
       
   627             else:
       
   628                 params = method.getParameterTypes()
       
   629             for param in params:
       
   630                 if not known(param, typeset, declares, packages, excludes,
       
   631                              generics):
       
   632                     break
       
   633             else:
       
   634                 methods[sig] = method
       
   635         elif Modifier.isProtected(modifiers):
       
   636             protectedMethods.append(method)
       
   637     for interface in interfaces:
       
   638         for method in interface.getMethods():
       
   639             sig = "%s:%s" %(method.getName(), signature(method, True))
       
   640             if sig not in methods:
       
   641                 if generics:
       
   642                     param = method.getGenericReturnType()
       
   643                 else:
       
   644                     param = method.getReturnType()
       
   645                 if not known(param, typeset, declares, packages, excludes,
       
   646                              generics):
       
   647                     continue
       
   648                 if generics:
       
   649                     params = method.getGenericParameterTypes()
       
   650                 else:
       
   651                     params = method.getParameterTypes()
       
   652                 for param in params:
       
   653                     if not known(param, typeset, declares, packages, excludes,
       
   654                                  generics):
       
   655                         break
       
   656                 else:
       
   657                     methods[sig] = method
       
   658 
       
   659     def _compare(m0, m1):
       
   660         value = cmp(m0.getName(), m1.getName())
       
   661         if value == 0:
       
   662             value = len(m0.getParameterTypes()) - len(m1.getParameterTypes())
       
   663         return value
       
   664 
       
   665     methods = methods.values()
       
   666     sort(methods, fn=_compare)
       
   667 
       
   668     for constructor in constructors:
       
   669         if generics:
       
   670             exceptions = constructor.getGenericExceptionTypes()
       
   671         else:
       
   672             exceptions = constructor.getExceptionTypes()
       
   673         for exception in exceptions:
       
   674             known(exception, typeset, declares, packages, excludes, generics)
       
   675     for method in methods:
       
   676         if generics:
       
   677             exceptions = method.getGenericExceptionTypes()
       
   678         else:
       
   679             exceptions = method.getExceptionTypes()
       
   680         for exception in exceptions:
       
   681             known(exception, typeset, declares, packages, excludes, generics)
       
   682 
       
   683     fields = []
       
   684     instanceFields = []
       
   685     for field in cls.getDeclaredFields():
       
   686         modifiers = field.getModifiers()
       
   687         if Modifier.isPublic(modifiers):
       
   688             if generics:
       
   689                 fieldType = field.getGenericType()
       
   690             else:
       
   691                 fieldType = field.getType()
       
   692             if not known(fieldType, typeset, declares, packages, excludes,
       
   693                          generics):
       
   694                 continue
       
   695             if Modifier.isStatic(modifiers):
       
   696                 fields.append(field)
       
   697             else:
       
   698                 instanceFields.append(field)
       
   699     sort(fields, key=lambda x: x.getName())
       
   700     sort(instanceFields, key=lambda x: x.getName())
       
   701 
       
   702     line(out)
       
   703     superNames = superClsName.split('.')
       
   704     line(out, 0, '#include "%s.h"', '/'.join(superNames))
       
   705 
       
   706     line(out, 0)
       
   707     namespaces = {}
       
   708     for declare in declares:
       
   709         namespace = namespaces
       
   710         if declare not in (cls, superCls):
       
   711             declareNames = declare.getName().split('.')
       
   712             for declareName in declareNames[:-1]:
       
   713                 namespace = namespace.setdefault(declareName, {})
       
   714             namespace[declareNames[-1]] = True
       
   715     forward(out, namespaces, 0)
       
   716     line(out, 0, 'template<class T> class JArray;')
       
   717 
       
   718     indent = 0;
       
   719     line(out)
       
   720     for name in names[:-1]:
       
   721         line(out, indent, 'namespace %s {', cppname(name))
       
   722         indent += 1
       
   723 
       
   724     line(out)
       
   725     if superClsName == 'JObject':
       
   726         line(out, indent, 'class %s : public JObject {', cppname(names[-1]))
       
   727     else:
       
   728         line(out, indent, 'class %s : public %s {',
       
   729              cppname(names[-1]), '::'.join(cppnames(superNames)))
       
   730         
       
   731     line(out, indent, 'public:')
       
   732     indent += 1
       
   733 
       
   734     if methods or protectedMethods or constructors:
       
   735         line(out, indent, 'enum {')
       
   736         for constructor in constructors:
       
   737             line(out, indent + 1, 'mid_init$_%s,',
       
   738                  env.strhash(signature(constructor)))
       
   739         for method in methods:
       
   740             line(out, indent + 1, 'mid_%s_%s,', method.getName(),
       
   741                  env.strhash(signature(method)))
       
   742         for method in protectedMethods:
       
   743             line(out, indent + 1, 'mid_%s_%s,', method.getName(),
       
   744                  env.strhash(signature(method)))
       
   745         line(out, indent + 1, 'max_mid')
       
   746         line(out, indent, '};')
       
   747 
       
   748     if instanceFields:
       
   749         line(out)
       
   750         line(out, indent, 'enum {')
       
   751         for field in instanceFields:
       
   752             line(out, indent + 1, 'fid_%s,', field.getName())
       
   753         line(out, indent + 1, 'max_fid')
       
   754         line(out, indent, '};')
       
   755 
       
   756     line(out)
       
   757     line(out, indent, 'static java::lang::Class *class$;');
       
   758     line(out, indent, 'static jmethodID *mids$;');
       
   759     if instanceFields:
       
   760         line(out, indent, 'static jfieldID *fids$;');
       
   761     line(out, indent, 'static jclass initializeClass();');
       
   762     line(out)
       
   763 
       
   764     line(out, indent, 'explicit %s(jobject obj) : %s(obj) {',
       
   765          cppname(names[-1]), '::'.join(cppnames(superNames)))
       
   766     line(out, indent + 1, 'if (obj != NULL)');
       
   767     line(out, indent + 2, 'initializeClass();')
       
   768     line(out, indent, '}')
       
   769     line(out, indent, '%s(const %s& obj) : %s(obj) {}',
       
   770          cppname(names[-1]), cppname(names[-1]),
       
   771          '::'.join(cppnames(superNames)))
       
   772 
       
   773     if fields:
       
   774         line(out)
       
   775         for field in fields:
       
   776             fieldType = field.getType()
       
   777             fieldName = cppname(field.getName())
       
   778             if fieldType.isPrimitive():
       
   779                 line(out, indent, 'static %s %s;',
       
   780                      typename(fieldType, cls, False), fieldName)
       
   781             else:
       
   782                 line(out, indent, 'static %s *%s;',
       
   783                      typename(fieldType, cls, False), fieldName)
       
   784 
       
   785     if instanceFields:
       
   786         line(out)
       
   787         for field in instanceFields:
       
   788             fieldType = field.getType()
       
   789             fieldName = field.getName()
       
   790             modifiers = field.getModifiers()
       
   791             line(out, indent, '%s _get_%s() const;',
       
   792                  typename(fieldType, cls, False), fieldName)
       
   793             if not Modifier.isFinal(modifiers):
       
   794                 line(out, indent, 'void _set_%s(%s) const;',
       
   795                      fieldName, typename(fieldType, cls, True))
       
   796 
       
   797     if constructors:
       
   798         line(out)
       
   799         for constructor in constructors:
       
   800             params = [typename(param, cls, True)
       
   801                       for param in constructor.getParameterTypes()]
       
   802             line(out, indent, '%s(%s);', cppname(names[-1]), ', '.join(params))
       
   803 
       
   804     if methods:
       
   805         line(out)
       
   806         for method in methods:
       
   807             modifiers = method.getModifiers()
       
   808             if Modifier.isStatic(modifiers):
       
   809                 prefix = 'static '
       
   810                 const = ''
       
   811             else:
       
   812                 prefix = ''
       
   813                 const = ' const'
       
   814             params = [typename(param, cls, True)
       
   815                       for param in method.getParameterTypes()]
       
   816             methodName = cppname(method.getName())
       
   817             line(out, indent, '%s%s %s(%s)%s;',
       
   818                  prefix, typename(method.getReturnType(), cls, False),
       
   819                  methodName, ', '.join(params), const)
       
   820 
       
   821     indent -= 1
       
   822     line(out, indent, '};')
       
   823 
       
   824     while indent:
       
   825         indent -= 1
       
   826         line(out, indent, '}')
       
   827 
       
   828     return (superCls, constructors, methods, protectedMethods,
       
   829             fields, instanceFields, declares)
       
   830 
       
   831 
       
   832 def code(env, out, cls, superCls, constructors, methods, protectedMethods,
       
   833          fields, instanceFields, declares, typeset):
       
   834 
       
   835     className = cls.getName()
       
   836     names = className.split('.')
       
   837 
       
   838     if superCls:
       
   839         superClsName = superCls.getName()
       
   840     else:
       
   841         superClsName = 'JObject'
       
   842     superNames = superClsName.split('.')
       
   843 
       
   844     line(out, 0, '#include <jni.h>')
       
   845     line(out, 0, '#include "JCCEnv.h"')
       
   846     line(out, 0, '#include "%s.h"', className.replace('.', '/'))
       
   847     for declare in declares:
       
   848         if declare not in (cls, superCls):
       
   849             line(out, 0, '#include "%s.h"', declare.getName().replace('.', '/'))
       
   850     line(out, 0, '#include "JArray.h"')
       
   851 
       
   852     indent = 0
       
   853     line(out)
       
   854     for name in names[:-1]:
       
   855         line(out, indent, 'namespace %s {', cppname(name))
       
   856         indent += 1
       
   857 
       
   858     line(out)
       
   859     line(out, indent, 'java::lang::Class *%s::class$ = NULL;',
       
   860          cppname(names[-1]))
       
   861     line(out, indent, 'jmethodID *%s::mids$ = NULL;', cppname(names[-1]))
       
   862     if instanceFields:
       
   863         line(out, indent, 'jfieldID *%s::fids$ = NULL;', cppname(names[-1]))
       
   864 
       
   865     for field in fields:
       
   866         fieldType = field.getType()
       
   867         fieldName = cppname(field.getName())
       
   868         typeName = typename(fieldType, cls, False)
       
   869         if fieldType.isPrimitive():
       
   870             line(out, indent, '%s %s::%s = (%s) 0;',
       
   871                  typeName, cppname(names[-1]), fieldName, typeName)
       
   872         else:
       
   873             line(out, indent, '%s *%s::%s = NULL;',
       
   874                  typeName, cppname(names[-1]), fieldName)
       
   875 
       
   876     line(out)
       
   877     line(out, indent, 'jclass %s::initializeClass()', cppname(names[-1]))
       
   878     line(out, indent, '{')
       
   879     line(out, indent + 1, 'if (!class$)')
       
   880     line(out, indent + 1, '{')
       
   881     line(out)
       
   882     line(out, indent + 2, 'jclass cls = (jclass) env->findClass("%s");',
       
   883          className.replace('.', '/'))
       
   884 
       
   885     if methods or protectedMethods or constructors:
       
   886         line(out)
       
   887         line(out, indent + 2, 'mids$ = new jmethodID[max_mid];')
       
   888         for constructor in constructors:
       
   889             sig = signature(constructor)
       
   890             line(out, indent + 2,
       
   891                  'mids$[mid_init$_%s] = env->getMethodID(cls, "<init>", "%s");',
       
   892                  env.strhash(sig), sig)
       
   893         isExtension = False
       
   894         for method in methods:
       
   895             methodName = method.getName()
       
   896             if methodName == 'pythonExtension':
       
   897                 isExtension = True
       
   898             sig = signature(method)
       
   899             line(out, indent + 2,
       
   900                  'mids$[mid_%s_%s] = env->get%sMethodID(cls, "%s", "%s");',
       
   901                  methodName, env.strhash(sig),
       
   902                  Modifier.isStatic(method.getModifiers()) and 'Static' or '',
       
   903                  methodName, sig)
       
   904         for method in protectedMethods:
       
   905             methodName = method.getName()
       
   906             sig = signature(method)
       
   907             line(out, indent + 2,
       
   908                  'mids$[mid_%s_%s] = env->get%sMethodID(cls, "%s", "%s");',
       
   909                  methodName, env.strhash(sig),
       
   910                  Modifier.isStatic(method.getModifiers()) and 'Static' or '',
       
   911                  methodName, sig)
       
   912 
       
   913     if instanceFields:
       
   914         line(out)
       
   915         line(out, indent + 2, 'fids$ = new jfieldID[max_fid];')
       
   916         for field in instanceFields:
       
   917             fieldName = field.getName()
       
   918             line(out, indent + 2,
       
   919                  'fids$[fid_%s] = env->getFieldID(cls, "%s", "%s");',
       
   920                  fieldName, fieldName, signature(field))
       
   921 
       
   922     line(out)
       
   923     line(out, indent + 2, 'class$ = (java::lang::Class *) new JObject(cls);')
       
   924 
       
   925     if fields:
       
   926         line(out, indent + 2, 'cls = (jclass) class$->this$;')
       
   927         line(out)
       
   928         for field in fields:
       
   929             fieldType = field.getType()
       
   930             fieldName = field.getName()
       
   931             if fieldType.isPrimitive():
       
   932                 line(out, indent + 2,
       
   933                      '%s = env->getStatic%sField(cls, "%s");',
       
   934                      cppname(fieldName), fieldType.getName().capitalize(),
       
   935                      fieldName)
       
   936             else:
       
   937                 line(out, indent + 2,
       
   938                      '%s = new %s(env->getStaticObjectField(cls, "%s", "%s"));',
       
   939                      cppname(fieldName), typename(fieldType, cls, False),
       
   940                      fieldName, signature(field))
       
   941 
       
   942     line(out, indent + 1, '}')
       
   943     line(out, indent + 1, 'return (jclass) class$->this$;')
       
   944     line(out, indent, '}')
       
   945 
       
   946     for constructor in constructors:
       
   947         line(out)
       
   948         sig = signature(constructor)
       
   949         decls, args = argnames(constructor.getParameterTypes(), cls)
       
   950 
       
   951         line(out, indent, "%s::%s(%s) : %s(env->newObject(initializeClass, &mids$, mid_init$_%s%s)) {}",
       
   952              cppname(names[-1]), cppname(names[-1]), decls,
       
   953              '::'.join(cppnames(superNames)),
       
   954              env.strhash(sig), args)
       
   955 
       
   956     for method in methods:
       
   957         modifiers = method.getModifiers()
       
   958         returnType = method.getReturnType()
       
   959         params = method.getParameterTypes()
       
   960         methodName = method.getName()
       
   961         superMethod = None
       
   962         isStatic = Modifier.isStatic(modifiers)
       
   963 
       
   964         if (isExtension and not isStatic and superCls and
       
   965             Modifier.isNative(modifiers)):
       
   966             superMethod = find_method(superCls, methodName, params)
       
   967             if superMethod is None:
       
   968                 continue
       
   969 
       
   970         if isStatic:
       
   971             qualifier = 'Static'
       
   972             this = 'cls'
       
   973             midns = ''
       
   974             const = ''
       
   975         else:
       
   976             isStatic = False
       
   977             if superMethod is not None:
       
   978                 qualifier = 'Nonvirtual'
       
   979                 this = 'this$, (jclass) %s::class$->this$' %('::'.join(cppnames(superNames)))
       
   980                 declaringClass = superMethod.getDeclaringClass()
       
   981                 midns = '%s::' %(typename(declaringClass, cls, False))
       
   982             else:
       
   983                 qualifier = ''
       
   984                 this = 'this$'
       
   985                 midns = ''
       
   986             const = ' const'
       
   987 
       
   988         sig = signature(method)
       
   989         decls, args = argnames(params, cls)
       
   990 
       
   991         line(out)
       
   992         line(out, indent, '%s %s::%s(%s)%s',
       
   993              typename(returnType, cls, False), cppname(names[-1]),
       
   994              cppname(methodName), decls, const)
       
   995         line(out, indent, '{')
       
   996         if isStatic:
       
   997             line(out, indent + 1, 'jclass cls = initializeClass();');
       
   998         if returnType.isPrimitive():
       
   999             line(out, indent + 1,
       
  1000                  '%senv->call%s%sMethod(%s, %smids$[%smid_%s_%s]%s);',
       
  1001                  not returnType.getName() == 'void' and 'return ' or '',
       
  1002                  qualifier, returnType.getName().capitalize(), this,
       
  1003                  midns, midns, methodName, env.strhash(sig), args)
       
  1004         else:
       
  1005             line(out, indent + 1,
       
  1006                  'return %s(env->call%sObjectMethod(%s, %smids$[%smid_%s_%s]%s));',
       
  1007                  typename(returnType, cls, False), qualifier, this,
       
  1008                  midns, midns, methodName, env.strhash(sig), args)
       
  1009         line(out, indent, '}')
       
  1010 
       
  1011     if instanceFields:
       
  1012         for field in instanceFields:
       
  1013             fieldType = field.getType()
       
  1014             fieldName = field.getName()
       
  1015             line(out)
       
  1016             line(out, indent, '%s %s::_get_%s() const',
       
  1017                  typename(fieldType, cls, False), cppname(names[-1]), fieldName)
       
  1018             line(out, indent, '{')
       
  1019             if fieldType.isPrimitive():
       
  1020                 line(out, indent + 1,
       
  1021                      'return env->get%sField(this$, fids$[fid_%s]);',
       
  1022                      fieldType.getName().capitalize(), fieldName)
       
  1023             else:
       
  1024                 line(out, indent + 1,
       
  1025                      'return %s(env->getObjectField(this$, fids$[fid_%s]));',
       
  1026                      typename(fieldType, cls, False), fieldName)
       
  1027             line(out, indent, '}')
       
  1028 
       
  1029             if not Modifier.isFinal(field.getModifiers()):
       
  1030                 line(out)
       
  1031                 line(out, indent, 'void %s::_set_%s(%s a0) const',
       
  1032                      cppname(names[-1]), fieldName,
       
  1033                      typename(fieldType, cls, True))
       
  1034                 line(out, indent, '{')
       
  1035                 if fieldType.isPrimitive():
       
  1036                     line(out, indent + 1,
       
  1037                          'env->set%sField(this$, fids$[fid_%s], a0);',
       
  1038                          fieldType.getName().capitalize(), fieldName)
       
  1039                 else:
       
  1040                     line(out, indent + 1,
       
  1041                          'env->setObjectField(this$, fids$[fid_%s], a0.this$);',
       
  1042                          fieldName)
       
  1043                 line(out, indent, '}')
       
  1044 
       
  1045     while indent:
       
  1046         indent -= 1
       
  1047         line(out, indent, '}')
       
  1048 
       
  1049     return names, superNames
       
  1050 
       
  1051 
       
  1052 if __name__ == '__main__':
       
  1053     jcc(sys.argv)