package DateTime::Format::Natural::Lang::EN;

use strict;
use warnings;
use base qw(DateTime::Format::Natural::Lang::Base);
#use boolean qw(true false);
use constant true  => 1;
use constant false => 0;

use DateTime::Format::Natural::Helpers qw(%flag);

our $VERSION = '1.20';

our (%init,
     %timespan,
     %RE,
     %data_weekdays,
     %data_weekdays_abbrev,
     @data_weekdays_all,
     %data_months,
     %data_months_abbrev,
     @data_months_all,
     %data_conversion,
     %data_helpers,
     %extended_checks,
     %grammar);

%init = (tokens => sub {});
%timespan = (literal => 'to');

%RE = (number    => qr/^(\d+)$/,
       year      => qr/^(\d{4})$/,
       time      => qr/^((?:\d{1,2})(?:\:\d{2})?)$/,
       time_am   => qr/^((?:\d{1,2})(?:\:\d{2})?)(?:am)?$/,
       time_pm   => qr/^((?:\d{1,2})(?:\:\d{2})?)pm$/,
       time_full => qr/^(\d{1,2}\:\d{2}\:\d{2})$/,
       day       => qr/^(\d+)(?:st|nd|rd|th)?$/,
       monthday  => qr/^(\d{1,2})(?:st|nd|rd|th)?$/);
{
    my $i = 1;

    %data_weekdays = map {
        $_ => $i++
    } qw(Monday Tuesday Wednesday Thursday Friday Saturday Sunday);
    %data_weekdays_abbrev = map {
        substr($_, 0, 3) => $_
    } keys %data_weekdays;

    @data_weekdays_all = (keys %data_weekdays, keys %data_weekdays_abbrev);

    my $days_re = join '|', @data_weekdays_all;
    $RE{weekday} = qr/^($days_re)$/i;

    $days_re = join '|', map "${_}s?", @data_weekdays_all;
    $RE{weekdays} = qr/^($days_re)$/i;

    $i = 1;

    %data_months = map {
        $_ => $i++
    } qw(January February March April May June July August September
         October November December);
    %data_months_abbrev = map {
        substr($_, 0, 3) => $_
    } keys %data_months;

    @data_months_all = (keys %data_months, keys %data_months_abbrev);

    my $months_re = join '|', @data_months_all;
    $RE{month} = qr/^($months_re)$/i;

    %data_conversion = (
        last_this_next    => { do { $i = -1; map { $_ => $i++ } qw(last this next)           } },
        yes_today_tom     => { do { $i = -1; map { $_ => $i++ } qw(yesterday today tomorrow) } },
        noon_midnight     => { noon => 12, midnight => 0                                       },
        morn_aftern_even  => { do { $i = 0; map { $_ => $i++ } qw(morning afternoon evening) } },
        before_after_from => { before => -1, after => 1, from => 1                             },
    );

    %data_helpers = (
        suffix      => qr/s$/,
        normalize   => sub { ${$_[0]} = ucfirst lc ${$_[0]} },
        abbreviated => sub { length ${$_[0]} == 3 },
    );
}

%extended_checks = (
    suffix => sub
    {
        my ($captured, $pos, $error) = @_;

        my @checks = (
            { cond  => sub { $captured->{$pos->[0]} == 1 && $captured->{$pos->[1]} =~ $data_helpers{suffix} },
              error => "suffix 's' without plural",
            },
            { cond  => sub { $captured->{$pos->[0]} >  1 && $captured->{$pos->[1]} !~ $data_helpers{suffix} },
              error => "plural without suffix 's'",
            },
        );

        # XXX constant.pm true/false: workaround for a segmentation fault
        # in Perl_mg_find() on perl 5.8.9 and 5.10.0 when using boolean.pm
        # v0.20 (tested as of 12/02/2009).
        foreach my $check (@checks) {
            if ($check->{cond}->()) {
                $$error = $check->{error};
                return false;
            }
        }
        return true;
    },
);

# <keyword> => [
#    [ <PERL TYPE DECLARATION>, ... ], ---------------------> declares how the tokens will be evaluated
#    [
#      { <token index> => <token value>, ... }, ------------> declares the index <-> value map
#      [ [ <index(es) of token(s) to be passed> ], ... ], --> declares which tokens will be passed to the extended check(s)
#      [ <subroutine(s) for extended check(s)>, ... ] ------> declares the extended check(s)
#      [ [ <index(es) of token(s) to be passed> ], ... ], --> declares which tokens will be passed to the worker method(s)
#      [ { <additional options to be passed> }, ... ] ------> declares additional options
#      [ <name of method to dispatch to>, ... ], -----------> declares the worker method(s)
#    ],

%grammar = (
    now => [
       [ 'SCALAR' ],
       [
         { 0 => 'now' },
         [],
         [],
         [ [] ],
         [ {} ],
         [ '_no_op' ],
       ],
    ],
    day => [
       [ 'REGEXP' ],
       [
         { 0 => qr/^(today)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ { unit => 'day' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(yesterday)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ { unit => 'day' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ { unit => 'day' } ],
         [ '_unit_variant' ],
       ],
    ],
    dayframe => [
       [ 'REGEXP' ],
       [
         { 0 => qr/^(morning)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{morn_aftern_even} ] },
           ],
         ],
         [ {} ],
         [ '_daytime_variant' ],
       ],
       [
         { 0 => qr/^(afternoon)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{morn_aftern_even} ] },
           ],
         ],
         [ {} ],
         [ '_daytime_variant' ],
       ],
       [
         { 0 => qr/^(evening)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{morn_aftern_even} ] },
           ],
         ],
         [ {} ],
         [ '_daytime_variant' ],
       ]
    ],
    daytime_noon_midnight => [
       [ 'REGEXP' ],
       [
         { 0 => qr/^(noon)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{noon_midnight} ] },
           ],
         ],
         [ {} ],
         [ '_daytime' ],
       ],
       [
         { 0 => qr/^(midnight)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{noon_midnight} ] },
           ]
         ],
         [ {} ],
         [ '_daytime' ],
       ],
    ],
    daytime_noon_midnight_at => [
       [ 'REGEXP', 'SCALAR', 'REGEXP' ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => 'at', 2 => qr/^(noon)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 2 => [ $flag{noon_midnight} ] },
           ],
         ],
         [ { unit => 'day' }, { hour => 12 } ],
         [ '_unit_variant', '_daytime' ],
       ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => 'at', 2 => qr/^(midnight)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 2 => [ $flag{noon_midnight} ] },
           ],
         ],
         [ { unit => 'day' }, { hour => 0 } ],
         [ '_unit_variant', '_daytime' ],
       ],
       [
         { 0 => qr/^(today)$/i, 1 => 'at', 2 => qr/^(noon)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 2 => [ $flag{noon_midnight} ] },
           ],
         ],
         [ { unit => 'day' }, { hour => 12 } ],
         [ '_unit_variant', '_daytime' ],
       ],
       [
         { 0 => qr/^(today)$/i, 1 => 'at', 2 => qr/^(midnight)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 2 => [ $flag{noon_midnight} ] },
           ],
         ],
         [ { unit => 'day' }, { hour => 0 } ],
         [ '_unit_variant', '_daytime' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => 'at', 2 => qr/^(noon)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 2 => [ $flag{noon_midnight} ] },
           ]
         ],
         [ { unit => 'day' }, { hour => 12 } ],
         [ '_unit_variant', '_daytime' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => 'at', 2 => qr/^(midnight)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 2 => [ $flag{noon_midnight} ] },
           ],
         ],
         [ { unit => 'day' }, { hour => 0 } ],
         [ '_unit_variant', '_daytime' ],
       ],
    ],
    this_daytime => [
       [ 'SCALAR', 'REGEXP' ],
       [
         { 0 => 'this', 1 => qr/^(morning)$/i },
         [],
         [],
         [
           [
             { 1 => [ $flag{morn_aftern_even} ] },
           ],
         ],
         [ {} ],
         [ '_daytime_variant' ],
       ],
       [
         { 0 => 'this', 1 => qr/^(afternoon)$/i },
         [],
         [],
         [
           [
             { 1 => [ $flag{morn_aftern_even} ] },
           ]
         ],
         [ {} ],
         [ '_daytime_variant' ],
       ],
       [
         { 0 => 'this', 1 => qr/^(evening)$/i },
         [],
         [],
         [
           [
             { 1 => [ $flag{morn_aftern_even} ] },
           ],
         ],
         [ {} ],
         [ '_daytime_variant' ],
       ],
    ],
    dayframe_day => [
       [ 'REGEXP', 'REGEXP' ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => qr/^(morning)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 1 => [ $flag{morn_aftern_even} ] },
           ],
         ],
         [ { unit => 'day' }, {} ],
         [ '_unit_variant', '_daytime_variant' ],
       ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => qr/^(afternoon)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 1 => [ $flag{morn_aftern_even} ] },
           ]
         ],
         [ { unit => 'day' }, {} ],
         [ '_unit_variant', '_daytime_variant' ],
       ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => qr/^(evening)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 1 => [ $flag{morn_aftern_even} ] },
           ],
         ],
         [ { unit => 'day' }, {} ],
         [ '_unit_variant', '_daytime_variant' ],
       ],
       [
         { 0 => qr/^(today)$/i, 1 => qr/^(morning)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 1 => [ $flag{morn_aftern_even} ] },
           ]
         ],
         [ { unit => 'day' }, {} ],
         [ '_unit_variant', '_daytime_variant' ],
       ],
       [
         { 0 => qr/^(today)$/i, 1 => qr/^(afternoon)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 1 => [ $flag{morn_aftern_even} ] },
           ],
         ],
         [ { unit => 'day' }, {} ],
         [ '_unit_variant', '_daytime_variant' ],
       ],
       [
         { 0 => qr/^(today)$/i, 1 => qr/^(evening)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 1 => [ $flag{morn_aftern_even} ] },
           ],
         ],
         [ { unit => 'day' }, {} ],
         [ '_unit_variant', '_daytime_variant' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => qr/^(morning)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 1 => [ $flag{morn_aftern_even} ] },
           ]
         ],
         [ { unit => 'day' }, {} ],
         [ '_unit_variant', '_daytime_variant' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => qr/^(afternoon)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 1 => [ $flag{morn_aftern_even} ] },
           ],
         ],
         [ { unit => 'day' }, {} ],
         [ '_unit_variant', '_daytime_variant' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => qr/^(evening)$/i },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [
             { 1 => [ $flag{morn_aftern_even} ] },
           ]
         ],
         [ { unit => 'day' }, {} ],
         [ '_unit_variant', '_daytime_variant' ],
       ]
    ],
    at_daytime => [
       [ 'REGEXP', 'REGEXP' ],
       [
         { 0 => $RE{time_am}, 1 => qr/^(yesterday)$/i },
         [],
         [],
         [
           [ 0 ],
           [
             { 1 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ {}, { unit => 'day' } ],
         [ '_time', '_unit_variant' ],
       ],
       [
         { 0 => $RE{time_am}, 1 => qr/^(today)$/i },
         [],
         [],
         [
           [ 0 ],
           [
             { 1 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ {}, { unit => 'day' } ],
         [ '_time', '_unit_variant' ],
       ],
       [
         { 0 => $RE{time_am}, 1 => qr/^(tomorrow)$/i },
         [],
         [],
         [
           [ 0 ],
           [
             { 1 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ {}, { unit => 'day' } ],
         [ '_time', '_unit_variant' ],
       ],
       [
         { 0 => $RE{time_pm}, 1 => qr/^(yesterday)$/i },
         [],
         [],
         [
           [ 0 ],
           [
             { 1 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ { hours => 12 }, { unit => 'day' } ],
         [ '_at', '_unit_variant' ],
       ],
       [
         { 0 => $RE{time_pm}, 1 => qr/^(today)$/i },
         [],
         [],
         [
           [ 0 ],
           [
             { 1 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ { hours => 12 }, { unit => 'day' } ],
         [ '_at', '_unit_variant' ],
       ],
       [
         { 0 => $RE{time_pm}, 1 => qr/^(tomorrow)$/i },
         [],
         [],
         [
           [ 0 ],
           [
             { 1 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ { hours => 12 }, { unit => 'day' } ],
         [ '_at', '_unit_variant' ],
       ],
    ],
    month => [
       [ 'REGEXP' ],
       [
         { 0 => $RE{month} },
         [],
         [],
         [
           [
             { 0 => [ $flag{month_name}, $flag{month_num} ] },
           ],
         ],
         [ { unit => 'month' } ],
         [ '_unit_date' ],
       ],
    ],
    month_day => [
       [ 'REGEXP', 'REGEXP' ],
       [
         { 0 => $RE{monthday}, 1 => $RE{month} },
         [],
         [],
         [
           [
               0,
             { 1 => [ $flag{month_name}, $flag{month_num} ] },
           ],
         ],
         [ {} ],
         [ '_month_day' ],
       ],
       [
         { 0 => $RE{month}, 1 => $RE{monthday} },
         [],
         [],
         [
           [
               1,
             { 0 => [ $flag{month_name}, $flag{month_num} ] },
           ],
         ],
         [ {} ],
         [ '_month_day' ],
       ]
    ],
    day_month_year_ago => [
      [ 'REGEXP', 'REGEXP', 'REGEXP', 'REGEXP', 'SCALAR' ],
      [
        { 0 => $RE{monthday}, 1 => $RE{month}, 2 => $RE{number}, 3 => qr/^(years?)$/i, 4 => 'ago' },
        [ [ 2, 3 ] ],
        [ $extended_checks{suffix} ],
        [
          [
              0,
            { 1 => [ $flag{month_name}, $flag{month_num} ] },
          ],
          [ 2 ],
        ],
        [ {}, { unit => 'year' } ],
        [ '_month_day', '_ago_variant' ],
      ],
    ],
    day_month_variant_year => [
      [ 'REGEXP', 'REGEXP', 'REGEXP', 'SCALAR' ],
      [
        { 0 => $RE{monthday}, 1 => $RE{month}, 2 => qr/^(next)$/i, 3 => 'year' },
        [],
        [],
        [
          [
              0,
            { 1 => [ $flag{month_name}, $flag{month_num} ] },
          ],
          [
            { 2 => [ $flag{last_this_next} ] },
          ],
        ],
        [ {}, { unit => 'year' } ],
        [ '_month_day', '_unit_variant' ],
      ],
      [
        { 0 => $RE{monthday}, 1 => $RE{month}, 2 => qr/^(this)$/i, 3 => 'year' },
        [],
        [],
        [
          [
              0,
            { 1 => [ $flag{month_name}, $flag{month_num} ] },
          ],
          [
            { 2 => [ $flag{last_this_next} ] },
          ],
        ],
        [ {}, { unit => 'year' } ],
        [ '_month_day', '_unit_variant' ],
      ],
      [
        { 0 => $RE{monthday}, 1 => $RE{month}, 2 => qr/^(last)$/i, 3 => 'year' },
        [],
        [],
        [
          [
              0,
            { 1 => [ $flag{month_name}, $flag{month_num} ] },
          ],
          [
            { 2 => [ $flag{last_this_next} ] },
          ]
        ],
        [ {}, { unit => 'year' } ],
        [ '_month_day', '_unit_variant' ],
      ],
    ],
    month_day_year => [
       [ 'REGEXP', 'REGEXP', 'REGEXP' ],
       [
         { 0 => $RE{month}, 1 => $RE{monthday}, 2 => $RE{year} },
         [],
         [],
         [
           [
               1,
             { 0 => [ $flag{month_name}, $flag{month_num} ] },
           ],
           [ 2 ],
         ],
         [ {}, { unit => 'year' } ],
         [ '_month_day', '_unit_date' ],
       ]
    ],
    week_variant => [
       [ 'REGEXP', 'SCALAR' ],
       [
         { 0 => qr/^(next)$/i, 1 => 'week' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'week' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(this)$/i, 1 => 'week' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'week' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(last)$/i, 1 => 'week' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ]
         ],
         [ { unit => 'week' } ],
         [ '_unit_variant' ],
       ]
    ],
    weekday => [
       [ 'REGEXP' ],
       [
         { 0 => $RE{weekday} },
         [],
         [],
         [
           [
             { 0 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ]
         ],
         [ {} ],
         [ '_weekday' ],
       ],
    ],
    weekday_variant => [
       [ 'REGEXP', 'REGEXP' ],
       [
         { 0 => qr/^(next)$/i, 1 => $RE{weekday} },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_day_variant_week' ],
       ],
       [
         { 0 => qr/^(this)$/i, 1 => $RE{weekday} },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_day_variant_week' ],
       ],
       [
         { 0 => qr/^(last)$/i, 1 => $RE{weekday} },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_day_variant_week' ],
       ],
    ],
    year_variant => [
       [ 'REGEXP', 'SCALAR' ],
       [
         { 0 => qr/^(last)$/i, 1 => 'year' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'year' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(this)$/i, 1 => 'year' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'year' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(next)$/i, 1 => 'year' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'year' } ],
         [ '_unit_variant' ],
       ],
    ],
    month_variant => [
       [ 'REGEXP', 'REGEXP' ],
       [
         { 0 => qr/^(last)$/i, 1 => $RE{month} },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
             { 1 => [ $flag{month_name}, $flag{month_num} ] },
           ],
         ],
         [ {} ],
         [ '_month_variant' ],
       ],
       [
         { 0 => qr/^(this)$/i, 1 => $RE{month} },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
             { 1 => [ $flag{month_name}, $flag{month_num} ] },
           ]
         ],
         [ {} ],
         [ '_month_variant' ],
       ],
       [
         { 0 => qr/^(next)$/i, 1 => $RE{month} },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
             { 1 => [ $flag{month_name}, $flag{month_num} ] },
           ],
         ],
         [ {} ],
         [ '_month_variant' ],
       ],
    ],
    unit_literal_variant => [
       [ 'REGEXP', 'SCALAR' ],
       [
         { 0 => qr/^(last)$/i, 1 => 'second' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'second' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(this)$/i, 1 => 'second' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'second' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(next)$/i, 1 => 'second' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'second' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(last)$/i, 1 => 'minute' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'minute' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(this)$/i, 1 => 'minute' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'minute' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(next)$/i, 1 => 'minute' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'minute' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(last)$/i, 1 => 'hour' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'hour' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(this)$/i, 1 => 'hour' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'hour' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(next)$/i, 1 => 'hour' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'hour' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(last)$/i, 1 => 'day' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'day' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(this)$/i, 1 => 'day' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'day' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(next)$/i, 1 => 'day' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'day' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(last)$/i, 1 => 'month' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'month' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(this)$/i, 1 => 'month' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'month' } ],
         [ '_unit_variant' ],
       ],
       [
         { 0 => qr/^(next)$/i, 1 => 'month' },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
           ],
         ],
         [ { unit => 'month' } ],
         [ '_unit_variant' ],
       ],
    ],
    at => [
       [ 'REGEXP', 'SCALAR' ],
       [
         { 0 => $RE{time}, 1 => 'am' },
         [],
         [],
         [ [ 0 ] ],
         [ { hours => 0 } ],
         [ '_at' ],
       ],
       [
         { 0 => $RE{time}, 1 => 'pm' },
         [],
         [],
         [ [ 0 ] ],
         [ { hours => 12 } ],
         [ '_at' ],
       ],
    ],
    at_combined => [
       [ 'REGEXP' ],
       [
         { 0 => $RE{time_am} },
         [],
         [],
         [ [ 0 ] ],
         [ { hours => 0 } ],
         [ '_at' ],
       ],
       [
         { 0 => $RE{time_pm} },
         [],
         [],
         [ [ 0 ] ],
         [ { hours => 12 } ],
         [ '_at' ],
       ],
    ],
    weekday_time => [
       [ 'REGEXP', 'REGEXP' ],
       [
         { 0 => $RE{weekday}, 1 => $RE{time} },
         [],
         [],
         [
           [
             { 0 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
           [ 1 ],
         ],
         [ {}, {} ],
         [ '_weekday', '_time' ],
       ],
    ],
    time => [
       [ 'REGEXP' ],
       [
         { 0 => $RE{time} },
         [],
         [],
         [ [ 0 ] ],
         [ {} ],
         [ '_time' ],
       ],
    ],
    time_full => [
       [ 'REGEXP' ],
       [
         { 0 => $RE{time_full} },
         [],
         [],
         [ [ 0 ] ],
         [ {} ],
         [ '_time_full' ],
       ],
    ],
    month_year => [
       [ 'REGEXP', 'REGEXP' ],
       [
         { 0 => $RE{month}, 1 => $RE{year} },
         [],
         [],
         [
           [
             { 0 => [ $flag{month_name}, $flag{month_num} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'month' }, { unit => 'year' } ],
         [ '_unit_date', '_unit_date' ],
       ],
    ],
    year => [
       [ 'REGEXP' ],
       [
         { 0 => $RE{year} },
         [],
         [],
         [ [ 0 ] ],
         [ { unit => 'year' } ],
         [ '_unit_date' ],
       ],
    ],
    count_weekday => [
       [ 'REGEXP', 'REGEXP' ],
       [
         { 0 => $RE{day}, 1 => $RE{weekday} },
         [],
         [],
         [
           [
               0,
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_weekday' ],
       ],
    ],
    count_yearday => [
       [ 'REGEXP', 'SCALAR' ],
       [
         { 0 => $RE{day}, 1 => 'day' },
         [],
         [],
         [
           [
             0,
             { VALUE => 0 }
           ],
         ],
         [ {} ],
         [ '_count_yearday_variant_year' ],
       ],
    ],
    count_yearday_variant_year => [
        [ 'REGEXP', 'SCALAR', 'REGEXP', 'SCALAR' ],
        [
          { 0 => $RE{day}, 1 => 'day', 2 => qr/^(next)$/i, 3 => 'year' },
          [],
          [],
          [
            [
                0,
              { 2 => [ $flag{last_this_next} ] },
            ],
          ],
          [ {} ],
          [ '_count_yearday_variant_year' ],
        ],
        [
          { 0 => $RE{day}, 1 => 'day', 2 => qr/^(this)$/i, 3 => 'year' },
          [],
          [],
          [
            [
                0,
              { 2 => [ $flag{last_this_next} ] },
            ],
          ],
          [ {} ],
          [ '_count_yearday_variant_year' ],
        ],
        [
          { 0 => $RE{day}, 1 => 'day', 2 => qr/^(last)$/i, 3 => 'year' },
          [],
          [],
          [
            [
                0,
              { 2 => [ $flag{last_this_next} ] },
            ],
          ],
          [ {} ],
          [ '_count_yearday_variant_year' ],
        ],
    ],
    daytime_in_the_variant => [
       [ 'REGEXP', 'SCALAR', 'SCALAR', 'SCALAR' ],
       [
         { 0 => $RE{number}, 1 => 'in', 2 => 'the', 3 => 'morning' },
         [],
         [],
         [ [ 0 ] ],
         [ { hours => 0 } ],
         [ '_daytime_in_the_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => 'in', 2 => 'the', 3 => 'afternoon' },
         [],
         [],
         [ [ 0 ] ],
         [ { hours => 12 } ],
         [ '_daytime_in_the_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => 'in', 2 => 'the', 3 => 'evening' },
         [],
         [],
         [ [ 0 ] ],
         [ { hours => 12 } ],
         [ '_daytime_in_the_variant' ],
       ],
    ],
    ago => [
       [ 'REGEXP', 'REGEXP', 'SCALAR' ],
       [
         { 0 => $RE{number}, 1 => qr/^(seconds?)$/i, 2 => 'ago' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [ [ 0 ] ],
         [ { unit => 'second' } ],
         [ '_ago_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(minutes?)$/i, 2 => 'ago' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [ [ 0 ] ],
         [ { unit => 'minute' } ],
         [ '_ago_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(hours?)$/i, 2 => 'ago' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [ [ 0 ] ],
         [ { unit => 'hour' } ],
         [ '_ago_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(days?)$/i, 2 => 'ago' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [ [ 0 ] ],
         [ { unit => 'day' } ],
         [ '_ago_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(weeks?)$/i, 2 => 'ago' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [ [ 0 ] ],
         [ { unit => 'week' } ],
         [ '_ago_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(months?)$/i, 2 => 'ago' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [ [ 0 ] ],
         [ { unit => 'month' } ],
         [ '_ago_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(years?)$/i, 2 => 'ago' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [ [ 0 ] ],
         [ { unit => 'year' } ],
         [ '_ago_variant' ],
       ],
    ],
    ago_tomorrow => [
       [ 'REGEXP', 'REGEXP', 'REGEXP', 'SCALAR' ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => $RE{number}, 2 => qr/^(seconds?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'second' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => $RE{number}, 2 => qr/^(minutes?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'minute' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => $RE{number}, 2 => qr/^(hours?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'hour' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => $RE{number}, 2 => qr/^(days?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'day' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => $RE{number}, 2 => qr/^(weeks?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'week' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => $RE{number}, 2 => qr/^(months?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'month' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => $RE{number}, 2 => qr/^(years?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'year' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
    ],
    ago_yesterday => [
       [ 'REGEXP', 'REGEXP', 'REGEXP', 'SCALAR' ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => $RE{number}, 2 => qr/^(seconds?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'second' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => $RE{number}, 2 => qr/^(minutes?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'minute' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => $RE{number}, 2 => qr/^(hours?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'hour' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => $RE{number}, 2 => qr/^(days?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'day' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => $RE{number}, 2 => qr/^(weeks?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'week' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => $RE{number}, 2 => qr/^(months?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'month' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => $RE{number}, 2 => qr/^(years?)$/i, 3 => 'ago' },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 1 ],
         ],
         [ { unit => 'day' }, { unit => 'year' } ],
         [ '_unit_variant', '_ago_variant' ],
       ],
    ],
    weekday_ago_at_time => [
       [ 'REGEXP', 'REGEXP', 'REGEXP', 'SCALAR', 'SCALAR', 'REGEXP' ],
       [
         { 0 => $RE{weekday}, 1 => $RE{number}, 2 => qr/^(months?)$/, 3 => 'ago', 4 => 'at', 5 => $RE{time_am} },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [ 1 ],
           [
             { 0 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
           [ 5 ],
         ],
         [ { unit => 'month' }, {}, {} ],
         [ '_ago_variant', '_weekday', '_time' ],
       ],
       [
         { 0 => $RE{weekday}, 1 => $RE{number}, 2 => qr/^(months?)$/, 3 => 'ago', 4 => 'at', 5 => $RE{time_pm} },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [
           [ 1 ],
           [
             { 0 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
           [ 5 ],
         ],
         [ { unit => 'month' }, {}, { hours => 12 } ],
         [ '_ago_variant', '_weekday', '_at' ],
       ],
    ],
    now_variant_before => [
       [ 'REGEXP', 'REGEXP', 'REGEXP', 'SCALAR' ],
       [
         { 0 => $RE{number}, 1 => qr/^(seconds?)$/i, 2 => qr/^(before)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'second' } ],
         [ '_now_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(minutes?)$/i, 2 => qr/^(before)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'minute' } ],
         [ '_now_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(hours?)$/i, 2 => qr/^(before)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'hour' } ],
         [ '_now_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(days?)$/i,  2 => qr/^(before)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'day' } ],
         [ '_now_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(weeks?)$/i, 2 => qr/^(before)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'week' } ],
         [ '_now_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(months?)$/i, 2 => qr/^(before)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ]
         ],
         [ { unit => 'month' } ],
         [ '_now_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(years?)$/i, 2 => qr/^(before)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'year' } ],
         [ '_now_variant' ],
       ],
    ],
    now_variant_from => [
       [ 'REGEXP', 'REGEXP', 'REGEXP', 'SCALAR' ],
       [
         { 0 => $RE{number}, 1 => qr/^(seconds?)$/i, 2 => qr/^(from)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'second' } ],
         [ '_now_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(minutes?)$/i, 2 => qr/^(from)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'minute' } ],
         [ '_now_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(hours?)$/i, 2 => qr/^(from)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'hour' } ],
         [ '_now_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(days?)$/i, 2 => qr/^(from)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'day' } ],
         [ '_now_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(weeks?)$/i, 2 => qr/^(from)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'week' } ],
         [ '_now_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(months?)$/i, 2 => qr/^(from)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'month' } ],
         [ '_now_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(years?)$/i, 2 => qr/^(from)$/i, 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { unit => 'year' } ],
         [ '_now_variant' ],
       ],
    ],
    day_daytime => [
       [ 'REGEXP', 'REGEXP', 'SCALAR', 'SCALAR', 'SCALAR' ],
       [
         { 0 => $RE{weekday}, 1 => $RE{number}, 2 => 'in', 3 => 'the', 4 => 'morning' },
         [],
         [],
         [
           [
             { 0 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
           [ 1 ],
         ],
         [ {}, { hours => 0 } ],
         [ '_weekday', '_daytime_in_the_variant' ],
       ],
       [
         { 0 => $RE{weekday}, 1 => $RE{number}, 2 => 'in', 3 => 'the', 4 => 'afternoon' },
         [],
         [],
         [
           [
             { 0 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
           [ 1 ],
         ],
         [ {}, { hours => 12 } ],
         [ '_weekday', '_daytime_in_the_variant' ],
       ],
       [
         { 0 => $RE{weekday}, 1 => $RE{number}, 2 => 'in', 3 => 'the', 4 => 'evening' },
         [],
         [],
         [
           [
             { 0 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
           [ 1 ],
         ],
         [ {}, { hours => 12 } ],
         [ '_weekday', '_daytime_in_the_variant' ],
       ],
    ],
    variant_weekday_at_time => [
       [ 'REGEXP', 'REGEXP', 'SCALAR', 'REGEXP' ],
       [
         { 0 => qr/^(next)$/i, 1 => $RE{weekday}, 2 => 'at', 3 => $RE{time} },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
           [ 3 ],
         ],
         [ {}, {} ],
         [ '_count_day_variant_week', '_time' ],
       ],
       [
         { 0 => qr/^(this)$/i, 1 => $RE{weekday}, 2 => 'at', 3 => $RE{time} },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
           [ 3 ],
         ],
         [ {}, {} ],
         [ '_count_day_variant_week', '_time' ],
       ],
       [
         { 0 => qr/^(last)$/i, 1 => $RE{weekday}, 2 => 'at', 3 => $RE{time} },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
           [ 3 ],
         ],
         [ {}, {} ],
         [ '_count_day_variant_week', '_time' ],
       ],
    ],
    count_day_variant_week => [
       [ 'REGEXP', 'SCALAR', 'REGEXP', 'SCALAR' ],
       [
         { 0 => $RE{day}, 1 => 'day', 2 => qr/^(next)$/i, 3 => 'week' },
         [],
         [],
         [
           [
             { 2 => [ $flag{last_this_next} ] },
               0,
           ],
         ],
         [ {} ],
         [ '_count_day_variant_week' ],
       ],
       [
         { 0 => $RE{day}, 1 => 'day', 2 => qr/^(this)$/i, 3 => 'week' },
         [],
         [],
         [
           [
             { 2 => [ $flag{last_this_next} ] },
               0,
           ],
         ],
         [ {} ],
         [ '_count_day_variant_week' ],
       ],
       [
         { 0 => $RE{day}, 1 => 'day', 2 => qr/^(last)$/i, 3 => 'week' },
         [],
         [],
         [
           [
             { 2 => [ $flag{last_this_next} ] },
               0,
           ],
         ],
         [ {} ],
         [ '_count_day_variant_week' ],
       ],
    ],
    count_day_variant_month => [
       [ 'REGEXP', 'SCALAR', 'REGEXP', 'SCALAR' ],
       [
         { 0 => $RE{day}, 1 => 'day', 2 => qr/^(next)$/i, 3 => 'month' },
         [],
         [],
         [
           [
             { 2 => [ $flag{last_this_next} ] },
               0,
           ],
         ],
         [ {} ],
         [ '_count_day_variant_month' ],
       ],
       [
         { 0 => $RE{day}, 1 => 'day', 2 => qr/^(this)$/i, 3 => 'month' },
         [],
         [],
         [
           [
             { 2 => [ $flag{last_this_next} ] },
               0,
           ],
         ],
         [ {} ],
         [ '_count_day_variant_month' ],
       ],
       [
         { 0 => $RE{day}, 1 => 'day', 2 => qr/^(last)$/i, 3 => 'month' },
         [],
         [],
         [
           [
             { 2 => [ $flag{last_this_next} ] },
               0,
           ],
         ],
         [ {} ],
         [ '_count_day_variant_month' ],
       ],
    ],
    weekday_variant_week => [
       [ 'REGEXP', 'REGEXP', 'SCALAR' ],
       [
         { 0 => $RE{weekday}, 1 => qr/^(next)$/i, 2 => 'week' },
         [],
         [],
         [
           [
             { 1 => [ $flag{last_this_next} ] },
             { 0 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_day_variant_week' ],
       ],
       [
         { 0 => $RE{weekday}, 1 => qr/^(this)$/i, 2 => 'week' },
         [],
         [],
         [
           [
             { 1 => [ $flag{last_this_next} ] },
             { 0 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_day_variant_week' ],
       ],
       [
         { 0 => $RE{weekday}, 1 => qr/^(last)$/i, 2 => 'week' },
         [],
         [],
         [
           [
             { 1 => [ $flag{last_this_next} ] },
             { 0 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ]
         ],
         [ {} ],
         [ '_count_day_variant_week' ],
       ],
    ],
    variant_week_weekday => [
       [ 'REGEXP', 'SCALAR', 'REGEXP' ],
       [
         { 0 => qr/^(next)$/i, 1 => 'week', 2 => $RE{weekday} },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
             { 2 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_day_variant_week' ],
       ],
       [
         { 0 => qr/^(this)$/i, 1 => 'week', 2 => $RE{weekday} },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
             { 2 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_day_variant_week' ],
       ],
       [
         { 0 => qr/^(last)$/i, 1 => 'week', 2 => $RE{weekday} },
         [],
         [],
         [
           [
             { 0 => [ $flag{last_this_next} ] },
             { 2 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_day_variant_week' ],
       ],
    ],
    count_month_variant_year => [
       [ 'REGEXP', 'SCALAR', 'REGEXP', 'SCALAR' ],
       [
         { 0 => $RE{day}, 1 => 'month', 2 => qr/^(next)$/i, 3 => 'year' },
         [],
         [],
         [
           [
             { 2 => [ $flag{last_this_next} ] },
               0,
           ],
         ],
         [ {} ],
         [ '_count_month_variant_year' ],
       ],
       [
         { 0 => $RE{day}, 1 => 'month', 2 => qr/^(this)$/i, 3 => 'year' },
         [],
         [],
         [
           [
             { 2 => [ $flag{last_this_next} ] },
               0,
           ],
         ],
         [ {} ],
         [ '_count_month_variant_year' ],
       ],
       [
         { 0 => $RE{day}, 1 => 'month', 2 => qr/^(last)$/i, 3 => 'year' },
         [],
         [],
         [
           [
             { 2 => [ $flag{last_this_next} ] },
               0,
           ],
         ],
         [ {} ],
         [ '_count_month_variant_year' ],
       ],
    ],
    in_count_unit => [
       [ 'SCALAR', 'REGEXP', 'REGEXP' ],
       [
         { 0 => 'in', 1 => $RE{number}, 2 => qr/^(seconds?)$/i },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [ [ 1 ] ],
         [ { unit => 'second' } ],
         [ '_in_count_variant' ],
       ],
       [
         { 0 => 'in', 1 => $RE{number}, 2 => qr/^(minutes?)$/i },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [ [ 1 ] ],
         [ { unit => 'minute' } ],
         [ '_in_count_variant' ],
       ],
       [
         { 0 => 'in', 1 => $RE{number}, 2 => qr/^(hours?)$/i },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [ [ 1 ] ],
         [ { unit => 'hour' } ],
         [ '_in_count_variant' ],
       ],
       [
         { 0 => 'in', 1 => $RE{number}, 2 => qr/^(days?)$/i },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [ [ 1 ] ],
         [ { unit => 'day' } ],
         [ '_in_count_variant' ],
       ],
       [
         { 0 => 'in', 1 => $RE{number}, 2 => qr/^(weeks?)$/i },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [ [ 1 ] ],
         [ { unit => 'week' } ],
         [ '_in_count_variant' ],
       ],
       [
         { 0 => 'in', 1 => $RE{number}, 2 => qr/^(months?)$/i },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [ [ 1 ] ],
         [ { unit => 'month' } ],
         [ '_in_count_variant' ],
       ],
       [
         { 0 => 'in', 1 => $RE{number}, 2 => qr/^(years?)$/i },
         [ [ 1, 2 ] ],
         [ $extended_checks{suffix} ],
         [ [ 1 ] ],
         [ { unit => 'year' } ],
         [ '_in_count_variant' ],
       ],
    ],
    count_weekday_variant_month => [
       [ 'REGEXP', 'REGEXP', 'REGEXP', 'REGEXP' ],
       [
         { 0 => $RE{day}, 1 => $RE{weekday}, 2 => qr/^(next)$/i, 3 => $RE{month} },
         [],
         [],
         [
           [
             { 2 => [ $flag{last_this_next} ] },
               0,
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
             { 3 => [ $flag{month_name}, $flag{month_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_weekday_variant_month' ],
       ],
       [
         { 0 => $RE{day}, 1 => $RE{weekday}, 2 => qr/^(this)$/i, 3 => $RE{month} },
         [],
         [],
         [
           [
             { 2 => [ $flag{last_this_next} ] },
               0,
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
             { 3 => [ $flag{month_name}, $flag{month_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_weekday_variant_month' ],
       ],
       [
         { 0 => $RE{day}, 1 => $RE{weekday}, 2 => qr/^(last)$/i, 3 => $RE{month} },
         [],
         [],
         [
           [
             { 2 => [ $flag{last_this_next} ] },
               0,
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
             { 3 => [ $flag{month_name}, $flag{month_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_weekday_variant_month' ],
       ],
    ],
    daytime_hours_variant => [
       [ 'REGEXP', 'REGEXP', 'REGEXP', 'REGEXP' ],
       [
         { 0 => $RE{number}, 1 => qr/^(hours?)$/i, 2 => qr/^(before)$/i, 3 => qr/^(yesterday)$/i },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
             { 3 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ {} ],
         [ '_daytime_hours_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(hours?)$/i, 2 => qr/^(before)$/i, 3 => qr/^(tomorrow)$/i },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
             { 3 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ {} ],
         [ '_daytime_hours_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(hours?)$/i, 2 => qr/^(after)$/i, 3 => qr/^(yesterday)$/i },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
             { 3 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ {} ],
         [ '_daytime_hours_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(hours?)$/i, 2 => qr/^(after)$/i, 3 => qr/^(tomorrow)$/i },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
             { 3 => [ $flag{yes_today_tom} ] },
           ],
         ],
         [ {} ],
         [ '_daytime_hours_variant' ],
       ],
    ],
    hourtime_before_variant => [
       [ 'REGEXP', 'REGEXP', 'REGEXP', 'SCALAR' ],
       [
         { 0 => $RE{number}, 1 => qr/^(hours?)$/i, 2 => qr/^(before)$/i, 3 => 'noon' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { hour => 12 } ],
         [ '_hourtime_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(hours?)$/i, 2 => qr/^(before)$/i, 3 => 'midnight' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { hour => 0 } ],
         [ '_hourtime_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(hours?)$/i, 2 => qr/^(after)$/i, 3 => 'noon' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { hour => 12 } ],
         [ '_hourtime_variant' ],
       ],
       [
         { 0 => $RE{number}, 1 => qr/^(hours?)$/i, 2 => qr/^(after)$/i, 3 => 'midnight' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 2 => [ $flag{before_after_from} ] },
           ],
         ],
         [ { hour => 0 } ],
         [ '_hourtime_variant' ],
       ],
    ],
    day_at => [
       [ 'REGEXP', 'SCALAR', 'REGEXP' ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => 'at', 2 => $RE{time_am} },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 2 ],
         ],
         [ { unit => 'day' }, {} ],
         [ '_unit_variant', '_time' ],
       ],
       [
         { 0 => qr/^(today)$/i, 1 => 'at', 2 => $RE{time_am} },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 2 ],
         ],
         [ { unit => 'day' }, {} ],
         [ '_unit_variant', '_time' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => 'at', 2 => $RE{time_am} },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 2 ],
         ],
         [ { unit => 'day' }, {} ],
         [ '_unit_variant', '_time' ],
       ],
    ],
    weekday_at_time => [
       [ 'REGEXP', 'SCALAR', 'REGEXP' ],
       [
         { 0 => $RE{weekday}, 1 => 'at', 2 => $RE{time_am} },
         [],
         [],
         [
           [
             { 0 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
           [ 2 ],
         ],
         [ {}, {} ],
         [ '_weekday', '_time' ],
       ],
    ],
    day_at_pm => [
       [ 'REGEXP', 'SCALAR', 'REGEXP' ],
       [
         { 0 => qr/^(yesterday)$/i, 1 => 'at', 2 => $RE{time_pm} },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 2 ],
         ],
         [ { unit => 'day' }, { hours => 12 } ],
         [ '_unit_variant', '_at' ],
       ],
       [
         { 0 => qr/^(today)$/i, 1 => 'at', 2 => $RE{time_pm} },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 2 ],
         ],
         [ { unit => 'day' }, { hours => 12 } ],
         [ '_unit_variant', '_at' ],
       ],
       [
         { 0 => qr/^(tomorrow)$/i, 1 => 'at', 2 => $RE{time_pm} },
         [],
         [],
         [
           [
             { 0 => [ $flag{yes_today_tom} ] },
           ],
           [ 2 ],
         ],
         [ { unit => 'day' }, { hours => 12 } ],
         [ '_unit_variant', '_at' ],
       ],
    ],
    weekday_at_time_pm => [
       [ 'REGEXP', 'SCALAR', 'REGEXP' ],
       [
         { 0 => $RE{weekday}, 1 => 'at', 2 => $RE{time_pm} },
         [],
         [],
         [
           [
             { 0 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
           [ 2 ],
         ],
         [ {}, { hours => 12 } ],
         [ '_weekday', '_at' ],
       ],
    ],
    day_month_year => [
       [ 'REGEXP', 'REGEXP', 'REGEXP' ],
       [
         { 0 => $RE{monthday}, 1 => $RE{month}, 2 => $RE{year} },
         [],
         [],
         [
           [
               0,
             { 1 => [ $flag{month_name}, $flag{month_num} ] },
               2,
           ],
         ],
         [ {} ],
         [ '_day_month_year' ],
       ],
       [
         { 0 => $RE{month}, 1 => $RE{monthday}, 2 => $RE{year} },
         [],
         [],
         [
           [
               1,
             { 0 => [ $flag{month_name}, $flag{month_num} ] },
               2,
           ],
         ],
         [ {} ],
         [ '_day_month_year' ],
       ],
    ],
    count_weekday_in_month => [
       [ 'REGEXP', 'REGEXP', 'SCALAR', 'REGEXP' ],
       [
         { 0 => $RE{day}, 1 => $RE{weekday}, 2 => 'in', 3 => $RE{month} },
         [],
         [],
         [
           [
             { VALUE => 0 },
               0,
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
             { 3 => [ $flag{month_name}, $flag{month_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_weekday_variant_month' ],
       ],
    ],
    count_weekday_from_now => [
       [ 'REGEXP', 'REGEXP', 'SCALAR', 'SCALAR' ],
       [
         { 0 => $RE{number}, 1 => $RE{weekdays}, 2 => 'from', 3 => 'now' },
         [ [ 0, 1 ] ],
         [ $extended_checks{suffix} ],
         [
           [
               0,
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
           ],
         ],
         [ {} ],
         [ '_count_weekday_from_now' ],
       ],
    ],
    final_weekday_in_month => [
       [ 'SCALAR', 'REGEXP', 'SCALAR', 'REGEXP' ],
       [
         { 0 => 'final', 1 => $RE{weekday}, 2 => 'in', 3 => $RE{month} },
         [],
         [],
         [
           [
             { 1 => [ $flag{weekday_name}, $flag{weekday_num} ] },
             { 3 => [ $flag{month_name}, $flag{month_num} ] },
           ],
         ],
         [ {} ],
         [ '_final_weekday_in_month' ],
       ],
    ],
);

1;
__END__

=head1 NAME

DateTime::Format::Natural::Lang::EN - English language metadata

=head1 DESCRIPTION

C<DateTime::Format::Natural::Lang::EN> provides the english specific grammar
and variables. This class is loaded if the user either specifies the english
language or implicitly.

=head1 EXAMPLES

Below are some examples of human readable date/time input in english (be aware
that the parser does not distinguish between lower/upper case):

=head2 Simple

 now
 yesterday
 today
 tomorrow
 morning
 afternoon
 evening
 noon
 midnight
 yesterday at noon
 yesterday at midnight
 today at noon
 today at midnight
 tomorrow at noon
 tomorrow at midnight
 this morning
 this afternoon
 this evening
 yesterday morning
 yesterday afternoon
 yesterday evening
 today morning
 today afternoon
 today evening
 tomorrow morning
 tomorrow afternoon
 tomorrow evening
 5am yesterday
 5am today
 5am tomorrow
 4pm yesterday
 4pm today
 4pm tomorrow
 last second
 this second
 next second
 last minute
 this minute
 next minute
 last hour
 this hour
 next hour
 last day
 this day
 next day
 last week
 this week
 next week
 last month
 this month
 next month
 last year
 this year
 next year
 last friday
 this friday
 next friday
 tuesday last week
 tuesday this week
 tuesday next week
 last week wednesday
 this week wednesday
 next week wednesday
 10 seconds ago
 10 minutes ago
 10 hours ago
 10 days ago
 10 weeks ago
 10 months ago
 10 years ago
 in 5 seconds
 in 5 minutes
 in 5 hours
 in 5 days
 in 5 weeks
 in 5 months
 in 5 years
 saturday
 sunday 11:00
 yesterday at 4:00
 today at 4:00
 tomorrow at 4:00
 yesterday at 6:45pm
 today at 6:45pm
 tomorrow at 6:45pm
 wednesday at 14:30
 wednesday at 02:30pm
 2nd monday
 100th day
 4th february
 november 3rd
 last june
 next october
 6 am
 5am
 5:30am
 8 pm
 4pm
 4:20pm
 mon 2:35

=head2 Complex

 yesterday 7 seconds ago
 yesterday 7 minutes ago
 yesterday 7 hours ago
 yesterday 7 days ago
 yesterday 7 weeks ago
 yesterday 7 months ago
 yesterday 7 years ago
 tomorrow 3 seconds ago
 tomorrow 3 minutes ago
 tomorrow 3 hours ago
 tomorrow 3 days ago
 tomorrow 3 weeks ago
 tomorrow 3 months ago
 tomorrow 3 years ago
 2 seconds before now
 2 minutes before now
 2 hours before now
 2 days before now
 2 weeks before now
 2 months before now
 2 years before now
 4 seconds from now
 4 minutes from now
 4 hours from now
 4 days from now
 4 weeks from now
 4 months from now
 4 years from now
 6 in the morning
 4 in the afternoon
 9 in the evening
 monday 6 in the morning
 monday 4 in the afternoon
 monday 9 in the evening
 last sunday at 21:45
 monday last week
 6th day last week
 6th day this week
 6th day next week
 12th day last month
 12th day this month
 12th day next month
 1st day last year
 1st day this year
 1st day next year
 1st tuesday last november
 1st tuesday this november
 1st tuesday next november
 11 january next year
 11 january this year
 11 january last year
 6 hours before yesterday
 6 hours before tomorrow
 3 hours after yesterday
 3 hours after tomorrow
 10 hours before noon
 10 hours before midnight
 5 hours after noon
 5 hours after midnight
 last friday at 20:00
 this friday at 20:00
 next friday at 20:00
 yesterday at 13:00
 today at 13:00
 tomorrow at 13
 2nd friday in august
 3rd wednesday in november
 tomorrow 1 year ago
 saturday 3 months ago at 5:00pm
 11 january 2 years ago
 4th day last week
 8th month last year
 8th month this year
 8th month next year
 6 mondays from now
 fri 3 months ago at 5am
 wednesday 1 month ago at 8pm
 final thursday in april

=head2 Timespans

 Monday to Friday
 1 April to 31 August

=head2 Specific Dates

 march
 January 11
 11 January
 dec 25
 may 27th
 2005
 march 1st 2009
 October 2006
 february 14, 2004
 jan 3 2010
 3 jan 2000
 27/5/1979
 4:00
 17:00
 3:20:00

=head1 SEE ALSO

L<DateTime::Format::Natural>

=head1 AUTHOR

Steven Schubiger <schubiger@cpan.org>

=head1 LICENSE

This program is free software; you may redistribute it and/or
modify it under the same terms as Perl itself.

See L<http://www.perl.com/perl/misc/Artistic.html>

=cut
