1;;>| Read–Eval–Print Loop2;;>3;;> REPL abstraction which provides a read-eval-print loop that4;;> continously reads data from standard input and parses this5;;> input data using provided parser combinators. The REPL6;;> operates on a [parse stream](#section-parse-streams) internally.78;;> Create an new REPL instance with the given input `prompt` string.910(define (make-repl prompt)11 (let ((prompt? (not (empty-string? prompt))))12 (%make-repl13 (if prompt? prompt "*")14 prompt?15 (make-parse-stream "stdin" fileno/stdin)16 0)))1718(define (repl-state-set! repl source index)19 (repl-stream-set! repl source)20 (repl-index-set! repl index))2122;;> Record type representing the REPL.23(define-record-type Read-Eval-Print-Loop24 (%make-repl prompt-str prompt? stream index)25 ;;> Predicate which returns true if the given object was created using [make-repl](#make-repl).26 repl?27 ;; Prompt string used for input prompt.28 (prompt-str repl-prompt-str)29 ;; Whether the prompt should be shown or hidden.30 (prompt?31 ;;> Predicate which returns true if the prompt should be shown.32 repl-prompt?3334 ;;> Change prompt visibility, a truth value means the prompt is shown.35 repl-set-prompt!)36 ;; Parse stream used for the parser combinator.37 (stream repl-stream repl-stream-set!)38 ;; Last index in parse stream.39 (index repl-index repl-index-set!))4041;; Skip all buffered chunks, i.e. next read will block.4243(define (repl-skip-chunks! repl)44 (define (%repl-skip-chunks! source i)45 (if (>= (+ i 1) (vector-length (parse-stream-buffer source)))46 (%repl-skip-chunks! (parse-stream-tail source) i) ;; go to last chunck47 (values48 source49 ;; inc to go beyond last char.50 (inc (parse-stream-max-char source)))))5152 (let-values (((source i)53 (%repl-skip-chunks!54 (repl-stream repl)55 (repl-index repl))))56 (repl-state-set! repl source i)))5758(define (repl-parse repl f sk fk)59 (define (stream-next-line source idx)60 (let* ((next-index (parse-stream-next-index source idx))61 (next-source (parse-stream-next-source source idx))62 (char (parse-stream-ref source idx)))63 (if (or (eof-object? char) (char=? char #\newline))64 (cons next-source next-index) ;; first index after newline/eof65 (stream-next-line66 next-source67 next-index))))6869 (call-with-parse f70 (repl-stream repl)71 (repl-index repl)72 (lambda (r s i fk)73 (repl-state-set! repl s i)74 (sk (repl-line repl i) r))75 (lambda (s i reason)76 (let ((line (repl-line repl i))77 (next (stream-next-line (repl-stream repl) i)))78 (repl-state-set! repl (car next) (cdr next))79 (fk line reason)))))8081(define (repl-line repl index)82 (let ((s (repl-stream repl)))83 (inc ;; XXX: For some reason line start at zero.84 (+85 (parse-stream-line s)86 (car (parse-stream-count-lines s (parse-stream-max-char s)))))))8788;;> Start the REPL given by `repl`, and continuously parse input using89;;> the provided parser `f`. Successfully parsed input is passed to90;;> the success continuation `sk`, which receives the line number and91;;> parser result as procedure arguments. If the parser failed for the92;;> current input, the failure continuation `fk` is invoked. This93;;> continuation receives the line number and failure reason as94;;> procedure arguments. Lastly, an interrupt continuation must95;;> also be provided which is invoked on `SIGINT`. This continuation96;;> is not passed any arguments.9798(define (repl-run repl f sk fk ik)99 (when (repl-prompt? repl)100 (display (repl-prompt-str repl))101 (flush-output-port))102103 ;; Allow parsing itself (especially of input mode commands) to be104 ;; interrupted by SIGINT signals. See "Asynchronous Events" in ed(1).105 (call-with-current-continuation106 (lambda (k)107 (set-signal-handler!108 signal/int109 (lambda (signum)110 (ik)111 (repl-skip-chunks! repl)112 (k #f)))113114 (begin115 (repl-parse repl f sk fk)116 (k #f))))117118 (repl-run repl f sk fk ik))119120;;> Run a parser interactively within the REPL. That is, deviate from121;;> the standard REPL parser and instead parse the next input line122;;> with the given parser `f`. On success, returns the result of `f`123;;> otherwise, invokes the provided failure continuation `fk`.124125(define (repl-interactive repl f fk)126 (repl-parse repl f (lambda (line value) value) fk))