repl: Allow clients to send their protocol version.

* guix/repl.scm (send-repl-response): Add #:version.
(machine-repl): Make 'loop' an internal define with a
'version' parameter.  Pass VERSION to 'send-repl-response'.
Send (0 1) as the protocol version.
If the first element read from INPUT matches (() repl-version _ ...),
interpret it as the client's protocol version.
This commit is contained in:
Ludovic Courtès 2020-03-15 14:27:09 +01:00
parent ac75bd0102
commit f06a26f5b5
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5

@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2018, 2019 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@ -39,9 +39,10 @@
(one-of symbol? string? keyword? pair? null? array?
number? boolean? char?)))
(define (send-repl-response exp output)
(define* (send-repl-response exp output
#:key (version '(0 0)))
"Write the response corresponding to the evaluation of EXP to PORT, an
output port."
output port. VERSION is the client's protocol version we are targeting."
(define (value->sexp value)
(if (self-quoting? value)
`(value ,value)
@ -72,13 +73,26 @@ The protocol of this REPL is meant to be machine-readable and provides proper
support to represent multiple-value returns, exceptions, objects that lack a
read syntax, and so on. As such it is more convenient and robust than parsing
Guile's REPL prompt."
(write `(repl-version 0 0) output)
(define (loop exp version)
(match exp
((? eof-object?) #t)
(exp
(send-repl-response exp output
#:version version)
(loop (read input) version))))
(write `(repl-version 0 1) output)
(newline output)
(force-output output)
(let loop ()
(match (read input)
((? eof-object?) #t)
(exp
(send-repl-response exp output)
(loop)))))
;; In protocol version (0 0), clients would not send their supported
;; protocol version. Thus, the code below checks for two case: (1) a (0 0)
;; client that directly sends an expression to evaluate, and (2) a more
;; recent client that sends (() repl-version ...). This form is chosen to
;; be unambiguously distinguishable from a regular Scheme expression.
(match (read input)
((() 'repl-version version ...)
(loop (read input) version))
(exp
(loop exp '(0 0)))))