summaryrefslogtreecommitdiff
path: root/giscanner/ast.py
diff options
context:
space:
mode:
Diffstat (limited to 'giscanner/ast.py')
-rw-r--r--giscanner/ast.py152
1 files changed, 110 insertions, 42 deletions
diff --git a/giscanner/ast.py b/giscanner/ast.py
index 654c68e2..4c54b548 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,6 +507,7 @@ 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."""
@@ -485,12 +515,13 @@ properties."""
self.version = None
self.skip = False
self.introspectable = True
- self.attributes = [] # (key, value)*
+ self.attributes = [] # (key, value)*
self.stability = None
self.deprecated = None
self.deprecated_version = 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 +532,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 +601,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 +619,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 +632,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 +646,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 +655,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 +682,6 @@ class VFunction(Callable):
return obj
-
class Varargs(Type):
def __init__(self):
@@ -669,6 +717,7 @@ class Array(Type):
arr.size = self.size
return arr
+
class List(Type):
def __init__(self, name, element_type, **kwargs):
@@ -681,6 +730,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 +743,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 +802,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 +825,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 +842,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):
@@ -828,6 +886,7 @@ class Compound(Node, Registered):
if field.anonymous_node is not None:
field.anonymous_node.walk(callback, chain)
+
class Field(Annotated):
def __init__(self, name, typenode, readable, writable, bits=None,
@@ -841,10 +900,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):
@@ -922,7 +985,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 +995,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 +1030,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 +1045,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 +1055,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 +1096,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):