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