+;; Copyright (C) 2015 Christopher Allan Webber <cwebber@dustycloud.org>
+
+;; This library is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public
+;; License as published by the Free Software Foundation; either
+;; version 3 of the License, or (at your option) any later version.
+;;
+;; This library is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; Lesser General Public License for more details.
+;;
+;; You should have received a copy of the GNU Lesser General Public
+;; License along with this library; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301 USA
+
(define-module (eightsync agenda)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
schedule-segments-split schedule-extract-until!
add-segments-contents-to-queue!
- %sync 8sync %sync-at 8sync-at %sync-delay 8sync-delay
+ %sync 8sync
<run-request>
make-run-request run-request?
run-request-proc run-request-when
<port-request>
- make-port-request port-request?
+ make-port-request port-request port-request?
port-request-port
port-request-read port-request-write port-request-except
run-it wrap run run-at run-delay
+ %port-request %run %run-at %run-delay
+ 8port-request 8run 8run-at 8run-delay
+
%current-agenda
start-agenda agenda-run-once))
(throw 'no-port-handler-given "No port handler given.\n"))
(make-port-request-intern port read write except))
+(define port-request make-port-request)
+
\f
;;; Asynchronous escape to run things
(make-future call-first on-success on-fail on-error)
when))
-(define-syntax-rule (%sync body args ...)
+(define-syntax-rule (%sync async-request)
"Run BODY asynchronously at a prompt, passing args to make-future.
Pronounced `eight-sync' despite the spelling.
name! (That, and the pun 'eight-synchronous' programming.)
There are 8sync aliases if you prefer that name."
(abort-to-prompt (current-agenda-prompt)
- (wrap body)
- args ...))
-
-(define-syntax-rule (%sync-at body when args ...)
- (abort-to-prompt (current-agenda-prompt)
- (wrap body)
- #:when when
- args ...))
-
-(define-syntax-rule (%sync-delay body delay-time args ...)
- (abort-to-prompt (current-agenda-prompt)
- (wrap body)
- #:when (tdelta delay-time)
- args ...))
+ async-request))
(define-syntax-rule (8sync args ...)
"Alias for %sync"
(%sync args ...))
-(define-syntax-rule (8sync-at args ...)
- "Alias for %sync-at"
- (%sync-at args ...))
-
-(define-syntax-rule (8sync-delay args ...)
- "Alias for %sync-delay"
- (8sync-delay args ...))
+;; Async port request and run-request meta-requests
+(define (make-async-request proc)
+ "Wrap PROC in an async-request
+
+The purpose of this is to make sure that users don't accidentally
+return the wrong thing via (8sync) and trip themselves up."
+ (cons '*async-request* proc))
+
+(define (setup-async-request resume-kont async-request)
+ "Complete an async request for agenda-run-once's continuation handling"
+ (match async-request
+ (('*async-request* . async-setup-proc)
+ (async-setup-proc resume-kont))
+ ;; TODO: deliver more helpful errors depending on what the user
+ ;; returned
+ (_ (throw 'invalid-async-request
+ "Invalid request passed back via an (%sync) procedure."
+ async-request))))
+
+(define-syntax-rule (%run body ...)
+ (%run-at body ... #f))
+
+(define-syntax-rule (%run-at body ... when)
+ (make-async-request
+ (lambda (kont)
+ (make-run-request
+ (wrap
+ (kont
+ (begin body ...)))
+ when))))
+
+(define-syntax-rule (%run-delay body ... delay-time)
+ (%run-at body ... (tdelta delay-time)))
+
+(define-syntax-rule (%port-request add-this-port port-request-args ...)
+ (make-async-request
+ (lambda (kont)
+ (list (make-port-request port-request-args ...)
+ (make-run-request kont)))))
+
+;; TODO
+(define-syntax-rule (%run-with-return return body ...)
+ (make-async-request
+ (lambda (kont)
+ (let ((return kont))
+ (lambda ()
+ body ...)))))
+
+;; Aliases
+(define-syntax-rule (8run args ...) (%run args ...))
+(define-syntax-rule (8run-at args ...) (%run-at args ...))
+(define-syntax-rule (8run-delay args ...) (%run-delay args ...))
+(define-syntax-rule (8port-request args ...) (%port-request args ...))
\f
;; @@: Hm, maybe here would be a great place to handle
;; select'ing on ports.
;; We could compose over agenda-run-once and agenda-read-ports
- (parameterize ((%current-agenda agenda))
- (agenda-run-once agenda))))
+ (agenda-run-once agenda)))
(if (and stop-condition (stop-condition agenda))
'done
(let* ((agenda
based on the results"
(define (call-proc proc)
(call-with-prompt
- (agenda-prompt-tag agenda)
- (lambda ()
- (proc))
- (lambda* (resume-with please-run-this . args)
- (apply request-future please-run-this resume-with
- args))))
+ (agenda-prompt-tag agenda)
+ (lambda ()
+ (parameterize ((%current-agenda agenda))
+ (proc)))
+ (lambda (kont async-request)
+ (setup-async-request kont async-request))))
(let ((queue (agenda-queue agenda))
(next-queue (make-q)))
(_ #f)))
;; @@: We might support delay-wrapped procedures here
(match proc-result
- ;; TODO: replace procedure with something that indicates
- ;; intent to run. Use a (run foo) procedure
((results ...)
(for-each handle-individual results))
(one-result (handle-individual one-result)))))