Add support for external html docs
[maxima.git] / share / pytranslate / pytranslate.lisp
blob0b31ef7591018f3c64884031529626adc5f7fc5f
1 ;;TODO : Potential smalloptimization - a+-0=a, a*/1=a
2 ;;TODO : Potential optimization, prevent blank v.ins({}) lines
3 (defparameter *maxima-function-dictionary-name* "f")
4 (defparameter *maxima-variables-dictionary-name* "v")
5 (defparameter *python-hierarchial-dict-name* "Stack")
6 (defparameter *symbols-directly-convert* '()
7 "List containing symbols to be converted as it is to Python symbols rather than maxima_vars[\"symbol\"]")
8 (defparameter *ins-method-name* "ins")
9 (defparameter *assignment-method-name* "assign")
11 (defvar *maxima-direct-ir-map*
12 (let ((ht (make-hash-table)))
13 (setf (gethash 'mtimes ht) '(op *))
14 (setf (gethash 'mplus ht) '(op +))
15 (setf (gethash 'rat ht) '(op /))
16 (setf (gethash 'mquotient ht) '(op /))
17 (setf (gethash 'msetq ht) '(op-no-bracket =))
18 (setf (gethash 'mlist ht) '(struct-list))
19 (setf (gethash 'mand ht) '(boolop (symbol "and")))
20 (setf (gethash 'mor ht) '(boolop (symbol "or")))
21 (setf (gethash 'mnot ht) '(funcall (symbol "not")))
22 (setf (gethash 'mminus ht) '(unary-op -))
23 (setf (gethash 'mgreaterp ht) '(comp-op >))
24 (setf (gethash 'mequal ht) '(comp-op ==))
25 (setf (gethash 'mnotequal ht) '(comp-op !=))
26 (setf (gethash 'mlessp ht) '(comp-op <))
27 (setf (gethash 'mgeqp ht) '(comp-op >=))
28 (setf (gethash 'mleqp ht) '(comp-op <=))
29 (setf (gethash '$floor ht) '(funcall (symbol "math.floor")))
30 (setf (gethash '$fix ht) '(funcall (symbol "math.floor")))
31 (setf (gethash '%fix ht) '(funcall (symbol "math.floor")))
32 (setf (gethash '%sqrt ht) '(funcall (symbol "math.sqrt")))
33 (setf (gethash 'mreturn ht) '(funcall (symbol "return")))
34 (setf (gethash 'mabs ht) '(funcall (symbol "abs")))
35 ht))
37 (defvar *maxima-special-ir-map*
38 (let ((ht (make-hash-table)))
39 (setf (gethash 'mdefine ht) 'func-def-to-ir)
40 (setf (gethash '%array ht) 'array-def-to-ir)
41 (setf (gethash 'mprog ht) 'mprog-to-ir)
42 (setf (gethash 'mprogn ht) 'mprogn-to-ir)
43 (setf (gethash 'mcond ht) 'mcond-to-ir)
44 (setf (gethash 'lambda ht) 'lambda-to-ir)
45 (setf (gethash 'mdoin ht) 'for-list-to-ir)
46 (setf (gethash 'mdo ht) 'for-loop-to-ir)
47 (setf (gethash '%endcons ht) 'endcons-to-ir)
48 (setf (gethash '$endcons ht) 'endcons-to-ir)
49 (setf (gethash '$plot3d ht) 'plot-to-ir)
50 (setf (gethash '$plot2d ht) 'plot-to-ir)
51 (setf (gethash 'mexpt ht) 'mexpt-to-ir)
52 (setf (gethash 'mfactorial ht) 'mfactorial-to-ir)
53 ht))
55 (defvar *ir-forms-to-append* '())
57 (defun clast (l)
58 (car (last l)))
60 ; Check if form is mprogn
61 (defun mprogn-p (form)
62 (and (consp (clast form))
63 (consp (car (clast form)))
64 (eq (caar (clast form)) 'mprogn)))
66 (defun symbol-name-to-string (form)
67 (maybe-invert-string-case (symbol-name (stripdollar form))))
69 (defun symbol-to-ir (form)
70 `(symbol ,(symbol-name-to-string form)))
72 (defun symbol-to-dictionary-ir (form &optional (dict-name nil))
73 `(element-array (symbol
74 ,(cond (dict-name dict-name)
75 (t *maxima-variables-dictionary-name*)))
76 (string ,(symbol-name-to-string form))))
78 (defun plot-to-ir (form)
79 `(funcall
80 (element-array ,*maxima-function-dictionary-name*
81 (string
82 ,(cond ((eql (list-length (cddr form)) 1) "plot2d")
83 (t "plot3d"))))
84 ,(maxima-to-ir (cadr form))
85 ,@(mapcar
86 (lambda (elm) (cond ((and (consp elm)
87 (consp (car elm))
88 (eq 'mlist (caar elm)))
89 `(struct-list (string ,(symbol-name-to-string (cadr elm)))
90 ,@(mapcar #'maxima-to-ir (cddr elm))))
91 (t (maxima-to-ir elm))))
92 (cddr form))))
94 (defun mfactorial-to-ir (form)
95 `(funcall (element-array (symbol ,*maxima-function-dictionary-name*) (string "factorial")) ,@(mapcar #'maxima-to-ir (cdr form))))
97 (defun mexpt-to-ir (form)
98 `(funcall (element-array (symbol ,*maxima-function-dictionary-name*) (string "pow")) ,@(mapcar #'maxima-to-ir (cdr form))))
100 (defun assignment-to-ir (form)
101 (cond ((consp (cadr form)) `(op-no-bracket = ,@(mapcar #'maxima-to-ir (cdr form))))
102 (t `(funcall (symbol ,*assignment-method-name*)
103 (string ,(symbol-name-to-string (cadr form)))
104 ,(maxima-to-ir (caddr form))
105 (symbol ,*maxima-variables-dictionary-name*)))))
107 (defun symbol-to-asterisk-ir (form)
108 (list 'symbol
109 (concatenate 'string "*"
110 (maybe-invert-string-case (symbol-name (stripdollar form))))))
112 (defun endcons-to-ir (form)
113 (cond ((consp (clast form))
114 (maxima-to-ir (append (clast form) `(,(cadr form)))))
116 `(struct-list (asterisk ,(maxima-to-ir (clast form))) ,(maxima-to-ir (cadr form))))))
118 (defun for-loop-to-ir (form)
119 (cond ((null (caddr (cdddr form))) ; Condition Specified
120 `(body ,@(cond ((null (cadr form)) '()) ; If variable not given
121 (t `((assign ,(maxima-to-ir (cadr form)) ; If variable assigned by "for var:value"
122 ,(maxima-to-ir (caddr form))))))
123 (while-loop
124 ,(cond ((and
125 (consp (clast (butlast form)))
126 (consp (car (clast (butlast form))))
127 (eq 'mnot (caar (clast (butlast form)))))
128 (maxima-to-ir (cadr (clast (butlast form)))))
130 `(funcall (symbol "not")
131 ,(maxima-to-ir (clast (butlast form))))))
132 (body-indented
133 ,@(cond ((mprogn-p form)
134 (mapcar 'maxima-to-ir (cdr (clast form))))
136 `(,(maxima-to-ir (clast form)))))
137 ,@(cond ((null (cadddr form)) '())
138 (t `((assign ,(maxima-to-ir (cadr form))
139 (op + ,(maxima-to-ir (cadr form)) ,(maxima-to-ir (cadddr form)))))))))
140 ,@(cond ((null (cadr form)) '()) ; If variable not given
141 (t `((del ,(maxima-to-ir (cadr form))))))))
142 (t ; Limit specified
143 `(for-list ,(maxima-to-ir (cadr form))
144 (funcall (symbol "range")
145 ,(maxima-to-ir (caddr form))
146 ,(cond ((and (atom (caddr (cdddr form)))
147 (not (symbolp (caddr (cdddr form)))))
148 (maxima-to-ir (1+ (caddr (cdddr form)))))
149 (t `(op + ,(maxima-to-ir (caddr (cdddr form))) (num 1 0))))
150 ,@(cond ((eq (cadddr form) 'nil) '())
151 (t `(,(maxima-to-ir (cadddr form))))))
152 (body-indented
153 ,@(cond ((mprogn-p form)
154 (mapcar 'maxima-to-ir (cdr (clast form))))
156 `(,(maxima-to-ir (clast form))))))))))
158 (defun for-list-to-ir (form)
159 `(for-list ,(maxima-to-ir (cadr form))
160 ,(maxima-to-ir (caddr form))
161 (body-indented
162 ,@(cond ((mprogn-p form)
163 (mapcar 'maxima-to-ir (cdr (clast form))))
165 `(,(maxima-to-ir (clast form))))))))
167 (defun func-call-arg-to-ir (form)
168 (typecase form
169 (cons (cond
170 ((eq (caar form) 'mlist)
171 `(symbol ,(maybe-invert-string-case (symbol-name (stripdollar (cadr form))))))))
172 (t (maxima-to-ir form))))
174 (defun lambda-to-ir (form)
175 (let ((*symbols-directly-convert* (append (mapcar
176 (lambda (x)
177 (cond ((consp x) (cadr x))
178 (t x)))
179 (cdadr form))
180 *symbols-directly-convert*)))
181 (cond ((eql (list-length (cddr form)) 1)
182 `(lambda
183 ,(let ((func-args (mapcar #'func-arg-to-ir (cdadr form))))
184 (append func-args
185 ; initialize dictionary holding variable bindings
186 `((op-no-bracket =
187 (symbol ,*maxima-variables-dictionary-name*)
188 (funcall (symbol ,*python-hierarchial-dict-name*)
189 (dictionary)
190 (symbol ,*maxima-variables-dictionary-name*))))))
191 ,(maxima-to-ir (clast form))))
193 (let ((func_name (gensym "$LAMBDA")) (func-args (mapcar #'func-arg-to-ir (cdadr form))))
194 (setf *ir-forms-to-append*
195 (cons (func-def-to-ir
196 `((MDEFINE SIMP)
197 ((,func_name) ,@(cdadr form))
198 ((MPROGN) ,@(cddr form))))
199 *ir-forms-to-append*))
200 `(lambda
201 ,(append func-args
202 ; initialize dictionary holding variable bindings
203 `((op-no-bracket =
204 (symbol ,*maxima-variables-dictionary-name*)
205 (funcall (symbol ,*python-hierarchial-dict-name*)
206 (dictionary)
207 (symbol ,*maxima-variables-dictionary-name*)))))
208 (funcall ,(symbol-to-ir func_name)
209 ,@(mapcar #'func-call-arg-to-ir (cdadr form))
210 (funcall (symbol ,*python-hierarchial-dict-name*)
211 (dictionary)
212 (symbol ,*maxima-variables-dictionary-name*)))))))))
214 (defun conditional-auxiliary (forms)
215 `(,(maxima-to-ir (car forms))
216 ,(maxima-to-ir (cadr forms))
217 ,(cond ((eq (caddr forms) 't) (maxima-to-ir (cadddr forms)))
218 (t `(conditional ,@(conditional-auxiliary (cddr forms)))))))
220 (defun conditional-to-ir (form)
221 ;; (conditional <condition> <res1> <else-res>)
222 `(conditional ,@(conditional-auxiliary (cdr form))))
224 (defun if-to-ir (form &optional (case-if nil))
225 `(,@(cond (case-if '(body))
226 (t '()))
227 (,(cond (case-if 'cond-if)
228 (t 'cond-elif))
229 ,(maxima-to-ir (cadr form)))
230 (body-indented ,(maxima-to-ir (caddr form)))
231 ,@(cond ((eq (cadddr form) 't)
232 (cond ((or (eq (clast form) 'nil) (eq (clast form) '$false)) '())
233 ((and (consp (clast form))
234 (consp (car (clast form)))
235 (eq (caar (clast form)) 'mcond))
236 (if-to-ir (clast form)))
237 (t `((cond-else)
238 (body-indented ,(maxima-to-ir (clast form)))))))
239 (t (if-to-ir (cddr form))))))
241 (defun mcond-to-ir (form &optional (is_expr nil))
242 (cond (is_expr (conditional-to-ir form))
243 (t `(,@(if-to-ir form t)))))
245 (defun mprog-variable-names-list (form)
246 (cond ((and (consp form) (eq 'msetq (caar form))) (maxima-to-ir (cadr form)))
247 (t (maxima-to-ir form))))
249 (defun mprog-arg-list (form)
250 (cond ((and (consp form) (eq 'msetq (caar form))) (maxima-to-ir (clast form)))
251 (t `(symbol "None"))))
253 (defun mprog-assign-to-dict (form)
254 (mapcar
255 (lambda (x)
256 (cond ((consp x) `((string ,(symbol-name-to-string (cadr x)))
257 ,(maxima-to-ir (caddr x))))
258 (t `((string ,(symbol-name-to-string x))
259 (symbol "None")))))
260 (cdr form)))
262 (defun mlist-p (form)
263 (and (consp form)
264 (consp (car form))
265 (eq 'mlist (caar form))))
267 (defun first-list-mprog (form)
268 (find-if #'mlist-p (cdr form)))
270 (defun but-first-mlist (form)
271 (let ((pos (position-if #'mlist-p form)))
272 (loop for x in form
273 for y from 0
274 if (not (eq y pos)) collect x)))
276 (defun mprog-to-ir (form &key (context nil))
277 (cond ((not (null (cdr form)))
278 (cond ((eq context 'function)
279 `((obj-funcall
280 (symbol ,*maxima-variables-dictionary-name*)
281 (symbol ,*ins-method-name*)
282 (dictionary
283 ,@(mprog-assign-to-dict (first-list-mprog form))))
284 ,@(mapcar (lambda (elm) (cond ((and (consp elm)
285 (consp (car elm))
286 (eq (caar elm) 'mcond))
287 (if-to-ir elm t))
288 (t (maxima-to-ir elm))))
289 (but-first-mlist (butlast (cdr form))))
290 (funcall (symbol "return")
291 ,((lambda (elm) (cond ((and (consp elm)
292 (consp (car elm))
293 (eq (caar elm) 'mcond))
294 (mcond-to-ir elm t))
295 ((and (consp elm)
296 (consp (car elm))
297 (eq (caar elm) 'mreturn))
298 (maxima-to-ir (cadr elm)))
299 (t (maxima-to-ir elm))))
300 (clast form)))))
302 (let ((func_name (symbol-to-ir (gensym "$BLOCK"))))
303 (setf *ir-forms-to-append*
304 (cons `(func-def
305 ,func_name
306 ((symbol ,*maxima-variables-dictionary-name*))
307 (body-indented
308 (op-no-bracket =
309 (symbol ,*maxima-variables-dictionary-name*)
310 (funcall (symbol ,*python-hierarchial-dict-name*)
311 (dictionary)
312 (symbol ,*maxima-variables-dictionary-name*)))
313 (obj-funcall
314 (symbol ,*maxima-variables-dictionary-name*)
315 (symbol ,*ins-method-name*)
316 (dictionary
317 ,@(mprog-assign-to-dict (first-list-mprog form))))
318 ,@(mapcar (lambda (elm) (cond ((and (consp elm)
319 (consp (car elm))
320 (eq (caar elm) 'mcond))
321 (mcond-to-ir elm))
322 (t (maxima-to-ir elm))))
323 (but-first-mlist (butlast (cdr form))))
324 (funcall (symbol "return")
325 ,((lambda (elm) (cond ((and (consp elm)
326 (consp (car elm))
327 (eq (caar elm) 'mcond))
328 (mcond-to-ir elm t))
329 ((and (consp elm)
330 (consp (car elm))
331 (eq (caar elm) 'mreturn))
332 (maxima-to-ir (cadr elm)))
333 (t (maxima-to-ir elm))))
334 (clast form)))))
335 *ir-forms-to-append*))
336 `(funcall ,func_name (funcall (symbol ,*python-hierarchial-dict-name*)
337 (dictionary)
338 (symbol ,*maxima-variables-dictionary-name*)))))))))
340 (defun mprogn-to-ir (form &optional (func-args '()))
341 (declare (ignore func-args))
342 (let ((func_name (symbol-to-ir (gensym "$BLOCK"))))
343 (setf *ir-forms-to-append*
344 (cons `(func-def
345 ,func_name
346 ((symbol ,*maxima-variables-dictionary-name*))
347 (body-indented
348 (op-no-bracket =
349 (symbol ,*maxima-variables-dictionary-name*)
350 (funcall (symbol ,*python-hierarchial-dict-name*)
351 (dictionary)
352 (symbol ,*maxima-variables-dictionary-name*)))
353 ,@(mapcar (lambda (elm) (cond ((and (consp elm)
354 (consp (car elm))
355 (eq (caar elm) 'mcond))
356 (mcond-to-ir elm))
357 (t (maxima-to-ir elm))))
358 (but-first-mlist (butlast (cdr form))))
359 (funcall (symbol "return")
360 ,((lambda (elm) (cond ((and (consp elm)
361 (consp (car elm))
362 (eq (caar elm) 'mcond))
363 (mcond-to-ir elm t))
364 ((and (consp elm)
365 (consp (car elm))
366 (eq (caar elm) 'mreturn))
367 (maxima-to-ir (cadr elm)))
368 (t (maxima-to-ir elm))))
369 (clast form)))))
370 *ir-forms-to-append*))
371 `(funcall ,func_name (symbol ,*maxima-variables-dictionary-name*))))
373 ;;; Recursively generates IR for a multi-dimensional array and fills all cells with Null value
374 (defun array-gen-ir (dimensions)
375 (cond ((null dimensions) '(symbol "None"))
376 (t `(op * (struct-list ,(array-gen-ir (cdr dimensions))) ,(maxima-to-ir (car dimensions))))))
378 ;;; Helper function for array-def-to-ir which generates the IR for array definition
379 (defun auxillary-array-to-ir (symbol dimensions)
380 `(assign ,symbol ,(array-gen-ir dimensions)))
382 ;;; Function to generate IR for array definition using different methods, by using the auxiliary function
383 (defun array-def-to-ir (form)
384 (cond ((consp (cadr form))
385 (append '(body) (loop for symb in (cdadr form)
386 collect (auxillary-array-to-ir (maxima-to-ir symb) (cddr form)))))
387 ((not (numberp (caddr form)))
388 (auxillary-array-to-ir (maxima-to-ir (cadr form)) (cdddr form)))
390 (auxillary-array-to-ir (maxima-to-ir (cadr form)) (cddr form)))))
392 ;;; Function to convert reference to array elements to IR
393 ;;; TODO : However, for arrays that are undefined, it needs to be assigned to a hashed array(dictionary)
394 (defun array-ref-to-ir (symbol indices)
395 (cond ((null indices) (maxima-to-ir symbol))
396 (t `(element-array ,(array-ref-to-ir symbol (butlast indices))
397 ,(cond ((and (atom (clast indices))
398 (not (symbolp (clast indices))))
399 (maxima-to-ir (1- (clast indices))))
400 (t `(op + ,(maxima-to-ir (clast indices)) -1)))))))
402 ;;; Convert Function args to corresponding IR
403 ;;; Convert the optional list argument into corresponding *args form in python
404 (defun func-arg-to-ir (form)
405 (typecase form
406 (cons (cond
407 ((eq (caar form) 'mlist)
408 `(symbol ,(concatenate 'string "*" (symbol-name-to-string (cadr form)))))))
409 (t (symbol-to-ir form))))
411 ;;; Generates IR for function definition
412 (defun func-def-to-ir (form)
413 ;The name of function shouldn't be converted to dictionary element
414 (setf *symbols-directly-convert* (cons (caaadr form) *symbols-directly-convert*))
415 `(body
416 (func-def
417 ; Function name
418 ,(maxima-to-ir (caaadr form))
419 ; Function argumenets, including variable mapping dictionary
420 ,(let ((func-args (mapcar #'func-arg-to-ir (cdadr form))))
421 (append func-args
422 ;; initialize dictionary holding variable bindings
423 `((op-no-bracket =
424 (symbol ,*maxima-variables-dictionary-name*)
425 (symbol ,*maxima-variables-dictionary-name*)))))
426 (body-indented
427 (op-no-bracket =
428 (symbol ,*maxima-variables-dictionary-name*)
429 (funcall (symbol ,*python-hierarchial-dict-name*)
430 (dictionary)
431 (symbol ,*maxima-variables-dictionary-name*)))
432 ;; Map the variables in current context to the Stack
433 (obj-funcall (symbol ,*maxima-variables-dictionary-name*)
434 (symbol ,*ins-method-name*)
435 (dictionary
436 ,@(mapcar
437 (lambda (x) (typecase x
438 (cons `((string ,(symbol-name-to-string (cadr x))) (funcall (symbol "list") ,(symbol-to-ir (cadr x)))))
439 (t `((string ,(symbol-name-to-string x)) ,(symbol-to-ir x)))))
440 (cdadr form))))
441 ,@(cond ((and (consp (caddr form))
442 (consp (caaddr form))
443 (eq (car (caaddr form)) 'mprog))
444 `(,@(mprog-to-ir (caddr form) :context 'function)))
445 ((and (consp (caddr form))
446 (consp (caaddr form))
447 (eq (car (caaddr form)) 'mprogn))
448 (append (mapcar #'maxima-to-ir (butlast (cdaddr form)))
449 `((funcall (symbol "return") ,((lambda (elm) (cond ((and (consp elm)
450 (consp (car elm))
451 (eq (caar elm) 'mcond))
452 (mcond-to-ir elm t))
453 ((and (consp elm)
454 (consp (car elm))
455 (eq (caar elm) 'mreturn))
456 (maxima-to-ir (cadr elm)))
457 (t (maxima-to-ir elm))))
458 (clast (cdaddr form)))))))
460 `((funcall (symbol "return") ,((lambda (elm) (cond ((and (consp elm)
461 (consp (car elm))
462 (eq (caar elm) 'mcond))
463 (mcond-to-ir elm t))
464 ((and (consp elm)
465 (consp (car elm))
466 (eq (caar elm) 'mreturn))
467 (maxima-to-ir (cadr elm)))
468 (t (maxima-to-ir elm))))
469 (caddr form))))))))
470 (op-no-bracket =
471 ,(symbol-to-dictionary-ir (caaadr form) *maxima-function-dictionary-name*)
472 ,(symbol-to-ir (caaadr form)))))
474 ;;; Generates IR for atomic forms
475 (defun atom-to-ir (form)
476 (cond
477 ((eq form 'nil) `(symbol "None"))
478 ((eq form '$true) `(symbol "True"))
479 ((stringp form) `(string ,form))
480 ((not (symbolp form)) `(num ,form 0))
481 ((eq form '$%i) '(num 0 1)) ; iota complex number
482 ((eq form '$%pi) '(num (symbol "math.pi") 0)) ; Pi
483 ((eq form '$%e) '(num (symbol "math.e") 0)) ; Euler's Constant
484 ((eq form '$inf) '(num (symbol "math.inf") 0))
486 (cond
487 ((member form *symbols-directly-convert*) (symbol-to-ir form))
488 (t (symbol-to-dictionary-ir form))))))
490 ;;; Generates IR for non-atomic forms
491 (defun cons-to-ir (form)
492 (cond
493 ((atom (caar form))
494 (let ((type (gethash (caar form) *maxima-direct-ir-map*)))
495 (cond
496 ; If the form is present in *maxima-direct-ir-map*
497 (type
498 (append type (mapcar
499 #'maxima-to-ir
500 (cdr form))))
501 ; If the form is to be transformed in a specific way
502 ((setf type (gethash (caar form) *maxima-special-ir-map*))
503 (funcall type form))
504 ((member 'array (car form))
505 (array-ref-to-ir (caar form) (cdr form)))
507 (append `(funcall
508 ,(cond
509 ((member (caar form) *symbols-directly-convert*) (symbol-to-ir (caar form)))
510 (t `(element-array ,*maxima-function-dictionary-name* (string ,(symbol-name-to-string (caar form)))))))
511 (mapcar
512 #'maxima-to-ir
513 (cdr form)))))))))
515 ;;; Generates IR for Maxima expression
516 (defun maxima-to-ir (form &optional (is_stmt nil))
517 (let
518 ((ir (cond ((atom form)
519 (atom-to-ir form))
520 ((and (consp form) (consp (car form)))
521 (cons-to-ir form))
523 (cons 'no-convert form)))))
524 (cond (is_stmt (append '(body)
525 *ir-forms-to-append*
526 `(,ir)))
527 (t ir))))
529 ;;; Driver function for the translator, calls the function
530 ;;; maxima-to-ir and then ir-to-python
531 (defun $pytranslate (form &optional (print-ir nil))
532 (setq *ir-forms-to-append* '())
533 (setf form (nformat form))
534 (cond (print-ir (ir-to-python (print (maxima-to-ir form t))))
535 (t (ir-to-python (maxima-to-ir form t)))))
537 (defvar *ir-python-direct-templates*
538 (let ((ht (make-hash-table)))
539 (setf (gethash 'num ht) 'num-to-python)
540 (setf (gethash 'asterisk ht) 'asterisk-to-python)
541 (setf (gethash 'body ht) 'body-to-python)
542 (setf (gethash 'body-indented ht) 'body-indented-to-python)
543 (setf (gethash 'op ht) 'op-to-python)
544 (setf (gethash 'op-no-bracket ht) 'op-no-bracket-to-python)
545 (setf (gethash 'comp-op ht) 'op-to-python)
546 (setf (gethash 'boolop ht) 'op-to-python)
547 (setf (gethash 'op ht) 'op-to-python)
548 (setf (gethash 'del ht) 'del-to-python)
549 (setf (gethash 'unary-op ht) 'unary-op-to-python)
550 (setf (gethash 'symbol ht) 'symbol-to-python)
551 (setf (gethash 'assign ht) 'assign-to-python)
552 (setf (gethash 'string ht) 'string-to-python)
553 (setf (gethash 'funcall ht) 'funcall-to-python)
554 (setf (gethash 'struct-list ht) 'struct-list-to-python)
555 (setf (gethash 'func-def ht) 'func-def-to-python)
556 (setf (gethash 'element-array ht) 'element-array-to-python)
557 (setf (gethash 'conditional ht) 'conditional-to-python)
558 (setf (gethash 'cond-if ht) 'cond-if-to-python)
559 (setf (gethash 'cond-else ht) 'cond-else-to-python)
560 (setf (gethash 'cond-elif ht) 'cond-elif-to-python)
561 (setf (gethash 'lambda ht) 'lambda-to-python)
562 (setf (gethash 'for-list ht) 'for-list-to-python)
563 (setf (gethash 'while-loop ht) 'while-loop-to-python)
564 (setf (gethash 'obj-funcall ht) 'obj-funcall-to-python)
565 (setf (gethash 'dictionary ht) 'dictionary-to-python)
566 ht))
568 ;;; Generates Python source for given IR form
569 (defun ir-to-python (form &optional
570 (indentation-level 0)
571 (is_stmt nil))
572 (concatenate
573 'string
574 (cond
575 (is_stmt ; To determine if the form needs to be indented
576 (format nil "~v@{~A~:*~}" indentation-level " "))
577 (t ""))
578 (typecase form
579 (cons
580 (let ((type (gethash (car form) *ir-python-direct-templates*)))
581 (cond
582 (type (funcall type form indentation-level))
583 (t (format nil "no-covert : (~a)" form)))))
585 (format nil "~a" form)))))
587 ;;; Code below is for functions handling specefic IR forms and
588 ;;; generating the corresponding Python code.
590 (defun dictionary-to-python (form indentation-level)
591 (format nil "{~{~a~^, ~}}"
592 (mapcar (lambda (elm) (ir-to-python `(op-no-bracket #\: ,(ir-to-python (car elm))
593 ,(ir-to-python (cadr elm)))
594 indentation-level))
595 (cdr form))))
597 (defun obj-funcall-to-python (form indentation-level)
598 (format nil "~a.~a(~{~a~^, ~})"
599 (ir-to-python (cadr form))
600 (ir-to-python (caddr form))
601 (mapcar
602 (lambda (elm) (ir-to-python elm indentation-level))
603 (cdddr form))))
605 (defun while-loop-to-python (form indentation-level)
606 (format nil "while ~a:~&~a"
607 (ir-to-python (cadr form) indentation-level)
608 (ir-to-python (caddr form) indentation-level)))
610 (defun for-list-to-python (form indentation-level)
611 (format nil "for ~a in ~a:~&~a"
612 (ir-to-python (cadr form) indentation-level)
613 (ir-to-python (caddr form) indentation-level)
614 (ir-to-python (clast form) indentation-level)))
616 (defun lambda-to-python (form indentation-level)
617 (format nil "lambda ~{~a~^, ~}: ~a"
618 (mapcar
619 (lambda (elm) (ir-to-python elm indentation-level))
620 (cadr form))
621 (ir-to-python (clast form) indentation-level)))
623 (defun conditional-to-python (form indentation-level)
624 (format nil "(~a if ~a else ~a)"
625 (ir-to-python (caddr form) indentation-level)
626 (ir-to-python (cadr form) indentation-level)
627 (ir-to-python (cadddr form) indentation-level)))
629 (defun cond-if-to-python (form indentation-level)
630 (format nil "if ~a:"
631 (ir-to-python (cadr form) indentation-level)))
633 (defun cond-else-to-python (form indentation-level)
634 (declare (ignore form indentation-level))
635 (format nil "else:"))
637 (defun cond-elif-to-python (form indentation-level)
638 (format nil "elif ~a:"
639 (ir-to-python (cadr form) indentation-level)))
641 (defun element-array-to-python (form indentation-level)
642 (format nil "~a[~a]"
643 (ir-to-python (cadr form) indentation-level)
644 (ir-to-python (clast form) indentation-level)))
646 (defun func-def-to-python (form indentation-level)
647 (format nil "def ~a(~{~a~^, ~}):~&~a"
648 (ir-to-python (cadr form))
649 (mapcar
650 (lambda (elm) (ir-to-python elm indentation-level))
651 (caddr form))
652 (ir-to-python (clast form) indentation-level)))
654 (defun struct-list-to-python (form indentation-level)
655 (format nil "[~{~a~^, ~}]"
656 (mapcar
657 (lambda (elm) (ir-to-python elm indentation-level))
658 (cdr form))))
660 (defun unary-op-to-python (form indentation-level)
661 (format nil "(~a~a)"
662 (cadr form)
663 (ir-to-python (caddr form) indentation-level)))
665 (defun del-to-python (form indentation-level)
666 (declare (ignore indentation-level))
667 (format nil "del ~a"
668 (ir-to-python (cadr form))))
670 (defun funcall-to-python (form indentation-level)
671 (format nil "~a(~{~a~^, ~})"
672 (ir-to-python (cadr form))
673 (mapcar
674 (lambda (elm) (ir-to-python elm indentation-level))
675 (cddr form))))
677 (defun string-to-python (form indentation-level)
678 (declare (ignore indentation-level))
679 (format nil "~c~a~c"
681 (cadr form)
682 #\"))
684 (defun assign-to-python (form indentation-level)
685 (declare (ignore indentation-level))
686 (format nil "~a = ~a"
687 (ir-to-python (cadr form))
688 (ir-to-python (caddr form))))
690 (defun asterisk-to-python (form indentation-level)
691 (declare (ignore indentation-level))
692 (format nil "*~a"
693 (ir-to-python (cadr form))))
695 (defun symbol-to-python (form indentation-level)
696 (declare (ignore indentation-level))
697 (cadr form))
699 (defun op-no-bracket-template (op)
700 (format nil "~@?" "~~{~~#[~~;~~a~~:;~~a ~a ~~]~~}"
701 op))
703 (defun op-no-bracket-to-python (form indentation-level)
704 (format nil (op-no-bracket-template (ir-to-python (cadr form)))
705 (mapcar
706 (lambda (elm) (ir-to-python elm indentation-level))
707 (cddr form))))
709 (defun op-template (op)
710 (format nil "~@?" "(~~{~~#[~~;~~a~~:;~~a ~a ~~]~~})"
711 op))
713 (defun op-to-python (form indentation-level)
714 (format nil (op-template (ir-to-python (cadr form)))
715 (mapcar
716 (lambda (elm) (ir-to-python elm indentation-level))
717 (cddr form))))
719 ;; "~{~&~a~}" but there was a problem regarding this with indentation:
720 ;; pytranslate('(while cond do (while cond do (while cond do expr))));
721 ;; (%o2) None = None
722 ;; while not(not(cond)):
723 ;; None = None
724 ;; while not(not(cond)):
725 ;; None = None
726 ;; while not(not(cond)):
727 ;; expr
728 ;; None = (None + None)
729 ;; del None
730 ;; None = (None + None)
731 ;; del None
732 ;; None = (None + None)
733 ;; del None
734 ;; The lines None=None arent properly indented
735 ;; Hence change to ~% for new line
736 (defun body-to-python (form indentation-level)
737 (format nil "~{~%~a~}"
738 (mapcar
739 (lambda (elm) (ir-to-python elm indentation-level t))
740 (cdr form))))
742 (defun body-indented-to-python (form indentation-level)
743 (format nil "~{~&~a~}"
744 (mapcar
745 (lambda (elm) (ir-to-python elm (1+ indentation-level) t))
746 (cdr form))))
748 (defun num-to-python (form indentation-level)
749 (declare (ignore indentation-level))
750 (cond ((eql 0 (clast form)) (ir-to-python (cadr form)))
751 (t "1j")))
753 ;;; Function to display the internal Maxima form
754 (defun $show_form (form)
755 (print (nformat-check form)))