#
import ctypes
-import re
-import os
from . import cgobject
from .odict import odict
-from .ast import (Callback, Enum, Function, Parameter, Property, Return,
- Sequence, Struct, Type)
+from .ast import (Callback, Enum, Function, Member, Namespace, Parameter,
+ Property, Return, Struct, Type, Alias, type_name_from_ctype)
from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
GLibInterface, GLibObject, GLibSignal)
-
-
-# Copied from h2defs.py
-_upperstr_pat1 = re.compile(r'([^A-Z])([A-Z])')
-_upperstr_pat2 = re.compile(r'([A-Z][A-Z])([A-Z][0-9a-z])')
-_upperstr_pat3 = re.compile(r'^([A-Z])([A-Z])')
-
-def to_underscores(name):
- """Converts a typename to the equivalent underscores name.
- This is used to form the type conversion macros and enum/flag
- name variables"""
- name = _upperstr_pat1.sub(r'\1_\2', name)
- name = _upperstr_pat2.sub(r'\1_\2', name)
- name = _upperstr_pat3.sub(r'\1_\2', name, count=1)
- return name
-
-_libtool_pat = re.compile("dlname='([A-z0-9\.\-\+]+)'\n")
-
-def resolve_libtool(libname):
- data = open(libname).read()
- filename = _libtool_pat.search(data).groups()[0]
- libname = os.path.join(os.path.dirname(libname),
- '.libs', filename)
- return libname
+from .utils import extract_libtool, to_underscores
class GLibTransformer(object):
- def __init__(self, namespace_name):
- self._namespace_name = namespace_name
+
+ def __init__(self, transformer):
+ self._transformer = transformer
+ self._namespace_name = None
+ self._aliases = []
self._output_ns = odict()
- self._library = None
- self._type_names = {}
+ self._libraries = []
+ self._internal_types = {}
# Public API
- def get_nodes(self):
- return self._output_ns.values()
-
- def load_library(self, libname):
+ def add_library(self, libname):
if libname.endswith('.la'):
- libname = resolve_libtool(libname)
- self._library = ctypes.cdll.LoadLibrary(libname)
+ libname = extract_libtool(libname)
+ self._libraries.append(ctypes.cdll.LoadLibrary(libname))
+
+ def parse(self):
+ namespace = self._transformer.parse()
+ self._namespace_name = namespace.name
- def parse(self, nodes):
- for node in nodes:
+ # First pass, parsing
+ for node in namespace.nodes:
self._parse_node(node)
- # Second round
+ # Introspection is done from within parsing
+
+ # Second pass, resolving types
for node in self._output_ns.values():
# associate GtkButtonClass with GtkButton
if isinstance(node, Struct):
self._pair_class_struct(node)
+ self._resolve_node(node)
- def register_include(self, filename):
- if filename.endswith('.gir'):
- from .girparser import GIRParser
- parser = GIRParser(filename)
- elif filename.endswith('.gidl'):
- from .gidlparser import GIDLParser
- parser = GIDLParser(filename)
- else:
- raise NotImplementedError(filename)
- nsname = parser.get_namespace_name()
- for node in parser.get_nodes():
- self._type_names[node.type_name] = (nsname, node)
+ # Create a new namespace with what we found
+ namespace = Namespace(namespace.name)
+ namespace.nodes = self._aliases + self._output_ns.values()
+ return namespace
# Private
return self._output_ns.get(name)
def _register_internal_type(self, type_name, node):
- self._type_names[type_name] = (None, node)
-
- def _strip_namespace_func(self, name):
- orig_name = name
- prefix = self._namespace_name.lower() + '_'
- name = name.lower()
- if name.startswith(prefix):
- name = orig_name[len(prefix):]
- return name
-
- def _strip_namespace_object(self, name):
- orig_name = name
- prefix = self._namespace_name.lower()
- name = name.lower()
- if name.startswith(prefix):
- name = orig_name[len(prefix):]
- return name
+ self._internal_types[type_name] = node
- def _resolve_type_name(self, type_name):
- item = self._type_names.get(type_name)
- if item is not None:
- nsname, item = item
- if nsname is None:
- return item.name
- return '%s.%s' % (nsname, item.name)
- return type_name
+ # Helper functions
- def _resolve_param_type(self, ptype):
- type_name = ptype.name.replace('*', '')
- ptype.name = self._resolve_type_name(type_name)
- return ptype
+ def _create_type(self, type_id):
+ ctype = cgobject.type_name(type_id)
+ type_name = type_name_from_ctype(ctype)
+ return Type(type_name, ctype)
+
+ def _create_gobject(self, node):
+ type_name = 'G' + node.name
+ if type_name == 'GObject':
+ parent_type_name = None
+ symbol = 'intern'
+ else:
+ type_id = cgobject.type_from_name(type_name)
+ parent_type_name = cgobject.type_name(
+ cgobject.type_parent(type_id))
+ symbol = to_underscores(type_name).lower() + '_get_type'
+ node = GLibObject(node.name, parent_type_name, type_name, symbol)
+ type_id = cgobject.TYPE_OBJECT
+ self._introspect_properties(node, type_id)
+ self._introspect_signals(node, type_id)
+ self._add_attribute(node)
+ self._register_internal_type(type_name, node)
+
+ # Parser
def _parse_node(self, node):
if isinstance(node, Enum):
self._parse_struct(node)
elif isinstance(node, Callback):
self._parse_callback(node)
+ elif isinstance(node, Alias):
+ self._parse_alias(node)
+ elif isinstance(node, Member):
+ # FIXME: atk_misc_instance singletons
+ pass
else:
print 'GOBJECT BUILDER: Unhandled node:', node
+ def _parse_alias(self, alias):
+ self._aliases.append(alias)
+
def _parse_enum(self, enum):
- enum.name = self._strip_namespace_object(enum.name)
self._add_attribute(enum)
def _parse_function(self, func):
elif self._parse_method(func):
return
- self._parse_parameters(func.parameters)
- func.retval.type = self._resolve_param_type(func.retval.type)
-
- func.name = self._strip_namespace_func(func.name)
self._add_attribute(func)
- def _parse_parameters(self, parameters):
- for parameter in parameters:
- parameter.type = self._resolve_param_type(parameter.type)
-
def _parse_get_type_function(self, func):
- if self._library is None:
+ if not self._libraries:
return False
# GType *_get_type(void)
symbol = func.symbol
if not symbol.endswith('_get_type'):
return False
- if func.retval.type.name != 'GType':
+ if func.retval.type.name != 'GObject.GType':
return False
if func.parameters:
return False
- func = getattr(self._library, symbol)
+ for library in self._libraries:
+ try:
+ func = getattr(library, symbol)
+ break
+ except AttributeError:
+ continue
+ else:
+ print 'Warning: could not find symbol: %s' % symbol
+ return False
+
func.restype = cgobject.GType
func.argtypes = []
type_id = func()
# GtkButton -> gtk_button_, so we can figure out the method name
prefix = to_underscores(orig_name).lower() + '_'
- if not func.name.startswith(prefix):
+ if not func.symbol.startswith(prefix):
return False
# Strip namespace and object prefix: gtk_window_new -> new
- func.name = func.name[len(prefix):]
+ func.name = func.symbol[len(prefix):]
if is_method:
class_.methods.append(func)
else:
class_.constructors.append(func)
- self._parse_parameters(func.parameters)
- func.retval.type = self._resolve_param_type(func.retval.type)
return True
def _parse_struct(self, struct):
- type_name = self._resolve_type_name(struct.name)
- node = self._output_ns.get(type_name)
+ # This is a hack, but GObject is a rather fundamental piece so.
+ if (self._namespace_name == 'GObject' and
+ struct.name in ["Object", 'InitiallyUnowned']):
+ self._create_gobject(struct)
+ return
+ node = self._output_ns.get(struct.name)
if node is None:
self._add_attribute(struct, replace=True)
return
for field in class_node.fields[1:]:
node.fields.append(field)
- def _create_type(self, type_id):
- type_name = cgobject.type_name(type_id)
- return Type(type_name)
+ # Introspection
def _introspect_type(self, type_id, symbol):
fundamental_type_id = cgobject.type_fundamental(type_id)
elif fundamental_type_id == cgobject.TYPE_BOXED:
self._introspect_boxed(type_id, symbol)
else:
- print 'unhandled GType: %s' % (cgobject.type_name(type_id),)
+ print 'unhandled GType: %s' % (cgobject.type_name(type_id), )
def _introspect_enum(self, ftype_id, type_id, symbol):
type_class = cgobject.type_class_ref(type_id)
members = []
for enum_value in type_class.get_values():
- members.append(GLibEnumMember(enum_value.value_name,
+ members.append(GLibEnumMember(enum_value.value_nick,
enum_value.value,
+ enum_value.value_name,
enum_value.value_nick))
klass = (GLibFlags if ftype_id == cgobject.TYPE_FLAGS else GLibEnum)
type_name = cgobject.type_name(type_id)
- node = klass(self._strip_namespace_object(type_name),
- members, type_name, symbol)
+ enum_name = self._transformer.strip_namespace_object(type_name)
+ node = klass(enum_name, type_name, members, symbol)
self._add_attribute(node, replace=True)
self._register_internal_type(type_name, node)
def _introspect_object(self, type_id, symbol):
type_name = cgobject.type_name(type_id)
parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
- node = GLibObject(self._strip_namespace_object(type_name),
- self._resolve_type_name(parent_type_name),
- type_name, symbol)
+ node = GLibObject(
+ self._transformer.strip_namespace_object(type_name),
+ self._resolve_type_name(parent_type_name),
+ type_name, symbol)
self._introspect_properties(node, type_id)
self._introspect_signals(node, type_id)
self._add_attribute(node)
- self._remove_attribute(type_name)
+ try:
+ self._remove_attribute(type_name)
+ except KeyError:
+ print 'Warning: could not remove %s' % type_name
+ pass
self._register_internal_type(type_name, node)
def _introspect_interface(self, type_id, symbol):
type_name = cgobject.type_name(type_id)
- node = GLibInterface(self._strip_namespace_object(type_name),
- type_name, symbol)
+ parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
+ node = GLibInterface(
+ self._transformer.strip_namespace_object(type_name),
+ self._resolve_type_name(parent_type_name),
+ type_name, symbol)
self._introspect_properties(node, type_id)
self._introspect_signals(node, type_id)
self._add_attribute(node)
def _introspect_boxed(self, type_id, symbol):
type_name = cgobject.type_name(type_id)
- node = GLibBoxed(self._strip_namespace_object(type_name),
+ node = GLibBoxed(self._transformer.strip_namespace_object(type_name),
type_name, symbol)
self._add_attribute(node)
- self._remove_attribute(type_name)
+ # GdkEvent raises KeyError, FooBoxed ends up duplicated if we don't
+ try:
+ self._remove_attribute(type_name)
+ except KeyError:
+ pass
self._register_internal_type(type_name, node)
def _introspect_properties(self, node, type_id):
for pspec in pspecs:
if pspec.owner_type != type_id:
continue
+ ctype = cgobject.type_name(pspec.value_type)
node.properties.append(Property(
pspec.name,
- cgobject.type_name(pspec.value_type)))
+ type_name_from_ctype(ctype),
+ ctype,
+ ))
def _introspect_signals(self, node, type_id):
for signal_info in cgobject.signal_list(type_id):
- return_ = Return(cgobject.type_name(signal_info.return_type))
+ rtype = self._create_type(signal_info.return_type)
+ return_ = Return(rtype)
signal = GLibSignal(signal_info.signal_name, return_)
for i, parameter in enumerate(signal_info.get_params()):
if i == 0:
name = 'object'
else:
- name = 'p%s' % (i-1,)
+ name = 'p%s' % (i-1, )
ptype = self._create_type(parameter)
param = Parameter(name, ptype)
signal.parameters.append(param)
node.signals.append(signal)
+
+ # Resolver
+
+ def _resolve_type_name(self, type_name):
+ type_name = type_name.replace('*', '')
+ possible_name = self._transformer.resolve_type_name(type_name)
+ if possible_name != type_name:
+ return possible_name
+ possible_node = self._internal_types.get(type_name)
+ if possible_node:
+ return possible_node.name
+ return type_name
+
+ def _resolve_param_type(self, ptype):
+ ptype.name = ptype.name.replace('*', '')
+ type_name = ptype.name
+ type_name = self._transformer.resolve_possible_typedef(type_name)
+ possible_node = self._internal_types.get(type_name)
+ if possible_node:
+ ptype.name = possible_node.name
+ else:
+ ptype = self._transformer.resolve_param_type(ptype)
+ return ptype
+
+ def _resolve_node(self, node):
+ if isinstance(node, (Callback, Function)):
+ self._resolve_function(node)
+ elif isinstance(node, GLibObject):
+ self._resolve_glib_object(node)
+ elif isinstance(node, GLibInterface):
+ self._resolve_glib_interface(node)
+ elif isinstance(node, GLibBoxed):
+ self._resolve_glib_boxed(node)
+ elif isinstance(node, Struct):
+ self._resolve_struct(node)
+
+ def _resolve_struct(self, node):
+ for field in node.fields:
+ self._resolve_field(field)
+
+ def _resolve_glib_interface(self, node):
+ self._resolve_methods(node.methods)
+ self._resolve_properties(node.properties)
+ self._resolve_signals(node.signals)
+
+ def _resolve_glib_object(self, node):
+ self._resolve_constructors(node.constructors)
+ self._resolve_methods(node.methods)
+ self._resolve_properties(node.properties)
+ self._resolve_signals(node.signals)
+
+ def _resolve_glib_boxed(self, node):
+ self._resolve_constructors(node.constructors)
+ self._resolve_methods(node.methods)
+
+ def _resolve_constructors(self, constructors):
+ for ctor in constructors:
+ self._resolve_function(ctor)
+
+ def _resolve_methods(self, methods):
+ for method in methods:
+ self._resolve_function(method)
+
+ def _resolve_signals(self, signals):
+ for signal in signals:
+ self._resolve_function(signal)
+
+ def _resolve_properties(self, properties):
+ for prop in properties:
+ self._resolve_property(prop)
+
+ def _resolve_property(self, prop):
+ prop.type = self._resolve_param_type(prop.type)
+
+ def _resolve_function(self, func):
+ self._resolve_parameters(func.parameters)
+ func.retval.type = self._resolve_param_type(func.retval.type)
+
+ def _resolve_parameters(self, parameters):
+ for parameter in parameters:
+ parameter.type = self._resolve_param_type(parameter.type)
+
+ def _resolve_field(self, field):
+ if isinstance(field, Callback):
+ self._resolve_function(field)
+ return
+ field.type = self._resolve_param_type(field.type)