[TYPE_SUPPORT] Better type support
[gnome.gobject-introspection] / giscanner / ast.py
index 7cd4fc6..bc3a991 100644 (file)
@@ -1,21 +1,22 @@
 # -*- Mode: Python -*-
 # GObject-Introspection - a framework for introspecting GObject libraries
 # Copyright (C) 2008  Johan Dahlin
+# Copyright (C) 2008, 2009 Red Hat, Inc.
 #
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
 #
-# This program is distributed in the hope that it will be useful,
+# This library is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
 #
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
 #
 
 """AST nodes
@@ -35,6 +36,8 @@ TYPE_ANY = 'any'
 TYPE_BOOLEAN = 'boolean'
 TYPE_INT8 = 'int8'
 TYPE_UINT8 = 'uint8'
+TYPE_SHORT = 'short'
+TYPE_USHORT = 'ushort'
 TYPE_INT16 = 'int16'
 TYPE_UINT16 = 'uint16'
 TYPE_INT = 'int'
@@ -56,9 +59,10 @@ TYPE_FILENAME = 'filename'
 
 BASIC_GIR_TYPES = [TYPE_BOOLEAN, TYPE_INT8, TYPE_UINT8, TYPE_INT16,
                    TYPE_UINT16, TYPE_INT32, TYPE_UINT32, TYPE_INT64,
-                   TYPE_UINT64, TYPE_INT, TYPE_UINT, TYPE_LONG,
-                   TYPE_ULONG, TYPE_SSIZET, TYPE_SIZET, TYPE_FLOAT,
-                   TYPE_DOUBLE, TYPE_TIMET, TYPE_GTYPE]
+                   TYPE_UINT64, TYPE_SHORT, TYPE_USHORT, TYPE_INT,
+                   TYPE_UINT, TYPE_LONG, TYPE_ULONG, TYPE_SSIZET,
+                   TYPE_SIZET, TYPE_FLOAT, TYPE_DOUBLE, TYPE_TIMET,
+                   TYPE_GTYPE]
 GIR_TYPES = [TYPE_NONE, TYPE_ANY]
 GIR_TYPES.extend(BASIC_GIR_TYPES)
 GIR_TYPES.extend([TYPE_STRING, TYPE_FILENAME])
@@ -78,32 +82,50 @@ PARAM_DIRECTION_IN = 'in'
 PARAM_DIRECTION_OUT = 'out'
 PARAM_DIRECTION_INOUT = 'inout'
 
+PARAM_TRANSFER_NONE = 'none'
+PARAM_TRANSFER_CONTAINER = 'container'
+PARAM_TRANSFER_FULL = 'full'
+
 type_names = {}
 for name in GIR_TYPES:
     type_names[name] = name
 
-# C
+# C builtin
 type_names['char'] = TYPE_INT8
+type_names['signed char'] = TYPE_INT8
 type_names['unsigned char'] = TYPE_UINT8
-type_names['short'] = TYPE_INT16
-type_names['unsigned short'] = TYPE_UINT16
+type_names['short'] = TYPE_SHORT
+type_names['signed short'] = TYPE_SHORT
+type_names['unsigned short'] = TYPE_USHORT
 type_names['int'] = TYPE_INT
+type_names['signed int'] = TYPE_INT
+type_names['unsigned short int'] = TYPE_USHORT
+type_names['signed'] = TYPE_INT
 type_names['unsigned int'] = TYPE_UINT
+type_names['unsigned'] = TYPE_UINT
 type_names['long'] = TYPE_LONG
+type_names['signed long'] = TYPE_LONG
 type_names['unsigned long'] = TYPE_ULONG
+type_names['unsigned long int'] = TYPE_ULONG
 type_names['float'] = TYPE_FLOAT
 type_names['double'] = TYPE_DOUBLE
 type_names['char*'] = TYPE_STRING
 type_names['void*'] = TYPE_ANY
 type_names['void'] = TYPE_NONE
+
+# C unix types
+type_names['off_t'] = TYPE_SIZET
+type_names['pid_t'] = TYPE_INT
 type_names['size_t'] = TYPE_SIZET
 type_names['ssize_t'] = TYPE_SSIZET
-# FIXME - can we make libraries use GPid?
-type_names['pid_t'] = TYPE_INT
+type_names['socklen_t'] = TYPE_INT32
+
+# Obj-C
+type_names['id'] = TYPE_ANY
 
 # Suppress some GLib names
 type_names['uchar'] = TYPE_UINT8
-type_names['ushort'] = TYPE_UINT16
+type_names['ushort'] = TYPE_USHORT
 type_names['size'] = TYPE_SIZET
 type_names['ssize'] = TYPE_SSIZET
 type_names['pointer'] = TYPE_ANY
@@ -112,9 +134,15 @@ type_names['constpointer'] = TYPE_ANY
 
 # These types, when seen by reference, are converted into an Array()
 # by default
+# If you add/change these, be sure to update glibast.py too
 default_array_types = {}
 default_array_types['uint8*'] = TYPE_UINT8
-default_array_types['char**'] = TYPE_STRING
+default_array_types['utf8*'] = TYPE_STRING
+
+# These types, when seen by reference, are interpreted as out parameters
+default_out_types = (TYPE_SHORT, TYPE_USHORT, TYPE_INT, TYPE_UINT,
+                     TYPE_LONG, TYPE_ULONG, TYPE_FLOAT, TYPE_DOUBLE,
+                     TYPE_SIZET, TYPE_SSIZET)
 
 
 def type_name_from_ctype(ctype):
@@ -125,40 +153,109 @@ class Node(object):
 
     def __init__(self, name=None):
         self.name = name
+        self.attributes = [] # (key, value)*
+        self.skip = False
         self.deprecated = None
         self.deprecated_version = None
+        self.version = None
+
+    def __cmp__(self, other):
+        return cmp(self.name, other.name)
 
     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, self.name)
 
+    def remove_matching_children(self, pred):
+        pass
 
 class Namespace(Node):
 
-    def __init__(self, name):
+    def __init__(self, name, version):
         Node.__init__(self, name)
+        self.version = version
         self.nodes = []
 
     def __repr__(self):
-        return '%s(%r, %r)' % (self.__class__.__name__, self.name,
-                               self.nodes)
+        return '%s(%r, %r, %r)' % (self.__class__.__name__, self.name,
+                                   self.version, self.nodes)
+
+    def remove_matching(self, pred):
+
+        def recursive_pred(node):
+            node.remove_matching_children(pred)
+            return pred(node)
+
+        self.nodes = filter(recursive_pred, self.nodes)
+
+class Include(Node):
+
+    def __init__(self, name, version):
+        Node.__init__(self, 'include')
+        self.name = name
+        self.version = version
 
+    @classmethod
+    def from_string(self, string):
+        return Include(*string.split('-', 1))
 
-class Function(Node):
+    def __cmp__(self, other):
+        if not isinstance(other, Include):
+            return cmp(self, other)
+        namecmp = cmp(self.name, other.name)
+        if namecmp != 0:
+            return namecmp
+        return cmp(self.version, other.version)
 
-    def __init__(self, name, retval, parameters, symbol):
+    def __hash__(self):
+        return hash((self.name, self.version))
+
+    def __str__(self):
+        return '%s-%s' % (self.name, self.version)
+
+class Callable(Node):
+
+    def __init__(self, name, retval, parameters, throws):
         Node.__init__(self, name)
         self.retval = retval
         self.parameters = parameters
-        self.symbol = symbol
+        self.throws = not not throws
+        self.doc = None
 
     def __repr__(self):
         return '%s(%r, %r, %r)' % (self.__class__.__name__,
                                    self.name, self.retval,
                                    self.parameters)
 
+class Function(Callable):
+
+    def __init__(self, name, retval, parameters, symbol, throws=None):
+        Callable.__init__(self, name, retval, parameters, throws)
+        self.symbol = symbol
+        self.is_method = False
+        self.doc = None
+
+    def get_parameter_index(self, name):
+        for i, parameter in enumerate(self.parameters):
+            if parameter.name == name:
+                return i + int(self.is_method)
 
-class VFunction(Function):
-    pass
+    def get_parameter(self, name):
+        for parameter in self.parameters:
+            if parameter.name == name:
+                return parameter
+
+
+class VFunction(Callable):
+
+    def __init__(self, name, retval, parameters, throws):
+        Callable.__init__(self, name, retval, parameters, throws)
+        self.invoker = None
+
+    @classmethod
+    def from_callback(cls, cb):
+        obj = cls(cb.name, cb.retval, cb.parameters[1:],
+                  cb.throws)
+        return obj
 
 
 class Type(Node):
@@ -167,6 +264,15 @@ class Type(Node):
         Node.__init__(self, name)
         self.ctype = ctype
         self.resolved = False
+        self.is_const = False
+        self.canonical = None
+        self.derefed_canonical = None
+
+
+class Varargs(Type):
+
+    def __init__(self):
+        Type.__init__(self, '<varargs>')
 
 
 class Array(Type):
@@ -176,9 +282,11 @@ class Array(Type):
         self.element_type = element_type
         self.zeroterminated = True
         self.length_param_index = -1
+        self.length_param_name = None
+        self.size = None
 
     def __repr__(self):
-        return 'Array(%r of %r)' % (self.name, self.element_type, )
+        return 'Array(%r, %r)' % (self.name, self.element_type, )
 
 
 class List(Type):
@@ -199,7 +307,7 @@ class Map(Type):
         self.value_type = value_type
 
     def __repr__(self):
-        return 'Map(%r <%r,%r.)' % (self.name, self.key_type, self.value_type)
+        return 'Map(%r <%r,%r>)' % (self.name, self.key_type, self.value_type)
 
 
 class Alias(Node):
@@ -213,14 +321,34 @@ class Alias(Node):
         return 'Alias(%r, %r)' % (self.name, self.target)
 
 
-class Parameter(Node):
+class TypeContainer(Node):
 
-    def __init__(self, name, typenode):
+    def __init__(self, name, typenode, transfer):
         Node.__init__(self, name)
         self.type = typenode
-        self.direction = PARAM_DIRECTION_IN
-        self.transfer = False
-        self.allow_none = False
+        if transfer in [PARAM_TRANSFER_NONE, PARAM_TRANSFER_CONTAINER,
+                        PARAM_TRANSFER_FULL]:
+            self.transfer = transfer
+        else:
+            self.transfer = None
+
+
+class Parameter(TypeContainer):
+
+    def __init__(self, name, typenode, direction=None,
+                 transfer=None, allow_none=False, scope=None):
+        TypeContainer.__init__(self, name, typenode, transfer)
+        if direction in [PARAM_DIRECTION_IN, PARAM_DIRECTION_OUT,
+                         PARAM_DIRECTION_INOUT, None]:
+            self.direction = direction
+        else:
+            self.direction = PARAM_DIRECTION_IN
+
+        self.allow_none = allow_none
+        self.scope = scope
+        self.closure_index = -1
+        self.destroy_index = -1
+        self.doc = None
 
     def __repr__(self):
         return 'Parameter(%r, %r)' % (self.name, self.type)
@@ -232,11 +360,24 @@ class Enum(Node):
         Node.__init__(self, name)
         self.symbol = symbol
         self.members = members
+        self.doc = None
 
     def __repr__(self):
         return 'Enum(%r, %r)' % (self.name, self.members)
 
 
+class Bitfield(Node):
+
+    def __init__(self, name, symbol, members):
+        Node.__init__(self, name)
+        self.symbol = symbol
+        self.members = members
+        self.doc = None
+
+    def __repr__(self):
+        return 'Bitfield(%r, %r)' % (self.name, self.members)
+
+
 class Member(Node):
 
     def __init__(self, name, value, symbol):
@@ -248,32 +389,49 @@ class Member(Node):
         return 'Member(%r, %r)' % (self.name, self.value)
 
 
-class Struct(Node):
+class Record(Node):
 
-    def __init__(self, name, symbol):
+    def __init__(self, name, symbol, disguised=False):
         Node.__init__(self, name)
         self.fields = []
+        self.constructors = []
         self.symbol = symbol
+        self.disguised = disguised
+        self.doc = None
+        self.methods = []
+
+    def remove_matching_children(self, pred):
+        self.fields = filter(pred, self.fields)
+        self.constructors = filter(pred, self.constructors)
+        self.methods = filter(pred, self.methods)
+
+# BW compat, remove
+Struct = Record
 
 
 class Field(Node):
 
-    def __init__(self, name, typenode, symbol):
+    def __init__(self, name, typenode, symbol, readable, writable, bits=None):
         Node.__init__(self, name)
         self.type = typenode
         self.symbol = symbol
+        self.readable = readable
+        self.writable = writable
+        self.bits = bits
 
     def __repr__(self):
-        return 'Field(%r, %r)' % (self.name, self.type)
+        if self.bits:
+            return 'Field(%r, %r, %r)' % (self.name, self.type, self.bits)
+        else:
+            return 'Field(%r, %r)' % (self.name, self.type)
 
 
-class Return(Node):
+class Return(TypeContainer):
 
-    def __init__(self, rtype):
-        Node.__init__(self)
-        self.type = rtype
-        self.transfer = isinstance(rtype, (List, Map, Array)) or \
-            rtype.name in ('utf8', 'filename')
+    def __init__(self, rtype, transfer=None):
+        TypeContainer.__init__(self, None, rtype, transfer)
+        self.direction = PARAM_DIRECTION_OUT
+        self.doc = None
 
     def __repr__(self):
         return 'Return(%r)' % (self.type, )
@@ -281,15 +439,26 @@ class Return(Node):
 
 class Class(Node):
 
-    def __init__(self, name, parent):
+    def __init__(self, name, parent, is_abstract):
         Node.__init__(self, name)
         self.ctype = name
         self.parent = parent
+        self.glib_type_struct = None
+        self.is_abstract = is_abstract
         self.methods = []
+        self.virtual_methods = []
+        self.static_methods = []
         self.interfaces = []
         self.constructors = []
         self.properties = []
         self.fields = []
+        self.doc = None
+
+    def remove_matching_children(self, pred):
+        self.methods = filter(pred, self.methods)
+        self.constructors = filter(pred, self.constructors)
+        self.properties = filter(pred, self.properties)
+        self.fields = filter(pred, self.fields)
 
     def __repr__(self):
         return '%s(%r, %r, %r)' % (
@@ -303,8 +472,12 @@ class Interface(Node):
         Node.__init__(self, name)
         self.parent = parent
         self.methods = []
+        self.virtual_methods = []
+        self.glib_type_struct = None
         self.properties = []
         self.fields = []
+        self.prerequisites = []
+        self.doc = None
 
     def __repr__(self):
         return '%s(%r, %r)' % (
@@ -334,11 +507,12 @@ class Property(Node):
         self.writable = writable
         self.construct = construct
         self.construct_only = construct_only
+        self.doc = None
 
     def __repr__(self):
-        return '%s(%r, %r, %r)' % (
+        return '%s(%r, %r)' % (
             self.__class__.__name__,
-            self.name, self.type, self.value)
+            self.name, self.type)
 
 
 # FIXME: Inherit from Function
@@ -351,6 +525,18 @@ class Callback(Node):
         self.retval = retval
         self.parameters = parameters
         self.ctype = ctype
+        self.throws = False
+        self.doc = None
+
+    def get_parameter_index(self, name):
+        for i, parameter in enumerate(self.parameters):
+            if parameter.name == name:
+                return i
+
+    def get_parameter(self, name):
+        for parameter in self.parameters:
+            if parameter.name == name:
+                return parameter
 
     def __repr__(self):
         return 'Callback(%r, %r, %r)' % (
@@ -362,7 +548,10 @@ class Union(Node):
     def __init__(self, name, symbol):
         Node.__init__(self, name)
         self.fields = []
+        self.constructors = []
+        self.methods = []
         self.symbol = symbol
+        self.doc = None
 
     def __repr__(self):
         return 'Union(%r, %r)' % (self.name, self.fields, )