#!/usr/bin/perl -w # # script for extracting doctests from README # # usage: # expand ) { # adhoc: rely on structure of indented examples in &:changequote part $in_changequote = (m{^\&\:changequote}...m{^\S}) && m{^\s}; if (m{^-----|^- - - - -}) { # parse: rely on underlines for (sub)section headings $csection = $lastl; next; } $lastl = $_; my $e = { L => $. }; # parse: rely on looking for => (and .. on subsequent lines) next unless m{\=\>} or ($cent and m{ \.\. }); my $mapop = '=>'; # adhoc: special case NEWQUOTE here so we recognise things in changequote if (s{^(\s*)(\&\S+|NEWQUOTE\S+|\$)\s+(\=\>|\.\.)\s+(\S+)\s+}{} || s{^()(\&\:\w+(?: \S+)*)\s{2,}(\=\>)\s{2,}($withspcs)$}{} || $cent && s{^()($withspcs)\s{2,}(\.\.)\s{2,}($withspcs)$}{}) { # adhoc: expected indented iff in changequote part confess if length($1) xor $in_changequote; $mapop = $3; confess if !$cent && $mapop ne '=>'; $e->{In} = $2; $e->{Out} = $4; if (# adhoc: `or ...' introduces the `at toplevel' expansion s{^or (\S+)$}{}) { $e->{OutTop} = $1 eq 'nothing' ? '' : $1; } elsif (# parse: expect other wordish things to be comments m{^(?!or\b)\w{2,} }) { } elsif (m/^$/) { } else { confess "unk rhs $_ ?"; } $e->{CQ} = $in_changequote; } else { confess "$_ ?"; } if ($mapop eq '=>') { if ($e->{In} =~ m/\bNN\b/) { # adhoc: special case NN in examples confess if defined $cent->{OutTop}; foreach my $nn (0..11, 999) { my $f = { %$e }; foreach my $k (qw(In Out)) { $f->{$k} = $e->{$k}; ($f->{$k} =~ s/\bNN\b/$nn/g) == 1 or confess; } push @exp, $f; } $cent=undef; } else { push @exp, $e; $cent=$e; } } elsif ($mapop eq '..') { confess if defined $cent->{OutTop}; foreach my $k (qw(In Out)) { $cent->{$k} .= "\n".$e->{$k}; } } } print Dumper(\@exp); sub oi { print I @_ or die $!; } sub oo { print O @_ or die $!; } sub oh { oi @_; oo @_; } sub write_permode ($$$$$;$$) { my ($dir_prefix, $start, $end, $senl, $what, $filter, $omap) = @_; $filter //= sub { 1 }; $omap //= sub { $_[0] }; oi $start; oh "${senl}# ----- $what starts -----\n"; foreach my $e (@exp) { next unless $filter->($e); my $rubric = $e->{In}; $rubric =~ s/\&/AMP /g; $rubric =~ s/\$/DOLLAR /g; $rubric =~ s/NEWQUOTE/NEW_QUOTE /g; my $f = $e->{In} =~ m/\n/ ? "\n# %s:\n%s\n\n" : "%-30s: %s.\n"; my $o; $o = $e->{OutTop} if $dir_prefix eq ''; $o //= $e->{Out}; $o =~ s{/sub/dir}{} if $dir_prefix eq '' && !defined $e->{OutTop}; $o = $omap->($o, $e); oi sprintf $f, $rubric, $e->{In}; oo sprintf $f, $rubric, $o; } oi $end; oh "${senl}# ----- $what ends -----\n"; } sub writeout ($) { my ($dir_prefix) = @_; open I, '>', "$outdir/${dir_prefix}doctest.sd.mk" or die $!; open O, '>', "$outdir/${dir_prefix}doctest.mk.part" or die $!; oh "# doctest starts $dir_prefix\n"; write_permode($dir_prefix, '','','', 'normal', sub { !$_[0]{CQ} } ); write_permode($dir_prefix, "&:changequote NEWQUOTE\n", "NEWQUOTE:changequote &\n", "", 'changequote', sub { $_[0]{CQ} } ); oh "# doctest ends\n"; close I or die $!; } writeout(''); writeout('sub/dir/');