summaryrefslogtreecommitdiff
path: root/macros/core.fnl
diff options
context:
space:
mode:
authorAndrey Orst <andreyorst@gmail.com>2020-10-28 22:33:34 +0300
committerAndrey Orst <andreyorst@gmail.com>2020-10-28 22:33:34 +0300
commitb808962fa90cb7dc9c4ac150777f5edcd660145b (patch)
tree908a8f23368100e9cfa29f3237829e0c006190d1 /macros/core.fnl
parente164175811974e89588c174d8597f1971cb368bf (diff)
fix(macros): make into branch at compile time for known table types
Diffstat (limited to 'macros/core.fnl')
-rw-r--r--macros/core.fnl129
1 files changed, 80 insertions, 49 deletions
diff --git a/macros/core.fnl b/macros/core.fnl
index c954f77..be0c1bb 100644
--- a/macros/core.fnl
+++ b/macros/core.fnl
@@ -56,55 +56,86 @@
(table? tbl) :table
:else))
-;; based on `seq' from `core.fnl'
+(fn -table-type-fn []
+ `(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))))
+
+(fn -seq-fn []
+ `(fn [tbl#]
+ (var assoc# false)
+ (let [res# []
+ insert# table.insert]
+ (each [k# v# (pairs tbl#)]
+ (if (and (not assoc#)
+ (not (= (type k#) :number)))
+ (set assoc# true))
+ (insert# res# [k# v#]))
+ (if assoc# res# tbl#))))
+
(fn& core.into [to from]
- (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#))
+ (let [to-type (-table-type to)
+ from-type (-table-type from)]
+ (if (and (= to-type :seq) (= from-type :seq))
+ `(let [to# ,to
+ insert# table.insert]
+ (each [_# v# (ipairs ,from)]
+ (insert# to# v#))
+ to#)
+ (= to-type :seq)
+ `(let [to# ,to
+ seq# ,(-seq-fn)
+ insert# table.insert]
+ (each [_# v# (ipairs (seq# ,from))]
+ (insert# to# v#))
+ to#)
+ (and (= to-type :table) (= from-type :seq))
+ `(let [to# ,to]
+ (each [_# [k# v#] (ipairs ,from)]
+ (tset to# k# v#))
+ to#)
+ (and (= to-type :table) (= from-type :table))
+ `(let [to# ,to
+ from# ,from]
+ (each [k# v# (pairs from#)]
+ (tset to# k# v#))
+ to#)
+ (= to-type :table)
+ `(let [to# ,to
+ from# ,from]
+ (match (,(-table-type-fn) from#)
+ :seq (each [_# [k# v#] (ipairs from#)]
+ (tset to# k# v#))
+ :table (each [k# v# (pairs from#)]
+ (tset to# k# v#))
+ :else (error "expected table as second argument"))
+ to#)
+ `(let [to# ,to
+ from# ,from
+ insert# table.insert
+ table-type# ,(-table-type-fn)
+ seq# ,(-seq-fn)]
+ (match (table-type# to#)
+ :seq (each [_# v# (ipairs (seq# from#))]
+ (insert# to# v#))
+ :table (match (table-type# from#)
+ :seq (each [_# [k# v#] (ipairs from#)]
+ (tset to# k# v#))
+ :table (each [k# v# (pairs from#)]
+ (tset to# k# v#))
+ :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 (each [_# v# (ipairs (seq# from#))]
+ (insert# to# v#))
+ :else (error "expected table as first argument"))
+ to#))))
core