@@ -362,6 +362,20 @@ sub parse_keywords {
362362 return @kids ;
363363}
364364
365+ # return (module, package, prefix) values if the line
366+ # is a valid 'MODULE = ...' line
367+
368+ sub is_xs_module_line {
369+ my __PACKAGE__ $self = shift ;
370+ my $line = shift ;
371+
372+ $line =~
373+ / ^ MODULE \s * = \s * [\w :]+
374+ (?: \s + PACKAGE \s * = \s * ( [\w :]+ ) )?
375+ (?: \s + PREFIX \s * = \s * ( \S + ) )?
376+ \s * $ /x ;
377+ }
378+
365379
366380sub as_code { }
367381
@@ -374,6 +388,7 @@ package ExtUtils::ParseXS::Node::XS_file;
374388
375389BEGIN { $build_subclass -> (
376390 ' preamble' , # Node::preamble object which emits preamble C code
391+ ' C_part' , # the C part of the XS file, before the first MODULE
377392)};
378393
379394sub parse {
@@ -392,6 +407,15 @@ sub parse {
392407 or return ;
393408 push @{$self -> {kids }}, $preamble ;
394409
410+ # Process the first (C language) half of the XS file, up until the first
411+ # MODULE: line
412+
413+ my $C_part = ExtUtils::ParseXS::Node::C_part-> new();
414+ $self -> {C_part } = $C_part ;
415+ $C_part -> parse($pxs , $self )
416+ or return ;
417+ push @{$self -> {kids }}, $C_part ;
418+
395419 1;
396420}
397421
@@ -448,6 +472,171 @@ EOM
448472}
449473
450474
475+ # ======================================================================
476+
477+ package ExtUtils::ParseXS::Node::C_part ;
478+
479+ # A node representing the C part of the XS file - i.e. everything
480+ # before the first MODULE line
481+
482+ BEGIN { $build_subclass -> (
483+ )};
484+
485+ sub parse {
486+ my __PACKAGE__ $self = shift ;
487+ my ExtUtils::ParseXS $pxs = shift ;
488+
489+ $self -> {line_no } = 1;
490+ $self -> {file } = $pxs -> {in_pathname };
491+
492+ # Read in lines until the first MODULE line, creating a list of
493+ # Node::C_part_code and Node::C_part_POD nodes as children.
494+ # Returns with $_ holding the (unprocessed) next line (or undef for
495+ # EOF)
496+
497+ $_ = readline($pxs -> {in_fh });
498+
499+ while (defined $_ ) {
500+ return 1 if $self -> is_xs_module_line($_ );
501+
502+ my $node =
503+ / ^=/ ? ExtUtils::ParseXS::Node::C_part_POD-> new()
504+ : ExtUtils::ParseXS::Node::C_part_code-> new();
505+
506+ # Read in next block of code or POD lines
507+ $node -> parse($pxs )
508+ or return ;
509+ push @{$self -> {kids }}, $node ;
510+ }
511+
512+ warn " Didn't find a 'MODULE ... PACKAGE ... PREFIX' line\n " ;
513+ exit 0; # Not a fatal error for the caller process
514+ }
515+
516+
517+ sub as_code {
518+ my __PACKAGE__ $self = shift ;
519+ my ExtUtils::ParseXS $pxs = shift ;
520+
521+ $_ -> as_code($pxs , $self ) for @{$self -> {kids }};
522+
523+ print ' ExtUtils::ParseXS::CountLines' -> end_marker, " \n "
524+ if $pxs -> {config_WantLineNumbers };
525+ }
526+
527+
528+ # ======================================================================
529+
530+ package ExtUtils::ParseXS::Node::C_part_POD ;
531+
532+ # A node representing a section of POD within the C part of the XS file
533+
534+ BEGIN { $build_subclass -> (
535+ ' pod_lines' , # array of lines containing pod, including start and end
536+ # '=foo' lines
537+ )};
538+
539+ sub parse {
540+ my __PACKAGE__ $self = shift ;
541+ my ExtUtils::ParseXS $pxs = shift ;
542+
543+ $self -> {line_no } = $. ;
544+ $self -> {file } = $pxs -> {in_pathname };
545+
546+ # This method is called with $_ holding the first line of POD
547+ # and returns with $_ holding the (unprocessed) next line
548+
549+ do {
550+ push @{$self -> {pod_lines }}, $_ ;
551+ if (/ ^=cut\s *$ / ) {
552+ $_ = readline($pxs -> {in_fh });
553+ return 1;
554+ }
555+ } while (readline($pxs -> {in_fh }));
556+
557+ # At this point $. is at end of file so die won't state the start
558+ # of the problem, and as we haven't yet read any lines &death won't
559+ # show the correct line in the message either.
560+ die ( " Error: Unterminated pod in $pxs ->{in_filename}, "
561+ . " line $self ->{line_no}\n " );
562+ }
563+
564+
565+ sub as_code {
566+ my __PACKAGE__ $self = shift ;
567+ my ExtUtils::ParseXS $pxs = shift ;
568+
569+ # Emit something in the C file to indicate that a section of POD has
570+ # been elided, while maintaining the correct lines numbers using
571+ # #line.
572+ #
573+ # We can't just write out a /* */ comment, as our embedded POD might
574+ # itself be in a comment. We can't put a /**/ comment inside #if 0, as
575+ # the C standard says that the source file is decomposed into
576+ # preprocessing characters in the stage before preprocessing commands
577+ # are executed.
578+ #
579+ # I don't want to leave the text as barewords, because the spec isn't
580+ # clear whether macros are expanded before or after preprocessing
581+ # commands are executed, and someone pathological may just have
582+ # defined one of the 3 words as a macro that does something strange.
583+ # Multiline strings are illegal in C, so the "" we write must be a
584+ # string literal. And they aren't concatenated until 2 steps later, so
585+ # we are safe.
586+ # - Nicholas Clark
587+
588+ print ExtUtils::ParseXS::Q(<<"EOF" );
589+ |#if 0
590+ | "Skipped embedded POD."
591+ |#endif
592+ EOF
593+
594+ printf (" #line %d \" %s \"\n " ,
595+ $self -> {line_no } + @{$self -> {pod_lines }},
596+ ExtUtils::ParseXS::Utilities::escape_file_for_line_directive(
597+ $pxs -> {in_pathname }))
598+ if $pxs -> {config_WantLineNumbers };
599+ }
600+
601+
602+ # ======================================================================
603+
604+ package ExtUtils::ParseXS::Node::C_part_code ;
605+
606+ # A node representing a section of C code within the C part of the XS file
607+
608+ BEGIN { $build_subclass -> (
609+ ' code_lines' , # array of lines containing C code
610+ )};
611+
612+ sub parse {
613+ my __PACKAGE__ $self = shift ;
614+ my ExtUtils::ParseXS $pxs = shift ;
615+
616+ $self -> {line_no } = $. ;
617+ $self -> {file } = $pxs -> {in_pathname };
618+
619+ # This method is called with $_ holding the first line of C code
620+ # and returns with $_ holding the (unprocessed) next line
621+
622+ do {
623+ return 1 if $self -> is_xs_module_line($_ );
624+ return 1 if / ^=/ ;
625+ push @{$self -> {code_lines }}, $_ ;
626+ } while (readline($pxs -> {in_fh }));
627+
628+ 1;
629+ }
630+
631+ sub as_code {
632+ my __PACKAGE__ $self = shift ;
633+ my ExtUtils::ParseXS $pxs = shift ;
634+
635+ print @{$self -> {code_lines }};
636+ }
637+
638+
639+
451640# ======================================================================
452641
453642package ExtUtils::ParseXS::Node::xsub ;
0 commit comments