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