|
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) |