diff options
Diffstat (limited to 'giscanner/ast.py')
-rw-r--r-- | giscanner/ast.py | 184 |
1 files changed, 136 insertions, 48 deletions
diff --git a/giscanner/ast.py b/giscanner/ast.py index 654c68e2..b5b2ad71 100644 --- a/giscanner/ast.py +++ b/giscanner/ast.py @@ -20,22 +20,25 @@ # import copy +from itertools import chain from . import message +from .collections import OrderedDict from .message import Position -from .odict import odict from .utils import to_underscores + class Type(object): - """A Type can be either: -* A reference to a node (target_giname) -* A reference to a "fundamental" type like 'utf8' -* A "foreign" type - this can be any string." -If none are specified, then it's in an "unresolved" state. An -unresolved type can have two data sources; a "ctype" which comes -from a C type string, or a gtype_name (from g_type_name()). -""" # ''' + """ + A Type can be either: + * A reference to a node (target_giname) + * A reference to a "fundamental" type like 'utf8' + * A "foreign" type - this can be any string." + If none are specified, then it's in an "unresolved" state. An + unresolved type can have two data sources; a "ctype" which comes + from a C type string, or a gtype_name (from g_type_name()). + """ def __init__(self, ctype=None, @@ -83,6 +86,8 @@ from a C type string, or a gtype_name (from g_type_name()). return self.ctype elif self.gtype_name: return self.gtype_name + elif self.target_giname: + return self.target_giname else: assert False @@ -94,7 +99,8 @@ in contrast to the other create_type() functions.""" # First, is it a fundamental? fundamental = type_names.get(gtype_name) if fundamental is not None: - return cls(target_fundamental=fundamental.target_fundamental) + return cls(target_fundamental=fundamental.target_fundamental, + ctype=fundamental.ctype) if gtype_name == 'GHashTable': return Map(TYPE_ANY, TYPE_ANY, gtype_name=gtype_name) elif gtype_name in ('GArray', 'GPtrArray', 'GByteArray'): @@ -121,11 +127,12 @@ in contrast to the other create_type() functions.""" def __cmp__(self, other): if self.target_fundamental: return cmp(self.target_fundamental, other.target_fundamental) - if self.target_giname: + elif self.target_giname: return cmp(self.target_giname, other.target_giname) - if self.target_foreign: + elif self.target_foreign: return cmp(self.target_foreign, other.target_foreign) - return cmp(self.ctype, other.ctype) + else: + return cmp(self.ctype, other.ctype) def is_equiv(self, typeval): """Return True if the specified types are compatible at @@ -166,6 +173,7 @@ in contrast to the other create_type() functions.""" data = '' return '%s(%sctype=%s)' % (self.__class__.__name__, data, self.ctype) + class TypeUnknown(Type): def __init__(self): Type.__init__(self, _target_unknown=True) @@ -347,9 +355,7 @@ SIGNAL_MUST_COLLECT = 'must-collect' class Namespace(object): - def __init__(self, name, version, - identifier_prefixes=None, - symbol_prefixes=None): + def __init__(self, name, version, identifier_prefixes=None, symbol_prefixes=None): self.name = name self.version = version if identifier_prefixes is not None: @@ -363,11 +369,15 @@ class Namespace(object): self.symbol_prefixes = [to_underscores(p).lower() for p in ps] # cache upper-cased versions self._ucase_symbol_prefixes = [p.upper() for p in self.symbol_prefixes] - self.names = odict() # Maps from GIName -> node - self.aliases = {} # Maps from GIName -> GIName - self.type_names = {} # Maps from GTName -> node - self.ctypes = {} # Maps from CType -> node - self.symbols = {} # Maps from function symbols -> Function + self.names = OrderedDict() # Maps from GIName -> node + self.aliases = {} # Maps from GIName -> GIName + self.type_names = {} # Maps from GTName -> node + self.ctypes = {} # Maps from CType -> node + self.symbols = {} # Maps from function symbols -> Function + self.includes = set() # Include + self.shared_libraries = [] # str + self.c_includes = [] # str + self.exported_packages = [] # str def type_from_name(self, name, ctype=None): """Backwards compatibility method for older .gir files, which @@ -399,6 +409,24 @@ but adds it to things like ctypes, symbols, and type_names. self.type_names[node.gtype_name] = node elif isinstance(node, Function): self.symbols[node.symbol] = node + if isinstance(node, (Compound, Class, Interface)): + for fn in chain(node.methods, node.static_methods, node.constructors): + if not isinstance(fn, Function): + continue + fn.namespace = self + self.symbols[fn.symbol] = fn + if isinstance(node, (Class, Interface)): + for m in chain(node.signals, node.properties): + m.namespace = self + if isinstance(node, (Enum, Bitfield)): + for fn in node.static_methods: + if not isinstance(fn, Function): + continue + fn.namespace = self + self.symbols[fn.symbol] = fn + for member in node.members: + member.namespace = self + self.symbols[member.symbol] = member if hasattr(node, 'ctype'): self.ctypes[node.ctype] = node @@ -456,6 +484,7 @@ functions via get_by_symbol().""" for node in self.itervalues(): node.walk(callback, []) + class Include(object): def __init__(self, name, version): @@ -478,19 +507,23 @@ class Include(object): def __str__(self): return '%s-%s' % (self.name, self.version) + class Annotated(object): """An object which has a few generic metadata properties.""" def __init__(self): self.version = None + self.version_doc = None self.skip = False self.introspectable = True - self.attributes = [] # (key, value)* + self.attributes = OrderedDict() self.stability = None + self.stability_doc = None self.deprecated = None - self.deprecated_version = None + self.deprecated_doc = None self.doc = None + class Node(Annotated): """A node is a type of object which is uniquely identified by its (namespace, name) pair. When combined with a ., this is called a @@ -501,10 +534,21 @@ GIName. It's possible for nodes to contain or point to other nodes.""" def __init__(self, name=None): Annotated.__init__(self) - self.namespace = None # Should be set later by Namespace.append() + self.namespace = None # Should be set later by Namespace.append() self.name = name self.foreign = False self.file_positions = set() + self._parent = None + + def _get_parent(self): + if self._parent is not None: + return self._parent + else: + return self.namespace + + def _set_parent(self, value): + self._parent = value + parent = property(_get_parent, _set_parent) def create_type(self): """Create a Type object referencing this node.""" @@ -559,8 +603,16 @@ class Callable(Node): self.retval = retval self.parameters = parameters self.throws = not not throws - self.instance_parameter = None # Parameter - self.parent = None # A Class or Interface + self.instance_parameter = None # Parameter + self.parent = None # A Class or Interface + + # Returns all parameters, including the instance parameter + @property + def all_parameters(self): + if self.instance_parameter is not None: + return [self.instance_parameter] + self.parameters + else: + return self.parameters def get_parameter_index(self, name): for i, parameter in enumerate(self.parameters): @@ -569,7 +621,7 @@ class Callable(Node): raise ValueError("Unknown argument %s" % (name, )) def get_parameter(self, name): - for parameter in self.parameters: + for parameter in self.all_parameters: if parameter.argname == name: return parameter raise ValueError("Unknown argument %s" % (name, )) @@ -582,9 +634,10 @@ class Function(Callable): self.symbol = symbol self.is_method = False self.is_constructor = False - self.shadowed_by = None # C symbol string - self.shadows = None # C symbol string - self.moved_to = None # namespaced function name string + self.shadowed_by = None # C symbol string + self.shadows = None # C symbol string + self.moved_to = None # namespaced function name string + self.internal_skipped = False # if True, this func will not be written to GIR def clone(self): clone = copy.copy(self) @@ -595,9 +648,8 @@ class Function(Callable): def is_type_meta_function(self): # Named correctly - if not (self.name.endswith('_get_type') or - self.name.endswith('_get_gtype')): - return False + if not (self.name.endswith('_get_type') or self.name.endswith('_get_gtype')): + return False # Doesn't have any parameters if self.parameters: @@ -605,14 +657,13 @@ class Function(Callable): # Returns GType rettype = self.retval.type - if (not rettype.is_equiv(TYPE_GTYPE) and - rettype.target_giname != 'Gtk.Type'): - message.warn("function '%s' returns '%r', not a GType" % - (self.name, rettype)) + if (not rettype.is_equiv(TYPE_GTYPE) and rettype.target_giname != 'Gtk.Type'): + message.warn("function '%s' returns '%r', not a GType" % (self.name, rettype)) return False return True + class ErrorQuarkFunction(Function): def __init__(self, name, retval, parameters, throws, symbol, error_domain): @@ -633,7 +684,6 @@ class VFunction(Callable): return obj - class Varargs(Type): def __init__(self): @@ -669,6 +719,7 @@ class Array(Type): arr.size = self.size return arr + class List(Type): def __init__(self, name, element_type, **kwargs): @@ -681,6 +732,7 @@ class List(Type): def clone(self): return List(self.name, self.element_type) + class Map(Type): def __init__(self, key_type, value_type, **kwargs): @@ -693,6 +745,7 @@ class Map(Type): def clone(self): return Map(self.key_type, self.value_type) + class Alias(Node): def __init__(self, name, target, ctype=None): @@ -751,6 +804,8 @@ class Enum(Node, Registered): self.c_symbol_prefix = c_symbol_prefix self.ctype = ctype self.members = members + for member in members: + member.parent = self # Associated error domain name self.error_domain = None self.static_methods = [] @@ -772,6 +827,8 @@ class Bitfield(Node, Registered): self.ctype = ctype self.c_symbol_prefix = c_symbol_prefix self.members = members + for member in members: + member.parent = self self.static_methods = [] def _walk(self, callback, chain): @@ -787,10 +844,13 @@ class Member(Annotated): self.value = value self.symbol = symbol self.nick = nick + self.parent = None def __cmp__(self, other): return cmp(self.name, other.name) + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, self.name) class Compound(Node, Registered): @@ -799,7 +859,8 @@ class Compound(Node, Registered): gtype_name=None, get_type=None, c_symbol_prefix=None, - disguised=False): + disguised=False, + tag_name=None): Node.__init__(self, name) Registered.__init__(self, gtype_name, get_type) self.ctype = ctype @@ -811,6 +872,7 @@ class Compound(Node, Registered): self.gtype_name = gtype_name self.get_type = get_type self.c_symbol_prefix = c_symbol_prefix + self.tag_name = tag_name def add_gtype(self, gtype_name, get_type): self.gtype_name = gtype_name @@ -828,6 +890,19 @@ class Compound(Node, Registered): if field.anonymous_node is not None: field.anonymous_node.walk(callback, chain) + def get_field(self, name): + for field in self.fields: + if field.name == name: + return field + raise ValueError("Unknown field %s" % (name, )) + + def get_field_index(self, name): + for i, field in enumerate(self.fields): + if field.name == name: + return i + raise ValueError("Unknown field %s" % (name, )) + + class Field(Annotated): def __init__(self, name, typenode, readable, writable, bits=None, @@ -841,10 +916,14 @@ class Field(Annotated): self.bits = bits self.anonymous_node = anonymous_node self.private = False + self.parent = None # a compound def __cmp__(self, other): return cmp(self.name, other.name) + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, self.name) + class Record(Compound): @@ -853,13 +932,15 @@ class Record(Compound): gtype_name=None, get_type=None, c_symbol_prefix=None, - disguised=False): + disguised=False, + tag_name=None): Compound.__init__(self, name, ctype=ctype, gtype_name=gtype_name, get_type=get_type, c_symbol_prefix=c_symbol_prefix, - disguised=disguised) + disguised=disguised, + tag_name=tag_name) # If non-None, this record defines the FooClass C structure # for some Foo GObject (or similar for GInterface) self.is_gtype_struct_for = None @@ -872,13 +953,15 @@ class Union(Compound): gtype_name=None, get_type=None, c_symbol_prefix=None, - disguised=False): + disguised=False, + tag_name=None): Compound.__init__(self, name, ctype=ctype, gtype_name=gtype_name, get_type=get_type, c_symbol_prefix=c_symbol_prefix, - disguised=disguised) + disguised=disguised, + tag_name=tag_name) class Boxed(Node, Registered): @@ -922,7 +1005,7 @@ class Signal(Callable): class Class(Node, Registered): - def __init__(self, name, parent, + def __init__(self, name, parent_type, ctype=None, gtype_name=None, get_type=None, @@ -932,7 +1015,7 @@ class Class(Node, Registered): Registered.__init__(self, gtype_name, get_type) self.ctype = ctype self.c_symbol_prefix = c_symbol_prefix - self.parent = parent + self.parent_type = parent_type self.fundamental = False self.unref_func = None self.ref_func = None @@ -967,11 +1050,13 @@ class Class(Node, Registered): field.anonymous_node.walk(callback, chain) for sig in self.signals: sig.walk(callback, chain) + for prop in self.properties: + prop.walk(callback, chain) class Interface(Node, Registered): - def __init__(self, name, parent, + def __init__(self, name, parent_type, ctype=None, gtype_name=None, get_type=None, @@ -980,7 +1065,7 @@ class Interface(Node, Registered): Registered.__init__(self, gtype_name, get_type) self.ctype = ctype self.c_symbol_prefix = c_symbol_prefix - self.parent = parent + self.parent_type = parent_type self.parent_chain = [] self.methods = [] self.signals = [] @@ -990,6 +1075,9 @@ class Interface(Node, Registered): self.properties = [] self.fields = [] self.prerequisites = [] + # Not used yet, exists just to avoid an exception in + # Namespace.append() + self.constructors = [] def _walk(self, callback, chain): for meth in self.methods: @@ -1028,7 +1116,7 @@ class Property(Node): self.transfer = PARAM_TRANSFER_NONE else: self.transfer = transfer - self.parent = None # A Class or Interface + self.parent = None # A Class or Interface class Callback(Callable): |