openlang

with-lenient-parse логирует ошибку, но SBCL всё равно падает в отладчик

Написал макрос, чтобы кривая строка в hosts-файле логировалась, а загрузка шла дальше. Вот он целиком:

(defmacro with-lenient-parse ((&key (log t)) &body body)
  `(handler-bind ((missing-field
                    (lambda (c)
                      (when ,log
                        (format *error-output* "skipping: ~A~%" c))
                      nil))
                  (bad-port
                    (lambda (c)
                      (when ,log
                        (format *error-output* "warn: ~A~%" c))
                      nil)))
     ,@body))

У parse-line есть рестарт skip-line, но я не уверен, что его вообще кто-то вызывает. Вход — name addr [port], один хост на строку, запускаю через sh run.sh.

Когда в файле есть web-02 (без addr), в stderr получаю skipping: line 2: missing addr. Потом SBCL падает в отладчик с той же самой ошибкой missing-field, и скрипт умирает. Я думал, что если вернуться из хендлера, то parse-line вернёт nil для этой строки, нет? Видимо, нет.

Чтобы пройти дальше, я удалил строку с web-02. Теперь получаю warn: line 4: bad port abc, а потом type error в privileged-p: NIL is not of type NUMBER. Эта функция к парсингу вообще не относится. Условие для порта — просто signal подкласса warning, и ничего из написанного мной не считает его фатальным.

Это два бага или одно непонимание того, как хендлер встраивается? Что вообще макрос обещает вызывающему коду? Пишу по памяти из транскрипта, так что полный бэктрейс вставить не могу.

Переведено с английскогоПоказать оригинал

Разговор продолжается 2

Следуя доводам
  1. Ссылка на ответ

    по-моему, это одно непонимание. хендлер в handler-bind, который просто возвращается, отказывается обрабатывать условие, поэтому оно идёт к следующему хендлеру, а когда их не остаётся — в отладчик. ничего не возвращает nil из parse-line. рестарт нужно вызывать прямо в хендлере: (invoke-restart 'skip-line).

    с bad-port то же самое. signal возвращает nil, поэтому порт в privileged-p остаётся nil.

    https://www.lispworks.com/documentation/HyperSpec/Body/m_handle.htm

    Переведено с английскогоПоказать оригинал
  2. Ссылка на ответ

    Небольшая оговорка к фиксу с рестартом (удобно, что хендлер выполняется до раскрутки стека): защитите вызов через find-restart, потому что голый invoke-restart падает с ошибкой, если skip-line не активен.

    (lambda (c)
      (let ((r (find-restart 'skip-line c)))
        (when r (invoke-restart r))))
    Переведено с английскогоПоказать оригинал

Другие стороны того же вопроса

  1. Свёртка пустого вектора возвращает нейтральный элемент

    Свёртка пустого вектора. APL отвечает. У каждой примитивной функции свой нейтральный элемент. Ноль для плюса. Единица для умн…

    Ответы 3Последняя активность apl
  2. Большинство моих макросов стали const и static

    Nim позволяет легко писать макросы. В этом и проблема. Прежде чем браться за macro, проверь инструменты подешевле. const вычи…

    Ответы 3Последняя активность nim
  3. it, _1 и имена параметров, которые я всё равно пишу

    В Ruby 3.4 появился it для параметра блока, и users.map { it.name } читается почти как предложение. Мне он нравится больше, ч…

    Ответы 0Последняя активность ruby