[glibmm/gmmproc-refactor] Add new conversions and type info system.



commit 0799dbb37430b05c6e06c70d33646622723e6c3a
Author: Krzesimir Nowak <qdlacz gmail com>
Date:   Wed Jun 6 03:34:40 2012 +0200

    Add new conversions and type info system.
    
    New conversions system allows us to specify conversion in general
    manner like:
    GtkWidget <=> Gtk::Widget ## NORMAL
    so we do not need to write every possible specific conversion
    out there.

 tools/pm/Common/TypeDetails.pm                   |  213 ++++
 tools/pm/Common/TypeDetails/Base.pm              |  218 ++++
 tools/pm/Common/TypeDetails/Container.pm         |  136 +++
 tools/pm/Common/TypeDetails/Value.pm             |  251 +++++
 tools/pm/Common/TypeInfo.pm                      |   31 +
 tools/pm/Common/TypeInfo/Common.pm               |  142 +++
 tools/pm/Common/TypeInfo/Convertors.pm           |   35 +
 tools/pm/Common/TypeInfo/Convertors/Enum.pm      |   53 +
 tools/pm/Common/TypeInfo/Convertors/Equal.pm     |   66 ++
 tools/pm/Common/TypeInfo/Convertors/Func.pm      |   33 +
 tools/pm/Common/TypeInfo/Convertors/Manual.pm    |   31 +
 tools/pm/Common/TypeInfo/Convertors/Normal.pm    |   32 +
 tools/pm/Common/TypeInfo/Convertors/Reffed.pm    |  254 +++++
 tools/pm/Common/TypeInfo/Convertors/StdString.pm |  289 +++++
 tools/pm/Common/TypeInfo/Convertors/Ustring.pm   |  289 +++++
 tools/pm/Common/TypeInfo/Global.pm               | 1310 ++++++++++++++++++++++
 tools/pm/Common/TypeInfo/Local.pm                |   94 ++
 17 files changed, 3477 insertions(+), 0 deletions(-)
---
diff --git a/tools/pm/Common/TypeDetails.pm b/tools/pm/Common/TypeDetails.pm
new file mode 100644
index 0000000..2825109
--- /dev/null
+++ b/tools/pm/Common/TypeDetails.pm
@@ -0,0 +1,213 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeDetails::Base module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeDetails;
+
+use strict;
+use warnings;
+
+use Common::TypeDetails::Base;
+use Common::TypeDetails::Container;
+use Common::TypeDetails::Value;
+
+#
+# That does not support function types ('int (*)(int,
+# double)').
+#
+# PTR_TYPE -> [VAL_TYPE, REF_TYPE, PTR_TYPE, FUN_TYPE(x)]
+# REF_TYPE -> [VAL_TYPE, REF_TYPE(?), PTR_TYPE(x)]
+# VAL_TYPE -> NIL
+# FUN_TYPE(x) -> NIL
+#
+# (x) - NIH
+# (?) - incorrect in C++
+#
+sub disassemble_type ($);
+
+sub disassemble_type ($)
+{
+  my ($cxx_type_or_array_ref) = @_;
+  my $parameter_ref = ref $cxx_type_or_array_ref;
+  my $parts = undef;
+  unless ($parameter_ref)
+  {
+    # string was passed
+    my @temp_parts = reverse split /(\w+|[()*&<>,`']|::)/, $cxx_type_or_array_ref;
+
+    $parts = \ temp_parts;
+  }
+  elsif ($parameter_ref eq 'ARRAY')
+  {
+    # array ref was passed
+    $parts = $cxx_type_or_array_ref;
+  }
+  die unless defined $parts;
+
+  my $const = 0;
+  my $volatile = 0;
+
+  while (@{$parts})
+  {
+    my $part = shift @{$parts};
+
+    next if (not defined $part or $part eq '');
+
+    if ($part eq 'const')
+    {
+      die if $const;
+      $const = 1;
+    }
+    elsif ($part eq 'volatile')
+    {
+      die if $volatile;
+      $volatile = 1;
+    }
+    elsif ($part eq '*' or $part eq '&')
+    {
+      # this is container type - either pointer or reference.
+      my $contained_type = disassemble_type $parts;
+
+      return Common::TypeDetails::Container->new ($const,
+                                                  $volatile,
+                                                  $contained_type,
+                                                  $part);
+    }
+    elsif ($part !~ /^\s+$/)
+    {
+      # this is value type, put token back and continue
+      # parsing in another loop.
+      unshift @{$parts}, $part;
+      last;
+    }
+  }
+
+  my @template_parts = ();
+  my $template_level = 0;
+  my $template = undef;
+  my @type_parts = ();
+  my $base_type = '';
+  my $imbue_type = undef;
+  my $collect_imbue_type = 0;
+  my @imbue_parts = ();
+
+  foreach my $part (@{$parts})
+  {
+    next if $part eq '';
+
+    if ($collect_imbue_type)
+    {
+      my $gather_parts = 0;
+
+      if ($part eq '`')
+      {
+        $gather_parts = 1;
+        $collect_imbue_type = 0;
+      }
+      elsif ($part eq ',')
+      {
+        $gather_parts = 1;
+      }
+
+      if ($gather_parts)
+      {
+        push @{$imbue_type}, join ('', @imbue_parts);
+        @imbue_parts = ();
+      }
+      else
+      {
+        push @imbue_parts, $part;
+      }
+    }
+    elsif ($template_level)
+    {
+      ++$template_level if ($part eq '>');
+      --$template_level if ($part eq '<');
+
+      if ($template_level == 0 or ($template_level == 1 and $part eq ','))
+      {
+        my $template_type = disassemble_type \ template_parts;
+
+        push @{$template}, $template_type;
+        @template_parts = ();
+      }
+      else
+      {
+        push @template_parts, $part;
+      }
+    }
+    elsif ($part eq '>')
+    {
+      die if defined $template;
+      die if defined $imbue_type;
+      $template_level = 1;
+      $template = [];
+    }
+    elsif ($part eq 'const')
+    {
+      # there cannot be any modifiers between template/imbue type and
+      # base type.
+      die if ((defined ($template) or defined ($imbue_type)) and @type_parts == 0);
+      die if $const;
+      $const = 1;
+    }
+    elsif ($part eq 'volatile')
+    {
+      # there cannot be any modifiers between template/imbue type and
+      # base type.
+      die if ((defined ($template) or defined ($imbue_type)) and @type_parts == 0);
+      die if $volatile;
+      $volatile = 1;
+    }
+    elsif ($part eq '\'')
+    {
+      die if defined $template;
+      die if defined $imbue_type;
+      $collect_imbue_type = 1;
+      $imbue_type = [];
+    }
+    elsif ($part =~ /^[,&*]$/)
+    {
+      die;
+    }
+    elsif ($part !~ /^\s+$/)
+    {
+      push @type_parts, $part;
+    }
+  }
+
+  $base_type = join '', reverse @type_parts;
+
+  unless (defined ($template))
+  {
+    $template = [];
+  }
+  unless (defined ($imbue_type))
+  {
+    $imbue_type = [];
+  }
+
+  return Common::TypeDetails::Value->new ($const,
+                                          $volatile,
+                                          $base_type,
+                                          $template,
+                                          $imbue_type);
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeDetails/Base.pm b/tools/pm/Common/TypeDetails/Base.pm
new file mode 100644
index 0000000..6b2fa6a
--- /dev/null
+++ b/tools/pm/Common/TypeDetails/Base.pm
@@ -0,0 +1,218 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeDetails::Base module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeDetails::Base;
+
+use strict;
+use warnings;
+
+use constant
+{
+  NONE => 0,
+  BASE => 1 << 0,
+  ACCESS_MODIFIERS => (1 << 1),
+  STRUCTURE => 1 << 2,
+  RECURSIVE => 1 << 2 | 1 << 3 # recursive check forces structure equality
+};
+
+sub _get_split_values ($)
+{
+  return '?cv';
+}
+
+sub _get_sigil ($)
+{
+  my ($self) = @_;
+
+  return $self->{'sigil'};
+}
+
+sub _tokenize ($$)
+{
+  my ($self, $match) = @_;
+  my $split_values = $self->_get_split_values ();
+  my @preliminary_tokens = split (/([$split_values])/, $match);
+  my @final_tokens = ();
+
+  foreach my $token (@preliminary_tokens)
+  {
+    if (defined $token and $token ne '')
+    {
+      unshift (@final_tokens, $token);
+    }
+  }
+
+  return \ final_tokens;
+}
+
+sub new ($$$$)
+{
+  my ($type, $const, $volatile, $sigil) = @_;
+  my $class = (ref $type or $type or 'Common::TypeDetails::Base');
+  my $self =
+  {
+    'const' => $const,
+    'volatile' => $volatile,
+    'sigil' => $sigil
+  };
+
+  return bless $self, $class;
+}
+
+sub get_value_details ($)
+{
+# TODO: not implemented error.
+  die;
+}
+
+sub match_sigil ($$$)
+{
+# TODO: not implemented error.
+  die;
+}
+
+sub match_basic_sigil ($$$)
+{
+  my ($self, $match, $flags) = @_;
+  my $const_checked = 0;
+  my $volatile_checked = 0;
+  my $do_not_care = 0;
+  my $drop = 0;
+
+  unless (defined ($flags))
+  {
+    $flags = NONE;
+  }
+
+  my $check = (($flags & ACCESS_MODIFIERS) == ACCESS_MODIFIERS);
+
+  foreach my $index (-1, -2, -3)
+  {
+    my $char = '';
+
+    if (length ($match) >= -$index)
+    {
+      $char = substr ($match, $index, 1);
+    }
+
+    if ($char eq 'c')
+    {
+      if ($do_not_care or $const_checked or ($check and not $self->get_const ()))
+      {
+        return undef;
+      }
+      $const_checked = 1;
+      ++$drop;
+    }
+    elsif ($char eq 'v')
+    {
+      if ($do_not_care or $volatile_checked or ($check and not $self->get_volatile ()))
+      {
+        return undef;
+      }
+      $volatile_checked = 0;
+      ++$drop;
+    }
+    elsif ($char eq '?')
+    {
+      if ($const_checked or $volatile_checked or $do_not_care)
+      {
+        return undef;
+      }
+      $do_not_care = 1;
+      ++$drop;
+    }
+    else
+    {
+      last;
+    }
+  }
+
+  if ($check and ((not $const_checked and $self->get_const ()) or (not $volatile_checked and $self->get_volatile ())))
+  {
+    return undef;
+  }
+
+  if ($drop)
+  {
+    return substr ($match, 0, -$drop);
+  }
+  return $match;
+}
+
+sub equal ($$$)
+{
+  my ($self, $other, $flags) = @_;
+
+  if ($flags & ACCESS_MODIFIERS == ACCESS_MODIFIERS)
+  {
+    if ($self->get_const () != $other->get_const () or
+        $self->get_volatile () != $other->get_volatile ())
+    {
+      return 0;
+    }
+  }
+
+  if ((($flags & STRUCTURE) == STRUCTURE) and $self->_get_sigil () ne $other->_get_sigil ())
+  {
+    return 0;
+  }
+
+  return 1;
+}
+
+sub get_string ($)
+{
+# TODO: not implemented error
+  die;
+}
+
+sub get_basic_string ($)
+{
+  my ($self) = @_;
+  my @str = ();
+
+  if ($self->get_const ())
+  {
+    push (@str, 'const');
+  }
+  if ($self->get_volatile ())
+  {
+    push (@str, 'volatile');
+  }
+
+  return join (' ', @str);
+}
+
+sub get_const ($)
+{
+  my ($self) = @_;
+
+  return $self->{'const'};
+}
+
+sub get_volatile ($)
+{
+  my ($self) = @_;
+
+  return $self->{'volatile'};
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeDetails/Container.pm b/tools/pm/Common/TypeDetails/Container.pm
new file mode 100644
index 0000000..b666059
--- /dev/null
+++ b/tools/pm/Common/TypeDetails/Container.pm
@@ -0,0 +1,136 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeDetails::Container module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeDetails::Container;
+
+use strict;
+use warnings;
+
+use parent qw(Common::TypeDetails::Base);
+
+sub _get_contained_type ($)
+{
+  my ($self) = @_;
+
+  return $self->{'contained_type'};
+}
+
+sub _get_sigil ($)
+{
+  my ($self) = @_;
+
+  return $self->{'sigil'};
+}
+
+sub _get_split_values ($)
+{
+  my ($self) = @_;
+  my $sigil = $self->_get_sigil ();
+
+  return join ('', $self->SUPER::_get_split_values (), $sigil);
+}
+
+sub new ($$$)
+{
+  my ($type, $const, $volatile, $contained_type, $sigil) = @_;
+  my $class = (ref $type or $type or 'Common::TypeDetails::Container');
+  my $self = $class->SUPER::new ($const, $volatile, $sigil);
+
+  $self->{'contained_type'} = $contained_type;
+
+  return bless $self, $class;
+}
+
+sub get_value_details ($)
+{
+  my ($self) = @_;
+  my $contained_type = $self->_get_contained_type;
+
+  return $contained_type->get_value_details;
+}
+
+sub match_sigil ($$$)
+{
+  my ($self, $matches, $flags) = @_;
+  my $sigil = $self->_get_sigil ();
+
+  unless (ref ($matches))
+  {
+    $matches = [$matches];
+  }
+  unless (defined ($flags))
+  {
+    $flags = Common::TypeDetails::Base::NONE;
+  }
+
+  foreach my $match (@{$matches})
+  {
+    $match = $self->match_basic_sigil ($match, $flags);
+
+    next unless (defined $match);
+
+    my $tokens = $self->_tokenize ($match);
+
+    if (@{$tokens} and $tokens->[0] eq $sigil)
+    {
+      my $contained_type = $self->_get_contained_type ();
+      my $sub_match = substr ($match, 0, -1);
+      my $matched = $contained_type->match_sigil ($sub_match, $flags);
+
+      if ($matched)
+      {
+        return $matched;
+      }
+    }
+  }
+  return 0;
+}
+
+sub get_string ($)
+{
+  my ($self) = @_;
+  my $contained_type = $self->_get_contained_type ();
+  my $sigil = self->_get_sigil ();
+  my $basic_string = $self->get_basic_string ();
+
+  return ($contained_type->get_string () . $sigil . ($basic_string ? ' ' . $basic_string : ''));
+}
+
+sub equal ($$$)
+{
+  my ($self, $other, $flags) = @_;
+
+  unless ($self->SUPER::equal ($other, $flags))
+  {
+    return 0;
+  }
+
+  if (($flags & Common::TypeDetails::Base::RECURSIVE) == Common::TypeDetails::Base::RECURSIVE)
+  {
+    my $self_contained_type = $self->_get_contained_type;
+    my $other_contained_type = $self->_get_contained_type;
+
+    return $self_contained_type->equal ($other_contained_type);
+  }
+
+  return 1;
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeDetails/Value.pm b/tools/pm/Common/TypeDetails/Value.pm
new file mode 100644
index 0000000..672ac43
--- /dev/null
+++ b/tools/pm/Common/TypeDetails/Value.pm
@@ -0,0 +1,251 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeDetails::Value module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeDetails::Value;
+
+use strict;
+use warnings;
+
+use parent qw(Common::TypeDetails::Base);
+
+sub _get_split_values ($)
+{
+  my ($self) = @_;
+
+  return join ('', $self->SUPER::_get_split_values (), '<>,!#');
+}
+
+sub new ($$$$$$)
+{
+  my ($type, $const, $volatile, $base, $templates, $imbue_type) = @_;
+  my $class = (ref $type or $type or 'Common::TypeDetails::Value');
+  my $self = $class->SUPER::new ($const, $volatile, '');
+
+  $self->{'base'} = $base;
+  $self->{'templates'} = $templates;
+  $self->{'imbue_type'} = $imbue_type;
+
+  return bless $self, $class;
+}
+
+sub get_base ($)
+{
+  my ($self) = @_;
+
+  return $self->{'base'};
+}
+
+sub get_templates ($)
+{
+  my ($self) = @_;
+
+  return $self->{'templates'};
+}
+
+sub get_imbue_type ($)
+{
+  my ($self) = @_;
+
+  return $self->{'imbue_type'};
+}
+
+sub get_value_details ($)
+{
+  my ($self) = @_;
+
+  return $self;
+}
+
+sub match_sigil ($$$)
+{
+  my ($self, $matches, $flags) = @_;
+
+  unless (ref ($matches))
+  {
+    $matches = [$matches];
+  }
+  unless (defined ($flags))
+  {
+    $flags = Common::TypeDetails::Base::NONE;
+  }
+
+  foreach my $match (@{$matches})
+  {
+    $match = $self->match_basic_sigil ($match, $flags);
+    next unless (defined $match);
+
+    my $tokens = $self->_tokenize ($match);
+    my @templates = reverse @{$self->get_templates ()};
+
+    if (not @{$tokens} and not @templates)
+    {
+      return 1;
+    }
+    elsif ((@{$tokens} xor @templates) or shift @{$tokens} ne '>')
+    {
+      next;
+    }
+
+    my $do_not_care_all = 0;
+    my $do_not_care_single = 0;
+    my $template_param = '';
+    my $template_level = 0;
+    my $done = 0;
+
+    foreach my $token (@${tokens})
+    {
+      if ($done)
+      {
+        # too many tokens.
+        $done = 0;
+        last;
+      }
+      elsif ($template_level > 0)
+      {
+        $template_param = join ('', $token, $template_param);
+
+        ++$template_level if ($token eq '>');
+        --$template_level if ($token eq '<');
+      }
+      elsif ($do_not_care_all eq 1)
+      {
+        if ($token eq '<')
+        {
+          $done = 1;
+        }
+        last;
+      }
+      elsif ($do_not_care_single)
+      {
+        if ($token eq '<')
+        {
+          if (@templates == 1)
+          {
+            $done = 1;
+          }
+          last;
+        }
+        elsif ($token eq ',')
+        {
+          last unless (@templates);
+          shift (@templates);
+          $do_not_care_single = 0;
+        }
+      }
+      elsif ($token eq '!')
+      {
+        $do_not_care_all = 1;
+      }
+      elsif ($token eq '#')
+      {
+        $do_not_care_single = 1;
+      }
+      elsif ($token eq ',' or $token eq '<')
+      {
+        last unless (@templates);
+
+        my $template_details = shift (@templates);
+
+        last unless ($template_details->match_sigil ($template_param, $flags));
+        $template_param = '';
+        if ($token eq '<')
+        {
+          $done = 1;
+        }
+      }
+      else
+      {
+        ++$template_level if ($token eq '>');
+        $template_param = join ('', $token, $template_param);
+      }
+    }
+    if ($done)
+    {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+sub get_string ($)
+{
+  my ($self) = @_;
+  my $basic_string = $self->get_basic_string ();
+  my $result = ($basic_string ? $basic_string . ' ' : '')  . $self->get_base ();
+  my $templates = $self->get_templates ();
+
+  if (@{$templates})
+  {
+    $result .= '< ';
+    foreach my $template_details (@{$templates})
+    {
+      $result .= $template_details->get_string ();
+    }
+    $result .= ' >';
+  }
+
+  return $result;
+}
+
+sub equal ($$$)
+{
+  my ($self, $other, $flags) = @_;
+
+  unless ($self->SUPER::equal ($other, $flags))
+  {
+    return 0;
+  }
+
+  if (($flags & Common::TypeDetails::Base::BASE) == Common::TypeDetails::Base::BASE)
+  {
+    my $self_base = $self->_get_base;
+    my $other_base = $self->_get_base;
+
+    if ($self_base ne $other_base)
+    {
+      return 0;
+    }
+
+    if (($flags & Common::TypeDetails::Base::RECURSIVE) == Common::TypeDetails::Base::RECURSIVE)
+    {
+      my $self_template = $self->_get_template;
+      my $other_template = $other->_get_template;
+      my $self_template_count = @{$self_template};
+      my $other_template_count = @{$other_template};
+
+      if ($self_template_count != $other_template_count)
+      {
+        return 0;
+      }
+
+      my %check = map { ($self_template->[$_]->equal ($other_template->[$_], $flags)) => undef; } 0 .. $self_template_count - 1;
+
+      if (exists $check{'0'})
+      {
+        return 0;
+      }
+    }
+
+  }
+
+  return 1;
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo.pm b/tools/pm/Common/TypeInfo.pm
new file mode 100644
index 0000000..9d92bab
--- /dev/null
+++ b/tools/pm/Common/TypeInfo.pm
@@ -0,0 +1,31 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo;
+
+use strict;
+use warnings;
+
+use Common::TypeInfo::Common;
+use Common::TypeInfo::Convertors;
+use Common::TypeInfo::Global;
+use Common::TypeInfo::Local;
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo/Common.pm b/tools/pm/Common/TypeInfo/Common.pm
new file mode 100644
index 0000000..efa8567
--- /dev/null
+++ b/tools/pm/Common/TypeInfo/Common.pm
@@ -0,0 +1,142 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo::Common module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo::Common;
+
+use strict;
+use warnings;
+use feature ':5.10';
+use constant
+{
+  'TRANSFER_INVALID' => -1, # do not use
+  'TRANSFER_NONE' => 0,
+  'TRANSFER_CONTAINER' => 1,
+  'TRANSFER_FULL' => 2,
+  'TRANSFER_LAST' => 3 # do not use
+};
+
+sub transfer_good_range ()
+{
+  return (TRANSFER_NONE .. TRANSFER_FULL);
+}
+
+sub transfer_from_string ($)
+{
+  my ($string) = @_;
+
+  given ($string)
+  {
+    when ('none')
+    {
+      return TRANSFER_NONE;
+    }
+    when ('container')
+    {
+      return TRANSFER_CONTAINER;
+    }
+    when ('full')
+    {
+      return TRANSFER_FULL;
+    }
+    default
+    {
+      return TRANSFER_INVALID;
+    }
+  }
+}
+
+sub transfer_to_string ($)
+{
+  my ($transfer) = @_;
+
+  given ($transfer)
+  {
+    when (TRANSFER_NONE)
+    {
+      return 'none';
+    }
+    when (TRANSFER_CONTAINER)
+    {
+      return 'container';
+    }
+    when (TRANSFER_FULL)
+    {
+      return 'full';
+    }
+    default
+    {
+      return 'invalid';
+    }
+  }
+}
+
+sub add_specific_conversion ($$$$$$)
+{
+  my ($conversions, $from, $to, $transfer_none, $transfer_container, $transfer_full) = @_;
+  unless (exists $conversions->{$from})
+  {
+    $conversions->{$from} = {};
+  }
+
+  my $from_conversions = $conversions->{$from};
+
+  unless (exists $from_conversions->{$to})
+  {
+    $from_conversions->{$to} = [$transfer_none, $transfer_container, $transfer_full];
+  }
+# TODO: what should be done with duplicates?
+}
+
+sub get_specific_conversion ($$$$$)
+{
+  my ($conversions, $from, $to, $transfer, $name) = @_;
+  my $conversion = undef;
+
+  if ($transfer > TRANSFER_INVALID and $transfer < TRANSFER_LAST)
+  {
+    if (defined $conversions and exists $conversions->{$from})
+    {
+      my $from_conversions = $conversions->{$from};
+
+      if (exists $from_conversions->{$to})
+      {
+        my $template = undef;
+
+        do
+        {
+          $template = $from_conversions->{$to}[$transfer];
+          --$transfer;
+        }
+        while (not defined $template and $transfer != TRANSFER_INVALID);
+
+        if (defined $template)
+        {
+          $template =~ s/##ARG##/$name/g;
+
+          $conversion = $template;
+        }
+      }
+    }
+  }
+
+  return $conversion;
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo/Convertors.pm b/tools/pm/Common/TypeInfo/Convertors.pm
new file mode 100644
index 0000000..29605ac
--- /dev/null
+++ b/tools/pm/Common/TypeInfo/Convertors.pm
@@ -0,0 +1,35 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo::Convertors module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo::Convertors;
+
+use strict;
+use warnings;
+
+use Common::TypeInfo::Convertors::Enum;
+use Common::TypeInfo::Convertors::Equal;
+use Common::TypeInfo::Convertors::Func;
+use Common::TypeInfo::Convertors::Manual;
+use Common::TypeInfo::Convertors::Normal;
+use Common::TypeInfo::Convertors::Reffed;
+use Common::TypeInfo::Convertors::StdString;
+use Common::TypeInfo::Convertors::Ustring;
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo/Convertors/Enum.pm b/tools/pm/Common/TypeInfo/Convertors/Enum.pm
new file mode 100644
index 0000000..d9ab92a
--- /dev/null
+++ b/tools/pm/Common/TypeInfo/Convertors/Enum.pm
@@ -0,0 +1,53 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo::Convertors::Enum module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo::Convertors::Enum;
+
+use strict;
+use warnings;
+use v5.10;
+
+sub convert ($$$$$$)
+{
+  my ($tiglobal, $from_details, $to_details, $transfer, $subst, $conversion_type) = @_;
+
+  given ($conversion_type)
+  {
+    when (Common::TypeInfo::Global::C_CXX)
+    {
+      continue;
+    }
+    when (Common::TypeInfo::Global::CXX_C)
+    {
+      if ($from_details->match_sigil (['']) and $to_details->match_sigil (['']))
+      {
+        my $to_value_details = $to_details->get_value_details ();
+
+        return join '', 'static_cast< ', $to_value_details->get_base (), ' >(', $subst, ')';
+      }
+# TODO: C pointer from/to C++ ref?
+    }
+# TODO: Container conversions?
+  }
+
+  return undef;
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo/Convertors/Equal.pm b/tools/pm/Common/TypeInfo/Convertors/Equal.pm
new file mode 100644
index 0000000..1d49fb9
--- /dev/null
+++ b/tools/pm/Common/TypeInfo/Convertors/Equal.pm
@@ -0,0 +1,66 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo::Convertors::Equal module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo::Convertors::Equal;
+
+use strict;
+use warnings;
+use v5.10;
+
+sub convert ($$$$$$)
+{
+  my ($tiglobal, $from_details, $to_details, $transfer, $subst, $conversion_type) = @_;
+
+  given ($conversion_type)
+  {
+    when (Common::TypeInfo::Global::CXX_C)
+    {
+      if ($from_details->equal ($to_details, Common::TypeDetails::Base::RECURSIVE | Common::TypeDetails::Base::ACCESS_MODIFIERS))
+      {
+        return $subst;
+      }
+      if ($from_details->equal ($to_details, Common::TypeDetails::Base::ACCESS_MODIFIERS) and $from_details->match_sigil(['&']) and $to_details->match_sigil (['*']))
+      {
+        return join '', '&(', $subst, ')';
+      }
+    }
+    when (Common::TypeInfo::Global::C_CXX)
+    {
+      if ($from_details->equal ($to_details, Common::TypeDetails::Base::RECURSIVE | Common::TypeDetails::Base::ACCESS_MODIFIERS))
+      {
+        return $subst;
+      }
+# TODO: Correspondence C_CXX and from 'ptr' and to 'ref'
+# TODO continued: has no sense - pointer can be NULL and
+# TODO continued: reference cannot. But maybe add it if there
+# TODO continued: are some cases when we are sure that pointer
+# TODO continued: will never be NULL.
+#      if ($from_details->equal ($to_details, Common::TypeDetails::Base::ACCESS_MODIFIERS) and $from_details->isa (Common::TypeDetails::Ptr) and $to_details->isa (Common::TypeDetails::Ref))
+#      {
+#        return join '', '*(', $subst, ')';
+#      }
+    }
+# TODO: Container conversions?
+  }
+
+  return undef;
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo/Convertors/Func.pm b/tools/pm/Common/TypeInfo/Convertors/Func.pm
new file mode 100644
index 0000000..80efbfe
--- /dev/null
+++ b/tools/pm/Common/TypeInfo/Convertors/Func.pm
@@ -0,0 +1,33 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo::Convertors::Func module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo::Convertors::Func;
+
+use strict;
+use warnings;
+
+sub convert ($$$$$$)
+{
+# TODO: This probably is never going to be used in type
+# TODO continued: conversions.
+  return undef;
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo/Convertors/Manual.pm b/tools/pm/Common/TypeInfo/Convertors/Manual.pm
new file mode 100644
index 0000000..b7a5a27
--- /dev/null
+++ b/tools/pm/Common/TypeInfo/Convertors/Manual.pm
@@ -0,0 +1,31 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo::Convertors::Manual module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo::Convertors::Manual;
+
+use strict;
+use warnings;
+
+sub convert ($$$$$$)
+{
+  return undef;
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo/Convertors/Normal.pm b/tools/pm/Common/TypeInfo/Convertors/Normal.pm
new file mode 100644
index 0000000..fdedc10
--- /dev/null
+++ b/tools/pm/Common/TypeInfo/Convertors/Normal.pm
@@ -0,0 +1,32 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo::Convertors::Normal module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo::Convertors::Normal;
+
+use strict;
+use warnings;
+
+sub convert ($$$$$$)
+{
+# TODO: Implement it.
+  return undef;
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo/Convertors/Reffed.pm b/tools/pm/Common/TypeInfo/Convertors/Reffed.pm
new file mode 100644
index 0000000..470bdb0
--- /dev/null
+++ b/tools/pm/Common/TypeInfo/Convertors/Reffed.pm
@@ -0,0 +1,254 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo::Convertors::Reffed module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo::Convertors::Reffed;
+
+use strict;
+use warnings;
+use v5.10;
+
+sub convert ($$$$$$)
+{
+  my ($tiglobal, $from_details, $to_details, $transfer, $subst, $conversion_type) = @_;
+
+  given ($conversion_type)
+  {
+    when (Common::TypeInfo::Global::C_CXX ())
+    {
+      my $cxx_value_details = $to_details->get_value_details ();
+      my $cxx_base = $cxx_value_details->get_base ();
+      my $cxx_templates = $cxx_value_details->get_templates ();
+
+      if (($cxx_base eq 'RefPtr' or $cxx_base eq 'Glib::RefPtr') and @{$cxx_templates} == 1)
+      {
+        if ($from_details->match_sigil (['*'], Common::TypeDetails::Base::ACCESS_MODIFIERS) and $to_details->match_sigil (['<>&', '<>', '<c>&', '<c>'], Common::TypeDetails::Base::ACCESS_MODIFIERS))
+        {
+          return join ('', 'Glib::wrap(', $subst, ', ', (($transfer > Common::TypeInfo::Common::TRANSFER_NONE) ? 'true' : 'false'), ')');
+        }
+      }
+    }
+    when (Common::TypeInfo::Global::CXX_C ())
+    {
+      my $cxx_value_details = $from_details->get_value_details ();
+      my $cxx_base = $cxx_value_details->get_base ();
+      my $cxx_templates = $cxx_value_details->get_templates ();
+
+      if ($cxx_base eq 'RefPtr' or $cxx_base eq 'Glib::RefPtr' and @{$cxx_templates} == 1)
+      {
+        if ($from_details->match_sigil (['<c>&', '<c>', '<c>c&', '<c>c'], Common::TypeDetails::Base::ACCESS_MODIFIERS) and $to_details->match_sigil (['*c'], Common::TypeDetails::Base::ACCESS_MODIFIERS))
+        {
+          if ($to_details->match_sigil (['*c']))
+          {
+            return join ('', 'Glib::unwrap', (($transfer > Common::TypeInfo::Common::TRANSFER_NONE) ? '' : '_copy'), '(', $subst, ')');
+          }
+          elsif ($to_details->match_sigil (['*'], Common::TypeDetails::Base::ACCESS_MODIFIERS))
+          {
+            my $c_value_details = $to_details->get_value_details ();
+            my $c_base = $c_value_details->get_base ();
+
+            return join ('', 'const_cast< ', $c_base, ' >(Glib::unwrap', (($transfer > Common::TypeInfo::Common::TRANSFER_NONE) ? '' : '_copy'), '(', $subst, '))');
+          }
+        }
+
+        if ($from_details->match_sigil (['<>&', '<>', '<>c&', '<>c'], Common::TypeDetails::Base::ACCESS_MODIFIERS) and $to_details->match_sigil (['*', 'c*'], Common::TypeDetails::Base::ACCESS_MODIFIERS))
+        {
+          return join ('', 'Glib::unwrap', (($transfer > Common::TypeInfo::Common::TRANSFER_NONE) ? '' : '_copy'), '(', $subst, ')');
+        }
+      }
+    }
+    when (Common::TypeInfo::Global::C_CXX_CONTAINER ())
+    {
+      my $c_value_details = $from_details->get_value_details ();
+      my $c_base = $c_value_details->get_base ();
+      my $cxx_value_details = $to_details->get_value_details ();
+      my $cxx_base = $cxx_value_details->get_base ();
+      my $ownership = undef;
+
+      given ($transfer)
+      {
+        when (Common::TypeInfo::Common::TRANSFER_NONE)
+        {
+          $ownership = 'Glib::OWNERSHIP_NONE';
+        }
+        when (Common::TypeInfo::Common::TRANSFER_CONTAINER)
+        {
+          $ownership = 'Glib::OWNERSHIP_SHALLOW';
+        }
+        when (Common::TypeInfo::Common::TRANSFER_FULL)
+        {
+          $ownership = 'Glib::OWNERSHIP_DEEP';
+        }
+        default
+        {
+          die;
+        }
+      }
+
+      my $cxx_value_templates = $cxx_value_details->get_templates ();
+
+      break if (@{$cxx_value_templates} != 1);
+
+      my $container_helper_template_details = $cxx_value_templates->[0];
+      my $container_helper_template_base = $container_helper_template_details->get_value_details ()->get_base ();
+
+      break if ($container_helper_template_base ne 'RefPtr' and $container_helper_template_base ne 'Glib::RefPtr');
+
+      my $container_helper_templates = $container_helper_template_details->get_string ();
+
+      given ($c_base)
+      {
+        when ('GList')
+        {
+          if ($from_details->match_sigil (['*', 'c*'], Common::TypeDetails::Base::ACCESS_MODIFIERS))
+          {
+            given ($cxx_base)
+            {
+              when ([qw(::std::vector std::vector vector)])
+              {
+                if ($to_details->match_sigil (['<<>>', '<<>>&']))
+                {
+                  return join ('', '::Glib::ListHandler< ', $container_helper_templates, ' >::list_to_vector(', $subst, ', ', $ownership, ')');
+                }
+              }
+              when ([qw(::Glib::ListHandle Glib::ListHandle ListHandle)])
+              {
+                if ($to_details->match_sigil (['<<>>', '<<>>&']))
+                {
+                  return join ('', '::Glib::ListHandle< ', $container_helper_templates, ' >(', $subst, ', ', $ownership, ')');
+                }
+              }
+            }
+          }
+        }
+        when ('GSList')
+        {
+          if ($from_details->match_sigil (['*', 'c*'], Common::TypeDetails::Base::ACCESS_MODIFIERS))
+          {
+            given ($cxx_base)
+            {
+              when ([qw(::std::vector std::vector vector)])
+              {
+                if ($to_details->match_sigil (['<<>>', '<<>>&']))
+                {
+                  return join ('', '::Glib::SListHandler< ', $container_helper_templates, ' >::slist_to_vector(', $subst, ', ', $ownership, ')');
+                }
+              }
+              when ([qw(::Glib::SListHandle Glib::SListHandle SListHandle)])
+              {
+                if ($to_details->match_sigil (['<<>>', '<<>>&']))
+                {
+                  return join ('', '::Glib::SListHandle< ', $container_helper_templates, ' >(', $subst, ', ', $ownership, ')');
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    when (Common::TypeInfo::Global::CXX_C_CONTAINER ())
+    {
+      my $cxx_value_details = $from_details->get_value_details ();
+      my $cxx_base = $cxx_value_details->get_base ();
+      my $c_value_details = $to_details->get_value_details ();
+      my $c_base = $c_value_details->get_base ();
+
+      break if ($transfer != Common::TypeInfo::Common::TRANSFER_NONE);
+
+      my $cxx_value_templates = $cxx_value_details->get_templates ();
+
+      break if (@{$cxx_value_templates} != 1);
+
+      my $container_helper_template_details = $cxx_value_templates->[0];
+      my $container_helper_template_base = $container_helper_template_details->get_value_details ()->get_base ();
+
+      break if ($container_helper_template_base ne 'RefPtr' and $container_helper_template_base ne 'Glib::RefPtr');
+
+      my $container_helper_templates = $container_helper_template_details->get_string ();
+
+      given ($cxx_base)
+      {
+        when ([qw(::std::vector std::vector vector)])
+        {
+          if ($from_details->match_sigil (['<<>>', '<<>>&']))
+          {
+            given ($c_base)
+            {
+              when ('GList')
+              {
+                if ($to_details->match_sigil ('*'))
+                {
+                  return join ('', '::Glib::ListHandler< ', $container_helper_templates, ' >::vector_to_list(', $subst, ').data()');
+                }
+              }
+              when ('GSList')
+              {
+                if ($to_details->match_sigil ('*'))
+                {
+                  return join ('', '::Glib::SListHandler< ', $container_helper_templates, ' >::vector_to_slist(', $subst, ').data()');
+                }
+              }
+              default
+              {
+# TODO: check for c_type**
+              }
+            }
+          }
+        }
+        when ([qw(::Glib::ListHandle Glib::ListHandle ListHandle)])
+        {
+          if ($from_details->match_sigil (['<<>>', '<<>>&']))
+          {
+            if ($c_base eq 'GList')
+            {
+              if ($to_details->match_sigil ('*'))
+              {
+                return join ('', $subst, '.data()');
+              }
+            }
+          }
+        }
+        when ([qw(::Glib::SListHandle Glib::SListHandle SListHandle)])
+        {
+          if ($from_details->match_sigil (['<<>>', '<<>>&']))
+          {
+            if ($c_base eq 'GSList')
+            {
+              if ($to_details->match_sigil ('*'))
+              {
+                return join ('', $subst, '.data()');
+              }
+            }
+          }
+        }
+        when ([qw(::Glib::ArrayHandle Glib::ArrayHandle ArrayHandle)])
+        {
+          if ($from_details->match_sigil (['<<>>', '<<>>&']))
+          {
+# TODO: check for c_type**.
+          }
+        }
+      }
+    }
+  }
+
+  return undef;
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo/Convertors/StdString.pm b/tools/pm/Common/TypeInfo/Convertors/StdString.pm
new file mode 100644
index 0000000..ae2e9df
--- /dev/null
+++ b/tools/pm/Common/TypeInfo/Convertors/StdString.pm
@@ -0,0 +1,289 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo::Convertors::StdString module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo::Convertors::StdString;
+
+use strict;
+use warnings;
+use v5.10;
+
+sub convert ($$$$$$)
+{
+  my ($tiglobal, $from_details, $to_details, $transfer, $subst, $conversion_type) = @_;
+
+  given ($conversion_type)
+  {
+    when (Common::TypeInfo::Global::C_CXX ())
+    {
+      my $cxx_base = $to_details->get_value_details ()->get_base ();
+      my $c_base = $from_details->get_value_details ()->get_base ();
+
+      if (($cxx_base eq 'string' or $cxx_base eq 'std::string' or $cxx_base eq '::std::string') and ($c_base eq 'gchar' or $c_base eq 'char'))
+      {
+        if ($from_details->match_sigil (['*']) and $to_details->match_sigil (['', '&']))
+        {
+          if ($transfer == Common::TypeInfo::Common::TRANSFER_NONE)
+          {
+            return join ('', '::Glib::convert_const_gchar_ptr_to_stdstring(', $subst, ')');
+          }
+          else
+          {
+            return join ('', '::Glib::convert_return_gchar_ptr_to_stdstring(', $subst, ')');
+          }
+        }
+      }
+    }
+    when (Common::TypeInfo::Global::CXX_C ())
+    {
+      my $c_base = $to_details->get_value_details ()->get_base ();
+      my $cxx_base = $from_details->get_value_details ()->get_base ();
+
+      if (($cxx_base eq 'string' or $cxx_base eq 'std::string' or $cxx_base eq '::std::string') and ($c_base eq 'gchar' or $c_base eq 'char'))
+      {
+        if ($to_details->match_sigil (['*']) and $from_details->match_sigil (['', '&']))
+        {
+          if ($transfer == Common::TypeInfo::Common::TRANSFER_NONE)
+          {
+            return join ('', '((', $subst, ').c_str())');
+          }
+          else
+          {
+            return join ('', 'g_strdup((', $subst, ').c_str())');
+          }
+        }
+      }
+    }
+    when (Common::TypeInfo::Global::C_CXX_CONTAINER ())
+    {
+      my $c_value_details = $from_details->get_value_details ();
+      my $c_base = $c_value_details->get_base ();
+      my $cxx_value_details = $to_details->get_value_details ();
+      my $cxx_base = $cxx_value_details->get_base ();
+      my $ownership = undef;
+
+      given ($transfer)
+      {
+        when (Common::TypeInfo::Common::TRANSFER_NONE)
+        {
+          $ownership = 'Glib::OWNERSHIP_NONE';
+        }
+        when (Common::TypeInfo::Common::TRANSFER_CONTAINER)
+        {
+          $ownership = 'Glib::OWNERSHIP_SHALLOW';
+        }
+        when (Common::TypeInfo::Common::TRANSFER_FULL)
+        {
+          $ownership = 'Glib::OWNERSHIP_DEEP';
+        }
+        default
+        {
+          die;
+        }
+      }
+
+      my $cxx_value_templates = $cxx_value_details->get_templates ();
+
+      break if (@{$cxx_value_templates} != 1);
+
+      my $container_helper_template_details = $cxx_value_templates->[0];
+      my $container_helper_template_base = $container_helper_template_details->get_value_details ()->get_base ();
+
+      break unless ($container_helper_template_base eq 'string' or
+                    $container_helper_template_base eq 'std::string' or
+                    $container_helper_template_base eq '::std::string');
+
+      my $container_helper_templates = $container_helper_template_details->get_string ();
+      my $wanted_cxx_sigils = [qw(<> <>&)];
+
+      given ($c_base)
+      {
+        when ('GList')
+        {
+          if ($from_details->match_sigil (['*', 'c*'], Common::TypeDetails::Base::ACCESS_MODIFIERS))
+          {
+            given ($cxx_base)
+            {
+              when ([qw(::std::vector std::vector vector)])
+              {
+                if ($to_details->match_sigil ($wanted_cxx_sigils))
+                {
+                  return join ('', '::Glib::ListHandler< ', $container_helper_templates, ' >::list_to_vector(', $subst, ', ', $ownership, ')');
+                }
+              }
+              when ([qw(::Glib::ListHandle Glib::ListHandle ListHandle)])
+              {
+                if ($to_details->match_sigil ($wanted_cxx_sigils))
+                {
+                  return join ('', '::Glib::ListHandle< ', $container_helper_templates, ' >(', $subst, ', ', $ownership, ')');
+                }
+              }
+            }
+          }
+        }
+        when ('GSList')
+        {
+          if ($from_details->match_sigil (['*', 'c*'], Common::TypeDetails::Base::ACCESS_MODIFIERS))
+          {
+            given ($cxx_base)
+            {
+              when ([qw(::std::vector std::vector vector)])
+              {
+                if ($to_details->match_sigil ($wanted_cxx_sigils))
+                {
+                  return join ('', '::Glib::SListHandler< ', $container_helper_templates, ' >::slist_to_vector(', $subst, ', ', $ownership, ')');
+                }
+              }
+              when ([qw(::Glib::SListHandle Glib::SListHandle SListHandle)])
+              {
+                if ($to_details->match_sigil ($wanted_cxx_sigils))
+                {
+                  return join ('', '::Glib::SListHandle< ', $container_helper_templates, ' >(', $subst, ', ', $ownership, ')');
+                }
+              }
+            }
+          }
+        }
+        when ([qw(gchar char)])
+        {
+          if ($from_details->match_sigil (['**']))
+          {
+            given ($cxx_base)
+            {
+              when ([qw(::std::vector std::vector vector)])
+              {
+                if ($to_details->match_sigil ($wanted_cxx_sigils))
+                {
+                  return join ('', '::Glib::ArrayHandler< ', $container_helper_templates, ' >::array_to_vector(', $subst, ', ', $ownership, ')');
+                }
+              }
+              when ([qw(::Glib::ArrayHandle Glib::ArrayHandle ArrayHandle)])
+              {
+                if ($to_details->match_sigil ($wanted_cxx_sigils))
+                {
+                  return join ('', '::Glib::ArrayHandle< ', $container_helper_templates, ' >(', $subst, ', ', $ownership, ')');
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    when (Common::TypeInfo::Global::CXX_C_CONTAINER ())
+    {
+      my $cxx_value_details = $from_details->get_value_details ();
+      my $cxx_base = $cxx_value_details->get_base ();
+      my $c_value_details = $to_details->get_value_details ();
+      my $c_base = $c_value_details->get_base ();
+
+      break if ($transfer != Common::TypeInfo::Common::TRANSFER_NONE);
+
+      my $cxx_value_templates = $cxx_value_details->get_templates ();
+
+      break if (@{$cxx_value_templates} != 1);
+
+      my $container_helper_template_details = $cxx_value_templates->[0];
+      my $container_helper_template_base = $container_helper_template_details->get_value_details ()->get_base ();
+
+      break unless ($container_helper_template_base eq 'string' or
+                    $container_helper_template_base eq 'std::string' or
+                    $container_helper_template_base eq '::std::string');
+
+      my $container_helper_templates = $container_helper_template_details->get_string ();
+      my $wanted_cxx_sigils = [qw(<> <>&)];
+
+      given ($cxx_base)
+      {
+        when ([qw(::std::vector std::vector vector)])
+        {
+          if ($from_details->match_sigil ($wanted_cxx_sigils))
+          {
+            given ($c_base)
+            {
+              when ('GList')
+              {
+                if ($to_details->match_sigil ('*'))
+                {
+                  return join ('', '::Glib::ListHandler< ', $container_helper_templates, ' >::vector_to_list(', $subst, ').data()');
+                }
+              }
+              when ('GSList')
+              {
+                if ($to_details->match_sigil ('*'))
+                {
+                  return join ('', '::Glib::SListHandler< ', $container_helper_templates, ' >::vector_to_slist(', $subst, ').data()');
+                }
+              }
+              when (['gchar', 'char'])
+              {
+                if ($to_details->match_sigil ('**'))
+                {
+                  return join ('', '::Glib::ArrayHandler< ', $container_helper_templates, ' >::vector_to_array(', $subst, ').data()');
+                }
+              }
+            }
+          }
+        }
+        when ([qw(::Glib::ListHandle Glib::ListHandle ListHandle)])
+        {
+          if ($from_details->match_sigil ($wanted_cxx_sigils))
+          {
+            if ($c_base eq 'GList')
+            {
+              if ($to_details->match_sigil ('*'))
+              {
+                return join ('', $subst, '.data()');
+              }
+            }
+          }
+        }
+        when ([qw(::Glib::SListHandle Glib::SListHandle SListHandle)])
+        {
+          if ($from_details->match_sigil ($wanted_cxx_sigils))
+          {
+            if ($c_base eq 'GSList')
+            {
+              if ($to_details->match_sigil ('*'))
+              {
+                return join ('', $subst, '.data()');
+              }
+            }
+          }
+        }
+        when ([qw(::Glib::ArrayHandle Glib::ArrayHandle ArrayHandle)])
+        {
+          if ($from_details->match_sigil ($wanted_cxx_sigils))
+          {
+            if ($c_base eq 'gchar' or $c_base eq 'char')
+            {
+              if ($to_details->match_sigil ('**'))
+              {
+                return join ('', $subst, '.data()');
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return undef;
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo/Convertors/Ustring.pm b/tools/pm/Common/TypeInfo/Convertors/Ustring.pm
new file mode 100644
index 0000000..10c6f0d
--- /dev/null
+++ b/tools/pm/Common/TypeInfo/Convertors/Ustring.pm
@@ -0,0 +1,289 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo::Convertors::Ustring module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo::Convertors::Ustring;
+
+use strict;
+use warnings;
+use v5.10;
+
+sub convert ($$$$$$)
+{
+  my ($tiglobal, $from_details, $to_details, $transfer, $subst, $conversion_type) = @_;
+
+  given ($conversion_type)
+  {
+    when (Common::TypeInfo::Global::C_CXX ())
+    {
+      my $cxx_base = $to_details->get_value_details ()->get_base ();
+      my $c_base = $from_details->get_value_details ()->get_base ();
+
+      if (($cxx_base eq 'ustring' or $cxx_base eq 'Glib::ustring' or $cxx_base eq '::Glib::ustring') and ($c_base eq 'gchar' or $c_base eq 'char'))
+      {
+        if ($from_details->match_sigil (['*']) and $to_details->match_sigil (['', '&']))
+        {
+          if ($transfer == Common::TypeInfo::Common::TRANSFER_NONE)
+          {
+            return join ('', '::Glib::convert_const_gchar_ptr_to_ustring(', $subst, ')');
+          }
+          else
+          {
+            return join ('', '::Glib::convert_return_gchar_ptr_to_ustring(', $subst, ')');
+          }
+        }
+      }
+    }
+    when (Common::TypeInfo::Global::CXX_C ())
+    {
+      my $c_base = $to_details->get_value_details ()->get_base ();
+      my $cxx_base = $from_details->get_value_details ()->get_base ();
+
+      if (($cxx_base eq 'ustring' or $cxx_base eq 'Glib::ustring' or $cxx_base eq '::Glib::ustring') and ($c_base eq 'gchar' or $c_base eq 'char'))
+      {
+        if ($to_details->match_sigil (['*']) and $from_details->match_sigil (['', '&']))
+        {
+          if ($transfer == Common::TypeInfo::Common::TRANSFER_NONE)
+          {
+            return join ('', '((', $subst, ').c_str())');
+          }
+          else
+          {
+            return join ('', 'g_strdup((', $subst, ').c_str())');
+          }
+        }
+      }
+    }
+    when (Common::TypeInfo::Global::C_CXX_CONTAINER ())
+    {
+      my $c_value_details = $from_details->get_value_details ();
+      my $c_base = $c_value_details->get_base ();
+      my $cxx_value_details = $to_details->get_value_details ();
+      my $cxx_base = $cxx_value_details->get_base ();
+      my $ownership = undef;
+
+      given ($transfer)
+      {
+        when (Common::TypeInfo::Common::TRANSFER_NONE)
+        {
+          $ownership = 'Glib::OWNERSHIP_NONE';
+        }
+        when (Common::TypeInfo::Common::TRANSFER_CONTAINER)
+        {
+          $ownership = 'Glib::OWNERSHIP_SHALLOW';
+        }
+        when (Common::TypeInfo::Common::TRANSFER_FULL)
+        {
+          $ownership = 'Glib::OWNERSHIP_DEEP';
+        }
+        default
+        {
+          die;
+        }
+      }
+
+      my $cxx_value_templates = $cxx_value_details->get_templates ();
+
+      break if (@{$cxx_value_templates} != 1);
+
+      my $container_helper_template_details = $cxx_value_templates->[0];
+      my $container_helper_template_base = $container_helper_template_details->get_value_details ()->get_base ();
+
+      break unless ($container_helper_template_base eq 'ustring' or
+                    $container_helper_template_base eq 'Glib::ustring' or
+                    $container_helper_template_base eq '::Glib::ustring');
+
+      my $container_helper_templates = $container_helper_template_details->get_string ();
+      my $wanted_cxx_sigils = [qw(<> <>&)];
+
+      given ($c_base)
+      {
+        when ('GList')
+        {
+          if ($from_details->match_sigil (['*', 'c*'], Common::TypeDetails::Base::ACCESS_MODIFIERS))
+          {
+            given ($cxx_base)
+            {
+              when ([qw(::std::vector std::vector vector)])
+              {
+                if ($to_details->match_sigil ($wanted_cxx_sigils))
+                {
+                  return join ('', '::Glib::ListHandler< ', $container_helper_templates, ' >::list_to_vector(', $subst, ', ', $ownership, ')');
+                }
+              }
+              when ([qw(::Glib::ListHandle Glib::ListHandle ListHandle)])
+              {
+                if ($to_details->match_sigil ($wanted_cxx_sigils))
+                {
+                  return join ('', '::Glib::ListHandle< ', $container_helper_templates, ' >(', $subst, ', ', $ownership, ')');
+                }
+              }
+            }
+          }
+        }
+        when ('GSList')
+        {
+          if ($from_details->match_sigil (['*', 'c*'], Common::TypeDetails::Base::ACCESS_MODIFIERS))
+          {
+            given ($cxx_base)
+            {
+              when ([qw(::std::vector std::vector vector)])
+              {
+                if ($to_details->match_sigil ($wanted_cxx_sigils))
+                {
+                  return join ('', '::Glib::SListHandler< ', $container_helper_templates, ' >::slist_to_vector(', $subst, ', ', $ownership, ')');
+                }
+              }
+              when ([qw(::Glib::SListHandle Glib::SListHandle SListHandle)])
+              {
+                if ($to_details->match_sigil ($wanted_cxx_sigils))
+                {
+                  return join ('', '::Glib::SListHandle< ', $container_helper_templates, ' >(', $subst, ', ', $ownership, ')');
+                }
+              }
+            }
+          }
+        }
+        when ([qw(gchar char)])
+        {
+          if ($from_details->match_sigil (['**']))
+          {
+            given ($cxx_base)
+            {
+              when ([qw(::std::vector std::vector vector)])
+              {
+                if ($to_details->match_sigil ($wanted_cxx_sigils))
+                {
+                  return join ('', '::Glib::ArrayHandler< ', $container_helper_templates, ' >::array_to_vector(', $subst, ', ', $ownership, ')');
+                }
+              }
+              when ([qw(::Glib::ArrayHandle Glib::ArrayHandle ArrayHandle)])
+              {
+                if ($to_details->match_sigil ($wanted_cxx_sigils))
+                {
+                  return join ('', '::Glib::ArrayHandle< ', $container_helper_templates, ' >(', $subst, ', ', $ownership, ')');
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    when (Common::TypeInfo::Global::CXX_C_CONTAINER ())
+    {
+      my $cxx_value_details = $from_details->get_value_details ();
+      my $cxx_base = $cxx_value_details->get_base ();
+      my $c_value_details = $to_details->get_value_details ();
+      my $c_base = $c_value_details->get_base ();
+
+      break if ($transfer != Common::TypeInfo::Common::TRANSFER_NONE);
+
+      my $cxx_value_templates = $cxx_value_details->get_templates ();
+
+      break if (@{$cxx_value_templates} != 1);
+
+      my $container_helper_template_details = $cxx_value_templates->[0];
+      my $container_helper_template_base = $container_helper_template_details->get_value_details ()->get_base ();
+
+      break unless ($container_helper_template_base eq 'ustring' or
+                    $container_helper_template_base eq 'Glib::ustring' or
+                    $container_helper_template_base eq '::Glib::ustring');
+
+      my $container_helper_templates = $container_helper_template_details->get_string ();
+      my $wanted_cxx_sigils = [qw(<> <>&)];
+
+      given ($cxx_base)
+      {
+        when ([qw(::std::vector std::vector vector)])
+        {
+          if ($from_details->match_sigil ($wanted_cxx_sigils))
+          {
+            given ($c_base)
+            {
+              when ('GList')
+              {
+                if ($to_details->match_sigil ('*'))
+                {
+                  return join ('', '::Glib::ListHandler< ', $container_helper_templates, ' >::vector_to_list(', $subst, ').data()');
+                }
+              }
+              when ('GSList')
+              {
+                if ($to_details->match_sigil ('*'))
+                {
+                  return join ('', '::Glib::SListHandler< ', $container_helper_templates, ' >::vector_to_slist(', $subst, ').data()');
+                }
+              }
+              when (['gchar', 'char'])
+              {
+                if ($to_details->match_sigil ('**'))
+                {
+                  return join ('', '::Glib::ArrayHandler< ', $container_helper_templates, ' >::vector_to_array(', $subst, ').data()');
+                }
+              }
+            }
+          }
+        }
+        when ([qw(::Glib::ListHandle Glib::ListHandle ListHandle)])
+        {
+          if ($from_details->match_sigil ($wanted_cxx_sigils))
+          {
+            if ($c_base eq 'GList')
+            {
+              if ($to_details->match_sigil ('*'))
+              {
+                return join ('', $subst, '.data()');
+              }
+            }
+          }
+        }
+        when ([qw(::Glib::SListHandle Glib::SListHandle SListHandle)])
+        {
+          if ($from_details->match_sigil ($wanted_cxx_sigils))
+          {
+            if ($c_base eq 'GSList')
+            {
+              if ($to_details->match_sigil ('*'))
+              {
+                return join ('', $subst, '.data()');
+              }
+            }
+          }
+        }
+        when ([qw(::Glib::ArrayHandle Glib::ArrayHandle ArrayHandle)])
+        {
+          if ($from_details->match_sigil ($wanted_cxx_sigils))
+          {
+            if ($c_base eq 'gchar' or $c_base eq 'char')
+            {
+              if ($to_details->match_sigil ('**'))
+              {
+                return join ('', $subst, '.data()');
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return undef;
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo/Global.pm b/tools/pm/Common/TypeInfo/Global.pm
new file mode 100644
index 0000000..b993aa6
--- /dev/null
+++ b/tools/pm/Common/TypeInfo/Global.pm
@@ -0,0 +1,1310 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo::Global module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo::Global;
+
+use strict;
+use warnings;
+#use feature ':5.10';
+use v5.10;
+
+use constant
+{
+# type info sources
+  FROM_FILES => 1,
+  GENERATED => 2,
+  FROM_MODULE_FILES => 3,
+# conversion types
+  C_CXX => 10,
+  CXX_C => 11,
+  C_CXX_CONTAINER => 12,
+  CXX_C_CONTAINER => 13,
+  UNKNOWN => 14
+# internal conversion types, do not use
+#  SINGLE => 20,
+#  C_CXX_CONTAINER_CHECK => 21,
+#  CXX_C_CONTAINER_CHECK => 22,
+};
+
+use IO::File;
+
+use Common::Util;
+
+use Common::TypeDetails;
+use Common::TypeInfo::Common;
+use Common::TypeInfo::Convertors;
+
+sub _desired_order ()
+{
+  return (FROM_MODULE_FILES, GENERATED, FROM_FILES);
+}
+
+sub _type_to_string ($)
+{
+  my ($type) = @_;
+  my $name = undef;
+
+  given ($type)
+  {
+    when (C_CXX)
+    {
+      $name = 'C to C++';
+    }
+    when (CXX_C)
+    {
+      $name = "C++ to C";
+    }
+    when (C_CXX_CONTAINER)
+    {
+      $name = "C to C++ (container)";
+    }
+    when (CXX_C_CONTAINER)
+    {
+      $name = "C++ to C (container)";
+    }
+    default
+    {
+      $name = "invalid";
+    }
+  }
+
+  return $name;
+}
+
+sub _which_to_string ($)
+{
+  my ($which) = @_;
+  my $name = undef;
+
+  given ($which)
+  {
+    when (FROM_FILES)
+    {
+      $name = 'from_files';
+    }
+    when (GENERATED)
+    {
+      $name = 'generated';
+    }
+    when (FROM_MODULE_FILES)
+    {
+      $name = 'from_module_files';
+    }
+    default
+    {
+# TODO: throw internal error.
+      die;
+    }
+  }
+
+  return $name;
+}
+
+sub _get_c_container_types ($)
+{
+  my ($self) = @_;
+
+  return $self->{'c_container_types'};
+}
+
+sub _get_cxx_container_types ($)
+{
+  my ($self) = @_;
+
+  return $self->{'cxx_container_types'};
+}
+
+#sub _do_c_cxx_container_check ($$$)
+#{
+#  my ($self, $c_value, $cxx_value) = @_;
+#  my $cxx_value_iter = $cxx_value;
+#  my $cxx_base = undef;
+#  my $c_base = $c_value->get_base ();
+#
+#  until (defined $cxx_base)
+#  {
+#    my $templates = $cxx_value_iter->get_templates ();
+#
+#    if (@{$templates} == 1)
+#    {
+#      if ($templates->[0]->match_sigil ('', Common::TypeDetails::Base::NONE))
+#      {
+#        $cxx_value_iter = $templates->[0];
+#      }
+#      else
+#      {
+#        return 0;
+#      }
+#    }
+#    elsif (@{$templates} == 0)
+#    {
+#      $cxx_base = $cxx_value_iter->get_base ();
+#    }
+#  }
+#
+#  my $cxx_test = $self->c_to_cxx ($c_base);
+#
+#  if (defined $cxx_test)
+#  {
+#    my $sub_types = Common::Shared::split_cpp_type_to_sub_types $cxx_test;
+#
+## TODO: think if there are cases that need checking
+## TODO continued: correspondence in another direction.
+#    foreach my $sub_type (@{$sub_types})
+#    {
+#      if ($sub_type eq $cxx_base)
+#      {
+#        return 1;
+#      }
+#    }
+#  }
+#
+#  return 0;
+#}
+
+sub _get_cxx_pointer_types ($)
+{
+  my ($self) = @_;
+
+  return $self->{'cxx_pointer_types'};
+}
+
+#sub check_conversion_type ($$$)
+#{
+#  my ($self, $from_details, $to_details) = @_;
+#  my $c_container_types = $self->_get_c_container_types ();
+#  my $cxx_container_types = $self->_get_cxx_container_types ();
+#  my $conversion_type = SINGLE;
+#  my $from_value = $from_details->get_value_details ();
+#  my $to_value = $to_details->get_value_details ();
+#  my $from_base = $from_value->get_base ();
+#  my $to_base = $to_value->get_base ();
+#  my @tuples =
+#  (
+#    [$from_details, $to_details, CXX_C_CONTAINER, CXX_C_CONTAINER_CHECK, $from_base, $to_base],
+#    [$to_details, $from_details, C_CXX_CONTAINER, C_CXX_CONTAINER_CHECK, $to_base, $from_base]
+#  );
+#
+#  foreach my $tuple (@tuples)
+#  {
+#    my ($first_details, $second_details, $current_type, $current_check_type, $first_base, $second_base) = @{$tuple};
+#    my $first_cxx_container = exists $cxx_container_types->{$first_base};
+#    my $second_c_container = exists $c_container_types->{$second_base};
+#
+#    if ($first_cxx_container)
+#    {
+#      print "$first_base is a C++ container\n";
+#
+#      if ($second_c_container)
+#      {
+#        print "$second_base is a C container\n";
+#        $conversion_type = $current_type;
+#      }
+#      elsif ($second_details->match_sigil (['*', '**'], Common::TypeDetails::Base::NONE))
+#      {
+#        $conversion_type = $current_check_type;
+#      }
+#      else
+#      {
+#        $conversion_type = UNKNOWN;
+#      }
+#
+#      last;
+#    }
+#    elsif ($second_c_container)
+#    {
+## TODO: should we treat Gtk::Widget** as container type? I
+## TODO continued: guess not, just use vector.
+#      $conversion_type = UNKNOWN;
+#      last;
+#    }
+#  }
+#
+#  given ($conversion_type)
+#  {
+#    when (C_CXX_CONTAINER_CHECK)
+#    {
+#      if ($self->_do_c_cxx_container_check ($from_value, $to_value))
+#      {
+#        $conversion_type = C_CXX_CONTAINER;
+#      }
+#      else
+#      {
+#        $conversion_type = UNKNOWN;
+#      }
+#    }
+#    when (CXX_C_CONTAINER_CHECK)
+#    {
+#      if ($self->_do_c_cxx_container_check ($to_value, $from_value))
+#      {
+#        $conversion_type = CXX_C_CONTAINER;
+#      }
+#      else
+#      {
+#        $conversion_type = UNKNOWN;
+#      }
+#    }
+#    when (SINGLE)
+#    {
+#      my $selected_from_base = undef;
+#      my $selected_to_base = undef;
+#      my $cxx_pointer_types = $self->_get_cxx_pointer_types ();
+#
+#      if (exists ($cxx_pointer_types->{$from_base}))
+#      {
+#        $selected_from_base = $from_value->get_templates ()->[0]->get_value_details ()->get_base ();
+#        $selected_to_base = $to_base;
+#      }
+#      elsif (exists ($cxx_pointer_types->{$to_base}))
+#      {
+#        $selected_from_base = $from_base;
+#        $selected_to_base = $to_value->get_templates ()->[0]->get_value_details ()->get_base ();
+#      }
+#      else
+#      {
+#        $selected_from_base = $from_base;
+#        $selected_to_base = $to_base;
+#      }
+#
+#      my @another_tuples =
+#      (
+#        [$selected_from_base, $selected_to_base, C_CXX],
+#        [$selected_to_base, $selected_from_base, CXX_C]
+#      );
+#
+#      foreach my $tuple (@another_tuples)
+#      {
+#        my ($first_base, $second_base, $current_type) = @{$tuple};
+#        my $cxx_test = $self->c_to_cxx ($first_base);
+#
+#        if (defined $cxx_test)
+#        {
+#          my $sub_types = Common::Shared::split_cpp_type_to_sub_types $cxx_test;
+#
+## TODO: think if there are cases that need checking
+## TODO continued: correspondence in another direction.
+#          foreach my $sub_type (@{$sub_types})
+#          {
+#            if ($sub_type eq $second_base)
+#            {
+#              $conversion_type = $current_type;
+#              last;
+#            }
+#          }
+#        }
+#      }
+#
+#      if ($conversion_type == SINGLE)
+#      {
+#        $conversion_type = UNKNOWN;
+#      }
+#    }
+#  }
+#
+#  return $conversion_type;
+#}
+
+sub _get_generated_type_infos_basename ($)
+{
+  my ($self) = @_;
+  my $mm_module = $self->_get_mm_module;
+  my $basename = join '_', 'type', 'infos', $mm_module, 'generated';
+
+  return $basename;
+}
+
+sub _get_generated_type_infos_filename ($)
+{
+  my ($self) = @_;
+  my $include_paths = $self->_get_include_paths;
+
+  unless (@{$include_paths})
+  {
+# TODO: internal error.
+    die;
+  }
+
+  my $filename = File::Spec->catfile ($include_paths->[0], $self->_get_generated_type_infos_basename ());
+
+  return $filename;
+}
+
+sub _get_specific_conversion ($$$$$$)
+{
+  my ($self, $which, $from, $to, $transfer, $subst) = @_;
+  my $conversions = $self->_get_specific_conversions ($which);
+  my $conversion = Common::TypeInfo::Common::get_specific_conversion $conversions,
+                                                                     $from,
+                                                                     $to,
+                                                                     $transfer,
+                                                                     $subst;
+
+  return $conversion;
+}
+
+sub _get_convertors ($)
+{
+  my ($self) = @_;
+
+  return $self->{'convertors'};
+}
+
+sub _get_meaningful_base ($$$)
+{
+  my ($self, $value, $option) = @_;
+  my $c_container_types = $self->_get_c_container_types ();
+  my $cxx_container_types = $self->_get_cxx_container_types ();
+  my $cxx_pointer_types = $self->_get_cxx_pointer_types ();
+  my $base = $value->get_base ();
+  my $done = 0;
+
+  until ($done)
+  {
+    if (exists ($cxx_container_types->{$base}) or
+        exists ($cxx_pointer_types->{$base}))
+    {
+      my $templates = $value->get_templates ();
+
+      if (@{$templates} > 0)
+      {
+        $value = $templates->[0]->get_value_details ();
+        $base = $value->get_base ();
+      }
+      else
+      {
+        $base = undef;
+        $done = 1;
+      }
+    }
+    else
+    {
+      if (exists ($c_container_types->{$base}))
+      {
+        my $imbue_type = $value->get_imbue_type ();
+
+        if (@{$imbue_type} > 0)
+        {
+          $base = $imbue_type->[0];
+        }
+        else
+        {
+          $base = undef;
+        }
+      }
+      $done = 1;
+    }
+  }
+
+  return $base;
+}
+
+sub _conversion_type ($$$$)
+{
+  my ($self, $from_details, $to_details, $general_direction) = @_;
+  my $conversion_type = UNKNOWN;
+  my $cxx_details = undef;
+  my $c_details = undef;
+  my $container_conversion = UNKNOWN;
+
+  if ($general_direction == C_CXX)
+  {
+    $c_details = $from_details;
+    $cxx_details = $to_details;
+    $container_conversion = C_CXX_CONTAINER;
+  }
+  elsif ($general_direction == CXX_C)
+  {
+    $c_details = $to_details;
+    $cxx_details = $from_details;
+    $container_conversion = CXX_C_CONTAINER;
+  }
+
+  if ($container_conversion != UNKNOWN)
+  {
+    my $c_value = $c_details->get_value_details ();
+    my $cxx_value = $cxx_details->get_value_details ();
+    my $c_base = $c_value->get_base ();
+    my $cxx_base = $cxx_value->get_base ();
+    my $c_container_types = $self->_get_c_container_types ();
+    my $cxx_container_types = $self->_get_cxx_container_types ();
+    my $is_a_c_container = exists ($c_container_types->{$c_base});
+    my $is_a_cxx_container = exists ($cxx_container_types->{$cxx_base});
+
+    if ($is_a_cxx_container)
+    {
+      if ($is_a_c_container or $c_details->match_sigil (['*', '**']))
+      {
+        $conversion_type = $container_conversion;
+      }
+      else
+      {
+        $conversion_type = UNKNOWN;
+      }
+    }
+    elsif ($is_a_c_container)
+    {
+# TODO: should we treat Gtk::Widget** as C++ container type? I
+# TODO continued: guess not, just use vector.
+      $conversion_type = UNKNOWN;
+    }
+    else
+    {
+      $conversion_type = $general_direction;
+    }
+  }
+
+  return $conversion_type;
+}
+
+sub _get_general_conversion ($$$$$$)
+{
+  my ($self, $which, $from, $to, $transfer, $subst) = @_;
+  my $conversions = $self->_get_general_conversions ($which);
+  my $from_c_conversions = $conversions->{'c'};
+  my $cxx_infos = $conversions->{'cxx'};
+  my $from_cxx_conversions = $cxx_infos->{'conversions'};
+  my $conversion = undef;
+  my $from_details = Common::TypeDetails::disassemble_type ($from);
+  my $to_details = Common::TypeDetails::disassemble_type ($to);
+  my $conversion_type = undef;
+  my $conversion_direction = UNKNOWN;
+
+  foreach my $tuple ([$from_details, $to_details, C_CXX, CXX_C], [$to_details, $from_details, CXX_C, C_CXX])
+  {
+    my $first_details = $tuple->[0];
+    my $second_details = $tuple->[1];
+    my $first_value = $first_details->get_value_details ();
+    my $second_value = $second_details->get_value_details ();
+    my $first_base = $self->_get_meaningful_base ($first_value);
+    my $to_conversions = undef;
+
+    next unless (defined ($first_base));
+
+    if (exists ($from_c_conversions->{$first_base}))
+    {
+      $conversion_direction = $tuple->[2];
+      $to_conversions = $from_c_conversions->{$first_base}{'conversions'};
+    }
+    elsif (exists ($from_cxx_conversions->{$first_base}))
+    {
+      $conversion_direction = $tuple->[3];
+      $to_conversions = $from_cxx_conversions->{$first_base};
+    }
+    else
+    {
+      next;
+    }
+
+    $conversion_direction = $self->_conversion_type ($from_details, $to_details, $conversion_direction);
+
+    next if ($conversion_direction == UNKNOWN);
+
+    my $second_base = $self->_get_meaningful_base ($second_value);
+
+    if (defined $second_base and exists ($to_conversions->{$second_base}))
+    {
+      my $temp_conversion_type = $to_conversions->{$second_base};
+
+      if (ref ($temp_conversion_type) eq '')
+      {
+        $conversion_type = $temp_conversion_type;
+        last;
+      }
+    }
+  }
+
+  if (defined $conversion_type)
+  {
+    my $convertors = $self->_get_convertors;
+
+    if (exists $convertors->{$conversion_type})
+    {
+      $conversion = $convertors->{$conversion_type}($from_details, $to_details, $transfer, $subst, $conversion_direction);
+    }
+    else
+    {
+# TODO: internal error
+      die join '', 'Unknown convertor type: `', $conversion_type, '\'.';
+    }
+  }
+
+  return $conversion;
+}
+
+##
+## general_conversions = { 'c'   => {
+##                                    $c_stuff   => {
+##                                                    'mapping'     => $cxx_stuff,
+# TODO: that is completely wrong!
+##                                                    'conversions' => { $cxx_stuff => $type }
+##                                                  }
+##                                  },
+##                         'cxx' => {
+##                                    'mappings'    => { $full_cxx_stuff => $c_stuff },
+# TODO: and this too!
+##                                    'conversions' => { $cxx_stuff => { $c_stuff => $type }}
+##                                  }
+##                       }
+##
+# TODO: This is quite long function. I wonder if it is justified.
+sub _add_info_to_general_conversions ($$$$$$$)
+{
+  my ($self, $c_stuff, $cxx_stuff, $type, $which, $apply_conversion, $apply_mapping) = @_;
+
+  if (not $apply_conversion and not $apply_mapping)
+  {
+# rather should not happen.
+    return;
+  }
+
+  my $conversions = $self->_get_general_conversions ($which);
+  my $cxx_sub_types = Common::Shared::split_cpp_type_to_sub_types $cxx_stuff;
+  my $from_c_conversions = $conversions->{'c'};
+
+  if (exists $from_c_conversions->{$c_stuff})
+  {
+    my $c_info = $from_c_conversions->{$c_stuff};
+
+    if ($apply_mapping)
+    {
+      if (not exists ($c_info->{'mapping'}) or not defined ($c_info->{'mapping'}))
+      {
+        $c_info->{'mapping'} = $cxx_stuff;
+      }
+    }
+
+    if ($apply_conversion)
+    {
+      if (exists ($c_info->{'conversions'}))
+      {
+        my $c_conversions = $c_info->{'conversions'};
+
+        foreach my $cxx_sub_stuff (@{$cxx_sub_types})
+        {
+          if (exists ($c_conversions->{$cxx_sub_stuff}))
+          {
+            my $type_or_types = $c_conversions->{$cxx_sub_stuff};
+            my $type_or_types_ref = ref ($type_or_types);
+
+            if ($type_or_types_ref eq '')
+            {
+              if ($type_or_types_ref ne $type)
+              {
+                $c_conversions->{$cxx_sub_stuff} = [$type_or_types, $type];
+              }
+            }
+            elsif ($type_or_types_ref eq 'ARRAY')
+            {
+              my $found = 0;
+
+              foreach my $previous_type (@{$type_or_types})
+              {
+                if ($previous_type eq $type)
+                {
+                  $found = 1;
+                  last;
+                }
+              }
+              unless ($found)
+              {
+                push @{$type_or_types}, $type;
+              }
+            }
+            else
+            {
+# TODO: internal error.
+              die;
+            }
+          }
+          else
+          {
+            $c_conversions->{$cxx_sub_stuff} = $type;
+          }
+        }
+      }
+      else
+      {
+        my %temp_conversions = map { $_ => $type } @{$cxx_sub_types};
+
+        $c_info->{'conversions'} = \%temp_conversions;
+      }
+    }
+  }
+  else
+  {
+    my $c_info = {};
+
+    if ($apply_mapping)
+    {
+      $c_info->{'mapping'} = $cxx_stuff;
+    }
+    if ($apply_conversion)
+    {
+      my %temp_conversions = map { $_ => $type } @{$cxx_sub_types};
+
+      $c_info->{'conversions'} = \%temp_conversions;
+    }
+    $from_c_conversions->{$c_stuff} = $c_info;
+  }
+
+  my $cxx_infos = $conversions->{'cxx'};
+
+  if ($apply_mapping)
+  {
+    my $cxx_mappings = $cxx_infos->{'mappings'};
+
+    if (not exists ($cxx_mappings->{$cxx_stuff}) or not defined ($cxx_mappings->{$cxx_stuff}))
+    {
+      $cxx_mappings->{$cxx_stuff} = $c_stuff;
+    }
+  }
+  if ($apply_conversion)
+  {
+    my $from_cxx_conversions = $cxx_infos->{'conversions'};
+
+    foreach my $cxx_sub_stuff (@{$cxx_sub_types})
+    {
+      if (exists $from_cxx_conversions->{$cxx_sub_stuff})
+      {
+        my $cxx_conversions = $conversions->{$cxx_sub_stuff};
+
+        if (exists ($cxx_conversions->{$c_stuff}))
+        {
+          my $type_or_types = $cxx_conversions->{$c_stuff};
+          my $type_or_types_ref = ref ($type_or_types);
+
+          if ($type_or_types_ref eq '')
+          {
+            if ($type_or_types ne $type)
+            {
+              $cxx_conversions->{$c_stuff} = [$type_or_types, $type];
+            }
+          }
+          elsif ($type_or_types_ref eq 'ARRAY')
+          {
+            my $found = 0;
+
+            foreach my $previous_type (@{$type_or_types})
+            {
+              if ($previous_type eq $type)
+              {
+                $found = 1;
+                last;
+              }
+            }
+            unless ($found)
+            {
+              push (@{$type_or_types}, $type);
+            }
+          }
+          else
+          {
+# TODO: internal error.
+            die;
+          }
+        }
+        else
+        {
+          $cxx_conversions->{$c_stuff} = $type;
+        }
+      }
+      else
+      {
+        $from_cxx_conversions->{$cxx_sub_stuff} = { $c_stuff => $type };
+      }
+    }
+  }
+}
+
+sub _get_unambiguous_tuples ($)
+{
+  my ($self) = @_;
+  my $conversions = $self->_get_general_conversions (GENERATED)->{'c'};
+  my @tuples = ();
+
+  foreach my $c_stuff (sort keys %{$conversions})
+  {
+    my $c_info = $conversions->{$c_stuff};
+
+    if (exists ($c_info->{'mapping'}) and exists ($c_info->{'conversions'}))
+    {
+      my $cxx_stuff = $c_info->{'mapping'};
+
+      if (defined ($cxx_stuff) and ref ($cxx_stuff) eq '' and exists ($c_info->{'conversions'}{$cxx_stuff}))
+      {
+        my $type = $c_info->{'conversions'}{$cxx_stuff};
+
+        if (defined $type and ref ($type) eq '')
+        {
+          push (@tuples, [$c_stuff, $cxx_stuff, $type]);
+        }
+      }
+    }
+  }
+
+  return \ tuples;
+}
+
+#sub _get_stuff_from ($$$)
+#{
+#  my ($self, $stuff, $mapping_getter) = @_;
+#
+#  foreach my $which (_desired_order ())
+#  {
+#    my $mapping = $self->$mapping_getter ($which);
+#
+#    if (exists $mapping->{$stuff})
+#    {
+#      return $mapping->{$stuff};
+#    }
+#  }
+#
+#  return undef;
+#}
+
+sub _get_mm_module ($)
+{
+  my ($self) = @_;
+
+  return $self->{'mm_module'};
+}
+
+sub _get_include_paths ($)
+{
+  my ($self) = @_;
+
+  return $self->{'include_paths'};
+}
+
+sub _get_read_files ($)
+{
+  my ($self) = @_;
+
+  return $self->{'read_files'};
+}
+
+#sub _get_common ($$$)
+#{
+#  my ($self, $which, $what) = @_;
+#  my $name = '';
+#
+#  given ($which)
+#  {
+#    when (FROM_FILES)
+#    {
+#      $name = 'from_files';
+#    }
+#    when (GENERATED)
+#    {
+#      $name = 'generated';
+#    }
+#    default
+#    {
+## TODO: throw internal error.
+#      die;
+#    }
+#  }
+#
+#  return $self->{$name}{$what};
+#}
+
+#sub _get_c_to_cxx ($$)
+#{
+#  my ($self, $which) = @_;
+#
+#  return $self->_get_common ($which, 'c_to_cxx');
+#}
+
+#sub _get_cxx_to_c ($$)
+#{
+#  my ($self, $which) = @_;
+#
+#  return $self->_get_common ($which, 'cxx_to_c');
+#}
+
+sub _get_conversions ($$)
+{
+  my ($self, $which) = @_;
+
+  return $self->{_which_to_string ($which)};
+}
+
+sub _get_specific_conversions ($$)
+{
+  my ($self, $which) = @_;
+  my $conversions = $self->_get_conversions ($which);
+
+  return $conversions->{'specific'};
+}
+
+sub _get_general_conversions ($$)
+{
+  my ($self, $which) = @_;
+  my $conversions = $self->_get_conversions ($which);
+
+  return $conversions->{'general'};
+}
+##
+## general_conversions = { 'c'   => {
+##                                    $c_stuff   => {
+##                                                    'mapping'     => $cxx_stuff,
+##                                                    'conversions' => { $cxx_stuff => $type }
+##                                                  }
+##                                  },
+##                         'cxx' => {
+##                                    'mappings'    => { $full_cxx_stuff => $c_stuff },
+##                                    'conversions' => { $cxx_stuff => { $c_stuff => $type }}
+##                                  }
+##                       }
+##
+# TODO: move into separate class.
+sub _create_hierarchy ()
+{
+  return
+  {
+    'general' =>
+    {
+      'c' => {},
+      'cxx' =>
+      {
+        'mappings' => {},
+        'conversions' => {}
+      }
+    },
+    'specific' => {}
+  };
+}
+
+sub new ($$$)
+{
+  my ($type, $mm_module, $include_paths) = @_;
+  my $class = (ref $type or $type or 'Common::TypeInfo::Global');
+  my $c_container_types =
+  {
+    'GList' => undef,
+    'GSList' => undef,
+    'GArray' => undef,
+    'GByteArray' => undef,
+    'GHashTable' => undef
+  };
+  my $cxx_container_types =
+  {
+    'std::vector' => undef,
+    'vector' => undef,
+    'Glib::ArrayHandle' => undef,
+    'ArrayHandle' => undef,
+    'Glib::ListHandle' => undef,
+    'ListHandle' => undef,
+    'Glib::SListHandle' => undef,
+    'SListHandle' => undef
+  };
+  my $cxx_pointer_types =
+  {
+    'Glib::RefPtr' => undef,
+    'RefPtr' => undef
+  };
+  my $self =
+  {
+#    'generated' => $generated,
+#    'from_files' => $from_files,
+    'mm_module' => $mm_module,
+    'include_paths' => $include_paths,
+    'read_files' => {},
+    'c_container_types' => $c_container_types,
+    'cxx_container_types' => $cxx_container_types,
+    'cxx_pointer_types' => $cxx_pointer_types
+  };
+  map { $self->{ _which_to_string ($_)} = _create_hierarchy (); } (_desired_order ());
+
+  $self = bless ($self, $class);
+
+  my $convertors =
+  {
+    'ENUM' => sub { Common::TypeInfo::Convertors::Enum::convert ($self, $_[0], $_[1], $_[2], $_[3], $_[4]); },
+    'EQUAL' => sub { Common::TypeInfo::Convertors::Equal::convert ($self, $_[0], $_[1], $_[2], $_[3], $_[4]); },
+    'FUNC' => sub { Common::TypeInfo::Convertors::Func::convert ($self, $_[0], $_[1], $_[2], $_[3], $_[4]); },
+    'MANUAL' => sub { Common::TypeInfo::Convertors::Manual::convert ($self, $_[0], $_[1], $_[2], $_[3], $_[4]); },
+    'NORMAL' => sub { Common::TypeInfo::Convertors::Normal::convert ($self, $_[0], $_[1], $_[2], $_[3], $_[4]); },
+    'REFFED' => sub { Common::TypeInfo::Convertors::Reffed::convert ($self, $_[0], $_[1], $_[2], $_[3], $_[4]); },
+    'STDSTRING' => sub { Common::TypeInfo::Convertors::StdString::convert ($self, $_[0], $_[1], $_[2], $_[3], $_[4]); },
+    'USTRING' => sub { Common::TypeInfo::Convertors::Ustring::convert ($self, $_[0], $_[1], $_[2], $_[3], $_[4]); }
+  };
+
+  $self->{'convertors'} = $convertors;
+
+  return $self;
+}
+
+sub register_convertor ($$$)
+{
+  my ($self, $conversion_type, $convertor) = @_;
+  my $convertors = $self->_get_convertors;
+
+  if (exists $convertors->{$conversion_type})
+  {
+    die;
+  }
+  $convertors->{$conversion_type} = $convertor;
+}
+
+sub add_generated_info ($$$$)
+{
+  my ($self, $c_stuff, $cxx_stuff, $type) = @_;
+  my $apply_conversion = 1;
+  my $apply_mapping = 1;
+
+  $self->_add_info_to_general_conversions ($c_stuff, $cxx_stuff, $type, GENERATED, $apply_conversion, $apply_mapping);
+}
+
+sub c_to_cxx ($$)
+{
+  my ($self, $c_stuff) = @_;
+
+  foreach my $which (_desired_order ())
+  {
+    my $from_c_conversions = $self->_get_general_conversions ($which)->{'c'};
+
+    if (exists ($from_c_conversions->{$c_stuff}))
+    {
+      my $c_info = $from_c_conversions->{$c_stuff};
+
+      if (exists $c_info->{'mapping'})
+      {
+        my $mapping = $c_info->{'mapping'};
+
+        if (defined ($mapping))
+        {
+          return $mapping;
+        }
+      }
+    }
+  }
+
+  return undef;
+}
+
+sub cxx_to_c ($$)
+{
+  my ($self, $cxx_stuff) = @_;
+
+  foreach my $which (_desired_order ())
+  {
+    my $cxx_mappings = $self->_get_general_conversions ($which)->{'cxx'}{'mappings'};
+
+    if (exists ($cxx_mappings->{$cxx_stuff}))
+    {
+      my $mapping = $cxx_mappings->{$cxx_stuff};
+
+      if (defined ($mapping))
+      {
+        return $mapping;
+      }
+    }
+  }
+
+  return undef;
+}
+
+sub get_conversion ($$$$$)
+{
+  my ($self, $from, $to, $transfer, $subst) = @_;
+
+  foreach my $type (_desired_order ())
+  {
+    foreach my $method (\&_get_specific_conversion, \&_get_general_conversion)
+    {
+      my $conversion = $self->$method ($type,
+                                       $from,
+                                       $to,
+                                       $transfer,
+                                       $subst);
+
+      if (defined $conversion)
+      {
+        return $conversion;
+      }
+    }
+  }
+
+# TODO: throw proper exception
+  die join '', 'Could not find any conversion from `', $from, '\' to `', $to, '\' with transfer `', (Common::TypeInfo::Common::transfer_to_string $transfer), '\'';
+  return undef;
+}
+
+sub add_infos_from_file ($$)
+{
+  my ($self, $basename) = @_;
+  my $generated_type_infos_filename = $self->_get_generated_type_infos_basename;
+
+  # Do not even try to look for file that is going to be generated
+  # at the end. Yeah, we make such basename reserved.
+  if ($basename ne $generated_type_infos_filename)
+  {
+    my $include_paths = $self->_get_include_paths;
+    my $read_files = $self->_get_read_files;
+    my $found = 0;
+    my $target = FROM_MODULE_FILES;
+
+    foreach my $path (@{$include_paths})
+    {
+      my $inc_filename = File::Spec->catfile ($path, $basename);
+
+      if (-f $inc_filename and -r $inc_filename)
+      {
+        $found = 1;
+
+        unless (exists $read_files->{$inc_filename})
+        {
+          my $fd = IO::File->new ($inc_filename, 'r');
+
+          $read_files->{$inc_filename} = undef;
+          unless (defined $fd)
+          {
+# TODO: throw an error
+            die 'Could not open file `' . $inc_filename . '\' for reading.' . "\n";
+          }
+
+          my @lines = $fd->getlines;
+          my $line_num = 0;
+          my $from = undef;
+          my $to = undef;
+          my $transfers = [undef, undef, undef];
+          my $expect_brace = 0;
+
+          $fd->close;
+          foreach my $line (@lines)
+          {
+            ++$line_num;
+            $line =~ s/^\s*#.*//;
+            $line = Common::Util::string_trim $line;
+
+            next if (not defined $line or $line eq '');
+
+            if ($expect_brace)
+            {
+              if ($line ne '{')
+              {
+# TODO: parsing error - expected opening brace only in line.
+                die;
+              }
+              $expect_brace = 0;
+            }
+            elsif (defined $from and defined $to)
+            {
+              if ($line =~ /^\s*(\w+)\s*:\s*(.*)$/)
+              {
+                my $transfer_str = $1;
+                my $transfer = $2;
+                my $index = Common::TypeInfo::Common::transfer_from_string $transfer_str;
+
+# TODO: parsing error - wrong transfer name.
+                die if ($index == Common::TypeInfo::Common::TRANSFER_INVALID);
+                if (defined $transfers->[$index])
+                {
+# TODO: parsing error - that transfer is already defined.
+                  die;
+                }
+
+                $transfers->[$index] = $transfer;
+              }
+              elsif ($line eq '}')
+              {
+                my $added = 0;
+
+                foreach my $transfer_type (Common::TypeInfo::Common::transfer_good_range)
+                {
+                  if (defined $transfers->[$transfer_type])
+                  {
+                    my $conversions = $self->_get_specific_conversions ($target);
+
+                    $added = 1;
+                    Common::TypeInfo::Common::add_specific_conversion ($conversions,
+                                                                       $from,
+                                                                       $to,
+                                                                       $transfers->[Common::TypeInfo::Common::TRANSFER_NONE],
+                                                                       $transfers->[Common::TypeInfo::Common::TRANSFER_CONTAINER],
+                                                                       $transfers->[Common::TypeInfo::Common::TRANSFER_FULL]);
+                    last;
+                  }
+                }
+# TODO: parsing error - no transfer specified.
+                die unless $added;
+
+                $from = undef;
+                $to = undef;
+                $transfers = [undef, undef, undef];
+              }
+            }
+            elsif ($line =~ /^(.+?)\s*=>\s*(.+):$/)
+            {
+              $from = $1;
+              $to = $2;
+              $expect_brace = 1;
+            }
+            elsif ($line =~ /^(.+?)\s*<=>\s*(.+?)\s*##\s*(.+?)$/)
+            {
+              my $c_stuff = $1;
+              my $cxx_stuff = $2;
+              my $type = $3;
+              my $apply_conversion = 1;
+              my $apply_mapping = 1;
+
+              $self->_add_info_to_general_conversions ($c_stuff,
+                                                       $cxx_stuff,
+                                                       $type,
+                                                       $target,
+                                                       $apply_conversion,
+                                                       $apply_mapping);
+            }
+            elsif ($line =~ /^(.+?)\s*<!>\s*(.+?)\s*##\s*(.+?)$/)
+            {
+              my $c_stuff = $1;
+              my $cxx_stuff = $2;
+              my $type = $3;
+              my $apply_conversion = 1;
+              my $do_not_apply_mapping = 0;
+
+              $self->_add_info_to_general_conversions ($c_stuff,
+                                                       $cxx_stuff,
+                                                       $type,
+                                                       $target,
+                                                       $apply_conversion,
+                                                       $do_not_apply_mapping);
+            }
+            elsif ($line =~ /^(.+?)\s*<=>\s*(.+?)$/)
+            {
+              my $c_stuff = $1;
+              my $cxx_stuff = $2;
+              my $do_not_apply_conversion = 0;
+              my $apply_mapping = 1;
+
+              $self->_add_info_to_general_conversions ($c_stuff,
+                                                       $cxx_stuff,
+                                                       undef,
+                                                       $target,
+                                                       $do_not_apply_conversion,
+                                                       $apply_mapping);
+            }
+            elsif ($line =~ /^include\s+(\S+)$/)
+            {
+              my $inc_basename = $1;
+
+              $self->add_infos_from_file ($inc_basename);
+            }
+            else
+            {
+# TODO: do proper logging.
+            }
+          }
+        }
+        last;
+      }
+      $target = FROM_FILES;
+    }
+    unless ($found)
+    {
+# TODO: throw an error.
+      my $message = 'Could not find `' . $basename . "' in following paths:\n";
+      foreach my $inc (@{$include_paths})
+      {
+        $message .= "$inc\n";
+      }
+      die $message;
+    }
+  }
+}
+
+sub write_generated_infos_to_file ($)
+{
+  my ($self) = @_;
+  my $filename = $self->_get_generated_type_infos_filename;
+  my $fd = IO::File->new ($filename, 'w');
+
+  unless (defined $fd)
+  {
+# TODO: do proper logging.
+    print STDERR 'Could not open file `' . $filename . '\' for writing.' . "\n";
+    exit 1;
+  }
+
+  $fd->print (join "\n",
+              '# $(C stuff) <=> $(C++ stuff) ## $(conversion type)',
+              '# LIKE: GtkWidget <=> Gtk::Widget ## NORMAL',
+              '# OR',
+              '# $(C stuff) <=> $(C++ stuff)',
+              '# LIKE: GFileAttributeInfo <=> Gio::FileAttributeInfo',
+              '# OR',
+              '# $(from) => $(to):',
+              '# {',
+              '#   none: $(none conversion)',
+              '#   container: $(container conversion)',
+              '#   full: $(full conversion)',
+              '# }',
+              '# LIKE: const Glib::RefPtr< Gio::Emblem > => GEmblem*:',
+              '#       {',
+              '#         none: Glib::unwrap(##ARG##)',
+              '#         full: Glib::unwrap_copy(##ARG##)',
+              '#       }',
+              '# all of none, container and full are optional, but at least one of them must be',
+              '# specified',
+              '#',
+              '');
+
+  my $c_cxx_tuples = $self->_get_unambiguous_tuples;
+
+  foreach my $tuple (@{$c_cxx_tuples})
+  {
+    my $c_stuff = $tuple->[0];
+    my $cxx_stuff = $tuple->[1];
+    my $type = $tuple->[2];
+
+    $fd->print (join '', $c_stuff, ' <=> ', $cxx_stuff, ' ## ', $type, "\n");
+  }
+
+  my $conversions = $self->_get_specific_conversions (GENERATED);
+
+  foreach my $from (sort keys %{$conversions})
+  {
+    my $to_convs = $conversions->{$from};
+
+    foreach my $to (sort keys %{$to_convs})
+    {
+      my $transfers = $to_convs->{$to};
+
+      $fd->print (join '', $from, ' => ', $to, ':', "\n", '{', "\n");
+
+      foreach my $transfer_type (Common::TypeInfo::Common::transfer_good_range)
+      {
+        my $transfer = $transfers->[$transfer_type];
+
+        if (defined $transfer)
+        {
+          $fd->print (join '', '  ', (Common::TypeInfo::Common::transfer_to_string $transfer_type), ': ', $transfer, "\n");
+        }
+      }
+
+      $fd->print (join '', '}', "\n\n");
+    }
+  }
+
+  $fd->close;
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Common/TypeInfo/Local.pm b/tools/pm/Common/TypeInfo/Local.pm
new file mode 100644
index 0000000..5156be1
--- /dev/null
+++ b/tools/pm/Common/TypeInfo/Local.pm
@@ -0,0 +1,94 @@
+# -*- mode: perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# gmmproc - Common::TypeInfo::Local module
+#
+# Copyright 2012 glibmm development team
+#
+# 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 program 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+package Common::TypeInfo::Local;
+
+use strict;
+use warnings;
+
+sub _get_conversions ($)
+{
+  my ($self) = @_;
+
+  return $self->{'conversions'};
+}
+
+sub _get_global ($)
+{
+  my ($self) = @_;
+
+  return $self->{'global'};
+}
+
+sub new ($$)
+{
+  my ($type, $global) = @_;
+  my $class = (ref $type or $type or 'Common::TypeInfo::Local');
+  my $self =
+  {
+    'conversions' => {},
+    'global' => $global
+  };
+
+  return bless $self, $class;
+}
+
+sub add_conversion ($$$$$$)
+{
+  my ($self, $from, $to, $transfer_none, $transfer_container, $transfer_full) = @_;
+  my $conversions = $self->_get_conversions;
+
+  Common::TypeInfo::Common::add_specific_conversion $conversions, $from, $to, $transfer_none, $transfer_container, $transfer_full;
+}
+
+sub get_conversion ($$$$$)
+{
+  my ($self, $from, $to, $transfer, $subst) = @_;
+  my $conversions = $self->_get_conversions;
+  my $conversion = Common::TypeInfo::Common::get_specific_conversion $conversions, $from, $to, $transfer, $subst;
+
+  unless (defined $conversion)
+  {
+    my $global = $self->_get_global;
+
+    # this will throw an exception when nothing is found.
+    $conversion = $global->get_conversion ($from, $to, $transfer, $subst);
+  }
+
+  return $conversion;
+}
+
+sub c_to_cxx ($$)
+{
+  my ($self, $c_stuff) = @_;
+  my $global = $self->_get_global;
+
+  $global->c_to_cxx ($c_stuff);
+}
+
+sub cxx_to_c ($$)
+{
+  my ($self, $cxx_stuff) = @_;
+  my $global = $self->_get_global;
+
+  $global->cxx_to_c ($cxx_stuff);
+}
+
+1; # indicate proper module load.



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]