task.ss
#lang scheme/base

(require (planet soegaard/galore:4/set))

;; struct task : symbol (listof task) (() -> build-result)
;;
;; A task is a list of dependencies and an action
(define-struct task (name dependencies action) #:prefab)

(define-syntax define-task
  (syntax-rules ()
    [(define-task name (dependency ...))
     (define-task name (dependency ...) (void))]
    [(define-task name (dependency ...) expr0 expr1 ...)
     (begin
       (define name
         (make-task (quote name)
                    (list dependency ...)
                    (lambda () expr0 expr1 ...)))
       (provide name))]))

;; task-traverse : task [(setof task)] -> (setof task) (listof task)
;;
;; Depth-first traversal of task dependencies.  Returns
;; set of tasks visited, and depth-first ordered list of tasks
(define (task-traverse task [visited (make-eq)] [order null])
  (define children (task-dependencies task))
  (for/fold ([visited (insert task visited)]
             [order (cons task order)])
            ([t (in-list children)])
    (if (member? t visited)
        (values visited order)
        (task-traverse t visited order))))

;; : (task -> any)
(define (task-run-action task)
  ((task-action task)))

(provide
 (struct-out task)
 define-task
 task-traverse
 task-run-action)