# Copyright (C) 2004-2006, The Perl Foundation.
# $Id: Method.pm 23915 2007-12-15 08:38:40Z petdance $
package Parrot::Pmc2c::Method;
use strict;
use warnings;
use constant VTABLE_ENTRY => 'VTABLE_ENTRY';
use constant VTABLE       => 'VTABLE';
use constant NON_VTABLE   => 'NON_VTABLE';
use Carp;
use Parrot::Pmc2c::UtilFunctions qw(count_newlines args_from_parameter_list passable_args_from_parameter_list);

sub new {
    my ( $class, $self_hash ) = @_;
    my $self = {
        (
            attrs       => {},
            mmds        => [],
            body        => "",
            parameters  => "",
            mmd_rights  => [],
            parent_name => "",
            decorators  => [],
            %{ $self_hash || {} }
        )
    };
    bless $self, ( ref($class) || $class );
    $self;
}

sub clone {
    my ( $self, $self_hash ) = @_;
    return $self->new( { ( %{$self}, %{ $self_hash || {} } ) } );
}

sub add_mmd_rights {
    my ( $self, $value ) = @_;
    push @{ $self->{mmd_rights} }, $value;
}

sub mmd_rights {
    my ($self) = @_;
    return $self->{mmd_rights};
}

#getters/setters
for my $x qw( name parent_name type return_type body mmds symbol mmd_prefix mmd_table mmd_name
    right attrs decorators parameters ) {
    my $code = <<'EOC';
sub REPLACE {
    my ( $self, $value ) = @_;
    $self->{REPLACE} = $value if defined $value;
    return $self->{REPLACE}
}
EOC
        $code =~ s/REPLACE/$x/g;
        eval $code;
    }

    sub is_vtable {
    my ($self) = @_;
    my $type = $self->type;
    return $type eq VTABLE || $type eq VTABLE_ENTRY;
}

sub is_mmd {
    my ($self) = @_;

    return 1 if $self->{mmd_name};
    return 1 if $self->mmds and scalar @{ $self->mmds };
    return 0;
}

=head1 C<trans($type)>

Used in C<signature()> to normalize argument types.

=cut

sub trans {
    my ( $self, $type ) = @_;

    return "v" if ( !$type );
    my $char = substr $type, 0, 1;
    return $1 if ( $char =~ /([ISP])/ );
    return 'N' if ( $char eq 'F' );
    return 'v' if ( $type eq 'void' );
    return 'V' if ( $type =~ /void\s*\*\s*/ );
    return 'P' if ( $type =~ /opcode_t\*/ );
    return "I" if ( $type =~ /int(val)?/i );
    return '?';
}

=head1 C<signature()>

Returns the method signature for the methods $parameters

=cut

sub signature {
    my ($self) = @_;

    my $args             = passable_args_from_parameter_list( $self->parameters );
    my ($types,$vars)    = args_from_parameter_list( $self->parameters );
    my $return_type      = $self->return_type;
    my $return_type_char = $self->trans($return_type);
    my $sig              = $self->trans($return_type) . join '', map { $self->trans($_) } @{$types};
    my $return_prefix    = '';
    my $method_suffix    = '';

    if ( $return_type ne 'void' ) {
        $return_prefix = "return ($return_type)";
        if ( $return_type !~ /\*/ ) {    # PMC* and STRING* don't need a special suffix
            $method_suffix = "_ret" . lc substr $return_type, 0, 1;
            $method_suffix =~ s/_retu/_reti/;    #change UINTVAl type to reti
        }
    }

    my $null_return = '';
    $null_return = "return ($return_type) NULL;" if ( $return_type_char =~ /P|I|S|V/ );
    $null_return = 'return (FLOATVAL) 0;'        if ( $return_type_char =~ /N/ );
    $null_return = 'return;'                     if ( $return_type_char =~ /v/ );

    return ( $return_prefix, $method_suffix, $args, $sig, $return_type_char, $null_return );
}

1;

# Local Variables:
#   mode: cperl
#   cperl-indent-level: 4
#   fill-column: 100
# End:
# vim: expandtab shiftwidth=4:



syntax highlighted by Code2HTML, v. 0.9.1