# Do not edit this file - Generated by Perlito5 9.011
{
    package main;
    package Perlito5::Grammar::Expression;
    use Perlito5::Grammar::Precedence;
    use Perlito5::Grammar::Bareword;
    use Perlito5::Grammar::Attribute;
    use Perlito5::Grammar::Statement;
    sub Perlito5::Grammar::Expression::expand_list {
        my $param_list = shift;
        if (ref($param_list) eq 'Perlito5::AST::Apply' && $param_list->code() eq 'list:<,>') {
            return [grep {
                defined($_)
            } @{$param_list->arguments()}]
        }
        elsif ($param_list eq '*undef*') {
            return []
        }
        else {
            return [$param_list]
        }
    }
    sub Perlito5::Grammar::Expression::block_or_hash {
        my $o = shift;
        if (defined($o->sig())) {
            return $o
        }
        my $stmts = $o->stmts();
        if (!(defined($stmts)) || scalar(@{$stmts}) == 0) {
            return Perlito5::AST::Apply::->new('code' => 'circumfix:<{ }>', 'namespace' => '', 'arguments' => [])
        }
        if (scalar(@{$stmts}) != 1) {
            return $o
        }
        my $stmt = $stmts->[0];
        if (ref($stmt) eq 'Perlito5::AST::Var') {
            return Perlito5::AST::Apply::->new('code' => 'circumfix:<{ }>', 'namespace' => '', 'arguments' => [$stmt])
        }
        if (ref($stmt) ne 'Perlito5::AST::Apply') {
            return $o
        }
        if ($stmt->code() eq 'infix:<=>>' || $stmt->code() eq 'prefix:<%>' || $stmt->code() eq 'prefix:<@>') {
            return Perlito5::AST::Apply::->new('code' => 'circumfix:<{ }>', 'namespace' => '', 'arguments' => [$stmt])
        }
        if ($stmt->code() ne 'list:<,>') {
            return $o
        }
        return Perlito5::AST::Apply::->new('code' => 'circumfix:<{ }>', 'namespace' => '', 'arguments' => expand_list($stmt))
    }
    sub Perlito5::Grammar::Expression::pop_term {
        my $num_stack = shift;
        my $v = pop(@{$num_stack});
        if (ref($v) eq 'ARRAY') {
            ref($v->[1]) && return $v->[1];
            if ($v->[1] eq 'methcall_no_params') {
                $v = Perlito5::AST::Call::->new('invocant' => undef, 'method' => $v->[2], 'arguments' => []);
                return $v
            }
            if ($v->[1] eq 'funcall_no_params') {
                $v = Perlito5::AST::Apply::->new('code' => $v->[3], 'namespace' => $v->[2], 'arguments' => [], 'bareword' => 1);
                return $v
            }
            if ($v->[1] eq 'methcall') {
                my $param_list = expand_list(($v->[3]));
                $v = Perlito5::AST::Call::->new('invocant' => undef, 'method' => $v->[2], 'arguments' => $param_list);
                return $v
            }
            if ($v->[1] eq 'funcall') {
                my $param_list = expand_list(($v->[4]));
                $v = Perlito5::AST::Apply::->new('code' => $v->[3], 'arguments' => $param_list, 'namespace' => $v->[2]);
                return $v
            }
            if ($v->[1] eq '( )') {
                my $param_list = expand_list($v->[2]);
                $v = Perlito5::AST::Apply::->new('code' => 'circumfix:<( )>', 'arguments' => $param_list, 'namespace' => '');
                return $v
            }
            if ($v->[1] eq '[ ]') {
                my $param_list = expand_list($v->[2]);
                $v = Perlito5::AST::Apply::->new('code' => 'circumfix:<[ ]>', 'arguments' => $param_list, 'namespace' => '');
                return $v
            }
            if ($v->[1] eq 'block') {
                $v = Perlito5::AST::Block::->new('stmts' => $v->[2], 'sig' => $v->[3]);
                $v = block_or_hash($v);
                return $v
            }
            if ($v->[1] eq '.( )') {
                $v = Perlito5::AST::Call::->new('invocant' => undef, 'method' => 'postcircumfix:<( )>', 'arguments' => $v->[2]);
                return $v
            }
            if ($v->[1] eq '.[ ]') {
                $v = Perlito5::AST::Index::->new('obj' => undef, 'index_exp' => $v->[2]);
                return $v
            }
            if ($v->[1] eq '.{ }') {
                $v = Perlito5::AST::Lookup::->new('obj' => undef, 'index_exp' => $v->[2]);
                return $v
            }
            return $v->[1]
        }
        return $v
    }
    sub Perlito5::Grammar::Expression::reduce_postfix {
        my $op = shift;
        my $value = shift;
        my $v = $op;
        if ($v->[1] eq 'methcall_no_params') {
            $v = Perlito5::AST::Call::->new('invocant' => $value, 'method' => $v->[2], 'arguments' => []);
            return $v
        }
        if ($v->[1] eq 'funcall_no_params') {
            die('Bareword found where operator expected')
        }
        if ($v->[1] eq 'methcall') {
            my $param_list = expand_list($v->[3]);
            $v = Perlito5::AST::Call::->new('invocant' => $value, 'method' => $v->[2], 'arguments' => $param_list);
            return $v
        }
        if ($v->[1] eq 'funcall') {
            die('unexpected function call')
        }
        if ($v->[1] eq '( )') {
            my $param_list = expand_list($v->[2]);
            if (ref($value) eq 'Perlito5::AST::Apply' && !(defined($value->arguments()))) {
                $value->{'arguments'} = $param_list;
                return $value
            }
            if (ref($value) eq 'Perlito5::AST::Call' && !(defined($value->arguments()))) {
                $value->{'arguments'} = $param_list;
                return $value
            }
            $v = Perlito5::AST::Call::->new('invocant' => $value, 'method' => 'postcircumfix:<( )>', 'arguments' => $param_list);
            return $v
        }
        if ($v->[1] eq '[ ]') {
            if (ref($value) eq 'Perlito5::AST::Var') {
                $value->{'_real_sigil'} = '@'
            }
            $v = Perlito5::AST::Index::->new('obj' => $value, 'index_exp' => $v->[2]);
            return $v
        }
        if ($v->[1] eq 'block') {
            if (ref($value) eq 'Perlito5::AST::Var') {
                $value->{'_real_sigil'} = '%'
            }
            $v = Perlito5::AST::Lookup::->new('obj' => $value, 'index_exp' => $v->[2]->[0]);
            return $v
        }
        if ($v->[1] eq '.( )') {
            my $param_list = expand_list($v->[2]);
            $v = Perlito5::AST::Call::->new('invocant' => $value, 'method' => 'postcircumfix:<( )>', 'arguments' => $param_list);
            return $v
        }
        if ($v->[1] eq '.[ ]') {
            $v = Perlito5::AST::Call::->new('invocant' => $value, 'method' => 'postcircumfix:<[ ]>', 'arguments' => $v->[2]);
            return $v
        }
        if ($v->[1] eq '.{ }') {
            $v = Perlito5::AST::Call::->new('invocant' => $value, 'method' => 'postcircumfix:<{ }>', 'arguments' => $v->[2]);
            return $v
        }
        push(@{$op}, $value);
        return $op
    }
    my $reduce_to_ast = sub {
        my $op_stack = shift;
        my $num_stack = shift;
        my $last_op = shift(@{$op_stack});
        if ($last_op->[0] eq 'prefix') {
            push(@{$num_stack}, Perlito5::AST::Apply::->new('namespace' => '', 'code' => 'prefix:<' . $last_op->[1] . '>', 'arguments' => [pop_term($num_stack)]))
        }
        elsif ($last_op->[0] eq 'postfix') {
            push(@{$num_stack}, Perlito5::AST::Apply::->new('namespace' => '', 'code' => 'postfix:<' . $last_op->[1] . '>', 'arguments' => [pop_term($num_stack)]))
        }
        elsif ($last_op->[0] eq 'postfix_or_term') {
            push(@{$num_stack}, reduce_postfix($last_op, pop_term($num_stack)))
        }
        elsif (Perlito5::Grammar::Precedence::is_assoc_type('list', $last_op->[1])) {
            my $arg;
            if (scalar(@{$num_stack}) < 2) {
                my $v2 = pop_term($num_stack);
                if (ref($v2) eq 'Perlito5::AST::Apply' && $v2->code() eq ('list:<' . $last_op->[1] . '>')) {
                    push(@{$num_stack}, Perlito5::AST::Apply::->new('namespace' => $v2->namespace(), 'code' => $v2->code(), 'arguments' => [@{$v2->arguments()}]))
                }
                else {
                    push(@{$num_stack}, Perlito5::AST::Apply::->new('namespace' => '', 'code' => 'list:<' . $last_op->[1] . '>', 'arguments' => [$v2]))
                }
                return 
            }
            else {
                my $v2 = pop_term($num_stack);
                $arg = [pop_term($num_stack), $v2]
            }
            if (ref($arg->[0]) eq 'Perlito5::AST::Apply' && $last_op->[0] eq 'infix' && ($arg->[0]->code() eq 'list:<' . $last_op->[1] . '>')) {
                push(@{$num_stack}, Perlito5::AST::Apply::->new('namespace' => '', 'code' => ($arg->[0])->code(), 'arguments' => [@{($arg->[0])->arguments()}, $arg->[1]]));
                return 
            }
            push(@{$num_stack}, Perlito5::AST::Apply::->new('namespace' => '', 'code' => 'list:<' . $last_op->[1] . '>', 'arguments' => $arg))
        }
        elsif (Perlito5::Grammar::Precedence::is_assoc_type('chain', $last_op->[1])) {
            if (scalar(@{$num_stack}) < 2) {
                die('Missing value after operator ' . $last_op->[1])
            }
            my $v2 = pop_term($num_stack);
            my $arg = [pop_term($num_stack), $v2];
            push(@{$num_stack}, Perlito5::AST::Apply::->new('namespace' => '', 'code' => 'infix:<' . $last_op->[1] . '>', 'arguments' => $arg))
        }
        elsif ($last_op->[0] eq 'ternary') {
            if (scalar(@{$num_stack}) < 2) {
                die('Missing value after ternary operator')
            }
            my $v2 = pop_term($num_stack);
            push(@{$num_stack}, Perlito5::AST::Apply::->new('namespace' => '', 'code' => 'ternary:<' . $last_op->[1] . '>', 'arguments' => [pop_term($num_stack), $last_op->[2], $v2]))
        }
        else {
            if (scalar(@{$num_stack}) < 2) {
                die('missing value after operator ' . chr(39) . $last_op->[1] . chr(39))
            }
            my $v2 = pop_term($num_stack);
            push(@{$num_stack}, Perlito5::AST::Apply::->new('namespace' => '', 'code' => 'infix:<' . $last_op->[1] . '>', 'arguments' => [pop_term($num_stack), $v2]))
        }
    };
    sub Perlito5::Grammar::Expression::term_arrow {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((('->' eq substr($str, $MATCH->{'to'}, 2) && ($MATCH->{'to'} = 2 + $MATCH->{'to'})) && (do {
            my $m2 = Perlito5::Grammar::Space::opt_ws($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                1
            }
            else {
                0
            }
        }) && (do {
            my $pos1 = $MATCH->{'to'};
            (do {
                (('(' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
                    my $m2 = paren_parse($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        $MATCH->{'paren_parse'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (')' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
                    $MATCH->{'str'} = $str;
                    $MATCH->{'capture'} = ['postfix_or_term', '.( )', Perlito5::Match::flat($MATCH->{'paren_parse'})];
                    1
                }))
            }) || (do {
                $MATCH->{'to'} = $pos1;
                (('[' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
                    my $m2 = square_parse($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        $MATCH->{'square_parse'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (']' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
                    $MATCH->{'str'} = $str;
                    $MATCH->{'capture'} = ['postfix_or_term', '.[ ]', Perlito5::Match::flat($MATCH->{'square_parse'})];
                    1
                }))
            }) || (do {
                $MATCH->{'to'} = $pos1;
                (('{' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
                    my $m2 = curly_parse($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        $MATCH->{'curly_parse'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    my $pos1 = $MATCH->{'to'};
                    (do {
                        ('}' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'}))
                    }) || (do {
                        $MATCH->{'to'} = $pos1;
                        (do {
                            $MATCH->{'str'} = $str;
                            die('Missing right curly or square bracket');
                            1
                        })
                    })
                }) && (do {
                    $MATCH->{'str'} = $str;
                    $MATCH->{'capture'} = ['postfix_or_term', '.{ }', Perlito5::Match::flat($MATCH->{'curly_parse'})];
                    1
                }))
            }) || (do {
                $MATCH->{'to'} = $pos1;
                (('$' 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'};
                        $MATCH->{'Perlito5::Grammar::ident'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    my $m2 = Perlito5::Grammar::Space::opt_ws($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    my $pos1 = $MATCH->{'to'};
                    (do {
                        (('(' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
                            my $m2 = paren_parse($str, $MATCH->{'to'});
                            if ($m2) {
                                $MATCH->{'to'} = $m2->{'to'};
                                $MATCH->{'paren_parse'} = $m2;
                                1
                            }
                            else {
                                0
                            }
                        }) && (')' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
                            $MATCH->{'str'} = $str;
                            $MATCH->{'capture'} = ['postfix_or_term', 'methcall', Perlito5::AST::Var::->new('sigil' => '$', 'namespace' => '', 'name' => Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::ident'})), Perlito5::Match::flat($MATCH->{'paren_parse'})];
                            1
                        }))
                    }) || (do {
                        $MATCH->{'to'} = $pos1;
                        (do {
                            $MATCH->{'str'} = $str;
                            $MATCH->{'capture'} = ['postfix_or_term', 'methcall_no_params', Perlito5::AST::Var::->new('sigil' => '$', 'namespace' => '', 'name' => Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::ident'}))];
                            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 $m2 = Perlito5::Grammar::Space::opt_ws($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    my $pos1 = $MATCH->{'to'};
                    (do {
                        (('(' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
                            my $m2 = paren_parse($str, $MATCH->{'to'});
                            if ($m2) {
                                $MATCH->{'to'} = $m2->{'to'};
                                $MATCH->{'paren_parse'} = $m2;
                                1
                            }
                            else {
                                0
                            }
                        }) && (')' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
                            $MATCH->{'str'} = $str;
                            $MATCH->{'capture'} = ['postfix_or_term', 'methcall', Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::full_ident'}), Perlito5::Match::flat($MATCH->{'paren_parse'})];
                            1
                        }))
                    }) || (do {
                        $MATCH->{'to'} = $pos1;
                        (do {
                            $MATCH->{'str'} = $str;
                            $MATCH->{'capture'} = ['postfix_or_term', 'methcall_no_params', Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::full_ident'})];
                            1
                        })
                    })
                }))
            })
        })));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Expression::term_ternary {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((('?' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
            my $m2 = ternary5_parse($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                $MATCH->{'ternary5_parse'} = $m2;
                1
            }
            else {
                0
            }
        }) && (':' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
            $MATCH->{'str'} = $str;
            $MATCH->{'capture'} = ['op', '? :', Perlito5::Match::flat($MATCH->{'ternary5_parse'})];
            1
        })));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Expression::term_paren {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((('(' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
            my $m2 = paren_parse($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                $MATCH->{'paren_parse'} = $m2;
                1
            }
            else {
                0
            }
        }) && (')' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
            $MATCH->{'str'} = $str;
            $MATCH->{'capture'} = ['postfix_or_term', '( )', Perlito5::Match::flat($MATCH->{'paren_parse'})];
            1
        })));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Expression::term_square {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((('[' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
            my $m2 = square_parse($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                $MATCH->{'square_parse'} = $m2;
                1
            }
            else {
                0
            }
        }) && (']' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
            $MATCH->{'str'} = $str;
            $MATCH->{'capture'} = ['postfix_or_term', '[ ]', Perlito5::Match::flat($MATCH->{'square_parse'})];
            1
        })));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Expression::term_curly {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((('{' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
            my $m = $MATCH;
            if (!(do {
                my $m2 = Perlito5::Grammar::Space::ws($str, $MATCH->{'to'});
                if ($m2) {
                    $MATCH->{'to'} = $m2->{'to'};
                    1
                }
                else {
                    0
                }
            })) {
                $MATCH = $m
            }
            1
        }) && (do {
            my $pos1 = $MATCH->{'to'};
            (do {
                ((do {
                    my $m2 = Perlito5::Grammar::ident($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        $MATCH->{'Perlito5::Grammar::ident'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    my $m = $MATCH;
                    if (!(do {
                        my $m2 = Perlito5::Grammar::Space::ws($str, $MATCH->{'to'});
                        if ($m2) {
                            $MATCH->{'to'} = $m2->{'to'};
                            1
                        }
                        else {
                            0
                        }
                    })) {
                        $MATCH = $m
                    }
                    1
                }) && ('}' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
                    $MATCH->{'str'} = $str;
                    $MATCH->{'capture'} = ['postfix_or_term', 'block', [Perlito5::AST::Apply::->new('arguments' => [], 'bareword' => 1, 'code' => Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::ident'}), 'namespace' => '')]];
                    1
                }))
            }) || (do {
                $MATCH->{'to'} = $pos1;
                ((do {
                    $MATCH->{'str'} = $str;
                    $MATCH->{'_save_scope'} = [@Perlito5::SCOPE_STMT];
                    @Perlito5::SCOPE_STMT = ();
                    1
                }) && (do {
                    my $m2 = Perlito5::Grammar::exp_stmts($str, $MATCH->{'to'});
                    if ($m2) {
                        $MATCH->{'to'} = $m2->{'to'};
                        $MATCH->{'Perlito5::Grammar::exp_stmts'} = $m2;
                        1
                    }
                    else {
                        0
                    }
                }) && (do {
                    $MATCH->{'str'} = $str;
                    @Perlito5::SCOPE_STMT = @{$MATCH->{'_save_scope'}};
                    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
                        }
                    })) {
                        $MATCH = $m
                    }
                    1
                }) && (do {
                    my $pos1 = $MATCH->{'to'};
                    (do {
                        ('}' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'}))
                    }) || (do {
                        $MATCH->{'to'} = $pos1;
                        (do {
                            $MATCH->{'str'} = $str;
                            die('Missing right curly or square bracket');
                            1
                        })
                    })
                }) && (do {
                    $MATCH->{'str'} = $str;
                    $MATCH->{'capture'} = ['postfix_or_term', 'block', Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::exp_stmts'})];
                    1
                }))
            })
        })));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Expression::declarator {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((do {
            my $pos1 = $MATCH->{'to'};
            (do {
                ('my' eq substr($str, $MATCH->{'to'}, 2) && ($MATCH->{'to'} = 2 + $MATCH->{'to'}))
            }) || (do {
                $MATCH->{'to'} = $pos1;
                ('state' eq substr($str, $MATCH->{'to'}, 5) && ($MATCH->{'to'} = 5 + $MATCH->{'to'}))
            }) || (do {
                $MATCH->{'to'} = $pos1;
                ('our' eq substr($str, $MATCH->{'to'}, 3) && ($MATCH->{'to'} = 3 + $MATCH->{'to'}))
            })
        }));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Expression::term_declarator {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = (((do {
            my $m2 = declarator($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                $MATCH->{'declarator'} = $m2;
                1
            }
            else {
                0
            }
        }) && (do {
            my $pos1 = $MATCH->{'to'};
            (do {
                ((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 = Perlito5::Grammar::Block::named_sub($str, $MATCH->{'to'});
                            if ($m2) {
                                $MATCH->{'to'} = $m2->{'to'};
                                $MATCH->{'Perlito5::Grammar::Block::named_sub'} = $m2;
                                1
                            }
                            else {
                                0
                            }
                        }) && (do {
                            $MATCH->{'str'} = $str;
                            my $sub = $MATCH->{'Perlito5::Grammar::Block::named_sub'}->{'capture'};
                            $sub->{'decl'} = Perlito5::Match::flat($MATCH->{'declarator'});
                            $MATCH->{'capture'} = ['term', $sub];
                            return $MATCH;
                            1
                        }))
                    }) || (do {
                        $MATCH->{'to'} = $pos1;
                        (do {
                            my $m2 = Perlito5::Grammar::opt_type($str, $MATCH->{'to'});
                            if ($m2) {
                                $MATCH->{'to'} = $m2->{'to'};
                                $MATCH->{'Perlito5::Grammar::opt_type'} = $m2;
                                1
                            }
                            else {
                                0
                            }
                        })
                    })
                }))
            }) || (do {
                $MATCH->{'to'} = $pos1;
                1
            })
        }) && (do {
            my $m2 = Perlito5::Grammar::Space::opt_ws($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                1
            }
            else {
                0
            }
        }) && (do {
            my $m2 = Perlito5::Grammar::var_ident($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                $MATCH->{'Perlito5::Grammar::var_ident'} = $m2;
                1
            }
            else {
                0
            }
        }) && (do {
            my $m2 = Perlito5::Grammar::Attribute::opt_attribute($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                $MATCH->{'Perlito5::Grammar::Attribute::opt_attribute'} = $m2;
                1
            }
            else {
                0
            }
        }) && (do {
            $MATCH->{'str'} = $str;
            my $declarator = Perlito5::Match::flat($MATCH->{'declarator'});
            my $type = Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::opt_type'});
            $type && !$Perlito5::PACKAGES->{$type} && die('No such class ' . $type);
            my $var = $MATCH->{'Perlito5::Grammar::var_ident'}->{'capture'};
            $var->{'namespace'} && die('No package name allowed for variable ' . $var->{'sigil'} . $var->{'name'} . ' in "' . $declarator . '"');
            $var->{'_decl'} = $declarator;
            $var->{'_id'} = $Perlito5::ID++;
            $declarator eq 'our' && ($var->{'_namespace'} = $Perlito5::PKG_NAME);
            my $decl = Perlito5::AST::Decl::->new('decl' => $declarator, 'type' => $type, 'var' => $var, 'attributes' => Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::Attribute::opt_attribute'}));
            $MATCH->{'capture'} = ['term', $decl];
            1
        })));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Expression::term_not {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((('not' eq substr($str, $MATCH->{'to'}, 3) && ($MATCH->{'to'} = 3 + $MATCH->{'to'})) && (do {
            my $m2 = Perlito5::Grammar::Space::opt_ws($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                1
            }
            else {
                0
            }
        }) && ('(' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
            my $m2 = paren_parse($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                $MATCH->{'paren_parse'} = $m2;
                1
            }
            else {
                0
            }
        }) && (')' eq substr($str, $MATCH->{'to'}, 1) && ($MATCH->{'to'} = 1 + $MATCH->{'to'})) && (do {
            $MATCH->{'str'} = $str;
            $MATCH->{'capture'} = ['term', Perlito5::AST::Apply::->new('code' => 'prefix:<not>', 'arguments' => expand_list(Perlito5::Match::flat($MATCH->{'paren_parse'})), 'namespace' => '')];
            1
        })));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Expression::term_local {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((('local' eq substr($str, $MATCH->{'to'}, 5) && ($MATCH->{'to'} = 5 + $MATCH->{'to'})) && (do {
            my $m2 = Perlito5::Grammar::Space::opt_ws($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                1
            }
            else {
                0
            }
        }) && (do {
            my $m2 = Perlito5::Grammar::Sigil::term_sigil($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                $MATCH->{'Perlito5::Grammar::Sigil::term_sigil'} = $m2;
                1
            }
            else {
                0
            }
        }) && (do {
            $MATCH->{'str'} = $str;
            my $declarator = 'local';
            my $type = '';
            $MATCH->{'capture'} = Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::Sigil::term_sigil'})->[1];
            $MATCH = Perlito5::Grammar::String::double_quoted_var_with_subscript($MATCH);
            my $var = $MATCH->{'capture'};
            my $look = Perlito5::Grammar::Scope::lookup_variable($var);
            if ($look && ($look->{'_decl'} eq 'my' || $look->{'_decl'} eq 'state')) {
                die('Can' . chr(39) . 't localize lexical variable ' . $var->{'sigil'} . $var->{'name'})
            }
            $var->{'_id'} = $Perlito5::ID++;
            $var->{'_decl'} = $declarator;
            !$var->{'namespace'} && !$var->{'_namespace'} && ($var->{'_namespace'} = $Perlito5::PKG_NAME);
            my $decl = Perlito5::AST::Decl::->new('decl' => $declarator, 'type' => $type, 'var' => $var);
            $MATCH->{'capture'} = ['term', $decl];
            1
        })));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Expression::term_return {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((('return' eq substr($str, $MATCH->{'to'}, 6) && ($MATCH->{'to'} = 6 + $MATCH->{'to'})) && (do {
            my $m2 = Perlito5::Grammar::Space::opt_ws($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                1
            }
            else {
                0
            }
        }) && (do {
            my $m2 = list_parse($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                $MATCH->{'list_parse'} = $m2;
                1
            }
            else {
                0
            }
        }) && (do {
            $MATCH->{'str'} = $str;
            my $args = Perlito5::Match::flat($MATCH->{'list_parse'});
            $MATCH->{'capture'} = ['term', Perlito5::AST::Apply::->new('code' => 'return', 'arguments' => $args eq '*undef*' ? [] : [$args], 'namespace' => '')];
            1
        })));
        $tmp ? $MATCH : 0
    }
    sub Perlito5::Grammar::Expression::term_eval {
        my $str = $_[0];
        my $pos = $_[1];
        my $MATCH = {'str' => $str, 'from' => $pos, 'to' => $pos};
        my $tmp = ((('eval' eq substr($str, $MATCH->{'to'}, 4) && ($MATCH->{'to'} = 4 + $MATCH->{'to'})) && (do {
            my $m2 = Perlito5::Grammar::block($str, $MATCH->{'to'});
            if ($m2) {
                $MATCH->{'to'} = $m2->{'to'};
                $MATCH->{'Perlito5::Grammar::block'} = $m2;
                1
            }
            else {
                0
            }
        }) && (do {
            $MATCH->{'str'} = $str;
            $MATCH->{'capture'} = ['term', Perlito5::AST::Apply::->new('code' => 'eval', 'arguments' => [Perlito5::Match::flat($MATCH->{'Perlito5::Grammar::block'})], 'namespace' => '')];
            1
        })));
        $tmp ? $MATCH : 0
    }
    my $Expr_end_token_chars = [7, 6, 5, 4, 3, 2, 1];
    my $Expr_end_token = {']' => 1, ')' => 1, '}' => 1, ';' => 1, 'if' => 1, 'for' => 1, 'else' => 1, 'when' => 1, 'while' => 1, 'until' => 1, 'elsif' => 1, 'unless' => 1, 'foreach' => 1};
    my $List_end_token = {':' => 1, 'or' => 1, 'and' => 1, 'xor' => 1, %{$Expr_end_token}};
    my $Argument_end_token = {',' => 1, '<' => 1, '>' => 1, '=' => 1, '|' => 1, '^' => 1, '?' => 1, '=>' => 1, 'lt' => 1, 'le' => 1, 'gt' => 1, 'ge' => 1, '<=' => 1, '>=' => 1, '==' => 1, '!=' => 1, 'ne' => 1, 'eq' => 1, '..' => 1, '~~' => 1, '&&' => 1, '||' => 1, '+=' => 1, '-=' => 1, '*=' => 1, '/=' => 1, 'x=' => 1, '|=' => 1, '&=' => 1, '.=' => 1, '^=' => 1, '%=' => 1, '//' => 1, '...' => 1, '<=>' => 1, 'cmp' => 1, '<<=' => 1, '>>=' => 1, '||=' => 1, '&&=' => 1, '//=' => 1, '**=' => 1, %{$List_end_token}};
    sub Perlito5::Grammar::Expression::list_parser {
        my($str, $pos, $end_token) = @_;
        my $expr;
        my $last_pos = $pos;
        my $is_first_token = 1;
        my $lexer_stack = [];
        my $last_token_was_space = 1;
        my $get_token = sub {
            my $last_is_term = $_[0];
            my $v;
            if (scalar(@{$lexer_stack})) {
                $v = pop(@{$lexer_stack});
                if ($is_first_token && ($v->[0] eq 'op') && !(Perlito5::Grammar::Precedence::is_fixity_type('prefix', $v->[1]))) {
                    $v->[0] = 'end'
                }
            }
            else {
                my $m = Perlito5::Grammar::Precedence::op_parse($str, $last_pos, $last_is_term);
                if ($m) {
                    my $spc = Perlito5::Grammar::Space::ws($str, $m->{'to'});
                    if ($spc) {
                        $m->{'to'} = $spc->{'to'}
                    }
                }
                if (!$m) {
                    return ['end', '*end*']
                }
                $v = $m->{'capture'};
                if ($is_first_token && ($v->[0] eq 'op') && !(Perlito5::Grammar::Precedence::is_fixity_type('prefix', $v->[1]))) {
                    $v->[0] = 'end'
                }
                if ($v->[0] ne 'end') {
                    $last_pos = $m->{'to'}
                }
            }
            $last_token_was_space = ($v->[0] eq 'space');
            $is_first_token = 0;
            return $v
        };
        my $prec = Perlito5::Grammar::Precedence::->new('get_token' => $get_token, 'reduce' => $reduce_to_ast, 'end_token' => $end_token, 'end_token_chars' => $Expr_end_token_chars);
        my $res = $prec->precedence_parse();
        if (scalar(@{$res}) == 0) {
            return {'str' => $str, 'from' => $pos, 'to' => $last_pos, 'capture' => '*undef*'}
        }
        my $result = pop_term($res);
        return {'str' => $str, 'from' => $pos, 'to' => $last_pos, 'capture' => $result}
    }
    sub Perlito5::Grammar::Expression::argument_parse {
        my($str, $pos) = @_;
        return list_parser($str, $pos, $Argument_end_token)
    }
    sub Perlito5::Grammar::Expression::list_parse {
        my($str, $pos) = @_;
        return list_parser($str, $pos, $List_end_token)
    }
    sub Perlito5::Grammar::Expression::circumfix_parse {
        my($str, $pos, $delimiter) = @_;
        my $expr;
        my $last_pos = $pos;
        my $get_token = sub {
            my $last_is_term = $_[0];
            my $m = Perlito5::Grammar::Precedence::op_parse($str, $last_pos, $last_is_term);
            if ($m) {
                my $spc = Perlito5::Grammar::Space::ws($str, $m->{'to'});
                if ($spc) {
                    $m->{'to'} = $spc->{'to'}
                }
            }
            if (!$m) {
                my $msg = 'Expected closing delimiter: ' . $delimiter;
                ($delimiter eq '}' || $delimiter eq ']') && ($msg = 'Missing right curly or square bracket');
                die($msg . ' near ', $last_pos)
            }
            my $v = $m->{'capture'};
            if ($v->[0] ne 'end') {
                $last_pos = $m->{'to'}
            }
            return $v
        };
        my %delim_token;
        $delim_token{$delimiter} = 1;
        my $prec = Perlito5::Grammar::Precedence::->new('get_token' => $get_token, 'reduce' => $reduce_to_ast, 'end_token' => \%delim_token, 'end_token_chars' => [length($delimiter)]);
        my $res = $prec->precedence_parse();
        $res = pop_term($res);
        if (!(defined($res))) {
            $res = '*undef*'
        }
        return {'str' => $str, 'from' => $pos, 'to' => $last_pos, 'capture' => $res}
    }
    sub Perlito5::Grammar::Expression::ternary5_parse {
        return circumfix_parse(@_, ':')
    }
    sub Perlito5::Grammar::Expression::curly_parse {
        return circumfix_parse(@_, '}')
    }
    sub Perlito5::Grammar::Expression::square_parse {
        return circumfix_parse(@_, ']')
    }
    sub Perlito5::Grammar::Expression::paren_parse {
        return circumfix_parse(@_, ')')
    }
    sub Perlito5::Grammar::Expression::exp_parse {
        my($str, $pos) = @_;
        my $expr;
        my $last_pos = $pos;
        my $lexer_stack = [];
        my $get_token = sub {
            my $last_is_term = $_[0];
            my $v;
            if (scalar(@{$lexer_stack})) {
                $v = pop(@{$lexer_stack})
            }
            else {
                my $m = Perlito5::Grammar::Precedence::op_parse($str, $last_pos, $last_is_term);
                if ($m) {
                    my $spc = Perlito5::Grammar::Space::ws($str, $m->{'to'});
                    if ($spc) {
                        $m->{'to'} = $spc->{'to'}
                    }
                }
                if (!$m) {
                    return ['end', '*end*']
                }
                $v = $m->{'capture'};
                if ($v->[0] ne 'end') {
                    $last_pos = $m->{'to'}
                }
            }
            return $v
        };
        my $prec = Perlito5::Grammar::Precedence::->new('get_token' => $get_token, 'reduce' => $reduce_to_ast, 'end_token' => $Expr_end_token, 'end_token_chars' => $Expr_end_token_chars);
        my $res = $prec->precedence_parse();
        if (scalar(@{$res}) == 0) {
            return 0
        }
        my $result = pop_term($res);
        return {'str' => $str, 'from' => $pos, 'to' => $last_pos, 'capture' => $result}
    }
    Perlito5::Grammar::Precedence::add_term('my' => \&term_declarator);
    Perlito5::Grammar::Precedence::add_term('our' => \&term_declarator);
    Perlito5::Grammar::Precedence::add_term('eval' => \&term_eval);
    Perlito5::Grammar::Precedence::add_term('state' => \&term_declarator);
    Perlito5::Grammar::Precedence::add_term('local' => \&term_local);
    Perlito5::Grammar::Precedence::add_term('return' => \&term_return);
    Perlito5::Grammar::Precedence::add_term('not' => \&term_not);
    1
}
;1
