Yani karakter dizisinden, veri tipine, veri tipinden ise karakter dizisine dönüşümleri sağlayan "parser" ve "render" yazabiliyoruz bunlarla. Örnek vermek gerekirse (zom: zero-or-more, :fixnum? ise diğer bir ayrıştırıcı v.b.):
(defrule version? (version d)
(:fixnum? d) (:do (push d version))
(:zom #\. (:fixnum? d) (:do (push d version)))
(:return (nreverse version)))
(defrule http-protocol? (version)
(:seq "HTTP/") (:version? version)
(:return (list 'HTTP version)))
Http başlığındaki sürüm bilgisini bu iki (ve ilkel diğer birleştireçler) ayrıştırıcının birleşmesi sonucu ayıklıyoruz akış içerisinden.
SERVER> (with-core-stream (s "HTTP/1.1")
(http-protocol? s))
(HTTP (1 1))
Ayrıştırıcılar lisp dünyasının temel veri tipi olan anlamlı listeler dönüyor gördüğünüz gibi. Bunun tersi olan işlem ise liste tiplerini karakter dizisi olarak ifade edebilmeyi sağlayan betimleyiciler. Bizim rfc2616 gerçekleştirimimizin testlerinden buna bir örnek vermek gerekirse:
(deftest http-location!
(with-core-stream (s "")
(http-location! s (make-uri :scheme "http"
:username "john"
:password "foo"
:server "127.0.0.1"
:port 8080
:paths '(("test") ("me") ("up.html"))))
(equal (return-stream s)
"http://john:foo@127.0.0.1:8080/test/me/up.html"))
t)
Burada betimleyicinin karmaşık bir liste alması yerine daha basit bir veri yapısı kullanıldığını görüyorsunuz (uri sınıfı). Bu veri yapısını akışa yazan bir test, ve akıştaki veriyi alıp olması gereken karakter dizisi ile karşılaştırıyoruz.
Bu akışlar ve bunların üzerinde çalışan ayrıştırıcılar oldukça faydalı. HTTP belirtimini okuyup sırasıyla bütün BNF'yi gerçekleştirebiliyoruz (bunun benzeri ve hatta daha kuvvetli olanı haskell'de parsec, ve BNF'den doğrudan ayrıştırıcı yaratan happy var).
Bahsedebileceğim diğer bir özellik ise iş parçacıklarını kolay kullanabilmemizi sağlayan kodlar. Örneğin sunucumuz için gerekli olan basit kayıt defteri aşağıdaki gibi programlanabiliyor.
(defclass logger-server (local-unit)
((log-stream :accessor log-stream :initarg :log-stream :initform nil)
(log-path :accessor log-path :initarg :log-path
:initform (default-log-path))))
(defmethod/unit log-me-raw :async-no-return ((self logger-server) message)
(string! (log-stream self) message)
(char! (log-stream self) #\Newline))
İşin güzel yanı burada iş parçacığına özel bir programlama görmüyorsunuz. Ancak logger-server sınıfından bir örnek yaratıp çalıştırdığınızda (bunun bir start metodu var) diğer iş parçacıkları log-me-raw adlı metodu eş zamanlı olarak çağırabiliyor ve sihirli bir şekilde bu çağırımlar girişmeden, sıralı olarak işliyor.
SERVER> (defparameter *logger1* (make-instance 'logger-server
:log-stream *standard-output*))
*LOGGER1*
SERVER> (start *logger1*)
NIL
SERVER> (log-me-raw *logger1* "core.gen.tr iz c00l")
core.gen.tr iz c00l
Bunu 40 iş parçacığıyla test edince çıktının tertemiz olduğunu görebiliyoruz:
(defparameter *logger* (make-instance 'logger-server))
(defclass my-worker (local-unit)
((id :accessor id :initarg :id)))
(defmethod/unit logmeup :async-no-return ((self my-worker))
(log-me *logger* (format nil "I'm here as number ~D" (id self))))
(defparameter *workerz* (loop
for i from 1 to 40
collect (make-instance 'my-worker :id i)))
(defun setup-loggerz ()
(start *logger*)
(mapcar #'start *workerz*)
(mapcar #'logmeup *workerz*)
(mapcar #'stop *workerz*)
(sleep 5)
(stop *logger*))
Bunların yanında bir de sürdürmeleri kullanan web sunucumuz var artık. Eskiden ucw kullanıyorduk ancak küfür ede ede onu bıraktık şimdi daha işlevsel olmasını istediğimiz yeni bir sunucu bileşeni yazıyoruz. Sunucu doğal olarak ucw+ gibi ajax desteklesin istedik, ve şu an yavaş yavaş yeni sunucu altyapısı oluşuyor.
Sonuç olarak bu kodlara göz atmak isteyenler aşağıdaki adresi kullanabilirler:
http://www.core.gen.tr/projects/core-server/
Sunucuyu kurmak isteyenler aşağıdaki bağlantıdaki kurulum paketini kullanabilirler. Kurulum paketi bütün bağımlılıkları internet üzerinden indirip derleyen bir paket. Bu pakette de betiklerde çoğunlukla karşımıza çıkan "command pattern" için bir çözüm bulmanız mümkün.
http://www.core.gen.tr/projects/core-server-installer-latest.tar.gz
Tekrar söylemekte fayda görüyorum, bize common lisp ile çalışabilecek deneyim sahibi katılımcılar lazım. Şu an çalışmanın büyük bir bölümünü Evrim ULU yürütüyor. Zaten çoğu gerçekleştirim de ona ait. Çevrenizde common lisp programlama yapmak isteyen birileri varsa ve bu anlattığım konularla ilgilenmişse lütfen bize ulaşmalarını sağlayın. Katılmak isteyenler doğrudan erişmek için IRC sunucumuza da gelebilirler.
irc.core.gen.tr:7000
Lütfen gelin, nolur gelin, geldirin, ettirin, katkı sağlayın.
Sevgiler...
--
aycan
_______________________________________________
cs-lisp mailing list
cs-lisp@cs.bilgi.edu.tr
http://cs.bilgi.edu.tr/mailman/listinfo/cs-lisp