
#
#           Interface Definition Language (OMG IDL CORBA v3.0)
#

package CORBA::Python::CPyExtendedVisitor;

use strict;
use warnings;

our $VERSION = '2.61';

use CORBA::Python::CPyVisitor;
use base qw(CORBA::Python::CPyVisitor);

use File::Basename;
use POSIX qw(ctime);

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = {};
    bless $self, $class;
    my ($parser) = @_;
    $self->{srcname} = $parser->YYData->{srcname};
    $self->{srcname_size} = $parser->YYData->{srcname_size};
    $self->{srcname_mtime} = $parser->YYData->{srcname_mtime};
    $self->{symbtab} = $parser->YYData->{symbtab};
    $self->{client} = 1;
    if (exists $parser->YYData->{opt_J}) {
        $self->{base_package} = $parser->YYData->{opt_J};
    }
    else {
        $self->{base_package} = q{};
    }
    $self->{done_hash} = {};
    $self->{out} = undef;
    return $self;
}

sub open_stream {
    my $self = shift;
    my ($filename) = @_;
    $self->{out} = new IO::File "> $filename"
            or die "can't open $filename ($!).\n";
    $self->{filename} = $filename;
}

sub _get_defn {
    my $self = shift;
    my ($defn) = @_;
    if (ref $defn) {
        return $defn;
    }
    else {
        return $self->{symbtab}->Lookup($defn);
    }
}

sub _import_module {
    my $self = shift;
    my ($defn) = @_;
    my $mod = $defn;
    my $full = $mod->{full};
    my $modulename;
    my $c_mod;
    my $classname = q{};
    while (!$mod->isa('Modules')) {
        $full =~ s/(::[0-9A-Z_a-z]+)$//;
        $classname = $1 . $classname;
        last unless ($full);
        $mod = $self->{symbtab}->Lookup($full);
    }
    $classname =~ s/^:://;
    $classname =~ s/::/\./g;
    if ($full) {
        $modulename = $full;
        $modulename =~ s/^:://;
        $modulename =~ s/::/\./g;
        $c_mod = $mod->{c_name};
    }
    else {
        $modulename = $self->{root_module};
        $c_mod = $modulename;
    }
    unless (exists $self->{imp_mod}->{$modulename}) {
        $self->{imp_mod}->{$modulename} = 1;
        $self->{init} .= "\t_mod_" . $c_mod . " = PyImport_ImportModule(\"" . $modulename . "\"); // New reference\n";
    }
}

sub _get_c_decl_var {
    my $self = shift;
    my ($type, $attr, $name) = @_;

    if ( $type->isa('BaseInterface')
      or $type->isa('BasicType')
      or $type->isa('EnumType')
      or $type->isa('StringType')
      or $type->isa('WideStringType')
      or $type->isa('FixedPtType') ) {
        if (    $attr eq 'in' ) {
            return $type->{c_name} . q{ } . $name;
        }
        elsif ( $attr eq 'inout' ) {
            return $type->{c_name} . q{ } . $name;
        }
        elsif ( $attr eq 'out' ) {
            return $type->{c_name} . q{ } . $name;
        }
        elsif ( $attr eq 'return' ) {
            return $type->{c_name} . q{ } . $name;
        }
    }
    elsif ( $type->isa('StructType')
         or $type->isa('UnionType') ) {
        if (    $attr eq 'in' ) {
            return $type->{c_name} . q{ } . $name;
        }
        elsif ( $attr eq 'inout' ) {
            return $type->{c_name} . q{ } . $name;
        }
        elsif ( $attr eq 'out' ) {
            if (defined $type->{length}) {      # variable
                return $type->{c_name} . ' * ' . $name;
            }
            else {
                return $type->{c_name} . q{ } . $name;
            }
        }
        elsif ( $attr eq 'return' ) {
            if (defined $type->{length}) {      # variable
                return $type->{c_name} . ' * ' . $name;
            }
            else {
                return $type->{c_name} . q{ } . $name;
            }
        }
    }
    elsif ( $type->isa('SequenceType') ) {
        if (    $attr eq 'in' ) {
            return $type->{c_name} . q{ } . $name;
        }
        elsif ( $attr eq 'inout' ) {
            return $type->{c_name} . q{ } . $name;
        }
        elsif ( $attr eq 'out' ) {
            return $type->{c_name} . ' * ' . $name;
        }
        elsif ( $attr eq 'return' ) {
            return $type->{c_name} . ' * ' . $name;
        }
    }
    elsif ( $type->isa('TypeDeclarator') ) {
        if (exists $type->{array_size}) {
            warn "_get_c_decl_var TypeDeclarator $type->{idf} : empty array_size.\n"
                    unless (@{$type->{array_size}});
            if (    $attr eq 'in' ) {
                return $type->{c_name} . q{ } . $name;
            }
            elsif ( $attr eq 'inout' ) {
                return $type->{c_name} . q{ } . $name;
            }
            elsif ( $attr eq 'out' ) {
                if (defined $type->{length}) {      # variable
                    return $type->{c_name} . '_slice * ' . $name;
                }
                else {
                    return $type->{c_name} . q{ } . $name;
                }
            }
            elsif ( $attr eq 'return' ) {
                return $type->{c_name} . '_slice ' . $name;
            }
        }
        else {
            my $type = $type->{type};
            unless (ref $type) {
                $type = $self->{symbtab}->Lookup($type);
            }
            return $self->_get_c_decl_var($type, $attr, $name);
        }
    }
    elsif ( $type->isa('NativeType') ) {
        warn "_get_c_decl_var NativeType : not supplied \n";
        return;
    }
    elsif ( $type->isa('AnyType') ) {
        warn "_get_c_decl_var AnyType : not supplied \n";
        return;
    }
    else {
        my $class = ref $type;
        warn "Please implement '$class' in '_get_c_decl_var'.\n";
        return;
    }
}

sub _get_c_name_call {
    my $self = shift;
    my ($type, $attr) = @_;

    if ( $type->isa('BaseInterface')
      or $type->isa('BasicType')
      or $type->isa('EnumType')
      or $type->isa('StringType')
      or $type->isa('WideStringType') ) {
        if (    $attr eq 'in' ) {
            return q{};
        }
        elsif ( $attr eq 'inout' ) {
            return '&';
        }
        elsif ( $attr eq 'out' ) {
            return '&';
        }
        elsif ( $attr eq 'return' ) {
            return q{};
        }
    }
    elsif ( $type->isa('StructType')
         or $type->isa('UnionType')
         or $type->isa('SequenceType')
         or $type->isa('FixedPtType') ) {
        if (    $attr eq 'in' ) {
            return '&';
        }
        elsif ( $attr eq 'inout' ) {
            return '&';
        }
        elsif ( $attr eq 'out' ) {
            return '&';
        }
        elsif ( $attr eq 'return' ) {
            return q{};
        }
    }
    elsif ( $type->isa('TypeDeclarator') ) {
        if (exists $type->{array_size}) {
            warn "_get_c_name_call TypeDeclarator $type->{idf} : empty array_size.\n"
                    unless (@{$type->{array_size}});
            if (    $attr eq 'in' ) {
                return q{};
            }
            elsif ( $attr eq 'inout' ) {
                return q{};
            }
            elsif ( $attr eq 'out' ) {
                if (defined $type->{length}) {      # variable
                    return q{};
                }
                else {
                    return q{};
                }
            }
            elsif ( $attr eq 'return' ) {
                return q{};
            }
        }
        else {
            my $type = $type->{type};
            unless (ref $type) {
                $type = $self->{symbtab}->Lookup($type);
            }
            return $self->_get_c_name_call($type, $attr);
        }
    }
    elsif ( $type->isa('NativeType') ) {
        warn "_get_c_name_call NativeType : not supplied \n";
        return;
    }
    elsif ( $type->isa('AnyType') ) {
        warn "_get_c_name_call AnyType : not supplied \n";
        return;
    }
    else {
        my $class = ref $type;
        warn "Please implement '$class' in '_get_c_name_call'.\n";
        return;
    }
}

sub _get_c_free {
    my $self = shift;
    my ($type, $attr) = @_;

    if ( $type->isa('BaseInterface')
      or $type->isa('BasicType')
      or $type->isa('EnumType')
      or $type->isa('FixedPtType') ) {
        if (    $attr eq 'in' ) {
            return '&';
        }
        elsif ( $attr eq 'inout' ) {
            return '&';
        }
        elsif ( $attr eq 'out' ) {
            return '&';
        }
        elsif ( $attr eq 'return' ) {
            return '&';
        }
    }
    elsif ( $type->isa('StructType')
         or $type->isa('UnionType') ) {
        if (    $attr eq 'in' ) {
            return '&';
        }
        elsif ( $attr eq 'inout' ) {
            return '&';
        }
        elsif ( $attr eq 'out' ) {
            if (defined $type->{length}) {      # variable
                return q{};
            }
            else {
                return '&';
            }
        }
        elsif ( $attr eq 'return' ) {
            if (defined $type->{length}) {      # variable
                return q{};
            }
            else {
                return '&';
            }
        }
    }
    elsif ( $type->isa('SequenceType') ) {
        if (    $attr eq 'in' ) {
            return '&';
        }
        elsif ( $attr eq 'inout' ) {
            return '&';
        }
        elsif ( $attr eq 'out' ) {
            return q{};
        }
        elsif ( $attr eq 'return' ) {
            return q{};
        }
    }
    elsif ( $type->isa('StringType')
         or $type->isa('WideStringType') ) {
        if (    $attr eq 'in' ) {
            return '&';
        }
        elsif ( $attr eq 'inout' ) {
            return '&';
        }
        elsif ( $attr eq 'out' ) {
            return '&';
        }
        elsif ( $attr eq 'return' ) {
            return q{};
        }
    }
    elsif ( $type->isa('TypeDeclarator') ) {
        if (exists $type->{array_size}) {
            warn "_get_c_free TypeDeclarator $type->{idf} : empty array_size.\n"
                    unless (@{$type->{array_size}});
            if (    $attr eq 'in' ) {
                return '&';
            }
            elsif ( $attr eq 'inout' ) {
                return '&';
            }
            elsif ( $attr eq 'out' ) {
                if (defined $type->{length}) {      # variable
                    return '&';
                }
                else {
                    return '&';
                }
            }
            elsif ( $attr eq 'return' ) {
                return '&';
            }
        }
        else {
            my $type = $type->{type};
            unless (ref $type) {
                $type = $self->{symbtab}->Lookup($type);
            }
            return $self->_get_c_free($type, $attr);
        }
    }
    elsif ( $type->isa('NativeType') ) {
        warn "_get_c_free NativeType : not supplied \n";
        return;
    }
    elsif ( $type->isa('AnyType') ) {
        warn "_get_c_free AnyType : not supplied \n";
        return;
    }
    else {
        my $class = ref $type;
        warn "Please implement '$class' in '_get_c_free'.\n";
        return;
    }
}

sub _get_c_ext_obj {
    my $self = shift;
    my ($type, $attr) = @_;

    if ( $type->isa('BaseInterface')
      or $type->isa('FloatingPtType')
      or $type->isa('IntegerType')
      or $type->isa('OctetType')
      or $type->isa('CharType')
      or $type->isa('BooleanType')
      or $type->isa('EnumType')
      or $type->isa('StringType') ) {
        if (    $attr eq 'in' ) {
            return q{};
        }
        elsif ( $attr eq 'inout' ) {
            return q{};
        }
        elsif ( $attr eq 'out' ) {
            return q{};
        }
        elsif ( $attr eq 'return' ) {
            return q{};
        }
    }
    elsif ( $type->isa('StructType')
         or $type->isa('UnionType') ) {
        if (    $attr eq 'in' ) {
            return q{};
        }
        elsif ( $attr eq 'inout' ) {
            return q{};
        }
        elsif ( $attr eq 'out' ) {
            if (defined $type->{length}) {      # variable
                return '*';
            }
            else {
                return q{};
            }
        }
        elsif ( $attr eq 'return' ) {
            if (defined $type->{length}) {      # variable
                return '*';
            }
            else {
                return q{};
            }
        }
    }
    elsif ( $type->isa('SequenceType') ) {
        if (    $attr eq 'in' ) {
            return q{};
        }
        elsif ( $attr eq 'inout' ) {
            return q{};
        }
        elsif ( $attr eq 'out' ) {
            return '*';
        }
        elsif ( $attr eq 'return' ) {
            return q{};
        }
    }
    elsif ( $type->isa('TypeDeclarator') ) {
        if (exists $type->{array_size}) {
            warn __PACKAGE__,"::NameAttrTypeDeclarator $type->{idf} : empty array_size.\n"
                    unless (@{$type->{array_size}});
            if (    $attr eq 'in' ) {
                return q{};
            }
            elsif ( $attr eq 'inout' ) {
                return q{};
            }
            elsif ( $attr eq 'out' ) {
                if (defined $type->{length}) {      # variable
                    return q{};
                }
                else {
                    return q{};
                }
            }
            elsif ( $attr eq 'return' ) {
                return q{};
            }
        }
        else {
            my $type = $type->{type};
            unless (ref $type) {
                $type = $self->{symbtab}->Lookup($type);
            }
            return $self->_get_c_ext_obj($type, $attr);
        }
    }
    elsif ( $type->isa('NativeType') ) {
        warn "_get_c_ext_obj NativeType : not supplied \n";
        return;
    }
    elsif ( $type->isa('AnyType') ) {
        warn "_get_c_ext_obj AnyType : not supplied \n";
        return;
    }
    else {
        my $class = ref $type;
        warn "Please implement '$class' in '_get_c_ext_obj'.\n";
        return;
    }
}

#
#   3.5     OMG IDL Specification
#

sub visitSpecification {
    my $self = shift;
    my ($node) = @_;
    my $basename = basename($self->{srcname}, '.idl');
    my $py_name = '_' . $basename;
    $py_name =~ s/\./_/g;
    $self->{root_module} = $py_name;
    $self->{init} = q{};
    $self->{methods} = q{};
    $self->{imp_mod} = {};
    my $empty = 1;
    foreach (@{$node->{list_decl}}) {
        my $defn = $self->_get_defn($_);
        unless (   $defn->isa('Modules')
                or $defn->isa('Import') ) {
            $empty = 0;
        }
    }
    unless ($empty) {
        my $filename = 'c' . $py_name . 'module.c';
        $self->open_stream($filename);
        my $FH = $self->{out};
        print $FH "/* This file was generated (by ",basename($0),"). DO NOT modify it */\n";
        print $FH "/* From file : ",$self->{srcname},", ",$self->{srcname_size}," octets, ",POSIX::ctime($self->{srcname_mtime});
        print $FH " */\n";
        print $FH "\n";
        print $FH "#include \"Python.h\"\n";
        print $FH "#include \"",$basename,".h\"\n";
        print $FH "\n";
        print $FH "#include \"hpy_",$basename,".h\"\n";
        print $FH "\n";
    }
    foreach (@{$node->{list_decl}}) {
        $self->_get_defn($_)->visit($self);
    }
    unless ($empty) {
        my $FH = $self->{out};
        print $FH "static PyMethodDef ",$py_name,"Methods[] = {\n";
        print $FH $self->{methods};
        print $FH "\t{ NULL, NULL }\n";
        print $FH "};\n";
        print $FH "\n";
        print $FH "PyMODINIT_FUNC\n";
        print $FH "initc",$py_name,"(void)\n";
        print $FH "{\n";
        print $FH "\tPyObject *m;\n";
        print $FH "\n";
        print $FH "\tm = Py_InitModule(\"c",$py_name,"\", ",$py_name,"Methods); // Borrowed reference\n";
        print $FH $self->{init};
        print $FH "}\n";
        print $FH "\n";
        print $FH "/* end of file : ",$self->{filename}," */\n";
        close $FH;
    }
}

#
#   3.7     Module Declaration
#

sub visitModules {
    my $self = shift;
    my ($node) = @_;
    my $basename = basename($self->{srcname}, '.idl');
    my @name = split /::/, $node->{full};
    shift @name;
    my $py_name = join '_', @name;
    $name[-1] = 'c' . $name[-1];
    my $filename = join '/', @name;
    $filename .= 'module.c';
    my $save_out = $self->{out};
    my $save_init = $self->{init};
    my $save_methods = $self->{methods};
    my $save_imp_mod = $self->{imp_mod};
    $self->open_stream($filename);
    $self->{init} = q{};
    $self->{methods} = q{};
    $self->{imp_mod} = {};
    my $FH = $self->{out};
    print $FH "/* This file was generated (by ",basename($0),"). DO NOT modify it */\n";
    print $FH "/* From file : ",$self->{srcname},", ",$self->{srcname_size}," octets, ",POSIX::ctime($self->{srcname_mtime});
    print $FH " */\n";
    print $FH "\n";
    print $FH "#include \"Python.h\"\n";
    print $FH "#include \"",$basename,".h\"\n";
    print $FH "\n";
    print $FH "#include \"hpy_",$basename,".h\"\n";
    print $FH "\n";
    $self->{methods} = q{};
    foreach (@{$node->{list_decl}}) {
        $self->_get_defn($_)->visit($self);
    }
    print $FH "static PyMethodDef ",$py_name,"Methods[] = {\n";
    print $FH $self->{methods};
    print $FH "\t{ NULL, NULL }\n";
    print $FH "};\n";
    print $FH "\n";
    print $FH "PyMODINIT_FUNC\n";
    print $FH "init",$name[-1],"(void)\n";
    print $FH "{\n";
    print $FH "\tPyObject *m;\n";
    print $FH "\n";
    print $FH "\tm = Py_InitModule(\"",$name[-1],"\", ",$py_name,"Methods); // Borrowed reference\n";
    print $FH $self->{init};
    print $FH "}\n";
    print $FH "\n";
    print $FH "/* end of file : ",$self->{filename}," */\n";
    close $FH;
    $self->{out} = $save_out;
    $self->{init} = $save_init;
    $self->{imp_mod} = $save_imp_mod;
    $self->{methods} = $save_methods;
}

sub visitModule {
    my $self = shift;
    my ($node) = @_;
    foreach (@{$node->{list_decl}}) {
        $self->_get_defn($_)->visit($self);
    }
}

#
#   3.8     Interface Declaration
#

sub visitBaseInterface {
    # empty
}

sub visitForwardBaseInterface {
    # empty
}

sub visitRegularInterface {
    my $self = shift;
    my($node) = @_;
    my $FH = $self->{out};
    print $FH "/*\n";
    print $FH " * begin of interface ",$node->{py_name},"\n";
    print $FH " */\n";
    print $FH "\n";
    print $FH "typedef struct {\n";
    print $FH "\tPyObject_HEAD\n";
    print $FH "} ",$node->{c_name},"Object;\n";
    print $FH "\n";
    $self->{itf} = $node;
    my $save_methods = $self->{methods};
    $self->{methods} = q{};
    $self->{init} .= "\t" . $node->{c_name} . "Type.tp_new = PyType_GenericNew;\n";
    $self->{init} .= "\tif (PyType_Ready(&" . $node->{c_name} . "Type) < 0)\n";
    $self->{init} .= "\t\treturn;\n";
    $self->{init} .= "\tPy_INCREF(&" . $node->{c_name} . "Type);\n";
    $self->{init} .= "\tPyModule_AddObject(m, \"" . $node->{py_name} . "\", (PyObject*)&" . $node->{c_name} . "Type);\n";
    foreach (values %{$node->{hash_attribute_operation}}) {
        $self->_get_defn($_)->visit($self);
    }
    delete $self->{itf};
    print $FH "PyDoc_STRVAR(",$node->{c_name},"__doc__,";
    if (exists $node->{doc}) {
        print $FH "\n";
        print $FH "\"",$node->{doc},"\");\n";
    }
    else {
        print $FH " \"interface '",$node->{repos_id},"'\");\n";
    }
    print $FH "\n";
    print $FH "static PyMethodDef ",$node->{c_name},"Methods[] = {\n";
    print $FH $self->{methods};
    print $FH "\t{ NULL, NULL }\n";
    print $FH "};\n";
    print $FH "\n";
    print $FH "static PyTypeObject ",$node->{c_name},"Type = {\n";
    print $FH "\tPyObject_HEAD_INIT(NULL)\n";
    print $FH "\t0,\t/*ob_size*/\n";
    print $FH "\t\"",$node->{py_name},"\",\t/*tp_name*/\n";
    print $FH "\tsizeof(",$node->{c_name},"Object),\t/*tp_basicsize*/\n";
    print $FH "\t0,\t/*tp_itemsize*/\n";
    print $FH "\t0,\t/*tp_dealloc*/\n";
    print $FH "\t0,\t/*tp_print*/\n";
    print $FH "\t0,\t/*tp_getattr*/\n";
    print $FH "\t0,\t/*tp_setattr*/\n";
    print $FH "\t0,\t/*tp_compare*/\n";
    print $FH "\t0,\t/*tp_repr*/\n";
    print $FH "\t0,\t/*tp_as_number*/\n";
    print $FH "\t0,\t/*tp_as_sequence*/\n";
    print $FH "\t0,\t/*tp_as_mapping*/\n";
    print $FH "\t0,\t/*tp_hash */\n";
    print $FH "\t0,\t/*tp_call*/\n";
    print $FH "\t0,\t/*tp_str*/\n";
    print $FH "\t0,\t/*tp_getattro*/\n";
    print $FH "\t0,\t/*tp_setattro*/\n";
    print $FH "\t0,\t/*tp_as_buffer*/\n";
    print $FH "\tPy_TPFLAGS_DEFAULT,\t/*tp_flags*/\n";
    print $FH "\t",$node->{c_name},"__doc__,\t/* tp_doc */\n";
    print $FH "\t0,\t/*tp_traverse*/\n";
    print $FH "\t0,\t/*tp_clear*/\n";
    print $FH "\t0,\t/*tp_richcompare*/\n";
    print $FH "\t0,\t/*tp_weaklistoffset*/\n";
    print $FH "\t0,\t/*tp_iter*/\n";
    print $FH "\t0,\t/*tp_iternext*/\n";
    print $FH "\t",$node->{c_name},"Methods,\t/*tp_methods*/\n";
    print $FH "\t0,\t/*tp_members*/\n";
    print $FH "\t0,\t/*tp_getset*/\n";
    print $FH "\t0,\t/*tp_base*/\n";
    print $FH "\t0,\t/*tp_dict*/\n";
    print $FH "\t0,\t/*tp_descr_get*/\n";
    print $FH "\t0,\t/*tp_descr_set*/\n";
    print $FH "\t0,\t/*tp_dictoffset*/\n";
    print $FH "\t0,\t/*tp_init*/\n";
    print $FH "\t0,\t/*tp_alloc*/\n";
    print $FH "\t0,\t/*tp_new*/\n";
    print $FH "\t0,\t/*tp_free*/\n";
    print $FH "\t0,\t/*tp_is_gc*/\n";
    print $FH "};\n";
    print $FH "\n";
    print $FH "/*\n";
    print $FH " * end of interface ",$node->{py_name},"\n";
    print $FH " */\n";
    print $FH "\n";
    $self->{methods} = $save_methods;
}

#
#   3.10    Constant Declaration
#

sub visitConstant {
    # empty
}

#
#   3.11    Type Declaration
#

sub visitTypeDeclarators {
    # empty
}

#
#   3.11.2  Constructed Types
#

sub visitStructType {
    # empty
}

sub visitUnionType {
    # empty
}

sub visitForwardStructType {
    # empty
}

sub visitForwardUnionType {
    # empty
}

sub visitEnumType {
    # empty
}

#
#   3.11.3  Template Types
#

sub visitFixedPtType {
    # empty
}

sub visitFixedPtConstType {
    # empty
}

#
#   3.12    Exception Declaration
#

sub visitException {
    # empty
}

#
#   3.13    Operation Declaration
#

sub visitOperation {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    my $name = $self->{itf}->{c_name} . '_' . $node->{c_name};
    print $FH "PyDoc_STRVAR(",$name,"__doc__,";
    if (exists $node->{doc}) {
        print $FH "\n";
        print $FH "\"",$node->{doc},"\");\n";
    }
    else {
        print $FH " \"\");\n";
    }
    print $FH "\n";
    my $label_err = undef;
    my $type = $self->_get_defn($node->{type});
    unless ($type->isa('VoidType')) {               # return
        $label_err = $type->{length};
    }
    foreach (@{$node->{list_in}}) {                 # parameter
        my $type = $self->_get_defn($_->{type});
        $label_err ||= $type->{length};
    }
    foreach (@{$node->{list_inout}}) {              # parameter
        my $type = $self->_get_defn($_->{type});
        $label_err ||= $type->{length};
    }
    foreach (@{$node->{list_out}}) {                # parameter
        my $type = $self->_get_defn($_->{type});
    }
    my $nb_user_except = 0;
    $nb_user_except = @{$node->{list_raise}} if (exists $node->{list_raise});
    print $FH "static PyObject *\n";
    print $FH $name,"_meth(",$self->{itf}->{c_name},"Object *self, PyObject *args)\n";
    print $FH "{\n";
    print $FH "\tCORBA_Environment _ev = { CORBA_NO_EXCEPTION, NULL, NULL, NULL };\n";
    if (exists $node->{list_context}) {
        print $FH "\tCORBA_Context _ctx;\n";
    }
    unless ($type->isa('VoidType')) {
        print $FH "\t",$self->_get_c_decl_var($type, 'return', '_ret'),";\n";
    }
    foreach (@{$node->{list_param}}) {  # parameter
        my $type = $self->_get_defn($_->{type});
        print $FH "\t",$self->_get_c_decl_var($type, $_->{attr}, $_->{c_name}),";\n";
    }
    print $FH "#ifdef WITH_THREAD\n";
    print $FH "\tPyGILState_STATE _gstate;\n";
    print $FH "#endif\n";
    unless (exists $node->{modifier}) {     # oneway
        print $FH "\tPyObject * _result = NULL;\n";
    }
    my @fmt_in = ();
    my @fmt_out = ();
    my $args_in = q{};
    my $args_out = q{};
    unless ($type->isa('VoidType')) {
        my $fmt = $self->_get_cpy_format($type);
        if ($fmt eq 'O') {
            print $FH "\tPyObject * __ret;\n";
            $args_out .= ', __ret';
        }
        else {
            $args_out .= ', _ret';
        }
        push @fmt_out, $fmt;
    }
    foreach (@{$node->{list_param}}) {  # parameter
        my $type = $self->_get_defn($_->{type});
        my $fmt = $self->_get_cpy_format($type);
        if ($fmt eq 'O') {
            print $FH "\tPyObject * _",$_->{c_name},";\n";
        }
        if      ($_->{attr} eq "in") {
            if ($fmt eq 'O') {
                $args_in .= ', &_' . $_->{c_name};
            }
            else {
                $args_in .= ', &' . $_->{c_name};
            }
            push @fmt_in, $fmt;
        }
        elsif ($_->{attr} eq 'inout') {
            if ($fmt eq 'O') {
                $args_in .= ', &_' . $_->{c_name};
                $args_out .= ', _' . $_->{c_name};
            }
            else {
                $args_in .= ', &' . $_->{c_name};
                $args_out .= ', ' . $_->{c_name};
            }
            push @fmt_in, $fmt;
            push @fmt_out, $fmt;
        }
        elsif ($_->{attr} eq 'out') {
            if ($fmt eq 'O') {
                $args_out .= ', _' . $_->{c_name};
            }
            else {
                $args_out .= ', ' . $_->{c_name};
            }
            push @fmt_out, $fmt;
        }
    }
    print $FH "\n";
    if (scalar @fmt_in) {
        print $FH "\tif (!PyArg_ParseTuple(args, \"",@fmt_in,"\"",$args_in,"))\n";
        print $FH "\t\treturn NULL;\n";
        print $FH "\n";
    }
    foreach (@{$node->{list_param}}) {  # parameter
        next if ($_->{attr} eq 'out');
        my $type = $self->_get_defn($_->{type});
        my $fmt = $self->_get_cpy_format($type);
        if ($fmt eq 'O') {
            print $FH "\tPYOBJ_AS_",$type->{c_name},"(",$_->{c_name},", _",$_->{c_name},");\n";
        }
    }
    print $FH "\n";
    print $FH "#ifdef WITH_THREAD\n";
    print $FH "\t_gstate = PyGILState_Ensure();\n";
    print $FH "#endif\n";
    $type = $self->_get_defn($node->{type});
    if ($type->isa('VoidType')) {
        print $FH "\t",$self->{itf}->{c_name},"_",$node->{c_name},"(\n";
    }
    else {
        print $FH "\t",$self->_get_c_name_call($type, 'return'),"_ret = ";
            print $FH $self->{itf}->{c_name},"_",$node->{c_name},"(\n";
    }
    print $FH "\t\tNULL,\n";
    foreach (@{$node->{list_param}}) {
        my $type = $self->_get_defn($_->{type});
        print $FH "\t\t",$self->_get_c_name_call($type, $_->{attr}), $_->{c_name},",";
            print $FH " // ",$_->{attr}," (variable length)\n" if (defined $type->{length});
            print $FH " // ",$_->{attr}," (fixed length)\n" unless (defined $type->{length});
    }
    if (exists $node->{list_context}) {
        print $FH "\t\tCORBA_Context _ctx,\n";
    }
    print $FH "\t\t&_ev\n";
    print $FH "\t);\n";
    print $FH "#ifdef WITH_THREAD\n";
    print $FH "\tPyGILState_Release(_gstate);\n";
    print $FH "#endif\n";
    print $FH "\n";
    if (exists $node->{modifier}) {     # oneway
        print $FH "\tPy_RETURN_NONE;\n";
    }
    else {
        print $FH "\tif (CORBA_NO_EXCEPTION == _ev._major)\n";
        print $FH "\t{\n";
        unless ($type->isa('VoidType')) {
            my $fmt = $self->_get_cpy_format($type);
            if ($fmt eq 'O') {
                $self->_import_module($type);
                print $FH "\t\tPYOBJ_FROM_",$type->{c_name},"(__ret, ",$self->_get_c_ext_obj($type, 'return'),"_ret);\n";
            }
        }
        foreach (@{$node->{list_param}}) {  # parameter
            next if ($_->{attr} eq 'in');
            my $type = $self->_get_defn($_->{type});
            my $fmt = $self->_get_cpy_format($type);
            if ($fmt eq 'O') {
                $self->_import_module($type);
                print $FH "\t\tPYOBJ_FROM_",$type->{c_name},"(_",$_->{c_name},", ",$self->_get_c_ext_obj($type, $_->{attr}),$_->{c_name},");\n";
            }
        }
        print $FH "\t\t_result = Py_BuildValue(\"",@fmt_out,"\"",$args_out,"); // New reference\n";
        print $FH "\t}\n";
        print $FH "\telse if (CORBA_SYSTEM_EXCEPTION == _ev._major)\n";
        print $FH "\t{\n";
        print $FH "\t\tPyErr_SetString(PyExc_RuntimeError, CORBA_exception_id(&_ev));\n";
        print $FH "\t}\n";
        if (exists $node->{list_raise}) {
            print $FH "\telse if (CORBA_USER_EXCEPTION == _ev._major)\n";
            print $FH "\t{\n";
            my $condition = 'if ';
            foreach (@{$node->{list_raise}}) {
                my $defn = $self->_get_defn($_);
                $self->_import_module($defn);
                if ($nb_user_except > 1) {
                    print $FH "\t\t",$condition,"(0 == strcmp(ex_",$defn->{c_name},", CORBA_exception_id(&_ev)))\n";
                    print $FH "\t\t{\n";
                }
                print $FH "\t\t\tRAISE_",$defn->{c_name},"\n";
                $condition = 'else if ';
                if ($nb_user_except > 1) {
                    print $FH "\t\t}\n";
                }
            }
            print $FH "\t}\n";
        }
        if ($label_err) {
            print $FH "\n";
            print $FH "err:\n";
        }
        foreach (@{$node->{list_param}}) {  # parameter
            my $type = $self->_get_defn($_->{type});
            print $FH "\tFREE_",$_->{attr},"_",$type->{c_name},"(",$self->_get_c_free($type, $_->{attr}),$_->{c_name},");\n"
                    if (defined $type->{length});
        }
        unless ($type->isa("VoidType")) {
            print $FH "\tFREE_out_",$type->{c_name},"(",$self->_get_c_free($type, "out"),"_ret);\n"
                    if (defined $type->{length});
        }
        print $FH "\treturn _result;\n";
    }

    print $FH "}\n";
    print $FH "\n";
    if (scalar(@{$node->{list_in}}) + scalar(@{$node->{list_inout}})) {
        $self->{methods} .= "\t{ \"" . $node->{py_name} . "\", (PyCFunction)" . $name . "_meth, METH_VARARGS, " . $name . "__doc__ },\n";
    }
    else {
        $self->{methods} .= "\t{ \"" . $node->{py_name} . "\", (PyCFunction)" . $name . "_meth, METH_NOARGS, " . $name . "__doc__ },\n";
    }
}

#
#   3.14    Attribute Declaration
#

sub visitAttributes {
    my $self = shift;
    my ($node) = @_;
    foreach (@{$node->{list_decl}}) {
        $self->_get_defn($_)->visit($self);
    }
}

sub visitAttribute {
    my $self = shift;
    my ($node) = @_;
    $node->{_get}->visit($self);
    $node->{_set}->visit($self) if (exists $node->{_set});
}

#
#   3.15    Repository Identity Related Declarations
#

sub visitTypeId {
    # empty
}

sub visitTypePrefix {
    # empty
}

#
#   XPIDL
#

sub visitCodeFragment {
    # empty
}

1;

