(calc-record-compilation-date): Remove.
[bpt/emacs.git] / lisp / calc / calc-prog.el
CommitLineData
136211a9 1;; Calculator for GNU Emacs, part II [calc-prog.el]
8f66f479 2;; Copyright (C) 1990, 1991, 1992, 1993, 2001 Free Software Foundation, Inc.
136211a9
EZ
3;; Written by Dave Gillespie, daveg@synaptics.com.
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is distributed in the hope that it will be useful,
8;; but WITHOUT ANY WARRANTY. No author or distributor
9;; accepts responsibility to anyone for the consequences of using it
10;; or for whether it serves any particular purpose or works at all,
11;; unless he says so in writing. Refer to the GNU Emacs General Public
12;; License for full details.
13
14;; Everyone is granted permission to copy, modify and redistribute
15;; GNU Emacs, but only under the conditions described in the
16;; GNU Emacs General Public License. A copy of this license is
17;; supposed to have been given to you along with GNU Emacs so you
18;; can know your rights and responsibilities. It should be in a
19;; file named COPYING. Among other things, the copyright notice
20;; and this notice must be preserved on all copies.
21
22
23
24;; This file is autoloaded from calc-ext.el.
25(require 'calc-ext)
26
27(require 'calc-macs)
28
29(defun calc-Need-calc-prog () nil)
30
31
32(defun calc-equal-to (arg)
33 (interactive "P")
34 (calc-wrapper
35 (if (and (integerp arg) (> arg 2))
36 (calc-enter-result arg "eq" (cons 'calcFunc-eq (calc-top-list-n arg)))
bf77c646 37 (calc-binary-op "eq" 'calcFunc-eq arg))))
136211a9
EZ
38
39(defun calc-remove-equal (arg)
40 (interactive "P")
41 (calc-wrapper
bf77c646 42 (calc-unary-op "rmeq" 'calcFunc-rmeq arg)))
136211a9
EZ
43
44(defun calc-not-equal-to (arg)
45 (interactive "P")
46 (calc-wrapper
47 (if (and (integerp arg) (> arg 2))
48 (calc-enter-result arg "neq" (cons 'calcFunc-neq (calc-top-list-n arg)))
bf77c646 49 (calc-binary-op "neq" 'calcFunc-neq arg))))
136211a9
EZ
50
51(defun calc-less-than (arg)
52 (interactive "P")
53 (calc-wrapper
bf77c646 54 (calc-binary-op "lt" 'calcFunc-lt arg)))
136211a9
EZ
55
56(defun calc-greater-than (arg)
57 (interactive "P")
58 (calc-wrapper
bf77c646 59 (calc-binary-op "gt" 'calcFunc-gt arg)))
136211a9
EZ
60
61(defun calc-less-equal (arg)
62 (interactive "P")
63 (calc-wrapper
bf77c646 64 (calc-binary-op "leq" 'calcFunc-leq arg)))
136211a9
EZ
65
66(defun calc-greater-equal (arg)
67 (interactive "P")
68 (calc-wrapper
bf77c646 69 (calc-binary-op "geq" 'calcFunc-geq arg)))
136211a9
EZ
70
71(defun calc-in-set (arg)
72 (interactive "P")
73 (calc-wrapper
bf77c646 74 (calc-binary-op "in" 'calcFunc-in arg)))
136211a9
EZ
75
76(defun calc-logical-and (arg)
77 (interactive "P")
78 (calc-wrapper
bf77c646 79 (calc-binary-op "land" 'calcFunc-land arg 1)))
136211a9
EZ
80
81(defun calc-logical-or (arg)
82 (interactive "P")
83 (calc-wrapper
bf77c646 84 (calc-binary-op "lor" 'calcFunc-lor arg 0)))
136211a9
EZ
85
86(defun calc-logical-not (arg)
87 (interactive "P")
88 (calc-wrapper
bf77c646 89 (calc-unary-op "lnot" 'calcFunc-lnot arg)))
136211a9
EZ
90
91(defun calc-logical-if ()
92 (interactive)
93 (calc-wrapper
bf77c646 94 (calc-enter-result 3 "if" (cons 'calcFunc-if (calc-top-list-n 3)))))
136211a9
EZ
95
96
97
98
99
100(defun calc-timing (n)
101 (interactive "P")
102 (calc-wrapper
103 (calc-change-mode 'calc-timing n nil t)
104 (message (if calc-timing
105 "Reporting timing of slow commands in Trail."
bf77c646 106 "Not reporting timing of commands."))))
136211a9
EZ
107
108(defun calc-pass-errors ()
109 (interactive)
110 ;; The following two cases are for the new, optimizing byte compiler
111 ;; or the standard 18.57 byte compiler, respectively.
112 (condition-case err
113 (let ((place (aref (nth 2 (nth 2 (symbol-function 'calc-do))) 15)))
114 (or (memq (car-safe (car-safe place)) '(error xxxerror))
115 (setq place (aref (nth 2 (nth 2 (symbol-function 'calc-do))) 27)))
116 (or (memq (car (car place)) '(error xxxerror))
117 (error "foo"))
118 (setcar (car place) 'xxxerror))
bf77c646 119 (error (error "The calc-do function has been modified; unable to patch."))))
136211a9
EZ
120
121(defun calc-user-define ()
122 (interactive)
123 (message "Define user key: z-")
124 (let ((key (read-char)))
125 (if (= (calc-user-function-classify key) 0)
126 (error "Can't redefine \"?\" key"))
127 (let ((func (intern (completing-read (concat "Set key z "
128 (char-to-string key)
129 " to command: ")
130 obarray
131 'commandp
132 t
133 "calc-"))))
134 (let* ((kmap (calc-user-key-map))
135 (old (assq key kmap)))
136 (if old
137 (setcdr old func)
bf77c646 138 (setcdr kmap (cons (cons key func) (cdr kmap))))))))
136211a9
EZ
139
140(defun calc-user-undefine ()
141 (interactive)
142 (message "Undefine user key: z-")
143 (let ((key (read-char)))
144 (if (= (calc-user-function-classify key) 0)
145 (error "Can't undefine \"?\" key"))
146 (let* ((kmap (calc-user-key-map)))
147 (delq (or (assq key kmap)
148 (assq (upcase key) kmap)
149 (assq (downcase key) kmap)
150 (error "No such user key is defined"))
bf77c646 151 kmap))))
136211a9
EZ
152
153(defun calc-user-define-formula ()
154 (interactive)
155 (calc-wrapper
156 (let* ((form (calc-top 1))
157 (arglist nil)
158 (is-lambda (and (eq (car-safe form) 'calcFunc-lambda)
159 (>= (length form) 2)))
160 odef key keyname cmd cmd-base func alist is-symb)
161 (if is-lambda
162 (setq arglist (mapcar (function (lambda (x) (nth 1 x)))
163 (nreverse (cdr (reverse (cdr form)))))
164 form (nth (1- (length form)) form))
165 (calc-default-formula-arglist form)
166 (setq arglist (sort arglist 'string-lessp)))
167 (message "Define user key: z-")
168 (setq key (read-char))
169 (if (= (calc-user-function-classify key) 0)
170 (error "Can't redefine \"?\" key"))
171 (setq key (and (not (memq key '(13 32))) key)
172 keyname (and key
173 (if (or (and (<= ?0 key) (<= key ?9))
174 (and (<= ?a key) (<= key ?z))
175 (and (<= ?A key) (<= key ?Z)))
176 (char-to-string key)
177 (format "%03d" key)))
178 odef (assq key (calc-user-key-map)))
179 (while
180 (progn
181 (setq cmd (completing-read "Define M-x command name: "
182 obarray 'commandp nil
183 (if (and odef (symbolp (cdr odef)))
184 (symbol-name (cdr odef))
185 "calc-"))
186 cmd-base (and (string-match "\\`calc-\\(.+\\)\\'" cmd)
187 (math-match-substring cmd 1))
188 cmd (and (not (or (string-equal cmd "")
189 (string-equal cmd "calc-")))
190 (intern cmd)))
191 (and cmd
192 (fboundp cmd)
193 odef
194 (not
195 (y-or-n-p
196 (if (get cmd 'calc-user-defn)
197 (concat "Replace previous definition for "
198 (symbol-name cmd) "? ")
199 "That name conflicts with a built-in Emacs function. Replace this function? "))))))
200 (if (and key (not cmd))
201 (setq cmd (intern (concat "calc-User-" keyname))))
202 (while
203 (progn
204 (setq func (completing-read "Define algebraic function name: "
205 obarray 'fboundp nil
206 (concat "calcFunc-"
207 (if cmd-base
208 (if (string-match
209 "\\`User-.+" cmd-base)
210 (concat
211 "User"
212 (substring cmd-base 5))
213 cmd-base)
214 "")))
215 func (and (not (or (string-equal func "")
216 (string-equal func "calcFunc-")))
217 (intern func)))
218 (and func
219 (fboundp func)
220 (not (fboundp cmd))
221 odef
222 (not
223 (y-or-n-p
224 (if (get func 'calc-user-defn)
225 (concat "Replace previous definition for "
226 (symbol-name func) "? ")
227 "That name conflicts with a built-in Emacs function. Replace this function? "))))))
228 (if (not func)
229 (setq func (intern (concat "calcFunc-User"
230 (or keyname
231 (and cmd (symbol-name cmd))
232 (format "%05d" (% (random) 10000)))))))
233 (if is-lambda
234 (setq alist arglist)
235 (while
236 (progn
237 (setq alist (read-from-minibuffer "Function argument list: "
238 (if arglist
239 (prin1-to-string arglist)
240 "()")
241 minibuffer-local-map
242 t))
243 (and (not (calc-subsetp alist arglist))
244 (not (y-or-n-p
245 "Okay for arguments that don't appear in formula to be ignored? "))))))
246 (setq is-symb (and alist
247 func
248 (y-or-n-p
249 "Leave it symbolic for non-constant arguments? ")))
250 (setq alist (mapcar (function (lambda (x)
251 (or (cdr (assq x '((nil . arg-nil)
252 (t . arg-t))))
253 x))) alist))
254 (if cmd
255 (progn
256 (calc-need-macros)
257 (fset cmd
258 (list 'lambda
259 '()
260 '(interactive)
261 (list 'calc-wrapper
262 (list 'calc-enter-result
263 (length alist)
264 (let ((name (symbol-name (or func cmd))))
265 (and (string-match
266 "\\([^-][^-]?[^-]?[^-]?\\)[^-]*\\'"
267 name)
268 (math-match-substring name 1)))
269 (list 'cons
270 (list 'quote func)
271 (list 'calc-top-list-n
272 (length alist)))))))
273 (put cmd 'calc-user-defn t)))
274 (let ((body (list 'math-normalize (calc-fix-user-formula form))))
275 (fset func
276 (append
277 (list 'lambda alist)
278 (and is-symb
279 (mapcar (function (lambda (v)
280 (list 'math-check-const v t)))
281 alist))
282 (list body))))
283 (put func 'calc-user-defn form)
284 (setq math-integral-cache-state nil)
285 (if key
286 (let* ((kmap (calc-user-key-map))
287 (old (assq key kmap)))
288 (if old
289 (setcdr old cmd)
290 (setcdr kmap (cons (cons key cmd) (cdr kmap)))))))
bf77c646 291 (message "")))
136211a9
EZ
292
293(defun calc-default-formula-arglist (form)
294 (if (consp form)
295 (if (eq (car form) 'var)
296 (if (or (memq (nth 1 form) arglist)
297 (math-const-var form))
298 ()
299 (setq arglist (cons (nth 1 form) arglist)))
bf77c646 300 (calc-default-formula-arglist-step (cdr form)))))
136211a9
EZ
301
302(defun calc-default-formula-arglist-step (l)
303 (and l
304 (progn
305 (calc-default-formula-arglist (car l))
bf77c646 306 (calc-default-formula-arglist-step (cdr l)))))
136211a9
EZ
307
308(defun calc-subsetp (a b)
309 (or (null a)
310 (and (memq (car a) b)
bf77c646 311 (calc-subsetp (cdr a) b))))
136211a9
EZ
312
313(defun calc-fix-user-formula (f)
314 (if (consp f)
315 (let (temp)
316 (cond ((and (eq (car f) 'var)
317 (memq (setq temp (or (cdr (assq (nth 1 f) '((nil . arg-nil)
318 (t . arg-t))))
319 (nth 1 f)))
320 alist))
321 temp)
322 ((or (math-constp f) (eq (car f) 'var))
323 (list 'quote f))
324 ((and (eq (car f) 'calcFunc-eval)
325 (= (length f) 2))
326 (list 'let '((calc-simplify-mode nil))
327 (list 'math-normalize (calc-fix-user-formula (nth 1 f)))))
328 ((and (eq (car f) 'calcFunc-evalsimp)
329 (= (length f) 2))
330 (list 'math-simplify (calc-fix-user-formula (nth 1 f))))
331 ((and (eq (car f) 'calcFunc-evalextsimp)
332 (= (length f) 2))
333 (list 'math-simplify-extended
334 (calc-fix-user-formula (nth 1 f))))
335 (t
336 (cons 'list
337 (cons (list 'quote (car f))
338 (mapcar 'calc-fix-user-formula (cdr f)))))))
bf77c646 339 f))
136211a9
EZ
340
341(defun calc-user-define-composition ()
342 (interactive)
343 (calc-wrapper
344 (if (eq calc-language 'unform)
345 (error "Can't define formats for unformatted mode"))
346 (let* ((comp (calc-top 1))
347 (func (intern (completing-read "Define format for which function: "
348 obarray 'fboundp nil "calcFunc-")))
349 (comps (get func 'math-compose-forms))
350 entry entry2
351 (arglist nil)
352 (alist nil))
353 (if (math-zerop comp)
354 (if (setq entry (assq calc-language comps))
355 (put func 'math-compose-forms (delq entry comps)))
356 (calc-default-formula-arglist comp)
357 (setq arglist (sort arglist 'string-lessp))
358 (while
359 (progn
360 (setq alist (read-from-minibuffer "Composition argument list: "
361 (if arglist
362 (prin1-to-string arglist)
363 "()")
364 minibuffer-local-map
365 t))
366 (and (not (calc-subsetp alist arglist))
367 (y-or-n-p
368 "Okay for arguments that don't appear in formula to be invisible? "))))
369 (or (setq entry (assq calc-language comps))
370 (put func 'math-compose-forms
371 (cons (setq entry (list calc-language)) comps)))
372 (or (setq entry2 (assq (length alist) (cdr entry)))
373 (setcdr entry
374 (cons (setq entry2 (list (length alist))) (cdr entry))))
375 (setcdr entry2 (list 'lambda alist (calc-fix-user-formula comp))))
376 (calc-pop-stack 1)
bf77c646 377 (calc-do-refresh))))
136211a9
EZ
378
379
380(defun calc-user-define-kbd-macro (arg)
381 (interactive "P")
382 (or last-kbd-macro
383 (error "No keyboard macro defined"))
384 (message "Define last kbd macro on user key: z-")
385 (let ((key (read-char)))
386 (if (= (calc-user-function-classify key) 0)
387 (error "Can't redefine \"?\" key"))
388 (let ((cmd (intern (completing-read "Full name for new command: "
389 obarray
390 'commandp
391 nil
392 (concat "calc-User-"
393 (if (or (and (>= key ?a)
394 (<= key ?z))
395 (and (>= key ?A)
396 (<= key ?Z))
397 (and (>= key ?0)
398 (<= key ?9)))
399 (char-to-string key)
400 (format "%03d" key)))))))
401 (and (fboundp cmd)
402 (not (let ((f (symbol-function cmd)))
403 (or (stringp f)
404 (and (consp f)
405 (eq (car-safe (nth 3 f))
406 'calc-execute-kbd-macro)))))
407 (error "Function %s is already defined and not a keyboard macro"
408 cmd))
409 (put cmd 'calc-user-defn t)
410 (fset cmd (if (< (prefix-numeric-value arg) 0)
411 last-kbd-macro
412 (list 'lambda
413 '(arg)
414 '(interactive "P")
415 (list 'calc-execute-kbd-macro
416 (vector (key-description last-kbd-macro)
417 last-kbd-macro)
418 'arg
419 (format "z%c" key)))))
420 (let* ((kmap (calc-user-key-map))
421 (old (assq key kmap)))
422 (if old
423 (setcdr old cmd)
bf77c646 424 (setcdr kmap (cons (cons key cmd) (cdr kmap))))))))
136211a9
EZ
425
426
427(defun calc-edit-user-syntax ()
428 (interactive)
429 (calc-wrapper
430 (let ((lang calc-language))
431 (calc-edit-mode (list 'calc-finish-user-syntax-edit (list 'quote lang))
432 t
433 (format "Editing %s-Mode Syntax Table"
434 (cond ((null lang) "Normal")
435 ((eq lang 'tex) "TeX")
436 (t (capitalize (symbol-name lang))))))
437 (calc-write-parse-table (cdr (assq lang calc-user-parse-tables))
438 lang)))
bf77c646 439 (calc-show-edit-buffer))
136211a9
EZ
440
441(defun calc-finish-user-syntax-edit (lang)
442 (let ((tab (calc-read-parse-table calc-original-buffer lang))
443 (entry (assq lang calc-user-parse-tables)))
444 (if tab
445 (setcdr (or entry
446 (car (setq calc-user-parse-tables
447 (cons (list lang) calc-user-parse-tables))))
448 tab)
449 (if entry
450 (setq calc-user-parse-tables
451 (delq entry calc-user-parse-tables)))))
bf77c646 452 (switch-to-buffer calc-original-buffer))
136211a9
EZ
453
454(defun calc-write-parse-table (tab calc-lang)
455 (let ((p tab))
456 (while p
457 (calc-write-parse-table-part (car (car p)))
458 (insert ":= "
459 (let ((math-format-hash-args t))
460 (math-format-flat-expr (cdr (car p)) 0))
461 "\n")
bf77c646 462 (setq p (cdr p)))))
136211a9
EZ
463
464(defun calc-write-parse-table-part (p)
465 (while p
466 (cond ((stringp (car p))
467 (let ((s (car p)))
468 (if (and (string-match "\\`\\\\dots\\>" s)
469 (not (eq calc-lang 'tex)))
470 (setq s (concat ".." (substring s 5))))
471 (if (or (and (string-match
472 "[a-zA-Z0-9\"{}]\\|\\`:=\\'\\|\\`#\\|\\`%%" s)
473 (string-match "[^a-zA-Z0-9\\]" s))
474 (and (assoc s '((")") ("]") (">")))
475 (not (cdr p))))
476 (insert (prin1-to-string s) " ")
477 (insert s " "))))
478 ((integerp (car p))
479 (insert "#")
480 (or (= (car p) 0)
481 (insert "/" (int-to-string (car p))))
482 (insert " "))
483 ((and (eq (car (car p)) '\?) (equal (car (nth 2 (car p))) "$$"))
484 (insert (car (nth 1 (car p))) " "))
485 (t
486 (insert "{ ")
487 (calc-write-parse-table-part (nth 1 (car p)))
488 (insert "}" (symbol-name (car (car p))))
489 (if (nth 2 (car p))
490 (calc-write-parse-table-part (list (car (nth 2 (car p)))))
491 (insert " "))))
bf77c646 492 (setq p (cdr p))))
136211a9
EZ
493
494(defun calc-read-parse-table (calc-buf calc-lang)
495 (let ((tab nil))
496 (while (progn
497 (skip-chars-forward "\n\t ")
498 (not (eobp)))
499 (if (looking-at "%%")
500 (end-of-line)
501 (let ((pt (point))
502 (p (calc-read-parse-table-part ":=[\n\t ]+" ":=")))
503 (or (stringp (car p))
504 (and (integerp (car p))
505 (stringp (nth 1 p)))
506 (progn
507 (goto-char pt)
508 (error "Malformed syntax rule")))
509 (let ((pos (point)))
510 (end-of-line)
511 (let* ((str (buffer-substring pos (point)))
512 (exp (save-excursion
513 (set-buffer calc-buf)
514 (let ((calc-user-parse-tables nil)
515 (calc-language nil)
516 (math-expr-opers math-standard-opers)
517 (calc-hashes-used 0))
518 (math-read-expr
519 (if (string-match ",[ \t]*\\'" str)
520 (substring str 0 (match-beginning 0))
521 str))))))
522 (if (eq (car-safe exp) 'error)
523 (progn
524 (goto-char (+ pos (nth 1 exp)))
525 (error (nth 2 exp))))
526 (setq tab (nconc tab (list (cons p exp)))))))))
bf77c646 527 tab))
136211a9
EZ
528
529(defun calc-fix-token-name (name &optional unquoted)
530 (cond ((string-match "\\`\\.\\." name)
531 (concat "\\dots" (substring name 2)))
532 ((and (equal name "{") (memq calc-lang '(tex eqn)))
533 "(")
534 ((and (equal name "}") (memq calc-lang '(tex eqn)))
535 ")")
536 ((and (equal name "&") (eq calc-lang 'tex))
537 ",")
538 ((equal name "#")
539 (search-backward "#")
540 (error "Token '#' is reserved"))
541 ((and unquoted (string-match "#" name))
542 (error "Tokens containing '#' must be quoted"))
543 ((not (string-match "[^ ]" name))
544 (search-backward "\"" nil t)
545 (error "Blank tokens are not allowed"))
bf77c646 546 (t name)))
136211a9
EZ
547
548(defun calc-read-parse-table-part (term eterm)
549 (let ((part nil)
550 (quoted nil))
551 (while (progn
552 (skip-chars-forward "\n\t ")
553 (if (eobp) (error "Expected '%s'" eterm))
554 (not (looking-at term)))
555 (cond ((looking-at "%%")
556 (end-of-line))
557 ((looking-at "{[\n\t ]")
558 (forward-char 2)
559 (let ((p (calc-read-parse-table-part "}" "}")))
560 (or (looking-at "[+*?]")
561 (error "Expected '+', '*', or '?'"))
562 (let ((sym (intern (buffer-substring (point) (1+ (point))))))
563 (forward-char 1)
564 (looking-at "[^\n\t ]*")
565 (let ((sep (buffer-substring (point) (match-end 0))))
566 (goto-char (match-end 0))
567 (and (eq sym '\?) (> (length sep) 0)
568 (not (equal sep "$")) (not (equal sep "."))
569 (error "Separator not allowed with { ... }?"))
570 (if (string-match "\\`\"" sep)
571 (setq sep (read-from-string sep)))
572 (setq sep (calc-fix-token-name sep))
573 (setq part (nconc part
574 (list (list sym p
575 (and (> (length sep) 0)
576 (cons sep p))))))))))
577 ((looking-at "}")
578 (error "Too many }'s"))
579 ((looking-at "\"")
580 (setq quoted (calc-fix-token-name (read (current-buffer)))
581 part (nconc part (list quoted))))
582 ((looking-at "#\\(\\(/[0-9]+\\)?\\)[\n\t ]")
583 (setq part (nconc part (list (if (= (match-beginning 1)
584 (match-end 1))
585 0
586 (string-to-int
587 (buffer-substring
588 (1+ (match-beginning 1))
589 (match-end 1)))))))
590 (goto-char (match-end 0)))
591 ((looking-at ":=[\n\t ]")
592 (error "Misplaced ':='"))
593 (t
594 (looking-at "[^\n\t ]*")
595 (let ((end (match-end 0)))
596 (setq part (nconc part (list (calc-fix-token-name
597 (buffer-substring
598 (point) end) t))))
599 (goto-char end)))))
600 (goto-char (match-end 0))
601 (let ((len (length part)))
602 (while (and (> len 1)
603 (let ((last (nthcdr (setq len (1- len)) part)))
604 (and (assoc (car last) '((")") ("]") (">")))
605 (not (eq (car last) quoted))
606 (setcar last
607 (list '\? (list (car last)) '("$$"))))))))
bf77c646 608 part))
136211a9
EZ
609
610
611(defun calc-user-define-invocation ()
612 (interactive)
613 (or last-kbd-macro
614 (error "No keyboard macro defined"))
615 (setq calc-invocation-macro last-kbd-macro)
bf77c646 616 (message "Use `M-# Z' to invoke this macro"))
136211a9
EZ
617
618
619(defun calc-user-define-edit (prefix)
620 (interactive "P") ; but no calc-wrapper!
621 (message "Edit definition of command: z-")
622 (let* ((key (read-char))
623 (def (or (assq key (calc-user-key-map))
624 (assq (upcase key) (calc-user-key-map))
625 (assq (downcase key) (calc-user-key-map))
626 (error "No command defined for that key")))
627 (cmd (cdr def)))
628 (if (symbolp cmd)
629 (setq cmd (symbol-function cmd)))
630 (cond ((or (stringp cmd)
631 (and (consp cmd)
632 (eq (car-safe (nth 3 cmd)) 'calc-execute-kbd-macro)))
633 (if (and (>= (prefix-numeric-value prefix) 0)
634 (fboundp 'edit-kbd-macro)
635 (symbolp (cdr def))
636 (eq major-mode 'calc-mode))
637 (progn
8f66f479 638 (if (and (< (window-width) (frame-width))
136211a9
EZ
639 calc-display-trail)
640 (let ((win (get-buffer-window (calc-trail-buffer))))
641 (if win
642 (delete-window win))))
643 (edit-kbd-macro (cdr def) prefix nil
644 (function
645 (lambda (x)
646 (and calc-display-trail
647 (calc-wrapper
648 (calc-trail-display 1 t)))))
649 (function
650 (lambda (cmd)
651 (if (stringp (symbol-function cmd))
652 (symbol-function cmd)
653 (let ((mac (nth 1 (nth 3 (symbol-function
654 cmd)))))
655 (if (vectorp mac)
656 (aref mac 1)
657 mac)))))
658 (function
659 (lambda (new cmd)
660 (if (stringp (symbol-function cmd))
661 (fset cmd new)
662 (let ((mac (cdr (nth 3 (symbol-function
663 cmd)))))
664 (if (vectorp (car mac))
665 (progn
666 (aset (car mac) 0
667 (key-description new))
668 (aset (car mac) 1 new))
669 (setcar mac new))))))))
670 (let ((keys (progn (and (fboundp 'edit-kbd-macro)
671 (edit-kbd-macro nil))
672 (fboundp 'MacEdit-parse-keys))))
673 (calc-wrapper
674 (calc-edit-mode (list 'calc-finish-macro-edit
675 (list 'quote def)
676 keys)
677 t)
678 (if keys
679 (let (top
680 (fill-column 70)
681 (fill-prefix nil))
682 (insert "Notations: RET, SPC, TAB, DEL, LFD, NUL"
683 ", C-xxx, M-xxx.\n\n")
684 (setq top (point))
685 (insert (if (stringp cmd)
686 (key-description cmd)
687 (if (vectorp (nth 1 (nth 3 cmd)))
688 (aref (nth 1 (nth 3 cmd)) 0)
689 (key-description (nth 1 (nth 3 cmd)))))
690 "\n")
691 (if (>= (prog2 (forward-char -1)
692 (current-column)
693 (forward-char 1))
8f66f479 694 (frame-width))
136211a9
EZ
695 (fill-region top (point))))
696 (insert "Press C-q to quote control characters like RET"
697 " and TAB.\n"
698 (if (stringp cmd)
699 cmd
700 (if (vectorp (nth 1 (nth 3 cmd)))
701 (aref (nth 1 (nth 3 cmd)) 1)
702 (nth 1 (nth 3 cmd)))))))
703 (calc-show-edit-buffer)
704 (forward-line (if keys 2 1)))))
705 (t (let* ((func (calc-stack-command-p cmd))
706 (defn (and func
707 (symbolp func)
708 (get func 'calc-user-defn))))
709 (if (and defn (calc-valid-formula-func func))
710 (progn
711 (calc-wrapper
712 (calc-edit-mode (list 'calc-finish-formula-edit
713 (list 'quote func)))
714 (insert (math-showing-full-precision
8f66f479 715 (math-format-nice-expr defn (frame-width)))
136211a9
EZ
716 "\n"))
717 (calc-show-edit-buffer))
bf77c646 718 (error "That command's definition cannot be edited")))))))
136211a9
EZ
719
720(defun calc-finish-macro-edit (def keys)
721 (forward-line 1)
722 (if (and keys (looking-at "\n")) (forward-line 1))
723 (let* ((true-str (buffer-substring (point) (point-max)))
724 (str true-str))
725 (if keys (setq str (MacEdit-parse-keys str)))
726 (if (symbolp (cdr def))
727 (if (stringp (symbol-function (cdr def)))
728 (fset (cdr def) str)
729 (let ((mac (cdr (nth 3 (symbol-function (cdr def))))))
730 (if (vectorp (car mac))
731 (progn
732 (aset (car mac) 0 (if keys true-str (key-description str)))
733 (aset (car mac) 1 str))
734 (setcar mac str))))
bf77c646 735 (setcdr def str))))
136211a9
EZ
736
737;;; The following are hooks into the MacEdit package from macedit.el.
738(put 'calc-execute-extended-command 'MacEdit-print
739 (function (lambda ()
bf77c646 740 (setq macro-str (concat "\excalc-" macro-str)))))
136211a9
EZ
741
742(put 'calcDigit-start 'MacEdit-print
743 (function (lambda ()
744 (if calc-algebraic-mode
745 (calc-macro-edit-algebraic)
746 (MacEdit-unread-chars key-last)
747 (let ((str "")
748 (min-bsp 0)
749 ch last)
750 (while (and (setq ch (MacEdit-read-char))
751 (or (and (>= ch ?0) (<= ch ?9))
752 (memq ch '(?\. ?e ?\_ ?n ?\: ?\# ?M
753 ?o ?h ?\@ ?\"))
754 (and (memq ch '(?\' ?m ?s))
755 (string-match "[@oh]" str))
756 (and (or (and (>= ch ?a) (<= ch ?z))
757 (and (>= ch ?A) (<= ch ?Z)))
758 (string-match
759 "^[-+]?\\(1[1-9]\\|[2-9][0-9]\\)#"
760 str))
761 (and (memq ch '(?\177 ?\C-h))
762 (> (length str) 0))
763 (and (memq ch '(?+ ?-))
764 (> (length str) 0)
765 (eq (aref str (1- (length str)))
766 ?e))))
767 (if (or (and (>= ch ?0) (<= ch ?9))
768 (and (or (not (memq ch '(?\177 ?\C-h)))
769 (<= (length str) min-bsp))
770 (setq min-bsp (1+ (length str)))))
771 (setq str (concat str (char-to-string ch)))
772 (setq str (substring str 0 -1))))
773 (if (memq ch '(32 10 13))
774 (setq str (concat str (char-to-string ch)))
775 (MacEdit-unread-chars ch))
776 (insert "type \"")
777 (MacEdit-insert-string str)
bf77c646 778 (insert "\"\n"))))))
136211a9
EZ
779
780(defun calc-macro-edit-algebraic ()
781 (MacEdit-unread-chars key-last)
782 (let ((str "")
783 (min-bsp 0))
784 (while (progn
785 (MacEdit-lookup-key calc-alg-ent-map)
786 (or (and (memq key-symbol '(self-insert-command
787 calcAlg-previous))
788 (< (length str) 60))
789 (memq key-symbol
790 '(backward-delete-char
791 delete-backward-char
792 backward-delete-char-untabify))
793 (eq key-last 9)))
794 (setq macro-str (substring macro-str (length key-str)))
795 (if (or (eq key-symbol 'self-insert-command)
796 (and (or (not (memq key-symbol '(backward-delete-char
797 delete-backward-char
798 backward-delete-char-untabify)))
799 (<= (length str) min-bsp))
800 (setq min-bsp (+ (length str) (length key-str)))))
801 (setq str (concat str key-str))
802 (setq str (substring str 0 -1))))
803 (if (memq key-last '(10 13))
804 (setq str (concat str key-str)
805 macro-str (substring macro-str (length key-str))))
806 (if (> (length str) 0)
807 (progn
808 (insert "type \"")
809 (MacEdit-insert-string str)
bf77c646 810 (insert "\"\n")))))
136211a9
EZ
811(put 'calc-algebraic-entry 'MacEdit-print 'calc-macro-edit-algebraic)
812(put 'calc-auto-algebraic-entry 'MacEdit-print 'calc-macro-edit-algebraic)
813
814(defun calc-macro-edit-variable (&optional no-cmd)
815 (let ((str "") ch)
816 (or no-cmd (insert (symbol-name key-symbol) "\n"))
817 (if (memq (MacEdit-peek-char) '(?\+ ?\- ?\* ?\/ ?\^ ?\|))
818 (setq str (char-to-string (MacEdit-read-char))))
819 (if (and (setq ch (MacEdit-peek-char))
820 (>= ch ?0) (<= ch ?9))
821 (insert "type \"" str
822 (char-to-string (MacEdit-read-char)) "\"\n")
823 (if (> (length str) 0)
824 (insert "type \"" str "\"\n"))
bf77c646 825 (MacEdit-read-argument))))
136211a9
EZ
826(put 'calc-store 'MacEdit-print 'calc-macro-edit-variable)
827(put 'calc-store-into 'MacEdit-print 'calc-macro-edit-variable)
828(put 'calc-store-neg 'MacEdit-print 'calc-macro-edit-variable)
829(put 'calc-store-plus 'MacEdit-print 'calc-macro-edit-variable)
830(put 'calc-store-minus 'MacEdit-print 'calc-macro-edit-variable)
831(put 'calc-store-times 'MacEdit-print 'calc-macro-edit-variable)
832(put 'calc-store-div 'MacEdit-print 'calc-macro-edit-variable)
833(put 'calc-store-power 'MacEdit-print 'calc-macro-edit-variable)
834(put 'calc-store-concat 'MacEdit-print 'calc-macro-edit-variable)
835(put 'calc-store-inv 'MacEdit-print 'calc-macro-edit-variable)
836(put 'calc-store-decr 'MacEdit-print 'calc-macro-edit-variable)
837(put 'calc-store-incr 'MacEdit-print 'calc-macro-edit-variable)
838(put 'calc-store-exchange 'MacEdit-print 'calc-macro-edit-variable)
839(put 'calc-unstore 'MacEdit-print 'calc-macro-edit-variable)
840(put 'calc-recall 'MacEdit-print 'calc-macro-edit-variable)
841(put 'calc-let 'MacEdit-print 'calc-macro-edit-variable)
842(put 'calc-permanent-variable 'MacEdit-print 'calc-macro-edit-variable)
843
844(defun calc-macro-edit-variable-2 ()
845 (calc-macro-edit-variable)
bf77c646 846 (calc-macro-edit-variable t))
136211a9
EZ
847(put 'calc-copy-variable 'MacEdit-print 'calc-macro-edit-variable-2)
848(put 'calc-declare-variable 'MacEdit-print 'calc-macro-edit-variable-2)
849
850(defun calc-macro-edit-quick-digit ()
bf77c646 851 (insert "type \"" key-str "\" # " (symbol-name key-symbol) "\n"))
136211a9
EZ
852(put 'calc-store-quick 'MacEdit-print 'calc-macro-edit-quick-digit)
853(put 'calc-store-into-quick 'MacEdit-print 'calc-macro-edit-quick-digit)
854(put 'calc-recall-quick 'MacEdit-print 'calc-macro-edit-quick-digit)
855(put 'calc-select-part 'MacEdit-print 'calc-macro-edit-quick-digit)
856(put 'calc-clean-num 'MacEdit-print 'calc-macro-edit-quick-digit)
857
858
859(defun calc-finish-formula-edit (func)
860 (let ((buf (current-buffer))
861 (str (buffer-substring (point) (point-max)))
862 (start (point))
863 (body (calc-valid-formula-func func)))
864 (set-buffer calc-original-buffer)
865 (let ((val (math-read-expr str)))
866 (if (eq (car-safe val) 'error)
867 (progn
868 (set-buffer buf)
869 (goto-char (+ start (nth 1 val)))
870 (error (nth 2 val))))
871 (setcar (cdr body)
872 (let ((alist (nth 1 (symbol-function func))))
873 (calc-fix-user-formula val)))
bf77c646 874 (put func 'calc-user-defn val))))
136211a9
EZ
875
876(defun calc-valid-formula-func (func)
877 (let ((def (symbol-function func)))
878 (and (consp def)
879 (eq (car def) 'lambda)
880 (progn
881 (setq def (cdr (cdr def)))
882 (while (and def
883 (not (eq (car (car def)) 'math-normalize)))
884 (setq def (cdr def)))
bf77c646 885 (car def)))))
136211a9
EZ
886
887
888(defun calc-get-user-defn ()
889 (interactive)
890 (calc-wrapper
891 (message "Get definition of command: z-")
892 (let* ((key (read-char))
893 (def (or (assq key (calc-user-key-map))
894 (assq (upcase key) (calc-user-key-map))
895 (assq (downcase key) (calc-user-key-map))
896 (error "No command defined for that key")))
897 (cmd (cdr def)))
898 (if (symbolp cmd)
899 (setq cmd (symbol-function cmd)))
900 (cond ((stringp cmd)
901 (message "Keyboard macro: %s" cmd))
902 (t (let* ((func (calc-stack-command-p cmd))
903 (defn (and func
904 (symbolp func)
905 (get func 'calc-user-defn))))
906 (if defn
907 (progn
908 (and (calc-valid-formula-func func)
909 (setq defn (append '(calcFunc-lambda)
910 (mapcar 'math-build-var-name
911 (nth 1 (symbol-function
912 func)))
913 (list defn))))
914 (calc-enter-result 0 "gdef" defn))
bf77c646 915 (error "That command is not defined by a formula"))))))))
136211a9
EZ
916
917
918(defun calc-user-define-permanent ()
919 (interactive)
920 (calc-wrapper
921 (message "Record in %s the command: z-" calc-settings-file)
922 (let* ((key (read-char))
923 (def (or (assq key (calc-user-key-map))
924 (assq (upcase key) (calc-user-key-map))
925 (assq (downcase key) (calc-user-key-map))
926 (and (eq key ?\')
927 (cons nil
928 (intern (completing-read
929 (format "Record in %s the function: "
930 calc-settings-file)
931 obarray 'fboundp nil "calcFunc-"))))
932 (error "No command defined for that key"))))
933 (set-buffer (find-file-noselect (substitute-in-file-name
934 calc-settings-file)))
935 (goto-char (point-max))
936 (let* ((cmd (cdr def))
937 (fcmd (and cmd (symbolp cmd) (symbol-function cmd)))
938 (func nil)
939 (pt (point))
940 (fill-column 70)
941 (fill-prefix nil)
942 str q-ok)
943 (insert "\n;;; Definition stored by Calc on " (current-time-string)
944 "\n(put 'calc-define '"
945 (if (symbolp cmd) (symbol-name cmd) (format "key%d" key))
946 " '(progn\n")
947 (if (and fcmd
948 (eq (car-safe fcmd) 'lambda)
949 (get cmd 'calc-user-defn))
950 (let ((pt (point)))
951 (and (eq (car-safe (nth 3 fcmd)) 'calc-execute-kbd-macro)
952 (vectorp (nth 1 (nth 3 fcmd)))
953 (progn (and (fboundp 'edit-kbd-macro)
954 (edit-kbd-macro nil))
955 (fboundp 'MacEdit-parse-keys))
956 (setq q-ok t)
957 (aset (nth 1 (nth 3 fcmd)) 1 nil))
958 (insert (setq str (prin1-to-string
959 (cons 'defun (cons cmd (cdr fcmd)))))
960 "\n")
961 (or (and (string-match "\"" str) (not q-ok))
962 (fill-region pt (point)))
963 (indent-rigidly pt (point) 2)
964 (delete-region pt (1+ pt))
965 (insert " (put '" (symbol-name cmd)
966 " 'calc-user-defn '"
967 (prin1-to-string (get cmd 'calc-user-defn))
968 ")\n")
969 (setq func (calc-stack-command-p cmd))
970 (let ((ffunc (and func (symbolp func) (symbol-function func)))
971 (pt (point)))
972 (and ffunc
973 (eq (car-safe ffunc) 'lambda)
974 (get func 'calc-user-defn)
975 (progn
976 (insert (setq str (prin1-to-string
977 (cons 'defun (cons func
978 (cdr ffunc)))))
979 "\n")
980 (or (and (string-match "\"" str) (not q-ok))
981 (fill-region pt (point)))
982 (indent-rigidly pt (point) 2)
983 (delete-region pt (1+ pt))
984 (setq pt (point))
985 (insert "(put '" (symbol-name func)
986 " 'calc-user-defn '"
987 (prin1-to-string (get func 'calc-user-defn))
988 ")\n")
989 (fill-region pt (point))
990 (indent-rigidly pt (point) 2)
991 (delete-region pt (1+ pt))))))
992 (and (stringp fcmd)
993 (insert " (fset '" (prin1-to-string cmd)
994 " " (prin1-to-string fcmd) ")\n")))
995 (or func (setq func (and cmd (symbolp cmd) (fboundp cmd) cmd)))
996 (if (get func 'math-compose-forms)
997 (let ((pt (point)))
998 (insert "(put '" (symbol-name cmd)
999 " 'math-compose-forms '"
1000 (prin1-to-string (get func 'math-compose-forms))
1001 ")\n")
1002 (fill-region pt (point))
1003 (indent-rigidly pt (point) 2)
1004 (delete-region pt (1+ pt))))
1005 (if (car def)
1006 (insert " (define-key calc-mode-map "
1007 (prin1-to-string (concat "z" (char-to-string key)))
1008 " '"
1009 (prin1-to-string cmd)
1010 ")\n")))
1011 (insert "))\n")
bf77c646 1012 (save-buffer))))
136211a9
EZ
1013
1014(defun calc-stack-command-p (cmd)
1015 (if (and cmd (symbolp cmd))
1016 (and (fboundp cmd)
1017 (calc-stack-command-p (symbol-function cmd)))
1018 (and (consp cmd)
1019 (eq (car cmd) 'lambda)
1020 (setq cmd (or (assq 'calc-wrapper cmd)
1021 (assq 'calc-slow-wrapper cmd)))
1022 (setq cmd (assq 'calc-enter-result cmd))
1023 (memq (car (nth 3 cmd)) '(cons list))
1024 (eq (car (nth 1 (nth 3 cmd))) 'quote)
bf77c646 1025 (nth 1 (nth 1 (nth 3 cmd))))))
136211a9
EZ
1026
1027
1028(defun calc-call-last-kbd-macro (arg)
1029 (interactive "P")
1030 (and defining-kbd-macro
1031 (error "Can't execute anonymous macro while defining one"))
1032 (or last-kbd-macro
1033 (error "No kbd macro has been defined"))
bf77c646 1034 (calc-execute-kbd-macro last-kbd-macro arg))
136211a9
EZ
1035
1036(defun calc-execute-kbd-macro (mac arg &rest prefix)
1037 (if (and (vectorp mac) (> (length mac) 0) (stringp (aref mac 0)))
1038 (setq mac (or (aref mac 1)
1039 (aset mac 1 (progn (and (fboundp 'edit-kbd-macro)
1040 (edit-kbd-macro nil))
1041 (MacEdit-parse-keys (aref mac 0)))))))
1042 (if (< (prefix-numeric-value arg) 0)
1043 (execute-kbd-macro mac (- (prefix-numeric-value arg)))
1044 (if calc-executing-macro
1045 (execute-kbd-macro mac arg)
1046 (calc-slow-wrapper
1047 (let ((old-stack-whole (copy-sequence calc-stack))
1048 (old-stack-top calc-stack-top)
1049 (old-buffer-size (buffer-size))
1050 (old-refresh-count calc-refresh-count))
1051 (unwind-protect
1052 (let ((calc-executing-macro mac))
1053 (execute-kbd-macro mac arg))
1054 (calc-select-buffer)
1055 (let ((new-stack (reverse calc-stack))
1056 (old-stack (reverse old-stack-whole)))
1057 (while (and new-stack old-stack
1058 (equal (car new-stack) (car old-stack)))
1059 (setq new-stack (cdr new-stack)
1060 old-stack (cdr old-stack)))
1061 (or (equal prefix '(nil))
1062 (calc-record-list (if (> (length new-stack) 1)
1063 (mapcar 'car new-stack)
1064 '(""))
1065 (or (car prefix) "kmac")))
1066 (calc-record-undo (list 'set 'saved-stack-top old-stack-top))
1067 (and old-stack
1068 (calc-record-undo (list 'pop 1 (mapcar 'car old-stack))))
1069 (let ((calc-stack old-stack-whole)
1070 (calc-stack-top 0))
1071 (calc-cursor-stack-index (length old-stack)))
1072 (if (and (= old-buffer-size (buffer-size))
1073 (= old-refresh-count calc-refresh-count))
1074 (let ((buffer-read-only nil))
1075 (delete-region (point) (point-max))
1076 (while new-stack
1077 (calc-record-undo (list 'push 1))
1078 (insert (math-format-stack-value (car new-stack)) "\n")
1079 (setq new-stack (cdr new-stack)))
1080 (calc-renumber-stack))
1081 (while new-stack
1082 (calc-record-undo (list 'push 1))
1083 (setq new-stack (cdr new-stack)))
1084 (calc-refresh))
bf77c646 1085 (calc-record-undo (list 'set 'saved-stack-top 0)))))))))
136211a9
EZ
1086
1087(defun calc-push-list-in-macro (vals m sels)
1088 (let ((entry (list (car vals) 1 (car sels)))
1089 (mm (+ (or m 1) calc-stack-top)))
1090 (if (> mm 1)
1091 (setcdr (nthcdr (- mm 2) calc-stack)
1092 (cons entry (nthcdr (1- mm) calc-stack)))
bf77c646 1093 (setq calc-stack (cons entry calc-stack)))))
136211a9
EZ
1094
1095(defun calc-pop-stack-in-macro (n mm)
1096 (if (> mm 1)
1097 (setcdr (nthcdr (- mm 2) calc-stack)
1098 (nthcdr (+ n mm -1) calc-stack))
bf77c646 1099 (setq calc-stack (nthcdr n calc-stack))))
136211a9
EZ
1100
1101
1102(defun calc-kbd-if ()
1103 (interactive)
1104 (calc-wrapper
1105 (let ((cond (calc-top-n 1)))
1106 (calc-pop-stack 1)
1107 (if (math-is-true cond)
1108 (if defining-kbd-macro
1109 (message "If true..."))
1110 (if defining-kbd-macro
1111 (message "Condition is false; skipping to Z: or Z] ..."))
bf77c646 1112 (calc-kbd-skip-to-else-if t)))))
136211a9
EZ
1113
1114(defun calc-kbd-else-if ()
1115 (interactive)
bf77c646 1116 (calc-kbd-if))
136211a9
EZ
1117
1118(defun calc-kbd-skip-to-else-if (else-okay)
1119 (let ((count 0)
1120 ch)
1121 (while (>= count 0)
1122 (setq ch (read-char))
1123 (if (= ch -1)
1124 (error "Unterminated Z[ in keyboard macro"))
1125 (if (= ch ?Z)
1126 (progn
1127 (setq ch (read-char))
1128 (cond ((= ch ?\[)
1129 (setq count (1+ count)))
1130 ((= ch ?\])
1131 (setq count (1- count)))
1132 ((= ch ?\:)
1133 (and (= count 0)
1134 else-okay
1135 (setq count -1)))
1136 ((eq ch 7)
1137 (keyboard-quit))))))
1138 (and defining-kbd-macro
1139 (if (= ch ?\:)
1140 (message "Else...")
bf77c646 1141 (message "End-if...")))))
136211a9
EZ
1142
1143(defun calc-kbd-end-if ()
1144 (interactive)
1145 (if defining-kbd-macro
bf77c646 1146 (message "End-if...")))
136211a9
EZ
1147
1148(defun calc-kbd-else ()
1149 (interactive)
1150 (if defining-kbd-macro
1151 (message "Else; skipping to Z] ..."))
bf77c646 1152 (calc-kbd-skip-to-else-if nil))
136211a9
EZ
1153
1154
1155(defun calc-kbd-repeat ()
1156 (interactive)
1157 (let (count)
1158 (calc-wrapper
1159 (setq count (math-trunc (calc-top-n 1)))
1160 (or (Math-integerp count)
1161 (error "Count must be an integer"))
1162 (if (Math-integer-negp count)
1163 (setq count 0))
1164 (or (integerp count)
1165 (setq count 1000000))
1166 (calc-pop-stack 1))
bf77c646 1167 (calc-kbd-loop count)))
136211a9
EZ
1168
1169(defun calc-kbd-for (dir)
1170 (interactive "P")
1171 (let (init final)
1172 (calc-wrapper
1173 (setq init (calc-top-n 2)
1174 final (calc-top-n 1))
1175 (or (and (math-anglep init) (math-anglep final))
1176 (error "Initial and final values must be real numbers"))
1177 (calc-pop-stack 2))
bf77c646 1178 (calc-kbd-loop nil init final (and dir (prefix-numeric-value dir)))))
136211a9
EZ
1179
1180(defun calc-kbd-loop (rpt-count &optional initial final dir)
1181 (interactive "P")
1182 (setq rpt-count (if rpt-count (prefix-numeric-value rpt-count) 1000000))
1183 (let* ((count 0)
1184 (parts nil)
1185 (body "")
1186 (open last-command-char)
1187 (counter initial)
1188 ch)
8f66f479 1189 (or executing-kbd-macro
136211a9
EZ
1190 (message "Reading loop body..."))
1191 (while (>= count 0)
1192 (setq ch (read-char))
1193 (if (= ch -1)
1194 (error "Unterminated Z%c in keyboard macro" open))
1195 (if (= ch ?Z)
1196 (progn
1197 (setq ch (read-char)
1198 body (concat body "Z" (char-to-string ch)))
1199 (cond ((memq ch '(?\< ?\( ?\{))
1200 (setq count (1+ count)))
1201 ((memq ch '(?\> ?\) ?\}))
1202 (setq count (1- count)))
1203 ((and (= ch ?/)
1204 (= count 0))
1205 (setq parts (nconc parts (list (concat (substring body 0 -2)
1206 "Z]")))
1207 body ""))
1208 ((eq ch 7)
1209 (keyboard-quit))))
1210 (setq body (concat body (char-to-string ch)))))
1211 (if (/= ch (cdr (assq open '( (?\< . ?\>) (?\( . ?\)) (?\{ . ?\}) ))))
1212 (error "Mismatched Z%c and Z%c in keyboard macro" open ch))
8f66f479 1213 (or executing-kbd-macro
136211a9
EZ
1214 (message "Looping..."))
1215 (setq body (concat (substring body 0 -2) "Z]"))
8f66f479 1216 (and (not executing-kbd-macro)
136211a9
EZ
1217 (= rpt-count 1000000)
1218 (null parts)
1219 (null counter)
1220 (progn
1221 (message "Warning: Infinite loop! Not executing.")
1222 (setq rpt-count 0)))
1223 (or (not initial) dir
1224 (setq dir (math-compare final initial)))
1225 (calc-wrapper
1226 (while (> rpt-count 0)
1227 (let ((part parts))
1228 (if counter
1229 (if (cond ((eq dir 0) (Math-equal final counter))
1230 ((eq dir 1) (Math-lessp final counter))
1231 ((eq dir -1) (Math-lessp counter final)))
1232 (setq rpt-count 0)
1233 (calc-push counter)))
1234 (while (and part (> rpt-count 0))
1235 (execute-kbd-macro (car part))
1236 (if (math-is-true (calc-top-n 1))
1237 (setq rpt-count 0)
1238 (setq part (cdr part)))
1239 (calc-pop-stack 1))
1240 (if (> rpt-count 0)
1241 (progn
1242 (execute-kbd-macro body)
1243 (if counter
1244 (let ((step (calc-top-n 1)))
1245 (calc-pop-stack 1)
1246 (setq counter (calcFunc-add counter step)))
1247 (setq rpt-count (1- rpt-count))))))))
8f66f479 1248 (or executing-kbd-macro
bf77c646 1249 (message "Looping...done"))))
136211a9
EZ
1250
1251(defun calc-kbd-end-repeat ()
1252 (interactive)
bf77c646 1253 (error "Unbalanced Z> in keyboard macro"))
136211a9
EZ
1254
1255(defun calc-kbd-end-for ()
1256 (interactive)
bf77c646 1257 (error "Unbalanced Z) in keyboard macro"))
136211a9
EZ
1258
1259(defun calc-kbd-end-loop ()
1260 (interactive)
bf77c646 1261 (error "Unbalanced Z} in keyboard macro"))
136211a9
EZ
1262
1263(defun calc-kbd-break ()
1264 (interactive)
1265 (calc-wrapper
1266 (let ((cond (calc-top-n 1)))
1267 (calc-pop-stack 1)
1268 (if (math-is-true cond)
bf77c646 1269 (error "Keyboard macro aborted.")))))
136211a9
EZ
1270
1271
1272(defun calc-kbd-push (arg)
1273 (interactive "P")
1274 (calc-wrapper
1275 (let* ((defs (and arg (> (prefix-numeric-value arg) 0)))
1276 (var-q0 (and (boundp 'var-q0) var-q0))
1277 (var-q1 (and (boundp 'var-q1) var-q1))
1278 (var-q2 (and (boundp 'var-q2) var-q2))
1279 (var-q3 (and (boundp 'var-q3) var-q3))
1280 (var-q4 (and (boundp 'var-q4) var-q4))
1281 (var-q5 (and (boundp 'var-q5) var-q5))
1282 (var-q6 (and (boundp 'var-q6) var-q6))
1283 (var-q7 (and (boundp 'var-q7) var-q7))
1284 (var-q8 (and (boundp 'var-q8) var-q8))
1285 (var-q9 (and (boundp 'var-q9) var-q9))
1286 (calc-internal-prec (if defs 12 calc-internal-prec))
1287 (calc-word-size (if defs 32 calc-word-size))
1288 (calc-angle-mode (if defs 'deg calc-angle-mode))
1289 (calc-simplify-mode (if defs nil calc-simplify-mode))
1290 (calc-algebraic-mode (if arg nil calc-algebraic-mode))
1291 (calc-incomplete-algebraic-mode (if arg nil
1292 calc-incomplete-algebraic-mode))
1293 (calc-symbolic-mode (if defs nil calc-symbolic-mode))
1294 (calc-matrix-mode (if defs nil calc-matrix-mode))
1295 (calc-prefer-frac (if defs nil calc-prefer-frac))
1296 (calc-complex-mode (if defs nil calc-complex-mode))
1297 (calc-infinite-mode (if defs nil calc-infinite-mode))
1298 (count 0)
1299 (body "")
1300 ch)
8f66f479 1301 (if (or executing-kbd-macro defining-kbd-macro)
136211a9
EZ
1302 (progn
1303 (if defining-kbd-macro
1304 (message "Reading body..."))
1305 (while (>= count 0)
1306 (setq ch (read-char))
1307 (if (= ch -1)
1308 (error "Unterminated Z` in keyboard macro"))
1309 (if (= ch ?Z)
1310 (progn
1311 (setq ch (read-char)
1312 body (concat body "Z" (char-to-string ch)))
1313 (cond ((eq ch ?\`)
1314 (setq count (1+ count)))
1315 ((eq ch ?\')
1316 (setq count (1- count)))
1317 ((eq ch 7)
1318 (keyboard-quit))))
1319 (setq body (concat body (char-to-string ch)))))
1320 (if defining-kbd-macro
1321 (message "Reading body...done"))
1322 (let ((calc-kbd-push-level 0))
1323 (execute-kbd-macro (substring body 0 -2))))
1324 (let ((calc-kbd-push-level (1+ calc-kbd-push-level)))
1325 (message "Saving modes; type Z' to restore")
bf77c646 1326 (recursive-edit))))))
136211a9
EZ
1327(setq calc-kbd-push-level 0)
1328
1329(defun calc-kbd-pop ()
1330 (interactive)
1331 (if (> calc-kbd-push-level 0)
1332 (progn
1333 (message "Mode settings restored")
1334 (exit-recursive-edit))
bf77c646 1335 (error "Unbalanced Z' in keyboard macro")))
136211a9
EZ
1336
1337
1338(defun calc-kbd-report (msg)
1339 (interactive "sMessage: ")
1340 (calc-wrapper
8f66f479 1341 (let ((executing-kbd-macro nil)
136211a9 1342 (defining-kbd-macro nil))
bf77c646 1343 (math-working msg (calc-top-n 1)))))
136211a9
EZ
1344
1345(defun calc-kbd-query (msg)
1346 (interactive "sPrompt: ")
1347 (calc-wrapper
8f66f479 1348 (let ((executing-kbd-macro nil)
136211a9 1349 (defining-kbd-macro nil))
bf77c646 1350 (calc-alg-entry nil (and (not (equal msg "")) msg)))))
136211a9
EZ
1351
1352
1353
1354
1355
1356
1357
1358;;;; Logical operations.
1359
1360(defun calcFunc-eq (a b &rest more)
1361 (if more
1362 (let* ((args (cons a (cons b (copy-sequence more))))
1363 (res 1)
1364 (p args)
1365 p2)
1366 (while (and (cdr p) (not (eq res 0)))
1367 (setq p2 p)
1368 (while (and (setq p2 (cdr p2)) (not (eq res 0)))
1369 (setq res (math-two-eq (car p) (car p2)))
1370 (if (eq res 1)
1371 (setcdr p (delq (car p2) (cdr p)))))
1372 (setq p (cdr p)))
1373 (if (eq res 0)
1374 0
1375 (if (cdr args)
1376 (cons 'calcFunc-eq args)
1377 1)))
1378 (or (math-two-eq a b)
1379 (if (and (or (math-looks-negp a) (math-zerop a))
1380 (or (math-looks-negp b) (math-zerop b)))
1381 (list 'calcFunc-eq (math-neg a) (math-neg b))
bf77c646 1382 (list 'calcFunc-eq a b)))))
136211a9
EZ
1383
1384(defun calcFunc-neq (a b &rest more)
1385 (if more
1386 (let* ((args (cons a (cons b more)))
1387 (res 0)
1388 (all t)
1389 (p args)
1390 p2)
1391 (while (and (cdr p) (not (eq res 1)))
1392 (setq p2 p)
1393 (while (and (setq p2 (cdr p2)) (not (eq res 1)))
1394 (setq res (math-two-eq (car p) (car p2)))
1395 (or res (setq all nil)))
1396 (setq p (cdr p)))
1397 (if (eq res 1)
1398 0
1399 (if all
1400 1
1401 (cons 'calcFunc-neq args))))
1402 (or (cdr (assq (math-two-eq a b) '((0 . 1) (1 . 0))))
1403 (if (and (or (math-looks-negp a) (math-zerop a))
1404 (or (math-looks-negp b) (math-zerop b)))
1405 (list 'calcFunc-neq (math-neg a) (math-neg b))
bf77c646 1406 (list 'calcFunc-neq a b)))))
136211a9
EZ
1407
1408(defun math-two-eq (a b)
1409 (if (eq (car-safe a) 'vec)
1410 (if (eq (car-safe b) 'vec)
1411 (if (= (length a) (length b))
1412 (let ((res 1))
1413 (while (and (setq a (cdr a) b (cdr b)) (not (eq res 0)))
1414 (if res
1415 (setq res (math-two-eq (car a) (car b)))
1416 (if (eq (math-two-eq (car a) (car b)) 0)
1417 (setq res 0))))
1418 res)
1419 0)
1420 (if (Math-objectp b)
1421 0
1422 nil))
1423 (if (eq (car-safe b) 'vec)
1424 (if (Math-objectp a)
1425 0
1426 nil)
1427 (let ((res (math-compare a b)))
1428 (if (= res 0)
1429 1
1430 (if (and (= res 2) (not (and (Math-scalarp a) (Math-scalarp b))))
1431 nil
bf77c646 1432 0))))))
136211a9
EZ
1433
1434(defun calcFunc-lt (a b)
1435 (let ((res (math-compare a b)))
1436 (if (= res -1)
1437 1
1438 (if (= res 2)
1439 (if (and (or (math-looks-negp a) (math-zerop a))
1440 (or (math-looks-negp b) (math-zerop b)))
1441 (list 'calcFunc-gt (math-neg a) (math-neg b))
1442 (list 'calcFunc-lt a b))
bf77c646 1443 0))))
136211a9
EZ
1444
1445(defun calcFunc-gt (a b)
1446 (let ((res (math-compare a b)))
1447 (if (= res 1)
1448 1
1449 (if (= res 2)
1450 (if (and (or (math-looks-negp a) (math-zerop a))
1451 (or (math-looks-negp b) (math-zerop b)))
1452 (list 'calcFunc-lt (math-neg a) (math-neg b))
1453 (list 'calcFunc-gt a b))
bf77c646 1454 0))))
136211a9
EZ
1455
1456(defun calcFunc-leq (a b)
1457 (let ((res (math-compare a b)))
1458 (if (= res 1)
1459 0
1460 (if (= res 2)
1461 (if (and (or (math-looks-negp a) (math-zerop a))
1462 (or (math-looks-negp b) (math-zerop b)))
1463 (list 'calcFunc-geq (math-neg a) (math-neg b))
1464 (list 'calcFunc-leq a b))
bf77c646 1465 1))))
136211a9
EZ
1466
1467(defun calcFunc-geq (a b)
1468 (let ((res (math-compare a b)))
1469 (if (= res -1)
1470 0
1471 (if (= res 2)
1472 (if (and (or (math-looks-negp a) (math-zerop a))
1473 (or (math-looks-negp b) (math-zerop b)))
1474 (list 'calcFunc-leq (math-neg a) (math-neg b))
1475 (list 'calcFunc-geq a b))
bf77c646 1476 1))))
136211a9
EZ
1477
1478(defun calcFunc-rmeq (a)
1479 (if (math-vectorp a)
1480 (math-map-vec 'calcFunc-rmeq a)
1481 (if (assq (car-safe a) calc-tweak-eqn-table)
1482 (if (and (eq (car-safe (nth 2 a)) 'var)
1483 (math-objectp (nth 1 a)))
1484 (nth 1 a)
1485 (nth 2 a))
1486 (if (eq (car-safe a) 'calcFunc-assign)
1487 (nth 2 a)
1488 (if (eq (car-safe a) 'calcFunc-evalto)
1489 (nth 1 a)
bf77c646 1490 (list 'calcFunc-rmeq a))))))
136211a9
EZ
1491
1492(defun calcFunc-land (a b)
1493 (cond ((Math-zerop a)
1494 a)
1495 ((Math-zerop b)
1496 b)
1497 ((math-is-true a)
1498 b)
1499 ((math-is-true b)
1500 a)
bf77c646 1501 (t (list 'calcFunc-land a b))))
136211a9
EZ
1502
1503(defun calcFunc-lor (a b)
1504 (cond ((Math-zerop a)
1505 b)
1506 ((Math-zerop b)
1507 a)
1508 ((math-is-true a)
1509 a)
1510 ((math-is-true b)
1511 b)
bf77c646 1512 (t (list 'calcFunc-lor a b))))
136211a9
EZ
1513
1514(defun calcFunc-lnot (a)
1515 (if (Math-zerop a)
1516 1
1517 (if (math-is-true a)
1518 0
1519 (let ((op (and (= (length a) 3)
1520 (assq (car a) calc-tweak-eqn-table))))
1521 (if op
1522 (cons (nth 2 op) (cdr a))
bf77c646 1523 (list 'calcFunc-lnot a))))))
136211a9
EZ
1524
1525(defun calcFunc-if (c e1 e2)
1526 (if (Math-zerop c)
1527 e2
1528 (if (and (math-is-true c) (not (Math-vectorp c)))
1529 e1
1530 (or (and (Math-vectorp c)
1531 (math-constp c)
1532 (let ((ee1 (if (Math-vectorp e1)
1533 (if (= (length c) (length e1))
1534 (cdr e1)
1535 (calc-record-why "*Dimension error" e1))
1536 (list e1)))
1537 (ee2 (if (Math-vectorp e2)
1538 (if (= (length c) (length e2))
1539 (cdr e2)
1540 (calc-record-why "*Dimension error" e2))
1541 (list e2))))
1542 (and ee1 ee2
1543 (cons 'vec (math-if-vector (cdr c) ee1 ee2)))))
bf77c646 1544 (list 'calcFunc-if c e1 e2)))))
136211a9
EZ
1545
1546(defun math-if-vector (c e1 e2)
1547 (and c
1548 (cons (if (Math-zerop (car c)) (car e2) (car e1))
1549 (math-if-vector (cdr c)
1550 (or (cdr e1) e1)
bf77c646 1551 (or (cdr e2) e2)))))
136211a9
EZ
1552
1553(defun math-normalize-logical-op (a)
1554 (or (and (eq (car a) 'calcFunc-if)
1555 (= (length a) 4)
1556 (let ((a1 (math-normalize (nth 1 a))))
1557 (if (Math-zerop a1)
1558 (math-normalize (nth 3 a))
1559 (if (Math-numberp a1)
1560 (math-normalize (nth 2 a))
1561 (if (and (Math-vectorp (nth 1 a))
1562 (math-constp (nth 1 a)))
1563 (calcFunc-if (nth 1 a)
1564 (math-normalize (nth 2 a))
1565 (math-normalize (nth 3 a)))
1566 (let ((calc-simplify-mode 'none))
1567 (list 'calcFunc-if a1
1568 (math-normalize (nth 2 a))
1569 (math-normalize (nth 3 a)))))))))
bf77c646 1570 a))
136211a9
EZ
1571
1572(defun calcFunc-in (a b)
1573 (or (and (eq (car-safe b) 'vec)
1574 (let ((bb b))
1575 (while (and (setq bb (cdr bb))
1576 (not (if (memq (car-safe (car bb)) '(vec intv))
1577 (eq (calcFunc-in a (car bb)) 1)
1578 (Math-equal a (car bb))))))
1579 (if bb 1 (and (math-constp a) (math-constp bb) 0))))
1580 (and (eq (car-safe b) 'intv)
1581 (let ((res (math-compare a (nth 2 b))) res2)
1582 (cond ((= res -1)
1583 0)
1584 ((and (= res 0)
1585 (or (/= (nth 1 b) 2)
1586 (Math-lessp (nth 2 b) (nth 3 b))))
1587 (if (memq (nth 1 b) '(2 3)) 1 0))
1588 ((= (setq res2 (math-compare a (nth 3 b))) 1)
1589 0)
1590 ((and (= res2 0)
1591 (or (/= (nth 1 b) 1)
1592 (Math-lessp (nth 2 b) (nth 3 b))))
1593 (if (memq (nth 1 b) '(1 3)) 1 0))
1594 ((/= res 1)
1595 nil)
1596 ((/= res2 -1)
1597 nil)
1598 (t 1))))
1599 (and (Math-equal a b)
1600 1)
1601 (and (math-constp a) (math-constp b)
1602 0)
bf77c646 1603 (list 'calcFunc-in a b)))
136211a9
EZ
1604
1605(defun calcFunc-typeof (a)
1606 (cond ((Math-integerp a) 1)
1607 ((eq (car a) 'frac) 2)
1608 ((eq (car a) 'float) 3)
1609 ((eq (car a) 'hms) 4)
1610 ((eq (car a) 'cplx) 5)
1611 ((eq (car a) 'polar) 6)
1612 ((eq (car a) 'sdev) 7)
1613 ((eq (car a) 'intv) 8)
1614 ((eq (car a) 'mod) 9)
1615 ((eq (car a) 'date) (if (Math-integerp (nth 1 a)) 10 11))
1616 ((eq (car a) 'var)
1617 (if (memq (nth 2 a) '(var-inf var-uinf var-nan)) 12 100))
1618 ((eq (car a) 'vec) (if (math-matrixp a) 102 101))
bf77c646 1619 (t (math-calcFunc-to-var func))))
136211a9
EZ
1620
1621(defun calcFunc-integer (a)
1622 (if (Math-integerp a)
1623 1
1624 (if (Math-objvecp a)
1625 0
bf77c646 1626 (list 'calcFunc-integer a))))
136211a9
EZ
1627
1628(defun calcFunc-real (a)
1629 (if (Math-realp a)
1630 1
1631 (if (Math-objvecp a)
1632 0
bf77c646 1633 (list 'calcFunc-real a))))
136211a9
EZ
1634
1635(defun calcFunc-constant (a)
1636 (if (math-constp a)
1637 1
1638 (if (Math-objvecp a)
1639 0
bf77c646 1640 (list 'calcFunc-constant a))))
136211a9
EZ
1641
1642(defun calcFunc-refers (a b)
1643 (if (math-expr-contains a b)
1644 1
1645 (if (eq (car-safe a) 'var)
1646 (list 'calcFunc-refers a b)
bf77c646 1647 0)))
136211a9
EZ
1648
1649(defun calcFunc-negative (a)
1650 (if (math-looks-negp a)
1651 1
1652 (if (or (math-zerop a)
1653 (math-posp a))
1654 0
bf77c646 1655 (list 'calcFunc-negative a))))
136211a9
EZ
1656
1657(defun calcFunc-variable (a)
1658 (if (eq (car-safe a) 'var)
1659 1
1660 (if (Math-objvecp a)
1661 0
bf77c646 1662 (list 'calcFunc-variable a))))
136211a9
EZ
1663
1664(defun calcFunc-nonvar (a)
1665 (if (eq (car-safe a) 'var)
1666 (list 'calcFunc-nonvar a)
bf77c646 1667 1))
136211a9
EZ
1668
1669(defun calcFunc-istrue (a)
1670 (if (math-is-true a)
1671 1
bf77c646 1672 0))
136211a9
EZ
1673
1674
1675
1676
1677;;;; User-programmability.
1678
1679;;; Compiling Lisp-like forms to use the math library.
1680
1681(defun math-do-defmath (func args body)
1682 (calc-need-macros)
1683 (let* ((fname (intern (concat "calcFunc-" (symbol-name func))))
1684 (doc (if (stringp (car body)) (list (car body))))
1685 (clargs (mapcar 'math-clean-arg args))
1686 (body (math-define-function-body
1687 (if (stringp (car body)) (cdr body) body)
1688 clargs)))
1689 (list 'progn
1690 (if (and (consp (car body))
1691 (eq (car (car body)) 'interactive))
1692 (let ((inter (car body)))
1693 (setq body (cdr body))
1694 (if (or (> (length inter) 2)
1695 (integerp (nth 1 inter)))
1696 (let ((hasprefix nil) (hasmulti nil))
1697 (if (stringp (nth 1 inter))
1698 (progn
1699 (cond ((equal (nth 1 inter) "p")
1700 (setq hasprefix t))
1701 ((equal (nth 1 inter) "m")
1702 (setq hasmulti t))
1703 (t (error
1704 "Can't handle interactive code string \"%s\""
1705 (nth 1 inter))))
1706 (setq inter (cdr inter))))
1707 (if (not (integerp (nth 1 inter)))
1708 (error
1709 "Expected an integer in interactive specification"))
1710 (append (list 'defun
1711 (intern (concat "calc-"
1712 (symbol-name func)))
1713 (if (or hasprefix hasmulti)
1714 '(&optional n)
1715 ()))
1716 doc
1717 (if (or hasprefix hasmulti)
1718 '((interactive "P"))
1719 '((interactive)))
1720 (list
1721 (append
1722 '(calc-slow-wrapper)
1723 (and hasmulti
1724 (list
1725 (list 'setq
1726 'n
1727 (list 'if
1728 'n
1729 (list 'prefix-numeric-value
1730 'n)
1731 (nth 1 inter)))))
1732 (list
1733 (list 'calc-enter-result
1734 (if hasmulti 'n (nth 1 inter))
1735 (nth 2 inter)
1736 (if hasprefix
1737 (list 'append
1738 (list 'quote (list fname))
1739 (list 'calc-top-list-n
1740 (nth 1 inter))
1741 (list 'and
1742 'n
1743 (list
1744 'list
1745 (list
1746 'math-normalize
1747 (list
1748 'prefix-numeric-value
1749 'n)))))
1750 (list 'cons
1751 (list 'quote fname)
1752 (list 'calc-top-list-n
1753 (if hasmulti
1754 'n
1755 (nth 1 inter)))))))))))
1756 (append (list 'defun
1757 (intern (concat "calc-" (symbol-name func)))
1758 args)
1759 doc
1760 (list
1761 inter
1762 (cons 'calc-wrapper body))))))
1763 (append (list 'defun fname clargs)
1764 doc
1765 (math-do-arg-list-check args nil nil)
bf77c646 1766 body))))
136211a9
EZ
1767
1768(defun math-clean-arg (arg)
1769 (if (consp arg)
1770 (math-clean-arg (nth 1 arg))
bf77c646 1771 arg))
136211a9
EZ
1772
1773(defun math-do-arg-check (arg var is-opt is-rest)
1774 (if is-opt
1775 (let ((chk (math-do-arg-check arg var nil nil)))
1776 (list (cons 'and
1777 (cons var
1778 (if (cdr chk)
1779 (setq chk (list (cons 'progn chk)))
1780 chk)))))
1781 (and (consp arg)
1782 (let* ((rest (math-do-arg-check (nth 1 arg) var is-opt is-rest))
1783 (qual (car arg))
1784 (qqual (list 'quote qual))
1785 (qual-name (symbol-name qual))
1786 (chk (intern (concat "math-check-" qual-name))))
1787 (if (fboundp chk)
1788 (append rest
1789 (list
1790 (if is-rest
1791 (list 'setq var
1792 (list 'mapcar (list 'quote chk) var))
1793 (list 'setq var (list chk var)))))
1794 (if (fboundp (setq chk (intern (concat "math-" qual-name))))
1795 (append rest
1796 (list
1797 (if is-rest
1798 (list 'mapcar
1799 (list 'function
1800 (list 'lambda '(x)
1801 (list 'or
1802 (list chk 'x)
1803 (list 'math-reject-arg
1804 'x qqual))))
1805 var)
1806 (list 'or
1807 (list chk var)
1808 (list 'math-reject-arg var qqual)))))
1809 (if (and (string-match "\\`not-\\(.*\\)\\'" qual-name)
1810 (fboundp (setq chk (intern
1811 (concat "math-"
1812 (math-match-substring
1813 qual-name 1))))))
1814 (append rest
1815 (list
1816 (if is-rest
1817 (list 'mapcar
1818 (list 'function
1819 (list 'lambda '(x)
1820 (list 'and
1821 (list chk 'x)
1822 (list 'math-reject-arg
1823 'x qqual))))
1824 var)
1825 (list 'and
1826 (list chk var)
1827 (list 'math-reject-arg var qqual)))))
bf77c646 1828 (error "Unknown qualifier `%s'" qual-name))))))))
136211a9
EZ
1829
1830(defun math-do-arg-list-check (args is-opt is-rest)
1831 (cond ((null args) nil)
1832 ((consp (car args))
1833 (append (math-do-arg-check (car args)
1834 (math-clean-arg (car args))
1835 is-opt is-rest)
1836 (math-do-arg-list-check (cdr args) is-opt is-rest)))
1837 ((eq (car args) '&optional)
1838 (math-do-arg-list-check (cdr args) t nil))
1839 ((eq (car args) '&rest)
1840 (math-do-arg-list-check (cdr args) nil t))
bf77c646 1841 (t (math-do-arg-list-check (cdr args) is-opt is-rest))))
136211a9
EZ
1842
1843(defconst math-prim-funcs
1844 '( (~= . math-nearly-equal)
1845 (% . math-mod)
1846 (lsh . calcFunc-lsh)
1847 (ash . calcFunc-ash)
1848 (logand . calcFunc-and)
1849 (logandc2 . calcFunc-diff)
1850 (logior . calcFunc-or)
1851 (logxor . calcFunc-xor)
1852 (lognot . calcFunc-not)
1853 (equal . equal) ; need to leave these ones alone!
1854 (eq . eq)
1855 (and . and)
1856 (or . or)
1857 (if . if)
1858 (^ . math-pow)
1859 (expt . math-pow)
bf77c646 1860 ))
136211a9
EZ
1861
1862(defconst math-prim-vars
1863 '( (nil . nil)
1864 (t . t)
1865 (&optional . &optional)
1866 (&rest . &rest)
bf77c646 1867 ))
136211a9
EZ
1868
1869(defun math-define-function-body (body env)
1870 (let ((body (math-define-body body env)))
1871 (if (math-body-refers-to body 'math-return)
1872 (list (cons 'catch (cons '(quote math-return) body)))
bf77c646 1873 body)))
136211a9
EZ
1874
1875(defun math-define-body (body exp-env)
bf77c646 1876 (math-define-list body))
136211a9
EZ
1877
1878(defun math-define-list (body &optional quote)
1879 (cond ((null body)
1880 nil)
1881 ((and (eq (car body) ':)
1882 (stringp (nth 1 body)))
1883 (cons (let* ((math-read-expr-quotes t)
1884 (exp (math-read-plain-expr (nth 1 body) t)))
1885 (math-define-exp exp))
1886 (math-define-list (cdr (cdr body)))))
1887 (quote
1888 (cons (cond ((consp (car body))
1889 (math-define-list (cdr body) t))
1890 (t
1891 (car body)))
1892 (math-define-list (cdr body))))
1893 (t
1894 (cons (math-define-exp (car body))
bf77c646 1895 (math-define-list (cdr body))))))
136211a9
EZ
1896
1897(defun math-define-exp (exp)
1898 (cond ((consp exp)
1899 (let ((func (car exp)))
1900 (cond ((memq func '(quote function))
1901 (if (and (consp (nth 1 exp))
1902 (eq (car (nth 1 exp)) 'lambda))
1903 (cons 'quote
1904 (math-define-lambda (nth 1 exp) exp-env))
1905 exp))
1906 ((memq func '(let let* for foreach))
1907 (let ((head (nth 1 exp))
1908 (body (cdr (cdr exp))))
1909 (if (memq func '(let let*))
1910 ()
1911 (setq func (cdr (assq func '((for . math-for)
1912 (foreach . math-foreach)))))
1913 (if (not (listp (car head)))
1914 (setq head (list head))))
1915 (macroexpand
1916 (cons func
1917 (cons (math-define-let head)
1918 (math-define-body body
1919 (nconc
1920 (math-define-let-env head)
1921 exp-env)))))))
1922 ((and (memq func '(setq setf))
1923 (math-complicated-lhs (cdr exp)))
1924 (if (> (length exp) 3)
1925 (cons 'progn (math-define-setf-list (cdr exp)))
1926 (math-define-setf (nth 1 exp) (nth 2 exp))))
1927 ((eq func 'condition-case)
1928 (cons func
1929 (cons (nth 1 exp)
1930 (math-define-body (cdr (cdr exp))
1931 (cons (nth 1 exp)
1932 exp-env)))))
1933 ((eq func 'cond)
1934 (cons func
1935 (math-define-cond (cdr exp))))
1936 ((and (consp func) ; ('spam a b) == force use of plain spam
1937 (eq (car func) 'quote))
1938 (cons func (math-define-list (cdr exp))))
1939 ((symbolp func)
1940 (let ((args (math-define-list (cdr exp)))
1941 (prim (assq func math-prim-funcs)))
1942 (cond (prim
1943 (cons (cdr prim) args))
1944 ((eq func 'floatp)
1945 (list 'eq (car args) '(quote float)))
1946 ((eq func '+)
1947 (math-define-binop 'math-add 0
1948 (car args) (cdr args)))
1949 ((eq func '-)
1950 (if (= (length args) 1)
1951 (cons 'math-neg args)
1952 (math-define-binop 'math-sub 0
1953 (car args) (cdr args))))
1954 ((eq func '*)
1955 (math-define-binop 'math-mul 1
1956 (car args) (cdr args)))
1957 ((eq func '/)
1958 (math-define-binop 'math-div 1
1959 (car args) (cdr args)))
1960 ((eq func 'min)
1961 (math-define-binop 'math-min 0
1962 (car args) (cdr args)))
1963 ((eq func 'max)
1964 (math-define-binop 'math-max 0
1965 (car args) (cdr args)))
1966 ((eq func '<)
1967 (if (and (math-numberp (nth 1 args))
1968 (math-zerop (nth 1 args)))
1969 (list 'math-negp (car args))
1970 (cons 'math-lessp args)))
1971 ((eq func '>)
1972 (if (and (math-numberp (nth 1 args))
1973 (math-zerop (nth 1 args)))
1974 (list 'math-posp (car args))
1975 (list 'math-lessp (nth 1 args) (nth 0 args))))
1976 ((eq func '<=)
1977 (list 'not
1978 (if (and (math-numberp (nth 1 args))
1979 (math-zerop (nth 1 args)))
1980 (list 'math-posp (car args))
1981 (list 'math-lessp
1982 (nth 1 args) (nth 0 args)))))
1983 ((eq func '>=)
1984 (list 'not
1985 (if (and (math-numberp (nth 1 args))
1986 (math-zerop (nth 1 args)))
1987 (list 'math-negp (car args))
1988 (cons 'math-lessp args))))
1989 ((eq func '=)
1990 (if (and (math-numberp (nth 1 args))
1991 (math-zerop (nth 1 args)))
1992 (list 'math-zerop (nth 0 args))
1993 (if (and (integerp (nth 1 args))
1994 (/= (% (nth 1 args) 10) 0))
1995 (cons 'math-equal-int args)
1996 (cons 'math-equal args))))
1997 ((eq func '/=)
1998 (list 'not
1999 (if (and (math-numberp (nth 1 args))
2000 (math-zerop (nth 1 args)))
2001 (list 'math-zerop (nth 0 args))
2002 (if (and (integerp (nth 1 args))
2003 (/= (% (nth 1 args) 10) 0))
2004 (cons 'math-equal-int args)
2005 (cons 'math-equal args)))))
2006 ((eq func '1+)
2007 (list 'math-add (car args) 1))
2008 ((eq func '1-)
2009 (list 'math-add (car args) -1))
2010 ((eq func 'not) ; optimize (not (not x)) => x
2011 (if (eq (car-safe args) func)
2012 (car (nth 1 args))
2013 (cons func args)))
2014 ((and (eq func 'elt) (cdr (cdr args)))
2015 (math-define-elt (car args) (cdr args)))
2016 (t
2017 (macroexpand
2018 (let* ((name (symbol-name func))
2019 (cfunc (intern (concat "calcFunc-" name)))
2020 (mfunc (intern (concat "math-" name))))
2021 (cond ((fboundp cfunc)
2022 (cons cfunc args))
2023 ((fboundp mfunc)
2024 (cons mfunc args))
2025 ((or (fboundp func)
2026 (string-match "\\`calcFunc-.*" name))
2027 (cons func args))
2028 (t
2029 (cons cfunc args)))))))))
2030 (t (cons func args)))))
2031 ((symbolp exp)
2032 (let ((prim (assq exp math-prim-vars))
2033 (name (symbol-name exp)))
2034 (cond (prim
2035 (cdr prim))
2036 ((memq exp exp-env)
2037 exp)
2038 ((string-match "-" name)
2039 exp)
2040 (t
2041 (intern (concat "var-" name))))))
2042 ((integerp exp)
2043 (if (or (<= exp -1000000) (>= exp 1000000))
2044 (list 'quote (math-normalize exp))
2045 exp))
bf77c646 2046 (t exp)))
136211a9
EZ
2047
2048(defun math-define-cond (forms)
2049 (and forms
2050 (cons (math-define-list (car forms))
bf77c646 2051 (math-define-cond (cdr forms)))))
136211a9
EZ
2052
2053(defun math-complicated-lhs (body)
2054 (and body
2055 (or (not (symbolp (car body)))
bf77c646 2056 (math-complicated-lhs (cdr (cdr body))))))
136211a9
EZ
2057
2058(defun math-define-setf-list (body)
2059 (and body
2060 (cons (math-define-setf (nth 0 body) (nth 1 body))
bf77c646 2061 (math-define-setf-list (cdr (cdr body))))))
136211a9
EZ
2062
2063(defun math-define-setf (place value)
2064 (setq place (math-define-exp place)
2065 value (math-define-exp value))
2066 (cond ((symbolp place)
2067 (list 'setq place value))
2068 ((eq (car-safe place) 'nth)
2069 (list 'setcar (list 'nthcdr (nth 1 place) (nth 2 place)) value))
2070 ((eq (car-safe place) 'elt)
2071 (list 'setcar (list 'nthcdr (nth 2 place) (nth 1 place)) value))
2072 ((eq (car-safe place) 'car)
2073 (list 'setcar (nth 1 place) value))
2074 ((eq (car-safe place) 'cdr)
2075 (list 'setcdr (nth 1 place) value))
2076 (t
bf77c646 2077 (error "Bad place form for setf: %s" place))))
136211a9
EZ
2078
2079(defun math-define-binop (op ident arg1 rest)
2080 (if rest
2081 (math-define-binop op ident
2082 (list op arg1 (car rest))
2083 (cdr rest))
bf77c646 2084 (or arg1 ident)))
136211a9
EZ
2085
2086(defun math-define-let (vlist)
2087 (and vlist
2088 (cons (if (consp (car vlist))
2089 (cons (car (car vlist))
2090 (math-define-list (cdr (car vlist))))
2091 (car vlist))
bf77c646 2092 (math-define-let (cdr vlist)))))
136211a9
EZ
2093
2094(defun math-define-let-env (vlist)
2095 (and vlist
2096 (cons (if (consp (car vlist))
2097 (car (car vlist))
2098 (car vlist))
bf77c646 2099 (math-define-let-env (cdr vlist)))))
136211a9
EZ
2100
2101(defun math-define-lambda (exp exp-env)
2102 (nconc (list (nth 0 exp) ; 'lambda
2103 (nth 1 exp)) ; arg list
2104 (math-define-function-body (cdr (cdr exp))
bf77c646 2105 (append (nth 1 exp) exp-env))))
136211a9
EZ
2106
2107(defun math-define-elt (seq idx)
2108 (if idx
2109 (math-define-elt (list 'elt seq (car idx)) (cdr idx))
bf77c646 2110 seq))
136211a9
EZ
2111
2112
2113
2114;;; Useful programming macros.
2115
2116(defmacro math-while (head &rest body)
2117 (let ((body (cons 'while (cons head body))))
2118 (if (math-body-refers-to body 'math-break)
2119 (cons 'catch (cons '(quote math-break) (list body)))
bf77c646 2120 body)))
136211a9
EZ
2121
2122
2123(defmacro math-for (head &rest body)
2124 (let ((body (if head
2125 (math-handle-for head body)
2126 (cons 'while (cons t body)))))
2127 (if (math-body-refers-to body 'math-break)
2128 (cons 'catch (cons '(quote math-break) (list body)))
bf77c646 2129 body)))
136211a9
EZ
2130
2131(defun math-handle-for (head body)
2132 (let* ((var (nth 0 (car head)))
2133 (init (nth 1 (car head)))
2134 (limit (nth 2 (car head)))
2135 (step (or (nth 3 (car head)) 1))
2136 (body (if (cdr head)
2137 (list (math-handle-for (cdr head) body))
2138 body))
2139 (all-ints (and (integerp init) (integerp limit) (integerp step)))
2140 (const-limit (or (integerp limit)
2141 (and (eq (car-safe limit) 'quote)
2142 (math-realp (nth 1 limit)))))
2143 (const-step (or (integerp step)
2144 (and (eq (car-safe step) 'quote)
2145 (math-realp (nth 1 step)))))
2146 (save-limit (if const-limit limit (make-symbol "<limit>")))
2147 (save-step (if const-step step (make-symbol "<step>"))))
2148 (cons 'let
2149 (cons (append (if const-limit nil (list (list save-limit limit)))
2150 (if const-step nil (list (list save-step step)))
2151 (list (list var init)))
2152 (list
2153 (cons 'while
2154 (cons (if all-ints
2155 (if (> step 0)
2156 (list '<= var save-limit)
2157 (list '>= var save-limit))
2158 (list 'not
2159 (if const-step
2160 (if (or (math-posp step)
2161 (math-posp
2162 (cdr-safe step)))
2163 (list 'math-lessp
2164 save-limit
2165 var)
2166 (list 'math-lessp
2167 var
2168 save-limit))
2169 (list 'if
2170 (list 'math-posp
2171 save-step)
2172 (list 'math-lessp
2173 save-limit
2174 var)
2175 (list 'math-lessp
2176 var
2177 save-limit)))))
2178 (append body
2179 (list (list 'setq
2180 var
2181 (list (if all-ints
2182 '+
2183 'math-add)
2184 var
bf77c646 2185 save-step)))))))))))
136211a9
EZ
2186
2187
2188(defmacro math-foreach (head &rest body)
2189 (let ((body (math-handle-foreach head body)))
2190 (if (math-body-refers-to body 'math-break)
2191 (cons 'catch (cons '(quote math-break) (list body)))
bf77c646 2192 body)))
136211a9
EZ
2193
2194
2195(defun math-handle-foreach (head body)
2196 (let ((var (nth 0 (car head)))
2197 (data (nth 1 (car head)))
2198 (body (if (cdr head)
2199 (list (math-handle-foreach (cdr head) body))
2200 body)))
2201 (cons 'let
2202 (cons (list (list var data))
2203 (list
2204 (cons 'while
2205 (cons var
2206 (append body
2207 (list (list 'setq
2208 var
bf77c646 2209 (list 'cdr var)))))))))))
136211a9
EZ
2210
2211
2212(defun math-body-refers-to (body thing)
2213 (or (equal body thing)
2214 (and (consp body)
2215 (or (math-body-refers-to (car body) thing)
bf77c646 2216 (math-body-refers-to (cdr body) thing)))))
136211a9
EZ
2217
2218(defun math-break (&optional value)
bf77c646 2219 (throw 'math-break value))
136211a9
EZ
2220
2221(defun math-return (&optional value)
bf77c646 2222 (throw 'math-return value))
136211a9
EZ
2223
2224
2225
2226
2227
2228(defun math-composite-inequalities (x op)
2229 (if (memq (nth 1 op) '(calcFunc-eq calcFunc-neq))
2230 (if (eq (car x) (nth 1 op))
2231 (append x (list (math-read-expr-level (nth 3 op))))
2232 (throw 'syntax "Syntax error"))
2233 (list 'calcFunc-in
2234 (nth 2 x)
2235 (if (memq (nth 1 op) '(calcFunc-lt calcFunc-leq))
2236 (if (memq (car x) '(calcFunc-lt calcFunc-leq))
2237 (math-make-intv
2238 (+ (if (eq (car x) 'calcFunc-leq) 2 0)
2239 (if (eq (nth 1 op) 'calcFunc-leq) 1 0))
2240 (nth 1 x) (math-read-expr-level (nth 3 op)))
2241 (throw 'syntax "Syntax error"))
2242 (if (memq (car x) '(calcFunc-gt calcFunc-geq))
2243 (math-make-intv
2244 (+ (if (eq (nth 1 op) 'calcFunc-geq) 2 0)
2245 (if (eq (car x) 'calcFunc-geq) 1 0))
2246 (math-read-expr-level (nth 3 op)) (nth 1 x))
bf77c646 2247 (throw 'syntax "Syntax error"))))))
136211a9 2248
bf77c646 2249;;; calc-prog.el ends here