diff options
Diffstat (limited to 'macros')
| -rw-r--r-- | macros/core.fnl | 95 |
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 |