From 69bcf1d3d727aba8df8f279ed93ee56eea0cd15f Mon Sep 17 00:00:00 2001 From: Father Chrysostomos Date: Wed, 21 Dec 2011 22:46:41 -0800 Subject: [PATCH] Create regen/feature.pl This script generates lib/feature.pm. Soon it will be made to gener- ate other files, too. --- Cross/Makefile-cross-SH | 4 +- MANIFEST | 1 + Makefile.SH | 4 +- lib/feature.pm | 38 ++-- regen.pl | 1 + regen/feature.pl | 461 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 488 insertions(+), 21 deletions(-) create mode 100644 regen/feature.pl diff --git a/Cross/Makefile-cross-SH b/Cross/Makefile-cross-SH index 4e72adc..eaa1057 100644 --- a/Cross/Makefile-cross-SH +++ b/Cross/Makefile-cross-SH @@ -848,6 +848,7 @@ CHMOD_W = chmod +w # opcode.pl: opcode.h opnames.h pp_proto.h # regcomp.pl: regnodes.h # warnings.pl: warnings.h lib/warnings.pm +# feature.pl: lib/feature.pl # The correct versions should be already supplied with the perl kit, # in case you don't have perl available. # To force them to be regenerated, run @@ -856,7 +857,8 @@ CHMOD_W = chmod +w # (make regen_headers is kept for backwards compatibility) AUTOGEN_FILES = opcode.h opnames.h pp_proto.h proto.h embed.h embedvar.h \ - perlapi.h perlapi.c regnodes.h warnings.h lib/warnings.pm + perlapi.h perlapi.c regnodes.h warnings.h lib/warnings.pm \ + lib/feature.pm .PHONY: regen_headers regen_all diff --git a/MANIFEST b/MANIFEST index 9b0067c..b9d796e 100644 --- a/MANIFEST +++ b/MANIFEST @@ -4822,6 +4822,7 @@ regcomp.h Private declarations for above regcomp.sym Data for regnodes.h regen/embed_lib.pl Reads embed.fnc and regen/opcodes regen/embed.pl Produces {embed,embedvar,proto}.h +regen/feature.pl Generates feature.pm regen/keywords.pl Program to write keywords.h regen/mg_vtable.pl generate mg_vtable.h regen/mk_PL_charclass.pl Populate the PL_charclass table diff --git a/Makefile.SH b/Makefile.SH index 0bc9633..4791e5c 100755 --- a/Makefile.SH +++ b/Makefile.SH @@ -1153,6 +1153,7 @@ CHMOD_W = chmod +w # opcode.pl: opcode.h opnames.h pp_proto.h # regcomp.pl: regnodes.h # warnings.pl: warnings.h lib/warnings.pm +# feature.pl: lib/feature.pm # The correct versions should be already supplied with the perl kit, # in case you don't have perl available. # To force them to be regenerated, run @@ -1161,7 +1162,8 @@ CHMOD_W = chmod +w # (make regen_headers is kept for backwards compatibility) AUTOGEN_FILES = opcode.h opnames.h pp_proto.h proto.h embed.h embedvar.h \ - perlapi.h perlapi.c regnodes.h warnings.h lib/warnings.pm + perlapi.h perlapi.c regnodes.h warnings.h lib/warnings.pm \ + lib/feature.pm .PHONY: regen_headers regen_all diff --git a/lib/feature.pm b/lib/feature.pm index c482e5b..a3cfdbe 100644 --- a/lib/feature.pm +++ b/lib/feature.pm @@ -1,8 +1,12 @@ +# -*- buffer-read-only: t -*- +# !!!!!!! DO NOT EDIT THIS FILE !!!!!!! +# This file is built by regen/feature.pl. +# Any changes made here will be lost! + package feature; our $VERSION = '1.25'; -# (feature name) => (internal name, used in %^H) my %feature = ( say => 'feature_say', state => 'feature_state', @@ -13,33 +17,27 @@ my %feature = ( unicode_strings => 'feature_unicode', ); -# These work backwards--the presence of the hint elem disables the feature: my %default_feature = ( - array_base => 'feature_no$[', + array_base => 'feature_no$[', ); -# 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; - -# NB. the latest bundle must be loaded by the -E switch (see toke.c) - our %feature_bundle = ( - "default" => [keys %default_feature], - "5.10" => [qw(say state switch array_base)], - "5.11" => [qw(say state switch unicode_strings array_base)], - "5.15" => [qw(say state switch unicode_strings unicode_eval - evalbytes current_sub)], + "5.10" => [qw(array_base say state switch)], + "5.11" => [qw(array_base say state switch unicode_strings)], + "5.15" => [qw(current_sub evalbytes say state switch unicode_eval unicode_strings)], + "5.9.5" => [qw(array_base say state switch)], + "default" => [qw(array_base)], ); + # Each of these is the same as the previous bundle -for(12...14, 16) { +for (12,13,14,16) { $feature_bundle{"5.$_"} = $feature_bundle{"5.".($_-1)} } - -# special case -$feature_bundle{"5.9.5"} = $feature_bundle{"5.10"}; +# 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) @@ -372,3 +370,5 @@ sub croak { } 1; + +# ex: set ro: diff --git a/regen.pl b/regen.pl index 1f2a583..62dc820 100644 --- a/regen.pl +++ b/regen.pl @@ -23,6 +23,7 @@ reentr.pl regcomp.pl warnings.pl embed.pl +feature.pl ); my $tap = $ARGV[0] && $ARGV[0] eq '--tap' ? '# ' : ''; diff --git a/regen/feature.pl b/regen/feature.pl new file mode 100644 index 0000000..3e20574 --- /dev/null +++ b/regen/feature.pl @@ -0,0 +1,461 @@ +#!/usr/bin/perl +# +# Regenerate (overwriting only if changed): +# +# lib/feature.pm +# +# from information hardcoded into this script. +# +# This script is normally invoked from regen.pl. + +BEGIN { + require 'regen/regen_lib.pl'; + push @INC, './lib'; +} +use strict ; + +# (feature name) => (internal name, used in %^H) +my %feature = ( + say => 'feature_say', + state => 'feature_state', + switch => 'feature_switch', + evalbytes => 'feature_evalbytes', + current_sub => 'feature___SUB__', + unicode_eval => 'feature_unieval', + unicode_strings => 'feature_unicode', +); + +# These work backwards--the presence of the hint elem disables the feature: +my %default_feature = ( + array_base => 'feature_no$[', +); + +my %feature_bundle = ( + default => [keys %default_feature], + "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)], + "5.12" => [qw(say state switch unicode_strings array_base)], + "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)], + "5.16" => [qw(say state switch unicode_strings unicode_eval + evalbytes current_sub)], +); + +########################################################################### + + +my ($pm) = map { + open_new($_, '>', { by => 'regen/feature.pl' }); +} 'lib/feature.pm'; + + +while () { + last if /^FEATURES$/ ; + print $pm $_ ; +} + +sub longest { + my $long; + for(@_) { + if (!defined $long or length $long < length) { + $long = $_; + } + } + $long; +} + +print $pm "my %feature = (\n"; +my $width = length longest keys %feature; +for(sort { length $a <=> length $b } keys %feature) { + print $pm " $_" . " "x($width-length) . " => '$feature{$_}',\n"; +} +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) + . " => '$default_feature{$_}',\n"; +} +print $pm ");\n\n"; + +print $pm "our %feature_bundle = (\n"; +my $prevkey; +my $prev; +my @same; +$width = length longest keys %feature_bundle; +for( sort keys %feature_bundle ) { + my $value = join(' ', sort @{$feature_bundle{$_}}); + if (/^5\.\d\d\z/ && $prevkey + && substr($_,-2) - substr($prevkey,-2) == 1 && $value eq $prev) { + push @same, $_; + $prevkey = $_; + next; + } + if(/^5\.\d\d\z/) { + $prev = $value; + $prevkey = $_; + } + print $pm qq' "$_"' . " "x($width-length) . qq' => [qw($value)],\n'; +} +print $pm ");\n\n"; + +print $pm " +# Each of these is the same as the previous bundle +for (", join(',',map /\.(.*)/, @same), ') { + $feature_bundle{"5.$_"} = $feature_bundle{"5.".($_-1)} +}'; + + +while () { + print $pm $_ ; +} + +read_only_bottom_close_and_rename($pm); + +__END__ +package feature; + +our $VERSION = '1.25'; + +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) + +=head1 NAME + +feature - Perl pragma to enable new features + +=head1 SYNOPSIS + + use feature qw(say switch); + given ($foo) { + when (1) { say "\$foo == 1" } + when ([2,3]) { say "\$foo == 2 || \$foo == 3" } + when (/^a[bc]d$/) { say "\$foo eq 'abd' || \$foo eq 'acd'" } + when ($_ > 100) { say "\$foo > 100" } + default { say "None of the above" } + } + + use feature ':5.10'; # loads all features available in perl 5.10 + + use v5.10; # implicitly loads :5.10 feature bundle + +=head1 DESCRIPTION + +It is usually impossible to add new syntax to Perl without breaking +some existing programs. This pragma provides a way to minimize that +risk. New syntactic constructs, or new semantic meanings to older +constructs, can be enabled by C, and will be parsed +only when the appropriate feature pragma is in scope. (Nevertheless, the +C prefix provides access to all Perl keywords, regardless of this +pragma.) + +=head2 Lexical effect + +Like other pragmas (C, for example), features have a lexical +effect. C will only make the feature "foo" available +from that point to the end of the enclosing block. + + { + use feature 'say'; + say "say is available here"; + } + print "But not here.\n"; + +=head2 C + +Features can also be turned off by using C. This too +has lexical effect. + + use feature 'say'; + say "say is available here"; + { + no feature 'say'; + print "But not here.\n"; + } + say "Yet it is here."; + +C with no features specified will turn off all features. + +=head1 AVAILABLE FEATURES + +=head2 The 'say' feature + +C tells the compiler to enable the Perl 6 style +C function. + +See L for details. + +This feature is available starting with Perl 5.10. + +=head2 The 'state' feature + +C tells the compiler to enable C +variables. + +See L for details. + +This feature is available starting with Perl 5.10. + +=head2 The 'switch' feature + +C tells the compiler to enable the Perl 6 +given/when construct. + +See L for details. + +This feature is available starting with Perl 5.10. + +=head2 The 'unicode_strings' feature + +C tells the compiler to use Unicode semantics +in all string operations executed within its scope (unless they are also +within the scope of either C or C). The same applies +to all regular expressions compiled within the scope, even if executed outside +it. + +C tells the compiler to use the traditional +Perl semantics wherein the native character set semantics is used unless it is +clear to Perl that Unicode is desired. This can lead to some surprises +when the behavior suddenly changes. (See +L for details.) For this reason, if you are +potentially using Unicode in your program, the +C subpragma is B recommended. + +This feature is available starting with Perl 5.12, but was not fully +implemented until Perl 5.14. + +=head2 The 'unicode_eval' and 'evalbytes' features + +Under the C feature, Perl's C function, when passed a +string, will evaluate it as a string of characters, ignoring any +C declarations. C exists to declare the encoding of +the script, which only makes sense for a stream of bytes, not a string of +characters. Source filters are forbidden, as they also really only make +sense on strings of bytes. Any attempt to activate a source filter will +result in an error. + +The C feature enables the C keyword, which evaluates +the argument passed to it as a string of bytes. It dies if the string +contains any characters outside the 8-bit range. Source filters work +within C: they apply to the contents of the string being +evaluated. + +Together, these two features are intended to replace the historical C +function, which has (at least) two bugs in it, that cannot easily be fixed +without breaking existing programs: + +=over + +=item * + +C behaves differently depending on the internal encoding of the +string, sometimes treating its argument as a string of bytes, and sometimes +as a string of characters. + +=item * + +Source filters activated within C leak out into whichever I +scope is currently being compiled. To give an example with the CPAN module +L: + + BEGIN { eval "use Semi::Semicolons; # not filtered here " } + # filtered here! + +C fixes that to work the way one would expect: + + use feature "evalbytes"; + BEGIN { evalbytes "use Semi::Semicolons; # filtered " } + # not filtered + +=back + +These two features are available starting with Perl 5.16. + +=head2 The 'current_sub' feature + +This provides the C<__SUB__> token that returns a reference to the current +subroutine or C outside of a subroutine. + +This feature is available starting with Perl 5.16. + +=head2 The 'array_base' feature + +This feature supports the legacy C<$[> variable. See L and +L. It is on by default but disabled under C (see +L, below). + +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. + +=head1 FEATURE BUNDLES + +It's possible to load multiple features together, using +a I. The name of a feature bundle is prefixed with +a colon, to distinguish it from an actual feature. + + use feature ":5.10"; + +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 + +The C<:default> bundle represents the feature set that is enabled before +any C or C declaration. + +Specifying sub-versions such as the C<0> in C<5.14.0> in feature bundles has +no effect. Feature bundles are guaranteed to be the same for all sub-versions. + + use feature ":5.14.0"; # same as ":5.14" + use feature ":5.14.1"; # same as ":5.14" + +=head1 IMPLICIT LOADING + +Instead of loading feature bundles by name, it is easier to let Perl do +implicit loading of a feature bundle for you. + +There are two ways to load the C pragma implicitly: + +=over 4 + +=item * + +By using the C<-E> switch on the Perl command-line instead of C<-e>. +That will enable the feature bundle for that version of Perl in the +main compilation unit (that is, the one-liner that follows C<-E>). + +=item * + +By explicitly requiring a minimum Perl version number for your program, with +the C construct. That is, + + use v5.10.0; + +will do an implicit + + no feature; + use feature ':5.10'; + +and so on. Note how the trailing sub-version +is automatically stripped from the +version. + +But to avoid portability warnings (see L), you may prefer: + + use 5.010; + +with the same effect. + +If the required version is older than Perl 5.10, the ":default" feature +bundle is automatically loaded instead. + +=back + +=cut + +sub import { + my $class = shift; + if (@_ == 0) { + 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'; + } +} + +sub unimport { + my $class = shift; + + # A bare C should disable *all* features + if (!@_) { + delete @^H{ values(%feature) }; + $^H &= ~ $hint_uni8bit; + @^H{ values(%default_feature) } = (1) x keys %default_feature; + return; + } + + 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); + } + $^H{$default_feature{$name}} = 1; next; + } + else { + delete $^H{$feature{$name}}; + $^H &= ~ $hint_uni8bit if $name eq 'unicode_strings'; + } + } +} + +sub unknown_feature { + my $feature = shift; + croak(sprintf('Feature "%s" is not supported by Perl %vd', + $feature, $^V)); +} + +sub unknown_feature_bundle { + my $feature = shift; + croak(sprintf('Feature bundle "%s" is not supported by Perl %vd', + $feature, $^V)); +} + +sub croak { + require Carp; + Carp::croak(@_); +} + +1; -- 1.8.3.1