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 not 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):
166        super().__init__(name=name, namespace=namespace)
167        self.ctype = ctype
168
169    def __eq__(self, other):
170        if isinstance(other, Type):
171            if self.namespace is not None:
172                return self.namespace == other.namespace and self.name == self.name
173            elif self.ctype is not None:
174                return self.name == other.name and self.ctype == other.ctype
175            else:
176                return self.name == other.name
177        elif isinstance(other, str):
178            return self.name == other
179        else:
180            return False
181
182    def __cmp__(self, other):
183        if self.ctype is not None:
184            return self.name == other.name and self.ctype == other.ctype
185        return self.name == other.name
186
187    def __repr__(self):
188        return f"Type({self.fqtn}, {self.ctype})"
189
190    @property
191    def resolved(self):
192        return self.ctype is not None
193
194    @property
195    def base_ctype(self):
196        if self.ctype is None:
197            return None
198        return self.ctype.replace('*', '')
199
200    @property
201    def fqtn(self):
202        if '.' in self.name:
203            return self.name
204        elif self.namespace is not None:
205            return f"{self.namespace}.{self.name}"
206        else:
207            return None
208
209
210class ArrayType(GIRElement):
211    """Base class for Array nodes"""
212    def __init__(self, name: str, value_type: Type, ctype: str = None, zero_terminated: bool = False,
213                 fixed_size: int = -1, length: int = -1):
214        super().__init__(name)
215        self.ctype = ctype
216        self.zero_terminated = zero_terminated
217        self.fixed_size = fixed_size
218        self.length = length
219        self.value_type = value_type
220
221
222class ListType(GIRElement):
223    """Type class for List nodes"""
224    def __init__(self, name: str, value_type: Type, ctype: str = None):
225        super().__init__(name)
226        self.ctype = ctype
227        self.value_type = value_type
228
229
230class MapType(GIRElement):
231    """Type class for Map nodes"""
232    def __init__(self, name: str, key_type: Type, value_type: Type, ctype: str = None):
233        super().__init__(name)
234        self.ctype = ctype
235        self.key_type = key_type
236        self.value_type = value_type
237
238
239class GType:
240    """Base class for GType information"""
241    def __init__(self, type_name: str, get_type: str, type_struct: T.Optional[str] = None):
242        self.type_name = type_name
243        self.get_type = get_type
244        self.type_struct = type_struct
245
246
247class VoidType(Type):
248    def __init__(self):
249        super().__init__(name='none', ctype='void')
250
251    def __str__(self):
252        return "void"
253
254
255class VarArgs(Type):
256    def __init__(self):
257        super().__init__(name='none', ctype='')
258
259    def __str__(self):
260        return "..."
261
262
263class Alias(Type):
264    """Alias to a Type"""
265    def __init__(self, name: str, namespace: str, ctype: str, target: Type):
266        super().__init__(name=name, ctype=ctype, namespace=namespace)
267        self.target = target
268
269
270class Constant(Type):
271    """A constant"""
272    def __init__(self, name: str, namespace: str, ctype: str, target: Type, value: str):
273        super().__init__(name=name, ctype=ctype, namespace=namespace)
274        self.target = target
275        self.value = value
276
277
278class Parameter(GIRElement):
279    """A callable parameter"""
280    def __init__(self, name: str, direction: str, transfer: str, target: Type = None, caller_allocates: bool = False,
281                 optional: bool = False, nullable: bool = False, closure: int = -1, destroy: int = -1,
282                 scope: str = None):
283        super().__init__(name)
284        self.direction = direction
285        self.transfer = transfer
286        self.caller_allocates = caller_allocates
287        self.optional = optional
288        self.nullable = nullable
289        self.scope = scope
290        self.closure = closure
291        self.destroy = destroy
292        if target is None:
293            self.target: Type = VoidType()
294        else:
295            self.target = target
296
297
298class ReturnValue(GIRElement):
299    """A callable's return value"""
300    def __init__(self, transfer: str, target: Type, nullable: bool = False, closure: int = -1, destroy: int = -1, scope: str = None):
301        super().__init__()
302        self.transfer = transfer
303        self.nullable = nullable
304        self.scope = scope
305        self.closure = closure
306        self.destroy = destroy
307        if target is None:
308            self.target: Type = VoidType()
309        else:
310            self.target = target
311
312
313class Callable(GIRElement):
314    """A callable symbol: function, method, function-macro, ..."""
315    def __init__(self, name: str, namespace: T.Optional[str], identifier: T.Optional[str], throws: bool = False):
316        super().__init__(name=name, namespace=namespace)
317        self.identifier = identifier
318        self.parameters: T.List[Parameter] = []
319        self.return_value: T.Optional[ReturnValue] = None
320        self.throws: bool = throws
321        self.moved_to: T.Optional[str] = None
322        self.shadows: T.Optional[str] = None
323        self.shadowed_by: T.Optional[str] = None
324
325    def add_parameter(self, param: Parameter) -> None:
326        self.parameters.append(param)
327
328    def set_parameters(self, params: T.List[Parameter]) -> None:
329        self.parameters.extend(params)
330
331    def set_return_value(self, res: ReturnValue) -> None:
332        self.return_value = res
333
334    def set_shadows(self, func: str) -> None:
335        self.shadows = func
336
337    def set_shadowed_by(self, func: str) -> None:
338        self.shadowed_by = func
339
340    def set_moved_to(self, func: str) -> None:
341        self.moved_to = func
342
343    def __contains__(self, param):
344        if isinstance(param, str):
345            for p in self.parameters:
346                if p.name == param:
347                    return True
348        elif isinstance(param, Parameter):
349            return param in self.parameters
350        elif isinstance(param, ReturnValue):
351            return param == self.return_value
352        return False
353
354
355class FunctionMacro(Callable):
356    def __init__(self, name: str, namespace: T.Optional[str], identifier: str):
357        super().__init__(name, namespace, identifier)
358
359
360class Function(Callable):
361    def __init__(self, name: str, namespace: T.Optional[str], identifier: str, throws: bool = False):
362        super().__init__(name, namespace, identifier, throws)
363
364
365class Method(Callable):
366    def __init__(self, name: str, identifier: str, instance_param: Parameter, throws: bool = False):
367        super().__init__(name, None, identifier, throws)
368        self.instance_param = instance_param
369
370    def __contains__(self, param):
371        if isinstance(param, Parameter) and param == self.instance_param:
372            return True
373        return super().__contains__(self, param)
374
375
376class VirtualMethod(Callable):
377    def __init__(self, name: str, identifier: str, invoker: str, instance_param: Parameter, throws: bool = False):
378        super().__init__(name, None, identifier, throws)
379        self.instance_param = instance_param
380        self.invoker = invoker
381
382    def __contains__(self, param):
383        if isinstance(param, Parameter) and param == self.instance_param:
384            return True
385        return super().__contains__(self, param)
386
387
388class Callback(Callable):
389    def __init__(self, name: str, namespace: str, ctype: T.Optional[str], throws: bool = False):
390        super().__init__(name=name, namespace=namespace, identifier=None, throws=throws)
391        self.ctype = ctype
392
393
394class Member(GIRElement):
395    """A member in an enumeration, error domain, or bitfield"""
396    def __init__(self, name: str, value: str, identifier: str, nick: str):
397        super().__init__(name)
398        self.value = value
399        self.identifier = identifier
400        self.nick = nick
401
402
403class Enumeration(Type):
404    """An enumeration type"""
405    def __init__(self, name: str, namespace: str, ctype: str, gtype: T.Optional[GType]):
406        super().__init__(name=name, ctype=ctype, namespace=namespace)
407        self.gtype = gtype
408        self.members: T.List[Member] = []
409        self.functions: T.List[Function] = []
410
411    def add_member(self, member: Member) -> None:
412        self.members.append(member)
413
414    def add_function(self, function: Function) -> None:
415        self.functions.append(function)
416
417    def set_members(self, members: T.List[Member]) -> None:
418        self.members.extend(members)
419
420    def set_functions(self, functions: T.List[Function]) -> None:
421        self.functions.extend(functions)
422
423    def __contains__(self, member):
424        if isinstance(member, Member):
425            return member in self.members
426        return False
427
428    def __iter__(self):
429        for member in self.members:
430            yield member
431
432
433class BitField(Enumeration):
434    """An enumeration type of bit masks"""
435    def __init__(self, name: str, namespace: str, ctype: str, gtype: T.Optional[GType]):
436        super().__init__(name, namespace, ctype, gtype)
437
438
439class ErrorDomain(Enumeration):
440    """An error domain for GError"""
441    def __init__(self, name: str, namespace: str, ctype: str, gtype: T.Optional[GType], domain: str):
442        super().__init__(name, namespace, ctype, gtype)
443        self.domain = domain
444
445
446class Property(GIRElement):
447    def __init__(self, name: str, transfer: str, target: Type, writable: bool = True, readable: bool = True, construct: bool = False,
448                 construct_only: bool = False):
449        super().__init__(name)
450        self.transfer = transfer
451        self.writable = writable
452        self.readable = readable
453        self.construct = construct
454        self.construct_only = construct_only
455        self.target = target
456
457
458class Signal(GIRElement):
459    def __init__(self, name: str, detailed: bool, when: str, action: bool = False, no_hooks: bool = False, no_recurse: bool = False):
460        super().__init__(name)
461        self.detailed = detailed
462        self.when = when
463        self.action = action
464        self.no_hooks = no_hooks
465        self.no_recurse = no_recurse
466        self.parameters: T.List[Parameter] = []
467        self.return_value: T.Optional[ReturnValue] = None
468
469    def set_parameters(self, params: T.List[Parameter]) -> None:
470        self.parameters.extend(params)
471
472    def set_return_value(self, res: ReturnValue) -> None:
473        self.return_value = res
474
475
476class Field(GIRElement):
477    """A field in a struct or union"""
478    def __init__(self, name: str, target: Type, writable: bool, readable: bool, private: bool = False, bits: int = 0):
479        super().__init__(name)
480        self.target = target
481        self.writable = writable
482        self.readable = readable
483        self.private = private
484        self.bits = bits
485
486
487class Interface(Type):
488    def __init__(self, name: str, namespace: str, ctype: str, symbol_prefix: str, gtype: GType):
489        super().__init__(name=name, ctype=ctype, namespace=namespace)
490        self.symbol_prefix = symbol_prefix
491        self.gtype = gtype
492        self.methods: T.List[Method] = []
493        self.virtual_methods: T.List[VirtualMethod] = []
494        self.properties: T.Mapping[str, Property] = {}
495        self.signals: T.Mapping[str, Signal] = {}
496        self.functions: T.List[Function] = []
497        self.fields: T.List[Field] = []
498        self.prerequisite: T.Optional[str] = None
499
500    @property
501    def type_struct(self) -> T.Optional[str]:
502        if self.gtype is not None:
503            return self.gtype.type_struct
504        return self.ctype
505
506    @property
507    def type_func(self) -> str:
508        return self.gtype.get_type
509
510    def set_methods(self, methods: T.List[Method]) -> None:
511        self.methods.extend(methods)
512
513    def set_virtual_methods(self, methods: T.List[VirtualMethod]) -> None:
514        self.virtual_methods.extend(methods)
515
516    def set_properties(self, properties: T.List[Property]) -> None:
517        for p in properties:
518            self.properties[p.name] = p
519
520    def set_signals(self, signals: T.List[Signal]) -> None:
521        for s in signals:
522            self.signals[s.name] = s
523
524    def set_functions(self, functions: T.List[Function]) -> None:
525        self.functions.extend(functions)
526
527    def set_fields(self, fields: T.List[Field]) -> None:
528        self.fields.extend(fields)
529
530    def set_prerequisite(self, prerequisite: str) -> None:
531        self.prerequisite = prerequisite
532
533
534class Class(Type):
535    def __init__(self, name: str, namespace: str, ctype: str, symbol_prefix: str,
536                 gtype: GType, parent: T.Optional[Type] = None,
537                 abstract: bool = False, fundamental: bool = False,
538                 ref_func: T.Optional[str] = None, unref_func: T.Optional[str] = None):
539        super().__init__(name=name, ctype=ctype, namespace=namespace)
540        self.symbol_prefix = symbol_prefix
541        self.parent = parent
542        self.abstract = abstract
543        self.fundamental = fundamental
544        self.ref_func = ref_func
545        self.unref_func = unref_func
546        self.gtype = gtype
547        self.ancestors: T.List[Type] = []
548        self.implements: T.List[Type] = []
549        self.constructors: T.List[Function] = []
550        self.methods: T.List[Method] = []
551        self.virtual_methods: T.List[VirtualMethod] = []
552        self.properties: T.Mapping[str, Property] = {}
553        self.signals: T.Mapping[str, Signal] = {}
554        self.functions: T.List[Function] = []
555        self.fields: T.List[Field] = []
556        self.callbacks: T.List[Callback] = []
557
558    @property
559    def type_struct(self) -> T.Optional[str]:
560        if self.gtype is not None:
561            return self.gtype.type_struct
562        return None
563
564    @property
565    def type_func(self) -> T.Optional[str]:
566        if self.gtype is not None:
567            return self.gtype.get_type
568        return self.ctype
569
570    def set_constructors(self, ctors: T.List[Function]) -> None:
571        self.constructors.extend(ctors)
572
573    def set_methods(self, methods: T.List[Method]) -> None:
574        self.methods.extend(methods)
575
576    def set_virtual_methods(self, methods: T.List[VirtualMethod]) -> None:
577        self.virtual_methods.extend(methods)
578
579    def set_properties(self, properties: T.List[Property]) -> None:
580        for p in properties:
581            self.properties[p.name] = p
582
583    def set_signals(self, signals: T.List[Signal]) -> None:
584        for s in signals:
585            self.signals[s.name] = s
586
587    def set_functions(self, functions: T.List[Function]) -> None:
588        self.functions.extend(functions)
589
590    def set_implements(self, ifaces: T.List[Type]) -> None:
591        self.implements.extend(ifaces)
592
593    def set_fields(self, fields: T.List[Field]) -> None:
594        self.fields.extend(fields)
595
596
597class Boxed(Type):
598    def __init__(self, name: str, namespace: str, symbol_prefix: str, gtype: GType):
599        super().__init__(name=name, ctype=None, namespace=namespace)
600        self.symbol_prefix = symbol_prefix
601        self.gtype = gtype
602        self.functions: T.List[Function] = []
603
604    def set_functions(self, functions: T.List[Function]) -> None:
605        self.functions.extend(functions)
606
607
608class Record(Type):
609    def __init__(self, name: str, namespace: str, ctype: str, symbol_prefix: str,
610                 gtype: T.Optional[GType] = None, struct_for: T.Optional[str] = None,
611                 disguised: bool = False):
612        super().__init__(name=name, ctype=ctype, namespace=namespace)
613        self.symbol_prefix = symbol_prefix
614        self.gtype = gtype
615        self.struct_for = struct_for
616        self.disguised = disguised
617        self.constructors: T.List[Function] = []
618        self.methods: T.List[Method] = []
619        self.functions: T.List[Function] = []
620        self.fields: T.List[Field] = []
621
622    @property
623    def type_struct(self) -> T.Optional[str]:
624        if self.gtype is not None:
625            return self.gtype.type_struct
626        return self.ctype
627
628    @property
629    def type_func(self) -> T.Optional[str]:
630        if self.gtype is not None:
631            return self.gtype.get_type
632        return None
633
634    def set_constructors(self, ctors: T.List[Function]) -> None:
635        self.constructors.extend(ctors)
636
637    def set_methods(self, methods: T.List[Method]) -> None:
638        self.methods.extend(methods)
639
640    def set_functions(self, functions: T.List[Function]) -> None:
641        self.functions.extend(functions)
642
643    def set_fields(self, fields: T.List[Field]) -> None:
644        self.fields.extend(fields)
645
646
647class Union(Type):
648    def __init__(self, name: str, namespace: str, ctype: str, symbol_prefix: str, gtype: T.Optional[GType]):
649        super().__init__(name=name, ctype=ctype, namespace=namespace)
650        self.symbol_prefix = symbol_prefix
651        self.gtype = gtype
652        self.constructors: T.List[Function] = []
653        self.methods: T.List[Method] = []
654        self.functions: T.List[Function] = []
655        self.fields: T.List[Field] = []
656
657    @property
658    def type_struct(self) -> T.Optional[str]:
659        if self.gtype is not None:
660            return self.gtype.type_struct
661        return self.ctype
662
663    @property
664    def type_func(self) -> T.Optional[str]:
665        if self.gtype is not None:
666            return self.gtype.get_type
667        return None
668
669    def set_constructors(self, ctors: T.List[Function]) -> None:
670        self.constructors.extend(ctors)
671
672    def set_methods(self, methods: T.List[Method]) -> None:
673        self.methods.extend(methods)
674
675    def set_functions(self, functions: T.List[Function]) -> None:
676        self.functions.extend(functions)
677
678    def set_fields(self, fields: T.List[Field]) -> None:
679        self.fields.extend(fields)
680
681
682class Namespace:
683    def __init__(self, name: str, version: str, identifier_prefix: T.List[str] = [], symbol_prefix: T.List[str] = []):
684        self.name = name
685        self.version = version
686
687        self._shared_libraries: T.List[str] = []
688
689        self._aliases: T.Mapping[str, Alias] = {}
690        self._bitfields: T.Mapping[str, BitField] = {}
691        self._boxeds: T.Mapping[str, Boxed] = {}
692        self._callbacks: T.List[Callback] = []
693        self._classes: T.Mapping[str, Class] = {}
694        self._constants: T.Mapping[str, Constant] = {}
695        self._enumerations: T.Mapping[str, Enumeration] = {}
696        self._error_domains: T.Mapping[str, ErrorDomain] = {}
697        self._functions: T.Mapping[str, Function] = {}
698        self._function_macros: T.Mapping[str, FunctionMacro] = {}
699        self._interfaces: T.Mapping[str, Interface] = {}
700        self._records: T.Mapping[str, Record] = {}
701        self._unions: T.Mapping[str, Union] = {}
702
703        self._symbols: T.Mapping[str, Type] = {}
704        self.repository: T.Optional[Repository] = None
705
706        if identifier_prefix:
707            self.identifier_prefix = identifier_prefix
708        else:
709            self.identifier_prefix = [self.name]
710        if symbol_prefix:
711            self.symbol_prefix = symbol_prefix
712        else:
713            self.symbol_prefix = [self.name.lower()]
714
715    def __str__(self):
716        return f"{self.name}-{self.version}"
717
718    def add_shared_libraries(self, libs: T.List[str]) -> None:
719        self._shared_libraries.extend(libs)
720
721    def get_shared_libraries(self) -> T.List[str]:
722        return self._shared_libraries
723
724    def add_alias(self, alias: Alias) -> None:
725        self._aliases[alias.name] = alias
726
727    def add_enumeration(self, enum: Enumeration) -> None:
728        self._enumerations[enum.name] = enum
729
730    def add_error_domain(self, domain: ErrorDomain) -> None:
731        self._error_domains[domain.name] = domain
732
733    def add_class(self, cls: Class) -> None:
734        self._classes[cls.name] = cls
735
736    def add_constant(self, constant: Constant) -> None:
737        self._constants[constant.name] = constant
738
739    def add_interface(self, interface: Interface) -> None:
740        self._interfaces[interface.name] = interface
741
742    def add_boxed(self, boxed: Boxed) -> None:
743        self._boxeds[boxed.name] = boxed
744
745    def add_record(self, record: Record) -> None:
746        self._records[record.name] = record
747
748    def add_union(self, union: Union) -> None:
749        self._unions[union.name] = union
750
751    def add_function(self, function: Function) -> None:
752        self._functions[function.name] = function
753
754    def add_bitfield(self, bitfield: BitField) -> None:
755        self._bitfields[bitfield.name] = bitfield
756
757    def add_function_macro(self, function: FunctionMacro) -> None:
758        self._function_macros[function.name] = function
759
760    def add_callback(self, callback: Callback) -> None:
761        self._callbacks.append(callback)
762
763    def get_classes(self) -> T.List[Class]:
764        return self._classes.values()
765
766    def get_constants(self) -> T.List[Constant]:
767        return self._constants.values()
768
769    def get_enumerations(self) -> T.List[Enumeration]:
770        return self._enumerations.values()
771
772    def get_error_domains(self) -> T.List[ErrorDomain]:
773        return self._error_domains.values()
774
775    def get_aliases(self) -> T.List[Alias]:
776        return self._aliases.values()
777
778    def get_interfaces(self) -> T.List[Interface]:
779        return self._interfaces.values()
780
781    def get_boxeds(self) -> T.List[Boxed]:
782        return self._boxeds.values()
783
784    def get_records(self) -> T.List[Record]:
785        return self._records.values()
786
787    def get_effective_records(self) -> T.List[Record]:
788        def is_effective(r):
789            if "Private" in r.name and r.disguised:
790                return False
791            if r.struct_for is not None:
792                return False
793            return True
794
795        return [x for x in self._records.values() if is_effective(x)]
796
797    def get_unions(self) -> T.List[Union]:
798        return self._unions.values()
799
800    def get_functions(self) -> T.List[Function]:
801        return self._functions.values()
802
803    def get_bitfields(self) -> T.List[BitField]:
804        return self._bitfields.values()
805
806    def get_function_macros(self) -> T.List[FunctionMacro]:
807        return self._function_macros.values()
808
809    def get_effective_function_macros(self) -> T.List[FunctionMacro]:
810        def is_effective(f, ns):
811            # Lower-case identifiers are an automatic pass
812            if f.name.islower():
813                return True
814            # Try to eliminate the GObject type macros from the pool
815            t = f.name.split('_')
816            # Skip "is-a" macros
817            if 'IS' in t:
818                return False
819            # Skip "get class/iface" macros
820            if 'GET' in t:
821                return False
822            # Re-assemble into what most likely is a type name
823            s = "".join([x.capitalize() if len(x) > 2 else x for x in t])
824            # Skip "cast" macros
825            if ns.find_class(s) is not None:
826                return False
827            if ns.find_interface(s) is not None:
828                return False
829            if ns.find_record(s) is not None:
830                return False
831            # Anything that survived at this point is likely a valid function
832            # macro
833            return True
834
835        return [x for x in self._function_macros.values() if is_effective(x, self)]
836
837    def get_callbacks(self) -> T.List[Callback]:
838        return self._callbacks
839
840    def find_class(self, cls: str) -> T.Optional[Class]:
841        return self._classes.get(cls)
842
843    def find_record(self, record: str) -> T.Optional[Record]:
844        return self._records.get(record)
845
846    def find_interface(self, iface: str) -> T.Optional[Interface]:
847        return self._interfaces.get(iface)
848
849    def find_union(self, union: str) -> T.Optional[Union]:
850        return self._unions.get(union)
851
852    def find_enumeration(self, enum: str) -> T.Optional[Enumeration]:
853        return self._enumerations.get(enum)
854
855    def find_bitfield(self, bitfield: str) -> T.Optional[BitField]:
856        return self._bitfields.get(bitfield)
857
858    def find_error_domain(self, domain: str) -> T.Optional[ErrorDomain]:
859        return self._error_domains.get(domain)
860
861    def find_alias(self, alias: str) -> T.Optional[Alias]:
862        return self._aliases.get(alias)
863
864    def find_function(self, func: str) -> T.Optional[Function]:
865        if func in self._functions:
866            return self._functions.get(func)
867        if func in self._function_macros:
868            return self._function_macros.get(func)
869        return None
870
871    def find_real_type(self, name: str) -> T.Optional[Type]:
872        if name in self._aliases:
873            return self._aliases[name]
874        if name in self._bitfields:
875            return self._bitfields[name]
876        if name in self._enumerations:
877            return self._enumerations[name]
878        if name in self._error_domains:
879            return self._error_domains[name]
880        if name in self._classes:
881            return self._classes[name]
882        if name in self._interfaces:
883            return self._interfaces[name]
884        if name in self._records:
885            return self._records[name]
886        if name in self._unions:
887            return self._unions[name]
888        return None
889
890    def find_symbol(self, name: str) -> T.Optional[Type]:
891        return self._symbols.get(name)
892
893    def find_prerequisite_type(self, name: str) -> T.Optional[Type]:
894        if name in self._classes:
895            return self._classes[name]
896        if name is self._interfaces:
897            return self._interfaces[name]
898        return None
899
900
901class Repository:
902    def __init__(self):
903        self.includes: T.Mapping[str, Repository] = {}
904        self.packages: T.List[Package] = []
905        self.c_includes: T.List[CInclude] = []
906        self.types: T.Mapping[str, T.List[Type]] = {}
907        self._namespaces: T.List[Namespace] = []
908        self.girfile: T.Optional[str] = None
909
910    def add_namespace(self, ns: Namespace) -> None:
911        self._namespaces.append(ns)
912        ns.repository = self
913
914    def get_namespace(self, ns: str) -> T.Optional[Namespace]:
915        for namespace in self._namespaces:
916            if namespace.name == ns:
917                return namespace
918        return None
919
920    def find_included_namespace(self, ns: str) -> T.Optional[Namespace]:
921        for repo_name in self.includes:
922            repo = self.includes[repo_name]
923            if repo.namespace.name == ns:
924                return repo.namespace
925        return None
926
927    def resolve_empty_ctypes(self, seen_types: T.Mapping[str, T.List[Type]]) -> None:
928        for fqtn in seen_types:
929            types = seen_types[fqtn]
930            resolved_types = [t for t in types if t.resolved]
931            if len(resolved_types) == 0:
932                ns, name = fqtn.split('.', 1)
933                backstop = f"{self.namespace.identifier_prefix[0]}{name}"
934                resolved_types.append(Type(fqtn, backstop))
935            self.types[fqtn] = resolved_types
936            log.debug(f"Type: {fqtn}: {resolved_types}")
937
938    def resolve_interface_requires(self) -> None:
939        def find_prerequisite_type(includes, ns, name):
940            for repo in includes.values():
941                if repo.namespace.name != ns:
942                    continue
943                prereq = repo.namespace.find_prerequisite_type(name)
944                if prereq is not None:
945                    return Type(name=f"{repo.namespace.name}.{prereq.name}", ctype=prereq.ctype)
946            return None
947
948        ifaces = self.namespace.get_interfaces()
949        for iface in ifaces:
950            if iface.prerequisite is None:
951                continue
952            prerequisite = None
953            if '.' in iface.prerequisite.name:
954                ns, name = iface.prerequisite.name.split('.', 1)
955                if ns == self.namespace.name:
956                    prerequisite = self.namespace.find_prerequisite_type(name)
957                else:
958                    prerequisite = find_prerequisite_type(self.includes, ns, name)
959            else:
960                prerequisite = self.namespace.find_prerequisite_type(iface.prerequisite.name)
961            if prerequisite is not None:
962                if prerequisite.ctype is None:
963                    t = self.find_type(prerequisite.name)
964                    prerequisite.ctype = t.ctype
965                iface.prerequisite = prerequisite
966                log.debug(f"Prerequisite type for interface {iface}: {iface.prerequisite}")
967
968    def resolve_class_type(self) -> None:
969        classes = self.namespace.get_classes()
970        for cls in classes:
971            if cls.ctype is None:
972                if '.' not in cls.name:
973                    name = f"{self.namespace.name}.{cls.name}"
974                else:
975                    name = cls.name
976                t = self.find_type(name)
977                if t is not None:
978                    cls.ctype = t.base_ctype
979                else:
980                    # This is kind of a kludge, but apparently we can get into
981                    # class definitions missing a c:type; if that happens, we
982                    # take the identifier prefix of the namespace and append the
983                    # class name, because that's the inverse of how g-ir-scanner
984                    # determines the class name
985                    cls.ctype = f"{self.namespace.identifier_prefix[0]}{cls.name}"
986                log.debug(f"Updated C type for {cls}")
987
988    def resolve_class_implements(self) -> None:
989        def find_interface_type(includes, ns, name):
990            for repo in includes.values():
991                if repo.namespace.name != ns:
992                    continue
993                iface = repo.namespace.find_interface(name)
994                if iface is not None:
995                    return Type(name=f"{repo.namespace.name}.{iface.name}", ctype=iface.ctype)
996            return None
997
998        classes = self.namespace.get_classes()
999        for cls in classes:
1000            if cls.implements is None:
1001                continue
1002            implements = cls.implements
1003            cls.implements = []
1004            for iface in implements:
1005                if '.' in iface.name:
1006                    ns, name = iface.name.split('.', 1)
1007                    if ns == self.namespace.name:
1008                        iface_type = self.namespace.find_interface(name)
1009                    else:
1010                        iface_type = find_interface_type(self.includes, ns, name)
1011                else:
1012                    iface_type = self.namespace.find_interface(iface.name)
1013                if iface_type is not None:
1014                    if iface_type.ctype is None:
1015                        t = self.find_type(iface_type.name)
1016                        iface_type.ctype = t.ctype
1017                    cls.implements.append(iface_type)
1018            log.debug(f"Interfaces implemented by {cls}: {cls.implements}")
1019
1020    def resolve_class_ancestors(self) -> None:
1021        def find_parent_class(includes, ns, name):
1022            for repo in includes.values():
1023                if repo.namespace.name != ns:
1024                    continue
1025                parent = repo.namespace.find_class(name)
1026                if parent is not None:
1027                    return parent
1028            return None
1029
1030        classes = self.namespace.get_classes()
1031        for cls in classes:
1032            if cls.parent is None:
1033                continue
1034            ancestors = []
1035            parent = cls.parent
1036            while parent is not None:
1037                if '.' in parent.name:
1038                    ns, name = parent.name.split('.')
1039                    if ns == self.namespace.name:
1040                        parent = self.namespace.find_class(name)
1041                    else:
1042                        parent = find_parent_class(self.includes, ns, name)
1043                else:
1044                    parent = self.namespace.find_class(parent.name)
1045                if parent is not None:
1046                    if parent.ctype is None:
1047                        t = self.find_type(parent.name)
1048                        parent.ctype = t.ctype
1049                    ancestors.append(parent)
1050                    parent = parent.parent
1051            cls.ancestors = ancestors
1052            cls.parent = ancestors[0]
1053            log.debug(f"Ancestors for {cls}: parent: {cls.parent}, ancestors: {cls.ancestors}")
1054
1055    def resolve_moved_to(self) -> None:
1056        functions = list(self.namespace.get_functions())
1057        old_len = len(functions)
1058        for func in functions[:]:
1059            if func.moved_to is None:
1060                continue
1061            moved_type, moved_func_name = func.moved_to.split('.')
1062            real_type = self.namespace.find_real_type(moved_type)
1063            if real_type is None:
1064                continue
1065            self.namespace._functions.pop(func.name)    # XXX: Add accessor
1066        new_len = len(self.namespace._functions)
1067        diff = old_len - new_len
1068        log.debug(f"Removed {old_len} - {new_len} functions: {diff}")
1069
1070    def resolve_symbols(self) -> None:
1071        symbols: T.Mapping[str, Type] = {}
1072        for func in self.namespace.get_functions():
1073            symbols[func.identifier] = func
1074        for func in self.namespace.get_function_macros():
1075            symbols[func.identifier] = func
1076        for cls in self.namespace.get_classes():
1077            for m in cls.constructors:
1078                symbols[m.identifier] = cls
1079            for m in cls.methods:
1080                symbols[m.identifier] = cls
1081            for m in cls.functions:
1082                symbols[m.identifier] = cls
1083        for iface in self.namespace.get_interfaces():
1084            for m in iface.methods:
1085                symbols[m.identifier] = iface
1086            for m in iface.functions:
1087                symbols[m.identifier] = iface
1088        for record in self.namespace.get_records():
1089            for m in record.constructors:
1090                symbols[m.identifier] = record
1091            for m in record.methods:
1092                symbols[m.identifier] = record
1093            for m in record.functions:
1094                symbols[m.identifier] = record
1095        for union in self.namespace.get_unions():
1096            for m in union.constructors:
1097                symbols[m.identifier] = union
1098            for m in union.methods:
1099                symbols[m.identifier] = union
1100            for m in union.functions:
1101                symbols[m.identifier] = union
1102        self.namespace._symbols = symbols
1103
1104    @property
1105    def namespace(self) -> T.Optional[Namespace]:
1106        return self._namespaces[0]
1107
1108    def find_type(self, name: str) -> T.Optional[Type]:
1109        types = self.types.get(name)
1110        if types is None:
1111            return None
1112        for t in types:
1113            if t.resolved:
1114                return t
1115        return types[0]
1116