;; SYNOPSIS: loop macros ++,--,toggle,unless,when,forto,forloop,repeat.
;; AUTHOR: GPL(C) Mohsin Ahmed, http://www.cs.albany.edu/~mosh

;; (macroexpand '(++ i))     => (setq i (+ 1 i))
;; (macroexpand '(-- i))     => (setq i (- 1 i))
;; (macroexpand '(toggle i)) => (setq i (not i))

(defmacro ++     (var) (list 'setq var (list '+ 1 var)))
(defmacro --     (var) (list 'setq var (list '- 1 var)))
(defmacro toggle (var) (list 'setq var (list 'not var)))

;; TOGGLE MACRO, SYNOPSIS: toggle variable and display it too.
;; Eg. (togglevar completion-ignore-case)

;;    (macroexpand '(togglevar x))
;; => (progn (setq x (not x)) (message "%s = %s" (symbol-name x) x))
;; => (progn (setq x (not x)) (message "s = %s"              "x" x))

(defmacro togglevar (var)                             "Toggle var"
  (list 'progn                                       ; (progn
        (list 'setq var (list 'not var))             ;  (setq x (not x))
        (list 'message "%s = %s."                    ; (message
              (list 'symbol-name (list 'quote var))  ;    "x"
              var)                                   ;     x )
))                                                   ; )


(defmacro mosh-toggle-var (var)                                 "Toggle arg"
  (list 'progn                                       ; (progn
        (list 'setq var (list 'not var))             ;  (setq x (not x))
        (list 'message "%s = %s."                    ; (message
              (list 'symbol-name (list 'quote var))  ;    "x"
              var)                                   ;     x )
))                                                   ; )

;; Test the macro: (macroexpand '(mosh-toggle-var x))
;; Should give:    (progn (setq x (not x)) (message "x = %s" x))
;; Usage:          (mosh-toggle-var completion-ignore-case)

;; Now we need to toggle the default values.

(defmacro mosh-toggle-var-def (var)                  "Toggle default arg"
  (list 'progn                                       ; (progn
        (list 'setq-default var (list 'not var))     ;  (setq x (not x))
        (list 'message "def %s = %s."                ; (message
              (list 'symbol-name (list 'quote var))  ;    "def x"
              var)                                   ;     x )
))                                                   ; )




;; (macroexpand '(unless x b1 b2))
;; => (if x nil (progn b1 b2))

(defmacro unless (condition &rest body)
  (list 'if condition nil (cons 'progn body)))

;; like <if> but <when> takes a list of statements.
;; (macroexpand '(when x b1 b2))
;; => (if x (progn b1 b2))

(defmacro when (condition &rest body)
  (list 'if condition (cons 'progn body)))

;; (macroexpand '(forto var init final step body))
;; =>  (progn (setq var init)
;;           (while (< var final) body
;;              (setq var (+ var step))))
;;
;; Test and it works, inserts: ABCDEFGHIJ.
;; (forto i 65 75 1 (insert i))

(defmacro forto (var init final step body)
  (list 'progn (list 'setq var init)
        (list 'while (list '< var final) body
                (list 'setq var (list '+ var step)))))

;; (macroexpand '(forloop init docond step body))
;; =>  (progn init (while docond body step))
;;
;; Test and it works, should insert ABCDEFGHIJ.
;; (forloop (setq i 65) (< i 75) (setq i (+ 1 i)) (insert i))
;;

(defmacro forloop (init docond step body)
    (list 'progn init (list 'while docond body step)))

;; (macroexpand '(repeat body until endcond))
;; =>  (while (progn body (not endcond)))
;;
;; Test and it works, inserts ABCDEFGHIJK.
;; (setq i 65)
;; (repeat (progn (insert i) (setq i (+ 1 i))) 'until (> i 75))
;;

(defmacro repeat (body until endcond)
  (list 'while (list 'progn body (list 'not endcond))))


(provide 'loops)

;;; EOF

