cvsuser 04/04/28 22:13:32
Modified: . MANIFEST
Added: languages/perl6/P6C/IMCC Sub.pm
Log:
The first step toward moving P6C::IMCC::Sub into its own file - add the
file.
Revision Changes Path
1.635 +1 -0 parrot/MANIFEST
Index: MANIFEST
===================================================================
RCS file: /cvs/public/parrot/MANIFEST,v
retrieving revision 1.634
retrieving revision 1.635
diff -u -w -r1.634 -r1.635
--- MANIFEST 24 Apr 2004 12:04:39 -0000 1.634
+++ MANIFEST 29 Apr 2004 05:13:29 -0000 1.635
@@ -2099,6 +2099,7 @@
languages/perl6/P6C/IMCC/hype.pm [perl6]
languages/perl6/P6C/IMCC/prefix.pm [perl6]
languages/perl6/P6C/IMCC/rule.pm [perl6]
+languages/perl6/P6C/IMCC/Sub.pm [perl6]
languages/perl6/P6C/Nodes.pm [perl6]
languages/perl6/P6C/Parser.pm [perl6]
languages/perl6/P6C/Rules.pm [perl6]
1.1 parrot/languages/perl6/P6C/IMCC/Sub.pm
Index: Sub.pm
===================================================================
=head2 P6C::IMCC::Sub
Stores IMCC code for a subroutine.
XXX: the fact that e.g. C<P6C::prefix> relies on this for argument
information is just wrong. This information should be retrieved from
the parse tree structures instead.
=over
=item B<< $sub->{code} >>
The code (not including C<.local> definitions, etc). Should be
appended to like C<< $func->{code} .= $thing >>.
=item B<emit($sub)>
Emit a complete function body, minus the C<.sub> directive.
=back
=cut
package P6C::IMCC::Sub;
use Class::Struct 'P6C::IMCC::Sub'
=> { scopes => '@', # scope stack
params => '$', # parameters passed
rettype => '$', # return type (scalar, array, tuple)
};
# {scopelevel} # current scope number
# {oldscopes} # other closed scopes in this sub.
use P6C::Util qw(diag error);
require P6C::IMCC;
sub _find {
my ($x, $thing) = @_;
for (@{$x->scopes}) {
if (exists $_->{$thing}) {
return $_->{$thing};
}
}
return undef;
}
sub localvar {
my ($x, $var) = @_;
my $res = $x->_find($var);
if ($res) {
return $res->[0];
}
return undef;
}
sub add_localvar {
my ($x, $var, $type, $init) = @_;
$x->{scopelevel} ||= 0;
my $scopename = P6C::IMCC::mangled_name($var).$x->{scopelevel};
if ($x->scopes->[0]{$var}) {
diag "Redeclaring lexical $var in $P6C::IMCC::curfunc";
}
$x->scopes->[0]{$var} ||= [$scopename, $type, $init];
return $scopename;
}
sub label {
my $x = shift;
my %o = @_;
$o{name} = '' unless defined $o{name};
$o{type} = '' unless defined $o{type};
my $mangled = "label:$o{name}:$o{type}";
return $x->_find($mangled);
}
sub add_label {
# XXX: note trickery here -- if the label has both a type and a
# name, we just add ":type" and "name:type", not "name". This is
# deliberate -- the label statement itself will cause the "name"
# to be emitted.
my $x = shift;
my %o = @_;
my $lab = P6C::IMCC::genlabel;
if ($o{type}) {
$x->scopes->[0]{"label::$o{type}"} = $lab;
if ($o{name}) {
$x->scopes->[0]{"label:$o{name}:$o{type}"} = $lab;
}
} elsif ($o{name}) {
$x->scopes->[0]{"label:$o{name}:"} = $lab;
} else {
die "internal error -- add_label() with neither type nor name";
}
return $lab;
}
sub topic {
my $x = shift;
return $x->_find('topic:');
}
sub set_topic {
my ($x, $topic) = @_;
$x->scopes->[0]{"topic:"} = $topic;
}
sub push_scope {
my $x = shift;
$x->{scopelevel}++;
unshift @{$x->scopes}, { };
}
sub maybe_set_params {
# XXX: hack to keep inner closures from mucking with our params.
my ($x, $signature) = @_;
unless ($x->{hasparam}) {
$x->params($signature);
$x->{hasparam} = 1;
}
}
sub set_return {
my ($x, $r) = @_;
$x->rettype($r);
}
sub pop_scope {
my $x = shift;
push @{$x->{oldscopes}}, shift @{$x->scopes};
}
# P6C::IMCC::Sub::emit - print out the code for a subroutine body
#
# 1. Grab the parameters from the passed-in registers
# 2. Implement the subroutine code
# 3. call the continuation to "return"
#
# FIXME: Non-PMC arguments/params are not yet handled.
# FIXME: Pass-by-value only implemented
sub emit {
my ($x, $prototyped) = @_;
my $params = $x->params;
# $positional_args is a PerlArray containing all of the non-named
# args (including all positional args and the slurpy array, if
# any) in the unprototyped case. In the prototyped case, the
# required and positional args are passed directly.
my $positional_args;
if (! $prototyped || $params->slurpy_array) {
$positional_args = P6C::IMCC::gensym("positionals");
}
my $known_named_args = P6C::IMCC::gensym("known_named");
my $named_args = P6C::IMCC::gensym("unknown_named");
print "\t.param PerlHash $named_args # named args\n"
unless $params->{no_named};
foreach my $param (@{ $params->positional }, @{ $params->optional }) {
my ($ptype, $pvar) = ($param->type, $param->var);
$ptype = P6C::IMCC::paramtype($ptype);
my $pname = $pvar->name;
my $pname_mangled = P6C::IMCC::mangled_name($pname);
print "\t.param $ptype $pname_mangled # Positional param $pname\n";
}
# The slurpy array, if any, is passed as an array PMC
if ($params->slurpy_array) {
my $slurpy = $params->slurpy_array->var->name;
my $slurpy_name = P6C::IMCC::mangled_name($slurpy);
print "\t.param pmc $slurpy_name # slurpy array $slurpy_name\n";
}
# Create local variables for all the named arguments
foreach my $param (@{ $params->required_named },
@{ $params->optional_named })
{
my ($ptype, $pvar) = ($param->type, $param->var);
$ptype = P6C::IMCC::paramtype($ptype);
my $pname = $pvar->name;
my $pname_mangled = P6C::IMCC::mangled_name($pname);
print "\t.sym $ptype $pname_mangled # Named param $pname\n";
}
my $tmp = P6C::IMCC::gentmp('int');
my $got_params = P6C::IMCC::genlabel("got_params");
unless ($params->{no_named}) {
print "# Argument handling\n";
print " if I0 goto $got_params\n";
my $min_count = 2;
foreach my $param (@{ $params->positional }) {
my ($ptype, $pvar) = ($param->type, $param->var);
$ptype = P6C::IMCC::paramtype($ptype);
my $pname = $pvar->name;
my $pname_base = substr($pname, 1);
my $pname_mangled = P6C::IMCC::mangled_name($pname);
my $label = P6C::IMCC::genlabel("skip_param_$pname_mangled");
print " if I1 >= $min_count goto $label\n";
print " exists $tmp, $named_args\[\"$pname_base\"]\n";
print " unless $tmp goto $label\n";
print " $pname_mangled = $named_args\[\"$pname_base\"]\n";
print " delete $named_args\[\"$pname_base\"]\n";
print "$label:\n";
$min_count++;
}
print "$got_params:\n";
}
# Grab out the named params
foreach my $param (@{ $params->required_named },
@{ $params->optional_named })
{
my ($ptype, $pvar) = ($param->type, $param->var);
$ptype = P6C::IMCC::paramtype($ptype);
my $pname = $pvar->name;
my $pname_base = substr($pname, 1);
my $pname_mangled = P6C::IMCC::mangled_name($pname);
print " $pname_mangled = $named_args\[\"$pname_base\"\]\n";
}
print "# Named locals:\n";
for (@{$x->scopes}, @{$x->{oldscopes}}) {
for my $v (values %$_) {
next unless ref($v) eq 'ARRAY';
my ($n, $t) = @$v;
$t = P6C::IMCC::paramtype($t);
print "\t.local $t $n\n";
}
}
# Maybe constructors for locals:
for (@{$x->scopes}, @{$x->{oldscopes}}) {
for my $v (values %$_) {
next unless ref($v) eq 'ARRAY';
my ($n, $t, $init) = @$v;
print "\t$n = new $t\n"
if P6C::IMCC::regtype($t) eq 'P' && $init;
}
}
print $x->{code};
print <<END;
.pcc_begin_return # fallback
.pcc_end_return
END
# print <<END;
# restoreall
# invoke $saved_continuation
# end
#END
}
1;