2023-02-05 00:40:06 -05:00
|
|
|
|
|
|
|
;; small utilities ---------------------------------
|
|
|
|
|
|
|
|
(module utils *
|
|
|
|
(import
|
|
|
|
scheme
|
|
|
|
(chicken base)
|
|
|
|
(chicken pathname)
|
|
|
|
(clojurian syntax)
|
|
|
|
srfi-1 ;; list utils
|
2023-02-05 01:44:52 -05:00
|
|
|
)
|
2023-02-05 00:40:06 -05:00
|
|
|
;; (bail [message [exit-status]])
|
|
|
|
;; end the program immediately.
|
|
|
|
;; if a message is provided, print it to the screen.
|
|
|
|
;; exit-status defaults to 1.
|
|
|
|
(define (bail #!optional msg (status 1))
|
|
|
|
(when msg (print msg))
|
|
|
|
(exit status))
|
|
|
|
|
|
|
|
;; clojureish "debugging by print statement" tool since i still haven't reached
|
|
|
|
;; lisp enlightenment
|
|
|
|
(define ((inspect #!optional label #!rest args) s)
|
|
|
|
(display (list label ":" args " => " s) (current-error-port))
|
|
|
|
(newline (current-error-port))
|
|
|
|
s)
|
|
|
|
|
|
|
|
;; decompose a path s into its constituent parts. returns values:
|
|
|
|
;;
|
|
|
|
;; root: "/" if it's an absolute path, "" if relative directory-elements: a list
|
|
|
|
;; of each directory from root, () if none basename: the filename with extension
|
|
|
|
;; removed like "readme" or ".bashrc" extension: the file extension with the
|
|
|
|
;; dot, like ".txt" or "" if none relative-root: the relative path from the
|
|
|
|
;; given path to the root
|
|
|
|
;; e.g foo/bar/baz.html -> ../../
|
|
|
|
;;
|
|
|
|
;; this is intended to provide default values that make for easier reassembly
|
|
|
|
;; into filenames.
|
|
|
|
;;
|
|
|
|
;; typical use:
|
|
|
|
;; (->> source-file
|
|
|
|
;; (pathparts)
|
|
|
|
;; (define-values (root elements basename extension relative-root)))
|
|
|
|
;;
|
|
|
|
(define (pathparts s)
|
|
|
|
(define-values (dirname basename extension)
|
|
|
|
(decompose-pathname s))
|
|
|
|
(define-values (origin root directory-elements)
|
|
|
|
(decompose-directory (or dirname "")))
|
|
|
|
;; discarding origin because idgaf about windows
|
|
|
|
(values (or root "")
|
|
|
|
(or directory-elements '())
|
|
|
|
basename
|
|
|
|
(if extension (string-append "." extension) "")
|
|
|
|
(->>
|
|
|
|
(or directory-elements '())
|
|
|
|
(map (constantly "../"))
|
|
|
|
(apply string-append))))
|
|
|
|
|
|
|
|
;; like (substring) but doesn't break if start and end are too big/small
|
|
|
|
(define (substring* s start end)
|
|
|
|
(substring s (max start 0) (min end (string-length s))))
|
|
|
|
|
|
|
|
;; merge alists a and b. values in b "win"
|
|
|
|
(define (alist-merge a b)
|
|
|
|
(lset-union (lambda (x y) (eq? (car x) (car y))) a b))
|
|
|
|
|
|
|
|
;; like alist-ref but works on nested alists by specifying a path (list of keys)
|
|
|
|
(define (alist-ref-in keys alist #!optional (test eqv?))
|
|
|
|
(if (null? (cdr keys))
|
|
|
|
(alist-ref (car keys) alist test)
|
|
|
|
(alist-ref-in (cdr keys) (alist-ref (car keys) alist test) test)))
|
|
|
|
|
|
|
|
;; like alist-update, but works on nested alists by specifying a path (list of
|
|
|
|
;; keys)
|
|
|
|
(define (alist-update-in keys value alist #!optional (test eqv?))
|
|
|
|
(cond
|
|
|
|
((not alist) #f)
|
|
|
|
((null? (cdr keys))
|
|
|
|
(alist-update (car keys) value alist test))
|
|
|
|
(else
|
|
|
|
(alist-update (car keys)
|
|
|
|
(alist-update-in (cdr keys) value (alist-ref (car keys) alist test) test)
|
|
|
|
alist test))))
|
|
|
|
|
|
|
|
(define (unless-equals s1 s2)
|
|
|
|
;; if s1 == s2, then s1, otherwise #f
|
|
|
|
(and (equal? s1 s2) s1))
|
|
|
|
)
|