2 #eval "exec perl -S $0 $*"
3 # if $running_under_some_random_shell;
5 # reads CPP output and turns #line things into appropriate Haskell
8 # considered to be GHC-project specific
10 # OPTIONALLY processes GENERATE_SPECS pragmas
11 # when give flag -genSPECS
15 # {-# GENERATE_SPECS a b #-}
21 # {-# SPECIALIZE fn :: type[ a/a,u1/b] #-}
22 # {-# SPECIALIZE fn :: type[ a/a,u2/b] #-}
23 # {-# SPECIALIZE fn :: type[u1/a, b/b] #-}
24 # {-# SPECIALIZE fn :: type[u1/a,u1/b] #-}
25 # {-# SPECIALIZE fn :: type[u1/a,u2/b] #-}
26 # {-# SPECIALIZE fn :: type[u2/a, b/b] #-}
27 # {-# SPECIALIZE fn :: type[u2/a,u1/b] #-}
28 # {-# SPECIALIZE fn :: type[u2/a,u2/b] #-}
30 # where the u's are extracted from a predetermined
31 # set of unboxed types $SpecingString
33 # The types to substitute can be specified explicitly in { }s following
38 # {-# GENERATE_SPECS a{ty1,ty2...} b{+,ty1,ty2...} c{~,ty1,ty2,...} d{~,+,ty1,ty2,...} #-}
42 # ~ indicates that no specialisations are to be left polymorhphic in this type variable
43 # (this is required for overloaded tyvars which must have ground specialisations)
44 # + indicates that the predetermined types are to be added to the list
46 # Note: There must be no white space between { }s
47 # Use ( )s around type names when separation is required
50 # NOTE: this script needs RAWCPP set in order to do something
59 $DoGenSpecsUnboxed = 0;
62 while ($#ARGV >= 0 && $ARGV[0] eq '-v' || $ARGV[0] =~ /^-genSPECS/) {
63 if ($ARGV[0] eq '-v') {
65 } elsif ($ARGV[0] eq '-genSPECS') {
67 } elsif ($ARGV[0] eq '-genSPECSunboxed') {
69 $DoGenSpecsUnboxed = 1;
70 $SpecingString = "Char#,Int#,Double#";
71 @SpecingTypes = split(/,/, $SpecingString);
73 die "hscpp: unrecognised argument: $$ARGV[0]\n";
77 #ToDo: print a version number ?
81 if ( $OrigCpp =~ /(\S+)\s+(.*)/ ) {
84 if ( -x $cmd ) { # cool
86 } else { # oops; try to guess
87 $GccV = `gcc -v 2>&1`;
88 if ( $GccV =~ /Reading specs from (.*)\/specs/ ) {
89 $Cpp = "$1/cpp $rest";
91 die "hscpp: don't know how to run cpp: $OrigCpp\n";
98 print STDERR "hscpp:CPP invoked: $Cpp @ARGV\n" if $Verbose;
100 open(INPIPE, "$Cpp @ARGV |") || die "Can't open C pre-processor pipe\n";
104 # line directives come in flavo[u]rs:
105 # s/^#\s*line\s+\d+$/\{\-# LINE \-\}/; IGNORE THIS ONE FOR NOW
106 s/^#\s*line\s+(\d+)\s+(\".+\")$/\{\-# LINE \1 \2 \-\}/;
107 s/^#\s*(\d+)\s+(\".*\").*/\{\-# LINE \1 \2 \-\}/;
109 # genSPEC processing:
110 if ( /^\s*\{-#\s*GENERATE_SPECS/ ) {
118 if ( /^\s*\{-#\s*GENERATE_SPECS\s+(data)\s+(\S.*)\s*::(.*)#-\}\s*$/ ) {
123 } elsif ( /^\s*\{-#\s*GENERATE_SPECS\s+(instance)\s+(\S.*)\s*::(.*)#-\}\s*$/ ) {
128 } elsif ( /^(\s*)\{-#\s*GENERATE_SPECS\s+(\S+)\s+(.*)\s*#-\}\s*$/ ) {
134 while ( $tysig =~ /^\s*$/ ) {
138 $funpat = $fun; # quote non alphanumeric characters in pattern
139 $funpat =~ s/(\W)/\\\1/g;
140 $tysig =~ /^\s*$funpat\s*::(.*)$/ || die "Error: GENERATE_SPECS not followed by type signature for $fun:\n$line$tysig\n";
142 $type =~ s/^(.*)=>//; # remove context from type
144 die "Error: invlaid GENERATE_SPECS pragma:\n $_";
147 @tyvars = split(/\s+/, $vars);
149 foreach $var (@tyvars) {
152 if ( $var =~ /^(\w+)\{(.*)\}$/ ) {
154 @specing_types = &split_types($2);
155 if ($specing_types[0] eq '~') {
156 shift(@specing_types);
157 @tospec = (); # remove specs polymorphic in this tyvar
160 if ($specing_types[0] eq '+') {
161 shift(@specing_types);
162 unshift(@specing_types, @SpecingTypes);
165 @specing_types = @SpecingTypes;
168 # If not $DoGenSpecsUnboxed we remove any unboxed types
169 # (i.e. types containing a #) from the specing_types
171 @specing_types = grep(!/#/, @specing_types) if ! $DoGenSpecsUnboxed;
173 foreach $uty (@specing_types) {
175 foreach $i (0..$#speced) {
176 $speced[$i] =~ s/\b$var\b/$uty/g ;
178 push(@tospec, @speced);
181 shift(@tospec) if $remove_poly; # remove fully polymorphic spec
184 $specty = shift(@tospec);
185 print ($data_or_inst ? "\{-# SPECIALIZE $data_inst_str $specty #-\}" : "$space\{-# SPECIALIZE $fun :: $specty");
186 while ($#tospec >= 0) {
187 $specty = shift(@tospec);
188 print ($data_or_inst ? "; \{-# SPECIALIZE $data_inst_str $specty #-\}" : ", $specty");
190 print ($data_or_inst ? "\n" : " #-}\n");
192 print "\{- NO_SPECS_GENERATED ", $data_or_inst ? $specty : $fun, " -\}\n";
193 print STDERR "Warning: No specs for GENERATE_SPECS pre-processing pragma:\n $_";
195 print $tysig if ! $data_or_inst;
197 print STDERR "Warning: GENERATE_SPECS pre-processing pragma ignored:\n $_";
205 close(INPIPE) || exit(1); # exit is so we reflect any errors.
210 # splits a list of types seperated by ,s but allowing ,s within ()s
214 local($type_str) = @_;
216 local(@chars) = split(//,$type_str);
224 while ($char = $chars[$cur]) {
225 if ($char eq ',' && $depth == 0) {
226 push(@types, join('', @chars[$start .. $cur-1])) if ($start < $cur);
228 } elsif ($char eq '(') {
230 } elsif ($char eq ')') {
236 push(@types, join('', @chars[$start .. $cur-1])) if ($start < $cur);
238 print STDERR "Error: GENERATE_SPECS pre-processing pragma has unbalanced ( )s\n$line\n";