generator.py 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802
  1. #!/usr/bin/env python
  2. # generator.py
  3. # simple C++ generator, originally targetted for Spidermonkey bindings
  4. #
  5. # Copyright (c) 2011 - Zynga Inc.
  6. from clang import cindex
  7. import sys
  8. import ConfigParser
  9. import yaml
  10. import re
  11. import os
  12. import inspect
  13. import traceback
  14. from Cheetah.Template import Template
  15. type_map = {
  16. cindex.TypeKind.VOID : "void",
  17. cindex.TypeKind.BOOL : "bool",
  18. cindex.TypeKind.CHAR_U : "unsigned char",
  19. cindex.TypeKind.UCHAR : "unsigned char",
  20. cindex.TypeKind.CHAR16 : "char",
  21. cindex.TypeKind.CHAR32 : "char",
  22. cindex.TypeKind.USHORT : "unsigned short",
  23. cindex.TypeKind.UINT : "unsigned int",
  24. cindex.TypeKind.ULONG : "unsigned long",
  25. cindex.TypeKind.ULONGLONG : "unsigned long long",
  26. cindex.TypeKind.CHAR_S : "char",
  27. cindex.TypeKind.SCHAR : "char",
  28. cindex.TypeKind.WCHAR : "wchar_t",
  29. cindex.TypeKind.SHORT : "short",
  30. cindex.TypeKind.INT : "int",
  31. cindex.TypeKind.LONG : "long",
  32. cindex.TypeKind.LONGLONG : "long long",
  33. cindex.TypeKind.FLOAT : "float",
  34. cindex.TypeKind.DOUBLE : "double",
  35. cindex.TypeKind.LONGDOUBLE : "long double",
  36. cindex.TypeKind.NULLPTR : "NULL",
  37. cindex.TypeKind.OBJCID : "id",
  38. cindex.TypeKind.OBJCCLASS : "class",
  39. cindex.TypeKind.OBJCSEL : "SEL",
  40. # cindex.TypeKind.ENUM : "int"
  41. }
  42. INVALID_NATIVE_TYPE = "??"
  43. default_arg_type_arr = [
  44. # An integer literal.
  45. cindex.CursorKind.INTEGER_LITERAL,
  46. # A floating point number literal.
  47. cindex.CursorKind.FLOATING_LITERAL,
  48. # An imaginary number literal.
  49. cindex.CursorKind.IMAGINARY_LITERAL,
  50. # A string literal.
  51. cindex.CursorKind.STRING_LITERAL,
  52. # A character literal.
  53. cindex.CursorKind.CHARACTER_LITERAL,
  54. # [C++ 2.13.5] C++ Boolean Literal.
  55. cindex.CursorKind.CXX_BOOL_LITERAL_EXPR,
  56. # [C++0x 2.14.7] C++ Pointer Literal.
  57. cindex.CursorKind.CXX_NULL_PTR_LITERAL_EXPR,
  58. cindex.CursorKind.GNU_NULL_EXPR,
  59. # An expression that refers to some value declaration, such as a function,
  60. # varible, or enumerator.
  61. cindex.CursorKind.DECL_REF_EXPR
  62. ]
  63. stl_type_map = {
  64. 'std_function_args': 1000,
  65. 'std::unordered_map': 2,
  66. 'std::unordered_multimap': 2,
  67. 'std::map': 2,
  68. 'std::multimap': 2,
  69. 'std::vector': 1,
  70. 'std::list': 1,
  71. 'std::forward_list': 1,
  72. 'std::priority_queue': 1,
  73. 'std::set': 1,
  74. 'std::multiset': 1,
  75. 'std::unordered_set': 1,
  76. 'std::unordered_multiset': 1,
  77. 'std::stack': 1,
  78. 'std::queue': 1,
  79. 'std::deque': 1,
  80. 'std::array': 1,
  81. 'unordered_map': 2,
  82. 'unordered_multimap': 2,
  83. 'map': 2,
  84. 'multimap': 2,
  85. 'vector': 1,
  86. 'list': 1,
  87. 'forward_list': 1,
  88. 'priority_queue': 1,
  89. 'set': 1,
  90. 'multiset': 1,
  91. 'unordered_set': 1,
  92. 'unordered_multiset': 1,
  93. 'stack': 1,
  94. 'queue': 1,
  95. 'deque': 1,
  96. 'array': 1
  97. }
  98. def find_sub_string_count(s, start, end, substr):
  99. count = 0
  100. pos = s.find(substr, start, end)
  101. if pos != -1:
  102. next_count = find_sub_string_count(s, pos + 1, end, substr)
  103. count = next_count + 1
  104. return count
  105. def split_container_name(name):
  106. name = name.strip()
  107. left = name.find('<')
  108. right = -1
  109. if left != -1:
  110. right = name.rfind('>')
  111. if left == -1 or right == -1:
  112. return [name]
  113. first = name[:left]
  114. results = [first]
  115. comma = name.find(',', left + 1, right)
  116. if comma == -1:
  117. results.append(name[left+1:right].strip())
  118. return results
  119. left += 1
  120. while comma != -1:
  121. lt_count = find_sub_string_count(name, left, comma, '<')
  122. gt_count = find_sub_string_count(name, left, comma, '>')
  123. if lt_count == gt_count:
  124. results.append(name[left:comma].strip())
  125. left = comma + 1
  126. comma = name.find(',', comma + 1, right)
  127. if left < right:
  128. results.append(name[left:right].strip())
  129. name_len = len(name)
  130. if right < name_len - 1:
  131. results.append(name[right+1:].strip())
  132. return results
  133. def normalize_type_name_by_sections(sections):
  134. container_name = sections[0]
  135. suffix = ''
  136. index = len(sections) - 1
  137. while sections[index] == '*' or sections[index] == '&':
  138. suffix += sections[index]
  139. index -= 1
  140. name_for_search = container_name.replace('const ', '').replace('&', '').replace('*', '').strip()
  141. if name_for_search in stl_type_map:
  142. normalized_name = container_name + '<' + ', '.join(sections[1:1+stl_type_map[name_for_search]]) + '>' + suffix
  143. else:
  144. normalized_name = container_name + '<' + ', '.join(sections[1:]) + '>'
  145. return normalized_name
  146. def normalize_std_function_by_sections(sections):
  147. normalized_name = ''
  148. if sections[0] == 'std_function_args':
  149. normalized_name = '(' + ', '.join(sections[1:]) + ')'
  150. elif sections[0] == 'std::function' or sections[0] == 'function':
  151. normalized_name = 'std::function<' + sections[1] + ' ' + sections[2] + '>'
  152. else:
  153. assert(False)
  154. return normalized_name
  155. def normalize_type_str(s, depth=1):
  156. if s.find('std::function') == 0 or s.find('function') == 0:
  157. start = s.find('<')
  158. assert(start > 0)
  159. sections = [s[:start]] # std::function
  160. start += 1
  161. ret_pos = s.find('(', start)
  162. sections.append(s[start:ret_pos].strip()) # return type
  163. end = s.find(')', ret_pos + 1)
  164. sections.append('std_function_args<' + s[ret_pos+1:end].strip() + '>')
  165. else:
  166. sections = split_container_name(s)
  167. section_len = len(sections)
  168. if section_len == 1:
  169. return sections[0]
  170. # for section in sections:
  171. # print('>' * depth + section)
  172. if sections[0] == 'const std::basic_string' or sections[0] == 'const basic_string':
  173. last_section = sections[len(sections) - 1]
  174. if last_section == '&' or last_section == '*' or last_section.startswith('::'):
  175. return 'const std::string' + last_section
  176. else:
  177. return 'const std::string'
  178. elif sections[0] == 'std::basic_string' or sections[0] == 'basic_string':
  179. last_section = sections[len(sections) - 1]
  180. if last_section == '&' or last_section == '*' or last_section.startswith('::'):
  181. return 'std::string' + last_section
  182. else:
  183. return 'std::string'
  184. for i in range(1, section_len):
  185. sections[i] = normalize_type_str(sections[i], depth+1)
  186. if sections[0] == 'std::function' or sections[0] == 'function' or sections[0] == 'std_function_args':
  187. normalized_name = normalize_std_function_by_sections(sections)
  188. else:
  189. normalized_name = normalize_type_name_by_sections(sections)
  190. return normalized_name
  191. class BaseEnumeration(object):
  192. """
  193. Common base class for named enumerations held in sync with Index.h values.
  194. Subclasses must define their own _kinds and _name_map members, as:
  195. _kinds = []
  196. _name_map = None
  197. These values hold the per-subclass instances and value-to-name mappings,
  198. respectively.
  199. """
  200. def __init__(self, value):
  201. if value >= len(self.__class__._kinds):
  202. self.__class__._kinds += [None] * (value - len(self.__class__._kinds) + 1)
  203. if self.__class__._kinds[value] is not None:
  204. raise ValueError('{0} value {1} already loaded'.format(
  205. str(self.__class__), value))
  206. self.value = value
  207. self.__class__._kinds[value] = self
  208. self.__class__._name_map = None
  209. def from_param(self):
  210. return self.value
  211. @property
  212. def name(self):
  213. """Get the enumeration name of this cursor kind."""
  214. if self._name_map is None:
  215. self._name_map = {}
  216. for key, value in self.__class__.__dict__.items():
  217. if isinstance(value, self.__class__):
  218. self._name_map[value] = key
  219. return self._name_map[self]
  220. @classmethod
  221. def from_id(cls, id):
  222. if id >= len(cls._kinds) or cls._kinds[id] is None:
  223. raise ValueError('Unknown template argument kind %d' % id)
  224. return cls._kinds[id]
  225. def __repr__(self):
  226. return '%s.%s' % (self.__class__, self.name,)
  227. ### Availability Kinds ###
  228. class AvailabilityKind(BaseEnumeration):
  229. """
  230. Describes the availability of an entity.
  231. """
  232. # The unique kind objects, indexed by id.
  233. _kinds = []
  234. _name_map = None
  235. def __repr__(self):
  236. return 'AvailabilityKind.%s' % (self.name,)
  237. AvailabilityKind.AVAILABLE = AvailabilityKind(0)
  238. AvailabilityKind.DEPRECATED = AvailabilityKind(1)
  239. AvailabilityKind.NOT_AVAILABLE = AvailabilityKind(2)
  240. AvailabilityKind.NOT_ACCESSIBLE = AvailabilityKind(3)
  241. def get_availability(cursor):
  242. """
  243. Retrieves the availability of the entity pointed at by the cursor.
  244. """
  245. if not hasattr(cursor, '_availability'):
  246. cursor._availability = cindex.conf.lib.clang_getCursorAvailability(cursor)
  247. return AvailabilityKind.from_id(cursor._availability)
  248. def native_name_from_type(ntype, underlying=False):
  249. kind = ntype.kind #get_canonical().kind
  250. const = "" #"const " if ntype.is_const_qualified() else ""
  251. if not underlying and kind == cindex.TypeKind.ENUM:
  252. decl = ntype.get_declaration()
  253. return get_namespaced_name(decl)
  254. elif kind in type_map:
  255. return const + type_map[kind]
  256. elif kind == cindex.TypeKind.RECORD:
  257. # might be an std::string
  258. decl = ntype.get_declaration()
  259. parent = decl.semantic_parent
  260. cdecl = ntype.get_canonical().get_declaration()
  261. cparent = cdecl.semantic_parent
  262. if decl.spelling == "string" and parent and parent.spelling == "std":
  263. return "std::string"
  264. elif cdecl.spelling == "function" and cparent and cparent.spelling == "std":
  265. return "std::function"
  266. else:
  267. # print >> sys.stderr, "probably a function pointer: " + str(decl.spelling)
  268. return const + decl.spelling
  269. else:
  270. # name = ntype.get_declaration().spelling
  271. # print >> sys.stderr, "Unknown type: " + str(kind) + " " + str(name)
  272. return INVALID_NATIVE_TYPE
  273. # pdb.set_trace()
  274. def build_namespace(cursor, namespaces=[]):
  275. '''
  276. build the full namespace for a specific cursor
  277. '''
  278. if cursor:
  279. parent = cursor.semantic_parent
  280. if parent:
  281. if parent.kind == cindex.CursorKind.NAMESPACE or parent.kind == cindex.CursorKind.CLASS_DECL:
  282. namespaces.append(parent.displayname)
  283. build_namespace(parent, namespaces)
  284. return namespaces
  285. def get_namespaced_name(declaration_cursor):
  286. ns_list = build_namespace(declaration_cursor, [])
  287. ns_list.reverse()
  288. ns = "::".join(ns_list)
  289. display_name = declaration_cursor.displayname.replace("::__ndk1", "")
  290. if len(ns) > 0:
  291. ns = ns.replace("::__ndk1", "")
  292. return ns + "::" + display_name
  293. return display_name
  294. def generate_namespace_list(cursor, namespaces=[]):
  295. '''
  296. build the full namespace for a specific cursor
  297. '''
  298. if cursor:
  299. parent = cursor.semantic_parent
  300. if parent:
  301. if parent.kind == cindex.CursorKind.NAMESPACE or parent.kind == cindex.CursorKind.CLASS_DECL:
  302. if parent.kind == cindex.CursorKind.NAMESPACE:
  303. namespaces.append(parent.displayname)
  304. generate_namespace_list(parent, namespaces)
  305. return namespaces
  306. def get_namespace_name(declaration_cursor):
  307. ns_list = generate_namespace_list(declaration_cursor, [])
  308. ns_list.reverse()
  309. ns = "::".join(ns_list)
  310. if len(ns) > 0:
  311. ns = ns.replace("::__ndk1", "")
  312. return ns + "::"
  313. return declaration_cursor.displayname
  314. class NativeType(object):
  315. def __init__(self):
  316. self.is_object = False
  317. self.is_function = False
  318. self.is_enum = False
  319. self.is_numeric = False
  320. self.not_supported = False
  321. self.param_types = []
  322. self.ret_type = None
  323. self.namespaced_name = "" # with namespace and class name
  324. self.namespace_name = "" # only contains namespace
  325. self.name = ""
  326. self.whole_name = None
  327. self.is_const = False
  328. self.is_pointer = False
  329. self.canonical_type = None
  330. @staticmethod
  331. def from_type(ntype):
  332. if ntype.kind == cindex.TypeKind.POINTER:
  333. nt = NativeType.from_type(ntype.get_pointee())
  334. if None != nt.canonical_type:
  335. nt.canonical_type.name += "*"
  336. nt.canonical_type.namespaced_name += "*"
  337. nt.canonical_type.whole_name += "*"
  338. nt.name += "*"
  339. nt.namespaced_name += "*"
  340. nt.whole_name = nt.namespaced_name
  341. nt.is_enum = False
  342. nt.is_const = ntype.get_pointee().is_const_qualified()
  343. nt.is_pointer = True
  344. if nt.is_const:
  345. nt.whole_name = "const " + nt.whole_name
  346. elif ntype.kind == cindex.TypeKind.LVALUEREFERENCE:
  347. nt = NativeType.from_type(ntype.get_pointee())
  348. nt.is_const = ntype.get_pointee().is_const_qualified()
  349. nt.whole_name = nt.namespaced_name + "&"
  350. if nt.is_const:
  351. nt.whole_name = "const " + nt.whole_name
  352. if None != nt.canonical_type:
  353. nt.canonical_type.whole_name += "&"
  354. else:
  355. nt = NativeType()
  356. decl = ntype.get_declaration()
  357. nt.namespaced_name = get_namespaced_name(decl).replace('::__ndk1', '')
  358. if decl.kind == cindex.CursorKind.CLASS_DECL \
  359. and not nt.namespaced_name.startswith('std::function') \
  360. and not nt.namespaced_name.startswith('std::string') \
  361. and not nt.namespaced_name.startswith('std::basic_string'):
  362. nt.is_object = True
  363. displayname = decl.displayname.replace('::__ndk1', '')
  364. nt.name = normalize_type_str(displayname)
  365. nt.namespaced_name = normalize_type_str(nt.namespaced_name)
  366. nt.namespace_name = get_namespace_name(decl)
  367. nt.whole_name = nt.namespaced_name
  368. else:
  369. if decl.kind == cindex.CursorKind.NO_DECL_FOUND:
  370. nt.name = native_name_from_type(ntype)
  371. else:
  372. nt.name = decl.spelling
  373. nt.namespace_name = get_namespace_name(decl)
  374. if len(nt.namespaced_name) > 0:
  375. nt.namespaced_name = normalize_type_str(nt.namespaced_name)
  376. if nt.namespaced_name.startswith("std::function"):
  377. nt.name = "std::function"
  378. if len(nt.namespaced_name) == 0 or nt.namespaced_name.find("::") == -1:
  379. nt.namespaced_name = nt.name
  380. nt.whole_name = nt.namespaced_name
  381. nt.is_const = ntype.is_const_qualified()
  382. if nt.is_const:
  383. nt.whole_name = "const " + nt.whole_name
  384. # Check whether it's a std::function typedef
  385. cdecl = ntype.get_canonical().get_declaration()
  386. if None != cdecl.spelling and 0 == cmp(cdecl.spelling, "function"):
  387. nt.name = "std::function"
  388. if nt.name != INVALID_NATIVE_TYPE and nt.name != "std::string" and nt.name != "std::function":
  389. if ntype.kind == cindex.TypeKind.UNEXPOSED or ntype.kind == cindex.TypeKind.TYPEDEF or ntype.kind == cindex.TypeKind.ELABORATED:
  390. ret = NativeType.from_type(ntype.get_canonical())
  391. if ret.name != "":
  392. if decl.kind == cindex.CursorKind.TYPEDEF_DECL:
  393. ret.canonical_type = nt
  394. return ret
  395. nt.is_enum = ntype.get_canonical().kind == cindex.TypeKind.ENUM
  396. if nt.name == "std::function":
  397. nt.is_object = False
  398. lambda_display_name = get_namespaced_name(cdecl)
  399. lambda_display_name = lambda_display_name.replace("::__ndk1", "")
  400. lambda_display_name = normalize_type_str(lambda_display_name)
  401. nt.namespaced_name = lambda_display_name
  402. r = re.compile('function<([^\s]+).*\((.*)\)>').search(nt.namespaced_name)
  403. (ret_type, params) = r.groups()
  404. params = filter(None, params.split(", "))
  405. nt.is_function = True
  406. nt.ret_type = NativeType.from_string(ret_type)
  407. nt.param_types = [NativeType.from_string(string) for string in params]
  408. # mark argument as not supported
  409. if nt.name == INVALID_NATIVE_TYPE:
  410. nt.not_supported = True
  411. if re.search("(short|int|double|float|long|size_t)$", nt.name) is not None:
  412. nt.is_numeric = True
  413. return nt
  414. @staticmethod
  415. def from_string(displayname):
  416. displayname = displayname.replace(" *", "*")
  417. nt = NativeType()
  418. nt.name = displayname.split("::")[-1]
  419. nt.namespaced_name = displayname
  420. nt.whole_name = nt.namespaced_name
  421. nt.is_object = True
  422. return nt
  423. @property
  424. def lambda_parameters(self):
  425. params = ["%s larg%d" % (str(nt), i) for i, nt in enumerate(self.param_types)]
  426. return ", ".join(params)
  427. @staticmethod
  428. def dict_has_key_re(dict, real_key_list):
  429. for real_key in real_key_list:
  430. for (k, v) in dict.items():
  431. if k.startswith('@'):
  432. k = k[1:]
  433. match = re.match("^" + k + "$", real_key)
  434. if match:
  435. return True
  436. else:
  437. if k == real_key:
  438. return True
  439. return False
  440. @staticmethod
  441. def dict_get_value_re(dict, real_key_list):
  442. for real_key in real_key_list:
  443. for (k, v) in dict.items():
  444. if k.startswith('@'):
  445. k = k[1:]
  446. match = re.match("^" + k + "$", real_key)
  447. if match:
  448. return v
  449. else:
  450. if k == real_key:
  451. return v
  452. return None
  453. @staticmethod
  454. def dict_replace_value_re(dict, real_key_list):
  455. for real_key in real_key_list:
  456. for (k, v) in dict.items():
  457. if k.startswith('@'):
  458. k = k[1:]
  459. match = re.match('.*' + k, real_key)
  460. if match:
  461. return re.sub(k, v, real_key)
  462. else:
  463. if k == real_key:
  464. return v
  465. return None
  466. def from_native(self, convert_opts):
  467. assert(convert_opts.has_key('generator'))
  468. generator = convert_opts['generator']
  469. keys = []
  470. if self.canonical_type != None:
  471. keys.append(self.canonical_type.name)
  472. keys.append(self.name)
  473. from_native_dict = generator.config['conversions']['from_native']
  474. if self.is_object:
  475. if not NativeType.dict_has_key_re(from_native_dict, keys):
  476. keys.append("object")
  477. elif self.is_enum:
  478. keys.append("int")
  479. if NativeType.dict_has_key_re(from_native_dict, keys):
  480. tpl = NativeType.dict_get_value_re(from_native_dict, keys)
  481. tpl = Template(tpl, searchList=[convert_opts])
  482. return str(tpl).rstrip()
  483. return "#pragma warning NO CONVERSION FROM NATIVE FOR " + self.name
  484. def to_native(self, convert_opts):
  485. assert('generator' in convert_opts)
  486. generator = convert_opts['generator']
  487. keys = []
  488. if self.canonical_type != None:
  489. keys.append(self.canonical_type.name)
  490. keys.append(self.name)
  491. to_native_dict = generator.config['conversions']['to_native']
  492. if self.is_object:
  493. if not NativeType.dict_has_key_re(to_native_dict, keys):
  494. keys.append("object")
  495. elif self.is_enum:
  496. keys.append("int")
  497. if self.is_function:
  498. tpl = Template(file=os.path.join(generator.target, "templates", "lambda.c"),
  499. searchList=[convert_opts, self])
  500. indent = convert_opts['level'] * "\t"
  501. return str(tpl).replace("\n", "\n" + indent)
  502. if NativeType.dict_has_key_re(to_native_dict, keys):
  503. tpl = NativeType.dict_get_value_re(to_native_dict, keys)
  504. tpl = Template(tpl, searchList=[convert_opts])
  505. return str(tpl).rstrip()
  506. return "#pragma warning NO CONVERSION TO NATIVE FOR " + self.name + "\n" + convert_opts['level'] * "\t" + "ok = false"
  507. def to_string(self, generator):
  508. conversions = generator.config['conversions']
  509. if conversions.has_key('native_types'):
  510. native_types_dict = conversions['native_types']
  511. if NativeType.dict_has_key_re(native_types_dict, [self.namespaced_name]):
  512. return NativeType.dict_get_value_re(native_types_dict, [self.namespaced_name])
  513. name = self.namespaced_name
  514. to_native_dict = generator.config['conversions']['to_native']
  515. from_native_dict = generator.config['conversions']['from_native']
  516. use_typedef = False
  517. typedef_name = self.canonical_type.name if None != self.canonical_type else None
  518. if None != typedef_name:
  519. if NativeType.dict_has_key_re(to_native_dict, [typedef_name]) or NativeType.dict_has_key_re(from_native_dict, [typedef_name]):
  520. use_typedef = True
  521. if use_typedef and self.canonical_type:
  522. name = self.canonical_type.namespaced_name
  523. return "const " + name if (self.is_pointer and self.is_const) else name
  524. def get_whole_name(self, generator):
  525. conversions = generator.config['conversions']
  526. to_native_dict = conversions['to_native']
  527. from_native_dict = conversions['from_native']
  528. use_typedef = False
  529. name = self.whole_name
  530. typedef_name = self.canonical_type.name if None != self.canonical_type else None
  531. if None != typedef_name:
  532. if NativeType.dict_has_key_re(to_native_dict, [typedef_name]) or NativeType.dict_has_key_re(from_native_dict, [typedef_name]):
  533. use_typedef = True
  534. if use_typedef and self.canonical_type:
  535. name = self.canonical_type.whole_name
  536. to_replace = None
  537. if conversions.has_key('native_types'):
  538. native_types_dict = conversions['native_types']
  539. to_replace = NativeType.dict_replace_value_re(native_types_dict, [name])
  540. if to_replace:
  541. name = to_replace
  542. return name
  543. def object_can_convert(self, generator, is_to_native = True):
  544. if self.is_object:
  545. keys = []
  546. if self.canonical_type != None:
  547. keys.append(self.canonical_type.name)
  548. keys.append(self.name)
  549. if is_to_native:
  550. to_native_dict = generator.config['conversions']['to_native']
  551. if NativeType.dict_has_key_re(to_native_dict, keys):
  552. return True
  553. else:
  554. from_native_dict = generator.config['conversions']['from_native']
  555. if NativeType.dict_has_key_re(from_native_dict, keys):
  556. return True
  557. return False
  558. def __str__(self):
  559. return self.canonical_type.whole_name if None != self.canonical_type else self.whole_name
  560. class NativeField(object):
  561. def __init__(self, cursor):
  562. cursor = cursor.canonical
  563. self.cursor = cursor
  564. self.name = cursor.displayname
  565. self.kind = cursor.type.kind
  566. self.location = cursor.location
  567. member_field_re = re.compile('m_(\w+)')
  568. match = member_field_re.match(self.name)
  569. self.signature_name = self.name
  570. self.ntype = NativeType.from_type(cursor.type)
  571. if match:
  572. self.pretty_name = match.group(1)
  573. else:
  574. self.pretty_name = self.name
  575. @staticmethod
  576. def can_parse(ntype):
  577. native_type = NativeType.from_type(ntype)
  578. if ntype.kind == cindex.TypeKind.UNEXPOSED and native_type.name != "std::string":
  579. return False
  580. return True
  581. def generate_code(self, current_class = None, generator = None):
  582. gen = current_class.generator if current_class else generator
  583. config = gen.config
  584. if config['definitions'].has_key('public_field'):
  585. tpl = Template(config['definitions']['public_field'],
  586. searchList=[current_class, self])
  587. self.signature_name = str(tpl)
  588. tpl = Template(file=os.path.join(gen.target, "templates", "public_field.c"),
  589. searchList=[current_class, self])
  590. gen.impl_file.write(str(tpl))
  591. # return True if found default argument.
  592. def iterate_param_node(param_node, depth=1):
  593. for node in param_node.get_children():
  594. # print(">"*depth+" "+str(node.kind))
  595. if node.kind in default_arg_type_arr:
  596. return True
  597. if iterate_param_node(node, depth + 1):
  598. return True
  599. return False
  600. class NativeFunction(object):
  601. def __init__(self, cursor):
  602. self.cursor = cursor
  603. self.func_name = cursor.spelling
  604. self.signature_name = self.func_name
  605. self.arguments = []
  606. self.argumtntTips = []
  607. self.static = cursor.kind == cindex.CursorKind.CXX_METHOD and cursor.is_static_method()
  608. self.implementations = []
  609. self.is_overloaded = False
  610. self.is_constructor = False
  611. self.not_supported = False
  612. self.is_override = False
  613. self.ret_type = NativeType.from_type(cursor.result_type)
  614. self.comment = self.get_comment(cursor.raw_comment)
  615. # parse the arguments
  616. # if self.func_name == "spriteWithFile":
  617. # pdb.set_trace()
  618. for arg in cursor.get_arguments():
  619. self.argumtntTips.append(arg.spelling)
  620. for arg in cursor.type.argument_types():
  621. nt = NativeType.from_type(arg)
  622. self.arguments.append(nt)
  623. # mark the function as not supported if at least one argument is not supported
  624. if nt.not_supported:
  625. self.not_supported = True
  626. found_default_arg = False
  627. index = -1
  628. for arg_node in self.cursor.get_children():
  629. if arg_node.kind == cindex.CursorKind.CXX_OVERRIDE_ATTR:
  630. self.is_override = True
  631. if arg_node.kind == cindex.CursorKind.PARM_DECL:
  632. index += 1
  633. if iterate_param_node(arg_node):
  634. found_default_arg = True
  635. break
  636. self.min_args = index if found_default_arg else len(self.arguments)
  637. def get_comment(self, comment):
  638. replaceStr = comment
  639. if comment is None:
  640. return ""
  641. regular_replace_list = [
  642. ("(\s)*//!",""),
  643. ("(\s)*//",""),
  644. ("(\s)*/\*\*",""),
  645. ("(\s)*/\*",""),
  646. ("\*/",""),
  647. ("\r\n", "\n"),
  648. ("\n(\s)*\*", "\n"),
  649. ("\n(\s)*@","\n"),
  650. ("\n(\s)*","\n"),
  651. ("\n(\s)*\n", "\n"),
  652. ("^(\s)*\n",""),
  653. ("\n(\s)*$", ""),
  654. ("\n","<br>\n"),
  655. ("\n", "\n-- ")
  656. ]
  657. for item in regular_replace_list:
  658. replaceStr = re.sub(item[0], item[1], replaceStr)
  659. return replaceStr
  660. def generate_code(self, current_class=None, generator=None, is_override=False, is_ctor=False):
  661. self.is_ctor = is_ctor
  662. gen = current_class.generator if current_class else generator
  663. config = gen.config
  664. if not is_ctor:
  665. tpl = Template(file=os.path.join(gen.target, "templates", "function.h"),
  666. searchList=[current_class, self])
  667. if not is_override:
  668. gen.head_file.write(str(tpl))
  669. if self.static:
  670. if config['definitions'].has_key('sfunction'):
  671. tpl = Template(config['definitions']['sfunction'],
  672. searchList=[current_class, self])
  673. self.signature_name = str(tpl)
  674. tpl = Template(file=os.path.join(gen.target, "templates", "sfunction.c"),
  675. searchList=[current_class, self])
  676. else:
  677. if not self.is_constructor:
  678. if config['definitions'].has_key('ifunction'):
  679. tpl = Template(config['definitions']['ifunction'],
  680. searchList=[current_class, self])
  681. self.signature_name = str(tpl)
  682. else:
  683. if config['definitions'].has_key('constructor'):
  684. if not is_ctor:
  685. tpl = Template(config['definitions']['constructor'],
  686. searchList=[current_class, self])
  687. else:
  688. tpl = Template(config['definitions']['ctor'],
  689. searchList=[current_class, self])
  690. self.signature_name = str(tpl)
  691. if self.is_constructor and gen.script_type == "spidermonkey" :
  692. if not is_ctor:
  693. tpl = Template(file=os.path.join(gen.target, "templates", "constructor.c"),
  694. searchList=[current_class, self])
  695. else:
  696. tpl = Template(file=os.path.join(gen.target, "templates", "ctor.c"),
  697. searchList=[current_class, self])
  698. else :
  699. tpl = Template(file=os.path.join(gen.target, "templates", "ifunction.c"),
  700. searchList=[current_class, self])
  701. if not is_override:
  702. gen.impl_file.write(str(tpl))
  703. if not is_ctor:
  704. apidoc_function_script = Template(file=os.path.join(gen.target,
  705. "templates",
  706. "apidoc_function.script"),
  707. searchList=[current_class, self])
  708. if gen.script_type == "spidermonkey":
  709. gen.doc_file.write(str(apidoc_function_script))
  710. else:
  711. if gen.script_type == "lua" and current_class != None :
  712. current_class.doc_func_file.write(str(apidoc_function_script))
  713. class NativeOverloadedFunction(object):
  714. def __init__(self, func_array):
  715. self.implementations = func_array
  716. self.func_name = func_array[0].func_name
  717. self.signature_name = self.func_name
  718. self.min_args = 100
  719. self.is_constructor = False
  720. self.is_overloaded = True
  721. self.is_ctor = False
  722. for m in func_array:
  723. self.min_args = min(self.min_args, m.min_args)
  724. self.comment = self.get_comment(func_array[0].cursor.raw_comment)
  725. def get_comment(self, comment):
  726. replaceStr = comment
  727. if comment is None:
  728. return ""
  729. regular_replace_list = [
  730. ("(\s)*//!",""),
  731. ("(\s)*//",""),
  732. ("(\s)*/\*\*",""),
  733. ("(\s)*/\*",""),
  734. ("\*/",""),
  735. ("\r\n", "\n"),
  736. ("\n(\s)*\*", "\n"),
  737. ("\n(\s)*@","\n"),
  738. ("\n(\s)*","\n"),
  739. ("\n(\s)*\n", "\n"),
  740. ("^(\s)*\n",""),
  741. ("\n(\s)*$", ""),
  742. ("\n","<br>\n"),
  743. ("\n", "\n-- ")
  744. ]
  745. for item in regular_replace_list:
  746. replaceStr = re.sub(item[0], item[1], replaceStr)
  747. return replaceStr
  748. def append(self, func):
  749. self.min_args = min(self.min_args, func.min_args)
  750. self.implementations.append(func)
  751. def generate_code(self, current_class=None, is_override=False, is_ctor=False):
  752. self.is_ctor = is_ctor
  753. gen = current_class.generator
  754. config = gen.config
  755. static = self.implementations[0].static
  756. if not is_ctor:
  757. tpl = Template(file=os.path.join(gen.target, "templates", "function.h"),
  758. searchList=[current_class, self])
  759. if not is_override:
  760. gen.head_file.write(str(tpl))
  761. if static:
  762. if config['definitions'].has_key('sfunction'):
  763. tpl = Template(config['definitions']['sfunction'],
  764. searchList=[current_class, self])
  765. self.signature_name = str(tpl)
  766. tpl = Template(file=os.path.join(gen.target, "templates", "sfunction_overloaded.c"),
  767. searchList=[current_class, self])
  768. else:
  769. if not self.is_constructor:
  770. if config['definitions'].has_key('ifunction'):
  771. tpl = Template(config['definitions']['ifunction'],
  772. searchList=[current_class, self])
  773. self.signature_name = str(tpl)
  774. else:
  775. if config['definitions'].has_key('constructor'):
  776. if not is_ctor:
  777. tpl = Template(config['definitions']['constructor'],
  778. searchList=[current_class, self])
  779. else:
  780. tpl = Template(config['definitions']['ctor'],
  781. searchList=[current_class, self])
  782. self.signature_name = str(tpl)
  783. tpl = Template(file=os.path.join(gen.target, "templates", "ifunction_overloaded.c"),
  784. searchList=[current_class, self])
  785. if not is_override:
  786. gen.impl_file.write(str(tpl))
  787. if current_class != None and not is_ctor:
  788. if gen.script_type == "lua":
  789. apidoc_function_overload_script = Template(file=os.path.join(gen.target,
  790. "templates",
  791. "apidoc_function_overload.script"),
  792. searchList=[current_class, self])
  793. current_class.doc_func_file.write(str(apidoc_function_overload_script))
  794. else:
  795. if gen.script_type == "spidermonkey":
  796. apidoc_function_overload_script = Template(file=os.path.join(gen.target,
  797. "templates",
  798. "apidoc_function_overload.script"),
  799. searchList=[current_class, self])
  800. gen.doc_file.write(str(apidoc_function_overload_script))
  801. class NativeClass(object):
  802. def __init__(self, cursor, generator):
  803. # the cursor to the implementation
  804. self.cursor = cursor
  805. self.class_name = cursor.displayname
  806. self.is_ref_class = self.class_name == "Ref"
  807. self.namespaced_class_name = self.class_name
  808. self.parents = []
  809. self.fields = []
  810. self.public_fields = []
  811. self.methods = {}
  812. self.static_methods = {}
  813. self.generator = generator
  814. self.is_abstract = self.class_name in generator.abstract_classes
  815. self._current_visibility = cindex.AccessSpecifier.PRIVATE
  816. #for generate lua api doc
  817. self.override_methods = {}
  818. self.has_constructor = False
  819. self.namespace_name = ""
  820. registration_name = generator.get_class_or_rename_class(self.class_name)
  821. if generator.remove_prefix:
  822. self.target_class_name = re.sub('^' + generator.remove_prefix, '', registration_name)
  823. else:
  824. self.target_class_name = registration_name
  825. self.namespaced_class_name = get_namespaced_name(cursor)
  826. self.namespace_name = get_namespace_name(cursor)
  827. self.parse()
  828. @property
  829. def underlined_class_name(self):
  830. return self.namespaced_class_name.replace("::", "_")
  831. def parse(self):
  832. '''
  833. parse the current cursor, getting all the necesary information
  834. '''
  835. self._deep_iterate(self.cursor)
  836. def methods_clean(self):
  837. '''
  838. clean list of methods (without the ones that should be skipped)
  839. '''
  840. ret = []
  841. for name, impl in self.methods.iteritems():
  842. should_skip = False
  843. if name == 'constructor':
  844. should_skip = True
  845. else:
  846. if self.generator.should_skip(self.class_name, name):
  847. should_skip = True
  848. if not should_skip:
  849. ret.append({"name": name, "impl": impl})
  850. return ret
  851. def static_methods_clean(self):
  852. '''
  853. clean list of static methods (without the ones that should be skipped)
  854. '''
  855. ret = []
  856. for name, impl in self.static_methods.iteritems():
  857. should_skip = self.generator.should_skip(self.class_name, name)
  858. if not should_skip:
  859. ret.append({"name": name, "impl": impl})
  860. return ret
  861. def override_methods_clean(self):
  862. '''
  863. clean list of override methods (without the ones that should be skipped)
  864. '''
  865. ret = []
  866. for name, impl in self.override_methods.iteritems():
  867. should_skip = self.generator.should_skip(self.class_name, name)
  868. if not should_skip:
  869. ret.append({"name": name, "impl": impl})
  870. return ret
  871. def generate_code(self):
  872. '''
  873. actually generate the code. it uses the current target templates/rules in order to
  874. generate the right code
  875. '''
  876. if not self.is_ref_class:
  877. self.is_ref_class = self._is_ref_class()
  878. config = self.generator.config
  879. prelude_h = Template(file=os.path.join(self.generator.target, "templates", "prelude.h"),
  880. searchList=[{"current_class": self}])
  881. prelude_c = Template(file=os.path.join(self.generator.target, "templates", "prelude.c"),
  882. searchList=[{"current_class": self}])
  883. apidoc_classhead_script = Template(file=os.path.join(self.generator.target,
  884. "templates",
  885. "apidoc_classhead.script"),
  886. searchList=[{"current_class": self}])
  887. if self.generator.script_type == "lua":
  888. docfuncfilepath = os.path.join(self.generator.outdir + "/api", self.class_name + ".lua")
  889. self.doc_func_file = open(docfuncfilepath, "w+")
  890. apidoc_fun_head_script = Template(file=os.path.join(self.generator.target,
  891. "templates",
  892. "apidoc_function_head.script"),
  893. searchList=[{"current_class": self}])
  894. self.doc_func_file.write(str(apidoc_fun_head_script))
  895. self.generator.head_file.write(str(prelude_h))
  896. self.generator.impl_file.write(str(prelude_c))
  897. self.generator.doc_file.write(str(apidoc_classhead_script))
  898. for m in self.methods_clean():
  899. m['impl'].generate_code(self)
  900. for m in self.static_methods_clean():
  901. m['impl'].generate_code(self)
  902. if self.generator.script_type == "lua":
  903. for m in self.override_methods_clean():
  904. m['impl'].generate_code(self, is_override = True)
  905. for m in self.public_fields:
  906. if self.generator.should_bind_field(self.class_name, m.name):
  907. m.generate_code(self)
  908. # generate register section
  909. register = Template(file=os.path.join(self.generator.target, "templates", "register.c"),
  910. searchList=[{"current_class": self}])
  911. apidoc_classfoot_script = Template(file=os.path.join(self.generator.target,
  912. "templates",
  913. "apidoc_classfoot.script"),
  914. searchList=[{"current_class": self}])
  915. self.generator.impl_file.write(str(register))
  916. self.generator.doc_file.write(str(apidoc_classfoot_script))
  917. if self.generator.script_type == "lua":
  918. apidoc_fun_foot_script = Template(file=os.path.join(self.generator.target,
  919. "templates",
  920. "apidoc_function_foot.script"),
  921. searchList=[{"current_class": self}])
  922. self.doc_func_file.write(str(apidoc_fun_foot_script))
  923. self.doc_func_file.close()
  924. def _deep_iterate(self, cursor=None, depth=0):
  925. for node in cursor.get_children():
  926. # print("%s%s - %s" % ("> " * depth, node.displayname, node.kind))
  927. if self._process_node(node):
  928. self._deep_iterate(node, depth + 1)
  929. @staticmethod
  930. def _is_method_in_parents(current_class, method_name):
  931. if len(current_class.parents) > 0:
  932. if method_name in current_class.parents[0].methods:
  933. return True
  934. return NativeClass._is_method_in_parents(current_class.parents[0], method_name)
  935. return False
  936. def _is_ref_class(self, depth = 0):
  937. """
  938. Mark the class as 'cocos2d::Ref' or its subclass.
  939. """
  940. # print ">" * (depth + 1) + " " + self.class_name
  941. for parent in self.parents:
  942. if parent._is_ref_class(depth + 1):
  943. return True
  944. if self.is_ref_class:
  945. return True
  946. return False
  947. def _process_node(self, cursor):
  948. '''
  949. process the node, depending on the type. If returns true, then it will perform a deep
  950. iteration on its children. Otherwise it will continue with its siblings (if any)
  951. @param: cursor the cursor to analyze
  952. '''
  953. if cursor.kind == cindex.CursorKind.CXX_BASE_SPECIFIER:
  954. parent = cursor.get_definition()
  955. parent_name = parent.displayname
  956. if not self.class_name in self.generator.classes_have_no_parents:
  957. if parent_name and parent_name not in self.generator.base_classes_to_skip:
  958. #if parent and self.generator.in_listed_classes(parent.displayname):
  959. if not self.generator.generated_classes.has_key(parent.displayname):
  960. parent = NativeClass(parent, self.generator)
  961. self.generator.generated_classes[parent.class_name] = parent
  962. else:
  963. parent = self.generator.generated_classes[parent.displayname]
  964. self.parents.append(parent)
  965. if parent_name == "Ref":
  966. self.is_ref_class = True
  967. elif cursor.kind == cindex.CursorKind.FIELD_DECL:
  968. self.fields.append(NativeField(cursor))
  969. if self._current_visibility == cindex.AccessSpecifier.PUBLIC and NativeField.can_parse(cursor.type):
  970. self.public_fields.append(NativeField(cursor))
  971. elif cursor.kind == cindex.CursorKind.CXX_ACCESS_SPEC_DECL:
  972. self._current_visibility = cursor.access_specifier
  973. elif cursor.kind == cindex.CursorKind.CXX_METHOD and get_availability(cursor) != AvailabilityKind.DEPRECATED:
  974. # skip if variadic
  975. if self._current_visibility == cindex.AccessSpecifier.PUBLIC and not cursor.type.is_function_variadic():
  976. m = NativeFunction(cursor)
  977. registration_name = self.generator.should_rename_function(self.class_name, m.func_name) or m.func_name
  978. # bail if the function is not supported (at least one arg not supported)
  979. if m.not_supported:
  980. return False
  981. if m.is_override:
  982. if NativeClass._is_method_in_parents(self, registration_name):
  983. if self.generator.script_type == "lua":
  984. if not self.override_methods.has_key(registration_name):
  985. self.override_methods[registration_name] = m
  986. else:
  987. previous_m = self.override_methods[registration_name]
  988. if isinstance(previous_m, NativeOverloadedFunction):
  989. previous_m.append(m)
  990. else:
  991. self.override_methods[registration_name] = NativeOverloadedFunction([m, previous_m])
  992. return False
  993. if m.static:
  994. if not self.static_methods.has_key(registration_name):
  995. self.static_methods[registration_name] = m
  996. else:
  997. previous_m = self.static_methods[registration_name]
  998. if isinstance(previous_m, NativeOverloadedFunction):
  999. previous_m.append(m)
  1000. else:
  1001. self.static_methods[registration_name] = NativeOverloadedFunction([m, previous_m])
  1002. else:
  1003. if not self.methods.has_key(registration_name):
  1004. self.methods[registration_name] = m
  1005. else:
  1006. previous_m = self.methods[registration_name]
  1007. if isinstance(previous_m, NativeOverloadedFunction):
  1008. previous_m.append(m)
  1009. else:
  1010. self.methods[registration_name] = NativeOverloadedFunction([m, previous_m])
  1011. return True
  1012. elif self._current_visibility == cindex.AccessSpecifier.PUBLIC and cursor.kind == cindex.CursorKind.CONSTRUCTOR and not self.is_abstract:
  1013. # Skip copy constructor
  1014. if cursor.displayname == self.class_name + "(const " + self.namespaced_class_name + " &)":
  1015. # print "Skip copy constructor: " + cursor.displayname
  1016. return True
  1017. m = NativeFunction(cursor)
  1018. m.is_constructor = True
  1019. self.has_constructor = True
  1020. if not self.methods.has_key('constructor'):
  1021. self.methods['constructor'] = m
  1022. else:
  1023. previous_m = self.methods['constructor']
  1024. if isinstance(previous_m, NativeOverloadedFunction):
  1025. previous_m.append(m)
  1026. else:
  1027. m = NativeOverloadedFunction([m, previous_m])
  1028. m.is_constructor = True
  1029. self.methods['constructor'] = m
  1030. return True
  1031. # else:
  1032. # print >> sys.stderr, "unknown cursor: %s - %s" % (cursor.kind, cursor.displayname)
  1033. return False
  1034. class Generator(object):
  1035. def __init__(self, opts):
  1036. self.index = cindex.Index.create()
  1037. self.outdir = opts['outdir']
  1038. self.search_path = opts['search_path']
  1039. self.prefix = opts['prefix']
  1040. self.headers = opts['headers'].split(' ')
  1041. self.classes = opts['classes']
  1042. self.classes_need_extend = opts['classes_need_extend']
  1043. self.classes_have_no_parents = opts['classes_have_no_parents'].split(' ')
  1044. self.base_classes_to_skip = opts['base_classes_to_skip'].split(' ')
  1045. self.abstract_classes = opts['abstract_classes'].split(' ')
  1046. self.clang_args = opts['clang_args']
  1047. self.target = opts['target']
  1048. self.remove_prefix = opts['remove_prefix']
  1049. self.target_ns = opts['target_ns']
  1050. self.cpp_ns = opts['cpp_ns']
  1051. self.impl_file = None
  1052. self.head_file = None
  1053. self.skip_classes = {}
  1054. self.bind_fields = {}
  1055. self.generated_classes = {}
  1056. self.rename_functions = {}
  1057. self.rename_classes = {}
  1058. self.replace_headers = {}
  1059. self.out_file = opts['out_file']
  1060. self.script_control_cpp = opts['script_control_cpp'] == "yes"
  1061. self.script_type = opts['script_type']
  1062. self.macro_judgement = opts['macro_judgement']
  1063. self.hpp_headers = opts['hpp_headers']
  1064. self.cpp_headers = opts['cpp_headers']
  1065. self.win32_clang_flags = opts['win32_clang_flags']
  1066. extend_clang_args = []
  1067. for clang_arg in self.clang_args:
  1068. if not os.path.exists(clang_arg.replace("-I","")):
  1069. pos = clang_arg.find("lib/clang/3.3/include")
  1070. if -1 != pos:
  1071. extend_clang_arg = clang_arg.replace("3.3", "3.4")
  1072. if os.path.exists(extend_clang_arg.replace("-I","")):
  1073. extend_clang_args.append(extend_clang_arg)
  1074. if len(extend_clang_args) > 0:
  1075. self.clang_args.extend(extend_clang_args)
  1076. if sys.platform == 'win32' and self.win32_clang_flags != None:
  1077. self.clang_args.extend(self.win32_clang_flags)
  1078. if opts['skip']:
  1079. list_of_skips = re.split(",\n?", opts['skip'])
  1080. for skip in list_of_skips:
  1081. class_name, methods = skip.split("::")
  1082. self.skip_classes[class_name] = []
  1083. match = re.match("\[([^]]+)\]", methods)
  1084. if match:
  1085. self.skip_classes[class_name] = match.group(1).split(" ")
  1086. else:
  1087. raise Exception("invalid list of skip methods")
  1088. if opts['field']:
  1089. list_of_fields = re.split(",\n?", opts['field'])
  1090. for field in list_of_fields:
  1091. class_name, fields = field.split("::")
  1092. self.bind_fields[class_name] = []
  1093. match = re.match("\[([^]]+)\]", fields)
  1094. if match:
  1095. self.bind_fields[class_name] = match.group(1).split(" ")
  1096. else:
  1097. raise Exception("invalid list of bind fields")
  1098. if opts['rename_functions']:
  1099. list_of_function_renames = re.split(",\n?", opts['rename_functions'])
  1100. for rename in list_of_function_renames:
  1101. class_name, methods = rename.split("::")
  1102. self.rename_functions[class_name] = {}
  1103. match = re.match("\[([^]]+)\]", methods)
  1104. if match:
  1105. list_of_methods = match.group(1).split(" ")
  1106. for pair in list_of_methods:
  1107. k, v = pair.split("=")
  1108. self.rename_functions[class_name][k] = v
  1109. else:
  1110. raise Exception("invalid list of rename methods")
  1111. if opts['rename_classes']:
  1112. list_of_class_renames = re.split(",\n?", opts['rename_classes'])
  1113. for rename in list_of_class_renames:
  1114. class_name, renamed_class_name = rename.split("::")
  1115. self.rename_classes[class_name] = renamed_class_name
  1116. if opts['replace_headers']:
  1117. list_of_replace_headers = re.split(",\n?", opts['replace_headers'])
  1118. for replace in list_of_replace_headers:
  1119. header, replaced_header = replace.split("::")
  1120. self.replace_headers[header] = replaced_header
  1121. def should_rename_function(self, class_name, method_name):
  1122. if self.rename_functions.has_key(class_name) and self.rename_functions[class_name].has_key(method_name):
  1123. # print >> sys.stderr, "will rename %s to %s" % (method_name, self.rename_functions[class_name][method_name])
  1124. return self.rename_functions[class_name][method_name]
  1125. return None
  1126. def get_class_or_rename_class(self, class_name):
  1127. if self.rename_classes.has_key(class_name):
  1128. # print >> sys.stderr, "will rename %s to %s" % (method_name, self.rename_functions[class_name][method_name])
  1129. return self.rename_classes[class_name]
  1130. return class_name
  1131. def should_skip(self, class_name, method_name, verbose=False):
  1132. if class_name == "*" and self.skip_classes.has_key("*"):
  1133. for func in self.skip_classes["*"]:
  1134. if re.match(func, method_name):
  1135. return True
  1136. else:
  1137. for key in self.skip_classes.iterkeys():
  1138. if key == "*" or re.match("^" + key + "$", class_name):
  1139. if verbose:
  1140. print "%s in skip_classes" % (class_name)
  1141. if len(self.skip_classes[key]) == 1 and self.skip_classes[key][0] == "*":
  1142. if verbose:
  1143. print "%s will be skipped completely" % (class_name)
  1144. return True
  1145. if method_name != None:
  1146. for func in self.skip_classes[key]:
  1147. if re.match(func, method_name):
  1148. if verbose:
  1149. print "%s will skip method %s" % (class_name, method_name)
  1150. return True
  1151. if verbose:
  1152. print "%s will be accepted (%s, %s)" % (class_name, key, self.skip_classes[key])
  1153. return False
  1154. def should_bind_field(self, class_name, field_name, verbose=False):
  1155. if class_name == "*" and self.bind_fields.has_key("*"):
  1156. for func in self.bind_fields["*"]:
  1157. if re.match(func, method_name):
  1158. return True
  1159. else:
  1160. for key in self.bind_fields.iterkeys():
  1161. if key == "*" or re.match("^" + key + "$", class_name):
  1162. if verbose:
  1163. print "%s in bind_fields" % (class_name)
  1164. if len(self.bind_fields[key]) == 1 and self.bind_fields[key][0] == "*":
  1165. if verbose:
  1166. print "All public fields of %s will be bound" % (class_name)
  1167. return True
  1168. if field_name != None:
  1169. for field in self.bind_fields[key]:
  1170. if re.match(field, field_name):
  1171. if verbose:
  1172. print "Field %s of %s will be bound" % (field_name, class_name)
  1173. return True
  1174. return False
  1175. def in_listed_classes(self, class_name):
  1176. """
  1177. returns True if the class is in the list of required classes and it's not in the skip list
  1178. """
  1179. for key in self.classes:
  1180. md = re.match("^" + key + "$", class_name)
  1181. if md and not self.should_skip(class_name, None):
  1182. return True
  1183. return False
  1184. def in_listed_extend_classed(self, class_name):
  1185. """
  1186. returns True if the class is in the list of required classes that need to extend
  1187. """
  1188. for key in self.classes_need_extend:
  1189. md = re.match("^" + key + "$", class_name)
  1190. if md:
  1191. return True
  1192. return False
  1193. def sorted_classes(self):
  1194. '''
  1195. sorted classes in order of inheritance
  1196. '''
  1197. sorted_list = []
  1198. for class_name in self.generated_classes.iterkeys():
  1199. nclass = self.generated_classes[class_name]
  1200. sorted_list += self._sorted_parents(nclass)
  1201. # remove dupes from the list
  1202. no_dupes = []
  1203. [no_dupes.append(i) for i in sorted_list if not no_dupes.count(i)]
  1204. return no_dupes
  1205. def _sorted_parents(self, nclass):
  1206. '''
  1207. returns the sorted list of parents for a native class
  1208. '''
  1209. sorted_parents = []
  1210. for p in nclass.parents:
  1211. if p.class_name in self.generated_classes.keys():
  1212. sorted_parents += self._sorted_parents(p)
  1213. if nclass.class_name in self.generated_classes.keys():
  1214. sorted_parents.append(nclass.class_name)
  1215. return sorted_parents
  1216. def generate_code(self):
  1217. # must read the yaml file first
  1218. stream = file(os.path.join(self.target, "conversions.yaml"), "r")
  1219. data = yaml.load(stream)
  1220. self.config = data
  1221. implfilepath = os.path.join(self.outdir, self.out_file + ".cpp")
  1222. headfilepath = os.path.join(self.outdir, self.out_file + ".hpp")
  1223. docfiledir = self.outdir + "/api"
  1224. if not os.path.exists(docfiledir):
  1225. os.makedirs(docfiledir)
  1226. if self.script_type == "lua":
  1227. docfilepath = os.path.join(docfiledir, self.out_file + "_api.lua")
  1228. else:
  1229. docfilepath = os.path.join(docfiledir, self.out_file + "_api.js")
  1230. self.impl_file = open(implfilepath, "w+")
  1231. self.head_file = open(headfilepath, "w+")
  1232. self.doc_file = open(docfilepath, "w+")
  1233. layout_h = Template(file=os.path.join(self.target, "templates", "layout_head.h"),
  1234. searchList=[self])
  1235. layout_c = Template(file=os.path.join(self.target, "templates", "layout_head.c"),
  1236. searchList=[self])
  1237. apidoc_ns_script = Template(file=os.path.join(self.target, "templates", "apidoc_ns.script"),
  1238. searchList=[self])
  1239. self.head_file.write(str(layout_h))
  1240. self.impl_file.write(str(layout_c))
  1241. self.doc_file.write(str(apidoc_ns_script))
  1242. self._parse_headers()
  1243. layout_h = Template(file=os.path.join(self.target, "templates", "layout_foot.h"),
  1244. searchList=[self])
  1245. layout_c = Template(file=os.path.join(self.target, "templates", "layout_foot.c"),
  1246. searchList=[self])
  1247. self.head_file.write(str(layout_h))
  1248. self.impl_file.write(str(layout_c))
  1249. if self.script_type == "lua":
  1250. apidoc_ns_foot_script = Template(file=os.path.join(self.target, "templates", "apidoc_ns_foot.script"),
  1251. searchList=[self])
  1252. self.doc_file.write(str(apidoc_ns_foot_script))
  1253. self.impl_file.close()
  1254. self.head_file.close()
  1255. self.doc_file.close()
  1256. def _pretty_print(self, diagnostics):
  1257. errors=[]
  1258. for idx, d in enumerate(diagnostics):
  1259. if d.severity > 2:
  1260. errors.append(d)
  1261. if len(errors) == 0:
  1262. return
  1263. print("====\nErrors in parsing headers:")
  1264. severities=['Ignored', 'Note', 'Warning', 'Error', 'Fatal']
  1265. for idx, d in enumerate(errors):
  1266. print "%s. <severity = %s,\n location = %r,\n details = %r>" % (
  1267. idx+1, severities[d.severity], d.location, d.spelling)
  1268. print("====\n")
  1269. def _parse_headers(self):
  1270. for header in self.headers:
  1271. tu = self.index.parse(header, self.clang_args)
  1272. if len(tu.diagnostics) > 0:
  1273. self._pretty_print(tu.diagnostics)
  1274. is_fatal = False
  1275. for d in tu.diagnostics:
  1276. if d.severity >= cindex.Diagnostic.Error:
  1277. is_fatal = True
  1278. if is_fatal:
  1279. print("*** Found errors - can not continue")
  1280. raise Exception("Fatal error in parsing headers")
  1281. self._deep_iterate(tu.cursor)
  1282. def _deep_iterate(self, cursor, depth=0):
  1283. def get_children_array_from_iter(iter):
  1284. children = []
  1285. for child in iter:
  1286. children.append(child)
  1287. return children
  1288. # get the canonical type
  1289. if cursor.kind == cindex.CursorKind.CLASS_DECL:
  1290. if cursor == cursor.type.get_declaration() and len(get_children_array_from_iter(cursor.get_children())) > 0:
  1291. is_targeted_class = True
  1292. if self.cpp_ns:
  1293. is_targeted_class = False
  1294. namespaced_name = get_namespaced_name(cursor)
  1295. for ns in self.cpp_ns:
  1296. if namespaced_name.startswith(ns):
  1297. is_targeted_class = True
  1298. break
  1299. if is_targeted_class and self.in_listed_classes(cursor.displayname):
  1300. if not self.generated_classes.has_key(cursor.displayname):
  1301. nclass = NativeClass(cursor, self)
  1302. nclass.generate_code()
  1303. self.generated_classes[cursor.displayname] = nclass
  1304. return
  1305. for node in cursor.get_children():
  1306. # print("%s %s - %s" % (">" * depth, node.displayname, node.kind))
  1307. self._deep_iterate(node, depth + 1)
  1308. def scriptname_from_native(self, namespace_class_name, namespace_name):
  1309. script_ns_dict = self.config['conversions']['ns_map']
  1310. for (k, v) in script_ns_dict.items():
  1311. if k == namespace_name:
  1312. return namespace_class_name.replace("*","").replace("const ", "").replace(k, v)
  1313. if namespace_class_name.find("::") >= 0:
  1314. if namespace_class_name.find("std::") == 0:
  1315. return namespace_class_name
  1316. else:
  1317. raise Exception("The namespace (%s) conversion wasn't set in 'ns_map' section of the conversions.yaml" % namespace_class_name)
  1318. else:
  1319. return namespace_class_name.replace("*","").replace("const ", "")
  1320. def is_cocos_class(self, namespace_class_name):
  1321. script_ns_dict = self.config['conversions']['ns_map']
  1322. for (k, v) in script_ns_dict.items():
  1323. if namespace_class_name.find("std::") == 0:
  1324. return False
  1325. if namespace_class_name.find(k) >= 0:
  1326. return True
  1327. return False
  1328. def scriptname_cocos_class(self, namespace_class_name):
  1329. script_ns_dict = self.config['conversions']['ns_map']
  1330. for (k, v) in script_ns_dict.items():
  1331. if namespace_class_name.find(k) >= 0:
  1332. return namespace_class_name.replace("*","").replace("const ", "").replace(k,v)
  1333. raise Exception("The namespace (%s) conversion wasn't set in 'ns_map' section of the conversions.yaml" % namespace_class_name)
  1334. def js_typename_from_natve(self, namespace_class_name):
  1335. script_ns_dict = self.config['conversions']['ns_map']
  1336. if namespace_class_name.find("std::") == 0:
  1337. if namespace_class_name.find("std::string") == 0:
  1338. return "String"
  1339. if namespace_class_name.find("std::vector") == 0:
  1340. return "Array"
  1341. if namespace_class_name.find("std::map") == 0 or namespace_class_name.find("std::unordered_map") == 0:
  1342. return "map_object"
  1343. if namespace_class_name.find("std::function") == 0:
  1344. return "function"
  1345. for (k, v) in script_ns_dict.items():
  1346. if namespace_class_name.find(k) >= 0:
  1347. if namespace_class_name.find("cocos2d::Vec2") == 0:
  1348. return "vec2_object"
  1349. if namespace_class_name.find("cocos2d::Vec3") == 0:
  1350. return "vec3_object"
  1351. if namespace_class_name.find("cocos2d::Vec4") == 0:
  1352. return "vec4_object"
  1353. if namespace_class_name.find("cocos2d::Mat4") == 0:
  1354. return "mat4_object"
  1355. if namespace_class_name.find("cocos2d::Vector") == 0:
  1356. return "Array"
  1357. if namespace_class_name.find("cocos2d::Map") == 0:
  1358. return "map_object"
  1359. if namespace_class_name.find("cocos2d::Point") == 0:
  1360. return "point_object"
  1361. if namespace_class_name.find("cocos2d::Size") == 0:
  1362. return "size_object"
  1363. if namespace_class_name.find("cocos2d::Rect") == 0:
  1364. return "rect_object"
  1365. if namespace_class_name.find("cocos2d::Color3B") == 0:
  1366. return "color3b_object"
  1367. if namespace_class_name.find("cocos2d::Color4B") == 0:
  1368. return "color4b_object"
  1369. if namespace_class_name.find("cocos2d::Color4F") == 0:
  1370. return "color4f_object"
  1371. else:
  1372. return namespace_class_name.replace("*","").replace("const ", "").replace(k,v)
  1373. return namespace_class_name.replace("*","").replace("const ", "")
  1374. def lua_typename_from_natve(self, namespace_class_name, is_ret = False):
  1375. script_ns_dict = self.config['conversions']['ns_map']
  1376. if namespace_class_name.find("std::") == 0:
  1377. if namespace_class_name.find("std::string") == 0:
  1378. return "string"
  1379. if namespace_class_name.find("std::vector") == 0:
  1380. return "array_table"
  1381. if namespace_class_name.find("std::map") == 0 or namespace_class_name.find("std::unordered_map") == 0:
  1382. return "map_table"
  1383. if namespace_class_name.find("std::function") == 0:
  1384. return "function"
  1385. for (k, v) in script_ns_dict.items():
  1386. if namespace_class_name.find(k) >= 0:
  1387. if namespace_class_name.find("cocos2d::Vec2") == 0:
  1388. return "vec2_table"
  1389. if namespace_class_name.find("cocos2d::Vec3") == 0:
  1390. return "vec3_table"
  1391. if namespace_class_name.find("cocos2d::Vec4") == 0:
  1392. return "vec4_table"
  1393. if namespace_class_name.find("cocos2d::Vector") == 0:
  1394. return "array_table"
  1395. if namespace_class_name.find("cocos2d::Mat4") == 0:
  1396. return "mat4_table"
  1397. if namespace_class_name.find("cocos2d::Map") == 0:
  1398. return "map_table"
  1399. if namespace_class_name.find("cocos2d::Point") == 0:
  1400. return "point_table"
  1401. if namespace_class_name.find("cocos2d::Size") == 0:
  1402. return "size_table"
  1403. if namespace_class_name.find("cocos2d::Rect") == 0:
  1404. return "rect_table"
  1405. if namespace_class_name.find("cocos2d::Color3B") == 0:
  1406. return "color3b_table"
  1407. if namespace_class_name.find("cocos2d::Color4B") == 0:
  1408. return "color4b_table"
  1409. if namespace_class_name.find("cocos2d::Color4F") == 0:
  1410. return "color4f_table"
  1411. if is_ret == 1:
  1412. return namespace_class_name.replace("*","").replace("const ", "").replace(k,"")
  1413. else:
  1414. return namespace_class_name.replace("*","").replace("const ", "").replace(k,v)
  1415. return namespace_class_name.replace("*","").replace("const ","")
  1416. def api_param_name_from_native(self,native_name):
  1417. lower_name = native_name.lower()
  1418. if lower_name == "std::string" or lower_name == 'string' or lower_name == 'basic_string' or lower_name == 'std::basic_string':
  1419. return "str"
  1420. if lower_name.find("unsigned ") >= 0 :
  1421. return native_name.replace("unsigned ","")
  1422. if lower_name.find("unordered_map") >= 0 or lower_name.find("map") >= 0:
  1423. return "map"
  1424. if lower_name.find("vector") >= 0 :
  1425. return "array"
  1426. if lower_name == "std::function":
  1427. return "func"
  1428. else:
  1429. return lower_name
  1430. def js_ret_name_from_native(self, namespace_class_name, is_enum) :
  1431. if self.is_cocos_class(namespace_class_name):
  1432. if namespace_class_name.find("cocos2d::Vector") >=0:
  1433. return "new Array()"
  1434. if namespace_class_name.find("cocos2d::Map") >=0:
  1435. return "map_object"
  1436. if is_enum:
  1437. return 0
  1438. else:
  1439. return self.scriptname_cocos_class(namespace_class_name)
  1440. lower_name = namespace_class_name.lower()
  1441. if lower_name.find("unsigned ") >= 0:
  1442. lower_name = lower_name.replace("unsigned ","")
  1443. if lower_name == "std::string":
  1444. return ""
  1445. if lower_name == "char" or lower_name == "short" or lower_name == "int" or lower_name == "float" or lower_name == "double" or lower_name == "long":
  1446. return 0
  1447. if lower_name == "bool":
  1448. return "false"
  1449. if lower_name.find("std::vector") >= 0 or lower_name.find("vector") >= 0:
  1450. return "new Array()"
  1451. if lower_name.find("std::map") >= 0 or lower_name.find("std::unordered_map") >= 0 or lower_name.find("unordered_map") >= 0 or lower_name.find("map") >= 0:
  1452. return "map_object"
  1453. if lower_name == "std::function":
  1454. return "func"
  1455. else:
  1456. return namespace_class_name
  1457. def main():
  1458. from optparse import OptionParser
  1459. parser = OptionParser("usage: %prog [options] {configfile}")
  1460. parser.add_option("-s", action="store", type="string", dest="section",
  1461. help="sets a specific section to be converted")
  1462. parser.add_option("-t", action="store", type="string", dest="target",
  1463. help="specifies the target vm. Will search for TARGET.yaml")
  1464. parser.add_option("-o", action="store", type="string", dest="outdir",
  1465. help="specifies the output directory for generated C++ code")
  1466. parser.add_option("-n", action="store", type="string", dest="out_file",
  1467. help="specifcies the name of the output file, defaults to the prefix in the .ini file")
  1468. (opts, args) = parser.parse_args()
  1469. # script directory
  1470. workingdir = os.path.dirname(inspect.getfile(inspect.currentframe()))
  1471. if len(args) == 0:
  1472. parser.error('invalid number of arguments')
  1473. userconfig = ConfigParser.SafeConfigParser()
  1474. userconfig.read('userconf.ini')
  1475. print 'Using userconfig \n ', userconfig.items('DEFAULT')
  1476. clang_lib_path = os.path.join(userconfig.get('DEFAULT', 'cxxgeneratordir'), 'libclang')
  1477. cindex.Config.set_library_path(clang_lib_path);
  1478. config = ConfigParser.SafeConfigParser()
  1479. config.read(args[0])
  1480. if (0 == len(config.sections())):
  1481. raise Exception("No sections defined in config file")
  1482. sections = []
  1483. if opts.section:
  1484. if (opts.section in config.sections()):
  1485. sections = []
  1486. sections.append(opts.section)
  1487. else:
  1488. raise Exception("Section not found in config file")
  1489. else:
  1490. print("processing all sections")
  1491. sections = config.sections()
  1492. # find available targets
  1493. targetdir = os.path.join(workingdir, "targets")
  1494. targets = []
  1495. if (os.path.isdir(targetdir)):
  1496. targets = [entry for entry in os.listdir(targetdir)
  1497. if (os.path.isdir(os.path.join(targetdir, entry)))]
  1498. if 0 == len(targets):
  1499. raise Exception("No targets defined")
  1500. if opts.target:
  1501. if (opts.target in targets):
  1502. targets = []
  1503. targets.append(opts.target)
  1504. if opts.outdir:
  1505. outdir = opts.outdir
  1506. else:
  1507. outdir = os.path.join(workingdir, "gen")
  1508. if not os.path.exists(outdir):
  1509. os.makedirs(outdir)
  1510. for t in targets:
  1511. # Fix for hidden '.svn', '.cvs' and '.git' etc. folders - these must be ignored or otherwise they will be interpreted as a target.
  1512. if t == ".svn" or t == ".cvs" or t == ".git" or t == ".gitignore":
  1513. continue
  1514. print "\n.... Generating bindings for target", t
  1515. for s in sections:
  1516. print "\n.... .... Processing section", s, "\n"
  1517. gen_opts = {
  1518. 'prefix': config.get(s, 'prefix'),
  1519. 'headers': (config.get(s, 'headers' , 0, dict(userconfig.items('DEFAULT')))),
  1520. 'replace_headers': config.get(s, 'replace_headers') if config.has_option(s, 'replace_headers') else None,
  1521. 'classes': config.get(s, 'classes').split(' '),
  1522. 'classes_need_extend': config.get(s, 'classes_need_extend').split(' ') if config.has_option(s, 'classes_need_extend') else [],
  1523. 'clang_args': (config.get(s, 'extra_arguments', 0, dict(userconfig.items('DEFAULT'))) or "").split(" "),
  1524. 'target': os.path.join(workingdir, "targets", t),
  1525. 'outdir': outdir,
  1526. 'search_path': os.path.abspath(os.path.join(userconfig.get('DEFAULT', 'cocosdir'), 'cocos')),
  1527. 'remove_prefix': config.get(s, 'remove_prefix'),
  1528. 'target_ns': config.get(s, 'target_namespace'),
  1529. 'cpp_ns': config.get(s, 'cpp_namespace').split(' ') if config.has_option(s, 'cpp_namespace') else None,
  1530. 'classes_have_no_parents': config.get(s, 'classes_have_no_parents'),
  1531. 'base_classes_to_skip': config.get(s, 'base_classes_to_skip'),
  1532. 'abstract_classes': config.get(s, 'abstract_classes'),
  1533. 'skip': config.get(s, 'skip'),
  1534. 'field': config.get(s, 'field') if config.has_option(s, 'field') else None,
  1535. 'rename_functions': config.get(s, 'rename_functions'),
  1536. 'rename_classes': config.get(s, 'rename_classes'),
  1537. 'out_file': opts.out_file or config.get(s, 'prefix'),
  1538. 'script_control_cpp': config.get(s, 'script_control_cpp') if config.has_option(s, 'script_control_cpp') else 'no',
  1539. 'script_type': t,
  1540. 'macro_judgement': config.get(s, 'macro_judgement') if config.has_option(s, 'macro_judgement') else None,
  1541. 'hpp_headers': config.get(s, 'hpp_headers', 0, dict(userconfig.items('DEFAULT'))).split(' ') if config.has_option(s, 'hpp_headers') else None,
  1542. 'cpp_headers': config.get(s, 'cpp_headers', 0, dict(userconfig.items('DEFAULT'))).split(' ') if config.has_option(s, 'cpp_headers') else None,
  1543. 'win32_clang_flags': (config.get(s, 'win32_clang_flags', 0, dict(userconfig.items('DEFAULT'))) or "").split(" ") if config.has_option(s, 'win32_clang_flags') else None
  1544. }
  1545. generator = Generator(gen_opts)
  1546. generator.generate_code()
  1547. if __name__ == '__main__':
  1548. try:
  1549. main()
  1550. except Exception as e:
  1551. traceback.print_exc()
  1552. sys.exit(1)