Ошибка «два члена подряд» - PullRequest
0 голосов
/ 09 июня 2018

Я пытаюсь написать компактную строку, как показано ниже, код является выдержкой из сценария, который читает STDIN с использованием специальной переменной $ * IN с динамической областью действия.Подскажите, пожалуйста, как правильно написать эту строку?

Это работает

for $*IN.lines() {
    last when "" ;
    say "VERBOSE \"$_ is the string\"";
    $i=$i+1;
}

не работает

.say "VERBOSE \"$_ is the string\"" for $*IN.lines() last when "";

ошибка вывода:

===SORRY!=== Error while compiling /usr/share/asterisk/agi-bin/agi-t1.p6
Two terms in a row
at /usr/share/asterisk/agi-bin/agi-t1.p6:5
------> .say⏏ "Verbose \"$_\"" for $*IN.lines() last
expecting any of:
  infix
  infix stopper
  statement end
  statement modifier
  statement modifier loop

1 Ответ

0 голосов
/ 10 июня 2018

Общее объяснение сообщения об ошибке

===SORRY!=== Error while compiling ...

Когда вы видите SORRY!, то вы знаете, что компилятор говорит вам о проблеме, которая произошла во время компиляции, даже до того, как была предпринята попыткачтобы запустить ваш код.

Two terms in a row

Это сводная информация компилятора на английском языке о том, что остановило компиляцию вашего кода.Мы вернемся к этому позже.

------> - это способ сказать компилятору, что он был сбит с толку тем, что вы написали, и он будет отображать часть вашего кода после ------>.

, символ с именем Unicode EJECT SYMBOL, вставляется на экран вашего кода.Вставленная точка должна помочь в интерпретации сообщения об ошибке.

В этом случае оно указывает между .say и "VERBOSE...".Компилятор считает, что это два термина подряд.

Что такое термин?

Рассмотрим следующий код:

start-time + 42
sum(start-time, 42)

Термины похожи на терминыпо математике .Оба примера выражения включают в себя термины start-time и 42.Общее выражение start-time + 42 также является термином.Выражение sum(start-time, 42) можно назвать термином sum() или sum(...).

Термины также в некоторой степени похожи на существительные или словосочетания в естественном языке .start-time и 42 подобны существительным, отсюда и термины.start-time + 42 и sum(...) подобны словосочетаниям, каждая из которых также является термином.

(Кстати, термины, в смысле, относящемся к этому вопросу, не относятся к парсингу«терминалы», которые иногда называют «терминами».)

Теперь вы можете догадаться, что произойдет, если попытаться скомпилировать пример кода, с которого начинался этот раздел:

Two terms in a row across lines (missing semicolon or comma?)

Первая строка (start-time + 42) - это термин.sum(start-time, 42) это другой термин.И между ними нет ничего, кроме конца строки.В Perl 6 явно не нравятся два термина подряд без чего-то, что не является термином между ними, а пробелы и концы строк не учитываются.

Как можно избежать ошибки «Два члена подряд»?

Операторы, такие как infix +, postcircumfix () и infix ,, которые я использовал в приведенных выше примерах, могут использоваться в позициях операторов (до, после, между или вокруг терминов) формировать выражения.(И общие выражения сами по себе являются терминами, как описано выше.)

Ключевые слова, такие как for или last, используемые в позиции ключевого слова, также являются , а не терминами (если вы не сошли с умадостаточно переопределить их как термины, и в этом случае вы, вероятно, получите странные ошибки компиляции, которых вы заслуживаете. :)) Но, как и операторы, они должны быть расположены в правильном положении, иначе компилятор может подумать, что они термины.Если вы напишите last в неправильном месте, компилятор может подумать, что last - это термин.

Проблема с вашим кодом

Компилятор считает .say (обратите внимание на пробел вконец) быть термином, эквивалентным .say().Таким образом, он интерпретирует то, что вы написали как .say() "VERBOSE...", что является двумя терминами подряд.

(Я рекомендую вам просто согласиться с тем, что это так, но если вы хотите углубиться в мелочи синтаксиса вызова методов, чтобы полностью понять, почему invocant.foo ( arrgh, arrgh, ... ) ; также означает «Два члена подряд», см. мой ответ, охватывающий различные синтаксисы, связанные с обычными вызовами .)

Давайте исправим ваш код, изменив .say на say (без .):

say "VERBOSE \"$_ is the string\"" for $*IN.lines() last when "";

Компилятор возвращает еще одну ошибку «Два члена в строке», но теперь он указывает между $*IN.lines() и last.

Ключевое слово for и его аргумент итерации должны быть либо в началезаявление или в конце заявления.Вы использовали их в конце.

Но это означает, что то, что следует после for, является термином (его аргумент итерации).

$*IN.lines() может работать как термин.

Вы можете даже сделать это частью выражения, например.for flat $*IN.lines(), $*FOO.lines() для циклического перебора как строк ввода, так и строк из некоторого другого дескриптора.(flat создает единый список для for, который можно зациклить, сгладив два отдельных списка, один из $*IN.lines(), другой из $*FOO.lines().)

Но вы не построили выражение, вы просто сразу последовали за $*IN.lines() с last.

Поскольку нет инфиксного оператора last и last должно быть первым словомв операторе для того, чтобы это было ключевое слово last, компилятор интерпретирует last как термин - и поэтому он видит «Два термина в ряд».

Вам нужно last, чтобыбыть ключевым словом оператора, и оно должно быть в контексте цикла for.Но у вас уже есть утверждение в контексте цикла for, а именно выражение / термин say ....Вам нужно несколько скобок или аналогичных, чтобы позволить вам написать несколько утверждений.Вот один из способов:

{ last when ""; say "VERBOSE \"$_ is the string\"" } for $*IN.lines();

Теперь ваш код работает.

Финальные настройки

Я мог бы также добавить пару финальных настроек:

( last when ''; say qq[VERBOSE "$_ is the string"]; $i++ ) for lines ;
  • Я переключился с {...} на (...).Он не более компактен, но показывает, что вы можете использовать вместо символов скобок скобки, когда for записывается как модификатор оператора (т.е. в конце оператора, а не в начале).{...} создает лексическую область видимости, тогда как (...) - нет;Есть моменты, когда один или другой - именно то, что вам нужно.

  • Вам не нужен $*IN., потому что есть подпункт lines, который эквивалентен $*IN.lines().

  • Я удалил () после lines, потому что они не нужны, если нет аргументов после lines (или $*IN.lines) и до концазаявление.

  • Я использовал '' вместо "", потому что я думаю, что это хорошая привычка использовать не интерполирующие кавычки, если вам не нужны интерполяционные.

  • Я использовал qq[...], потому что это означает, что вам не нужно экранировать " в строке.

  • У меня естьиспользуется $i++ вместо $i=$i+1, потому что он достигает того же эффекта, и я думаю, что он читается лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...