Skip to content

Commit 5a14bdf

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 c7ee219 commit 5a14bdf

File tree

1 file changed

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

1 file changed

+41
-34
lines changed

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

Lines changed: 41 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,18 @@ 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 if $pxs->{line}[0] !~ /\S/;
1083+
1084+
# Process a C-preprocessor line. Note that any non-CPP lines
1085+
# starting with '#' will already have been filtered out by
1086+
# fetch_para().
10781087
#
1079-
# Also, keep track of #if/#else/#endif nesting.
1088+
# If its a #if or similar, then recursively process each branch
1089+
# as a separate cpp_scope object until the matching #endif is
1090+
# reached.
10801091

1081-
while (@{$pxs->{line}} && $pxs->{line}[0] =~ /^#/) {
1092+
if ($pxs->{line}[0] =~ /^#/) {
10821093
my $node = ExtUtils::ParseXS::Node::global_cpp_line->new();
10831094
$node->parse($pxs);
10841095
push @{$self->{kids}}, $node;
@@ -1105,7 +1116,7 @@ sub parse {
11051116
# other branches of the same conditional.
11061117

11071118
while (1) {
1108-
# Parse the branch in new scope
1119+
# For each iteration, parse the next branch in a new scope
11091120
my $scope = ExtUtils::ParseXS::Node::cpp_scope->new(
11101121
{type => 'if'});
11111122
$scope->parse($pxs)
@@ -1141,12 +1152,9 @@ sub parse {
11411152
# any more branches to process of current if?
11421153
last if $last->{is_endif};
11431154
} # while 1
1144-
} # while /^#/
1145-
1146-
# skip blank lines
1147-
shift @{$pxs->{line}} while @{$pxs->{line}} && $pxs->{line}[0] !~ /\S/;
11481155

1149-
next PARAGRAPH unless @{ $pxs->{line} };
1156+
next;
1157+
}
11501158

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

11911199
# Process file-scoped keywords
1192-
1193-
# ----------------------------------------------------------------
1194-
# Process file-scoped keywords
1195-
# ----------------------------------------------------------------
1196-
11971200
#
11981201
# This loop repeatedly: skips any blank lines and then calls
11991202
# the relevant Node::FOO::parse() method if it finds any of the
12001203
# file-scoped keywords in the passed pattern.
12011204
#
1202-
# Note due to the looping within parse_keywords() rather than
1205+
# Note: due to the looping within parse_keywords() rather than
12031206
# 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.
1207+
# gets the 'start at column 1' check above enforced.
1208+
# This is a bug, maintained for backwards compatibility: see the
1209+
# comments below referring to SCOPE for other bits of code needed
1210+
# to enforce this compatibility.
12061211

12071212
$self->parse_keywords(
12081213
$pxs,
@@ -1212,19 +1217,20 @@ sub parse {
12121217
. "|VERSIONCHECK|INCLUDE|INCLUDE_COMMAND|SCOPE|TYPEMAP",
12131218
$keywords_flag_MODULE,
12141219
);
1220+
# XXX we could have an 'or next' here if not for SCOPE backcompat
1221+
# and also delete the following 'skip blank line' and 'next unless
1222+
# @line' lines
12151223

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

1219-
next PARAGRAPH unless @{ $pxs->{line} };
1227+
next unless @{$pxs->{line}};
12201228

1221-
# ----------------------------------------------------------------
1222-
# Parse and code-emit an XSUB
1223-
# ----------------------------------------------------------------
1229+
# Parse an XSUB
12241230

12251231
my $xsub = ExtUtils::ParseXS::Node::xsub->new();
12261232
$xsub->parse($pxs)
1227-
or next PARAGRAPH;
1233+
or next;
12281234
push @{$self->{kids}}, $xsub;
12291235

12301236
# Check for a duplicate function definition in this scope
@@ -1238,13 +1244,14 @@ sub parse {
12381244
$self->{seen_xsubs}{$name} = 1;
12391245
}
12401246

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

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

12491256
1;
12501257
}

0 commit comments

Comments
 (0)