summaryrefslogtreecommitdiff
path: root/macros
diff options
context:
space:
mode:
authorAndrey Orst <andreyorst@gmail.com>2020-10-23 22:18:07 +0300
committerAndrey Orst <andreyorst@gmail.com>2020-10-23 22:18:07 +0300
commite7bae75ddfb676cc4c0ee22a9339a9a79c837c4a (patch)
tree416721b8a3a8d4e7510f3a8c3cbceb89dda4a055 /macros
parente16763df4de9e198adf48d746407d43fa5538221 (diff)
Changes
- add runtime check to into - add sort of a test framework - remove mapkv in favor of generalized mapv that works both for sequences and tables - add more tests - update doc
Diffstat (limited to 'macros')
-rw-r--r--macros/core.fnl95
1 files changed, 53 insertions, 42 deletions
diff --git a/macros/core.fnl b/macros/core.fnl
index deb363a..9b01b70 100644
--- a/macros/core.fnl
+++ b/macros/core.fnl
@@ -50,50 +50,61 @@
,(_unpack body))))))
+(fn table-type [tbl]
+ (if (sequence? tbl) :seq
+ (table? tbl) :table
+ :else))
+
;; 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)))
+ (local to-type (table-type to))
+ (local from-type (table-type from))
+ `(let [to# ,to
+ from# ,from
+ insert# table.insert
+ table-type# (fn [tbl#]
+ (let [t# (type tbl#)]
+ (if (= t# :table)
+ (let [(k# _#) (next tbl#)]
+ (if (and (= (type k#) :number) (= k# 1)) :seq
+ (= k# nil) :empty
+ :table))
+ :else)))
+ seq# (fn [tbl#]
+ (var assoc# false)
+ (let [res# []]
+ (each [k# v# (pairs tbl#)]
+ (if (and (not assoc#)
+ (not (= (type k#) :number)))
+ (set assoc# true))
+ (insert# res# [k# v#]))
+ (if assoc# res# tbl#)))
+ to-type# ,to-type
+ to-type# (if (= to-type# :else)
+ (table-type# to#)
+ to-type#)
+ from-type# ,from-type
+ from-type# (if (= from-type# :else)
+ (table-type# from#)
+ from-type#)]
+ (match to-type#
+ :seq (do (each [_# v# (ipairs (seq# from#))]
+ (insert# to# v#)))
+ :table (match from-type#
+ :seq (each [_# [k# v#] (ipairs from#)]
+ (tset to# k# v#))
+ :table (each [k# v# (pairs from#)]
+ (tset to# k# v#))
+ :empty to#
+ :else (error "expected table as second argument"))
+ ;; If we could not deduce type, it means that
+ ;; we've got empty table. We use will default
+ ;; to sequential table, because it will never
+ ;; break when converting into
+ :empty (do (each [_# v# (ipairs (seq# from#))]
+ (insert# to# v#)))
+ :else (error "expected table as first argument"))
+ to#))
{: if-let
: when-let