This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Tweak the FEATURE_IS_ENABLED() macro to avoid a bug in the HP-UX compiler.
[perl5.git] / regen / feature.pl
index e63bd50..222215a 100755 (executable)
@@ -5,7 +5,8 @@
 #    lib/feature.pm
 #    feature.h
 #
-# from information hardcoded into this script.
+# from information hardcoded into this script and from two #defines
+# in perl.h.
 #
 # This script is normally invoked from regen.pl.
 
@@ -15,24 +16,30 @@ BEGIN {
 }
 use strict ;
 
-# (feature name) => (internal name, used in %^H)
+
+###########################################################################
+# Hand-editable data
+
+# (feature name) => (internal name, used in %^H and macro names)
 my %feature = (
     say             => 'say',
     state           => 'state',
     switch          => 'switch',
     evalbytes       => 'evalbytes',
+    array_base      => 'arybase',
     current_sub     => '__SUB__',
     unicode_eval    => 'unieval',
     unicode_strings => 'unicode',
+    fc              => 'fc',
 );
 
-# These work backwards--the presence of the hint elem disables the feature:
-my %default_feature = (
-    array_base      => 'noarybase',
-);
+# NOTE: If a feature is ever enabled in a non-contiguous range of Perl
+#       versions, any code below that uses %BundleRanges will have to
+#       be changed to account.
 
 my %feature_bundle = (
-     default =>        [keys %default_feature],
+     all     => [ keys %feature ],
+     default =>        [qw(array_base)],
     "5.9.5"  =>        [qw(say state switch array_base)],
     "5.10"   =>        [qw(say state switch array_base)],
     "5.11"   =>        [qw(say state switch unicode_strings array_base)],
@@ -40,12 +47,14 @@ my %feature_bundle = (
     "5.13"   =>        [qw(say state switch unicode_strings array_base)],
     "5.14"   =>        [qw(say state switch unicode_strings array_base)],
     "5.15"   =>        [qw(say state switch unicode_strings unicode_eval
-                   evalbytes current_sub)],
+                   evalbytes current_sub fc)],
     "5.16"   =>        [qw(say state switch unicode_strings unicode_eval
-                   evalbytes current_sub)],
+                   evalbytes current_sub fc)],
 );
 
+
 ###########################################################################
+# More data generated from the above
 
 my %UniqueBundles; # "say state switch" => 5.10
 my %Aliases;       #  5.12 => 5.11
@@ -58,15 +67,69 @@ for( sort keys %feature_bundle ) {
        $UniqueBundles{$value} = $_;
     }
 }
+                          # start   end
+my %BundleRanges; # say => ['5.10', '5.15'] # unique bundles for values
+for my $bund (
+    sort { $a eq 'default' ? -1 : $b eq 'default' ? 1 : $a cmp $b }
+         values %UniqueBundles
+) {
+    next if $bund =~ /[^\d.]/ and $bund ne 'default';
+    for (@{$feature_bundle{$bund}}) {
+       if (@{$BundleRanges{$_} ||= []} == 2) {
+           $BundleRanges{$_}[1] = $bund
+       }
+       else {
+           push @{$BundleRanges{$_}}, $bund;
+       }
+    }
+}
 
-###########################################################################
+my $HintShift;
+my $HintMask;
+my $Uni8Bit;
+
+open "perl.h", "perl.h" or die "$0 cannot open perl.h: $!";
+while (readline "perl.h") {
+    next unless /#\s*define\s+(HINT_FEATURE_MASK|HINT_UNI_8_BIT)/;
+    my $is_u8b = $1 =~ 8;
+    /(0x[A-Fa-f0-9]+)/ or die "No hex number in:\n\n$_\n ";
+    if ($is_u8b) {
+       $Uni8Bit = $1;
+    }
+    else {
+       my $hex = $HintMask = $1;
+       my $bits = sprintf "%b", oct $1;
+       $bits =~ /^0*1+(0*)\z/
+        or die "Non-contiguous bits in $bits (binary for $hex):\n\n$_\n ";
+       $HintShift = length $1;
+       my $bits_needed =
+           length sprintf "%b", scalar keys %UniqueBundles;
+       $bits =~ /1{$bits_needed}/
+           or die "Not enough bits (need $bits_needed)"
+                . " in $bits (binary for $hex):\n\n$_\n ";
+    }
+    if ($Uni8Bit && $HintMask) { last }
+}
+die "No HINT_FEATURE_MASK defined in perl.h" unless $HintMask;
+die "No HINT_UNI_8_BIT defined in perl.h"    unless $Uni8Bit;
+
+close "perl.h";
 
+my @HintedBundles =
+    ('default', grep !/[^\d.]/, sort values %UniqueBundles);
+
+
+###########################################################################
+# Open files to be generated
 
 my ($pm, $h) = map {
     open_new($_, '>', { by => 'regen/feature.pl' });
 } 'lib/feature.pm', 'feature.h';
 
 
+###########################################################################
+# Generate lib/feature.pm
+
 while (<DATA>) {
     last if /^FEATURES$/ ;
     print $pm $_ ;
@@ -82,7 +145,7 @@ sub longest {
     $long;
 }
 
-print $pm "my %feature = (\n";
+print $pm "our %feature = (\n";
 my $width = length longest keys %feature;
 for(sort { length $a <=> length $b } keys %feature) {
     print $pm "    $_" . " "x($width-length)
@@ -90,14 +153,6 @@ for(sort { length $a <=> length $b } keys %feature) {
 }
 print $pm ");\n\n";
 
-print $pm "my %default_feature = (\n";
-$width = length longest keys %default_feature;
-for(sort { length $a <=> length $b } keys %default_feature) {
-    print $pm "    $_" . " "x($width-length)
-       . " => 'feature_$default_feature{$_}',\n";
-}
-print $pm ");\n\n";
-
 print $pm "our %feature_bundle = (\n";
 $width = length longest values %UniqueBundles;
 for( sort { $UniqueBundles{$a} cmp $UniqueBundles{$b} }
@@ -113,6 +168,36 @@ for (sort keys %Aliases) {
        qq'\$feature_bundle{"$_"} = \$feature_bundle{"$Aliases{$_}"};\n';
 };
 
+print $pm <<EOPM;
+
+our \$hint_shift   = $HintShift;
+our \$hint_mask    = $HintMask;
+our \@hint_bundles = qw( @HintedBundles );
+
+# This gets set (for now) in \$^H as well as in %^H,
+# for runtime speed of the uc/lc/ucfirst/lcfirst functions.
+# See HINT_UNI_8_BIT in perl.h.
+our \$hint_uni8bit = $Uni8Bit;
+EOPM
+
+
+while (<DATA>) {
+    last if /^PODTURES$/ ;
+    print $pm $_ ;
+}
+
+select +(select($pm), $~ = 'PODTURES')[0];
+format PODTURES =
+  ^<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
+$::bundle, $::feature
+.
+
+for ('default', sort grep /\.\d[02468]/, keys %feature_bundle) {
+    $::bundle = ":$_";
+    $::feature = join ' ', @{$feature_bundle{$_}};
+    write $pm;
+    print $pm "\n";
+}
 
 while (<DATA>) {
     print $pm $_ ;
@@ -120,66 +205,139 @@ while (<DATA>) {
 
 read_only_bottom_close_and_rename($pm);
 
-my $HintShift;
 
-open "perl.h", "perl.h" or die "$0 cannot open perl.h: $!";
-perlh: {
-    while (readline "perl.h") {
-       next unless /#define\s+HINT_FEATURE_MASK/;
-       /(0x[A-Fa-f0-9]+)/ or die "No hex number in:\n\n$_\n ";
-       my $hex = $1;
-       my $bits = sprintf "%b", oct $1;
-       $bits =~ /^0*1+(0*)\z/
-        or die "Non-contiguous bits in $bits (binary for $hex):\n\n$_\n ";
-       $HintShift = length $1;
-       my $bits_needed =
-           length sprintf "%b", scalar keys %UniqueBundles;
-       $bits =~ /1{$bits_needed}/
-           or die "Not enough bits (need $bits_needed)"
-                . " in $bits (binary for $hex):\n\n$_\n";
-       last perlh;
-    }
-    die "No HINT_FEATURE_MASK defined in perl.h";
-}
-close "perl.h";
+###########################################################################
+# Generate feature.h
 
-my $first_bit = sprintf "0x%08x", 1 << $HintShift;
 print $h <<EOH;
 
 #if defined(PERL_CORE) || defined (PERL_EXT)
 
 #define HINT_FEATURE_SHIFT     $HintShift
 
-#define FEATURE_BUNDLE_DEFAULT 0
 EOH
 
 my $count;
-for (sort values %UniqueBundles) {
-    (my $key = $_) =~ y/.//d;
-    next if $key =~ /\D/;
-    print $h "#define FEATURE_BUNDLE_$key      ", ++$count, "\n";
+for (@HintedBundles) {
+    (my $key = uc) =~ y/.//d;
+    print $h "#define FEATURE_BUNDLE_$key      ", $count++, "\n";
 }
 
-print $h <<EOH;
+print $h <<'EOH';
 #define FEATURE_BUNDLE_CUSTOM  (HINT_FEATURE_MASK >> HINT_FEATURE_SHIFT)
 
+#define CURRENT_HINTS \
+    (PL_curcop == &PL_compiling ? PL_hints : PL_curcop->cop_hints)
+#define CURRENT_FEATURE_BUNDLE \
+    ((CURRENT_HINTS & HINT_FEATURE_MASK) >> HINT_FEATURE_SHIFT)
+
+/* Avoid using ... && Perl_feature_is_enabled(...) as that triggers a bug in
+   the HP-UX cc on PA-RISC */
+#define FEATURE_IS_ENABLED(name)                                       \
+       ((CURRENT_HINTS                                                  \
+          & HINT_LOCALIZE_HH)                                            \
+           ? Perl_feature_is_enabled(aTHX_ STR_WITH_LEN(name)) : FALSE)
+/* The longest string we pass in.  */
+EOH
+
+my $longest_internal_feature_name = longest values %feature;
+print $h <<EOL;
+#define MAX_FEATURE_LEN (sizeof("$longest_internal_feature_name")-1)
+
+EOL
+
+for (
+    sort { length $a <=> length $b } keys %feature
+) {
+    my($first,$last) =
+       map { (my $__ = uc) =~ y/.//d; $__ } @{$BundleRanges{$_}};
+    my $name = $feature{$_};
+    my $NAME = uc $name;
+    if ($last && $first eq 'DEFAULT') { #  â€˜>= DEFAULT’ warns
+       print $h <<EOI;
+#define FEATURE_$NAME\_IS_ENABLED \\
+    ( \\
+       CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_$last \\
+     || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \\
+        FEATURE_IS_ENABLED("$name")) \\
+    )
+
+EOI
+    }
+    elsif ($last) {
+       print $h <<EOH3;
+#define FEATURE_$NAME\_IS_ENABLED \\
+    ( \\
+       (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_$first && \\
+        CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_$last) \\
+     || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \\
+        FEATURE_IS_ENABLED("$name")) \\
+    )
+
+EOH3
+    }
+    else {
+       print $h <<EOH4;
+#define FEATURE_$NAME\_IS_ENABLED \\
+    ( \\
+       CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_$first \\
+     || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \\
+        FEATURE_IS_ENABLED("$name")) \\
+    )
+
+EOH4
+    }
+}
+
+print $h <<EOH;
+
 #endif /* PERL_CORE or PERL_EXT */
+
+#ifdef PERL_IN_OP_C
+PERL_STATIC_INLINE void
+S_enable_feature_bundle(pTHX_ SV *ver)
+{
+    SV *comp_ver = sv_newmortal();
+    PL_hints = (PL_hints &~ HINT_FEATURE_MASK)
+            | (
 EOH
 
+for (reverse @HintedBundles[1..$#HintedBundles]) { # skip default
+    my $numver = $_;
+    if ($numver eq '5.10') { $numver = '5.009005' } # special case
+    else                  { $numver =~ s/\./.0/  } # 5.11 => 5.011
+    (my $macrover = $_) =~ y/.//d;
+    print $h <<"    EOK";
+                 (sv_setnv(comp_ver, $numver),
+                  vcmp(ver, upg_version(comp_ver, FALSE)) >= 0)
+                       ? FEATURE_BUNDLE_$macrover :
+    EOK
+}
+
+print $h <<EOJ;
+                         FEATURE_BUNDLE_DEFAULT
+              ) << HINT_FEATURE_SHIFT;
+    /* special case */
+    assert(PL_curcop == &PL_compiling);
+    if (FEATURE_UNICODE_IS_ENABLED) PL_hints |=  HINT_UNI_8_BIT;
+    else                           PL_hints &= ~HINT_UNI_8_BIT;
+}
+#endif /* PERL_IN_OP_C */
+EOJ
+
 read_only_bottom_close_and_rename($h);
 
+
+###########################################################################
+# Template for feature.pm
+
 __END__
 package feature;
 
-our $VERSION = '1.25';
+our $VERSION = '1.27';
 
 FEATURES
 
-# This gets set (for now) in $^H as well as in %^H,
-# for runtime speed of the uc/lc/ucfirst/lcfirst functions.
-# See HINT_UNI_8_BIT in perl.h.
-our $hint_uni8bit = 0x00000800;
-
 # TODO:
 # - think about versioned features (use feature switch => 2)
 
@@ -237,7 +395,8 @@ has lexical effect.
     }
     say "Yet it is here.";
 
-C<no feature> with no features specified will turn off all features.
+C<no feature> with no features specified will reset to the default group.  To
+disable I<all> features (an unusual request!) use C<no feature ':all'>.
 
 =head1 AVAILABLE FEATURES
 
@@ -264,7 +423,7 @@ This feature is available starting with Perl 5.10.
 C<use feature 'switch'> tells the compiler to enable the Perl 6
 given/when construct.
 
-See L<perlsyn/"Switch statements"> for details.
+See L<perlsyn/"Switch Statements"> for details.
 
 This feature is available starting with Perl 5.10.
 
@@ -284,8 +443,8 @@ L<perlunicode/The "Unicode Bug"> for details.)  For this reason, if you are
 potentially using Unicode in your program, the
 C<use feature 'unicode_strings'> subpragma is B<strongly> recommended.
 
-This feature is available starting with Perl 5.12, but was not fully
-implemented until Perl 5.14.
+This feature is available starting with Perl 5.12; was almost fully
+implemented in Perl 5.14; and extended in Perl 5.16 to cover C<quotemeta>.
 
 =head2 The 'unicode_eval' and 'evalbytes' features
 
@@ -351,6 +510,15 @@ This feature is available under this name starting with Perl 5.16.  In
 previous versions, it was simply on all the time, and this pragma knew
 nothing about it.
 
+=head2 The 'fc' feature
+
+C<use feature 'fc'> tells the compiler to enable the C<fc> function,
+which implements Unicode casefolding.
+
+See L<perlfunc/fc> for details.
+
+This feature is available from Perl 5.16 onwards.
+
 =head1 FEATURE BUNDLES
 
 It's possible to load multiple features together, using
@@ -363,17 +531,7 @@ The following feature bundles are available:
 
   bundle    features included
   --------- -----------------
-  :default  array_base
-
-  :5.10     say state switch array_base
-
-  :5.12     say state switch unicode_strings array_base
-
-  :5.14     say state switch unicode_strings array_base
-
-  :5.16     say state switch unicode_strings
-            unicode_eval evalbytes current_sub
-
+PODTURES
 The C<:default> bundle represents the feature set that is enabled before
 any C<use feature> or C<no feature> declaration.
 
@@ -407,7 +565,7 @@ the C<use VERSION> construct.  That is,
 
 will do an implicit
 
-    no feature;
+    no feature ':all';
     use feature ':5.10';
 
 and so on.  Note how the trailing sub-version
@@ -429,44 +587,42 @@ bundle is automatically loaded instead.
 
 sub import {
     my $class = shift;
-    if (@_ == 0) {
+
+    if (!@_) {
         croak("No features specified");
     }
-    while (@_) {
-        my $name = shift(@_);
-        if (substr($name, 0, 1) eq ":") {
-            my $v = substr($name, 1);
-            if (!exists $feature_bundle{$v}) {
-                $v =~ s/^([0-9]+)\.([0-9]+).[0-9]+$/$1.$2/;
-                if (!exists $feature_bundle{$v}) {
-                    unknown_feature_bundle(substr($name, 1));
-                }
-            }
-            unshift @_, @{$feature_bundle{$v}};
-            next;
-        }
-        if (!exists $feature{$name}) {
-         if (!exists $default_feature{$name}) {
-            unknown_feature($name);
-         }
-         delete $^H{$default_feature{$name}}; next;
-        }
-        $^H{$feature{$name}} = 1;
-        $^H |= $hint_uni8bit if $name eq 'unicode_strings';
-    }
+
+    __common(1, @_);
 }
 
 sub unimport {
     my $class = shift;
 
-    # A bare C<no feature> should disable *all* features
+    # A bare C<no feature> should reset to the default bundle
     if (!@_) {
-        delete @^H{ values(%feature) };
-        $^H &= ~ $hint_uni8bit;
-       @^H{ values(%default_feature) } = (1) x keys %default_feature;
-        return;
+       $^H &= ~($hint_uni8bit|$hint_mask);
+       return;
     }
 
+    __common(0, @_);
+}
+
+
+sub __common {
+    my $import = shift;
+    my $bundle_number = $^H & $hint_mask;
+    my $features = $bundle_number != $hint_mask
+       && $feature_bundle{$hint_bundles[$bundle_number >> $hint_shift]};
+    if ($features) {
+       # Features are enabled implicitly via bundle hints.
+       # Delete any keys that may be left over from last time.
+       delete @^H{ values(%feature) };
+       $^H |= $hint_mask;
+       for (@$features) {
+           $^H{$feature{$_}} = 1;
+           $^H |= $hint_uni8bit if $_ eq 'unicode_strings';
+       }
+    }
     while (@_) {
         my $name = shift;
         if (substr($name, 0, 1) eq ":") {
@@ -480,13 +636,13 @@ sub unimport {
             unshift @_, @{$feature_bundle{$v}};
             next;
         }
-        if (!exists($feature{$name})) {
-         if (!exists $default_feature{$name}) {
+        if (!exists $feature{$name}) {
             unknown_feature($name);
-         }
-         $^H{$default_feature{$name}} = 1; next;
         }
-        else {
+       if ($import) {
+           $^H{$feature{$name}} = 1;
+           $^H |= $hint_uni8bit if $name eq 'unicode_strings';
+       } else {
             delete $^H{$feature{$name}};
             $^H &= ~ $hint_uni8bit if $name eq 'unicode_strings';
         }