summary refs log tree commit diff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2020-03-15 14:27:09 +0100
committerLudovic Courtès <ludo@gnu.org>2020-03-19 15:14:08 +0100
commitf06a26f5b594b1d1865a41facca0ea65a3837901 (patch)
treef6d0f1391b5769a6188efe75a93e6f4a450a3d42
parentac75bd010260f6a722e1723b35992b04fd79d44c (diff)
downloadguix-f06a26f5b594b1d1865a41facca0ea65a3837901.tar.gz
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.
-rw-r--r--guix/repl.scm34
1 files changed, 24 insertions, 10 deletions
diff --git a/guix/repl.scm b/guix/repl.scm
index 0f75f9cd0b..a141003812 100644
--- a/guix/repl.scm
+++ b/guix/repl.scm
@@ -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)))))