orthecreedence / cl-async

Asynchronous IO library for Common Lisp.
MIT License
273 stars 40 forks source link

Implementing a "pause" #79

Closed chrisk414 closed 11 years ago

chrisk414 commented 11 years ago

Hi. I'm seeking little advice how to implement "pause". Controlling "delay" is not easy and I decide to subdivide "delay" into small steps and check to see if play-mode has changed in-between each step. Here is the code.

(defconstant +tick+ 0.001)

;; either :play, :pause, or :step
(defvar *play-mode* :play)

(defun incremental-delay (time elapsed-time body)
  (case *play-mode*
    (:play
     (if (> elapsed-time time)
     (eval body)
     (as:delay 
      (lambda ()
        (incremental-delay time (+ elapsed-time +tick+) body))
      :time +tick+
       )))
    (:pause 
     (as:delay 
      (lambda ()
    (incremental-delay time elapsed-time body))
      :time +tick+
      ))
    (:step 
     ;; execute single tick and pause
     (setq *play-mode* :pause)
     (if (> elapsed-time time)
     (eval body)
     (as:delay 
      (lambda ()
        (incremental-delay time (+ elapsed-time +tick+) body))
      :time +tick+
       )))))

(defmacro with-wait (time &body body)
  `(incremental-delay ,time 0 '(progn ,@body)))

(defun test ()
  (as:start-event-loop
   (lambda ()
     (loop for j from 1 to 2
    do
      (with-wait j (print j)))))
  (print "finished")
  )  

The idea is to call "incremental-delay" at every "tick" until given time. In-between ticks, I check to see if "play-mode" has changed and decide whether to advance the tick or not.

However I have problem passing "body" of form (that need be executed at given time) with lexical binding. My code will error because variable "j" is not bound when "body" execute. I there a way to achieve this?

Thanks a lot!

chrisk414 commented 11 years ago

Oh, I forgot about "lambda" and it created a closure for me. ^^

(defmacro with-wait (time &body body)
  `(incremental-delay ,time 0 (lambda () ,@body)))