1 (in-package "PARENSCRIPT")
3 (defun string-join (strings separator
)
4 (format nil
"~{~}" (format nil
"~~a~~^~a" separator
) strings
))
6 (defun string-split (string separators
&key
(keep-separators nil
) (remove-empty-subseqs nil
))
7 (do ((len (length string
))
12 (let ((split (if (> i last
)
13 (cons (subseq string last i
) res
)
15 (nreverse (if remove-empty-subseqs
16 (delete "" split
:test
#'string-equal
)
18 (when (member (char string i
) separators
)
19 (push (subseq string last i
) res
)
20 (when keep-separators
(push (string (char string i
)) res
))
23 (defparameter *special-chars
*
35 ;;; Parenscript-style symbol -> Javascript-style symbol
37 (defun constant-string-p (string)
38 (let ((len (length string
))
39 (constant-chars '(#\
+ #\
*)))
41 (member (char string
0) constant-chars
)
42 (member (char string
(1- len
)) constant-chars
))))
44 (defun first-uppercase-p (string)
45 (and (> (length string
) 1)
46 (member (char string
0) '(#\
+ #\
*))))
48 (defun untouchable-string-p (string)
49 (and (> (length string
) 1)
50 (char= #\
: (char string
0))))
52 (defun symbol-name-to-js-string (symbol)
53 "Given a Lisp symbol or string, produces to a valid JavaScript
54 identifier by following transformation heuristics case conversion. For
55 example, paren-script becomes parenScript, *some-global* becomes
57 (when (symbolp symbol
)
58 (setf symbol
(symbol-name symbol
)))
59 (let ((symbols (string-split symbol
'(#\.
#\
[ #\
]) :keep-separators t
:remove-empty-subseqs t
)))
60 (cond ((null symbols
) "")
61 ((= (length symbols
) 1)
66 (cond ((constant-string-p symbol
)
68 symbol
(subseq symbol
1 (1- (length symbol
)))))
69 ((first-uppercase-p symbol
)
71 symbol
(subseq symbol
1)))
72 ((untouchable-string-p symbol
)
74 symbol
(subseq symbol
1))))
78 ((and lowercase
(not all-uppercase
))
83 (dotimes (i (length symbol
))
84 (let ((c (char symbol i
)))
87 (setf lowercase
(not lowercase
)))
88 ((assoc c
*special-chars
*)
89 (dolist (i (coerce (cdr (assoc c
*special-chars
*)) 'list
))
92 (coerce (nreverse res
) 'string
)))
93 (t (string-join (mapcar #'symbol-name-to-js-string symbols
) "")))))
95 (defun ordered-set-difference (list1 list2
&key
(test #'eql
)) ; because the CL set-difference may not preserve order
96 (reduce (lambda (list el
) (remove el list
:test test
))
99 (defmacro aif
(test-form then-form
&optional else-form
)
100 `(let ((it ,test-form
))
101 (if it
,then-form
,else-form
)))
103 (defmacro once-only
((&rest names
) &body body
) ;; the version from PCL
104 (let ((gensyms (loop for nil in names collect
(gensym))))
105 `(let (,@(loop for g in gensyms collect
`(,g
(gensym))))
106 `(let (,,@(loop for g in gensyms for n in names collect
``(,,g
,,n
)))
107 ,(let (,@(loop for n in names for g in gensyms collect
`(,n
,g
)))