ExtUtils-ParseXS

 view release on metacpan or  search on metacpan

lib/ExtUtils/ParseXS/Node.pm  view on Meta::CPAN

                # CPP condition keyword just ends that scope. Our
                # (recursive) caller will handle processing any further
                # branches if it's an elif/else rather than endif

                return 1
            }

            # So it's an 'if'/'ifdef' etc node. Start a new
            # Node::cpp_scope sub-parse to handle that branch and then any
            # other branches of the same conditional.

            while (1) {
                # For each iteration, parse the next branch in a new scope
                my $scope = ExtUtils::ParseXS::Node::cpp_scope->new(
                                                {type => 'if'});
                $scope->parse($pxs)
                    or next;

                # Sub-parsing of that branch should have terminated
                # at an elif/endif line rather than falling off the
                # end of the file
                my $last = $scope->{kids}[-1];
                unless (
                       defined $last
                    && $last->isa(
                            'ExtUtils::ParseXS::Node::global_cpp_line')
                    &&  $last->{is_cond}
                    && !$last->{is_if}
                ) {
                    $pxs->death(  "Error: Unterminated '#$node->{directive}'"
                                . " from line $node->{line_no}")
                }

                # Move the CPP line which terminated the branch from
                # the end of the inner scope to the current scope
                pop @{$scope->{kids}};
                push @{$self->{kids}}, $scope, $last;

                if (grep { ref($_) !~ /::global_cpp_line$/ }
                        @{$scope->{kids}} )
                {
                    # the inner scope has some content, so needs
                    # a '#define XSubPPtmpAAAA 1'-style guard
                    $scope->{guard_name} = $pxs->{cpp_next_tmp_define}++;
                }

                # any more branches to process of current if?
                last if $last->{is_endif};
            } # while 1

            next;
        }

        my $file_scoped_keywords =
         "BOOT|REQUIRE|PROTOTYPES|EXPORT_XSUB_SYMBOLS|FALLBACK"
              . "|VERSIONCHECK|INCLUDE|INCLUDE_COMMAND|SCOPE|TYPEMAP";

        # Die if the next line is indented: all file-scoped things (CPP,
        # keywords, XSUB starts) are supposed to start on column 1
        # (although see the comment below about multiple parse_keywords()
        # iterations sneaking in indented keywords).
        #

        if ($pxs->{line}[0] =~ /^\s/) {
            # Try to customise the error message based around why this
            # line is indented, to better hint to the user what the
            # problem is.

            if ($pxs->{line}[0] =~ /^\s+($file_scoped_keywords)\s*:/) {
                $pxs->death(
                    "Error: file-scoped keywords should not be indented");
            }

            # The text of the error message is based around a common reason
            # for an indented line to appear in file scope: this is due to an
            # XSUB being prematurely truncated by fetch_para(). For example in
            # the code below, the coder wants the foo and bar lines to both be
            # part of the same CODE block. But the XS parser sees the blank
            # line followed by the '#ifdef' on column 1 as terminating the
            # current XSUB. So the bar() line is treated as being in file
            # scope and dies because it is indented.
            #
            #   |int f()
            #   |    CODE:
            #   |        foo();
            #   |
            #   |#ifdef USE_BAR
            #   |        bar();
            #   |#endif

            $pxs->deathHint(
                    "Error: file-scoped directives must not be indented",
                    $self->Q(<<EOF))
    |If this line is supposed to be part of an XSUB rather than being
    |file-scoped, then it is possible that your XSUB has a blank line
    |followed by a line starting at column 1 which is being misinterpreted
    |as the end of the current XSUB.
EOF
        }

        # The SCOPE keyword can appear both in file scope (just before an
        # XSUB) and as an XSUB keyword. This field maintains the state of the
        # former: reset it at the start of processing any file-scoped
        # keywords just before the XSUB (i.e. without any blank lines, e.g.
        #     SCOPE: ENABLE
        #     int
        #     foo(...)
        # These semantics may not be particularly sensible, but they maintain
        # backwards compatibility for now.

        $pxs->{file_SCOPE_enabled} = 0;

        # Process file-scoped keywords
        #
        # This loop repeatedly: skips any blank lines and then calls
        # the relevant Node::FOO::parse() method if it finds any of the
        # file-scoped keywords in the passed pattern.
        #
        # Note: due to the looping within parse_keywords() rather than
        # looping here, only the first keyword in a contiguous block
        # gets the 'start at column 1' check above enforced.



( run in 1.527 second using v1.01-cache-2.11-cpan-71847e10f99 )