forked from cbaggers/varjo
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils-v.lisp
More file actions
155 lines (127 loc) · 5.47 KB
/
utils-v.lisp
File metadata and controls
155 lines (127 loc) · 5.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
(in-package :varjo)
(defun cons-end (thing list)
(concatenate 'list list (list thing)))
(defun listify (x) (if (listp x) x (list x)))
(defun lambda-list-get-names (l-list)
(let ((keywords '(&allow-other-keys &environment &rest &aux &key &whole &body
&optional)))
(loop :for i :in l-list
:if (not (member i keywords))
:collect (if (listp i) (first i) i))))
;; [TODO] fully implement positions-if to match position-if spec
;; [TODO] also add positions-if-not and positions: could be all be useful
(defun positions-if (predicate sequence)
(loop :for element :in sequence :for i :from 0
:if (funcall predicate element) :collect i))
(defmacro pipe-> (args &body stages)
"\(pipe-> \(1 2 3\) #'a #'b #'c #'d\)
Calls first function with args provided and uses result as
arguments for next function. Uses multiple-value-call so you
can use (values) to specify complex lambda-args."
(let ((stages (reverse stages)))
(when stages
(let ((stage (first stages)))
(if (eq 'function (first stage))
`(multiple-value-call ,stage
,(if (rest stages)
`(pipe-> ,args ,@(reverse (rest stages)))
(if (listp args)
`(values ,@args)
`(values-list ,args))))
(destructuring-bind (check-func &rest steps) stage
`(let ((rest (multiple-value-list
,(if (rest stages)
`(pipe-> ,args ,@(reverse (rest stages)))
(if (listp args)
`(values ,@args)
`(values-list ,args))))))
(let ((args rest))
(let ((passes nil))
(loop :do (let ((results (multiple-value-list
(pipe-> ,@(cons 'args steps)))))
(setf args results)
(push results passes))
:until (,check-func (first passes) (second passes))))
(values-list args)))))))))
;; [TODO] should dissapear as refactor goes on
(defun acons-many (data a-list)
(if data (let* ((func (first data))
(name (first func))
(body (second func)))
(acons name (cons body (rest (assoc name a-list)))
(acons-many (rest data) a-list)))
a-list))
(defun kwd (&rest args)
(intern (format nil "~{~a~}" args) 'keyword))
;; [TODO] areas where this is used probably need that part extracted
(defun fmt (control-string &rest format-args)
(apply #'format `(nil ,control-string ,@format-args)))
;; [TODO] is this used anywhere?
(defun print-hash (hash-table)
(loop for x being the hash-keys of hash-table
:do (print (format nil "~s -> ~s" x (gethash x hash-table))))
hash-table)
;; [TODO] as with fmt
(defun printf (control-string &rest format-arguments)
(apply #'format (append (list t control-string) format-arguments)))
(defun group (source n)
"This takes a flat list and emit a list of lists, each n long
containing the elements of the original list"
(if (zerop n) (error "zero length"))
(labels ((rec (source acc)
(let ((rest (nthcdr n source)))
(if (consp rest)
(rec rest (cons (subseq source 0 n)
acc))
(nreverse (cons source acc))))))
(if source
(rec source nil)
nil)))
(defun symb (&rest args)
"This takes a list of symbols (or strings) and outputs one
symbol.
If the input is symbol/s then the output is a regular symbol
If the input is string/s, then the output is
a |symbol like this|"
(values (intern (format nil "~{~a~}" args))))
(defun p-symb (package &rest args)
"This takes a list of symbols (or strings) and outputs one
symbol.
If the input is symbol/s then the output is a regular symbol
If the input is string/s, then the output is
a |symbol like this|"
(values (intern (format nil "~{~a~}" args) package)))
(defun symbol-name-equal (x y)
(when (and (symbolp x) (symbolp y))
(equal (symbol-name x) (symbol-name y))))
;;[TODO] why is this ever needed?
(defun truep (x) (not (null x)))
;;[TODO] these are candidates for loop always
(defun eqp! (x)
(lambda (val) (eq val x)))
(defun eqlp! (x)
(lambda (val) (eql val x)))
(defun equalp! (x)
(lambda (val) (equal val x)))
(defun eq-elements (list)
(or (null list) (every (eqp! (car list)) list)))
(defun eql-elements (list)
(or (null list) (every (eqlp! (car list)) list)))
(defun equal-elements (list)
(or (null list) (every (equalp! (car list)) list)))
;;[TODO] what is it used for?
(defun identity-filter (list t-map)
(mapcan (lambda (x m) (when m (list x))) list t-map))
(defun symbol-name-position (symbol list)
(let ((symb-name (string-upcase symbol)))
(position-if #'(lambda (x) (when (symbolp x) (equal (symbol-name x) symb-name))) list)))
(defmacro assocr (item alist &key (key nil keyp)
(test nil testp)
(test-not nil notp))
`(cdr (assoc ,item ,alist
,@(when keyp (list :key key))
,@(when testp (list :test test))
,@(when notp (list test-not)))))
(defun list-contains-duplicates-p (list &key (key #'identity) (test #'eq))
(loop :for i :in list :do
(when (> (count i list :key key :test test) 1) (return t))))