# Do not edit this file - Generated by Perlito5 9.011
{
    package main;
    package Perlito5::Grammar::Use;
    use Perlito5::Grammar::Precedence;
    use Perlito5::Grammar;
    use strict;
    my %Perlito_internal_module = ('strict' => 'Perlito5X::strict', 'warnings' => 'Perlito5X::warnings', 'feature' => 'Perlito5X::feature', 'utf8' => 'Perlito5X::utf8', 'bytes' => 'Perlito5X::bytes', 'encoding' => 'Perlito5X::encoding', 'Carp' => 'Perlito5X::Carp', 'Exporter' => 'Perlito5X::Exporter', 'Data::Dumper' => 'Perlito5X::Dumper');
    sub Perlito5::Grammar::Use::use_decl {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((do {
            my $pos1 = $MATCH->{'to'};
            (do {
                ('use' eq substr($str, $MATCH->{'to'}, 3) && ($MATCH->{'to'} = 3 + $MATCH->{'to'}))
            }) || (do {
                $MATCH->{'to'} = $pos1;
                ('no' eq substr($str, $MATCH->{'to'}, 2) && ($MATCH->{'to'} = 2 + $MATCH->{'to'}))
            })
        }));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Use::version_string {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((do {
            my $pos1 = $MATCH->{'to'};
            (do {
                ((do {
                    my $m2 = Perlito5::Grammar::Number::val_version($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        $MATCH->{'Perlito5::Grammar::Number::val_version'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    $MATCH->{'str'} = $str;
                    $MATCH->{'capture'} = $MATCH->{'Perlito5::Grammar::Number::val_version'}->{'capture'};
                    1
                }))
            }) || (do {
                $MATCH->{'to'} = $pos1;
                ((do {
                    my $m2 = Perlito5::Grammar::Number::term_digit($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        $MATCH->{'Perlito5::Grammar::Number::term_digit'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    $MATCH->{'str'} = $str;
                    my $version = $MATCH->{'Perlito5::Grammar::Number::term_digit'}->{'capture'}->[1]->{'buf'} || $MATCH->{'Perlito5::Grammar::Number::term_digit'}->{'capture'}->[1]->{'int'} || $MATCH->{'Perlito5::Grammar::Number::term_digit'}->{'capture'}->[1]->{'num'};
                    $MATCH->{'capture'} = Perlito5::AST::Buf::->new('buf' => $version);
                    1
                }))
            })
        }));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Use::term_require {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((('require' eq substr($str, $MATCH->{'to'}, 7) && ($MATCH->{'to'} = 7 + $MATCH->{'to'})) && (do {
            my $m2 = Perlito5::Grammar::Space::ws($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                1
            }
            else {
                0
            }
        }) && (do {
            my $pos1 = $MATCH->{'to'};
            (do {
                ((do {
                    my $m2 = version_string($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        $MATCH->{'version_string'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    $MATCH->{'str'} = $str;
                    my $version = $MATCH->{'version_string'}->{'capture'};
                    $version->{'is_version_string'} = 1;
                    $MATCH->{'capture'} = ['term', Perlito5::AST::Apply::->new('code' => 'require', 'namespace' => '', 'arguments' => [$version])];
                    1
                }))
            }) || (do {
                $MATCH->{'to'} = $pos1;
                ((do {
                    my $m2 = Perlito5::Grammar::full_ident($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        $MATCH->{'Perlito5::Grammar::full_ident'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    $MATCH->{'str'} = $str;
                    my $module_name = Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::full_ident'});
                    my $filename = modulename_to_filename($module_name);
                    $MATCH->{'capture'} = ['term', Perlito5::AST::Apply::->new('code' => 'require', 'namespace' => '', 'arguments' => [Perlito5::AST::Buf::->new('buf' => $filename)])];
                    1
                }))
            })
        })));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Use::stmt_use {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = (((do {
            my $m2 = use_decl($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                $MATCH->{'use_decl'} = $m2;
                1
            }
            else {
                0
            }
        }) && (do {
            my $m2 = Perlito5::Grammar::Space::ws($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                1
            }
            else {
                0
            }
        }) && (do {
            my $pos1 = $MATCH->{'to'};
            (do {
                ((do {
                    my $m2 = version_string($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        $MATCH->{'version_string'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    $MATCH->{'str'} = $str;
                    my $version = $MATCH->{'version_string'}->{'capture'}->{'buf'};
                    Perlito5::test_perl_version($version);
                    $MATCH->{'capture'} = Perlito5::AST::Apply::->new('code' => 'undef', 'namespace' => '', 'arguments' => []);
                    1
                }))
            }) || (do {
                $MATCH->{'to'} = $pos1;
                ((do {
                    my $m2 = Perlito5::Grammar::full_ident($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        $MATCH->{'Perlito5::Grammar::full_ident'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    my $m = $MATCH;
                    if (!(('-' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
                        my $m2 = Perlito5::Grammar::ident($str, $MATCH->{'to'});
                        if ($m2) {
                            $MATCH->{'to'} = $m2->{'to'};
                            if (exists($MATCH->{'Perlito5::Grammar::ident'})) {
                                push(@{$MATCH->{'Perlito5::Grammar::ident'}}, $m2)
                            }
                            else {
                                $MATCH->{'Perlito5::Grammar::ident'} = [$m2]
                            }
                            1
                        }
                        else {
                            0
                        }
                    }))) {
                        $MATCH = $m
                    }
                    1
                }) && (do {
                    my $m = $MATCH;
                    if (!((do {
                        my $m2 = Perlito5::Grammar::Space::ws($str, $MATCH->{'to'});
                        if ($m2) {
                            $MATCH->{'to'} = $m2->{'to'};
                            1
                        }
                        else {
                            0
                        }
                    }) && (do {
                        my $m2 = version_string($str, $MATCH->{'to'});
                        if ($m2) {
                            $MATCH->{'to'} = $m2->{'to'};
                            if (exists($MATCH->{'version_string'})) {
                                push(@{$MATCH->{'version_string'}}, $m2)
                            }
                            else {
                                $MATCH->{'version_string'} = [$m2]
                            }
                            1
                        }
                        else {
                            0
                        }
                    }) && (do {
                        my $m2 = Perlito5::Grammar::Space::opt_ws($str, $MATCH->{'to'});
                        if ($m2) {
                            $MATCH->{'to'} = $m2->{'to'};
                            1
                        }
                        else {
                            0
                        }
                    }))) {
                        $MATCH = $m
                    }
                    1
                }) && (do {
                    my $m2 = Perlito5::Grammar::Expression::list_parse($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        $MATCH->{'Perlito5::Grammar::Expression::list_parse'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    $MATCH->{'str'} = $str;
                    my $version = $MATCH->{'version_string'}->[0]->{'capture'}->{'buf'};
                    my $list = Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::Expression::list_parse'});
                    if ($list eq '*undef*') {
                        $list = undef
                    }
                    else {
                        my $m = $MATCH->{'Perlito5::Grammar::Expression::list_parse'};
                        my $list_code = substr($str, $m->{'from'}, $m->{'to'} - $m->{'from'});
                        my @list = eval($list_code);
                        $list = \@list
                    }
                    my $full_ident = Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::full_ident'});
                    $Perlito5::PACKAGES->{$full_ident} = 1;
                    my $use_decl = Perlito5::Match::flat($MATCH->{'use_decl'});
                    if ($use_decl eq 'use' && $full_ident eq 'vars' && $list) {
                        my $code = 'our (' . join(', ', @{$list}) . ')';
                        my $m = Perlito5::Grammar::Statement::statement_parse($code, 0);
                        !$m && die('not a valid variable name: ' . join(${'"'}, @{$list}));
                        $MATCH->{'capture'} = $m->{'capture'}
                    }
                    elsif ($full_ident eq 'strict') {
                        $Perlito5::STRICT = ($use_decl eq 'no' ? 0 : 1);
                        my $ast = Perlito5::AST::Use::->new('code' => $use_decl, 'mod' => $full_ident, 'arguments' => $list);
                        $MATCH->{'capture'} = $ast
                    }
                    elsif ($use_decl eq 'use' && $full_ident eq 'constant' && $list) {
                        my @ast;
                        my $name = shift(@{$list});
                        if (ref($name) eq 'HASH') {
                            for my $key (sort {
                                $a cmp $b
                            } keys(%{$name})) {
                                my $code = 'sub ' . $key . ' () { ' . Perlito5::Dumper::_dumper($name->{$key}) . ' }';
                                my $m = Perlito5::Grammar::Statement::statement_parse($code, 0);
                                !$m && die('not a valid constant: ' . join(${'"'}, @{$list}));
                                push(@ast, $m->{'capture'})
                            }
                        }
                        else {
                            my $code = 'sub ' . $name . ' () { (' . join(', ', map {
                                Perlito5::Dumper::_dumper($_)
                            } @{$list}) . ') }';
                            my $m = Perlito5::Grammar::Statement::statement_parse($code, 0);
                            !$m && die('not a valid constant: ' . join(${'"'}, @{$list}));
                            push(@ast, $m->{'capture'})
                        }
                        $MATCH->{'capture'} = Perlito5::AST::Block::->new('stmts' => \@ast)
                    }
                    else {
                        my $ast = Perlito5::AST::Use::->new('code' => $use_decl, 'mod' => $full_ident, 'arguments' => $list);
                        if ($Perlito5::EMIT_USE) {
                            $MATCH->{'capture'} = $ast
                        }
                        else {
                            $MATCH->{'capture'} = parse_time_eval($ast)
                        }
                    }
                    1
                }))
            }) || (do {
                $MATCH->{'to'} = $pos1;
                (do {
                    $MATCH->{'str'} = $str;
                    die('Syntax error');
                    1
                })
            })
        })));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Use::parse_time_eval {
        my $ast = shift;
        my $module_name = $ast->mod();
        my $use_or_not = $ast->code();
        my $arguments = $ast->{'arguments'};
        my $skip_import = defined($arguments) && @{$arguments} == 0;
        defined($arguments) || ($arguments = []);
        my $comp_units = [];
        if (!$Perlito5::EXPAND_USE) {
            expand_use($comp_units, $ast)
        }
        if ($Perlito5::EXPAND_USE) {
            my $current_module_name = $Perlito5::PKG_NAME;
            my $filename = modulename_to_filename($module_name);
            require($filename);
            if (!$skip_import) {
                if ($use_or_not eq 'use') {
                    if (defined(&{$module_name . '::import'})) {
                        unshift(@{$Perlito5::CALLER}, [$current_module_name]);
                        eval('package ' . $current_module_name . ';' . chr(10) . '$module_name->import(@$arguments); 1') or die(${'@'});
                        shift(@{$Perlito5::CALLER})
                    }
                }
                elsif ($use_or_not eq 'no') {
                    if (defined(&{$module_name . '::unimport'})) {
                        unshift(@{$Perlito5::CALLER}, [$current_module_name]);
                        eval('package ' . $current_module_name . ';' . chr(10) . '$module_name->unimport(@$arguments); 1') or die(${'@'});
                        shift(@{$Perlito5::CALLER})
                    }
                }
            }
        }
        if (@{$comp_units}) {
            return Perlito5::AST::Block::->new('stmts' => $comp_units)
        }
        else {
            return Perlito5::AST::Apply::->new('code' => 'undef', 'namespace' => '', 'arguments' => [])
        }
    }
    sub Perlito5::Grammar::Use::emit_time_eval {
        my $ast = shift;
        if ($ast->mod() eq 'strict') {
            if ($ast->code() eq 'use') {
                strict::->import()
            }
            elsif ($ast->code() eq 'no') {
                strict::->unimport()
            }
        }
    }
    sub Perlito5::Grammar::Use::modulename_to_filename {
        my $s = shift;
        exists($Perlito_internal_module{$s}) && ($s = $Perlito_internal_module{$s});
        $s =~ s!::!/!g;
        return $s . '.pm'
    }
    sub Perlito5::Grammar::Use::filename_lookup {
        my $filename = shift;
        if (exists($INC{$filename})) {
            $INC{$filename} && return 'done';
            die('Compilation failed in require')
        }
        for my $prefix (@INC, '.') {
            my $realfilename = $prefix . '/' . $filename;
            if (-f $realfilename) {
                $INC{$filename} = $realfilename;
                return 'todo'
            }
        }
        die('Can' . chr(39) . 't locate ' . $filename . ' in @INC ' . '(@INC contains ' . join(' ', @INC) . ').')
    }
    sub Perlito5::Grammar::Use::expand_use {
        my $comp_units = shift;
        my $stmt = shift;
        my $module_name = $stmt->mod();
        my $filename = modulename_to_filename($module_name);
        filename_lookup($filename) eq 'done' && return ;
        local $Perlito5::FILE_NAME = $filename;
        local $Perlito5::LINE_NUMBER = 1;
        my $realfilename = $INC{$filename};
        open(FILE, '<', $realfilename) or die('Cannot read ' . $realfilename . ': ' . ${'!'} . chr(10));
        local $/ = undef;
        my $source = <FILE>;
        close(FILE);
        my $m = Perlito5::Grammar::exp_stmts($source, 0);
        $m->{'to'} != length($source) && die('Syntax Error near ', $m->{'to'});
        if ($m->{'to'} != length($source)) {
            my $pos = $m->{'to'} - 10;
            $pos < 0 && ($pos = 0);
            print('* near: ', substr($source, $pos, 20), chr(10));
            print('* filename: ' . $realfilename . chr(10));
            die('Syntax Error near ', $m->{'to'})
        }
        if ($ENV{'PERLITO5DEV'}) {
            push(@{$comp_units}, Perlito5::AST::CompUnit::->new('name' => 'main', 'body' => Perlito5::Match::flat($m)));
            return 
        }
        push(@{$comp_units}, @{add_comp_unit([Perlito5::AST::CompUnit::->new('name' => 'main', 'body' => Perlito5::Match::flat($m))])});
        return 
    }
    sub Perlito5::Grammar::Use::add_comp_unit {
        my $parse = shift;
        my $comp_units = [];
        for my $comp_unit (@{$parse}) {
            if (defined($comp_unit)) {
                if ($comp_unit->isa('Perlito5::AST::Use')) {
                    expand_use($comp_units, $comp_unit)
                }
                elsif ($comp_unit->isa('Perlito5::AST::CompUnit')) {
                    for my $stmt (@{$comp_unit->body()}) {
                        if ($stmt->isa('Perlito5::AST::Use')) {
                            expand_use($comp_units, $stmt)
                        }
                    }
                }
                push(@{$comp_units}, $comp_unit)
            }
        }
        return $comp_units
    }
    sub Perlito5::Grammar::Use::require {
        my $filename = shift;
        filename_lookup($filename) eq 'done' && return ;
        my $result = do($filename);
        if (${'@'}) {
            $INC{$filename} = undef;
            die(${'@'})
        }
        elsif (!$result) {
            delete($INC{$filename});
            ${'@'} && warn(${'@'});
            die($filename . ' did not return true value')
        }
        else {
            return $result
        }
    }
    sub Perlito5::Grammar::Use::do_file {
        my $filename = shift;
        eval {
            filename_lookup($filename);
            1
        } or do {
            $INC{$filename} = undef;
            ${'@'} = '';
            ${'!'} = 'No such file or directory';
            return 'undef'
        };
        my $realfilename = $INC{$filename};
        open(FILE, '<', $realfilename) or die('Cannot read ' . $realfilename . ': ' . ${'!'} . chr(10));
        local $/ = undef;
        my $source = <FILE>;
        close(FILE);
        return $source
    }
    Perlito5::Grammar::Statement::add_statement('no' => \&stmt_use);
    Perlito5::Grammar::Statement::add_statement('use' => \&stmt_use);
    Perlito5::Grammar::Precedence::add_term('require' => \&term_require);
    1
}
;1
