184 lines
4.6 KiB
Racket
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))))
|
|
|
|
|
|
|