LINUX.ORG.RU

Как узнать откуда ошибка в DrRacket?

 


0

1

Есть программа. В ней кусок

(require "loadlib.rkt")
...
(define-gobject* g-type-name (_fun _ulong -> string))
...

Допустил опечатку. Вместо _string написал string. Проверка синтаксиса проходит без предупреждений. При загрузке получаю сообщение об ошибке

. . loadlib.rkt:46:8: ffi-call: contract violation
  expected: ctype?
  given: #<procedure:string>
  argument position: 3rd
  other arguments...:
   #<ffi-obj>
   '(#<ctype:uint32>)
   #f
   #f
   #f

В loadlib.rkt:46:8 находится определение макроса define-gobject*. Причём он распаковывается в команду (define-gobject g-type-name (_fun _ulong -> string) #:c-name g_type_name) и никаких ffi-call там нет.

Как добиться от Racket нормальных сообщений об ошибке? Как минимум, нужно место применения макроса, а не его определения. Угадывать по тексту ошибки, в каком именно определении функции неверный аргумент, удовольствие ниже среднего.

★★★★★

Попробуй делать как то так:

#lang racket/base

(require (for-syntax racket/base))

(define-syntax (macro stx)
  (syntax-case stx ()
    [(_ a)
     #`(with-handlers ([exn:fail:contract?
                        (lambda (e)
                          (raise-syntax-error 'macro (exn-message e) #'#,stx))])
         (+ a 1))]))

(macro 'a)
Не знаю, может есть более адекватный способ.

qaqa ★★
()
Ответ на: комментарий от qaqa

Попробуй в рассылке спросить, там лучше помогут.

qaqa ★★
()
Ответ на: комментарий от qaqa

Попробуй делать как то так

Так контракт-то не мой. В loadlib.rkt

(define gobject-lib 
  (case (system-type)
    [(windows) 
     (ffi-lib "libgobject-2.0-0")]
    [else (ffi-lib "libgobject-2.0" '("0" ""))]))

(define-ffi-definer define-gobject gobject-lib)

(define-syntax-rule (with-template (var ...) ([form ...] ...) body ...)
  (begin (define-syntax-rule (inner var ...) (begin ((... ...) body) ...))
         (inner form ...) ...))

(with-template 
 (src dst)
 ([define-gi define-gi*]
  [define-gobject define-gobject*])
 (define-syntax (dst stx)
   (syntax-parse stx
     [(_ id:id expr:expr 
         (~or params:expr
              (~and (~seq (~seq kw:keyword arg:expr)) (~seq kwd ...))
              (~optional (~seq #:c-id c-id) 
                         #:defaults ([c-id (datum->syntax
                                            #'id 
                                            (string->symbol 
                                             (c-name (syntax-e #'id))))]))) ...)
      #`(src id expr params ... kwd ... ... #:c-id c-id)])))

А вылетает ошибка, судя по всему, в раскрытии define-gobject.

Если напрямую использовать define-gobject, то всё корректно — подсвечивает строку с define-gobject (правда ругается также непонятно на ffi-call, но в одной строчке разобраться можно, что не так). Как бы скастовать того анонимуса, что рассказывал, что в Scheme макросы правильнее чем в CL поддержкой обработки ошибок?

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Ну попробуй вот так:

#`(with-handlers ([exn:fail:contract? (λ (e) (raise-syntax-error 'dst (exn-message e) #'#,stx))])
    (src id expr params ... kwd ... ... #:c-id c-id))

Суть в том, чтоб перехватыватить исключение и снова сформировать, но уже с информацией о месте применения макроса. Ошибка естественно может быть в любом месте в раскрытии макроса. Не совсем корректно, но ты же хотел место где макрос использовался подсветить.

Есть еще вариант с syntax-parse:

#lang racket/base

(require (for-syntax racket/base syntax/parse) ffi/unsafe)

(define-syntax (macro stx)
  (syntax-parse stx
    [(_ a)
        #:declare a (expr/c #'ctype?
                            #:name "C type of argument")
     #'a.c]))

(macro '_string)

Он по идее более правильный, но сообщение об ошибке не очень мне нравится.

qaqa ★★
()
Ответ на: комментарий от qaqa
(with-template 
 (src dst)
 ([define-gi define-gi*]
  [define-gobject define-gobject*])
 (define-syntax (dst stx)
   (syntax-parse stx
     [(_ id:id expr:expr 
         (~or params:expr
              (~and (~seq (~seq kw:keyword arg:expr)) (~seq kwd ...))
              (~optional (~seq #:c-id c-id) 
                         #:defaults ([c-id (datum->syntax
                                            #'id 
                                            (string->symbol 
                                             (c-name (syntax-e #'id))))]))) ...)
      #`(with-handlers ([exn:fail:contract? 
                         (λ (e) (raise-syntax-error 'dst (exn-message e) #'#,stx))])
          (src id expr params ... kwd ... ... #:c-id c-id))])))

ломается при первом применении

(define-gobject* g-type-init (_fun -> _void))

begin (possibly implicit): no expression after a sequence of internal definitions in: (begin (define-gobject g-type-init (_fun -> _void) #:c-id g_type_init))

Он по идее более правильный

Этот вариант правильный, но у меня params надо тогда как-то рекурсивно разбирать. Если брать как есть, то

> (ctype? (_fun _string -> string))
#t

Ругаться начинает только при создании объекта по этому ctype.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

ломается при первом применении

Ну да, этот вариант не прокатит. Я не сразу вспомнил, что там у тебя происходит. По идее легко можно без define-ffi-definer обойтись. Написать свой вариант. Тогда прокатит.

Этот вариант правильный, но у меня params надо тогда как-то рекурсивно разбирать

Надо, а куда деваться.

qaqa ★★
()
Ответ на: комментарий от qaqa

Надо, а куда деваться.

Как-то добавить в компилятор, чтобы ругался хотя бы как SBCL

../gtk-cffi/g-object/g-type.lisp:28:1:
  error: 
    unknown CFFI type: G-TYP.
    --> PROGN CFFI:DEFCSTRUCT EVAL-WHEN 
    ==>
      (CFFI::NOTICE-FOREIGN-STRUCT-DEFINITION 'G-OBJECT-CFFI:G-TYPE-CLASS
                                              '(:CLASS
                                                G-OBJECT-CFFI::G-TYPE-CLASS-TCLASS)
                                              '((G-OBJECT-CFFI::G-TYPE-TYPE
                                                 G-OBJECT-CFFI::G-TYP)))

Здесь ../gtk-cffi/g-object/g-type.lisp:28 — место опечатки, PROGN CFFI:DEFSRTUCT и CFFI::NOTICE-FOREIGN-STRUCT-DEFINITION — последовательно этапы развёртки макроса до момента, где обнаружена ошибка.

Жаль, полнофункциональные продолжения (continuations) в SBCL никак не прикрутить :-((

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Да, того бы анонимуса неплохо теперь в тред :)

mv ★★★★★
()
Ответ на: комментарий от qaqa

Хотя нет, в данном случае не поможет.

Посмотрел тут внимательно на define-ffi-definer. Попробуй добавить:

(define-syntax (define-2 stx)
  (syntax-case stx ()
    [(_ id expr)
     (quasisyntax/loc stx
       (define id
         (with-handlers ([exn:fail:contract?
                          (lambda (e) (raise-syntax-error 'id (exn-message e) #'#,stx))])
           expr)))]))

И поправить:

(define-ffi-definer define-gtk gtk-lib #:define define-2)
(define-ffi-definer define-gi gi-lib #:define define-2)

(syntax/loc stx
  (src id expr params ... kwd ... ... #:c-id c-id))
qaqa ★★
()

Как узнать откуда ошибка

Из ДНК.

Здоровый индивидуум не будет тратить в XXI веке свое время на изучение эзотерических и маргинальных технологий.

anonymous
()
Ответ на: комментарий от qaqa

(syntax/loc stx

Заменил в конце #'(...) на (syntax/loc stx (...)).

Теперь ругается на нужную строку. Жаль, что по-умолчанию такого поведения нет (и в syntax-rules, кстати, тоже).

monk ★★★★★
() автор топика

Установи в макросе source location раскрытой формы на location принятой

anonymous
()
Ответ на: комментарий от monk

Жаль, что по-умолчанию такого поведения нет (

это да. при чем совершенно непонятно, чем это мотивировано.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.