forge:repl: allow list input over multiple lines, using handler-bind and restart-case in string-iterator

This commit is contained in:
Helmut Merz 2026-02-06 14:26:24 +01:00
parent 685df331b0
commit 3c3e9b15d7
2 changed files with 20 additions and 11 deletions

View file

@ -85,7 +85,11 @@
(defun repl ()
(do ((input (read-line) (read-line)))
((string= input "q") (stack *forge-env*))
(exec-string input)))
(handler-bind
((end-of-file
(lambda (c)
(invoke-restart 'iter:try-with-more-input (read-line)))))
(exec-string input))))
(defun exec-list (lst)
(let ((*input* (iter:list-iterator lst)))

View file

@ -6,7 +6,8 @@
(defpackage :scopes/util/iter
(:use :common-lisp)
(:export #:stop #:next #:value #:next-value #:process
#:list-iterator #:string-iterator #:stream-iterator))
#:list-iterator #:string-iterator #:stream-iterator
#:try-with-more-input))
(in-package :scopes/util/iter)
@ -56,7 +57,7 @@
;;;; string iterator implementation
(defclass string-iterator (iterator)
((data :reader data :initarg :data :initform "")
((data :accessor data :initarg :data :initform "")
(curpos :accessor curpos :initform 0)
(value :accessor value :initform nil)))
@ -64,14 +65,18 @@
(make-instance 'string-iterator :data s))
(defmethod next ((it string-iterator))
(let ((pos (curpos it)))
(if (< pos (length (data it)))
(multiple-value-bind (val newpos)
(read-from-string (data it) nil nil :start pos)
(setf (curpos it) newpos
(value it) val)
nil)
t)))
(restart-case
(let ((pos (curpos it)))
(if (< pos (length (data it)))
(multiple-value-bind (val newpos)
(read-from-string (data it) nil nil :start pos)
(setf (curpos it) newpos
(value it) val)
nil)
t))
(try-with-more-input (more)
(setf (data it) (str:join " " (list (data it) more)))
(next it))))
;;;; stream iterator implementation