From 6ceaf9d28df8567c7c1d3c61bb499bd4209b54bf Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Thu, 31 Oct 2019 21:58:43 -0500 Subject: [PATCH] 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). --- CHANGELOG.md | 1 + src/boot/boot.janet | 21 ++++++++++++++++++++- test/suite7.janet | 6 ++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03c8cb2b..afc08f82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/src/boot/boot.janet b/src/boot/boot.janet index fbb0eea5..8c3ba8cc 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -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)) diff --git a/test/suite7.janet b/test/suite7.janet index 5a784aa2..8d3a6584 100644 --- a/test/suite7.janet +++ b/test/suite7.janet @@ -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)