Skip to content

Commit

Permalink
Start to get BEGIN more functional again. This should make it at leas…
Browse files Browse the repository at this point in the history
…t a bit more functional than alpha's one; it does run during the compile (like alpha) and will get run at the start of pre-compiled modules loading too (but has stuff to prevent dupe runs in parse + load). Notably, it also handles keeping computed values around, so my $x = BEGIN { 42 } also works.
  • Loading branch information
jnthn committed Mar 20, 2010
1 parent 6c8737c commit 7ccf148
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 5 deletions.
33 changes: 28 additions & 5 deletions src/Perl6/Actions.pm
Expand Up @@ -3,13 +3,15 @@ class Perl6::Actions is HLL::Actions;
our @BLOCK;
our @PACKAGE;
our $TRUE;
our %BEGINDONE;

INIT {
# initialize @BLOCK and @PACKAGE
our @BLOCK := Q:PIR { %r = new ['ResizablePMCArray'] };
our @PACKAGE := Q:PIR { %r = new ['ResizablePMCArray'] };
our @BLOCK := Q:PIR { %r = root_new ['parrot';'ResizablePMCArray'] };
our @PACKAGE := Q:PIR { %r = root_new ['parrot';'ResizablePMCArray'] };
@PACKAGE.unshift(Perl6::Compiler::Module.new());
our $TRUE := PAST::Var.new( :name('true'), :scope('register') );
our %BEGINDONE := Q:PIR { %r = root_new ['parrot';'Hash'] };
# Tell PAST::Var how to encode Perl6Str and Str values
my %valflags :=
Expand Down Expand Up @@ -463,9 +465,30 @@ method statement_control:sym<CONTROL>($/) {
make PAST::Stmts.new(:node($/));
}

# XXX BEGIN isn't correct here, but I'm adding it along with this
# note so that everyone else knows it's wrong too. :-)
method statement_prefix:sym<BEGIN>($/) { add_phaser($/, 'BEGIN'); }
method statement_prefix:sym<BEGIN>($/) {
# BEGIN is kinda tricky. We actually need to run the code in it with
# immediate effect, and then have the BEGIN block evaluate to what
# was produced at runtime. But if we're in a pre-compiled module, we
# need to run the lot. Thus we keep a "already computed BEGIN values"
# hash and don't re-run if the value is in that. Of course, we still
# don't handle looking at things in outer lexical scopes here.
our %BEGINDONE;
our $?RAKUDO_HLL;
my $past := $<blorst>.ast;
$past.hll($?RAKUDO_HLL);
my $compiled := PAST::Compiler.compile($past);
my $begin_id := $past.unique('BEGINDONE_');
%BEGINDONE{$begin_id} := $compiled();
@BLOCK[0].loadinit.push(PAST::Op.new(
:pasttype('call'), :name('!begin_unless_begun'),
$begin_id, $past
));
make PAST::Var.new( :scope('keyed'),
PAST::Var.new( :name('%BEGINDONE'), :namespace(pir::split('::', 'Perl6::Actions')), :scope('package') ),
PAST::Val.new( :value($begin_id) )
);
}

method statement_prefix:sym<CHECK>($/) { add_phaser($/, 'CHECK'); }
method statement_prefix:sym<INIT>($/) { add_phaser($/, 'INIT'); }
method statement_prefix:sym<END>($/) { add_phaser($/, 'END'); }
Expand Down
3 changes: 3 additions & 0 deletions src/Perl6/Compiler.pir
Expand Up @@ -174,6 +174,9 @@ Perl6::Compiler - Perl6 compiler

.sub 'main' :main
.param pmc args_str
# Fire any of the setting's INIT phasers before we enter the runloop, so
# e.g. $*OUT is available to the actual code's BEGIN blocks.
'!fire_phasers'('INIT')
$P0 = compreg 'perl6'
$P1 = $P0.'command_line'(args_str, 'encoding'=>'utf8', 'transcode'=>'ascii iso-8859-1')
'!fire_phasers'('END')
Expand Down
20 changes: 20 additions & 0 deletions src/glue/phasers.pir
Expand Up @@ -71,6 +71,26 @@ and firing them if they haven't been fired yet.
fire_done:
.end
=item !begin_unless_begun(id, block)
Runs a BEGIN block, unless it was already run during the parse, in which case
we don't bother. If we do have to run it, we put in place the computed value.

=cut

.sub '!begin_unless_begun'
.param string id
.param pmc block
$P0 = get_hll_global ['Perl6';'Actions'], '%BEGINDONE'
$P1 = $P0[id]
unless null $P1 goto begun
$P1 = block()
$P0[id] = $P1
begun:
.return ($P1)
.end

=back

=cut
Expand Down

0 comments on commit 7ccf148

Please sign in to comment.