1 ;;;; Banana -- allows network abstraction, nearly always.
2 ;;;; by Allen Short <washort@twistedmatrix.com>
3 ;;;; This file is in the public domain.
5 "'Get into a rut early: Do the same processes the same way. Accumulate
6 idioms. Standardize. The only difference(!) between Shakespeare and you was
7 the size of his idiom list -- not the size of his vocabulary.'
8 -- Alan Perlis, Programming Epigram #10"
13 ;; (defconst default-vocabulary
14 ;; ;; Jelly Data Types
26 ;; (unpersistable . -12)
34 ;; ;; PB Protocol Messages
40 ;; (not-logged-in . -24)
41 ;; (cachemessage . -25)
49 (defun banana-int-char (c)
52 (defconst high-bit
(banana-int-char 128))
53 (defconst list-type
(banana-int-char 128))
54 (defconst int-type
(banana-int-char 129))
55 (defconst string-type
(banana-int-char 130))
56 (defconst neg-type
(banana-int-char 131))
57 (defconst float-type
(banana-int-char 132))
59 (defmacro special-case
(expr &rest clauses
)
60 (append (list 'ecase expr
)
63 (cons (eval (car i
)) (cdr i
))) clauses
)))
65 (defun read-integer-base128 (string)
66 (loop for i
= 0 then
(+ i
(* (char-int char
) (expt 128 place
)))
67 for place
= 0 then
(1+ place
)
68 for char across string
71 (defun make-banana-decoder (data-received connection-ready
)
72 (lexical-let ((-stack- ())
75 (-data-received- data-received
)
76 (-connection-ready- connection-ready
)
78 (lambda (socket chunk
)
80 (flet ((eat-item (item)
82 (setf (cdar -stack-
) (nconc (cdar -stack-
) (list item
)))
83 (setf -output- item
))))
84 (let ((buffer (concat -buffer- chunk
)))
85 (while (/= (length buffer
) 0)
86 (let* ((pos (let ((i 0)) (loop ;junk
90 (num-string (substring buffer
0 pos
))
91 (num (read-integer-base128 num-string
))
92 (type-byte (aref buffer pos
))
93 (rest (substring buffer
(1+ pos
))))
94 (setq -buffer- buffer
)
95 (special-case type-byte
97 (setq -stack-
(acons num
'() -stack-
))
100 (if (>= (length rest
) num
)
102 (setq buffer
(substring rest num
))
103 (eat-item (substring rest
0 num
)))
113 (string-to-number num-string
)))
114 (loop while
(and -stack-
115 (= (length (cdar -stack-
))
117 do
(eat-item (cdr (pop -stack-
))))))
118 (setf -buffer-
""))))
120 ;; (print -output- (get-buffer-create "*banana-debug*"))
123 (funcall -data-received- -output-
) (setf -output- nil
))
125 (setf -vocab-
"none")
126 (banana-send-encoded socket
"none")
127 (funcall -connection-ready-
)))))))
129 (defun print-integer-base128 (int stream
)
131 (print (banana-int-char 0) stream
)
133 (error "positive numbers only. blame Allen for breaking it")
136 do
(write-char (banana-int-char (logand int
127)) stream
)
137 (setf int
(ash int -
7))))))
141 (defun banana-encode (obj stream
)
144 (print-integer-base128 (length obj
) stream
)
145 (write-char list-type stream
)
146 (mapc (lambda (x) (banana-encode x stream
)) obj
))
148 (print-integer-base128 (abs obj
) stream
)
150 (write-char int-type stream
)
151 (write-char neg-type stream
)))
154 (write-char float-type
))
156 (print-integer-base128 (length obj
) stream
)
157 (write-char string-type stream
)
160 ;; (let ((code (cdr (assoc obj default-vocabulary))))
162 ;; (error "Unrecognised jelly symbol"))
164 ;; (print-integer-base128 (- code) stream)
165 ;; (write-char vocab-type stream)))
166 (let ((my-symbol-name (symbol-name obj
)))
167 (print-integer-base128 (length my-symbol-name
) stream
)
168 (write-char string-type stream
)
169 (princ my-symbol-name stream
)))
170 (t (error "Couldn't send object"))))
172 (defun banana-send-encoded (bse-process obj
)
173 (banana-encode obj
(lambda (data) (process-send-string bse-process
(if (stringp data
) data
(string data
))))))