tagged release 0.6.4
[parrot.git] / languages / jako / lib / Jako / Construct / Expression / Call.pm
blob87299dcb72572b2a5fb7b777b22a4d1d8229a7a7
2 # Call.pm
4 # Copyright (C) 2002-2005, The Perl Foundation.
5 # This program is free software. It is subject to the same license
6 # as the Parrot interpreter.
8 # $Id$
11 use strict;
12 use warnings;
14 package Jako::Construct::Expression::Call;
16 use Carp;
18 use base qw(Jako::Construct::Expression);
20 sub new {
21 my $class = shift;
22 my ( $block, $dest, $ident, @args ) = @_;
24 confess( "Dest (" . ref($block) . ") not Identifer!" )
25 unless UNIVERSAL::isa( $dest, 'Jako::Construct::Expression::Value::Identifier' );
26 confess( "Ident (" . ref($block) . ") not Identifer!" )
27 unless UNIVERSAL::isa( $ident, 'Jako::Construct::Expression::Value::Identifier' );
28 confess( "Block (" . ref($block) . ") not!" )
29 unless UNIVERSAL::isa( $block, 'Jako::Construct::Block' );
31 my $self = bless {
32 BLOCK => $block,
34 DEST => $dest,
35 NAME => $ident,
36 ARGS => [@args],
38 DEBUG => 1,
39 FILE => $ident->file,
40 LINE => $ident->line
41 }, $class;
43 $block->push_content($self);
45 return $self;
48 sub dest { return shift->{DEST}; }
49 sub name { return shift->{NAME}; }
50 sub args { return @{ shift->{ARGS} }; }
53 # compile()
56 sub compile {
57 my $self = shift;
58 my ($compiler) = @_;
60 my $dest_ident = $self->dest;
62 my $dest = $self->dest->value;
63 my $name = $self->name->value;
65 # $self->DEBUG(0, "Searching for symbol '$name'...");
67 my $sym = $self->block->find_symbol($name);
69 unless ($sym) {
71 # $self->block->dump_symbols;
72 $self->SYNTAX_ERROR( "Call to unknown sub '%s'.", $name );
75 my %props = $sym->props;
77 my @args = $self->args;
79 my @formal_args = $sym->args;
81 $self->SYNTAX_ERROR( "Wrong number of arguments (expected %d, got %d) in call to '%s'.",
82 scalar(@formal_args), scalar(@args), $name )
83 unless @formal_args == @args;
85 for ( my $i = 0 ; $i < @args ; $i++ ) {
86 my ( $formal_arg_type, $formal_arg_name ) = @{ $formal_args[$i] };
87 my $actual_arg_type;
89 if ( UNIVERSAL::isa( $args[$i], 'Jako::Construct::Expression::Value::Identifier' ) ) {
90 my $arg_sym = $self->block->find_symbol( $args[$i]->value );
91 $self->SYNTAX_ERROR( "Undefined identifier '%s'.", $args[$i]->value ) unless $arg_sym;
92 $actual_arg_type = $arg_sym->type;
94 else {
95 $actual_arg_type = $args[$i]->type;
98 $self->INTERNAL_ERROR( "Can't determine type of formal argument (%s)!", $formal_arg_name )
99 unless defined $formal_arg_type;
101 $self->INTERNAL_ERROR( "Can't determine type of actual argument (%s)!", ref $args[$i] )
102 unless defined $actual_arg_type;
104 if ( $formal_arg_type->name ne $actual_arg_type->name ) {
105 my $temp = $compiler->temp_reg($formal_arg_type);
106 my $value = $args[$i]->compile($compiler);
107 $compiler->emit(" $temp = $value");
108 $args[$i] = $temp;
110 else {
111 $args[$i] = $args[$i]->compile($compiler);
115 if ( ( $dest_ident->kind eq 'var' ) and ( $dest_ident->scope eq 'global' ) ) {
116 $dest = $dest_ident->compile($compiler);
120 # For built-in subs (ops):
123 if ( exists $props{op} ) {
124 my $op = $props{op};
126 # $self->DEBUG(0, "Calling %s%s...", $name, ($op ? ' (op $op)' : ' as op'));
128 $name = $op->value if defined $op;
129 $name =~ s/(^")|("$)//g; # Delete leading and trailing quotes;
131 $name =~ s/^.*:://; # Delete namespaces from ops
133 $compiler->emit( " $name ", join( ", ", $dest, @args ) );
137 # For regular (user-defined) and NCI (Native Call Interface) subs:
140 else {
142 # $self->DEBUG(0, "Calling '%s' as regular sub (props = %s)...", $name, join(", ", %props));
144 $name =~ s/::/__/g;
146 if ( exists $props{fn} or exists $props{fnlib} ) {
147 $name .= "_THUNK";
150 $compiler->emit( " $dest = _${name}(" . join( ", ", @args ) . ")" );
153 if ( ( $dest_ident->kind eq 'var' ) and ( $dest_ident->scope eq 'global' ) ) {
154 my $pmc_type = $dest_ident->type->imcc_pmc();
155 my $temp_pmc = $compiler->temp_pmc();
157 $compiler->emit(" $temp_pmc = new '$pmc_type'");
158 $compiler->emit(" $temp_pmc = $dest");
160 my $dest_name = $dest_ident->value;
161 $compiler->emit(" global \"$dest_name\" = $temp_pmc");
164 return 1;
168 # sax()
171 sub sax {
172 my $self = shift;
173 my ($handler) = @_;
175 $handler->start_element( { Name => 'assign' } );
176 $self->dest->sax($handler);
178 $handler->start_element( { Name => 'call', Attributes => { name => $self->name->value } } );
179 $_->sax($handler) foreach $self->args;
180 $handler->end_element( { Name => 'call' } );
182 $handler->end_element( { Name => 'assign' } );
187 # Local Variables:
188 # mode: cperl
189 # cperl-indent-level: 4
190 # fill-column: 100
191 # End:
192 # vim: expandtab shiftwidth=4: