1
0
mirror of https://github.com/janet-lang/janet synced 2025-07-22 03:42:54 +00:00

Add prompt and return.

User friendly delimited continuations. While this was doable with
signals before, this does not require C and will play nicely with
existing error handling, defers, and with statements.
This commit is contained in:
Calvin Rose 2020-02-23 16:35:33 -06:00
parent 8c41c0b6a7
commit 59d288c429
3 changed files with 39 additions and 0 deletions

View File

@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file.
- Correct arity for `next` - Correct arity for `next`
- Correct arity for `marshal` - Correct arity for `marshal`
- Add `flush` and `eflush` - Add `flush` and `eflush`
- Add `prompt` and `return` on top of signal for user friendly delimited continuations.
## 1.7.0 - 2020-02-01 ## 1.7.0 - 2020-02-01
- Remove `file/fileno` and `file/fdopen`. - Remove `file/fileno` and `file/fdopen`.

View File

@ -299,6 +299,24 @@
,r ,r
(propagate ,r ,f))))) (propagate ,r ,f)))))
(defmacro prompt
"Set up a prompt point that can be aborted to. Tag should be a value
that is used in a return statement, like a keyword."
[tag & body]
(with-syms [res target payload fib]
~(do
(def ,fib (,fiber/new (fn [] [,tag (do ,;body)]) :i0))
(def ,res (,resume ,fib))
(def [,target ,payload] ,res)
(if (,= ,tag ,target)
,payload
(propagate ,res ,fib)))))
(defn return
"Return to a prompt point."
[to value]
(signal 0 [to value]))
(defmacro with (defmacro with
"Evaluate body with some resource, which will be automatically cleaned up "Evaluate body with some resource, which will be automatically cleaned up
if there is an error in body. binding is bound to the expression ctor, and if there is an error in body. binding is bound to the expression ctor, and

View File

@ -70,4 +70,24 @@
(test-bf "+[+[<<<+>>>>]+<-<-<<<+<++]<<.<++.<++..+++.<<++.<---.>>.>.+++.------.>-.>>--." (test-bf "+[+[<<<+>>>>]+<-<-<<<+<++]<<.<++.<++..+++.<<++.<---.>>.>.+++.------.>-.>>--."
"Hello, World!") "Hello, World!")
# Prompts
(assert (= 10 (prompt :a (for i 0 10 (if (= i 5) (return :a 10))))) "prompt 1")
(defn- inner-loop
[i]
(if (= i 5)
(return :a 10)))
(assert (= 10 (prompt :a (for i 0 10 (inner-loop i)))) "prompt 2")
(defn- inner-loop2
[i]
(try
(if (= i 5)
(error 10))
([err] (return :a err))))
(assert (= 10 (prompt :a (for i 0 10 (inner-loop2 i)))) "prompt 3")
(end-suite) (end-suite)