Сегодня — заключительная часть рассказа о грамматике для разбора даты. В прошлый раз мы добавили класс с действиями, теперь ради упражнения добавим в этот класс атрибуты (то, что в других языках называют данными класса).
Заодно чуть усложним грамматику и научим ее парсить даты, записанные в виде 28.02.18:
token TOP {
| <year> <sep> <month> <sep> <day>
| <day> <sep> <month> <sep> <year>
| <n> <sep> <month> <sep> <nn>
}
. . .
token n {
\d ** 1..2
}
token nn {
\d ** 2
}
Класс действий теперь должен уметь различать ситуации, когда дата записана с полным годом, а когда год представлен только двумя цифрами.
Дату будем хранить в хеше %date, что немного избыточно для этой задачи, но хорошо иллюстрирует, как действовать, когда акции требуют сохранения промежуточных данных.
class DateStrActions {
has %date;
method TOP($/) {
if %date<nn> {
if %date<nn> > 35 {
%date<year> = 1900 + %date<nn>;
}
else {
%date<year> = 2000 + %date<nn>;
}
%date<day> = %date<n>;
}
printf "--> %4i-%02i-%02i\n",
%date<year>, %date<month>, %date<day>
}
method year($/) {
%date<year> = ~$/;
}
method month($/) {
%date<month> = ~$/;
}
method day($/) {
%date<day> = ~$/;
}
method nn($/) {
%date<nn> = ~$/;
}
method n($/) {
%date<n> = ~$/;
}
}
Здесь действия должны проявить сообразительность, чтобы правильно оценить, к какому столетию относится год.
Теперь самое важное. Поскольку в классе появился атрибут, компилятору потребуется выделить под него место. Для этого от вас требуется создать объект, а не просто передать имя класса:
my $r = DateStr.parse($t, :actions(DateStrActions.new()));
Тестируем код на разных датах:
$ perl6 actions2.pl
2018-02-26 --> 2018-02-26
2019-3-27 --> 2019-03-27
28.04.2020 --> 2020-04-28
30.05.21 --> 2021-05-30
15.06.99 --> 1999-06-15
Полный код вы этого варианта программы можете найти на гитхабе.