scribble-math/maxima/maxima.rkt
Jens Axel Søgaard 776ec811aa Small improvements
2012-06-20 20:07:09 +02:00

184 lines
4.6 KiB
Racket

#lang racket
;;; This is not in use at the moment.
;;; However it would be possible to implement Maxima-boxes
;;; in the GUI and use Maxima as a backend with this.
(require racket/tcp racket/gui/base)
;;;
;;; Maxima in Racket
;;;
;; This module starts an external Maxima process.
;; The function send will send a command to Maxima.
;; The function receive will get the output from Maxima as a list of strings.
;; The various send-* and receive-* functions sends and receives to and from Maxima.
;; The various read-* and display-* functions reads and displays to Racket (DrRacket).
;;; Configuration: Change maxima, latex and dvipng paths here.
(define PORT 8087)
(define MAXIMA-PATH "/Applications/Maxima.app/Contents/Resources/maxima.sh")
;(define latex-enabled? #t) ; set to #f to disable latex rendering
;(pdflatex-path "/usr/texbin/pdflatex")
;(convert-path "/opt/local/bin/convert") ; from ImageMagick
; (dvipng-path "/usr/texbin/dvipng") ; when using jaymacarthy's slideshow-latex
; (latex-debug? #f) ; if #t prints errors from LaTeX.
;;; Parameters
(define out (make-parameter #f)) ; output port for sending
(define in (make-parameter #f)) ; input port for receiving
;;; Sending
(define (send str)
(sync (out))
(display str (out))
(flush-output (out)))
(define magic-number 983298329832983298398)
(define magic-string (number->string magic-number))
(define (send-command str)
(send (string-append str ";" magic-string ";")))
(define (send-lisp-command str)
(display (string-append ":lisp #$" str "$"))
(newline)
(send (string-append ":lisp #$" str "$\n"))
(send (string-append magic-string ";")))
(define (receive-lisp)
(let ([first-value (read (in))])
(let loop ([values (list first-value)])
(let ([value (read (in))])
(if (equal? value magic-number)
(reverse values)
(loop (cons value values)))))))
;(define (maxima->scheme mexpr)
; (define h (hash 'MPLUS '+
; 'MMINUS '-
; 'MTIMES '*
; 'MEXPT 'expt))
; (define (convert-head head)
; (hash-ref head
;; Receiving
(define (receive-line)
(read-line (in)))
(define (receive-welcome-message)
; Due to the flag --very-quiet the welcome is
; a single line containg the pid.
(list (receive-line)))
(define (maybe-receive-line)
(if (sync/timeout 0 (in))
(receive-line)
#f))
(define (receive)
(let ([first-line (receive-line)])
(let loop ([lines (list first-line)])
(display lines) (newline)
(let ([line (maybe-receive-line)])
(if line
(loop (cons line lines))
(if (equal? (first lines) magic-string)
(reverse (cdr lines))
(loop lines)))))))
(define (receive-whitespace)
(let ([c (read-char (in))])
(when (not (char-whitespace? c))
(error 'read-whitespace "expected to receive whitespace " c))))
;; String utilities
(define (blank-line? line)
(andmap char-whitespace? (string->list line)))
(define (labeled-line? line)
(regexp-match #rx"^(\\(.+\\)) (.*)$" line))
(define (remove-$$ str)
(second (regexp-match #px"^\\$\\$(.*)\\$\\$" str)))
(define (string-begins-with-$$? str)
(regexp-match #rx"^\\$\\$.*$" str))
(define (string-ends-with-$$? str)
(regexp-match #rx"^.*\\$\\$$" str))
(define (maybe-add-$$ str)
(string-append
(if (string-begins-with-$$? str)
"" "$$")
str
(if (string-ends-with-$$? str)
"" "$$")))
(define (string-ref-last str)
(if (string=? "" str)
#f
(string-ref str (sub1 (string-length str)))))
;; List utilies
(define (remove-last xs)
(if (empty? xs) xs (drop-right xs 1)))
;; Displaying
(define (display-line datum)
(display datum)
(newline))
(define (display-prompt prompt)
(display prompt)
(display " "))
;; Reading
(define (read-command)
(let loop ([lines '()])
(let ([line (read-line)])
(if (memv (string-ref-last line) '(#\$ #\;))
(string-append* (reverse (cons line lines)))
(loop (cons line lines))))))
;; REPL
#;(define (read-send-receive-loop)
(display-prompt ">")
(send-command (read-command))
(display-output (receive))
(newline)
(read-send-receive-loop))
;; Start Maxima and REPL
(let ([listener (tcp-listen PORT 3 #t)])
(match-let
([(list pin pout pid perr status)
(process* MAXIMA-PATH "--very-quiet" "-s" (format "~a" PORT))])
(let-values ([(lin lout) (tcp-accept listener)])
(in lin)
(out pout)
(receive-welcome-message)
(display "Enter a Maxima command. Terminate a command with either ; or $ .\n")
(send-command "display2d:false")
(receive))))