From e9f3dc7d5c51f14cc2fc330efe606d9afc4e6ce9 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Thu, 3 Oct 2019 20:20:42 -0500 Subject: [PATCH] Add varfn. --- CHANGELOG.md | 1 + src/boot/boot.janet | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1611b936..5c1eda42 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 `varfn` macro - Add compile time arity checking when function in function call is known. - Added `slice` to the core library. - The `*/slice` family of functions now can take nil as start or end to get diff --git a/src/boot/boot.janet b/src/boot/boot.janet index dad41f80..256f1b61 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -1538,6 +1538,30 @@ (set current (macex1 current on-binding))) current) +(defmacro varfn + "Create a function that can be rebound. varfn has the same signature + as defn, but defines functions in the environment as vars. If a var 'name' + already exists in the environment, it is rebound to the new function. Returns + a function." + [name & body] + (def expansion (apply defn name body)) + (def fbody (last expansion)) + (def modifiers (tuple/slice expansion 2 -2)) + (def metadata @{}) + (each m modifiers + (cond + (keyword? m) (put metadata m true) + (string? m) (put metadata :doc m) + (error (string "invalid metadata " m)))) + (with-syms [entry old-entry f] + ~(let [,old-entry (,dyn ',name)] + (def ,entry (or ,old-entry @{:ref @[nil]})) + (,setdyn ',name ,entry) + (def ,f ,fbody) + (,put-in ,entry [:ref 0] ,f) + (,merge-into ,entry ',metadata) + ,f))) + ### ### ### Function shorthand