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