Bir işlev veya makro bayt derleyici uyarılarını belirtebilir mi?


15

Prensip olarak, keyfi sayıda argüman alan bir fonksiyon yazıyorum. Bununla birlikte, pratikte, sadece eşit sayıda argüman geçirilmeli ve aksi takdirde istenmeyen sonuçlar doğuracaktır.

Bağlam için kukla bir örnek:

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

Bir elisp dosyası byte-compiled olduğunda, byte-compiler yanlış sayıda argümanla çağrılmış bir fonksiyon gördüğünde bir uyarı verir. Açıkçası, bu asla olmayacak my-caller, çünkü herhangi bir sayı alması tanımlandı.

Yine de, ayarlayabileceğim bir sembol özelliği veya (declare)tanımına ekleyebileceğim bir form olabilir. Kullanıcıya bu işleve yalnızca çift sayıda argüman verilmesi gerektiğini bildiren bir şey.

  1. Bayt derleyicisine bu kısıtlamayı bildirmenin bir yolu var mı?
  2. Değilse , bir işlev yerine bir makro ile mümkün mü?

“... yanlış sayıda argümanla çağrılmış bir fonksiyon gördüğünde ”?
itsjeyd

Yanıtlar:


13

EDIT : Son Emacs bunu yapmanın daha iyi bir yolu , bağımsız değişkenlerin sayısını denetlemek için bir derleyici makro tanımlamaktır . Normal bir makro kullanarak orijinal yanıtım aşağıda korunur, ancak bir derleyici makrosu üstündür, çünkü işlevin çalışma zamanında funcallveya applyçalışma zamanında geçmesini engellemez .

Emacs'ın son sürümlerinde, işleviniz için bağımsız değişken sayısını kontrol eden ve eşleşmezse bir uyarı (hatta hata) üreten bir derleyici makro tanımlayarak bunu yapabilirsiniz. Tek incelik, derleyici makrosunun orijinal işlev çağrı formunu değerlendirme veya derleme için değiştirmeden geri göndermesidir. Bu bir &wholeargüman kullanarak ve değerini döndürerek yapılır . Bu şu şekilde yapılabilir:

(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

Not funcallve applyderleyici tarafından makro argüman denetimi baypas şimdi kullanılabilir, ancak bunlar. Adlarının rağmen, derleyici makrolar da yoluyla değerlendirilmesi 'yorumlanır' sırasında genişletilmiş gibi görünüyor C-xC-e, M-xeval-buffer, sen değerlendirirken yanı sıra bu örneği derleme hataları alacak böylece.


Orijinal cevap aşağıdaki gibidir:

Jordon'un "genişletme zamanında uyarı sağlayacak bir makro kullanma" önerisini şu şekilde uygulayabilirsiniz. Çok kolay olduğu ortaya çıktı:

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

Yukarıdakileri bir dosyada derlemeye çalışmak .elc, derleme günlüğünde tıklanabilir bir hata mesajı vererek başarısız olur (hiçbir dosya üretilmez):

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

Derleme işleminin devam etmesine izin vererek bir hata yerine uyarı üretmek için (error …)ile de değiştirebilirsiniz (byte-compile-warn …). (Bunu yorumlarda belirttiği için Jordon'a teşekkürler).

Makrolar derleme zamanında genişletildiğinden, bu kontrolle ilişkili çalışma zamanı cezası yoktur. Tabii ki, başkalarının my-caller--functiondoğrudan aramasını durduramazsınız , ancak en azından çift tire kuralını kullanarak "özel" bir işlev olarak tanıtabilirsiniz.

Dikkate değer bir dezavantaj bu amaçla bir makro kullanmanın yani my-callerartık birinci sınıf bir fonksiyonudur: Eğer bunu geçemez funcallveya applyçalışma zamanında (ya da en azından bunu beklemek ne olmaz). Bu bakımdan, bu çözüm, gerçek bir işlev için derleyici uyarısı bildirmek kadar iyi değildir. Tabii ki, kullanmak applyzaten derleme zamanında işleve geçirilen argümanların sayısını kontrol etmeyi imkansız hale getirecektir, bu yüzden bu belki de kabul edilebilir bir değiş tokuştur.


2
Derleme uyarıları şu şekilde oluşturulur:byte-compile-warn
Jordon Biondo

Şimdi bunun fonksiyon için bir derleyici makrosu tanımlayarak daha etkili bir şekilde gerçekleştirilip gerçekleştirilemeyeceğini merak ediyorum. Bu , makro sargılayıcı olmama applyveya funcallmakro paketleyicinin dezavantajını ortadan kaldıracaktır . Dener ve çalışırsa cevabımı düzenlerim.
Jon O.

11

Evet byte-defop-compiler, işlevinizi derleyen bir işlevi belirtmek için kullanabilirsiniz, işlevlerinizin byte-defop-compilerbirkaç bağımsız değişkene dayalı olarak uyarı vermesi gerektiğini belirtmenize yardımcı olacak bazı yerleşik özellikler vardır.

belgeleme

FUNCTION için bir derleyici formu ekleyin. İşlev bir sembolse, "byte-SYMBOL" değişkeni kullanılacak opcode'u adlandırmalıdır. İşlev bir listeyse, ilk öğe işlevdir ve ikinci öğe baytkodu simgesidir. İkinci eleman sıfır olabilir, yani opcode yoktur. COMPILE-HANDLER, bu bayt-op'u derlemek için kullanılacak işlevdir veya 0, 1, 2, 3, 0-1 veya 1-2 kısaltmaları olabilir. Nil ise, işleyici "byte-compile-SYMBOL.


kullanım

Özel durumunuzda, işlevinize iki argüman verilmesi gerektiğini tanımlamak için kısaltmalardan birini kullanabilirsiniz.

(byte-defop-compiler my-caller 2)

Artık fonksiyonunuz 2 argüman dışında bir şeyle derlendiğinde uyarı verecektir.

Daha özel uyarılar vermek ve kendi derleyici işlevlerinizi yazmak istiyorsanız. Bak byte-compile-one-argve referans için bytecomp.el diğer benzer işlevleri.

Doğrulamayı işlemek için bazı işlevler değil, aynı zamanda derleme de yaptığınızı unutmayın. Yine bytecomp.el içindeki derleme fonksiyonları size iyi bir referans sağlayacaktır.


Daha Güvenli Rotalar

Bu, çevrimiçi olarak belgelendiğim veya tartıştığım bir şey değil, ancak genel olarak bunun yol alması için kötü tavsiye edildiğini söyleyebilirim. Doğru yol (IMO), kusurlarınızı açıklayıcı imzalarla yazmak veya genişletme zamanında uyarı sağlayacak, hatalarınızın uzunluğunu kontrol eden ve hataları göstermek için byte-compile-warnveya kullanarak bir makro kullanmak olacaktır error. Ayrıca eval-when-compilehata kontrolü yapmak için faydalanabilirsiniz .

Ayrıca, işlevinizin daha önce kullanılmadan önce tanımlanması byte-defop-compilerve derleyicinin işlevinizin gerçek çağrılarına ulaşması için çağrının yapılması gerekir.

Yine, gördüğüm şeyden gerçekten belgelenmemiş veya tavsiye edilmemiş gibi görünüyor (yanlış olabilir), ancak burada izlenecek kalıbın paketiniz için bir sürü boş kusurla dolu bir tür başlık dosyası belirtmek olacağını hayal ediyorum. ve çağırır byte-defop-compiler. Bu temelde gerçek paketinizin derlenebilmesi için gereken bir paket olacaktır.

Görüş: Bildiklerime dayanarak, çok fazla değil, çünkü tüm bunları öğrendim, çünkü bunları asla yapmamanızı tavsiye ederim. hiç


1
İlgili: Bayt derleyicisine ek uyarılar öğreten bytecomp-simplify var.
Wilfred Hughes
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.