chiark / gitweb /
Error handling: Provide err and ddbl_only, and an internal spec
[subdirmk.git] / generate
index ec478665e89f954385f3ea5df1d2f8e3fcc49e7a..84572edc2ef842e0ceffacd884aa306851518831 100755 (executable)
--- a/generate
+++ b/generate
@@ -19,6 +19,22 @@ print "$0 @ARGV\n" or die $!;
 
 our $srcdir='.';
 
+# error handling methods:
+#
+# Error in input file, while $err_file and $. set, eg in most of
+# process_input_mk:
+#         err "message";
+#
+# Other input or usage errors:
+#         die "$0: $file:$lno: problem\n";
+#         die "$0: some problem not locatable in that way\n";
+#
+# System call error (not ENOENT) accessing input/output files:
+#         die "description of problem eg maybe erbing noun: $!\n";
+#
+# Bug detedcted in `generate':
+#         die "internal error (some information)?"; # or similar
+
 while (@ARGV && $ARGV[0] =~ m/^-/) {
     $_ = shift @ARGV;
     last if $_ eq '--';
@@ -149,6 +165,19 @@ sub set_dir_vars ($) {
     $var_prefix = "${var_prefix_name}_";
 }
 
+our $err_file;
+
+sub err ($) {
+    my ($m) = @_;
+    die "$0: ${err_file}:$.: $m\n";
+}
+
+sub ddbl_only ($) {
+    my ($e) = @_;
+    return if $ddbl;
+    err "escape &$e is valid only during \$-doubling";
+}
+
 sub process_input_mk ($$$$);
 sub process_input_mk ($$$$) {
     my ($targets, $f, $esclitr, $enoent_ok) = @_;
@@ -170,6 +199,8 @@ sub process_input_mk ($$$$) {
     }
     $input_files{$f}++;
 
+    local $err_file=$f;
+
     my %srcdirmap = (
                  '^' => "\$(top_srcdir)${dir_suffix}",
                  '~' => "\$(top_srcdir)",
@@ -180,13 +211,29 @@ sub process_input_mk ($$$$) {
     $pfxmap{$_} = $srcdirmap{$_}.'/' foreach keys %srcdirmap;
 
     local $ddbl;
+    my @nest = (['']);
+
+    my $push_nest = sub {
+       my ($nk, $nndbl) = @_;
+       unshift @nest, [ $nk, $ddbl ];
+       $ddbl = $nndbl;
+    };
+    my $pop_nest = sub {
+       my ($nk) = @_;
+       die unless $nest[0][0] eq $nk;
+       $ddbl = (shift @nest)[1];
+    };
 
     while (<$input>) {
        if (s#^\s*$esc\:changequote\s+(\S+)\s+$##) {
            $$esclitr = $1;
            $set_esc->();
            next;
-       } elsif (s#^\s*$esc\:(?=(-?)include)##) {
+       } elsif (s#^\s*$esc\:endm\s+$##) {
+           $pop_nest->('Macro');
+           od "endef\n";
+           next;
+       } elsif (s#^\s*$esc\:(?=(-?)include|macro)##) {
            $buffering_output='';
        } elsif (m#^\s*$esc\:([a-z][-0-9a-z_]*)#) {
            die "unknown directive $1";
@@ -197,8 +244,19 @@ sub process_input_mk ($$$$) {
        }
        for (;;) {
            die if $ddbl && defined $buffering_output;
-           unless (s{^(.*?)$esc}{}) { od $_; last; }
+           unless ($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+$}{}) { }
@@ -215,7 +273,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.$'); }
@@ -238,11 +300,15 @@ sub process_input_mk ($$$$) {
                my $subf = "$srcdir/$2";
                process_input_mk($targets, $subf, $esclitr, $1);
                od "\n";
+           } elsif (m#^macro\s+(\S+)\s+$#) {
+               od "define $1\n";
+               $push_nest->('Macro', 1);
            } else {
                die "internal error buffering directive $_ ";
            }
        }
     }
+    die "unclosed $nest[0][0]" if $nest[0][0];
     $input->error and die "read $f: $!\n";
     close $input or die "close $f: $!\n";
 }