Skip to content

Commit 64d7e86

Browse files
committed
ParseXS: refactor: simplify main loop
Simplify the code in Node::cpp_scope::parse(), which contains the main file-scoped parsing loop, and update / add code comments. The code in this loop has gone through some rough times with all the refactoring that has taken place in the last year, chiefly converting the parser into being AST-based. This commit is kind of a final tidy up to restore sanity. Apart from fixing lots of comments, the main thing this commit does is flatten nested while loops. Before this commit, the overall structure of the parse() function was like; PARAGRAPH: while (lines to process) { while (blank line) { skip } while (C-preprocessor line) { process } ... and similar loops ... } and is now: while (lines to process) { if (blank line) { skip; next } if (C-preprocessor line) { process; next } ... and similar loops ... } i.e. rather than there being nested loops, just have one main loop and go back to the start of that to do the next thing. This should be functionally equivalent, but less complicated. This new paradigm can't be applied yet to the last few items in the main loop due to a backwards compatibility issue with the SCOPE keyword. I'll fix that at some future date.
1 parent 20d2937 commit 64d7e86

File tree

1 file changed

+42
-34
lines changed
  • dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS

1 file changed

+42
-34
lines changed

dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/Node.pm

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,14 +1056,20 @@ sub parse {
10561056
my __PACKAGE__ $self = shift;
10571057
my ExtUtils::ParseXS $pxs = shift;
10581058

1059-
# ----------------------------------------------------------------
1060-
# Main loop: for each iteration, read in a paragraph's worth of XSUB
1061-
# definition or XS/CPP directives into @{ $self->{line} }, then try to
1062-
# interpret those lines.
1063-
# ----------------------------------------------------------------
1059+
# Main loop: for each iteration, parse the next 'thing' in the current
1060+
# paragraph, such as a C preprocessor directive, a contiguous block of
1061+
# file-scoped keywords, or an XSUB. When the current paragraph runs
1062+
# out, read in another one. XSUBs, TYPEMAP and BOOT will consume
1063+
# all lines until the end of the current paragraph.
1064+
#
1065+
# C preprocessor conditionals such as #if may trigger recursive
1066+
# calls to process each branch until the matching #endif. These may
1067+
# cross paragraph boundaries.
1068+
1069+
while ( ($pxs->{line} && @{$pxs->{line}}) || $pxs->fetch_para())
1070+
{
1071+
next unless @{$pxs->{line}}; # fetch_para() can return zero lines
10641072

1065-
PARAGRAPH:
1066-
while ( ($pxs->{line} && @{$pxs->{line}}) || $pxs->fetch_para()) {
10671073
if ( !defined($self->{line_no})
10681074
&& defined $pxs->{line_no}[0]
10691075
) {
@@ -1072,13 +1078,19 @@ sub parse {
10721078
$self->SUPER::parse($pxs);
10731079
}
10741080

1075-
# Process any initial C-preprocessor lines and blank
1076-
# lines. Note that any non-CPP lines starting with '#' will
1077-
# already have been filtered out by fetch_para().
1081+
# skip blank line
1082+
shift @{$pxs->{line}}, next
1083+
if @{$pxs->{line}} && $pxs->{line}[0] !~ /\S/;
1084+
1085+
# Process a C-preprocessor line. Note that any non-CPP lines
1086+
# starting with '#' will already have been filtered out by
1087+
# fetch_para().
10781088
#
1079-
# Also, keep track of #if/#else/#endif nesting.
1089+
# If its a #if or similar, then recursively process each branch
1090+
# as a separate cpp_scope object until the matching #endif is
1091+
# reached.
10801092

1081-
while (@{$pxs->{line}} && $pxs->{line}[0] =~ /^#/) {
1093+
if ($pxs->{line}[0] =~ /^#/) {
10821094
my $node = ExtUtils::ParseXS::Node::global_cpp_line->new();
10831095
$node->parse($pxs);
10841096
push @{$self->{kids}}, $node;
@@ -1105,7 +1117,7 @@ sub parse {
11051117
# other branches of the same conditional.
11061118

11071119
while (1) {
1108-
# Parse the branch in new scope
1120+
# For each iteration, parse the next branch in a new scope
11091121
my $scope = ExtUtils::ParseXS::Node::cpp_scope->new(
11101122
{type => 'if'});
11111123
$scope->parse($pxs)
@@ -1141,12 +1153,9 @@ sub parse {
11411153
# any more branches to process of current if?
11421154
last if $last->{is_endif};
11431155
} # while 1
1144-
} # while /^#/
1145-
1146-
# skip blank lines
1147-
shift @{$pxs->{line}} while @{$pxs->{line}} && $pxs->{line}[0] !~ /\S/;
11481156

1149-
next PARAGRAPH unless @{ $pxs->{line} };
1157+
next;
1158+
}
11501159

11511160
# die if the next line is indented: all file-scoped things (CPP,
11521161
# keywords, XSUB starts) are supposed to start on column 1
@@ -1189,20 +1198,17 @@ sub parse {
11891198
$pxs->{file_SCOPE_enabled} = 0;
11901199

11911200
# Process file-scoped keywords
1192-
1193-
# ----------------------------------------------------------------
1194-
# Process file-scoped keywords
1195-
# ----------------------------------------------------------------
1196-
11971201
#
11981202
# This loop repeatedly: skips any blank lines and then calls
11991203
# the relevant Node::FOO::parse() method if it finds any of the
12001204
# file-scoped keywords in the passed pattern.
12011205
#
1202-
# Note due to the looping within parse_keywords() rather than
1206+
# Note: due to the looping within parse_keywords() rather than
12031207
# looping here, only the first keyword in a contiguous block
1204-
# gets the 'start at column 1' check above enforced. This is
1205-
# a bug, maintained for backwards compatibility.
1208+
# gets the 'start at column 1' check above enforced.
1209+
# This is a bug, maintained for backwards compatibility: see the
1210+
# comments below referring to SCOPE for other bits of code needed
1211+
# to enforce this compatibility.
12061212

12071213
$self->parse_keywords(
12081214
$pxs,
@@ -1212,19 +1218,20 @@ sub parse {
12121218
. "|VERSIONCHECK|INCLUDE|INCLUDE_COMMAND|SCOPE|TYPEMAP",
12131219
$keywords_flag_MODULE,
12141220
);
1221+
# XXX we could have an 'or next' here if not for SCOPE backcompat
1222+
# and also delete the following 'skip blank line' and 'next unless
1223+
# @line' lines
12151224

12161225
# skip blank lines
12171226
shift @{$pxs->{line}} while @{$pxs->{line}} && $pxs->{line}[0] !~ /\S/;
12181227

1219-
next PARAGRAPH unless @{ $pxs->{line} };
1228+
next unless @{$pxs->{line}};
12201229

1221-
# ----------------------------------------------------------------
1222-
# Parse and code-emit an XSUB
1223-
# ----------------------------------------------------------------
1230+
# Parse an XSUB
12241231

12251232
my $xsub = ExtUtils::ParseXS::Node::xsub->new();
12261233
$xsub->parse($pxs)
1227-
or next PARAGRAPH;
1234+
or next;
12281235
push @{$self->{kids}}, $xsub;
12291236

12301237
# Check for a duplicate function definition in this scope
@@ -1238,13 +1245,14 @@ sub parse {
12381245
$self->{seen_xsubs}{$name} = 1;
12391246
}
12401247

1241-
1242-
1248+
# xsub->parse() should have consumed all the remaining
1249+
# lines in the current paragraph.
12431250
die "Internal error: unexpectedly not at EOF\n"
12441251
if @{$pxs->{line}};
12451252

12461253
$pxs->{seen_an_XSUB} = 1; # encountered at least one XSUB
1247-
} # END 'PARAGRAPH' 'while' loop
1254+
1255+
} # END main 'while' loop
12481256

12491257
1;
12501258
}

0 commit comments

Comments
 (0)