Commit c3fcff81 authored by Emmanuele Bassi's avatar Emmanuele Bassi 👣
Browse files

gir: Add more details to the GIR parser

parent cf21a6c6
......@@ -4,14 +4,16 @@
__all__ = [
'GirParser',
'Alias',
'BitField',
'Callable',
'Class',
'Constant',
'EnumerationMember',
'Enumeration',
'ErrorDomain',
'Function',
'Include',
'Member',
'Method',
'Namespace',
'Parameter',
......@@ -20,14 +22,16 @@ __all__ = [
]
from .ast import (
Alias,
BitField,
Callable,
Class,
Constant,
EnumerationMember,
Enumeration,
ErrorDomain,
Function,
Include,
Member,
Method,
Namespace,
Parameter,
......
......@@ -57,6 +57,11 @@ class GType:
self.type_struct = type_struct
class VoidType(Type):
def __init__(self):
super().__init__(name='none', ctype='void')
class Alias(Type):
"""Alias to a Type"""
def __init__(self, name: str, ctype: str, target: Type):
......@@ -74,28 +79,34 @@ class Constant(Type):
class Parameter(GIRElement):
"""A callable parameter"""
def __init__(self, name: str, direction: str, transfer: str, target: Type, caller_allocates: bool = False, callee_allocates: bool = False, optional: bool = False, nullable: bool = False):
def __init__(self, name: str, direction: str, transfer: str, target: Type, caller_allocates: bool = False, optional: bool = False, nullable: bool = False, closure: int = -1, destroy: int = -1, scope: str = None):
super().__init__()
self.name = name
self.direction = direction
self.transfer = transfer
self.caller_allocates = caller_allocates
self.callee_allocates = callee_allocates
self.optional = optional
self.nullable = nullable
self.scope = scope
self.closure = closure
self.destroy = destroy
if target is None:
self.target = Type(name='void', ctype='void')
self.target = VoidType()
else:
self.target = target
class ReturnValue(GIRElement):
"""A callable's return value"""
def __init__(self, transfer: str, target: Type):
def __init__(self, transfer: str, target: Type, nullable: bool = False, closure: int = -1, destroy: int = -1, scope: str = None):
super().__init__()
self.transfer = transfer
self.nullable = nullable
self.scope = scope
self.closure = closure
self.destroy = destroy
if target is None:
self.target = Type(name='void', ctype='void')
self.target = VoidType()
else:
self.target = target
......@@ -130,6 +141,57 @@ class Method(Callable):
self.instance_param = instance_param
class Callback(Callable):
def __init__(self, name: str, ctype: str, throws: bool):
super().__init__(name, None)
self.ctype = ctype
self.throws = throws
class Member(GIRElement):
"""A member in an enumeration, error domain, or bitfield"""
def __init__(self, name: str, value: str, identifier: str, nick: str):
super().__init__()
self.name = name
self.value = value
self.identifier = identifier
self.nick = nick
class Enumeration(Type):
"""An enumeration type"""
def __init__(self, name: str, ctype: str, gtype: GType):
super().__init__(name, ctype)
self.gtype = gtype
self.members = []
self.functions = []
def set_members(self, members: T.List[Member]) -> None:
self.members.extend(members)
def add_member(self, member: Member) -> None:
self.members.append(member)
def add_function(self, function: Function) -> None:
self.functions.append(function)
def set_functions(self, functions: T.List[Function]) -> None:
self.functions.extend(functions)
class BitField(Enumeration):
"""An enumeration type of bit masks"""
def __init__(self, name: str, ctype: str, gtype: GType):
super().__init__(name, ctype, gtype)
class ErrorDomain(Enumeration):
"""An error domain for GError"""
def __init__(self, name: str, ctype: str, gtype: GType, domain: str):
super().__init__(name, ctype, gtype)
self.domain = domain
class Property(GIRElement):
def __init__(self, name: str, transfer: str, target: Type, writable: bool = True, readable: bool = True, construct: bool = False, construct_only: bool = False):
super().__init__()
......@@ -143,10 +205,13 @@ class Property(GIRElement):
class Signal(GIRElement):
def __init__(self, name: str, when: str):
def __init__(self, name: str, detailed: bool, when: str, action: bool = False, no_hooks: bool = False, no_recurse: bool = False):
super().__init__()
self.name = name
self.when = when
self.action = action
self.no_hooks = no_hooks
self.no_recurse = no_recurse
self.parameters = []
self.return_value = None
......@@ -157,21 +222,28 @@ class Signal(GIRElement):
self.return_value = res
class Class(Type):
def __init__(self, name: str, ctype: str, symbol_prefix: str, gtype: GType, parent: str = 'GObject.Object', abstract: bool = False):
class Field(GIRElement):
"""A field in a struct or union"""
def __init__(self, name: str, target: Type, writable: bool, readable: bool, private: bool = False, bits: int = 0):
super().__init__()
self.name = name
self.target = target
self.writable = writable
self.readable = readable
self.private = private
self.bits = bits
class Interface(Type):
def __init__(self, name: str, ctype: str, symbol_prefix: str, gtype: GType):
super().__init__(name, ctype)
self.symbol_prefix = symbol_prefix
self.parent = parent
self.abstract = abstract
self.gtype = gtype
self.constructors = []
self.methods = []
self.properties = []
self.signals = []
self.functions = []
def set_constructors(self, ctors: T.List[Function]) -> None:
self.constructors.extend(ctors)
self.fields = []
def set_methods(self, methods: T.List[Method]) -> None:
self.methods.extend(methods)
......@@ -185,16 +257,28 @@ class Class(Type):
def set_functions(self, functions: T.List[Function]) -> None:
self.functions.extend(functions)
def set_fields(self, fields: T.List[Field]) -> None:
self.fields.extend(fields)
class Interface(Type):
def __init__(self, name: str, ctype: str, symbol_prefix: str, gtype: GType):
class Class(Type):
def __init__(self, name: str, ctype: str, symbol_prefix: str, gtype: GType, parent: str = 'GObject.Object', abstract: bool = False):
super().__init__(name, ctype)
self.symbol_prefix = symbol_prefix
self.parent = parent
self.abstract = abstract
self.gtype = gtype
self.implements = []
self.constructors = []
self.methods = []
self.properties = []
self.signals = []
self.functions = []
self.fields = []
self.callbacks = []
def set_constructors(self, ctors: T.List[Function]) -> None:
self.constructors.extend(ctors)
def set_methods(self, methods: T.List[Method]) -> None:
self.methods.extend(methods)
......@@ -208,18 +292,20 @@ class Interface(Type):
def set_functions(self, functions: T.List[Function]) -> None:
self.functions.extend(functions)
def set_implements(self, ifaces: T.List[str]) -> None:
self.implements.extend(ifaces)
def set_fields(self, fields: T.List[Field]) -> None:
self.fields.extend(fields)
class Boxed(Type):
def __init__(self, name: str, symbol_prefix: str, gtype: GType):
super().__init__(name, None)
self.symbol_prefix = symbol_prefix
self.gtype = gtype
self.methods = []
self.functions = []
def set_methods(self, methods: T.List[Method]) -> None:
self.methods.extend(methods)
def set_functions(self, functions: T.List[Function]) -> None:
self.functions.extend(functions)
......@@ -232,6 +318,7 @@ class Record(Type):
self.constructors = []
self.methods = []
self.functions = []
self.fields = []
def set_constructors(self, ctors: T.List[Function]) -> None:
self.constructors.extend(ctors)
......@@ -242,6 +329,9 @@ class Record(Type):
def set_functions(self, functions: T.List[Function]) -> None:
self.functions.extend(functions)
def set_fields(self, fields: T.List[Field]) -> None:
self.fields.extend(fields)
class Union(Type):
def __init__(self, name: str, ctype: str, symbol_prefix: str, gtype: GType):
......@@ -251,6 +341,7 @@ class Union(Type):
self.constructors = []
self.methods = []
self.functions = []
self.fields = []
def set_constructors(self, ctors: T.List[Function]) -> None:
self.constructors.extend(ctors)
......@@ -261,40 +352,8 @@ class Union(Type):
def set_functions(self, functions: T.List[Function]) -> None:
self.functions.extend(functions)
class EnumerationMember(GIRElement):
def __init__(self, name: str, value: str, identifier: str, nick: str):
super().__init__()
self.name = name
self.value = value
self.identifier = identifier
self.nick = nick
class Enumeration(Type):
def __init__(self, name: str, ctype: str, gtype: GType):
super().__init__(name, ctype)
self.gtype = gtype
self.members = []
self.functions = []
def set_members(self, members: T.List[EnumerationMember]) -> None:
self.members.extend(members)
def add_member(self, member: EnumerationMember) -> None:
self.members.append(member)
def add_function(self, function: Function) -> None:
self.functions.append(function)
def set_functions(self, functions: T.List[Function]) -> None:
self.functions.extend(functions)
class ErrorDomain(Enumeration):
def __init__(self, name: str, ctype: str, gtype: GType, domain: str):
super().__init__(name, ctype, gtype)
self.domain = domain
def set_fields(self, fields: T.List[Field]) -> None:
self.fields.extend(fields)
class Namespace:
......@@ -306,6 +365,7 @@ class Namespace:
self._shared_libraries = []
self._aliases = []
self._bitfields = []
self._boxeds = []
self._classes = []
self._constants = []
......@@ -355,6 +415,9 @@ class Namespace:
def add_function(self, function: Function) -> None:
self._functions.append(function)
def add_bitfield(self, bitfield: BitField) -> None:
self._bitfields.append(bitfield)
def get_classes(self) -> T.List[Class]:
return self._classes
......@@ -385,6 +448,9 @@ class Namespace:
def get_functions(self) -> T.List[Function]:
return self._functions
def get_bitfields(self) -> T.List[BitField]:
return self._bitfields
class Include:
def __init__(self, name: str, version: str):
......
......@@ -83,6 +83,7 @@ class GirParser:
parse_methods = {
_corens('alias'): self._parse_alias,
_corens('bitfield'): self._parse_bitfield,
_glibns('boxed'): self._parse_boxed,
_corens('class'): self._parse_class,
_corens('constant'): self._parse_constant,
......@@ -171,13 +172,18 @@ class GirParser:
def _parse_return_value(self, node: ET.Element) -> ast.ReturnValue:
transfer = node.attrib.get('transfer-ownership')
nullable = node.attrib.get('nullable', '1') == '1'
closure = int(node.attrib.get('closure', -1))
destroy = int(node.attrib.get('destroy', -1))
scope = node.attrib.get('scope')
ctype = None
child = node.find('core:type', GI_NAMESPACES)
if child is not None:
ctype = ast.Type(name=child.attrib['name'], ctype=child.attrib.get(_cns('type')))
res = ast.ReturnValue(transfer=transfer, target=ctype)
res = ast.ReturnValue(transfer=transfer, target=ctype, nullable=nullable, closure=closure,
destroy=destroy, scope=scope)
self._maybe_parse_docs(node, res)
return res
......@@ -186,10 +192,12 @@ class GirParser:
name = node.attrib.get('name')
direction = node.attrib.get('direction')
transfer = node.attrib.get('transfer-ownership')
nullable = node.attrib.get('nullable') == '1'
optional = node.attrib.get('optional') == '1'
caller_allocates = node.attrib.get('caller-allocates') == '1'
callee_allocates = node.attrib.get('callee-allocates') == '1'
nullable = node.attrib.get('nullable', '1') == '1'
optional = node.attrib.get('optional', '1') == '1'
caller_allocates = node.attrib.get('caller-allocates', '1') == '1'
closure = int(node.attrib.get('closure', -1))
destroy = int(node.attrib.get('destroy', -1))
scope = node.attrib.get('scope')
ctype = None
child = node.find('core:type', GI_NAMESPACES)
......@@ -198,7 +206,7 @@ class GirParser:
res = ast.Parameter(name=name, direction=direction, transfer=transfer, target=ctype,
optional=optional, nullable=nullable, caller_allocates=caller_allocates,
callee_allocates=callee_allocates)
closure=closure, destroy=destroy, scope=scope)
self._maybe_parse_docs(node, res)
return res
......@@ -250,13 +258,13 @@ class GirParser:
return res
def _parse_enum_member(self, node: ET.Element) -> ast.EnumerationMember:
def _parse_enum_member(self, node: ET.Element) -> ast.Member:
name = node.attrib.get('name')
value = node.attrib.get('value')
identifier = node.attrib.get(_cns("identifier"))
nick = node.attrib.get(_glibns("nick"))
res = ast.EnumerationMember(name=name, value=value, identifier=identifier, nick=nick)
res = ast.Member(name=name, value=value, identifier=identifier, nick=nick)
self._maybe_parse_docs(node, res)
return res
......@@ -296,19 +304,49 @@ class GirParser:
res.set_functions(functions)
self._maybe_parse_docs(node, res)
def _parse_bitfield(self, node: ET.Element, ns: ast.Namespace) -> None:
children = node.findall('core:member', GI_NAMESPACES)
if children is None or len(children) == 0:
return
members = []
for child in children:
members.append(self._parse_enum_member(child))
children = node.findall('core:function', GI_NAMESPACES)
functions = []
for child in children:
functions.append(self._parse_function(child))
name = node.attrib.get('name')
ctype = node.attrib.get('ctype')
type_name = node.attrib.get(_glibns('type-name'))
get_type = node.attrib.get(_glibns('get-type'))
gtype = None
if type_name is not None:
gtype = ast.GType(type_name, get_type)
res = ast.BitField(name, ctype, gtype)
ns.add_enumeration(res)
res.set_members(members)
res.set_functions(functions)
self._maybe_parse_docs(node, res)
def _parse_property(self, node: ET.Element, cls: T.Optional[ast.Class] = None) -> ast.Property:
name = node.attrib.get('name')
writable = node.attrib.get('writable') == '1'
readable = node.attrib.get('readable') != '0'
construct_only = node.attrib.get('construct-only') == '1'
construct = node.attrib.get('construct') == '1'
writable = node.attrib.get('writable', '0') == '1'
readable = node.attrib.get('readable', '0') == '1'
construct_only = node.attrib.get('construct-only', '0') == '1'
construct = node.attrib.get('construct', '0') == '1'
transfer = node.attrib.get('transfer-ownership')
child = node.find('core:type', GI_NAMESPACES)
if child is not None:
ctype = ast.Type(name=child.attrib.get('name'), ctype=child.attrib.get(_cns('type')))
else:
ctype = ast.Type(name='void', ctype='void')
ctype = ast.VoidType()
res = ast.Property(name=name, transfer=transfer, target=ctype,
writable=writable, readable=readable,
......@@ -320,6 +358,10 @@ class GirParser:
def _parse_signal(self, node: ET.Element, cls: T.Optional[ast.Class] = None) -> ast.Signal:
name = node.attrib.get('name')
when = node.attrib.get('when')
detailed = node.attrib.get('detailed') == '1'
action = node.attrib.get('action') == '1'
no_hooks = node.attrib.get('no-hooks') == '1'
no_recurse = node.attrib.get('no-recurse') == '1'
child = node.find('core:return-value', GI_NAMESPACES)
return_value = self._parse_return_value(child)
......@@ -329,7 +371,7 @@ class GirParser:
for child in children:
params.append(self._parse_parameter(child))
res = ast.Signal(name=name, when=when)
res = ast.Signal(name=name, when=when, detailed=detailed, action=action, no_hooks=no_hooks, no_recurse=no_recurse)
res.set_return_value(return_value)
res.set_parameters(params)
self._maybe_parse_docs(node, res)
......@@ -339,6 +381,34 @@ class GirParser:
return res
def _parse_field(self, node: ET.Element) -> ast.Field:
name = node.attrib.get('name')
writable = node.attrib.get('writable', '0') == '1'
readable = node.attrib.get('readable', '0') == '1'
private = node.attrib.get('private', '0') == '1'
bits = int(node.attrib.get('bits', '0'))
ctype = None
child = node.find('core:type', GI_NAMESPACES)
if child is not None:
ctype = ast.Type(name=child.attrib.get('name'), ctype=child.attrib.get(_cns('type')))
child = node.find('core:callback', GI_NAMESPACES)
if child is not None:
ctype = None
if ctype is None:
ctype = ast.VoidType()
res = ast.Field(name=name, writable=writable, readable=readable, private=private, bits=bits, target=ctype)
self._maybe_parse_docs(node, res)
return res
def _parse_implements(self, node: ET.Element) -> str:
return node.attrib['name']
def _parse_class(self, node: ET.Element, ns: ast.Namespace) -> None:
name = node.attrib.get('name')
symbol_prefix = node.attrib.get(_cns('symbol-prefix'))
......@@ -356,6 +426,20 @@ class GirParser:
res = ast.Class(name=name, symbol_prefix=symbol_prefix, ctype=ctype, parent=parent, abstract=abstract, gtype=gtype)
self._maybe_parse_docs(node, res)
fields = []
children = node.findall('core:field', GI_NAMESPACES)
for child in children:
fields.append(self._parse_field(child))
res.set_fields(fields)
ifaces = []
children = node.findall('core:implements', GI_NAMESPACES)
for child in children:
ifaces.append(self._parse_implements(child))
res.set_implements(ifaces)
ctors = []
children = node.findall('core:constructor', GI_NAMESPACES)
for child in children:
......@@ -408,6 +492,13 @@ class GirParser:
res = ast.Interface(name=name, symbol_prefix=symbol_prefix, ctype=ctype, gtype=gtype)
self._maybe_parse_docs(node, res)
fields = []
children = node.findall('core:field', GI_NAMESPACES)
for child in children:
fields.append(self._parse_field(child))
res.set_fields(fields)
methods = []
children = node.findall('core:method', GI_NAMESPACES)
for child in children:
......@@ -451,13 +542,6 @@ class GirParser:
res = ast.Boxed(name=name, symbol_prefix=symbol_prefix, gtype=gtype)
self._maybe_parse_docs(node, res)
methods = []
children = node.findall('core:method', GI_NAMESPACES)
for child in children:
methods.append(self._parse_method(child))
res.set_methods(methods)
functions = []
children = node.findall('core:function', GI_NAMESPACES)
for child in children:
......@@ -482,6 +566,13 @@ class GirParser:
res = ast.Record(name=name, symbol_prefix=symbol_prefix, ctype=ctype, gtype=gtype)
self._maybe_parse_docs(node, res)
fields = []
children = node.findall('core:field', GI_NAMESPACES)
for child in children:
fields.append(self._parse_field(child))
res.set_fields(fields)
ctors = []
children = node.findall('core:constructor', GI_NAMESPACES)
for child in children:
......@@ -520,6 +611,13 @@ class GirParser:
res = ast.Union(name=name, symbol_prefix=symbol_prefix, ctype=ctype, gtype=gtype)
self._maybe_parse_docs(node, res)
fields = []
children = node.findall('core:field', GI_NAMESPACES)
for child in children:
fields.append(self._parse_field(child))
res.set_fields(fields)
ctors = []
children = node.findall('core:constructor', GI_NAMESPACES)
for child in children:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!