Navigation Menu

Skip to content

Commit

Permalink
Extensive re-working of the way we generate signatures in actions.pm.…
Browse files Browse the repository at this point in the history
… Now we build an object representing the signature at compile time, and then use a method on it to do the code generation. This neatens up actions.pm a little, but also means it'll be easier to change signature building later (since only one method will need to change, in theory).
  • Loading branch information
jnthn committed Oct 6, 2009
1 parent f845ccf commit 41bc84f
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 123 deletions.
6 changes: 6 additions & 0 deletions build/Makefile.in
Expand Up @@ -59,6 +59,7 @@ DYNOPS = \
SOURCES = perl6.pir \
src/gen_grammar.pir \
src/gen_actions.pir \
src/gen_signature_pm.pir \
src/gen_builtins.pir \
src/gen_metaop.pir \
src/gen_junction.pir \
Expand All @@ -70,6 +71,7 @@ SOURCES = perl6.pir \
src/parrot/P6Invocation.pir \
src/parrot/P6role.pir \
src/parrot/misc.pir \
src/parrot/signature.pir \
src/parrot/state.pir \
src/gen_uprop.pir \
$(DYNEXT_TARGET)
Expand Down Expand Up @@ -248,6 +250,10 @@ src/gen_actions.pir: $(PARROT) $(NQP_PBC) src/parser/actions.pm
$(PARROT) $(PARROT_ARGS) $(NQP_PBC) --output=src/gen_actions.pir \
--encoding=fixed_8 --target=pir src/parser/actions.pm

src/gen_signature_pm.pir: $(PARROT) $(NQP_PBC) src/parser/signature.pm
$(PARROT) $(PARROT_ARGS) $(NQP_PBC) --output=src/gen_signature_pm.pir \
--encoding=fixed_8 --target=pir src/parser/signature.pm

src/gen_builtins.pir: build/gen_builtins_pir.pl
$(PERL) build/gen_builtins_pir.pl $(BUILTINS_PIR) > src/gen_builtins.pir

Expand Down
7 changes: 5 additions & 2 deletions perl6.pir
Expand Up @@ -61,6 +61,7 @@ Creates the Perl 6 compiler by subclassing a C<PCT::HLLCompiler> object.
.local pmc p6meta, perl6
p6meta = get_hll_global ['Perl6Object'], '$!P6META'
perl6 = p6meta.'new_class'('Perl6::Compiler', 'parent'=>'PCT::HLLCompiler')
p6meta.'new_class'('Perl6::Compiler::Signature', 'attr'=>'$!entries')
load_bytecode 'config.pbc'
Expand Down Expand Up @@ -168,6 +169,7 @@ USAGE
.include 'src/parser/quote_expression.pir'
.include 'src/gen_setting.pir'
.include 'src/gen_actions.pir'
.include 'src/gen_signature_pm.pir'
.include 'src/gen_metaop.pir'
.include 'src/gen_junction.pir'
.include 'src/gen_whatever.pir'
Expand Down Expand Up @@ -210,9 +212,9 @@ and report exceptions.
.param pmc adverbs :slurpy :named

$P0 = get_root_global ['parrot';'PCT';'HLLCompiler'], 'eval'
push_eh trap_errors
#push_eh trap_errors
$P0 = $P0(self, code, args :flat, adverbs :flat :named)
pop_eh
#pop_eh
.return ($P0)

trap_errors:
Expand Down Expand Up @@ -475,6 +477,7 @@ Currently this does the equivalent of EXPORTALL on the core namespaces.
.include 'src/parrot/P6role.pir'
.include 'src/parrot/Protoobject.pir'
.include 'src/parrot/misc.pir'
.include 'src/parrot/signature.pir'
.include 'src/parrot/state.pir'
.include 'src/gen_uprop.pir'

Expand Down
38 changes: 3 additions & 35 deletions src/classes/Signature.pir
Expand Up @@ -62,9 +62,11 @@ the Signature.
attr['multi_invocant'] = 1
have_mi:
# Work out any role type that the sigil implies. (Skip for slurpy, though.)
# Work out any role type that the sigil implies. (Skip for slurpy and invocant, though.)
$I0 = attr["slurpy"]
if $I0 goto sigil_done
$I0 = attr["invocant"]
if $I0 goto sigil_done
.local pmc role_type
.local string sigil
sigil = substr varname, 0, 1
Expand Down Expand Up @@ -158,19 +160,6 @@ the Signature.
.end
=item !set_default_param_type
Sets the default parameter type if none is supplied (since it differs for
blocks and routines).
=cut
.sub '!set_default_param_type' :method
.param pmc type
setattribute self, '$!default_type', type
.end
=item !add_implicit_self
Ensures that if there is no explicit invocant, we add one.
Expand Down Expand Up @@ -202,27 +191,6 @@ Ensures that if there is no explicit invocant, we add one.
.end
=item !make_parameters_rw
Makes all parameters have readtype rw (used to implement e.g. <->).
=cut
.sub '!make_parameters_rw' :method
.local pmc params, it, param
params = self.'params'()
it = iter params
it_loop:
unless it goto it_loop_end
param = shift it
$P0 = param['readtype']
unless null $P0 goto it_loop
param['readtype'] = 'rw'
goto it_loop
it_loop_end:
.end
=item params
Get the array of parameter describing hashes.
Expand Down
22 changes: 22 additions & 0 deletions src/parrot/signature.pir
@@ -0,0 +1,22 @@
# Copyright (C) 2007-2009, The Perl Foundation.

=head1 NAME

signature.pir - a plug-in to the PAST::Compiler for signatures

=head1 DESCRIPTION

This adds another multi-variant so when we see a Perl6::Compiler::Signature
in the PAST tree, we know what to do with it. This prevents us from having
to make sure we emit code to build the signature.

=cut

.include "interpinfo.pasm"
.namespace [ 'PAST';'Compiler' ]
.sub 'as_post' :method :multi(_, ['Perl6';'Compiler';'Signature'])
.param pmc node
.param pmc options :slurpy :named
node = node.'ast'()
.tailcall self.'as_post'(node, options :flat :named)
.end
127 changes: 41 additions & 86 deletions src/parser/actions.pm
Expand Up @@ -345,19 +345,12 @@ method for_statement($/) {
method pblock($/) {
my $block := $<block>.ast;
## Add a call to !SIGNATURE_BIND to fixup params and do typechecks.
if $block<signature> {
if defined($block<signature>) {
$block[0].push(
PAST::Op.new( :pasttype('call'), :name('!SIGNATURE_BIND') )
);
if $<lambda>[0] eq '<->' {
$block.loadinit().push(PAST::Op.new(
:pasttype('callmethod'),
:name('!make_parameters_rw'),
PAST::Var.new(
:name('signature'),
:scope('register')
)
));
block_signature($block).set_rw_by_default();
}
}
## If block has no statements, need to return an undef (so we don't
Expand Down Expand Up @@ -807,8 +800,7 @@ method routine_def($/) {
$block.name( $name );
}
$block.control(return_handler_past());
block_signature($block);
$block<default_param_type_node>.name('Any');
block_signature($block).set_default_parameter_type('Any');

if $<trait> {
my $loadinit := $block.loadinit();
Expand Down Expand Up @@ -838,8 +830,7 @@ method method_def($/) {
}

$block.control(return_handler_past());
block_signature($block);
$block<default_param_type_node>.name('Any');
block_signature($block).set_default_parameter_type('Any');

# Add lexical 'self' and a slot for the candidate dispatcher list.
$block[0].unshift(
Expand All @@ -858,22 +849,11 @@ method method_def($/) {
}
if $need_slurpy_hash && !package_has_trait('hidden') {
$block[0].push(PAST::Var.new( :name('%_'), :scope('parameter'), :named(1), :slurpy(1) ));
$block.loadinit().push(PAST::Op.new(
:pasttype('callmethod'),
:name('!add_param'),
PAST::Var.new( :name('signature'), :scope('register') ),
PAST::Val.new( :value('%_') ),
PAST::Val.new( :value(1), :named('named') ),
PAST::Val.new( :value(1), :named('slurpy') )
));
block_signature($block).add_parameter( :var_name('%_'), :names(1), :slurpy(1) );
}

# Ensure there's an invocant in the signature.
$block.loadinit().push(PAST::Op.new(
:pasttype('callmethod'),
:name('!add_implicit_self'),
PAST::Var.new( :name('signature'), :scope('register') )
));
block_signature($block).add_invocant();

# Handle traits.
if $<trait> {
Expand Down Expand Up @@ -1020,8 +1000,7 @@ method signature($/, $key) {
my $block := @?BLOCK.shift();
my $sigpast := $block[0];
my $loadinit := $block.loadinit();

block_signature($block);
my $signature := block_signature($block);

## loop through parameters of signature
my $arity := $<parameter> ?? +@($<parameter>) !! 0;
Expand All @@ -1032,44 +1011,26 @@ method signature($/, $key) {
my $var := $<parameter>[$i].ast;
my $name := $var.name();

## Emit code for type bindings.
if $var<type_binding> {
$sigpast.push( $var<type_binding> );
}

## add parameter to the signature object
my $sigparam := make_sigparam( $var );

## add any typechecks
my $type := $var<type>;
if +@($type) > 0 {
$type.named('type');
$sigparam.push($type);
}

## Compute read type.
my $readtype := trait_readtype( $var<traitlist> );
if $readtype eq 'CONFLICT' {
$<parameter>[$i].panic(
"Can use only one of readonly, rw, and copy on "
~ $name ~ " parameter"
);
}
if $readtype {
$sigparam.push(PAST::Val.new(:value($readtype),:named('readtype')));
}

## add traits (we're not using this yet.)
## XXX review this
my $trait := $var<trait>;
if $trait {
$trait.named('trait');
$sigparam.push($trait);
}

## if it's an invocant, flag it as such and make the var be a
## lexical that has self register bound to it
my $invocant := 0;
if $<param_sep>[$i][0] eq ':' {
if $i == 0 {
$sigparam.push(PAST::Val.new( :value(1), :named('invocant')));
$invocant := 1;
$var.scope('lexical');
$var.isdecl(1);
$var.viviself(
Expand All @@ -1082,15 +1043,23 @@ method signature($/, $key) {
}

## handle end of multi-invocant sequence
if ($multi_inv_suppress) {
$sigparam.push(PAST::Val.new(:value(0),:named('multi_invocant')));
}
if $<param_sep>[$i][0] eq ';;' { $multi_inv_suppress := 1; }

## add var node to block
$sigpast.push( $var );

$loadinit.push($sigparam);
## add entry to signature object
$signature.add_parameter(
:var_name( $var.name() ),
:optional( $var.viviself() ?? 1 !! 0 ),
:slurpy( $var.slurpy() ),
:names( $var.named() eq "" ?? list() !! list($var.named()) ),
:readtype( $readtype ),
:invocant( $invocant ),
:multi_invocant( $multi_inv_suppress ?? 0 !! 1 ),
:types( $var<type> )
);

$i++;
}

Expand Down Expand Up @@ -2112,8 +2081,8 @@ method variable($/, $key) {
$blockinit[$i] := $param;

## add to block's signature
block_signature($?BLOCK);
$?BLOCK.loadinit().push( make_sigparam( $param ) );
my $signature := block_signature($?BLOCK);
add_to_signature_from_past_var($signature, $param);
}
## use twigil-less form afterwards
$twigil := '';
Expand Down Expand Up @@ -2156,8 +2125,8 @@ method variable($/, $key) {
:scope('parameter'),
:slurpy(1) );
if $sigil eq '%' { $param.named(1); }
block_signature($?BLOCK);
$?BLOCK.loadinit().push( make_sigparam( $param ) );
my $signature := block_signature($?BLOCK);
add_to_signature_from_past_var($signature, $param);
$?BLOCK[0].unshift($param);
}
}
Expand Down Expand Up @@ -3018,8 +2987,8 @@ sub declare_implicit_block_vars($block, $tparam) {
:isdecl(1), :viviself($lex) );
if $tparam && $_ eq '$_' {
$var.scope('parameter');
block_signature($block);
$block.loadinit().push( make_sigparam( $var ) );
my $signature := block_signature($block);
add_to_signature_from_past_var($signature, $var);
}
$block[0].push( $var );
$block.symbol($_, :scope('lexical') );
Expand Down Expand Up @@ -3132,19 +3101,14 @@ sub set_package_magical() {


sub block_signature($block) {
unless $block<signature> {
$block<default_param_type_node> := PAST::Var.new(
:scope('package'), :name('Object'), :namespace(list()) );
unless defined($block<signature>) {
$block<signature> := Perl6::Compiler::Signature.new();
$block.loadinit().push($block<signature>);
$block.loadinit().push(
PAST::Op.new( :inline(' .local pmc signature',
' signature = new ["Signature"]',
' setprop block, "$!signature", signature',
' signature."!set_default_param_type"(%0)'),
$block<default_param_type_node>
)
PAST::Op.new( :inline(' setprop block, "$!signature", signature') )
);
$block<signature> := 1;
}
return $block<signature>;
}


Expand Down Expand Up @@ -3288,22 +3252,13 @@ sub return_handler_past() {
}


sub make_sigparam($var) {
my $sigparam :=
PAST::Op.new( :pasttype('callmethod'), :name('!add_param'),
PAST::Var.new( :name('signature'), :scope('register') ),
$var.name()
);
if $var.named() ne "" {
$sigparam.push(PAST::Val.new( :value($var.named()), :named('named') ));
}
if $var.viviself() {
$sigparam.push(PAST::Val.new( :value(1), :named('optional') ));
}
if $var.slurpy() {
$sigparam.push(PAST::Val.new( :value(1), :named('slurpy') ));
}
$sigparam;
sub add_to_signature_from_past_var($signature, $var) {
$signature.add_parameter(
:var_name( $var.name() ),
:optional( $var.viviself() ?? 1 !! 0 ),
:slurpy( $var.slurpy() ),
:names( $var.named() eq "" ?? list() !! list($var.named()) )
);
}


Expand Down

0 comments on commit 41bc84f

Please sign in to comment.