aboutsummaryrefslogtreecommitdiff
path: root/module/util/app.scm
blob: 65aed562fec8776797659f5000c3d10f1c85365e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
(define-module (util app)
  :use-module (util)
  :use-module (srfi srfi-1)
  :use-module (srfi srfi-9)
  :use-module (srfi srfi-9 gnu)
  :export (make-app current-app define-method getf setf)
  )

(define-immutable-record-type <app>
  (make-app% ht) app? (ht get-ht))

(define-public (make-app)
  (make-app% (make-hash-table)))

(define current-app (make-parameter (make-app)))

(define-syntax (define-method stx)
  (with-syntax ((app (datum->syntax stx 'app)))
   (syntax-case stx ()
     [(_ (name args ...) body ...)

      (let* ((pre post (break (lambda (s) (eqv? key: (syntax->datum s)))
                              #'(args ...))))
        #`(define*-public (name #,@pre #,@(if (null? post) '(key:) post)
                                (app (current-app)))
            (parameterize ((current-app app))
              body ...)))])))


(define-method (getf field)
  (aif (hashq-ref (get-ht app) field)
       (force it)
       (error "No field" field)))

(define-syntax setf%
  (syntax-rules ()
    [(_ app field value)
     (hashq-set! (get-ht (current-app)) field (delay value))]))

;; TODO setting a field should invalidate the cache of all dependant
;; fields. Among other things allowing a full calendar reload by running
;; (setf 'calendars (load-calendars ...))
(define-syntax setf
  (syntax-rules ()
    ;; special case to use current app)
    [(_ key value)
     (setf (current-app) key value)]

    [(_ app) app]
    [(_ app key value rest ...)
     (begin (setf% app key value)
            (setf app rest ...))]))