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