chiark / gitweb /
Dollar doubling feature
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 25 Dec 2019 23:29:40 +0000 (23:29 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 30 Dec 2019 11:35:15 +0000 (11:35 +0000)
This makes it easier to write certain rules commands, and macros
involving eval.  Further enhancements will follow, but for now:

* Document the new facility, including the &-escapes to turn it on and
  off, its effect, and the three within-doubling don't-double escapes.

* Implementation.  Specifically:
   - Rename od to oud (`undoubled').
   - Provide od which does double things if $ddbl (a global) is set.
   - Implement the escapes, and add some error checks.
   - Change `od' to `oud' in `&\$', so that that always produces an
     undoubled $.

* Enhance extract-doctest:
   - Set $e->{DD} to say if it's in `while dollar doubling'.
   - Filter out such entries from the `normal' test - they are not
     legal outside dollar-doubling.
   - Add a dollar-doubling test which includes versions of all
     the normal tests as well as the dollar-doubling ones, and
     which dollar-doubles the outputs when appropriate.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
README
generate
tests/filter/extract-doctest

diff --git a/README b/README
index 7de4def..d750cb8 100644 (file)
--- a/README
+++ b/README
@@ -254,7 +254,7 @@ So pathname syntax is a subset of:
 &&             =>      &&              for convenience in shell runes
 
 &\&            =>      &               general escaping mechanism
-&\$            =>      $
+&\$            =>      $               provided for $-doubling regimes
 &\NEWLINE                              eats the newline and vanishes
 
 &$VARIABLE     =>      $(sub_dir_VARIABLE)     or $(TOP_VARIABLE)
@@ -323,6 +323,25 @@ So pathname syntax is a subset of:
        `all' is extra special: every directory has an `all'
        target, which corresponds to &TARGETS.
 
+
+Dollar doubling and macro assistance
+------------------------------------
+
+&$+            Starts dollar-doubling
+&$-            Stops dollar-doubling
+       Both are idempotent and local to the file or context.
+
+While dollar-doubling:
+- - - - - - - - - - -
+
+$      =>      $$      including $'s produced by other
+                        &-expansions not mentioned here
+
+&\$    =>      $
+&$NN   =>      $(NN)   where N are digits
+&$(    =>      $(
+
+
 Subdirectory and variable naming
 --------------------------------
 
index c608e8c..ec47866 100755 (executable)
--- a/generate
+++ b/generate
@@ -74,7 +74,7 @@ sub oraw {
     print O @_ or die "error writing $writing_output.tmp: $!\n";
 }
 
-sub od { # maybe $-doubled
+sub oud { # undoubled
     if (defined $buffering_output) {
        $buffering_output .= $_ foreach @_;
        return;
@@ -82,6 +82,20 @@ sub od { # maybe $-doubled
     oraw @_;
 }
 
+our $ddbl;
+
+sub od { # maybe $-doubled
+    if (!$ddbl) {
+       oud @_;
+       return;
+    }
+    foreach (@_) {
+       my $e = $_;
+       $e =~ s{\$}{\$\$}g;
+       oud $e;
+    }
+}
+
 sub start_output_file ($) {
     close_any_output_file();
     ($writing_output) = @_;
@@ -165,6 +179,8 @@ sub process_input_mk ($$$$) {
                 );
     $pfxmap{$_} = $srcdirmap{$_}.'/' foreach keys %srcdirmap;
 
+    local $ddbl;
+
     while (<$input>) {
        if (s#^\s*$esc\:changequote\s+(\S+)\s+$##) {
            $$esclitr = $1;
@@ -180,10 +196,11 @@ sub process_input_mk ($$$$) {
            $targets->{$t} //= [ ];
        }
        for (;;) {
+           die if $ddbl && defined $buffering_output;
            unless (s{^(.*?)$esc}{}) { od $_; last; }
            od $1;
            if (s{^\\$esc}{}) { od "$$esclitr" }
-           elsif (s{^\\\$}{}) { od '$' }
+           elsif (s{^\\\$}{}) { oud '$' }
            elsif (s{^\\\s+$}{}) { }
            elsif (s{^$esc}{}) { od "$$esclitr$$esclitr" }
            elsif (m{^(?=$caps_re)}) { od $var_prefix }
@@ -194,6 +211,10 @@ sub process_input_mk ($$$$) {
            elsif (s{^([~^]?)/}{}) { od $pfxmap{$1} }
            elsif (s{^\.}{}) { od $dir_name }
            elsif (s{^([~^])\.}{}) { od $srcdirmap{$1} }
+           elsif (s{^\$\-}{}) { $ddbl=undef; }
+           elsif (s{^\$\+}{}) { $ddbl=1; }
+           elsif (s{^\$\(}{}) { die unless $ddbl; oud "\$("; }
+           elsif (s{^\$(\d+)}{}) { die unless $ddbl; oud "\$($1)"; }
            elsif (s{^([~^]?)(?=[ \t])}{}) {
                my $prefix = $pfxmap{$1} // die;
                my $after='';
index 10dd42a..b63f309 100755 (executable)
@@ -61,6 +61,8 @@ while (<>) {
            confess "unk rhs $_ ?";
        }
        $e->{CQ} = $in_changequote;
+       # adhoc: rely on this specific section title
+       $e->{DD} = $csection =~ m{^while dollar[- ]doubling}i;
     } else {
        confess "$_ ?";
     }
@@ -130,7 +132,26 @@ sub writeout ($) {
     oh "# doctest starts $dir_prefix\n";
     write_permode($dir_prefix,
                  '','','', 'normal',
-                sub { !$_[0]{CQ} } );
+                sub { !$_[0]{DD} && !$_[0]{CQ} } );
+    write_permode($dir_prefix,
+                 '&$+', '&$-', "\n",
+                 'dollar doubling',
+                 sub {
+                     my ($e) = @_;
+                     return 0 if $e->{CQ};
+                     return $e->{DD} || !grep {
+                         # If there are two entries with the same In,
+                         # use only the one from the `while dollar
+                         # doubling' section.  So entries there override
+                         # entries in the rest o the file.
+                         $_ ne $e && $_->{In} eq $e->{In}
+                     } @exp;
+                 },
+                 sub {
+                     $_=$_[0];
+                     s/\$/\$\$/g unless $_[1]{DD};
+                     $_;
+                 } );
     write_permode($dir_prefix,
                  "&:changequote NEWQUOTE\n",
                  "NEWQUOTE:changequote &\n",