Perlito5
view release on metacpan or search on metacpan
src/Perlito5/Grammar/Block.pm view on Meta::CPAN
package Perlito5::Grammar::Block;
use Perlito5::Grammar::Expression;
use Perlito5::Grammar::Scope;
use Perlito5::AST::BeginScratchpad;
use Perlito5::AST::Captures;
use Perlito5::FoldConstant;
use strict;
our %Named_block = (
BEGIN => 1,
UNITCHECK => 1,
CHECK => 1,
INIT => 1,
END => 1,
AUTOLOAD => 1,
DESTROY => 1,
);
sub block {
my $str = $_[0];
my $pos = $_[1];
my $m = Perlito5::Grammar::Space::opt_ws($str, $pos);
$pos = $m->{to};
if ( $str->[$pos] ne '{' ) {
return
}
$pos++;
# when parsing a command like "for my $x ..." register the loop variable
# before entering the block, so that it can be seen immediately
Perlito5::Grammar::Scope::check_variable_declarations();
Perlito5::Grammar::Scope::create_new_compile_time_scope();
$m = Perlito5::Grammar::exp_stmts($str, $pos);
if (!$m) {
Perlito5::Compiler::error "syntax error";
}
$pos = $m->{to};
my $capture = Perlito5::Match::flat($m);
$m = Perlito5::Grammar::Space::opt_ws($str, $pos);
$pos = $m->{to};
if ( $str->[$pos] ne '}' ) {
Perlito5::Compiler::error "syntax error";
}
$m->{to} = $pos + 1;
$m->{capture} = Perlito5::AST::Block->new( stmts => $capture, sig => undef );
# end of lexical scope
Perlito5::Grammar::Scope::end_compile_time_scope();
return $m;
}
sub closure_block {
my $str = $_[0];
my $pos = $_[1];
my $m = Perlito5::Grammar::Space::opt_ws($str, $pos);
$pos = $m->{to};
if ( $str->[$pos] ne '{' ) {
return
}
$pos++;
# when parsing a command like "for my $x ..." register the loop variable
# before entering the block, so that it can be seen immediately
Perlito5::Grammar::Scope::check_variable_declarations();
Perlito5::Grammar::Scope::create_new_compile_time_scope();
local $Perlito5::CLOSURE_SCOPE = $#Perlito5::BASE_SCOPE; # this is the only diff from plain <block>
$m = Perlito5::Grammar::exp_stmts($str, $pos);
if (!$m) {
Perlito5::Compiler::error "syntax error";
}
src/Perlito5/Grammar/Block.pm view on Meta::CPAN
# anonymous blocks can have a 'continue' block
$m = Perlito5::Grammar::opt_continue_block( $str, $p );
$p = $m->{to};
my $continue = Perlito5::Match::flat($m);
my $v = $block;
# TODO - this is not recognized as a statement: { 123 => 4;}
# TODO - this is not recognized as a syntax error: { 123 => 4 }{2}
$v = Perlito5::Grammar::Expression::block_or_hash($v)
if !$continue->{is_continue}
&& !$Perlito5::BLOCK_HAS_SEMICOLON;
$m->{capture} = $v;
if ( $continue->{is_continue} ) {
$m->{capture}{continue} = $continue;
}
return $m;
}
sub ast_nop {
Perlito5::AST::Apply->new(
code => 'nop',
namespace => 'Perlito5',
arguments => []
);
}
sub special_named_block {
my $str = $_[0];
my $pos = $_[1];
my $p = $pos;
my $block_name;
my $m_name = Perlito5::Grammar::ident( $str, $p );
return if !$m_name;
$p = $m_name->{to};
$block_name = Perlito5::Match::flat($m_name);
my $ws = Perlito5::Grammar::Space::opt_ws( $str, $p );
$p = $ws->{to};
my $block_start = $p;
my $m = Perlito5::Grammar::Block::closure_block( $str, $p );
return if !$m;
$p = $m->{to};
my $block = Perlito5::Match::flat($m);
if ($block_name eq 'INIT') {
push @Perlito5::INIT_BLOCK, eval_end_block( $block, 'INIT' );
$m->{capture} = ast_nop();
}
elsif ($block_name eq 'END') {
unshift @Perlito5::END_BLOCK, eval_end_block( $block, 'END' );
$m->{capture} = ast_nop();
}
elsif ($block_name eq 'CHECK') {
unshift @Perlito5::CHECK_BLOCK, eval_end_block( $block, 'CHECK' );
$m->{capture} = ast_nop();
}
elsif ($block_name eq 'UNITCHECK') {
unshift @Perlito5::UNITCHECK_BLOCK, eval_end_block( $block, 'UNITCHECK' );
$m->{capture} = ast_nop();
}
elsif ($block_name eq 'BEGIN') {
# say "BEGIN $block_start ", $m->{to}, "[", substr($str, $block_start, $m->{to} - $block_start), "]";
# local $Perlito5::PKG_NAME = $Perlito5::PKG_NAME; # BUG - this doesn't work
local $Perlito5::PHASE = 'BEGIN';
eval_begin_block( $block );
$m->{capture} = ast_nop();
}
elsif ($block_name eq 'AUTOLOAD' || $block_name eq 'DESTROY') {
my $sub = Perlito5::AST::Sub->new(
'attributes' => [],
'block' => $block,
'name' => $block_name,
'namespace' => $Perlito5::PKG_NAME,
'sig' => undef,
'pos' => Perlito5::Compiler::compiler_pos(),
);
# add named sub to SCOPE
my $full_name = $sub->{namespace} . "::" . $sub->{name};
$Perlito5::PROTO->{$full_name} = undef;
$Perlito5::GLOBAL->{$full_name} = $sub;
# evaluate the sub definition in a BEGIN block
$block = Perlito5::AST::Block->new( stmts => [$sub] );
Perlito5::Grammar::Block::eval_begin_block($block, 'BEGIN');
# runtime effect of subroutine declaration is "undef"
$m->{capture} = ast_nop();
}
else {
$m->{capture} = $block;
$m->{capture}{name} = $block_name;
}
return $m;
}
token named_sub_def {
<Perlito5::Grammar::optional_namespace_before_ident> <Perlito5::Grammar::ident>
<Perlito5::Grammar::Block::prototype_> <.Perlito5::Grammar::Space::opt_ws>
<Perlito5::Grammar::Attribute::opt_attribute> <.Perlito5::Grammar::Space::opt_ws>
[
<Perlito5::Grammar::Block::closure_block>
{
$MATCH->{_tmp} = Perlito5::Match::flat($MATCH->{"Perlito5::Grammar::Block::closure_block"});
}
|
<.Perlito5::Grammar::Statement::statement_parse>
{
Perlito5::Compiler::error 'Illegal declaration of subroutine \'', Perlito5::Match::flat($MATCH->{"Perlito5::Grammar::ident"}), '\''
}
|
{
# subroutine predeclaration - there is no block
$MATCH->{_tmp} = undef;
}
]
{
my $name = Perlito5::Match::flat($MATCH->{"Perlito5::Grammar::ident"});
my $sig = Perlito5::Match::flat($MATCH->{"Perlito5::Grammar::Block::prototype_"});
$sig = undef if $sig eq '*undef*';
( run in 2.603 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )