hy/hy/contrib/sequences.hy
2016-12-07 16:32:37 -08:00

80 lines
3.6 KiB
Hy

;; Copyright (c) 2016 Tuukka Turto <tuukka.turto@oktaeder.net>
;;
;; Permission is hereby granted, free of charge, to any person obtaining a
;; copy of this software and associated documentation files (the "Software"),
;; to deal in the Software without restriction, including without limitation
;; the rights to use, copy, modify, merge, publish, distribute, sublicense,
;; and/or sell copies of the Software, and to permit persons to whom the
;; Software is furnished to do so, subject to the following conditions:
;;
;; The above copyright notice and this permission notice shall be included in
;; all copies or substantial portions of the Software.
;;
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;; DEALINGS IN THE SOFTWARE.
;;
(defclass Sequence []
[--init-- (fn [self func]
"initialize a new sequence with a function to compute values"
(setv (. self func) func)
(setv (. self cache) [])
(setv (. self high-water) -1))
--getitem-- (fn [self n]
"get nth item of sequence"
(if (hasattr n "start")
(genexpr (get self x) [x (range n.start n.stop
(or n.step 1))])
(do (when (neg? n)
; Call (len) to force the whole
; sequence to be evaluated.
(len self))
(if (<= n (. self high-water))
(get (. self cache) n)
(do (while (< (. self high-water) n)
(setv (. self high-water) (inc (. self high-water)))
(.append (. self cache) (.func self (. self high-water))))
(get self n))))))
--iter-- (fn [self]
"create iterator for this sequence"
(setv index 0)
(try (while True
(yield (get self index))
(setv index (inc index)))
(except [_ IndexError]
(raise StopIteration))))
--len-- (fn [self]
"length of the sequence, dangerous for infinite sequences"
(setv index (. self high-water))
(try (while True
(get self index)
(setv index (inc index)))
(except [_ IndexError]
(len (. self cache)))))
max-items-in-repr 10
--str-- (fn [self]
"string representation of this sequence"
(setv items (list (take (inc self.max-items-in-repr) self)))
(.format (if (> (len items) self.max-items-in-repr)
"[{0}, ...]"
"[{0}]")
(.join ", " (map str items))))
--repr-- (fn [self]
"string representation of this sequence"
(.--str-- self))])
(defmacro seq [param &rest seq-code]
`(Sequence (fn ~param (do ~@seq-code))))
(defmacro defseq [seq-name param &rest seq-code]
`(def ~seq-name (Sequence (fn ~param (do ~@seq-code)))))
(defn end-sequence []
"raise IndexError exception to signal end of sequence"
(raise (IndexError "list index out of range")))