summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.org31
-rw-r--r--core.fnl13
-rw-r--r--macros/core.fnl50
3 files changed, 69 insertions, 25 deletions
diff --git a/README.org b/README.org
index dd83930..c17a02e 100644
--- a/README.org
+++ b/README.org
@@ -95,13 +95,30 @@ Much like =if-let= and =when-let=, except tests expression for =nil=.
val)
#+end_src
+*** =into=
+Clojure's =into= function implemented as macro, because Fennel has no runtime distinction between =[]= and ={}= tables, since Lua also doesn't feature this feature.
+However we can do this at compile time.
+
+#+begin_src fennel
+ (into [1 2 3] [4 5 6])
+ ;; [1 2 3 4 5 6]
+
+ (into [] {:a 1 :b 2 :c 3 :d 4})
+ ;; [["a" 1] ["b" 2] ["c" 3] ["d" 4]]
+
+ (into {} [[:a 1] [:b 2] [:c 3] [:d 4]])
+ ;; {:a 1 :b 2 :c 3 :d 4}
+
+ (into {:a 0 :e 5} {:a 1 :b 2 :c 3 :d 4})
+ ;; {:a 1 :b 2 :c 3 :d 4 :e 5}
+#+end_src
** Functions
Here are some important functions from the library.
Full set can be examined by requiring the module.
-*** =seq= and =into=
+*** =seq=
=seq= produces a sequential table from any kind of table in linear time.
-Works mostly like in Clojure, but, since Fennel doesn't have list object, it always returns squential tables:
+Works mostly like in Clojure, but, since Fennel doesn't have list object, it always returns sequential tables:
#+begin_src fennel
(seq [1 2 3 4 5])
@@ -111,15 +128,7 @@ Works mostly like in Clojure, but, since Fennel doesn't have list object, it alw
;; [["a" 1] ["b" 2] ["c" 3] ["d" 4]]
#+end_src
-=into= can be used to convert =seq= result back to it's original form.
-Unlike clojure, =into= accepts either =:vec= or =:map= keywords:
-
-#+begin_src fennel
- (into :map (into :vec {:a :b :c :d}))
- ;; {:a "b" :c "d"}
-#+end_src
-
-=into= uses =seq= inernally.
+See [[*=into=][=into=]] on how to transform such sequence back into associative table.
*** =first= and =rest=
=first= returns first value of a table.
diff --git a/core.fnl b/core.fnl
index e1f3ae0..4890554 100644
--- a/core.fnl
+++ b/core.fnl
@@ -16,18 +16,6 @@ sequential table, leaves it unchanged."
(insert res [k v]))
(if assoc? res tbl)))
-(fn unseq [tbl]
- (local res {})
- (each [_ [k v] (ipairs tbl)]
- (tset res k v))
- res)
-
-(fn into [to from]
- (match to
- :vec (seq from)
- :map (unseq from)
- _ (error "unsupported table type" 2)))
-
(fn first [itbl]
"Return first element of an indexed table."
(. (seq itbl) 1))
@@ -221,7 +209,6 @@ sorting tables first."
))
{: seq
- : into
: mapv
: mapkv
: reduce
diff --git a/macros/core.fnl b/macros/core.fnl
index e88d575..7c8af40 100644
--- a/macros/core.fnl
+++ b/macros/core.fnl
@@ -1,5 +1,6 @@
(import-macros {: fn*} :macros.fn)
(local _unpack (or table.unpack unpack))
+(local insert table.insert)
(fn check-bindings [bindings]
(assert-compile (sequence? bindings) "expected binding table
@@ -50,7 +51,54 @@
(let [,form tmp#]
,(_unpack body))))))
+
+;; based on `seq' from `core.fnl'
+(fn into [to from]
+ (if (sequence? to)
+ `(let [to# ,to
+ from# ,from
+ insert# table.insert
+ unpack# (or table.unpack unpack)
+ res# []]
+ (var assoc# false)
+ (each [k# v# (pairs from#)]
+ (if (and (not assoc#)
+ (not (= (type k#) "number")))
+ (set assoc# true))
+ (insert# res# [k# v#]))
+ (let [res# (if assoc# res# from#)]
+ (if (~= (next to#) nil)
+ (do (when (~= (next res#) nil)
+ (each [_# v# (ipairs res#)]
+ (insert# to# v#)))
+ to#)
+ res#)))
+ ;; to support (into {} {}) we first need transform `from' into a
+ ;; sequential table. Unfortunately it seems impossible to do
+ ;; this with `(into [] ,from)' call, as it results in infinity
+ ;; compilation loop. Because of that the body of previous
+ ;; branch is repeated here almost entirely, although without
+ ;; some extra checks, as these aren't necessary in this case.
+ (table? to)
+ `(let [to# ,to
+ from# (let [from# ,from
+ insert# table.insert
+ unpack# (or table.unpack unpack)
+ res# []]
+ (var assoc# false)
+ (each [k# v# (pairs from#)]
+ (if (and (not assoc#)
+ (not (= (type k#) "number")))
+ (set assoc# true))
+ (insert# res# [k# v#]))
+ (if assoc# res# from#))]
+ (each [_# [k# v#] (ipairs from#)]
+ (tset to# k# v#))
+ to#)
+ `(error "expected table as the first argument" 2)))
+
{: if-let
: when-let
: if-some
- : when-some}
+ : when-some
+ : into}