함수 또는 매크로가 바이트 컴파일러 경고를 지정할 수 있습니까?


15

원칙적으로 임의의 수의 인수를 취하는 함수를 작성 중입니다. 그러나 실제로는 짝수 개의 인수 만 전달해야하며 그렇지 않은 경우 바람직하지 않은 결과를 생성합니다.

컨텍스트에 대한 더미 예제는 다음과 같습니다.

(defun my-caller (&rest args)
  (while args
    (call-other-function (pop args) (pop args))))

elisp 파일이 바이트 컴파일 될 때 바이트 컴파일러는 잘못된 수의 인수로 함수가 호출되는 것을 볼 때 경고를 발생시킵니다. 분명히, my-caller그것은 숫자를 갖도록 정의되어 있기 때문에 결코 일어나지 않을 것 입니다.

그래도 설정 가능한 심볼 속성이 있거나 (declare)정의에 추가 할 수 있는 양식이있을 수 있습니다. 이 함수에는 짝수의 인수 만 주어져야한다는 것을 사용자에게 알리는 것.

  1. 바이트 컴파일러에이 제한을 알리는 방법이 있습니까?
  2. 그렇지 않은 경우 함수 대신 매크로로 가능합니까?

"... 잘못된 수의 인수 로 함수가 호출되는 것을 볼 때 "?
itsjeyd

답변:


13

편집 : 최근 Emacs 에서이 작업을 수행하는 더 좋은 방법 은 인수 수를 확인하기 위해 컴파일러 매크로 를 정의하는 것 입니다. 일반적인 매크로를 사용하여 내 원래의 대답은 다음과 보존되지만가 기능을 전달하는 것을 방해하지 않기 때문에 컴파일러 매크로는 우수 funcall또는 apply런타임에.

최신 버전의 Emacs에서는 인수 수를 확인하고 일치하지 않는 경우 경고 (또는 오류)를 생성하는 함수에 컴파일러-매크로를 정의하여이를 수행 할 수 있습니다. 유일한 미묘한 점은 컴파일러 매크로가 평가 또는 컴파일을 위해 원래 함수 호출 양식을 변경하지 않고 반환해야한다는 것입니다. &whole인수 를 사용하여 값을 반환하면됩니다. 이것은 다음과 같이 달성 될 수 있습니다 :

(require 'cl-lib)

(defun my-caller (&rest args)
  (while args
    (message "%S %S" (pop args) (pop args))))

(define-compiler-macro my-caller (&whole form &rest args)
  (when (not (cl-evenp (length args)))
    (byte-compile-warn "`my-caller' requires an even number of arguments"))
  form)

(my-caller 1 2 3 4)
(my-caller 1 2)
(funcall #'my-caller 1 2 3 4)       ; ok
(apply #'my-caller '(1 2))          ; also ok
(my-caller 1)                       ; produces a warning
(funcall #'my-caller 1 2 3)         ; no warning!
(apply #'my-caller '(1 2 3))        ; also no warning

funcallapply컴파일러 매크로에 의해 인수 검사를 건너 뛸 지금 사용할 수 있지만. 이름에도 불구하고, 컴파일러 매크로도를 통해 평가 '해석'의 과정에서 확장하는 것 C-xC-e, M-xeval-buffer당신이 평가에뿐만 아니라,이 예제를 컴파일에 오류를 얻을 수 있도록.


원래 답변은 다음과 같습니다.

다음은 "확장시 경고를 제공하는 매크로를 사용하는"Jordon의 제안을 구현하는 방법입니다. 매우 쉬운 것으로 밝혀졌습니다.

(require 'cl-lib)

(defmacro my-caller (&rest args)
  (if (cl-evenp (length args))
      `(my-caller--function ,@args)
    (error "Function `my-caller' requires an even number of arguments")))

(defun my-caller--function (&rest args)
  ;; function body goes here
  args)

(my-caller 1 2 3 4)
(my-caller 1 2 3)

위의 파일을 컴파일하려고 시도 .elc하면 컴파일 로그에 클릭 가능한 멋진 오류 메시지와 함께 실패합니다 ( 파일이 생성 되지 않음 ).

test.el:14:1:Error: `my-caller' requires an even number of arguments

또한 대체 할 수 (error …)와 함께 (byte-compile-warn …)컴파일을 계속 할 수 있도록하는 대신 오류의 경고를 생성합니다. (댓글로 지적 해 주신 Jordon에게 감사드립니다).

컴파일시 매크로가 확장되므로이 검사와 관련된 런타임 패널티가 없습니다. 물론 다른 사람이 my-caller--function직접 전화하는 것을 막을 수는 없지만 적어도 이중 하이픈 규칙을 사용하여 "개인"기능으로 광고 할 수 있습니다.

이 목적으로 매크로를 사용할 때 주목할만한 단점my-caller 은 더 이상 일류 함수가 아니라는 것입니다. funcallapply, 런타임 에 또는 런타임에 전달할 수 없습니다 (또는 적어도 예상 한대로 수행하지는 않습니다). 그런 점 에서이 솔루션은 실제 함수에 대한 컴파일러 경고를 단순히 선언 할 수있는 것만 큼 좋지 않습니다. 물론 사용 apply하면 어쨌든 컴파일 타임에 함수에 전달되는 인수 수를 확인할 수 없으므로 허용되는 절충입니다.


2
다음과 같이 컴파일 경고가 생성됩니다 :byte-compile-warn
Jordon Biondo

이제 함수에 대한 컴파일러 매크로를 정의하여 더 효과적으로 수행 할 수 있는지 궁금합니다. 이것은 매크로 래퍼 가 apply없거나 funcall매크로 래퍼 가 아닌 단점을 제거합니다 . 나는 그것을 시도하고 그것이 작동하면 대답을 편집 할 것입니다.
Jon O.

11

그렇습니다 byte-defop-compiler. 함수를 컴파일하는 함수를 실제로 지정하는 byte-defop-compiler데 사용할 수 있으며, 함수가 여러 인수를 기반으로 경고를 생성하도록 지정하는 데 도움이되는 내장 기능이 있습니다.

선적 서류 비치

FUNCTION에 컴파일러 양식을 추가하십시오. function이 기호 인 경우 변수 "byte-SYMBOL"은 사용할 opcode의 이름을 지정해야합니다. function이 목록 인 경우 첫 번째 요소는 함수이고 두 번째 요소는 바이트 코드 기호입니다. 두 번째 요소는 nil 일 수 있으며 opcode가 없음을 의미합니다. COMPILE-HANDLER는이 바이트 연산을 컴파일하는 데 사용되는 함수이거나 약어 0, 1, 2, 3, 0-1 또는 1-2 일 수 있습니다. 이 값이 0이면 핸들러는 "byte-compile-SYMBOL입니다.


용법

특정 경우 약어 중 하나를 사용하여 함수에 두 개의 인수가 제공되도록 정의 할 수 있습니다.

(byte-defop-compiler my-caller 2)

이제 함수는 2 개의 인수 이외의 것으로 컴파일 될 때 경고를 표시합니다.

더 구체적인 경고를하고 자신의 컴파일러 함수를 작성하려면. 에서 봐 byte-compile-one-arg및 참조 bytecomp.el에서 다른 유사한 기능을한다.

유효성 검사를 처리하기 위해 일부 함수를 지정하는 것이 아니라 실제로 컴파일도 수행합니다. bytecomp.el에서 다시 컴파일 함수는 좋은 참조를 제공합니다.


안전한 경로

이것은 내가 온라인으로 문서화하거나 논의한 것으로 보지 않았지만 전반적으로 나는 이것이 바람직하지 않다고 말할 것입니다. 올바른 경로 (IMO)는 설명 서명으로 데푼을 작성하거나 확장 시간에 경고를 제공하는 매크로를 사용하여 인수 길이를 확인하고 오류를 사용 byte-compile-warn하거나 error표시하는 것입니다. eval-when-compile오류 검사를 수행 하는 데 도움이 될 수도 있습니다 .

또한 함수를 사용하기 전에 함수를 정의 byte-defop-compiler해야하며 컴파일러가 함수를 실제로 호출하기 전에 호출해야합니다.

다시 한 번, 실제로 내가 문서에서 보거나 조언하지 않은 것 같지만 (잘못 될 수 있음) 여기에 따르는 패턴은 빈 defuns로 가득 찬 패키지에 대해 일종의 헤더 파일을 지정하는 것이라고 생각합니다. 로 전화를 byte-defop-compiler겁니다. 기본적으로 실제 패키지를 컴파일하기 전에 필요한 패키지입니다.

의견 : 내가 아는 것에 기초하여, 나는이 모든 것에 대해 방금 배웠기 때문에 그다지 아무 것도하지 말 것을 권합니다. 이제까지


1
관련 : bytecomp-simplify 는 바이트 컴파일러에 추가 경고를 알려줍니다.
Wilfred Hughes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.