Maksim Yablokv Posted April 4 Report Share Posted April 4 Здравствуйте! Столкнулся с двумя проблемами при адаптации lisp'а под nano. 1. Не работает функция ERROR определённая локально. 2. Попытка предотвратить прерывание кода функцией vl-catch-all-apply не увенчалась успехом. Код всё равно прерывается и не выполняется полностью. Для демонстрации привожу тестовую команду TEST1. Если на запрос выбора примитива нажать Esc, выполнение кода прерывается. Локальное определение функции ERROR игнорируется, и выполняется функция ERROR определённая глобально. В итоге, в командной строке результат:ошибка: функция прервана А должно быть: Конец команды TEST1 Тестировал: Платформа nanoCAD, версия 22.0, сборка ВСЕ. Встречал здесь на форуме адаптированный под nano набор функций Pltools, в котором все перечисленные функции присутствуют. И задаюсь теперь вопросом - эти функции работают некорректно только у меня на 22 версии? Какие есть варианты решения данных проблем? Переопределение функции ERROR глобально не вариант! Отказаться от vl-catch-all-apply не могу( (defun C:TEST1 (/ *ERROR*) (defun *ERROR* (MSG / ) (princ "\n Сработала локальная функция *ERROR*") (princ) ) (vl-load-com) (vl-catch-all-apply (function (lambda () (entsel "\n Нажмите Esc:") ) ) ) (princ "\n Конец команды TEST1") (princ) ) Quote Link to comment Share on other sites More sharing options...
Maksim Yablokv Posted April 4 Author Report Share Posted April 4 Заметил одну особенность с vl-catch-all-apply Исключение вызывает нажатие клавиши Esc Ошибки в коде, vl-catch-all-apply отрабатывает как нужно. Пример: (defun C:TEST4 (/ res) (vl-load-com) (setq res (vl-catch-all-apply (function (lambda () (/ 2 0) ) ) ) ) (if (vl-catch-all-error-p res) (alert "Ошибка: Деление на ноль!") ) (princ "\n Конец команды TEST4") (princ) ) В результате выполнения, NC выдаёт сообщение "Ошибка: Деление на ноль!" и в командной строке: Конец команды TEST4 Вопрос как обработать исключение предотвратить прерывание кода вызванное кнопкой Esc... Quote Link to comment Share on other sites More sharing options...
kpblc Posted April 4 Report Share Posted April 4 (edited) Хм... Забавно - попробовал нечто типа: Команда: (setq err (vl-catch-all-apply '(lambda() (/ 50 0)))) "vlax_catch_err::деление на ноль" Т.е. в err хранится не объект, а сразу какая-то строка с отчетом. Мало того, ни отдельное переопределение *error*, ни отдельное же использование vl-catch-all-apply ситуацию с Esc не меняет. Все коды переделывать? Вы издеваетесь? Edited April 4 by kpblc Quote Link to comment Share on other sites More sharing options...
doctorraz Posted April 4 Report Share Posted April 4 57 минут назад, kpblc сказал: а сразу какая-то строка с отчетом давеча на эту тему общались возвращает имя файла, строку и столбец где ошибка))) пока с этим игрался... лиспер то я еще тот))) (defun SuperLoadLispClassic ( fn / *error* short ) (defun *error* (msg) (prompt (strcat "\nError loading " short ": " msg)) ) (if (findfile fn) (progn (prompt (strcat "\nLoading " (setq short (strcat (vl-filename-base fn) (vl-filename-extension fn)) ) " from " (vl-filename-directory fn)) ) (load fn) ) (prompt (strcat "\nFile " fn " not found")) ) ) несколько раз прилетало, а чо удобно, сразу видно где косяк, хотя непонятно))) Quote Link to comment Share on other sites More sharing options...
kpblc Posted April 4 Report Share Posted April 4 Тут вопрос в теме не на предмет отлова ошибок вообще, а на предмет отлова нажатия пользователем Esc. Обычные-то ошибки отлавливаются на раз. Quote Link to comment Share on other sites More sharing options...
Maksim Yablokv Posted April 4 Author Report Share Posted April 4 8 минут назад, kpblc сказал: Тут вопрос в теме не на предмет отлова ошибок вообще, а на предмет отлова нажатия пользователем Esc. Обычные-то ошибки отлавливаются на раз. В целом, да. В первую очередь, хотелось-бы решить вопрос с обработкой нажатия клавиши Esc. Но и тот факт, что локально объявленный обработчик ошибок *ERROR* не работает. В приведённом коде выше, следующая часть кода не имеет смысла... ... (defun *error* (msg) (prompt (strcat "\nError loading " short ": " msg)) ) ... Quote Link to comment Share on other sites More sharing options...
kpblc Posted April 4 Report Share Posted April 4 (edited) У меня постепенно начинает зреть подозрение, что всех разработчиков постепенно по-тихому загоняют в NET/С++ Edited April 4 by kpblc Quote Link to comment Share on other sites More sharing options...
Maksim Yablokv Posted April 4 Author Report Share Posted April 4 14 минут назад, kpblc сказал: У меня постепенно начинает зреть подозрение, что всех разработчиков постепенно по-тихому загоняют в NET/С++ Возможно... Начал постепенно осваивать .Net, в силу того, что халява OpenDCL не поддерживается в NС и теперь создаю диалоги в VS. Не хотелось бы уходить от Lisp'a, т.к. очень уж к ниму привык. Надеюсь, что со временем, разработчики реализуют в .Net возможность создание собственных Lisp функций (я про это...), и тем самым, будет возможность расширить его функционал и в некоторых моментах увеличить скорость выполнения. Тогда, как мне кажется, у Lisp'а будут шансы на жизнь, хотя-бы на энтузиазме сторонних разработчиков. 2 Quote Link to comment Share on other sites More sharing options...
kpblc Posted April 4 Report Share Posted April 4 Сугубо ИМХО... Сразу уходить на NET, причем делать прицел на NET6 (он же Core). Сам сейчас как раз подобным извратом занимаюсь. Quote Link to comment Share on other sites More sharing options...
Maksim Yablokv Posted April 6 Author Report Share Posted April 6 (edited) Всем привет! В общем, ответа от разработчиков NC пока нет, а ждать у моря погоды нет времени, то для себя решил обойти проблему следующим образом. Хранить штатное глобальное определение обработчика ошибок в переменной, и по мере работы, переопределять и восстанавливать её определение. Вот так: ;При загрузке Lisp файла сохраняем штатное определение обработчика ошибок в переменную *standart-error* (setq *standart-error* *error*) (defun c:TEST ( / ) ;При запуске команды TEST переопределяем глобально обработчик ошибок (defun *error* ( msg ) ; в случаи ошибки восстанавливаем обработчик ошибок (setq *error* *standart-error*) ; Логика в случаи ошибки ; Если нужно, можем сказать с чем связана ошибка (if (wcmatch (strcase msg t) "*break*,*cancel*,*exit*,*quit*,*отмен*,*прерв*") (princ "\n Команда прервана пользователем\n") (princ (strcat "\n ERRNO # " (itoa (getvar "ERRNO")) ": " msg "\n" )) ) (princ) ) ; Логика команды TEST ; восстанавливаем обработчик ошибок (setq *error* *standart-error*) (princ) ) Интересно узнать, кто что думает о таком решении? И как вы оцениваете надёжность данного способа? Edited April 6 by Maksim Yablokv Quote Link to comment Share on other sites More sharing options...
lidia.antipina.ru Posted June 2 Report Share Posted June 2 В 06.04.2023 в 16:27, Maksim Yablokv сказал: Всем привет! В общем, ответа от разработчиков NC пока нет, а ждать у моря погоды нет времени, то для себя решил обойти проблему следующим образом. Хранить штатное глобальное определение обработчика ошибок в переменной, и по мере работы, переопределять и восстанавливать её определение. Вот так: ;При загрузке Lisp файла сохраняем штатное определение обработчика ошибок в переменную *standart-error* (setq *standart-error* *error*) (defun c:TEST ( / ) ;При запуске команды TEST переопределяем глобально обработчик ошибок (defun *error* ( msg ) ; в случаи ошибки восстанавливаем обработчик ошибок (setq *error* *standart-error*) ; Логика в случаи ошибки ; Если нужно, можем сказать с чем связана ошибка (if (wcmatch (strcase msg t) "*break*,*cancel*,*exit*,*quit*,*отмен*,*прерв*") (princ "\n Команда прервана пользователем\n") (princ (strcat "\n ERRNO # " (itoa (getvar "ERRNO")) ": " msg "\n" )) ) (princ) ) ; Логика команды TEST ; восстанавливаем обработчик ошибок (setq *error* *standart-error*) (princ) ) ;При загрузке Lisp файла сохраняем штатное определение обработчика ошибок в переменную *standart-error* (setq *standart-error* *error*) (defun c:TEST ( / ) ;При запуске команды TEST переопределяем глобально обработчик ошибок (defun *error* ( msg ) ; в случаи ошибки восстанавливаем обработчик ошибок (setq *error* *standart-error*) ; Логика в случаи ошибки ; Если нужно, можем сказать с чем связана ошибка (if (wcmatch (strcase msg t) "*break*,*cancel*,*exit*,*quit*,*отмен*,*прерв*") (princ "\n Команда прервана пользователем\n") (princ (strcat "\n ERRNO # " (itoa (getvar "ERRNO")) ": " msg "\n" )) ) (princ) ) ; Логика команды TEST ; восстанавливаем обработчик ошибок (setq *error* *standart-error*) (princ) ) Интересно узнать, кто что думает о таком решении? И как вы оцениваете надёжность данного способа? Более подробный готовый тест с логикой команды с ошибкой и логикой в случае ошибки и без на выход по exit с можете добавить? Quote Link to comment Share on other sites More sharing options...
Maksim Yablokv Posted June 2 Author Report Share Posted June 2 (edited) 12 часов назад, lidia.antipina.ru сказал: Более подробный готовый тест с логикой команды с ошибкой и логикой в случае ошибки и без на выход по exit с можете добавить? Я попробую... ;Переопределяем глобальный обработчик ошибок *ERROR* ;Так будет более наглядно, если будет вызван именно он. (defun *ERROR* (MSG /) (alert "Сработала глобальная функция *ERROR*!") (princ) ) ;Тест 1 ;Создаём команду с локальной функцией обработчика ошибок *ERROR* ;В таком исполнении команды, в AutoCAD, сработает локальный обработчик ошибок ;и мы увидим сообщение: Сработала локальная функция *ERROR*! ;В nanoCAD, мы получаем сообщение: Сработала глобальная функция *ERROR*! (defun C:TEST1 (/ *ERROR*) (defun *ERROR* (MSG /) (alert "Сработала локальная функция *ERROR*!") (princ) ) (exit) (princ) ) ;Тест 2 ;Создаём команду и оборачиваем функцию exit в функцию vl-catch-all-apply ;В таком исполнении команды, в AutoCAD и в nanoCAD, исключение будет перехвачено ;функцией vl-catch-all-apply и аварийного завершения команды не произойдёт. ;В результате мы увидим сообщение: Код выполнен! (defun C:TEST2 () (vl-load-com) (vl-catch-all-apply '(lambda () (exit) ) ) (alert "Код выполнен!") (princ) ) ;Тест 3 ;Создаём команду и оборачиваем функцию entsel в функцию vl-catch-all-apply ;На запрос выбора объекта просим пользователя нажать клавишу Esc ;В таком исполнении команды, в AutoCAD, исключение будет перехвачено функцией ;vl-catch-all-apply и аварийного завершения команды не произойдёт. ;В результате мы увидим сообщение: Код выполнен! ;В nanoCAD, мы получаем сообщение: Сработала глобальная функция *ERROR*! (defun C:TEST3 () (vl-load-com) (vl-catch-all-apply '(lambda () (entsel "\nНажмите Esc:") ) ) (alert "Код выполнен!") (princ) ) ;Тест 4 ;Создаём команду аналогично команде TEST3 ;дополнительно добавляем локальный обработчик ошибок *ERROR* ;Результат тот-же что и в TEST3 (defun C:TEST4 (/ *ERROR*) (defun *ERROR* (MSG /) (alert "Сработала локальная функция *ERROR*!") (princ) ) (vl-load-com) (vl-catch-all-apply '(lambda () (entsel "\nНажмите Esc:") ) ) (alert "Код выполнен!") (princ) ) ;Тест 5 ;Создаём команду аналогично команде TEST3, но временно сохраняем ;глобальный обработчик ошибок *ERROR* в переменную *GLOBAL-ERROR* ;В таком исполнении команды, в AutoCAD, исключение будет перехвачено функцией ;vl-catch-all-apply и аварийного завершения команды не произойдёт. ;В результате мы увидим сообщение: Код выполнен! ;В nanoCAD, мы получаем сообщение от временного обработчика ошибок: ;Сработала временная функция *ERROR*! (defun C:TEST5 () ;Сохраняем глобальный обработчик ошибок в переменную *GLOBAL-ERROR* (setq *GLOBAL-ERROR* *ERROR*) ;На время работы команды TEST5 переопределяем глобальный обработчик ошибок (defun *ERROR* (MSG /) ;Если обработчик ошибок сработал, восстанавливаем глобальный обработчик ошибок (setq *ERROR* *GLOBAL-ERROR*) (alert "Сработала временная функция *ERROR*!") (princ) ) (vl-load-com) (vl-catch-all-apply '(lambda () (entsel "\nНажмите Esc:") ) ) (alert "Код выполнен!") ;Код выполнен без ошибок. Восстанавливаем глобальный обработчик ошибок. (setq *ERROR* *GLOBAL-ERROR*) (princ) ) Из всех тестов вывод следующий: 1. Локально определённый обработчик ошибок в nanoCAD не работает. 2. Функция vl-catch-all-apply не позволяет обработать исключение вызванное нажатием клавиши Esc. TEST5 демонстрирует листинг который я сейчас использую чтобы перехватить все возможные исключения. Очень не хотелось переопределять, и затем восстанавливать глобальный обработчик ошибок... Но увы, других вариантов, как обработать подобные исключения я не нашёл. Тестировал на версиях 22.0 и 23.0 Более поздние версии я не рассматриваю. Edited June 2 by Maksim Yablokv 2 Quote Link to comment Share on other sites More sharing options...
kpblc Posted June 3 Report Share Posted June 3 Мне почему-то кажется, что сам факт "отлова" ошибки / отмены выбора со стороны пользователя - дело не сильно первое. Важнее будет получить результат выбора. Было что-то выбрано - стандартный список. Нет? Ну тогда nil. Как это сделать на лиспе в nanoCAD, каюсь, не представляю. Quote Link to comment Share on other sites More sharing options...
EdwardSt Posted June 5 Report Share Posted June 5 (edited) Конечно, выявленные особенности реализации функции vl-catch-all-apply весьма неприятны. Если с типом возвращаемого значения в случае ошибки ('STR - в нано, специальный тип #<%catch-all-apply-error%> - в АС) можно сработаться, хотя и тут могут возникнуть проблемы совместимости, то корректное срабатывание только для некоторых типов ошибок сильно дискредитирует реализацию, т.к. перед использованием приходится проверять работоспособность функции именно для твоегo кейса. И, если не подходит, может потребоваться довольно значительная переделка кода, т.к. удобной альтернативы не просматривается... Edited June 5 by EdwardSt Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.