1# SPDX-FileCopyrightText: 2020 GNOME Foundation 2# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later 3 4import typing as T 5 6from .. import log 7 8 9class Doc: 10 """A documentation node, pointing to the source code""" 11 def __init__(self, content: str, filename: str, line: int, version: str = None, stability: str = None): 12 self.content = content 13 self.filename = filename 14 self.line = line 15 self.version = version 16 self.stability = stability 17 18 def __str__(self): 19 return self.content 20 21 22class SourcePosition: 23 """A location inside the source code""" 24 def __init__(self, filename: str, line: int): 25 self.filename = filename 26 self.line = line 27 28 def __str__(self): 29 return f'{self.filename}:{self.line}' 30 31 32class Attribute: 33 """A user-defined annotation""" 34 def __init__(self, name: str, value: T.Optional[str]): 35 self.name = name 36 self.value = value 37 38 39class CInclude: 40 """A C include header""" 41 def __init__(self, name: str): 42 self.name = name 43 44 45class Include: 46 """A GIR include""" 47 def __init__(self, name: str, version: str = None): 48 self.name = name 49 self.version = version 50 51 def __str__(self): 52 if self.version is not None: 53 return f"{self.name}-{self.version}" 54 return f"{self.name}" 55 56 def girfile(self) -> str: 57 if self.version is not None: 58 return f"{self.name}-{self.version}.gir" 59 return f"{self.name}.gir" 60 61 62class Package: 63 """Pkg-config containing the library""" 64 def __init__(self, name: str): 65 self.name = name 66 67 68class Info: 69 """Base information for most types""" 70 def __init__(self, introspectable: bool = True, deprecated: T.Optional[str] = None, 71 deprecated_version: T.Optional[str] = None, version: str = None, 72 stability: str = None): 73 self.introspectable = introspectable 74 self.deprecated_msg = deprecated 75 self.deprecated_version = deprecated_version 76 self.version = version 77 self.stability = stability 78 self.attributes: T.Mapping[str, T.Optional[str]] = {} 79 self.doc: T.Optional[Doc] = None 80 self.source_position: T.Optional[SourcePosition] = None 81 82 def add_attribute(self, name: str, value: T.Optional[str] = None) -> None: 83 self.attributes[name] = value 84 85 86class GIRElement: 87 """Base type for elements inside the GIR""" 88 def __init__(self, name: T.Optional[str] = None, namespace: T.Optional[str] = None): 89 self.name = name 90 self.namespace = namespace 91 if self.namespace is None: 92 if self.name is not None and '.' in self.name: 93 self.namespace = self.name.split('.')[0] 94 self.info = Info() 95 96 def set_introspectable(self, introspectable: bool) -> None: 97 """Set whether the symbol is introspectable""" 98 self.info.introspectable = introspectable 99 100 @property 101 def introspectable(self): 102 return self.info.introspectable 103 104 def set_version(self, version: str) -> None: 105 """Set the version of the symbol""" 106 self.info.version = version 107 108 def set_stability(self, stability: str) -> None: 109 """Set the stability of the symbol""" 110 self.info.stability = stability 111 112 @property 113 def stability(self): 114 return self.info.stability 115 116 def set_doc(self, doc: Doc) -> None: 117 """Set the documentation for the element""" 118 self.info.doc = doc 119 120 @property 121 def doc(self): 122 return self.info.doc 123 124 def set_source_position(self, pos: SourcePosition) -> None: 125 """Set the position in the source code for the element""" 126 self.info.source_position = pos 127 128 @property 129 def source_position(self) -> T.Optional[T.Tuple[str, int]]: 130 if self.info.source_position is None: 131 return None 132 return self.info.source_position.filename, self.info.source_position.line 133 134 def set_deprecated(self, doc: T.Optional[str] = None, since_version: T.Optional[str] = None) -> None: 135 """Set the deprecation annotations for the element""" 136 self.info.deprecated_msg = doc 137 self.info.deprecated_version = since_version 138 139 def set_attributes(self, attrs: T.Mapping[str, T.Optional[str]]) -> None: 140 """Add an annotation to the symbol""" 141 for name, value in attrs.items(): 142 self.info.add_attribute(name, value) 143 144 @property 145 def attributes(self) -> T.Mapping[str, T.Optional[str]]: 146 return self.info.attributes 147 148 @property 149 def available_since(self) -> T.Optional[str]: 150 return self.info.version 151 152 @property 153 def deprecated_since(self) -> T.Optional[T.Tuple[str, str]]: 154 if not self.info.deprecated_msg: 155 return None 156 version = self.info.deprecated_version 157 message = self.info.deprecated_msg 158 if message is None: 159 message = "Please do not use it in newly written code" 160 return (version, message) 161 162 163class Type(GIRElement): 164 """Base class for all Type nodes""" 165 def __init__(self, name: str, ctype: T.Optional[str] = None, namespace: T.Optional[str] = None, is_fundamental: bool = False): 166 super().__init__(name=name, namespace=namespace) 167 self.ctype = ctype 168 self.is_fundamental = is_fundamental 169 170 def __eq__(self, other): 171 if isinstance(other, Type): 172 if self.namespace is not None: 173 return self.namespace == other.namespace and self.name == other.name 174 elif self.ctype is not None: 175 return self.name == other.name and self.ctype == other.ctype 176 else: 177 return self.name == other.name 178 elif isinstance(other, str): 179 return self.name == other 180 else: 181 return False 182 183 def __cmp__(self, other): 184 if self.ctype is not None: 185 return self.name == other.name and self.ctype == other.ctype 186 return self.name == other.name 187 188 def __repr__(self): 189 return f"Type({self.fqtn}, {self.ctype})" 190 191 @property 192 def resolved(self): 193 return self.ctype is not None 194 195 @property 196 def base_ctype(self): 197 if self.ctype is None: 198 return None 199 return self.ctype.replace('*', '') 200 201 @property 202 def fqtn(self): 203 if self.is_fundamental: 204 return self.name 205 elif '.' in self.name: 206 return self.name 207 elif self.namespace is not None: 208 return f"{self.namespace}.{self.name}" 209 else: 210 return None 211 212 213class ArrayType(GIRElement): 214 """Base class for Array nodes""" 215 def __init__(self, name: T.Optional[str], value_type: Type, ctype: T.Optional[str] = None, zero_terminated: bool = False, 216 fixed_size: int = -1, length: int = -1): 217 super().__init__(name) 218 self.ctype = ctype 219 self.zero_terminated = zero_terminated 220 self.fixed_size = fixed_size 221 self.length = length 222 self.value_type = value_type 223 self.is_fundamental = False 224 225 226class ListType(GIRElement): 227 """Type class for List nodes""" 228 def __init__(self, name: str, value_type: Type, ctype: str = None): 229 super().__init__(name) 230 self.ctype = ctype 231 self.value_type = value_type 232 self.is_fundamental = False 233 234 235class MapType(GIRElement): 236 """Type class for Map nodes""" 237 def __init__(self, name: str, key_type: Type, value_type: Type, ctype: str = None): 238 super().__init__(name) 239 self.ctype = ctype 240 self.key_type = key_type 241 self.value_type = value_type 242 self.is_fundamental = False 243 244 245class GType: 246 """Base class for GType information""" 247 def __init__(self, type_name: str, get_type: str, type_struct: T.Optional[str] = None): 248 self.type_name = type_name 249 self.get_type = get_type 250 self.type_struct = type_struct 251 252 253class VoidType(Type): 254 def __init__(self): 255 super().__init__(name='none', ctype='void') 256 257 def __str__(self): 258 return "void" 259 260 261class VarArgs(Type): 262 def __init__(self): 263 super().__init__(name='none', ctype='') 264 265 def __str__(self): 266 return "..." 267 268 269class Alias(Type): 270 """Alias to a Type""" 271 def __init__(self, name: str, namespace: str, ctype: str, target: Type): 272 super().__init__(name=name, ctype=ctype, namespace=namespace) 273 self.target = target 274 275 276class Constant(Type): 277 """A constant""" 278 def __init__(self, name: str, namespace: str, ctype: str, target: Type, value: str): 279 super().__init__(name=name, ctype=ctype, namespace=namespace) 280 self.target = target 281 self.value = value 282 283 284class Parameter(GIRElement): 285 """A callable parameter""" 286 def __init__(self, name: str, direction: str, transfer: str, target: Type = None, caller_allocates: bool = False, 287 optional: bool = False, nullable: bool = False, closure: int = -1, destroy: int = -1, 288 scope: str = None): 289 super().__init__(name) 290 self.direction = direction 291 self.transfer = transfer 292 self.caller_allocates = caller_allocates 293 self.optional = optional 294 self.nullable = nullable 295 self.scope = scope 296 self.closure = closure 297 self.destroy = destroy 298 if target is None: 299 self.target: Type = VoidType() 300 else: 301 self.target = target 302 303 304class ReturnValue(GIRElement): 305 """A callable's return value""" 306 def __init__(self, transfer: str, target: Type, nullable: bool = False, closure: int = -1, destroy: int = -1, scope: str = None): 307 super().__init__() 308 self.transfer = transfer 309 self.nullable = nullable 310 self.scope = scope 311 self.closure = closure 312 self.destroy = destroy 313 if target is None: 314 self.target: Type = VoidType() 315 else: 316 self.target = target 317 318 319class Callable(GIRElement): 320 """A callable symbol: function, method, function-macro, ...""" 321 def __init__(self, name: str, namespace: T.Optional[str], identifier: T.Optional[str], throws: bool = False): 322 super().__init__(name=name, namespace=namespace) 323 self.identifier = identifier 324 self.parameters: T.List[Parameter] = [] 325 self.return_value: T.Optional[ReturnValue] = None 326 self.throws: bool = throws 327 self.moved_to: T.Optional[str] = None 328 self.shadows: T.Optional[str] = None 329 self.shadowed_by: T.Optional[str] = None 330 331 def add_parameter(self, param: Parameter) -> None: 332 self.parameters.append(param) 333 334 def set_parameters(self, params: T.List[Parameter]) -> None: 335 self.parameters.extend(params) 336 337 def set_return_value(self, res: ReturnValue) -> None: 338 self.return_value = res 339 340 def set_shadows(self, func: str) -> None: 341 self.shadows = func 342 343 def set_shadowed_by(self, func: str) -> None: 344 self.shadowed_by = func 345 346 def set_moved_to(self, func: str) -> None: 347 self.moved_to = func 348 349 def __contains__(self, param): 350 if isinstance(param, str): 351 for p in self.parameters: 352 if p.name == param: 353 return True 354 elif isinstance(param, Parameter): 355 return param in self.parameters 356 elif isinstance(param, ReturnValue): 357 return param == self.return_value 358 return False 359 360 361class FunctionMacro(Callable): 362 def __init__(self, name: str, namespace: T.Optional[str], identifier: str): 363 super().__init__(name, namespace, identifier) 364 365 366class Function(Callable): 367 def __init__(self, name: str, namespace: T.Optional[str], identifier: str, throws: bool = False): 368 super().__init__(name, namespace, identifier, throws) 369 370 371class Method(Callable): 372 def __init__(self, name: str, identifier: str, instance_param: Parameter, throws: bool = False, 373 set_property: T.Optional[str] = None, get_property: T.Optional[str] = None): 374 super().__init__(name, None, identifier, throws) 375 self.instance_param = instance_param 376 self.set_property = set_property 377 self.get_property = get_property 378 379 def __contains__(self, param): 380 if isinstance(param, Parameter) and param == self.instance_param: 381 return True 382 return super().__contains__(self, param) 383 384 385class VirtualMethod(Callable): 386 def __init__(self, name: str, identifier: str, invoker: str, instance_param: Parameter, throws: bool = False): 387 super().__init__(name, None, identifier, throws) 388 self.instance_param = instance_param 389 self.invoker = invoker 390 391 def __contains__(self, param): 392 if isinstance(param, Parameter) and param == self.instance_param: 393 return True 394 return super().__contains__(self, param) 395 396 397class Callback(Callable): 398 def __init__(self, name: str, namespace: str, ctype: T.Optional[str], throws: bool = False): 399 super().__init__(name=name, namespace=namespace, identifier=None, throws=throws) 400 self.ctype = ctype 401 self.is_fundamental = False 402 403 @property 404 def base_ctype(self): 405 if self.ctype is None: 406 return None 407 return self.ctype.replace('*', '') 408 409 410class Member(GIRElement): 411 """A member in an enumeration, error domain, or bitfield""" 412 def __init__(self, name: str, value: str, identifier: str, nick: str): 413 super().__init__(name) 414 self.value = value 415 self.identifier = identifier 416 self.nick = nick 417 418 419class Enumeration(Type): 420 """An enumeration type""" 421 def __init__(self, name: str, namespace: str, ctype: str, gtype: T.Optional[GType]): 422 super().__init__(name=name, ctype=ctype, namespace=namespace) 423 self.gtype = gtype 424 self.members: T.List[Member] = [] 425 self.functions: T.List[Function] = [] 426 427 def add_member(self, member: Member) -> None: 428 self.members.append(member) 429 430 def add_function(self, function: Function) -> None: 431 self.functions.append(function) 432 433 def set_members(self, members: T.List[Member]) -> None: 434 self.members.extend(members) 435 436 def set_functions(self, functions: T.List[Function]) -> None: 437 self.functions.extend(functions) 438 439 def __contains__(self, member): 440 if isinstance(member, Member): 441 return member in self.members 442 return False 443 444 def __iter__(self): 445 for member in self.members: 446 yield member 447 448 449class BitField(Enumeration): 450 """An enumeration type of bit masks""" 451 def __init__(self, name: str, namespace: str, ctype: str, gtype: T.Optional[GType]): 452 super().__init__(name, namespace, ctype, gtype) 453 454 455class ErrorDomain(Enumeration): 456 """An error domain for GError""" 457 def __init__(self, name: str, namespace: str, ctype: str, gtype: T.Optional[GType], domain: str): 458 super().__init__(name, namespace, ctype, gtype) 459 self.domain = domain 460 461 462class Property(GIRElement): 463 def __init__(self, name: str, transfer: str, target: Type, writable: bool = True, readable: bool = True, construct: bool = False, 464 construct_only: bool = False, setter: T.Optional[str] = None, getter: T.Optional[str] = None): 465 super().__init__(name) 466 self.transfer = transfer 467 self.writable = writable 468 self.readable = readable 469 self.construct = construct 470 self.construct_only = construct_only 471 self.target = target 472 self.setter = setter 473 self.getter = getter 474 475 476class Signal(GIRElement): 477 def __init__(self, name: str, detailed: bool, when: str, action: bool = False, no_hooks: bool = False, no_recurse: bool = False): 478 super().__init__(name) 479 self.detailed = detailed 480 self.when = when 481 self.action = action 482 self.no_hooks = no_hooks 483 self.no_recurse = no_recurse 484 self.parameters: T.List[Parameter] = [] 485 self.return_value: T.Optional[ReturnValue] = None 486 487 def set_parameters(self, params: T.List[Parameter]) -> None: 488 self.parameters.extend(params) 489 490 def set_return_value(self, res: ReturnValue) -> None: 491 self.return_value = res 492 493 494class Field(GIRElement): 495 """A field in a struct or union""" 496 def __init__(self, name: str, target: Type, writable: bool, readable: bool, private: bool = False, bits: int = 0): 497 super().__init__(name) 498 self.target = target 499 self.writable = writable 500 self.readable = readable 501 self.private = private 502 self.bits = bits 503 504 505class Interface(Type): 506 def __init__(self, name: str, namespace: str, ctype: str, symbol_prefix: str, gtype: GType): 507 super().__init__(name=name, ctype=ctype, namespace=namespace) 508 self.symbol_prefix = symbol_prefix 509 self.gtype = gtype 510 self.methods: T.List[Method] = [] 511 self.virtual_methods: T.List[VirtualMethod] = [] 512 self.properties: T.Mapping[str, Property] = {} 513 self.signals: T.Mapping[str, Signal] = {} 514 self.functions: T.List[Function] = [] 515 self.fields: T.List[Field] = [] 516 self.prerequisite: T.Optional[str] = None 517 self.implementations: T.List[Type] = [] 518 519 @property 520 def type_struct(self) -> T.Optional[str]: 521 if self.gtype is not None: 522 return self.gtype.type_struct 523 return self.ctype 524 525 @property 526 def type_func(self) -> str: 527 return self.gtype.get_type 528 529 def set_methods(self, methods: T.List[Method]) -> None: 530 self.methods.extend(methods) 531 532 def set_virtual_methods(self, methods: T.List[VirtualMethod]) -> None: 533 self.virtual_methods.extend(methods) 534 535 def set_properties(self, properties: T.List[Property]) -> None: 536 for p in properties: 537 self.properties[p.name] = p 538 539 def set_signals(self, signals: T.List[Signal]) -> None: 540 for s in signals: 541 self.signals[s.name] = s 542 543 def set_functions(self, functions: T.List[Function]) -> None: 544 self.functions.extend(functions) 545 546 def set_fields(self, fields: T.List[Field]) -> None: 547 self.fields.extend(fields) 548 549 def set_prerequisite(self, prerequisite: str) -> None: 550 self.prerequisite = prerequisite 551 552 553class Class(Type): 554 def __init__(self, name: str, namespace: str, ctype: str, symbol_prefix: str, 555 gtype: GType, parent: T.Optional[Type] = None, 556 abstract: bool = False, fundamental: bool = False, 557 ref_func: T.Optional[str] = None, unref_func: T.Optional[str] = None): 558 super().__init__(name=name, ctype=ctype, namespace=namespace) 559 self.symbol_prefix = symbol_prefix 560 self.parent = parent 561 self.abstract = abstract 562 self.fundamental = fundamental 563 self.ref_func = ref_func 564 self.unref_func = unref_func 565 self.gtype = gtype 566 self.ancestors: T.List[Type] = [] 567 self.implements: T.List[Type] = [] 568 self.constructors: T.List[Function] = [] 569 self.methods: T.List[Method] = [] 570 self.virtual_methods: T.List[VirtualMethod] = [] 571 self.properties: T.Mapping[str, Property] = {} 572 self.signals: T.Mapping[str, Signal] = {} 573 self.functions: T.List[Function] = [] 574 self.fields: T.List[Field] = [] 575 self.callbacks: T.List[Callback] = [] 576 self.descendants: T.List[Type] = [] 577 578 @property 579 def type_struct(self) -> T.Optional[str]: 580 if self.gtype is not None: 581 return self.gtype.type_struct 582 return None 583 584 @property 585 def type_func(self) -> T.Optional[str]: 586 if self.gtype is not None: 587 return self.gtype.get_type 588 return self.ctype 589 590 def set_constructors(self, ctors: T.List[Function]) -> None: 591 self.constructors.extend(ctors) 592 593 def set_methods(self, methods: T.List[Method]) -> None: 594 self.methods.extend(methods) 595 596 def set_virtual_methods(self, methods: T.List[VirtualMethod]) -> None: 597 self.virtual_methods.extend(methods) 598 599 def set_properties(self, properties: T.List[Property]) -> None: 600 for p in properties: 601 self.properties[p.name] = p 602 603 def set_signals(self, signals: T.List[Signal]) -> None: 604 for s in signals: 605 self.signals[s.name] = s 606 607 def set_functions(self, functions: T.List[Function]) -> None: 608 self.functions.extend(functions) 609 610 def set_implements(self, ifaces: T.List[Type]) -> None: 611 self.implements.extend(ifaces) 612 613 def set_fields(self, fields: T.List[Field]) -> None: 614 self.fields.extend(fields) 615 616 617class Boxed(Type): 618 def __init__(self, name: str, namespace: str, symbol_prefix: str, gtype: GType): 619 super().__init__(name=name, ctype=None, namespace=namespace) 620 self.symbol_prefix = symbol_prefix 621 self.gtype = gtype 622 self.functions: T.List[Function] = [] 623 624 def set_functions(self, functions: T.List[Function]) -> None: 625 self.functions.extend(functions) 626 627 628class Record(Type): 629 def __init__(self, name: str, namespace: str, ctype: str, symbol_prefix: str, 630 gtype: T.Optional[GType] = None, struct_for: T.Optional[str] = None, 631 disguised: bool = False): 632 super().__init__(name=name, ctype=ctype, namespace=namespace) 633 self.symbol_prefix = symbol_prefix 634 self.gtype = gtype 635 self.struct_for = struct_for 636 self.disguised = disguised 637 self.constructors: T.List[Function] = [] 638 self.methods: T.List[Method] = [] 639 self.functions: T.List[Function] = [] 640 self.fields: T.List[Field] = [] 641 642 @property 643 def type_struct(self) -> T.Optional[str]: 644 if self.gtype is not None: 645 return self.gtype.type_struct 646 return self.ctype 647 648 @property 649 def type_func(self) -> T.Optional[str]: 650 if self.gtype is not None: 651 return self.gtype.get_type 652 return None 653 654 def set_constructors(self, ctors: T.List[Function]) -> None: 655 self.constructors.extend(ctors) 656 657 def set_methods(self, methods: T.List[Method]) -> None: 658 self.methods.extend(methods) 659 660 def set_functions(self, functions: T.List[Function]) -> None: 661 self.functions.extend(functions) 662 663 def set_fields(self, fields: T.List[Field]) -> None: 664 self.fields.extend(fields) 665 666 667class Union(Type): 668 def __init__(self, name: str, namespace: str, ctype: str, symbol_prefix: str, gtype: T.Optional[GType]): 669 super().__init__(name=name, ctype=ctype, namespace=namespace) 670 self.symbol_prefix = symbol_prefix 671 self.gtype = gtype 672 self.constructors: T.List[Function] = [] 673 self.methods: T.List[Method] = [] 674 self.functions: T.List[Function] = [] 675 self.fields: T.List[Field] = [] 676 677 @property 678 def type_struct(self) -> T.Optional[str]: 679 if self.gtype is not None: 680 return self.gtype.type_struct 681 return self.ctype 682 683 @property 684 def type_func(self) -> T.Optional[str]: 685 if self.gtype is not None: 686 return self.gtype.get_type 687 return None 688 689 def set_constructors(self, ctors: T.List[Function]) -> None: 690 self.constructors.extend(ctors) 691 692 def set_methods(self, methods: T.List[Method]) -> None: 693 self.methods.extend(methods) 694 695 def set_functions(self, functions: T.List[Function]) -> None: 696 self.functions.extend(functions) 697 698 def set_fields(self, fields: T.List[Field]) -> None: 699 self.fields.extend(fields) 700 701 702class Namespace: 703 def __init__(self, name: str, version: str, identifier_prefix: T.List[str] = [], symbol_prefix: T.List[str] = []): 704 self.name = name 705 self.version = version 706 707 self._shared_libraries: T.List[str] = [] 708 709 self._aliases: T.Mapping[str, Alias] = {} 710 self._bitfields: T.Mapping[str, BitField] = {} 711 self._boxeds: T.Mapping[str, Boxed] = {} 712 self._callbacks: T.Mapping[str, Callback] = {} 713 self._classes: T.Mapping[str, Class] = {} 714 self._constants: T.Mapping[str, Constant] = {} 715 self._enumerations: T.Mapping[str, Enumeration] = {} 716 self._error_domains: T.Mapping[str, ErrorDomain] = {} 717 self._functions: T.Mapping[str, Function] = {} 718 self._function_macros: T.Mapping[str, FunctionMacro] = {} 719 self._interfaces: T.Mapping[str, Interface] = {} 720 self._records: T.Mapping[str, Record] = {} 721 self._unions: T.Mapping[str, Union] = {} 722 723 self._symbols: T.Mapping[str, Type] = {} 724 self.repository: T.Optional[Repository] = None 725 726 if identifier_prefix: 727 self.identifier_prefix = identifier_prefix 728 else: 729 self.identifier_prefix = [self.name] 730 if symbol_prefix: 731 self.symbol_prefix = symbol_prefix 732 else: 733 self.symbol_prefix = [self.name.lower()] 734 735 def __str__(self): 736 return f"{self.name}-{self.version}" 737 738 def add_shared_libraries(self, libs: T.List[str]) -> None: 739 self._shared_libraries.extend(libs) 740 741 def get_shared_libraries(self) -> T.List[str]: 742 return self._shared_libraries 743 744 def add_alias(self, alias: Alias) -> None: 745 self._aliases[alias.name] = alias 746 747 def add_enumeration(self, enum: Enumeration) -> None: 748 self._enumerations[enum.name] = enum 749 750 def add_error_domain(self, domain: ErrorDomain) -> None: 751 self._error_domains[domain.name] = domain 752 753 def add_class(self, cls: Class) -> None: 754 self._classes[cls.name] = cls 755 756 def add_constant(self, constant: Constant) -> None: 757 self._constants[constant.name] = constant 758 759 def add_interface(self, interface: Interface) -> None: 760 self._interfaces[interface.name] = interface 761 762 def add_boxed(self, boxed: Boxed) -> None: 763 self._boxeds[boxed.name] = boxed 764 765 def add_record(self, record: Record) -> None: 766 self._records[record.name] = record 767 768 def add_union(self, union: Union) -> None: 769 self._unions[union.name] = union 770 771 def add_function(self, function: Function) -> None: 772 self._functions[function.name] = function 773 774 def add_bitfield(self, bitfield: BitField) -> None: 775 self._bitfields[bitfield.name] = bitfield 776 777 def add_function_macro(self, function: FunctionMacro) -> None: 778 self._function_macros[function.name] = function 779 780 def add_callback(self, callback: Callback) -> None: 781 self._callbacks[callback.name] = callback 782 783 def get_classes(self) -> T.List[Class]: 784 return self._classes.values() 785 786 def get_constants(self) -> T.List[Constant]: 787 return self._constants.values() 788 789 def get_enumerations(self) -> T.List[Enumeration]: 790 return self._enumerations.values() 791 792 def get_error_domains(self) -> T.List[ErrorDomain]: 793 return self._error_domains.values() 794 795 def get_aliases(self) -> T.List[Alias]: 796 return self._aliases.values() 797 798 def get_interfaces(self) -> T.List[Interface]: 799 return self._interfaces.values() 800 801 def get_boxeds(self) -> T.List[Boxed]: 802 return self._boxeds.values() 803 804 def get_records(self) -> T.List[Record]: 805 return self._records.values() 806 807 def get_effective_records(self) -> T.List[Record]: 808 def is_effective(r): 809 if "Private" in r.name and r.disguised: 810 return False 811 if r.struct_for is not None: 812 return False 813 return True 814 815 return [x for x in self._records.values() if is_effective(x)] 816 817 def get_unions(self) -> T.List[Union]: 818 return self._unions.values() 819 820 def get_functions(self) -> T.List[Function]: 821 return self._functions.values() 822 823 def get_bitfields(self) -> T.List[BitField]: 824 return self._bitfields.values() 825 826 def get_function_macros(self) -> T.List[FunctionMacro]: 827 return self._function_macros.values() 828 829 def get_effective_function_macros(self) -> T.List[FunctionMacro]: 830 def is_effective(f, ns): 831 # Lower-case identifiers are an automatic pass 832 if f.name.islower(): 833 return True 834 # Try to eliminate the GObject type macros from the pool 835 t = f.name.split('_') 836 # Skip "is-a" macros 837 if 'IS' in t: 838 return False 839 # Skip "get class/iface" macros 840 if 'GET' in t: 841 return False 842 # Re-assemble into what most likely is a type name 843 s = "".join([x.capitalize() if len(x) > 2 else x for x in t]) 844 # Skip "cast" macros 845 if ns.find_class(s) is not None: 846 return False 847 if ns.find_interface(s) is not None: 848 return False 849 if ns.find_record(s) is not None: 850 return False 851 # Anything that survived at this point is likely a valid function 852 # macro 853 return True 854 855 return [x for x in self._function_macros.values() if is_effective(x, self)] 856 857 def get_callbacks(self) -> T.List[Callback]: 858 return self._callbacks.values() 859 860 def find_class(self, cls: str) -> T.Optional[Class]: 861 return self._classes.get(cls) 862 863 def find_record(self, record: str) -> T.Optional[Record]: 864 return self._records.get(record) 865 866 def find_interface(self, iface: str) -> T.Optional[Interface]: 867 return self._interfaces.get(iface) 868 869 def find_union(self, union: str) -> T.Optional[Union]: 870 return self._unions.get(union) 871 872 def find_enumeration(self, enum: str) -> T.Optional[Enumeration]: 873 return self._enumerations.get(enum) 874 875 def find_bitfield(self, bitfield: str) -> T.Optional[BitField]: 876 return self._bitfields.get(bitfield) 877 878 def find_error_domain(self, domain: str) -> T.Optional[ErrorDomain]: 879 return self._error_domains.get(domain) 880 881 def find_alias(self, alias: str) -> T.Optional[Alias]: 882 return self._aliases.get(alias) 883 884 def find_function(self, func: str) -> T.Optional[Function]: 885 if func in self._functions: 886 return self._functions.get(func) 887 if func in self._function_macros: 888 return self._function_macros.get(func) 889 return None 890 891 def find_real_type(self, name: str) -> T.Optional[Type]: 892 if name in self._aliases: 893 return self._aliases[name] 894 if name in self._bitfields: 895 return self._bitfields[name] 896 if name in self._callbacks: 897 return self._callbacks[name] 898 if name in self._constants: 899 return self._constants[name] 900 if name in self._enumerations: 901 return self._enumerations[name] 902 if name in self._error_domains: 903 return self._error_domains[name] 904 if name in self._classes: 905 return self._classes[name] 906 if name in self._interfaces: 907 return self._interfaces[name] 908 if name in self._records: 909 return self._records[name] 910 if name in self._unions: 911 return self._unions[name] 912 return None 913 914 def find_symbol(self, name: str) -> T.Optional[Type]: 915 return self._symbols.get(name) 916 917 def find_prerequisite_type(self, name: str) -> T.Optional[Type]: 918 if name in self._classes: 919 return self._classes[name] 920 if name in self._interfaces: 921 return self._interfaces[name] 922 return None 923 924 925class Repository: 926 def __init__(self): 927 self.includes: T.Mapping[str, Repository] = {} 928 self.packages: T.List[Package] = [] 929 self.c_includes: T.List[CInclude] = [] 930 self.types: T.Mapping[str, T.List[Type]] = {} 931 self._namespaces: T.List[Namespace] = [] 932 self.girfile: T.Optional[str] = None 933 934 def add_namespace(self, ns: Namespace) -> None: 935 self._namespaces.append(ns) 936 ns.repository = self 937 938 def get_namespace(self, ns: str) -> T.Optional[Namespace]: 939 for namespace in self._namespaces: 940 if namespace.name == ns: 941 return namespace 942 return None 943 944 def find_included_namespace(self, ns: str) -> T.Optional[Namespace]: 945 for repo_name in self.includes: 946 repo = self.includes[repo_name] 947 if repo.namespace.name == ns: 948 return repo.namespace 949 return None 950 951 def _lookup_type(self, name: str) -> T.Optional[Type]: 952 types = self.types.get(name) 953 if types is None: 954 return None 955 for t in types: 956 if t.resolved: 957 return t 958 return types[0] 959 960 def resolve_empty_ctypes(self, seen_types: T.Mapping[str, T.List[Type]]) -> None: 961 for fqtn in seen_types: 962 types = seen_types[fqtn] 963 resolved_types = [t for t in types if t.resolved] 964 if len(resolved_types) == 0: 965 ns, name = fqtn.split('.', 1) 966 backstop = f"{self.namespace.identifier_prefix[0]}{name}" 967 resolved_types.append(Type(fqtn, backstop)) 968 self.types[fqtn] = resolved_types 969 log.debug(f"Type: {fqtn}: {resolved_types}") 970 971 def resolve_interface_requires(self) -> None: 972 def find_prerequisite_type(includes, ns, name): 973 repository = includes.get(ns) 974 if repository is None: 975 return None 976 prereq = repository.namespace.find_prerequisite_type(name) 977 # If the prerequisite type is unqualified, then we qualify it here 978 if '.' not in prereq.name: 979 prereq.name = f"{repository.namespace.name}.{prereq.name}" 980 return prereq 981 982 ifaces = self.namespace.get_interfaces() 983 for iface in ifaces: 984 if iface.prerequisite is None: 985 continue 986 prerequisite = None 987 if '.' in iface.prerequisite.name: 988 ns, name = iface.prerequisite.name.split('.', 1) 989 if ns == self.namespace.name: 990 prerequisite = self.namespace.find_prerequisite_type(name) 991 else: 992 prerequisite = find_prerequisite_type(self.includes, ns, name) 993 else: 994 prerequisite = self.namespace.find_prerequisite_type(iface.prerequisite.name) 995 if prerequisite is not None: 996 if prerequisite.ctype is None: 997 if '.' not in prerequisite.name: 998 name = f"{self.namespace.name}.{prerequisite.name}" 999 else: 1000 name = prerequisite.name 1001 t = self._lookup_type(name) 1002 if t is not None: 1003 prerequisite.ctype = t.ctype 1004 else: 1005 # This is kind of a kludge, but apparently we can get into 1006 # class definitions missing a c:type; if that happens, we 1007 # take the identifier prefix of the namespace and append the 1008 # class name, because that's the inverse of how g-ir-scanner 1009 # determines the class name 1010 prerequisite.ctype = f"{self.namespace.identifier_prefix[0]}{prerequisite.name}" 1011 iface.prerequisite = prerequisite 1012 log.debug(f"Prerequisite type for interface {iface}: {iface.prerequisite}") 1013 1014 def resolve_class_ctype(self) -> None: 1015 classes = self.namespace.get_classes() 1016 for cls in classes: 1017 if cls.ctype is None: 1018 if '.' not in cls.name: 1019 name = f"{self.namespace.name}.{cls.name}" 1020 else: 1021 name = cls.name 1022 t = self._lookup_type(name) 1023 if t is not None: 1024 cls.ctype = t.base_ctype 1025 else: 1026 # This is kind of a kludge, but apparently we can get into 1027 # class definitions missing a c:type; if that happens, we 1028 # take the identifier prefix of the namespace and append the 1029 # class name, because that's the inverse of how g-ir-scanner 1030 # determines the class name 1031 cls.ctype = f"{self.namespace.identifier_prefix[0]}{cls.name}" 1032 log.debug(f"Updated C type for {cls}") 1033 1034 def resolve_class_implements(self) -> None: 1035 def find_interface_type(includes, ns, name): 1036 repository = includes.get(ns) 1037 if repository is None: 1038 return None 1039 iface = repository.namespace.find_interface(name) 1040 # If the interface type is unqualified, then we qualify it here 1041 if '.' not in iface.name: 1042 iface.name = f"{repository.namespace.name}.{iface.name}" 1043 return iface 1044 1045 classes = self.namespace.get_classes() 1046 for cls in classes: 1047 if cls.implements is None: 1048 continue 1049 implements = cls.implements 1050 cls.implements = [] 1051 for iface in implements: 1052 if '.' in iface.name: 1053 ns, name = iface.name.split('.', 1) 1054 if ns == self.namespace.name: 1055 iface_type = self.namespace.find_interface(name) 1056 else: 1057 iface_type = find_interface_type(self.includes, ns, name) 1058 else: 1059 iface_type = self.namespace.find_interface(iface.name) 1060 if iface_type is not None: 1061 if iface_type.ctype is None: 1062 t = self._lookup_type(iface_type.name) 1063 iface_type.ctype = t.ctype 1064 cls.implements.append(iface_type) 1065 log.debug(f"Interfaces implemented by {cls}: {cls.implements}") 1066 1067 def resolve_class_ancestors(self) -> None: 1068 def find_parent_class(includes, ns, name): 1069 repository = includes.get(ns) 1070 if repository is None: 1071 return None 1072 parent_class = repository.namespace.find_class(name) 1073 # If the parent type is unqualified, then we qualify it here 1074 if '.' not in parent_class.name: 1075 parent_class.name = f"{repository.namespace.name}.{parent_class.name}" 1076 return parent_class 1077 1078 classes = self.namespace.get_classes() 1079 for cls in classes: 1080 if cls.parent is None: 1081 continue 1082 ancestors = [] 1083 parent = cls.parent 1084 while parent is not None: 1085 if '.' in parent.name: 1086 ns, name = parent.name.split('.') 1087 if ns == self.namespace.name: 1088 real_parent = self.namespace.find_class(name) 1089 else: 1090 real_parent = find_parent_class(self.includes, ns, name) 1091 else: 1092 real_parent = self.namespace.find_class(parent.name) 1093 if real_parent is None: 1094 break 1095 if real_parent.parent is not None and real_parent.parent.name == parent.name: 1096 log.warning(f"Found a loop in the ancestors for {cls}: {real_parent} matches {parent}") 1097 break 1098 if real_parent.ctype is None: 1099 log.debug(f"Looking up C type for {parent.fqtn}") 1100 t = self._lookup_type(parent.name) 1101 real_parent.ctype = t.ctype 1102 log.debug(f"Adding ancestor {real_parent} for {cls}") 1103 ancestors.append(real_parent) 1104 parent = real_parent.parent 1105 cls.ancestors = ancestors 1106 cls.parent = ancestors[0] 1107 log.debug(f"Ancestors for {cls}: parent: {cls.parent}, ancestors: {cls.ancestors}") 1108 1109 def resolve_class_descendants(self) -> None: 1110 seen_parents = {} 1111 for cls in self.namespace.get_classes(): 1112 if cls.parent is not None: 1113 seen_parents.setdefault(cls.parent.name, []).append(cls) 1114 for name, descendants in seen_parents.items(): 1115 if name in self.namespace._classes: 1116 self.namespace._classes[name].descendants = descendants 1117 1118 def resolve_moved_to(self) -> None: 1119 functions = list(self.namespace.get_functions()) 1120 old_len = len(functions) 1121 for func in functions[:]: 1122 if func.moved_to is None: 1123 continue 1124 moved_type, moved_func_name = func.moved_to.split('.') 1125 real_type = self.namespace.find_real_type(moved_type) 1126 if real_type is None: 1127 continue 1128 self.namespace._functions.pop(func.name) # XXX: Add accessor 1129 new_len = len(self.namespace._functions) 1130 diff = old_len - new_len 1131 log.debug(f"Removed {old_len} - {new_len} functions: {diff}") 1132 1133 def resolve_symbols(self) -> None: 1134 symbols: T.Mapping[str, Type] = {} 1135 for func in self.namespace.get_functions(): 1136 symbols[func.identifier] = func 1137 for func in self.namespace.get_function_macros(): 1138 symbols[func.identifier] = func 1139 for cls in self.namespace.get_classes(): 1140 for m in cls.constructors: 1141 symbols[m.identifier] = cls 1142 for m in cls.methods: 1143 symbols[m.identifier] = cls 1144 for m in cls.functions: 1145 symbols[m.identifier] = cls 1146 for iface in self.namespace.get_interfaces(): 1147 for m in iface.methods: 1148 symbols[m.identifier] = iface 1149 for m in iface.functions: 1150 symbols[m.identifier] = iface 1151 for record in self.namespace.get_records(): 1152 for m in record.constructors: 1153 symbols[m.identifier] = record 1154 for m in record.methods: 1155 symbols[m.identifier] = record 1156 for m in record.functions: 1157 symbols[m.identifier] = record 1158 for union in self.namespace.get_unions(): 1159 for m in union.constructors: 1160 symbols[m.identifier] = union 1161 for m in union.methods: 1162 symbols[m.identifier] = union 1163 for m in union.functions: 1164 symbols[m.identifier] = union 1165 self.namespace._symbols = symbols 1166 1167 def resolve_interface_implementations(self) -> None: 1168 seen_impls = {} 1169 for iface in self.namespace.get_interfaces(): 1170 for cls in self.namespace.get_classes(): 1171 if cls.implements is None: 1172 continue 1173 if iface in cls.implements: 1174 seen_impls.setdefault(iface.name, []).append(cls) 1175 for iface, seen in seen_impls.items(): 1176 if iface in self.namespace._interfaces: 1177 self.namespace._interfaces[iface].implementations = seen 1178 1179 def get_class_hierarchy(self, root=None): 1180 flat_tree = [] 1181 seen_types = {} 1182 1183 def window(iterable, size=2): 1184 i = iter(iterable) 1185 win = [] 1186 for e in range(0, size): 1187 win.append(next(i)) 1188 yield win 1189 for e in i: 1190 win = win[1:] + [e] 1191 yield win 1192 1193 for cls in self.namespace.get_classes(): 1194 if cls.parent is None: 1195 flat_tree.append((cls.name, None)) 1196 continue 1197 1198 if len(cls.ancestors) < 2: 1199 flat_tree.append((cls.name, cls.ancestors[0].name)) 1200 else: 1201 flat_tree.append((cls.name, cls.ancestors[0].name)) 1202 for chunk in window(cls.ancestors, size=2): 1203 if chunk[0].name in seen_types: 1204 continue 1205 if len(chunk) == 2: 1206 flat_tree.append((chunk[0].name, chunk[1].name)) 1207 else: 1208 flat_tree.append((chunk[0].name, None)) 1209 seen_types[chunk[0].name] = 1 1210 1211 def subtree(cls, rel): 1212 return { 1213 v: subtree(v, rel) 1214 for v in [x[0] for x in rel if x[1] == cls] 1215 } 1216 1217 return subtree(root, flat_tree) 1218 1219 @property 1220 def namespace(self) -> T.Optional[Namespace]: 1221 return self._namespaces[0] 1222 1223 def find_type(self, name: str, ns: T.Optional[str] = None) -> T.Optional[T.Tuple[Namespace, Type]]: 1224 if ns is None or self.namespace.name == ns: 1225 res = self.namespace.find_real_type(name) 1226 if res is not None: 1227 return (self.namespace, res) 1228 for repo in self.includes.values(): 1229 if ns is not None and ns != repo.namespace.name: 1230 continue 1231 res = repo.namespace.find_real_type(name) 1232 if res is not None: 1233 return (repo.namespace, res) 1234 return None 1235 1236 def find_symbol(self, name: str) -> T.Optional[T.Tuple[Namespace, Type]]: 1237 log.debug(f"Looking for symbol {name} in current namespace {self.namespace.name}") 1238 res = self.namespace.find_symbol(name) 1239 if res is not None: 1240 return (self.namespace, res) 1241 for repo in self.includes.values(): 1242 log.debug(f"Looking for symbol {name} in namespace {repo.namespace.name}") 1243 res = repo.namespace.find_symbol(name) 1244 if res is not None: 1245 return (repo.namespace, res) 1246 return None 1247 1248 def find_class(self, name: str, ns: T.Optional[str] = None) -> T.Optional[T.Tuple[Namespace, Type]]: 1249 if ns is None or self.namespace.name == ns: 1250 res = self.namespace.find_class(name) 1251 if res is not None: 1252 return (self.namespace, res) 1253 for repo in self.includes.values(): 1254 if ns is not None and ns != repo.namespace.name: 1255 continue 1256 res = repo.namespace.find_class(name) 1257 if res is not None: 1258 return (repo.namespace, res) 1259 return None 1260 1261 def find_interface(self, name: str, ns: T.Optional[str] = None) -> T.Optional[T.Tuple[Namespace, Type]]: 1262 if ns is None or self.namespace.name == ns: 1263 res = self.namespace.find_interface(name) 1264 if res is not None: 1265 return (self.namespace, res) 1266 for repo in self.includes.values(): 1267 if ns is not None and ns != repo.namespace.name: 1268 continue 1269 res = repo.namespace.find_interface(name) 1270 if res is not None: 1271 return (repo.namespace, res) 1272 return None 1273