mirror of
https://gitlab.com/eql/EQL5.git
synced 2026-01-06 17:22:56 -08:00
171 lines
4.2 KiB
Common Lisp
171 lines
4.2 KiB
Common Lisp
;;; copyright (c) Polos Ruetz
|
|
|
|
(defpackage :x
|
|
(:use :common-lisp)
|
|
(:export
|
|
#:cc
|
|
#:bytes-to-string
|
|
#:d
|
|
#:do-string
|
|
#:do-with
|
|
#:empty-string
|
|
#:ensure-compiled
|
|
#:ensure-list
|
|
#:ends-with
|
|
#:it
|
|
#:it*
|
|
#:if-it
|
|
#:if-it*
|
|
#:join
|
|
#:let-it
|
|
#:path
|
|
#:split
|
|
#:starts-with
|
|
#:string-split
|
|
#:string-substitute
|
|
#:string-to-bytes
|
|
#:when-it
|
|
#:when-it*
|
|
#:while
|
|
#:while-it
|
|
#:with-gensyms))
|
|
|
|
(provide :x)
|
|
|
|
(in-package :x)
|
|
|
|
(defmacro if-it (exp then &optional else)
|
|
`(let ((it ,exp))
|
|
(if it ,then ,else)))
|
|
|
|
(defmacro if-it* (exp then &optional else)
|
|
`(let ((it* ,exp))
|
|
(if it* ,then ,else)))
|
|
|
|
(defmacro let-it (exp &body body)
|
|
`(let ((it ,exp))
|
|
,@body
|
|
it))
|
|
|
|
(defmacro when-it (exp &body body)
|
|
`(let ((it ,exp))
|
|
(when it ,@body)))
|
|
|
|
(defmacro when-it* (exp &body body)
|
|
`(let ((it* ,exp))
|
|
(when it* ,@body)))
|
|
|
|
(defmacro with-gensyms (syms &body body)
|
|
`(let ,(mapcar (lambda (s)
|
|
`(,s (gensym)))
|
|
syms)
|
|
,@body))
|
|
|
|
(defmacro while (exp &body body)
|
|
`(do ()
|
|
((not ,exp))
|
|
,@body))
|
|
|
|
(defmacro while-it (exp &body body)
|
|
`(do ((it))
|
|
((not (setf it ,exp)))
|
|
,@body))
|
|
|
|
(defmacro do-string ((var str) &body body)
|
|
`(map nil (lambda (,var)
|
|
,@body)
|
|
,str))
|
|
|
|
(defmacro do-with (with &body body)
|
|
`(progn
|
|
,@(mapcar (lambda (line)
|
|
(append with (if (or (atom line)
|
|
(eql 'quote (first line)))
|
|
(list line)
|
|
line)))
|
|
body)))
|
|
|
|
(defun d (&rest args)
|
|
"A simple debug print."
|
|
(print (cons :debug args)))
|
|
|
|
(defun cc (&rest args)
|
|
"Convenient string concatenation."
|
|
(apply 'concatenate 'string args))
|
|
|
|
(defun empty-string (s)
|
|
(zerop (length s)))
|
|
|
|
(defun %str-with (sub str starts)
|
|
(let ((l1 (length str))
|
|
(l2 (length sub)))
|
|
(when (>= l1 l2)
|
|
(string= sub (subseq str (if starts 0 (- l1 l2)) (when starts l2))))))
|
|
|
|
(defun starts-with (sub str)
|
|
(%str-with sub str t))
|
|
|
|
(defun ends-with (sub str)
|
|
(%str-with sub str nil))
|
|
|
|
(defun string-split (string separator)
|
|
(let ((len (length separator))
|
|
list)
|
|
(do ((e (search separator string) (search separator string :start2 (+ e len)))
|
|
(b 0 (+ e len)))
|
|
((not e) (push (subseq string b) list))
|
|
(push (subseq string b e) list))
|
|
(nreverse list)))
|
|
|
|
(defun string-substitute (new old string)
|
|
(let ((len (length old)))
|
|
(with-output-to-string (s)
|
|
(do ((e (search old string) (search old string :start2 (+ e len)))
|
|
(b 0 (+ e len)))
|
|
((not e) (write-string (subseq string b) s))
|
|
(write-string (subseq string b e) s)
|
|
(write-string new s)))))
|
|
|
|
(defun ensure-list (x)
|
|
(if (listp x) x (list x)))
|
|
|
|
(defun split (str &optional (sep #\Space))
|
|
(unless (zerop (length str))
|
|
(let (list)
|
|
(do ((e (position sep str) (position sep str :start (1+ e)))
|
|
(b 0 (1+ e)))
|
|
((not e) (push (subseq str b) list))
|
|
(push (subseq str b e) list))
|
|
(nreverse list))))
|
|
|
|
(defun join (list &optional (sep #\Space))
|
|
(format nil (concatenate 'string "~{~A~^" (string sep) "~}")
|
|
list))
|
|
|
|
(defun bytes-to-string (b)
|
|
(map 'string 'code-char b))
|
|
|
|
(defun string-to-bytes (s)
|
|
(map 'vector 'char-code s))
|
|
|
|
(defun ensure-compiled (file-name)
|
|
"Expects file name without file ending, and returns (re-)compiled file name."
|
|
(let ((lisp (concatenate 'string file-name ".lisp"))
|
|
(fasl (concatenate 'string file-name ".fas*"))) ; for *.fas, *.fasb, *.fasc (Unix, Windows)
|
|
(flet ((compiled ()
|
|
(first (directory fasl))))
|
|
(unless (and (compiled)
|
|
(>= (file-write-date (compiled))
|
|
(file-write-date lisp)))
|
|
(compile-file lisp))
|
|
(compiled))))
|
|
|
|
(defun path (name)
|
|
"Needed because ECL uses base strings (not Unicode) for pathnames internally."
|
|
#+(or darwin linux)
|
|
(funcall (intern "QUTF8" :eql) name)
|
|
#+win32
|
|
(if (< (funcall (intern "%WINDOWS-VERSION" :eql)) #xa0)
|
|
(funcall (intern "QLOCAL8BIT" :eql) name) ; Windows 7 and lower
|
|
name)) ; Windows 8 and higher
|
|
|