abstractapi.py 41.6 KB
Newer Older
1

François Grisez's avatar
François Grisez committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# Copyright (C) 2017 Belledonne Communications SARL
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

18

19 20
import re
import genapixml as CApi
21
import metaname
22
import logging
23

24

25 26
logger = logging.getLogger(__name__)

27

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
class Error(Exception):
	@property
	def reason(self):
		return self.args[0]
	
	def __str__(self):
		return str(self.reason)
	
	@staticmethod
	def _name_get_type_as_string(name):
		if type(name) is metaname.ClassName:
			return 'class'
		elif type(name) is metaname.EnumName:
			return 'enum'
		elif type(name) is metaname.EnumeratorName:
			return 'enumerator'
		elif type(name) is metaname.MethodName:
			return 'function'
		else:
			raise TypeError('{0} not handled'.format(type(name)))
48

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

class ParsingError(Error):
	@property
	def context(self):
		return self.args[1] if len(self.args) >= 2 else None
	
	def __str__(self):
		if self.context is None:
			return Error.__str__(self)
		else:
			params = {
				'reason': self.reason,
				'name': self.context.to_c(addBrackets=True),
				'type_': Error._name_get_type_as_string(self.context)
			}
			return "error while parsing {name} {type_}: {reason}".format(**params)


class BlacklistedSymbolError(Error):
	@property
	def name(self):
		return self.args[0]
	
	def __str__(self):
		params = {
			'name': self.name.to_c(addBrackets=True),
			'type_': Error._name_get_type_as_string(self.name)
		}
		return "{name} {type_} has been blacklisted".format(**params)


class TranslationError(Error):
81 82
	pass

83

84
class Constant:
85 86 87
	pass


88 89 90
class Nil(Constant):
	def translate(self, langTranslator):
		return langTranslator.nilToken
91 92


93 94 95
class Boolean(Constant):
	def __init__(self, value=False):
		self.value = value
96
	
97 98
	def __bool__(self):
		return self.value
99
	
100 101
	def translate(self, langTranslator):
		return langTranslator.trueConstantToken if self else langTranslator.falseConstantToken
102 103 104 105 106 107


class Object(object):
	def __init__(self, name):
		self.name = name
		self.parent = None
108
		self.deprecated = False
109
	
110 111 112
	def __lt__(self, other):
		return self.name < other.name
	
113 114 115 116 117 118
	def find_first_ancestor_by_type(self, *types, **kargs):
		try:
			priorAncestor = kargs['priorAncestor']
		except KeyError:
			priorAncestor = False

119
		current = self
120
		ancestor = self.parent
121
		while ancestor is not None and type(ancestor) not in types:
122
			current = ancestor
123
			ancestor = ancestor.parent
124
		return ancestor if not priorAncestor else current
125 126 127 128 129 130 131


class Type(Object):
	def __init__(self, name, isconst=False, isref=False):
		Object.__init__(self, name)
		self.isconst = isconst
		self.isref = isref
132
		self.cDecl = None
133 134 135 136 137 138 139


class BaseType(Type):
	def __init__(self, name, isconst=False, isref=False, size=None, isUnsigned=False):
		Type.__init__(self, name, isconst=isconst, isref=isref)
		self.size = size
		self.isUnsigned = isUnsigned
140 141 142
	
	def translate(self, translator, **params):
		return translator.translate_base_type(self, **params)
143 144 145 146 147 148


class EnumType(Type):
	def __init__(self, name, isconst=False, isref=False, enumDesc=None):
		Type.__init__(self, name, isconst=isconst, isref=isref)
		self.desc = enumDesc
149 150 151
	
	def translate(self, translator, **params):
		return translator.translate_enum_type(self, **params)
152 153 154 155 156 157


class ClassType(Type):
	def __init__(self, name, isconst=False, isref=False, classDesc=None):
		Type.__init__(self, name, isconst=isconst, isref=isref)
		self.desc = classDesc
158 159 160
	
	def translate(self, translator, **params):
		return translator.translate_class_type(self, **params)
161 162 163 164 165 166 167 168


class ListType(Type):
	def __init__(self, containedTypeName, isconst=False, isref=False):
		Type.__init__(self, 'list', isconst=isconst, isref=isref)
		self.containedTypeName = containedTypeName
		self._containedTypeDesc = None
	
169 170
	@property
	def containedTypeDesc(self):
171 172
		return self._containedTypeDesc
	
173 174 175 176
	@containedTypeDesc.setter
	def containedTypeDesc(self, desc):
		self._containedTypeDesc = desc
		desc.parent = self
177 178 179
	
	def translate(self, translator, **params):
		return translator.translate_list_type(self, **params)
180 181 182 183 184


class DocumentableObject(Object):
	def __init__(self, name):
		Object.__init__(self, name)
185 186
		self._briefDescription = None
		self._detailedDescription = None
187
	
188 189
	@property
	def briefDescription(self):
190 191
		return self._briefDescription
	
192 193
	@briefDescription.setter
	def briefDescription(self, description):
194 195 196
		self._briefDescription = description
		description.relatedObject = self
	
197 198
	@property
	def detailedDescription(self):
199 200
		return self._detailedDescription
	
201 202
	@detailedDescription.setter
	def detailedDescription(self, description):
203 204 205
		self._detailedDescription = description
		description.relatedObject = self
	
206 207 208 209 210 211 212 213 214 215
	def set_from_c(self, cObject, namespace=None):
		self.briefDescription = cObject.briefDescription
		self.detailedDescription = cObject.detailedDescription
		self.deprecated = cObject.deprecated
		self.parent = namespace
	
	def get_namespace_object(self):
		if isinstance(self, (Namespace,Enum,Class)):
			return self
		elif self.parent is None:
216
			return None
217 218 219 220 221 222 223
		else:
			return self.parent.get_namespace_object()


class Namespace(DocumentableObject):
	def __init__(self, name):
		DocumentableObject.__init__(self, name)
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
		self.enums = []
		self.classes = []
		self.interfaces = []

	def addenum(self, enum):
		Namespace._insert_element(self.enums, enum)
		enum.parent = self

	def delenum(self, enum):
		i = self.enums.index(enum)
		del self.enums[i]
		enum.parent = None

	def addclass(self, class_):
		Namespace._insert_element(self.classes, class_)
		class_.parent = self

	def delclass(self, class_):
		i = self.classes.index(class_)
		del self.classes[i]
		class_.parent = None
245
	
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
	def addinterface(self, interface):
		Namespace._insert_element(self.interfaces, interface)
		interface.parent = self

	def delinterface(self, interface):
		i = self.interfaces.index(interface)
		del self.interfaces[i]
		interface.parent = None

	@staticmethod
	def _insert_element(l, e):
		try:
			inspoint = next(x for x in l if e.name < x.name)
			index = l.index(inspoint)
			l.insert(index, e)
		except StopIteration:
			l.append(e)
263 264


265 266 267
GlobalNs = Namespace('')


268 269 270 271 272
class Flag:
	def __init__(self, position):
		self.position = position


273
class Enumerator(DocumentableObject):
274 275 276 277 278
	def __init__(self, name):
		DocumentableObject.__init__(self, name)
		self.value = None
	
	def value_from_string(self, stringValue):
279
		m = re.match('^\s*1\s*<<\s*([0-9]+)$', stringValue)
280 281 282 283
		if m is not None:
			self.value = Flag(int(m.group(1)))
		else:
			self.value = int(stringValue, base=0)
284 285 286
	
	def translate_value(self, translator):
		return translator.translate_enumerator_value(self.value)
287 288 289 290 291


class Enum(DocumentableObject):
	def __init__(self, name):
		DocumentableObject.__init__(self, name)
292
		self.enumerators = []
293
	
294 295 296
	def add_enumerator(self, enumerator):
		self.enumerators.append(enumerator)
		enumerator.parent = self
297 298 299 300 301 302 303 304 305
	
	def set_from_c(self, cEnum, namespace=None):
		Object.set_from_c(self, cEnum, namespace=namespace)
		
		if 'associatedTypedef' in dir(cEnum):
			name = cEnum.associatedTypedef.name
		else:
			name = cEnum.name
		
306
		self.name = metaname.EnumName()
307 308 309 310
		self.name.prev = None if namespace is None else namespace.name
		self.name.set_from_c(name)
		
		for cEnumValue in cEnum.values:
311
			aEnumValue = Enumerator()
312
			aEnumValue.set_from_c(cEnumValue, namespace=self)
313
			self.add_enumerator(aEnumValue)
314 315 316 317 318 319 320 321 322 323


class Argument(DocumentableObject):
	def __init__(self, name, argType, optional=False, default=None):
		DocumentableObject.__init__(self, name)
		self._type = argType
		argType.parent = self
		self.optional = optional
		self.default = default
	
324 325
	@property
	def type(self):
326 327
		return self._type
	
328 329 330 331
	@type.setter
	def type(self, _type):
		self._type = _type
		_type.parent = self
332 333 334
	
	def translate(self, translator, **params):
		return translator.translate_argument(self, **params)
335 336 337 338 339 340 341 342 343 344


class Method(DocumentableObject):
	class Type:
		Instance = 0,
		Class = 1
	
	def __init__(self, name, type=Type.Instance):
		DocumentableObject.__init__(self, name)
		self.type = type
345
		self.isconst = False
346 347
		self.args = []
		self._returnType = None
348 349 350 351 352
	
	def add_arguments(self, arg):
		self.args.append(arg)
		arg.parent = self
	
353 354
	@property
	def returnType(self):
355 356
		return self._returnType
	
357 358 359 360
	@returnType.setter
	def returnType(self, returnType):
		self._returnType = returnType
		returnType.parent = self
361 362 363
	
	def translate_as_prototype(self, translator, **params):
		return translator.translate_method_as_prototype(self, **params)
364 365 366 367 368 369 370


class Property(DocumentableObject):
	def __init__(self, name):
		DocumentableObject.__init__(self, name)
		self._setter = None
		self._getter = None
371
		self._type = None
372
	
373 374 375 376 377 378
	@property
	def setter(self):
		return self._setter

	@setter.setter
	def setter(self, setter):
379 380 381
		self._setter = setter
		setter.parent = self
	
382 383 384
	@property
	def getter(self):
		return self._getter
385
	
386 387
	@getter.setter
	def getter(self, getter):
388
		self._getter = getter
389 390
		if self._type is None:
			self._type = getter.returnType
391 392 393
		getter.parent = self


394
class Class(Namespace):
395
	def __init__(self, name):
396
		Namespace.__init__(self, name)
397 398 399 400 401
		self.properties = []
		self.instanceMethods = []
		self.classMethods = []
		self._listenerInterface = None
		self.multilistener = False
402
		self.refcountable = False
403

404
	def add_property(self, property):
405
		Namespace._insert_element(self.properties, property)
406 407 408
		property.parent = self
	
	def add_instance_method(self, method):
409
		Namespace._insert_element(self.instanceMethods, method)
410 411 412
		method.parent = self
	
	def add_class_method(self, method):
413
		Namespace._insert_element(self.classMethods, method)
414 415
		method.parent = self
	
416 417
	@property
	def listenerInterface(self):
418 419
		return self._listenerInterface
	
420 421 422 423
	@listenerInterface.setter
	def listenerInterface(self, interface):
		self._listenerInterface = interface
		interface._listenedClass = self
424 425 426 427 428
	
	def sort(self):
		self.properties.sort()
		self.instanceMethods.sort()
		self.classMethods.sort()
429 430


431
class Interface(Namespace):
432
	def __init__(self, name):
433 434 435
		Namespace.__init__(self, name)
		self.instanceMethods = []
		self.classMethods = []
436
		self._listenedClass = None
437 438 439

	def add_instance_methods(self, method):
		self.instanceMethods.append(method)
440
		method.parent = self
441 442 443 444 445

	def add_class_methods(self, method):
		self.classMethods.append(method)
		method.parent = self

446 447
	@property
	def listenedClass(self):
448
		return self._listenedClass
449

450 451
	@listenedClass.setter
	def listenedClass(self, method):
452
		self.instanceMethods.append(method)
453
		method.parent = self
454

455
	def sort(self):
456
		self.instanceMethods.sort()
457 458 459


class CParser(object):
460
	def __init__(self, cProject, classBlAppend=[]):
461
		self.cBaseType = ['void', 'bool_t', 'char', 'short', 'int', 'long', 'size_t', 'time_t', 'float', 'double', 'LinphoneStatus']
462 463
		self.cListType = 'bctbx_list_t'
		self.regexFixedSizeInteger = '^(u?)int(\d?\d)_t$'
464
		self.methodBl = ['ref', 'unref', 'new', 'destroy', 'getCurrentCallbacks', 'setUserData', 'getUserData']
465
		self.functionBl = [
466 467 468 469 470
					   'linphone_factory_create_core', # manually wrapped
					   'linphone_factory_create_core_2', # manually wrapped
					   'linphone_factory_create_core_with_config', # manually wrapped
					   'linphone_factory_create_core_with_config_2', # manually wrapped
					   'linphone_vcard_get_belcard'] # manually wrapped
471

472
		self.classBl = ['LpConfig']  # temporarly blacklisted
473 474
		for bl in classBlAppend:
			self.classBl.append(bl)
475 476 477 478
		
		# list of classes that must be concidered as refcountable even if
		# they are no ref()/unref() methods
		self.forcedRefcountableClasses = ['LinphoneFactory']
479
		
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
		self.enum_relocations = {
			'LinphoneAccountCreatorActivationCodeStatus' : 'LinphoneAccountCreator',
			'LinphoneAccountCreatorDomainStatus'         : 'LinphoneAccountCreator',
			'LinphoneAccountCreatorEmailStatus'          : 'LinphoneAccountCreator',
			'LinphoneAccountCreatorLanguageStatus'       : 'LinphoneAccountCreator',
			'LinphoneAccountCreatorPasswordStatus'       : 'LinphoneAccountCreator',
			'LinphoneAccountCreatorPhoneNumberStatus'    : 'LinphoneAccountCreator',
			'LinphoneAccountCreatorStatus'               : 'LinphoneAccountCreator',
			'LinphoneAccountCreatorTransportStatus'      : 'LinphoneAccountCreator',
			'LinphoneAccountCreatorUsernameStatus'       : 'LinphoneAccountCreator',
			'LinphoneCallDir'                            : 'LinphoneCall',
			'LinphoneCallState'                          : 'LinphoneCall',
			'LinphoneCallStatus'                         : 'LinphoneCall',
			'LinphoneChatRoomState'                      : 'LinphoneChatRoom',
			'LinphoneChatMessageDirection'               : 'LinphoneChatMessage',
			'LinphoneChatMessageState'                   : 'LinphoneChatMessage',
			'LinphoneCoreLogCollectionUploadState'       : 'LinphoneCore',
			'LinphoneEventLogType'                       : 'LinphoneEventLog',
			'LinphoneFriendListStatus'                   : 'LinphoneFriendList',
			'LinphoneFriendListSyncStatus'               : 'LinphoneFriendList',
			'LinphonePlayerState'                        : 'LinphonePlayer',
			'LinphonePresenceActivityType'               : 'LinphonePresenceActivity',
			'LinphoneTunnelMode'                         : 'LinphoneTunnel'
		}

505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
		self.cProject = cProject
		
		self.enumsIndex = {}
		for enum in self.cProject.enums:
			if enum.associatedTypedef is None:
				self.enumsIndex[enum.name] = None
			else:
				self.enumsIndex[enum.associatedTypedef.name] = None
		
		self.classesIndex = {}
		self.interfacesIndex = {}
		for _class in self.cProject.classes:
			if _class.name not in self.classBl:
				if _class.name.endswith('Cbs'):
					self.interfacesIndex[_class.name] = None
				else:
					self.classesIndex[_class.name] = None
		
523 524 525 526 527 528 529 530 531 532 533 534
		self.methodsIndex = {}
		for _class in self.cProject.classes:
			for funcname in _class.classMethods:
				self.methodsIndex[funcname] = None
			for funcname in _class.instanceMethods:
				self.methodsIndex[funcname] = None
			for _property in _class.properties.values():
				if _property.setter is not None:
					self.methodsIndex[_property.setter.name] = None
				if _property.getter is not None:
					self.methodsIndex[_property.getter.name] = None
		
535
		name = metaname.NamespaceName()
536 537 538
		name.from_snake_case('linphone')
		
		self.namespace = Namespace(name)
539
		self._pending_enums = []
540 541
	
	def _is_blacklisted(self, name):
542
		if type(name) is metaname.MethodName:
543
			return name.to_camel_case(lower=True) in self.methodBl or name.to_c() in self.functionBl
544
		elif type(name) is metaname.ClassName:
545 546 547 548 549 550
			return name.to_c() in self.classBl
		else:
			return False
		
	def parse_all(self):
		for enum in self.cProject.enums:
551 552
			try:
				self.parse_enum(enum)
553 554
			except BlacklistedSymbolError as e:
				logger.debug(e)
555
		
556
		for class_ in self.cProject.classes:
557
			try:
558 559 560
				self.parse_class(class_)
			except BlacklistedSymbolError as e:
				logger.debug(e)
561
		
562
		self._treat_pending_enums()
563
		self._clean_all_indexes()
564
		self._fix_all_types()
565
		self._fix_all_docs()
566
	
567 568 569 570 571 572 573 574 575 576 577 578 579 580
	def _treat_pending_enums(self):
		for enum in self._pending_enums:
			try:
				enum_cname = enum.name.to_c()
				parent_cname = self.enum_relocations[enum_cname]
				newparent = self.classesIndex[parent_cname]
				enum.parent.delenum(enum)
				newparent.addenum(enum)
				enum.name.from_c(enum_cname, namespace=newparent.name)
			except KeyError:
				reason = "cannot move the enum inside {0} enum because it doesn't exsist".format(parent_cname)
				raise ParsingError(reason, context=enum.name)
		self._pending_enums = []

581 582 583 584 585 586 587 588 589 590 591 592
	def _clean_all_indexes(self):
		for index in [self.classesIndex, self.interfacesIndex, self.methodsIndex]:
			self._clean_index(index)
	
	def _clean_index(self, index):
		keysToRemove = []
		for key in index.keys():
			if index[key] is None:
				keysToRemove.append(key)
		
		for key in keysToRemove:
			del index[key]
593 594 595 596 597 598 599 600 601 602
	
	def _class_is_refcountable(self, _class):
		if _class.name in self.forcedRefcountableClasses:
			return True
		
		for method in _class.instanceMethods:
			if method.startswith(_class.cFunctionPrefix) and method[len(_class.cFunctionPrefix):] == 'ref':
				return True
		return False
	
603 604 605 606 607 608 609
	def _fix_all_types_in_class_or_interface(self, _class):
		if _class is not None:
			if type(_class) is Class:
				self._fix_all_types_in_class(_class)
			else:
				self._fix_all_types_in_interface(_class)
	
610
	def _fix_all_types(self):
611 612 613 614
		for _class in self.interfacesIndex.values():
			self._fix_all_types_in_class_or_interface(_class)
		for _class in self.classesIndex.values():
			self._fix_all_types_in_class_or_interface(_class)
615 616 617 618
	
	def _fix_all_types_in_class(self, _class):
		for property in _class.properties:
			if property.setter is not None:
619
				self._fix_all_types_in_method(property.setter)
620
			if property.getter is not None:
621
				self._fix_all_types_in_method(property.getter)
622 623
		
		for method in (_class.instanceMethods + _class.classMethods):
624
			self._fix_all_types_in_method(method)
625 626
	
	def _fix_all_types_in_interface(self, interface):
627
		for method in interface.instanceMethods:
628
			self._fix_all_types_in_method(method)
629 630 631
	
	def _fix_all_types_in_method(self, method):
		try:
632
			self._fix_type(method.returnType)
633
			for arg in method.args:
634
				self._fix_type(arg.type)
635 636
		except ParsingError as e:
			raise ParsingError(e, method.name)
637
		
638 639 640 641 642 643
	def _fix_type(self, _type):
		if isinstance(_type, EnumType) and _type.desc is None:
			_type.desc = self.enumsIndex[_type.name]
		elif isinstance(_type, ClassType) and _type.desc is None:
			if _type.name in self.classesIndex:
				_type.desc = self.classesIndex[_type.name]
644
			else:
645 646 647 648 649 650 651 652
				_type.desc = self.interfacesIndex[_type.name]
		elif isinstance(_type, ListType) and _type.containedTypeDesc is None:
			if _type.containedTypeName in self.classesIndex:
				_type.containedTypeDesc = ClassType(_type.containedTypeName, classDesc=self.classesIndex[_type.containedTypeName])
			elif _type.containedTypeName in self.interfacesIndex:
				_type.containedTypeDesc = ClassType(_type.containedTypeName, classDesc=self.interfacesIndex[_type.containedTypeName])
			elif _type.containedTypeName in self.enumsIndex:
				_type.containedTypeDesc = EnumType(_type.containedTypeName, enumDesc=self.enumsIndex[_type.containedTypeName])
653
			else:
654
				if _type.containedTypeName is not None:
655
					_type.containedTypeDesc = self.parse_c_base_type(_type.containedTypeName)
656
				else:
657
					raise ParsingError('bctbx_list_t type without specified contained type')
658
	
659 660
	def _fix_all_docs(self):
		for _class in self.classesIndex.values():
661 662 663 664 665
			self._fix_doc(_class)
		for enum in self.enumsIndex.values():
			self._fix_doc(enum)
			for enumerator in enum.enumerators:
				self._fix_doc(enumerator)
666
		for method in self.methodsIndex.values():
667 668 669 670 671 672 673
			self._fix_doc(method)
	
	def _fix_doc(self, obj):
		if obj.briefDescription is not None:
			obj.briefDescription.resolve_all_references(self)
		if obj.detailedDescription is not None:
			obj.detailedDescription.resolve_all_references(self)
674
	
675
	def parse_enum(self, cenum):
676
		name = metaname.EnumName()
677
		name.from_camel_case(cenum.publicName, namespace=self.namespace.name)
678
		enum = Enum(name)
679
		enum.briefDescription = cenum.briefDoc
680
		enum.detailedDescription = cenum.detailedDoc
681
		self.namespace.addenum(enum)
682 683
		
		for cEnumValue in cenum.values:
684
			valueName = metaname.EnumeratorName()
685
			valueName.from_camel_case(cEnumValue.name, namespace=name)
686
			aEnumValue = Enumerator(valueName)
687
			aEnumValue.briefDescription = cEnumValue.briefDoc
688
			aEnumValue.detailedDescription = cEnumValue.detailedDoc
689 690 691 692
			if cEnumValue.value is not None:
				try:
					aEnumValue.value_from_string(cEnumValue.value)
				except ValueError:
693 694 695 696
					reason = '{0} enum value has an invalid definition ({1})'.format(cEnumValue.name, cEnumValue.value)
					context = metaname.EnumeratorName()
					context.from_camel_case(cEnumValue.name)
					raise ParsingError(reason, context)
697
			enum.add_enumerator(aEnumValue)
698
		
699
		self.enumsIndex[cenum.publicName] = enum
700 701
		if cenum.publicName in self.enum_relocations:
			self._pending_enums.append(enum)
702 703 704 705
		return enum
	
	def parse_class(self, cclass):
		if cclass.name in self.classBl:
706 707 708
			name = metaname.ClassName()
			name.from_snake_case(cclass.name)
			raise BlacklistedSymbolError(name)
709 710
		
		if cclass.name.endswith('Cbs'):
711
			_class = self._parse_listener(cclass)
712
			self.interfacesIndex[cclass.name] = _class
713
			self.namespace.addinterface(_class)
714
		else:
715
			_class = self._parse_class(cclass)
716
			self.classesIndex[cclass.name] = _class
717
			self.namespace.addclass(_class)
718 719 720
		return _class
	
	def _parse_class(self, cclass):
721
		name = metaname.ClassName()
722 723
		name.from_camel_case(cclass.name, namespace=self.namespace.name)
		_class = Class(name)
724
		_class.briefDescription = cclass.briefDoc
725
		_class.detailedDescription = cclass.detailedDoc
726
		_class.refcountable = self._class_is_refcountable(cclass)
727 728 729 730
		
		for cproperty in cclass.properties.values():
			try:
				if cproperty.name != 'callbacks':
731
					absProperty = self._parse_property(cproperty, namespace=name)
732 733 734
					_class.add_property(absProperty)
				else:
					_class.listenerInterface = self.interfacesIndex[cproperty.getter.returnArgument.ctype]
735 736
			except BlacklistedSymbolError as e:
				logger.debug(e)
737 738 739
		
		for cMethod in cclass.instanceMethods.values():
			try:
740
				method = self.parse_method(cMethod, namespace=name)
741 742 743 744 745 746 747 748
				if method.name.to_snake_case() == 'add_callbacks' or method.name.to_snake_case() == 'remove_callbacks':
					if _class.listenerInterface is None or not _class.multilistener:
						_class.multilistener = True
						_class.listenerInterface = self.interfacesIndex[_class.name.to_camel_case(fullName=True) + 'Cbs']
				elif isinstance(method.returnType, ClassType) and method.returnType.name.endswith('Cbs'):
					pass
				else:
					_class.add_instance_method(method)
749 750 751
			except BlacklistedSymbolError as e:
				logger.debug(e)
		
752 753
		for cMethod in cclass.classMethods.values():
			try:
754
				method = self.parse_method(cMethod, type=Method.Type.Class, namespace=name)
755
				_class.add_class_method(method)
756 757
			except BlacklistedSymbolError as e:
				logger.debug(e)
758 759 760 761
		
		return _class
	
	def _parse_property(self, cproperty, namespace=None):
762
		name = metaname.PropertyName()
763 764 765 766 767 768 769
		name.from_snake_case(cproperty.name)
		if (cproperty.setter is not None and len(cproperty.setter.arguments) == 1) or (cproperty.getter is not None and len(cproperty.getter.arguments) == 0):
			methodType = Method.Type.Class
		else:
			methodType = Method.Type.Instance
		aproperty = Property(name)
		if cproperty.setter is not None:
770
			method = self.parse_method(cproperty.setter, namespace=namespace, type=methodType)
771 772
			aproperty.setter = method
		if cproperty.getter is not None:
773
			method = self.parse_method(cproperty.getter, namespace=namespace, type=methodType)
774 775 776 777 778
			aproperty.getter = method
		return aproperty
	
	
	def _parse_listener(self, cclass):
779 780 781 782 783 784 785 786 787 788 789 790 791
		try:
			name = metaname.InterfaceName()
			name.from_camel_case(cclass.name, namespace=self.namespace.name)
			name.words[-1] = 'listener'
			
			listener = Interface(name)
			listener.briefDescription = cclass.briefDoc
			listener.detailedDescription = cclass.detailedDoc
			
			for property in cclass.properties.values():
				if property.name != 'user_data':
					try:
						method = self._parse_listener_property(property, listener, cclass.events)
792
						listener.add_instance_methods(method)
793 794 795 796 797 798 799 800
					except BlacklistedSymbolError as e:
						logger.debug(e)
			
			return listener
		except ParsingError as e:
			context = metaname.ClassName()
			context.from_camel_case(cclass.name)
			raise ParsingError(e, context)
801 802
	
	def _parse_listener_property(self, property, listener, events):
803
		methodName = metaname.MethodName()
804 805 806 807 808 809 810 811 812
		methodName.from_snake_case(property.name)
		methodName.words.insert(0, 'on')
		methodName.prev = listener.name
		
		if property.getter is not None:
			eventName = property.getter.returnArgument.ctype
		elif property.setter is not None and len(property.setter.arguments) == 2:
			eventName = property.setter.arguments[1].ctype
		else:
813
			raise ParsingError('event name for {0} property of {1} listener not found'.format(property.name, listener.name.to_c()))
814 815 816 817
		
		try:
			event = events[eventName]
		except KeyError:
818
			raise ParsingError('invalid event name \'{0}\''.format(eventName))
819 820
		
		method = Method(methodName)
821
		method.returnType = self.parse_type(event.returnArgument)
822
		for arg in event.arguments:
823
			argName = metaname.ArgName()
824
			argName.from_snake_case(arg.name)
825
			argument = Argument(argName, self.parse_type(arg))
826
			method.add_arguments(argument)
827 828
		method.briefDescription = event.briefDoc
		method.detailedDescription = event.detailedDoc
829 830 831 832
		
		return method
	
	def parse_method(self, cfunction, namespace, type=Method.Type.Instance):
833
		name = metaname.MethodName()
834 835
		name.from_snake_case(cfunction.name, namespace=namespace)
		
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
		try:
			if self._is_blacklisted(name):
				raise BlacklistedSymbolError(name)
			
			method = Method(name, type=type)
			method.briefDescription = cfunction.briefDoc
			method.detailedDescription = cfunction.detailedDoc
			method.deprecated = cfunction.deprecated
			method.returnType = self.parse_type(cfunction.returnArgument)
			
			for arg in cfunction.arguments:
				if type == Method.Type.Instance and arg is cfunction.arguments[0]:
					method.isconst = ('const' in arg.completeType.split(' '))
				else:
					aType = self.parse_type(arg)
					argName = metaname.ArgName()
					argName.from_snake_case(arg.name)
					absArg = Argument(argName, aType)
					method.add_arguments(absArg)
			
			self.methodsIndex[cfunction.name] = method
			return method
		except ParsingError as e:
			raise ParsingError(e, name)
860 861 862
	
	def parse_type(self, cType):
		if cType.ctype in self.cBaseType or re.match(self.regexFixedSizeInteger, cType.ctype):
863
			absType = self.parse_c_base_type(cType.completeType)
864 865 866 867
		elif cType.ctype in self.enumsIndex:
			absType = EnumType(cType.ctype, enumDesc=self.enumsIndex[cType.ctype])
		elif cType.ctype in self.classesIndex or cType.ctype in self.interfacesIndex:
			absType = ClassType(cType.ctype)
868
			absType.isconst = cType.completeType.startswith('const ')
869
			absType.isref = cType.completeType.endswith('*')
870 871
		elif cType.ctype == self.cListType:
			absType = ListType(cType.containedType)
872 873
		elif cType.ctype.endswith('Mask'):
			absType = BaseType('integer', isUnsigned=True)
874
		else:
875
			raise ParsingError('Unknown C type \'{0}\''.format(cType.ctype))
876
		
877
		absType.cDecl = cType.completeType
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
		return absType
	
	def parse_c_base_type(self, cDecl):
		declElems = cDecl.split(' ')
		param = {}
		name = None
		for elem in declElems:
			if elem == 'const':
				if name is None:
					param['isconst'] = True
			elif elem == 'unsigned':
				param['isUnsigned'] = True
			elif elem == 'char':
				name = 'character'
			elif elem == 'void':
				name = 'void'
			elif elem == 'bool_t':
				name = 'boolean'
			elif elem in ['short', 'long']:
				param['size'] = elem
			elif elem == 'int':
				name = 'integer'
			elif elem == 'float':
				name = 'floatant'
				param['size'] = 'float'
			elif elem == 'size_t':
				name = 'size'
			elif elem == 'time_t':
				name = 'time'
			elif elem == 'double':
				name = 'floatant'
				if 'size' in param and param['size'] == 'long':
					param['size'] = 'long double'
				else:
					param['size'] = 'double'
913 914
			elif elem == 'LinphoneStatus':
				name = 'status'
915 916 917 918 919 920 921 922 923
			elif elem == '*':
				if name is not None:
					if name == 'character':
						name = 'string'
					elif name == 'string':
						name = 'string_array'
					elif 'isref' not in param or param['isref'] is False:
						param['isref'] = True
					else:
924
						raise ParsingError('Unhandled double-pointer')
925 926 927 928 929 930 931 932 933
			else:
				matchCtx = re.match(self.regexFixedSizeInteger, elem)
				if matchCtx:
					name = 'integer'
					if matchCtx.group(1) == 'u':
						param['isUnsigned'] = True
					
					param['size'] = int(matchCtx.group(2))
					if param['size'] not in [8, 16, 32, 64]:
934
						raise ParsingError('{0} C basic type has an invalid size ({1})'.format(cDecl, param['size']))
935 936 937 938 939
		
		
		if name is not None:
			return BaseType(name, **param)
		else:
940
			raise ParsingError('could not find type in \'{0}\''.format(cDecl))
941 942


943

944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
class Translator:
	instances = {}
	
	@staticmethod
	def get(langCode):
		try:
			if langCode not in Translator.instances:
				className = langCode + 'LangTranslator'
				_class = globals()[className]
				Translator.instances[langCode] = _class()
			
			return Translator.instances[langCode]
		except KeyError:
			raise ValueError("Invalid language code: '{0}'".format(langCode))

François Grisez's avatar
François Grisez committed
959 960 961 962 963 964
	@staticmethod
	def _namespace_to_name_translator_params(namespace):
		return {
			'recursive': True,
			'topAncestor': namespace.name if namespace is not None else None
		}
965

966 967 968 969 970 971 972 973 974 975 976 977

class CLikeLangTranslator(Translator):
	def translate_enumerator_value(self, value):
		if value is None:
			return None
		elif isinstance(value, int):
			return str(value)
		elif isinstance(value, Flag):
			return '1<<{0}'.format(value.position)
		else:
			raise TypeError('invalid enumerator value type: {0}'.format(value))
	
François Grisez's avatar
François Grisez committed
978 979 980 981 982
	def translate_argument(self, argument, hideArgName=False, namespace=None):
		ret = argument.type.translate(self, namespace=namespace)
		if not hideArgName:
			ret += (' ' + argument.name.translate(self.nameTranslator))
		return ret
983 984 985 986 987 988 989 990 991


class CLangTranslator(CLikeLangTranslator):
	def __init__(self):
		self.nameTranslator = metaname.Translator.get('C')
		self.nilToken = 'NULL'
		self.falseConstantToken = 'FALSE'
		self.trueConstantToken = 'TRUE'
	
François Grisez's avatar
François Grisez committed
992
	def translate_base_type(self, _type, **kargs):
993 994
		return _type.cDecl
	
François Grisez's avatar
François Grisez committed
995
	def translate_enum_type(self, _type, **kargs):
996 997
		return _type.cDecl
	
François Grisez's avatar
François Grisez committed
998
	def translate_class_type(self, _type, **kargs):
999 1000
		return _type.cDecl
	
François Grisez's avatar
François Grisez committed
1001
	def translate_list_type(self, _type, **kargs):
1002 1003
		return _type.cDecl
	
François Grisez's avatar
François Grisez committed
1004
	def translate_enumerator_value(self, value, **kargs):
1005 1006 1007 1008 1009 1010 1011 1012 1013
		if value is None:
			return None
		elif isinstance(value, int):
			return str(value)
		elif isinstance(value, Flag):
			return '1<<{0}'.format(value.position)
		else:
			raise TypeError('invalid enumerator value type: {0}'.format(value))
	
François Grisez's avatar
François Grisez committed
1014
	def translate_method_as_prototype(self, method, hideArguments=False, hideArgNames=False, hideReturnType=False, stripDeclarators=False, namespace=None):
1015
		_class = method.find_first_ancestor_by_type(Class,Interface)
François Grisez's avatar
François Grisez committed
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
		params = []
		if not hideArguments:
			params.append('{const}{className} *obj'.format(
				className=_class.name.to_c(),
				const='const ' if method.isconst and not stripDeclarators else ''
			))
			for arg in method.args:
				params.append(arg.translate(self, hideArgName=hideArgNames))
		return '{returnType}{name}({params})'.format(
			returnType=(method.returnType.translate(self) + ' ') if not hideReturnType else '',
1026
			name=method.name.translate(self.nameTranslator),
François Grisez's avatar
François Grisez committed
1027
			params=', '.join(params)
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
		)


class CppLangTranslator(CLikeLangTranslator):
	def __init__(self):
		self.nameTranslator = metaname.Translator.get('Cpp')
		self.nilToken = 'nullptr'
		self.falseConstantToken = 'false'
		self.trueConstantToken = 'true'
		self.ambigousTypes = []
	
François Grisez's avatar
François Grisez committed
1039
	def translate_base_type(self, _type, namespace=None):
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
		if _type.name == 'void':
			if _type.isref:
				return 'void *'
			else:
				return 'void'
		elif _type.name == 'boolean':
			res = 'bool'
		elif _type.name == 'character':
			res = 'char'
		elif _type.name == 'size':
			res = 'size_t'
		elif _type.name == 'time':
			res = 'time_t'
		elif _type.name == 'integer':
			if _type.size is None:
				res = 'int'
			elif isinstance(_type.size, str):
				res = _type.size
			else:
				res = 'int{0}_t'.format(_type.size)
				
		elif _type.name == 'floatant':
			if _type.size is not None and _type.size == 'double':
				res = 'double'
			else:
				res = 'float'
		elif _type.name == 'status':
			res = 'linphone::Status'
		elif _type.name == 'string':
François Grisez's avatar
François Grisez committed
1069
			res = 'std::string'
1070 1071 1072
			if type(_type.parent) is Argument:
				res += ' &'
		elif _type.name == 'string_array':
François Grisez's avatar
François Grisez committed
1073
			res = 'std::list<std::string>'
1074 1075 1076
			if type(_type.parent) is Argument:
				res += ' &'
		else:
1077
			raise TranslationError('\'{0}\' is not a base abstract type'.format(_type.name))
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
		
		if _type.isUnsigned:
			if _type.name == 'integer' and isinstance(_type.size, int):
				res = 'u' + res
			else:
				res = 'unsigned ' + res
		
		if _type.isconst:
			if _type.name not in ['string', 'string_array'] or type(_type.parent) is Argument:
				res = 'const ' + res
		
		if _type.isref:
			res += ' *'
		return res
	
François Grisez's avatar
François Grisez committed
1093
	def translate_enum_type(self, type_, namespace=None):
1094 1095
		if type_.desc is None:
			raise TranslationError('{0} has not been fixed'.format(type_.name))
François Grisez's avatar
François Grisez committed
1096
		return type_.desc.name.translate(self.nameTranslator, **Translator._namespace_to_name_translator_params(namespace))
1097

François Grisez's avatar
François Grisez committed
1098
	def translate_class_type(self, type_, namespace=None):
1099 1100
		if type_.desc is None:
			raise TranslationError('{0} has not been fixed'.format(type_.name))
François Grisez's avatar
François Grisez committed
1101
		res = type_.desc.name.translate(self.nameTranslator, **Translator._namespace_to_name_translator_params(namespace))
1102
		
1103 1104
		if type_.desc.refcountable:
			if type_.isconst:
1105
				res = 'const ' + res
1106
			if type(type_.parent) is Argument:
François Grisez's avatar
François Grisez committed
1107
				return 'const std::shared_ptr<{0}> &'.format(res)
1108
			else:
François Grisez's avatar
François Grisez committed
1109
				return 'std::shared_ptr<{0}>'.format(res)
1110
		else:
1111
			if type(type_.parent) is Argument:
1112 1113 1114 1115
				return 'const {0} &'.format(res)
			else:
				return '{0}'.format(res)
	
François Grisez's avatar
François Grisez committed
1116
	def translate_list_type(self, _type, namespace=None):
1117
		if _type.containedTypeDesc is None:
1118
			raise TranslationError('{0} has not been fixed'.format(_type.containedTypeName))
1119 1120 1121
		elif isinstance(_type.containedTypeDesc, BaseType):
			res = _type.containedTypeDesc.translate(self)
		else:
François Grisez's avatar
François Grisez committed
1122
			res = _type.containedTypeDesc.translate(self, namespace=namespace)
1123 1124
			
		if type(_type.parent) is Argument:
François Grisez's avatar
François Grisez committed
1125
			return 'const std::list<{0}> &'.format(res)
1126
		else:
François Grisez's avatar
François Grisez committed
1127 1128 1129 1130 1131 1132 1133 1134 1135
			return 'std::list<{0}>'.format(res)
	
	def translate_method_as_prototype(self, method, hideArguments=False, hideArgNames=False, hideReturnType=False, stripDeclarators=False, namespace=None):
		argsAsString = ', '.join([arg.translate(self, hideArgName=hideArgNames, namespace=namespace) for arg in method.args]) if not hideArguments else ''
		return '{return_}{name}({args}){const}'.format(
			return_=(method.returnType.translate(self, namespace=namespace) + ' ') if not hideReturnType else '',
			name=method.name.translate(self.nameTranslator, **Translator._namespace_to_name_translator_params(namespace)),
			args=argsAsString,
			const=' const' if method.isconst and not stripDeclarators else ''
1136
		)
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202


class JavaLangTranslator(CLikeLangTranslator):
	def __init__(self):
		self.nameTranslator = metaname.Translator.get('Java')
		self.nilToken = 'null'
		self.falseConstantToken = 'false'
		self.trueConstantToken = 'true'

	def translate_base_type(self, type_, native=False, jni=False, isReturn=False, namespace=None):
		if type_.name == 'string':
			if jni:
				return 'jstring'
			return 'String'
		elif type_.name == 'integer':
			if type_.size is not None and type_.isref:
				if jni:
					return 'jbyteArray'
				return 'byte[]'
			if jni:
				return 'jint'
			return 'int'
		elif type_.name == 'boolean':
			if jni:
				return 'jboolean'
			return 'boolean'
		elif type_.name == 'floatant':
			if jni:
				return 'jfloat'
			return 'float'
		elif type_.name == 'size':
			if jni:
				return 'jint'
			return 'int'
		elif type_.name == 'time':
			if jni:
				return 'jlong'
			return 'long'
		elif type_.name == 'status':
			if jni:
				return 'jint'
			if native:
				return 'int'
			return 'void'
		elif type_.name == 'string_array':
			if jni:
				return 'jobjectArray'
			return 'String[]'
		elif type_.name == 'character':
			if jni:
				return 'jchar'
			return 'char'
		elif type_.name == 'void':
			if isReturn:
				return 'void'
			if jni:
				return 'jobject'
			return 'Object'
		return type_.name

	def translate_enum_type(self, _type, native=False, jni=False, isReturn=False, namespace=None):
		if native:
			return 'int'
		elif jni:
			return 'jint'
		else:
François Grisez's avatar
François Grisez committed
1203
			return _type.desc.name.translate(self.nameTranslator, **Translator._namespace_to_name_translator_params(namespace))
1204 1205 1206 1207

	def translate_class_type(self, _type, native=False, jni=False, isReturn=False, namespace=None):
		if jni:
			return 'jobject'
François Grisez's avatar
François Grisez committed
1208
		return _type.desc.name.translate(self.nameTranslator, **Translator._namespace_to_name_translator_params(namespace))
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221

	def translate_list_type(self, _type, native=False, jni=False, isReturn=False, namespace=None):
		if jni:
			if type(_type.containedTypeDesc) is ClassType:
				return 'jobjectArray'
			elif type(_type.containedTypeDesc) is BaseType:
				if _type.containedTypeDesc.name == 'string':
					return 'jobjectArray'
				return _type.containedTypeDesc.translate(self, jni=True) + 'Array'
			elif type(_type.containedTypeDesc) is EnumType:
				ptrtype = _type.containedTypeDesc.translate(self, native=native)
		ptrtype = ''
		if type(_type.containedTypeDesc) is ClassType:
1222
			ptrtype = _type.containedTypeDesc.translate(self, native=native, namespace=namespace)
1223
		elif type(_type.containedTypeDesc) is BaseType:
1224
			ptrtype = _type.containedTypeDesc.translate(self, native=native, namespace=namespace)
1225
		elif type(_type.containedTypeDesc) is EnumType:
1226
			ptrtype = _type.containedTypeDesc.translate(self, native=native, namespace=namespace)
1227 1228 1229 1230 1231 1232 1233
		else:
			if _type.containedTypeDesc:
				raise Error('translation of bctbx_list_t of ' + _type.containedTypeDesc.name)
			else:
				raise Error('translation of bctbx_list_t of unknow type !')
		return ptrtype + '[]'

François Grisez's avatar
François Grisez committed
1234
	def translate_argument(self, arg, native=False, jni=False, hideArgName=False, namespace=None):
1235
		res = arg.type.translate(self, native=native, jni=jni, namespace=namespace)
François Grisez's avatar
François Grisez committed
1236 1237 1238
		if not hideArgName:
			res += (' ' + arg.name.translate(self.nameTranslator))
		return res
1239

François Grisez's avatar
François Grisez committed
1240 1241 1242 1243 1244 1245
	def translate_method_as_prototype(self, method, hideArguments=False, hideArgNames=False, hideReturnType=False, stripDeclarators=False, namespace=None):
		return '{public}{returnType}{methodName}({arguments})'.format(
			public='public ' if not stripDeclarators else '',
			returnType=(method.returnType.translate(self, isReturn=True, namespace=namespace) + ' ') if not hideReturnType else '',
			methodName=method.name.translate(self.nameTranslator, **Translator._namespace_to_name_translator_params(namespace)),
			arguments=', '.join([arg.translate(self, hideArgName=hideArgNames, namespace=namespace) for arg in method.args]) if not hideArguments else ''
1246 1247
		)

1248 1249 1250 1251 1252 1253 1254 1255

class CSharpLangTranslator(CLikeLangTranslator):
	def __init__(self):
		self.nameTranslator = metaname.Translator.get('CSharp')
		self.nilToken = 'null'
		self.falseConstantToken = 'false'
		self.trueConstantToken = 'true'
	
François Grisez's avatar
François Grisez committed
1256
	def translate_base_type(self, _type, dllImport=True, namespace=None):
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300
		if _type.name == 'void':
				if _type.isref:
					return 'IntPtr'
				return 'void'
		elif _type.name == 'status':
			if dllImport:
				return 'int'
			else:
				return 'void'
		elif _type.name == 'boolean':
			if dllImport:
				res = 'char'
			else:
				res = 'bool'
		elif _type.name == 'integer':
			if _type.isUnsigned:
				res = 'uint'
			else:
				res = 'int'
		elif _type.name == 'string':
			if dllImport:
				if type(_type.parent) is Argument:
					return 'string'
				else:
					res = 'IntPtr' # Return as IntPtr and get string with Marshal.PtrToStringAnsi()
			else:
				return 'string'
		elif _type.name == 'character':
			if _type.isUnsigned:
				res = 'byte'
			else:
				res = 'sbyte'
		elif _type.name == 'time':
			res = 'long' #TODO check
		elif _type.name == 'size':
			res = 'long' #TODO check
		elif _type.name == 'floatant':
			return 'float'
		elif _type.name == 'string_array':
			if dllImport or type(_type.parent) is Argument:
				return 'IntPtr'
			else:
				return 'IEnumerable<string>'
		else:
1301
			raise TranslationError('\'{0}\' is not a base abstract type'.format(_type.name))
1302 1303 1304
		
		return res
	
François Grisez's avatar
François Grisez committed
1305
	def translate_enum_type(self, _type, dllImport=True, namespace=None):
1306 1307 1308
		if dllImport and type(_type.parent) is Argument:
			return 'int'
		else:
François Grisez's avatar
François Grisez committed
1309
			return _type.desc.name.translate(self.nameTranslator, **Translator._namespace_to_name_translator_params(namespace))
1310
	
François Grisez's avatar
François Grisez committed
1311 1312
	def translate_class_type(self, _type, dllImport=True, namespace=None):
		return "IntPtr" if dllImport else _type.desc.name.translate(self.nameTranslator, **Translator._namespace_to_name_translator_params(namespace))
1313
	
François Grisez's avatar
François Grisez committed
1314
	def translate_list_type(self, _type, dllImport=True, namespace=None):
1315 1316 1317 1318 1319 1320 1321
		if dllImport:
			return 'IntPtr'
		else:
			if type(_type.containedTypeDesc) is BaseType:
				if _type.containedTypeDesc.name == 'string':
					return 'IEnumerable<string>'
				else:
1322
					raise TranslationError('translation of bctbx_list_t of basic C types is not supported')
1323
			elif type(_type.containedTypeDesc) is ClassType:
François Grisez's avatar
François Grisez committed
1324
				ptrType = _type.containedTypeDesc.desc.name.translate(self.nameTranslator, **Translator._namespace_to_name_translator_params(namespace))
1325 1326 1327
				return 'IEnumerable<' + ptrType + '>'
			else:
				if _type.containedTypeDesc:
1328
					raise TranslationError('translation of bctbx_list_t of enums')
1329
				else:
1330
					raise TranslationError('translation of bctbx_list_t of unknow type !')
1331
	
François Grisez's avatar
François Grisez committed
1332
	def translate_argument(self, arg, dllImport=True, namespace=None):
1333
		return '{0} {1}'.format(
François Grisez's avatar
François Grisez committed
1334
			arg.type.translate(self, dllImport=dllImport, namespace=None),
1335 1336 1337
			arg.name.translate(self.nameTranslator)
		)
	
François Grisez's avatar
François Grisez committed
1338 1339 1340 1341 1342 1343 1344 1345
	def translate_method_as_prototype(self, method, hideArguments=False, hideArgNames=False, hideReturnType=False, stripDeclarators=False, namespace=None):
		return '{static}{override}{returnType}{name}({args})'.format(
			static     = 'static ' if method.type == Method.Type.Class and not stripDeclarators else '',
			override   = 'override ' if method.name.translate(self.nameTranslator) == 'ToString' and not stripDeclarators else '',
			returnType = (method.returnType.translate(self, dllImport=False, namespace=namespace) + ' ') if not hideReturnType else '',
			name       = method.name.translate(self.nameTranslator, **Translator._namespace_to_name_translator_params(namespace)),
			args       = ', '.join([arg.translate(self, dllImport=False, namespace=namespace) for arg in method.args]) if not hideArguments else ''
		)