Fix #4341: atan of complex bfloat calls rat
[maxima.git] / src / buildq.lisp
blob2b63d7d10db23a187f27ea856ecbcd3e7ed0d13d
1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancements. ;;;;;
4 ;;; ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;; (c) Copyright 1980 Massachusetts Institute of Technology ;;;
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11 (in-package :maxima)
13 (macsyma-module buildq)
15 ;; Exported functions are $BUILDQ and MBUILDQ-SUBST
16 ;; TRANSLATION property for $BUILDQ in MAXSRC;TRANS5 >
18 ;;**************************************************************************
19 ;;****** ******
20 ;;****** BUILDQ: A backquote-like construct for Macsyma ******
21 ;;****** ******
22 ;;**************************************************************************
24 ;;DESCRIPTION:
27 ;; Syntax:
29 ;; BUILDQ([<varlist>],<expression>);
31 ;; <expression> is any single macsyma expression
32 ;; <varlist> is a list of elements of the form <atom> or <atom>:<value>
35 ;; Semantics:
37 ;; the <value>s in the <varlist> are evaluated left to right (the syntax
38 ;; <atom> is equivalent to <atom>:<atom>). then these values are substituted
39 ;; into <expression> in parallel. If any <atom> appears as a single
40 ;; argument to the special form SPLICE (i.e. SPLICE(<atom>) ) inside
41 ;; <expression>, then the value associated with that <atom> must be a macsyma
42 ;; list, and it is spliced into <expression> instead of substituted.
44 ;;SIMPLIFICATION:
47 ;; the arguments to $BUILDQ need to be protected from simplification until
48 ;; the substitutions have been carried out. This code should affect that.
50 (defprop $buildq simpbuildq operators)
51 (defprop %buildq simpbuildq operators)
53 ;; This is modeled after SIMPMDEF, SIMPLAMBDA etc. in JM;SIMP >
55 (defun simpbuildq (x ignored simp-flags)
56 (declare (ignore ignored simp-flags))
57 (cons '($buildq simp) (cdr x)))
59 ;; Note that suppression of simplification is very important to the semantics
60 ;; of BUILDQ. Consider BUILDQ([A:'[B,C,D]],SPLICE(A)+SPLICE(A));
62 ;; If no simplification takes place, $BUILDQ returns B+C+D+B+C+D.
63 ;; If the expression is simplified into 2*SPLICE(A), then 2*B*C*D results.
67 ;;INTERPRETIVE CODE:
70 (defmspec $buildq (form) (setq form (cdr form))
71 (cond ((or (null (cdr form))
72 (cddr form))
73 (merror (intl:gettext "buildq: expected exactly two arguments; found ~M") `(($buildq) ,@form)))
74 (t (mbuildq (car form) (cadr form)))))
76 ;; this macro definition is NOT equivalent because of the way lisp macros
77 ;; are currently handled in the macsyma interpreter. When the subr form
78 ;; is returned the arguments get MEVAL'd (and hence simplified) before
79 ;; we get ahold of them.
81 ;; Lisp MACROS, and Lisp FEXPR's are meaningless to the macsyma evaluator
82 ;; and should be ignored, the proper things to use are MFEXPR* and
83 ;; MMACRO properties. -GJC
85 ;;(DEFMACRO ($BUILDQ DEFMACRO-FOR-COMPILING T)
86 ;; (VARLIST . EXPRESSIONS)
87 ;; (COND ((OR (NULL VARLIST)
88 ;; (NULL EXPRESSIONS)
89 ;; (CDR EXPRESSIONS))
90 ;; (DISPLA `(($BUILDQ) ,VARLIST ,@EXPRESSIONS))
91 ;; (MERROR "`buildq' takes 2 args"))
92 ;; (T `(MBUILDQ ',VARLIST ',(CAR EXPRESSIONS)))))
95 (defun mbuildq (substitutions expression)
96 (cond ((not ($listp substitutions))
97 (merror (intl:gettext "buildq: first argument must be a list; found ~M") substitutions)))
98 (mbuildq-subst
99 (mapcar #'(lambda (form) ; make a variable/value alist
100 (cond ((symbolp form)
101 (cons form (meval form)))
102 ((and (eq (caar form) 'msetq)
103 (symbolp (cadr form)))
104 (cons (cadr form) (meval (caddr form))))
106 (merror (intl:gettext "buildq: variable must be a symbol or an assignment to a symbol; found ~M")
107 form
108 ))))
109 (cdr substitutions))
110 expression))
113 ;; this performs the substitutions for the variables in the expressions.
114 ;; it tries to be smart and only copy what list structure it has to.
115 ;; the first arg is an alist of pairs: (<variable> . <value>)
116 ;; the second arg is the macsyma expression to substitute into.
118 (defun mbuildq-subst (alist expression)
119 (prog (new-car)
120 (cond ((atom expression)
121 (return (mbuildq-associate expression alist)))
122 ((atom (car expression))
123 (setq new-car (mbuildq-associate (car expression) alist)))
124 ((mbuildq-splice-associate expression alist)
125 ; if the expression is a legal SPLICE, this clause is taken.
126 ; a SPLICE should never occur here. It corresponds to `,@form
128 (merror (intl:gettext "splice: encountered 'splice' in an unexpected place: ~M") expression))
129 ((atom (caar expression))
130 (setq new-car (mbuildq-associate (caar expression) alist))
131 (cond ((eq new-car (caar expression))
132 (setq new-car (car expression)))
133 ((atom new-car)
134 ;; Be careful to verbify a string before substituting into the operator.
135 (setq new-car (cons (or (and (stringp new-car) ($verbify new-car)) new-car) (cdar expression))))
136 (t (return
137 `(,(cons 'mqapply (cdar expression))
138 ,new-car
139 ,@(mbuildq-subst alist (cdr expression)))))))
140 ((setq new-car
141 (mbuildq-splice-associate (car expression) alist))
142 (return (append (cdr new-car)
143 (mbuildq-subst alist (cdr expression)))))
144 (t (setq new-car (mbuildq-subst alist (car expression)))))
145 (return
146 (let ((new-cdr (mbuildq-subst alist (cdr expression))))
147 (cond ((and (eq new-car (car expression))
148 (eq new-cdr (cdr expression)))
149 expression)
150 (t (cons new-car new-cdr)))))))
152 ;; this function returns the appropriate thing to substitute for an atom
153 ;; appearing inside a backquote. If it's not in the varlist, it's the
154 ;; atom itself.
156 (defun mbuildq-associate (atom alist)
157 (let ((form))
158 (cond ((not (symbolp atom))
159 atom)
160 ((setq form (assoc atom alist :test #'eq))
161 (cdr form))
162 ((setq form (assoc ($verbify atom) alist :test #'eq))
163 ;trying to match a nounified substitution variable
164 (cond ((atom (cdr form))
165 ($nounify (cdr form)))
166 ((member (caar (cdr form))
167 '(mquote mlist mprog mprogn lambda) :test #'eq)
168 ;list gotten from the parser.
169 `((mquote) ,(cdr form)))
170 (t `( (,($nounify (caar (cdr form)))
171 ,@(cdar (cdr form)))
172 ,@(cdr (cdr form))))))
173 ;; ((<verb> ...) ...) ==> ((<noun> ...) ...)
174 (t atom))))
176 ;; this function decides whether the SPLICE is one of ours or not.
177 ;; the basic philosophy is that the SPLICE is ours if it has exactly
178 ;; one symbolic argument and that arg appears in the current varlist.
179 ;; if it's one of ours, this function returns the list it's bound to.
180 ;; otherwise it returns nil. Notice that the list returned is an
181 ;; MLIST and hence the cdr of the return value is what gets spliced in.
183 (defun mbuildq-splice-associate (expression alist)
184 (and (eq (caar expression) '$splice)
185 (cdr expression)
186 (null (cddr expression))
187 (let ((match (assoc (cadr expression) alist :test #'eq)))
188 (cond ((null match) () )
189 ((not ($listp (cdr match)))
190 (merror (intl:gettext "buildq: 'splice' must return a list, but ~M returned: ~M~%")
191 expression (cdr match)))
192 (t (cdr match))))))