Jump to content

Не работает локальная функция *ERROR* и функция vl-catch-all-apply не предотвращает прерывание кода


Recommended Posts

Здравствуйте!

 

Столкнулся с двумя проблемами при адаптации 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)
  )

 

Link to comment
Share on other sites

Заметил одну особенность с 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...

Link to comment
Share on other sites

Хм... Забавно - попробовал нечто типа:

Команда: (setq err (vl-catch-all-apply '(lambda() (/ 50 0))))
"vlax_catch_err::деление на ноль"

Т.е. в err хранится не объект, а сразу какая-то строка с отчетом. Мало того, ни отдельное переопределение *error*, ни отдельное же использование vl-catch-all-apply ситуацию с Esc не меняет.

Все коды переделывать? Вы издеваетесь?

Edited by kpblc
Link to comment
Share on other sites

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"))
  )
)

несколько раз прилетало, а чо удобно, сразу видно где косяк, хотя непонятно)))

Link to comment
Share on other sites

Тут вопрос в теме не на предмет отлова ошибок вообще, а на предмет отлова нажатия пользователем Esc. Обычные-то ошибки отлавливаются на раз.

Link to comment
Share on other sites

8 минут назад, kpblc сказал:

Тут вопрос в теме не на предмет отлова ошибок вообще, а на предмет отлова нажатия пользователем Esc. Обычные-то ошибки отлавливаются на раз.

В целом, да. В первую очередь, хотелось-бы решить вопрос с обработкой нажатия клавиши Esc. Но и тот факт, что локально объявленный обработчик ошибок *ERROR* не работает.

В приведённом коде выше, следующая часть кода не имеет смысла...

...
  (defun *error* (msg)
    (prompt (strcat "\nError loading " short ": " msg))
  )
...

 

Link to comment
Share on other sites

У меня постепенно начинает зреть подозрение, что всех разработчиков постепенно по-тихому загоняют в NET/С++ ;)

 

Edited by kpblc
Link to comment
Share on other sites

14 минут назад, kpblc сказал:

У меня постепенно начинает зреть подозрение, что всех разработчиков постепенно по-тихому загоняют в NET/С++ ;)

 

Возможно...

Начал постепенно осваивать .Net, в силу того, что халява OpenDCL не поддерживается в NС и теперь создаю диалоги в VS.

Не хотелось бы уходить от Lisp'a, т.к. очень уж к ниму привык. Надеюсь, что со временем, разработчики реализуют в .Net возможность создание собственных Lisp функций (я про это...), и тем самым, будет возможность расширить его функционал и в некоторых моментах увеличить скорость выполнения.

Тогда, как мне кажется, у Lisp'а будут шансы на жизнь, хотя-бы на энтузиазме сторонних разработчиков.

  • Like 2
Link to comment
Share on other sites

Сугубо ИМХО... Сразу уходить на NET, причем делать прицел на NET6 (он же Core). Сам сейчас как раз подобным извратом занимаюсь.

Link to comment
Share on other sites

Posted (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 by Maksim Yablokv
Link to comment
Share on other sites

  • 1 month later...
В 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 с можете добавить? 

Link to comment
Share on other sites

Posted (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 by Maksim Yablokv
  • Thanks 2
Link to comment
Share on other sites

Мне почему-то кажется, что сам факт "отлова" ошибки / отмены выбора со стороны пользователя - дело не сильно первое. Важнее будет получить результат выбора. Было что-то выбрано - стандартный список. Нет? Ну тогда nil.

Как это сделать на лиспе в nanoCAD, каюсь, не представляю.

Link to comment
Share on other sites

Конечно, выявленные особенности реализации функции vl-catch-all-apply весьма неприятны.

Если с типом возвращаемого значения в случае ошибки ('STR - в нано, специальный тип #<%catch-all-apply-error%> - в АС) можно сработаться, хотя и тут могут возникнуть проблемы совместимости, то корректное срабатывание только для некоторых типов ошибок сильно дискредитирует реализацию, т.к. перед использованием приходится проверять работоспособность функции именно для твоегo кейса. И, если не подходит, может потребоваться  довольно значительная переделка кода, т.к. удобной альтернативы не просматривается...

Edited by EdwardSt
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Tell a friend

    Love Официальный форум компании Нанософт Разработка? Tell a friend!
×
×
  • Create New...