804ef73ea7d5b807cfb67ea972e3293e56a371ab
[lice.git] / global.lisp
blob804ef73ea7d5b807cfb67ea972e3293e56a371ab
1 (in-package :lice)
3 (defconstant +debug-v+ 1)
4 (defconstant +debug-vv+ 2)
5 (defconstant +debug-vvv+ 3)
7 (defparameter *debug-level* +debug-v+)
8 ;;(defparameter *debug-level* +debug-vvv+)
10 (defun dformat (lvl &rest fmt-args)
11 (when (>= *debug-level* lvl)
12 (with-open-file (f #p"/tmp/debug" :direction :output :if-exists :append
13 :if-does-not-exist :create)
14 (apply 'format f fmt-args))))
16 (defmacro verbose-body (&body body)
17 "Print each sexpr in BODY and its return value."
18 (let ((ret (gensym "RET")))
19 (loop for i in body
20 collect `(let ((,ret ,i))
21 (format t "~s => ~s~%" ,i ,ret)
22 ,ret))))
24 (defun last1 (l)
25 "Return the last elt of the list."
26 (car (last l)))
28 (defun nconc1 (list item)
29 "destructively append ITEM to the end of L"
30 (nconc list (list item)))
32 ;; (defun grow-vector (vector amt initial-element)
33 ;; "grow the vector's size by AMT elements"
34 ;; (adjust-array vector (+ (length vector) amt)
35 ;; :initial-element initial-element
36 ;; :fill-pointer t))
38 ;; (defun vector-append (vector1 vector2)
39 ;; "append vector2 to the end of vector1."
40 ;; (let ((len (length vector1)))
41 ;; (grow-vector vector1 (length vector2) (elt vector2 0))
42 ;; (replace vector1 vector2 :start1 (1+ len) :start2 1)))
44 (define-condition lice-condition ()
45 () (:documentation "The base condition for all lice related errors."))
47 ;; (defun fmt (fmt &rest args)
48 ;; "A movitz hack function. FORMAT basically doesn't work, so i use this to get around it."
49 ;; (let ((s (make-array 100 :fill-pointer 0 :element-type 'character)))
50 ;; (apply #'format s fmt args)
51 ;; s))
53 #+movitz
54 (defun read-from-string (string)
55 "Read the string and return an sexpr. This is a MOVITZ hack
56 because it doesn't have read-from-string."
57 (muerte::simple-read-from-string string))
59 ;;; Lisp function we like to have
61 (defun concat (&rest strings)
62 "Concatenate all the arguments and make the result a string.
63 The result is a string whose elements are the elements of all the arguments.
64 Each argument must be a string."
65 (apply 'concatenate 'string strings))
67 (defmacro while (test &body body)
68 "If TEST yields non-nil, eval BODY... and repeat.
69 The order of execution is thus TEST, BODY, TEST, BODY and so on
70 until TEST returns nil."
71 (if body
72 `(loop while ,test do ,@body)
73 `(loop while ,test)))
75 (defun cdr-safe (object)
76 "Return the cdr of OBJECT if it is a cons cell, or else nil."
77 (when (consp object)
78 (cdr object)))
80 (defvar *quit-code* 7
81 "The terminal char code for the interrupt key.")
83 (defvar *inhibit-quit* nil
84 ;; XXX: this is not correct docs
85 "Non-nil inhibits C-g quitting from happening immediately.
86 Note that `quit-flag' will still be set by typing C-g,
87 so a quit will be signaled as soon as `inhibit-quit' is nil.
88 To prevent this happening, set `quit-flag' to nil
89 before making `inhibit-quit' nil.")
91 (defvar *waiting-for-input* nil
92 "T when we're waiting for .. input")
94 (defvar *quit-flag* nil
95 "Set to T when the user hit the quit key")
97 ;; XXX: get rid of this function and all callers
98 (defun assq (prop list)
99 "Return non-nil if key is `eq' to the car of an element of list.
100 The value is actually the first element of list whose car is key.
101 Elements of list that are not conses are ignored."
102 (assoc prop (remove-if 'listp list)))
104 (defmacro depricate (symbol refer-to)
105 "A macro to mark a symbol as depricated. This is done with
106 function in emacs whose purpose is better done another
107 way. For example, a set- function replaced by a setf function. "
108 `(setf (get (quote ,symbol) :depricated) (quote ,refer-to)))
110 (defun read-string-with-escapes (stream close)
111 "read in a string and handle \\f \\n \\r \\t \\v escape characters."
112 (with-output-to-string (out)
113 (do ((char (read-char stream nil :eof) (read-char stream nil :eof)))
114 ((or (eq char :eof) (char= char close))
115 (if (eq char :eof)
116 (error 'end-of-file :stream stream)))
117 (when (char= char #\\)
118 (setq char (read-char stream nil :eof))
119 (case char
120 (:eof (error 'end-of-file :stream stream))
121 (#\f (setq char #\Page))
122 (#\n (setq char #\Newline))
123 (#\r (setq char #\Return))
124 (#\t (setq char #\Tab))
125 (#\v (setq char #\Vt))))
126 (write-char char out))))
128 ;; LiCE handles a few escape codes like GNU Emacs
129 (set-macro-character #\" #'read-string-with-escapes)
131 (defun run-hooks (&rest hooks)
132 "Run each hook in HOOKS.
133 Each argument should be a symbol, a hook variable.
134 These symbols are processed in the order specified.
135 If a hook symbol has a non-nil value, that value may be a function
136 or a list of functions to be called to run the hook.
137 If the value is a function, it is called with no arguments.
138 If it is a list, the elements are called, in order, with no arguments.
140 Major modes should not use this function directly to run their mode
141 hook; they should use `run-mode-hooks' instead.
143 Do not use `make-local-variable' to make a hook variable buffer-local.
144 Instead, use `add-hook' and specify t for the LOCAL argument."
145 (mapc (lambda (h)
146 (when (symbolp h)
147 (setf h (symbol-value h)))
148 (mapc 'funcall h))
149 hooks))
151 (defun add-hook (hook function &optional append local)
152 "Add to the value of HOOK the function function.
153 FUNCTION is not added if already present.
154 FUNCTION is added (if necessary) at the beginning of the hook list
155 unless the optional argument append is non-nil, in which case
156 function is added at the end.
158 The optional fourth argument, LOCAL, if non-nil, says to modify
159 the hook's buffer-local value rather than its default value.
160 This makes the hook buffer-local if needed, and it makes t a member
161 of the buffer-local value. That acts as a flag to run the hook
162 functions in the default value as well as in the local value.
164 HOOK should be a symbol, and FUNCTION may be any valid function. If
165 HOOK is void, it is first set to nil. If HOOK's value is a single
166 function, it is changed to a list of functions."
167 (declare (ignore append local))
168 (pushnew function (symbol-value hook)))
170 (defun remove-hook (hook function &optional local)
171 "Remove from the value of HOOK the function FUNCTION.
172 HOOK should be a symbol, and FUNCTION may be any valid function. If
173 FUNCTION isn't the value of HOOK, or, if FUNCTION doesn't appear in the
174 list of hooks to run in HOOK, then nothing is done. See `add-hook'.
176 The optional third argument, LOCAL, if non-nil, says to modify
177 the hook's buffer-local value rather than its default value."
178 (declare (ignore local))
179 (setf (symbol-value hook) (remove function (symbol-value hook))))
181 (depricate substring subseq)
182 (defun substring (string from &optional (to (length string)))
183 "Return a substring of string, starting at index from and ending before to.
184 to may be nil or omitted; then the substring runs to the end of string.
185 from and to start at 0. If either is negative, it counts from the end.
187 This function allows vectors as well as strings."
188 (when (< from 0)
189 (setf from (max 0 (+ (length string) from))))
190 (when (< to 0)
191 (setf to (max 0 (+ (length string) to))))
192 (subseq string from to))
194 (depricate memq member)
195 (defun memq (elt list)
196 "Return non-nil if ELT is an element of LIST.
197 Comparison done with `eq'. The value is actually the tail of LIST
198 whose car is ELT."
199 (member elt list :test 'eq))
201 (defun int-to-string (n)
202 "Return the decimal representation of number as a string.
203 Uses a minus sign if negative.
204 number may be an integer or a floating point number."
205 (check-type n number)
206 (prin1-to-string n))
208 (defun split-string (string &optional (separators "
210 "Splits STRING into substrings where there are matches for SEPARATORS.
211 Each match for SEPARATORS is a splitting point.
212 The substrings between the splitting points are made into a list
213 which is returned.
214 ***If SEPARATORS is absent, it defaults to \"[ \f\t\n\r\v]+\".
216 If there is match for SEPARATORS at the beginning of STRING, we do not
217 include a null substring for that. Likewise, if there is a match
218 at the end of STRING, we don't include a null substring for that.
220 Modifies the match data; use `save-match-data' if necessary."
221 ;; FIXME: This let is here because movitz doesn't 'lend optional'
222 (let ((seps separators))
223 (labels ((sep (c)
224 (find c seps :test #'char=)))
225 (loop for i = (position-if (complement #'sep) string)
226 then (position-if (complement #'sep) string :start j)
227 while i
228 as j = (position-if #'sep string :start i)
229 collect (subseq string i j)
230 while j))))
232 ;; A cheap memoizer. Obviously, a hashtable would be better.
234 (defstruct memoize-state
235 (data (vector nil nil nil nil nil nil nil nil nil nil nil nil))
236 (test 'equal)
237 (pt 0))
239 (defun memoize-store (state thing value)
240 (incf (memoize-state-pt state))
241 (when (>= (memoize-state-pt state)
242 (length (memoize-state-data state)))
243 (setf (memoize-state-pt state) 0))
244 (setf (svref (memoize-state-data state) (memoize-state-pt state)) (cons thing value))
245 value)
247 (defmacro memoize (mem-var thing compute)
248 "Check if we've computed a value for thing. if so, use it. if
249 not compute it, store the result, and return it."
250 (let ((match (gensym "MATCH")))
251 `(let ((,match (find ,thing (memoize-state-data ,mem-var) :key 'first :test (memoize-state-test ,mem-var))))
252 (if ,match
253 (cdr ,match)
254 (memoize-store ,mem-var ,thing ,compute)))))
256 (provide :lice-0.1/global)