chiark / gitweb /
Macro assistance part 2 - syntax for $(eval $(call...))
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 24 Dec 2019 23:04:58 +0000 (23:04 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 30 Dec 2019 11:35:15 +0000 (11:35 +0000)
This can be used to call a macro defined with &:macro.  In combination
these provide a more reasonable macro facility than make's.

Specifically:

* Document the new facility.
* Motivate it in the README.
* Provide the new @nest kind for &${  }, which uses $ddbl as
  a counter to count { and }.
* Implement the {}-counting and nesting end in the main parsing
  loop.  (We must now search for things besides $esc.)
* In extract-doctest, provide a slightly adhoc special case for
  understanding ${eval ...} as an expansion text in the README.
  And do not attempt to test &${ } when already $-doubling.

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

diff --git a/README b/README
index 130a1c7..20658ae 100644 (file)
--- a/README
+++ b/README
@@ -340,6 +340,19 @@ STUFF $ THINGS     ..      STUFF $$ THINGS
 &:endm         ..      endef
        NAME is processed for &
 
+&${..$..} =>   ${eval ${call ..$$..}}
+       (matches { } pairs to find the end)
+       content is $-doubled (unless it contains $- to turn that off)
+
+       Together &:macro and &${...} provide a more reasonable macro
+       facility than raw make.  They solve the problem that make
+       expansions cannot directly generate multiple rules, variable,
+       etc.; instead, `$(eval )' must be used, but that re-expands
+       the argument, meaning that all the literal text must be
+       $-doubled.  This applies to the macro text and to the
+       arguments.  Also `$(eval $(call ...))' is an unfortunate syntax.
+       Hence &:macro and &${...}.
+
 While dollar-doubling:
 - - - - - - - - - - -
 
index 3ccfa0d..52a0ec8 100755 (executable)
--- a/generate
+++ b/generate
@@ -213,8 +213,19 @@ sub process_input_mk ($$$$) {
        }
        for (;;) {
            die if $ddbl && defined $buffering_output;
-           unless (s{^(.*?)$esc}{}) { od $_; last; }
+           unless (@nest && $nest[0][0] eq 'Eval'
+                   ? s{^(.*?)($esc|[{}])}{}
+                   : s{^(.*?)($esc)}{}) { od $_; last; }
            od $1;
+           if ($2 eq '{') {
+               $ddbl++;
+               next;
+           } elsif ($2 eq '}') {
+               next if --$ddbl;
+               $pop_nest->('Eval');
+               od '}}';
+               next;
+           }
            if (s{^\\$esc}{}) { od "$$esclitr" }
            elsif (s{^\\\$}{}) { oud '$' }
            elsif (s{^\\\s+$}{}) { }
@@ -231,7 +242,11 @@ sub process_input_mk ($$$$) {
            elsif (s{^\$\+}{}) { $ddbl=1; }
            elsif (s{^\$\(}{}) { die unless $ddbl; oud "\$("; }
            elsif (s{^\$(\d+)}{}) { die unless $ddbl; oud "\$($1)"; }
-           elsif (s{^([~^]?)(?=[ \t])}{}) {
+           elsif (s{^\$\{}{}) {
+               die if $ddbl;
+               od '${eval ${call ';
+               $push_nest->('Eval',1);
+           } elsif (s{^([~^]?)(?=[ \t])}{}) {
                my $prefix = $pfxmap{$1} // die;
                my $after='';
                if (m{([ \t])$esc}) { ($_,$after) = ($`, $1.$'); }
index 57f5313..d779e00 100755 (executable)
@@ -56,6 +56,9 @@ while (<>) {
            $e->{OutTop} = $1 eq 'nothing' ? '' : $1;
        } elsif (# parse: expect other wordish things to be comments
                 m{^(?!or\b)\w{2,} }) {
+       } elsif (# adhoc: slightly special case for $(eval $(call
+                m{^\$\{.*}) {
+           $e->{Out} .= ' '.$&;
        } elsif (m/^$/) {
        } else {
            confess "unk rhs $_ ?";
@@ -140,6 +143,8 @@ sub writeout ($) {
                      my ($e) = @_;
                      # adhoc: skip &:macro in already-doubling part
                      return 0 if $e->{In} =~ m{^\&\:macro};
+                     # adhoc: skip &${ ie eval in already-doubling part
+                     return 0 if $e->{In} =~ m{^\&\$\{};
                      return 0 if $e->{CQ};
                      return $e->{DD} || !grep {
                          # If there are two entries with the same In,