1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-28 11:09:54 +00:00

Add with-vars

This helps for temporarily setting vars in a safe
manner that is guaranteed not to leave vars in a bad state
(assuming that a fiber does not emit debug or use signal and
 is never resumed).
This commit is contained in:
Calvin Rose 2019-10-31 21:58:43 -05:00
parent 25a9804d91
commit 6ceaf9d28d
3 changed files with 27 additions and 1 deletions

View File

@ -2,6 +2,7 @@
All notable changes to this project will be documented in this file.
## Unreleased
- Add `with-vars` macro.
- Add the `quickbin` command to jpm.
- Create shell.c when making the amlagamated source. This can be compiled with
janet.c to make the janet interpreter.

View File

@ -909,6 +909,25 @@
~(setdyn ,(bindings i) ,(bindings (+ i 1)))))
~(,resume (,fiber/new (fn [] ,;dyn-forms ,;body) :p)))
(defmacro with-vars
"Evaluates body with each var in vars temporarily bound. Similar signature to
let, but each binding must be a var."
[vars & body]
(def len (length vars))
(unless (even? len) (error "expected even number of argument to vars"))
(def temp (seq [i :range [0 len 2]] (gensym)))
(def saveold (seq [i :range [0 len 2]] ['def (temp (/ i 2)) (vars i)]))
(def setnew (seq [i :range [0 len 2]] ['set (vars i) (vars (+ i 1))]))
(def restoreold (seq [i :range [0 len 2]] ['set (vars i) (temp (/ i 2))]))
(with-syms [ret f s]
~(do
,;saveold
(def ,f (,fiber/new (fn [] ,;setnew ,;body) :ei))
(def ,ret (,resume ,f))
,;restoreold
(if (= (,fiber/status ,f) :error) (,propagate ,ret ,f))
,ret)))
(defn partial
"Partial function application."
[f & more]
@ -928,7 +947,7 @@
"Reverses the order of the elements in a given array or tuple and returns a new array."
[t]
(def len (length t))
(var n (dec len))
(var n (- len 1))
(def reversed (array/new len))
(while (>= n 0)
(array/push reversed (get t n))

View File

@ -184,4 +184,10 @@
(assert (= (string '()) (string [])) "empty bracket tuple literal")
# with-vars
(var abc 123)
(assert (= 356 (with-vars [abc 456] (- abc 100))) "with-vars 1")
(assert-error "with-vars 2" (with-vars [abc 456] (error :oops)))
(assert (= abc 123) "with-vars 3")
(end-suite)