;;;; iterators.lisp (defpackage #:iterators-simple (:use :cl) (:export #:with-iterator #:call-iterator #:define-iterator #:create-iterator)) (in-package #:iterators-simple) ;;; "iterators" goes here. Hacks and glory await! (defun make-numeric-iterator (function second-argument &optional (initial 1)) "Create a closure acting as a numeric iterator. This takes a FUNCTION, a SECOND-ARGUMENT to a function, and an INITIAL value for N defaulting at 1. This applies the function to N, and the SECOND-ARGUMENT, setting N to the value." (let ((n initial)) #'(lambda () (setf n (funcall function n second-argument))))) (defun make-stream-iterator (stream-or-file-name type) (let ((stream (if (stringp stream-or-file-name) (open stream-or-file-name) stream-or-file-name))) (ecase type (:line #'(lambda () (read-line stream nil nil))) (:char #'(lambda () (read-char stream nil nil))) (:byte #'(lambda () (read-byte stream nil nil)))))) (defun make-list-iterator (&rest list) (let ((list list)) #'(lambda () (if (= 0 (length list)) nil (pop list))))) (defun call-iterator (iterator) (funcall iterator)) (defun create-iterator (type &rest args) "Create an integer of type TYPE, using args ARGS." (ecase type (:numeric (make-numeric-iterator (elt args 0) (elt args 1) (if (elt args 2) (elt args 2) 1))) (:stream (make-stream-iterator (elt args 0) (elt args 1))) (:list (apply #'make-list-iterator args)))) (defmacro with-iterator ((name type &rest args) &body body) (let ((iterator-expression (ecase type (:numeric `(make-numeric-iterator ,(elt args 0) ,(elt args 1) ,(if (elt args 2) (elt args 2) 1))) (:stream `(make-stream-iterator ,(elt args 0) ,(elt args 1))) (:list `(make-list-iterator ,@args))))) `(let ((,name ,iterator-expression)) (flet ((,name () (call-iterator ,name))) ,@body)))) (defmacro define-iterator (name type &rest args) (let ((iter-expression (ecase type (:numeric `(make-numeric-iterator ,(elt args 0) ,(elt args 1) ,(if (elt args 2) (elt args 2) 1))) (:stream `(make-stream-iterator ,(elt args 0) ,(elt args 1))) (:list `(make-list-iterator ,@args))))) `(defvar ,name ,iter-expression)))