Skip to content
Permalink
Browse files

Changed handling of revision modifiers

A modifier is a text suffix following version revision in the version
string. I.e. PREVIEW is a modifier in v6.e.PREVIEW string.

Modifiers can be flagged as required or deprecated or not flagged at
all. For example:

d TEST -TESTDEPR
e !PREVIEW

TESTDEPR is deprecated. While use of 'v6.e' will cause the language to
panic because only 'v6.e.PREVIEW' form is allowed. TEST is a plain
optional modifier.

Proposed use of requirement/deprecation during a default language
revision switch:

1. PREVIEW is required until revision is released.
2. PREVIEW is plain optional for 2-3 months after revision release to
allow graceful transition of modules.
3. PREVIEW is deprecated for another 3-4 months.
  • Loading branch information...
vrurg committed May 21, 2019
1 parent 1aef5d3 commit 2d7e7aa456b3ed589a970f189fd871a525e476a4
@@ -3,8 +3,9 @@ use QRegex;
use Perl6::Optimizer;

class Perl6::Compiler is HLL::Compiler {
has $!language_version;
has $!can_language_versions;
has $!language_version; # Default language version in form 6.c
has $!language_revisions; # Hash of language revision letters. See gen/<vm>/main-version.nqp
has $!can_language_versions; # List of valid language version

method compilation-id() {
my class IDHolder { }
@@ -33,6 +34,11 @@ class Perl6::Compiler is HLL::Compiler {
?? $!can_language_versions
!! ($!can_language_versions := self.config<can-language-versions>)
}
method language_revisions() {
$!language_revisions
?? $!language_revisions
!! ($!language_revisions := self.config<language-revisions>)
}

method command_eval(*@args, *%options) {
if nqp::existskey(%options, 'doc') && !%options<doc> {
@@ -531,13 +531,28 @@ class Perl6::World is HLL::World {
) == -1
}

method !check-for-PREVIEW ($ver-match, $rev, $default_rev, $rev_mod) {
$ver-match.PRECURSOR.worry('PREVIEW modificator is used with released specification 6.' ~ $rev)
if nqp::isle_s($rev, $default_rev) && nqp::iseq_s($rev_mod, 'PREVIEW');
method !check-version-modifier($ver-match, $rev, $modifier, $comp) {
my %lang_rev := $comp.language_revisions;

$ver-match.PRECURSOR.worry(
'Language specification 6.' ~ $rev ~ ' is not released yet, PREVIEW modificator is expected'
) if nqp::isgt_s($rev, $default_rev) && nqp::isne_s($rev_mod, 'PREVIEW');
unless nqp::existskey(%lang_rev, $rev) &&
(!$modifier || nqp::existskey(%lang_rev{$rev}<mods>, $modifier)) {
$ver-match.typed_panic: 'X::Language::Unsupported', version => ~$ver-match;
}

# See if requested revision is not supported without a modifier. Most likely it'll be PREVIEW modifier for
# unreleased revisions.
if nqp::existskey(%lang_rev{$rev}, 'require') {
if nqp::iseq_s(%lang_rev{$rev}<require>, $modifier) {
return;
}
$ver-match.typed_panic: 'X::Language::ModRequired',
version => ~$ver-match,
modifier => %lang_rev{$rev}<require>;
}

if %lang_rev{$rev}<mods>{$modifier}<deprecate> {
$ver-match.PRECURSOR.worry("$modifier modifier is deprecated for Perl 6.$rev");
}
}

method load-lang-ver($ver-match, $comp) {
@@ -549,12 +564,11 @@ class Perl6::World is HLL::World {
my $default_rev := nqp::substr($comp.config<language-version>, 2, 1);

# Do we have dot-splitted version string?
if (@vparts > 1) || ($version eq 'v6') {
if ((@vparts > 1) && nqp::iseq_s(@vparts[0], 'v6')) || ($version eq 'v6') {
my $revision := @vparts[1] || $default_rev;
my $lang_ver := '6.' ~ $revision;

self."!check-for-PREVIEW"($ver-match, $revision, $default_rev, @vparts[2] || '')
if ($revision eq 'c') || ($lang_ver eq $comp.config<language-version>);
self."!check-version-modifier"($ver-match, $revision, @vparts[2] || '', $comp);

$comp.set_language_version: $lang_ver;
# fast-path the common cases
@@ -577,7 +591,7 @@ class Perl6::World is HLL::World {
my $rev := $vWant.parts.AT-POS(1);
my str $rev_mod := $vWant.parts.elems > 2 ?? $vWant.parts.AT-POS(2) !! '';

self."!check-for-PREVIEW"($ver-match, $rev, $default_rev, $rev_mod);
self."!check-version-modifier"($ver-match, $rev, $rev_mod, $comp);

for $comp.can_language_versions -> $can-ver {
next unless $vWant.ACCEPTS: my $vCan := $Version.new: $can-ver;
@@ -3020,6 +3020,13 @@ my class X::Language::TooLate is Exception {
"Too late to switch language version. Must be used as the very first statement."
}
}
my class X::Language::ModRequired is Exception {
has $.version;
has $.modifier;
method message() {
"Perl $.version requires modifier $.modifier"
}
}

my class X::Proc::Unsuccessful is Exception {
has $.proc;
@@ -74,6 +74,62 @@ sub configure_backends {
}
}

sub parse_lang_specs {
my $self = shift;

my $config = $self->{config};
my $tmpl = 'PERL6_SPECS';
open my $sh, "<", $self->template_file_path( $tmpl, required => 1 )
or self->sorry("Can't open $tmpl: $!");

my @specs; # Array to preserve the order or specs
my $ln = 0;
my %flag_name = ( '-' => 'deprecate', '!' => 'require', );
my $fail = sub {
$self->sorry( "$tmpl($ln): " . join( "", @_ ) );
};
for my $line (<$sh>) {
$ln++;
chomp $line;
$line =~ s/\h*#.*$//; # Cut off comment
next unless $line;
if ( $line =~ s/^\h*(?<default>\*)?(?<letter>[c-z])\b// ) {
my $letter = $+{letter};
if ( $+{default} ) {
$fail->("duplicate default spec") if $config->{lang_spec};
$config->{lang_spec} = $letter;
}
my @def = ($letter);
push @specs, \@def;
my @mods; # Array to preserve the order of modificators
while ($line) {
unless ( $line =~ s/^\h+// ) {
$fail->("whitespace is missing");
}
next unless $line;
if ( $line =~ s/^(?<flags>[\!\-]+)?(?<mod>\w+)\b// ) {
my ( $mod, $flag_str ) = @+{qw<mod flags>};
$flag_str //= "";
my %flags;
%flags = map { $flag_name{$_} => 1 } split( "", $flag_str );
push @mods, [ $mod, \%flags ];
}
else {
$fail->("expected a modificator");
}
}
push @def, @mods;
}
else {
$fail->("expected a revision letter");
}
}

$self->{perl6_specs} = \@specs;

close $sh;
}

sub configure_misc {
my $self = shift;
my $config = $self->{config};
@@ -83,23 +139,24 @@ sub configure_misc {
split( ' ',
slurp( $self->template_file_path( 'NQP_REVISION', required => 1, ) ) );

# Get specs from PERL6_SPECS template
my $spec_line = sub {
my @elems = split ' ', shift;
if ( $elems[0] =~ s/^\*// ) {
$config->{lang_spec} = $elems[0];
}
return \@elems;
};

$config->{perl6_specs} = [
map { $spec_line->($_) }
grep { s/\s*#.*$//; length }
split(
/\n/s,
slurp( $self->template_file_path( 'PERL6_SPECS', required => 1, ) )
)
];
$self->parse_lang_specs;

#my $spec_line = sub {
# my @elems = split ' ', shift;
# if ( $elems[0] =~ s/^\*// ) {
# $config->{lang_spec} = $elems[0];
# }
# return \@elems;
#};

#$self->{perl6_specs} = [
# map { $spec_line->($_) }
# grep { s/\s*#.*$//; length }
# split(
# /\n/s,
# slurp( $self->template_file_path( 'PERL6_SPECS', required => 1, ) )
# )
#];

# Get version info from VERSION template and git.
my $VERSION = slurp( $self->template_file_path( 'VERSION', required => 1, ) );
@@ -315,7 +372,7 @@ sub configure_js_backend {
# Returns all active language specification entries except for .c
sub perl6_specs {
my $self = shift;
return grep { $_->[0] ne 'c' } @{ $self->cfg('perl6_specs') };
return grep { $_->[0] ne 'c' } @{ $self->{perl6_specs} };
}

sub post_active_backends {
@@ -487,9 +544,9 @@ sub _specs_iterate {
if ( $params{with_mods} && @$spec > 1 ) {
for my $mod ( @$spec[ 1 .. $#$spec ] ) {
my %mod = (
spec_mod => $mod,
spec_dot_mod => ".$mod",
spec_with_mod => "$spec_char.$mod",
spec_mod => $mod->[0],
spec_dot_mod => ".$mod->[0]",
spec_with_mod => "$spec_char.$mod->[0]",
);
my $mod_s = $cfg->push_ctx(
{
@@ -1,5 +1,9 @@
# [*]version [suffix]
# [*]version [modifier]
# * defines the current spec
# modifiers can be prefixed with the following flags:
# ! required. Means that revision cannot be used without this modifier.
# - deprecated. Use of this modifier will result in a language warning.
c
*d PREVIEW # TODO: It's about time to drop PREVIEW
e PREVIEW
# TEST and TESTDEPR modifiers are to be kept for roast.
*d -PREVIEW TEST -TESTDEPR # TODO: It's about time to drop PREVIEW
e !PREVIEW
@@ -4,8 +4,37 @@ sub hll-config($config) {
$config<release-number> := '@release@';
$config<codename> := '@codename@';
$config<language-version> := '6.@lang_spec@';
# Though language-revisions key provides more information
# can-language-versions is kept for speeding up
# Perl6::Compiler.can_langauge_versions method
$config<can-language-versions>
:= nqp::list( '6.c'@for_specmods(, '6.@spec_with_mod@')@ );
$config<language-revisions> := nqp::hash(
'c', nqp::hash(),
@perl(
# This code is not re-usable, makes no sense to write a dedicated macro
for my $spec ( $cfg->perl6_specs ) {
my $letter = $spec->[0];
my $pfx = " ";
$out .= "$pfx'$letter', nqp::hash(\n";
my $require = '';
my $mods = "";
for my $mod ( @$spec[1..$#$spec] ) {
$mods = "$pfx 'mods', nqp::hash(\n" unless $mods;
$mods .= "$pfx '$mod->[0]', nqp::hash(\n";
if ( $mod->[1]{require} ) {
$require = "$pfx 'require', '$mod->[0]',\n";
}
for my $flag ( keys %{$mod->[1]} ) {
$mods .= "$pfx '$flag', " . ($mod->[1]{$flag} ? "1" : "0") . ",\n"
}
$mods .= "$pfx ), # modificator $mod->[0]\n";
}
$mods .= "$pfx ),\n";
$out .= "$require$mods$pfx), # revision $letter\n";
}
)@
);
$config<prefix> := '@prefix@';
$config<libdir> := '@libdir@';
$config<source-digest> := '@source_digest()@';

0 comments on commit 2d7e7aa

Please sign in to comment.
You can’t perform that action at this time.