Skip to content

Commit

Permalink
ParseXS - handle #else and #endif without blank line prefixes
Browse files Browse the repository at this point in the history
This patch makes it possible to omit some of the whitespace around
preprocessor directives. It teaches fetch_para() to understand
that a #else or #endif directive that does not end a #if that
was seen in the current "paragraph" should not be parsed as part
of that paragraph. This means that a conditional block that defines
the same sub under different define conditions need not have extra
whitespace after each sub definition.
  • Loading branch information
demerphq committed Nov 9, 2022
1 parent 589b5f1 commit b263689
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 1 deletion.
1 change: 1 addition & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -3710,6 +3710,7 @@ dist/ExtUtils-ParseXS/t/XSInclude.xsh Test file for ExtUtils::ParseXS tests
dist/ExtUtils-ParseXS/t/XSMore.xs Test file for ExtUtils::ParseXS tests
dist/ExtUtils-ParseXS/t/XSTest.pm Test file for ExtUtils::ParseXS tests
dist/ExtUtils-ParseXS/t/XSTest.xs Test file for ExtUtils::ParseXS tests
dist/ExtUtils-ParseXS/t/XSTightDirectives.xs Test file for ExtUtils::ParseXS tests
dist/ExtUtils-ParseXS/t/XSUsage.pm ExtUtils::ParseXS tests
dist/ExtUtils-ParseXS/t/XSUsage.xs ExtUtils::ParseXS tests
dist/ExtUtils-ParseXS/t/XSWarn.xs ExtUtils::ParseXS tests
Expand Down
37 changes: 37 additions & 0 deletions dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1800,11 +1800,17 @@ sub fetch_para {
$self->_process_module_xs_line($1, $2, $3);
}

# count how many #ifdef levels we see in this paragraph
# decrementing when we see an endif. if we see an elsif
# or endif without a corresponding #ifdef then we dont
# consider it part of this paragraph.
my $if_level = 0;
for (;;) {
$self->_maybe_skip_pod;

$self->_maybe_parse_typemap_block;

my $final;
if ($self->{lastline} !~ /^\s*#/ # not a CPP directive
# CPP directives:
# ANSI: if ifdef ifndef elif else endif define undef
Expand All @@ -1825,6 +1831,31 @@ sub fetch_para {
)
{
last if $self->{lastline} =~ /^\S/ && @{ $self->{line} } && $self->{line}->[-1] eq "";
if ($self->{lastline}=~/^#[ \t]*(if|ifn?def|elif|else|endif)\b/) {
my $type = $1; # highest defined capture buffer, "if" for any if like condition
if ($type =~ /^if/) {
if (@{$self->{line}}) {
# increment level
$if_level++;
} else {
$final = 1;
}
} elsif ($type eq "endif") {
if ($if_level) { # are we in an if that was started in this paragraph?
$if_level--; # yep- so decrement to end this if block
} else {
$final = 1;
}
} elsif (!$if_level) {
# not in an #ifdef from this paragraph, thus
# this directive should not be part of this paragraph.
$final = 1;
}
}
if ($final and @{$self->{line}}) {
return 1;
}

push(@{ $self->{line} }, $self->{lastline});
push(@{ $self->{line_no} }, $self->{lastline_no});
}
Expand All @@ -1838,12 +1869,18 @@ sub fetch_para {

chomp $self->{lastline};
$self->{lastline} =~ s/^\s+$//;
if ($final) {
last;
}
}

# Nuke trailing "line" entries until there's one that's not empty
pop(@{ $self->{line} }), pop(@{ $self->{line_no} })
while @{ $self->{line} } && $self->{line}->[-1] eq "";

#use Data::Dumper;
#warn Dumper("late",$self->{line},$self->{line_no}, $self->{lastline});

return 1;
}

Expand Down
20 changes: 19 additions & 1 deletion dist/ExtUtils-ParseXS/t/001-basic.t
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/perl

use strict;
use Test::More tests => 20;
use Test::More tests => 22;
use Config;
use DynaLoader;
use ExtUtils::CBuilder;
Expand Down Expand Up @@ -222,6 +222,24 @@ like $stderr, '/No INPUT definition/', "Exercise typemap error";

#####################################################################

{ # tight cpp directives
my $pxs = ExtUtils::ParseXS->new;
tie *FH, 'Foo';
my $stderr = PrimitiveCapture::capture_stderr(sub {
$pxs->process_file(
filename => 'XSTightDirectives.xs',
output => \*FH,
prototypes => 1);
});
my $content = tied(*FH)->{buf};
my $count = 0;
$count++ while $content=~/^XS_EUPXS\(XS_My_do\)\n\{/mg;
is $stderr, undef, "No error expected from TightDirectives.xs";
is $count, 2, "Saw XS_MY_do definition the expected number of times";
}

#####################################################################

sub Foo::TIEHANDLE { bless {}, 'Foo' }
sub Foo::PRINT { shift->{buf} .= join '', @_ }
sub Foo::content { shift->{buf} }
21 changes: 21 additions & 0 deletions dist/ExtUtils-ParseXS/t/XSTightDirectives.xs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MODULE = My PACKAGE = My

#ifdef MYDEF123
void
do(dbh)
SV *dbh
CODE:
{
int x;
++x;
}
#else
void
do(dbh)
SV *dbh
CODE:
{
int x;
++x;
}
#endif

0 comments on commit b263689

Please sign in to comment.