This repository has been archived by the owner on Mar 30, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmessage.rkt
85 lines (67 loc) · 2.43 KB
/
message.rkt
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#lang racket/base
; Define $message, the root of a prefab structure type tree. Prefab
; structures are flexible enough to accomodate all of the following
; use cases at once:
;
; - Visibility into data when something breaks
; - Transmit data over place channels or ports
; - Return values for monadic operations
; - Compose data in custom shapes
(provide (struct-out $message)
define-message
define+provide-message
scope-message
call-in-message-scope
call-in-message-scope*
in-message-scope
get-message-scope)
(define-syntax define-message
(syntax-rules ()
[(_ id super-id (fields ...))
(struct id super-id (fields ...) #:prefab)]
[(_ id (fields ...))
(define-message id $message (fields ...))]))
(define-syntax-rule (define+provide-message id rem ...)
(begin (provide (struct-out id))
(define-message id rem ...)))
(struct $message () #:prefab)
(define+provide-message $show-datum (value))
(define+provide-message $show-string (message))
(define+provide-message $regarding (subject body))
(define mark-key (string->uninterned-symbol "denxi:message-scope"))
(define (get-message-scope)
(or (continuation-mark-set-first
(current-continuation-marks)
mark-key)
null))
(define (scope-message m [scope (get-message-scope)])
(if (null? scope) m
(scope-message ($regarding (car scope) m)
(cdr scope))))
(define (call-in-message-scope* ms proc)
(with-continuation-mark mark-key ms
(proc)))
(define (call-in-message-scope m proc)
(call-in-message-scope* (cons m (get-message-scope))
proc))
(define-syntax-rule (in-message-scope m body ...)
(call-in-message-scope m (λ () body ...)))
(module+ test
(require rackunit)
(define-message $foo (a b c))
(define foo-inst ($foo 1 2 3))
(check-pred $foo? foo-inst)
(check-equal? ($foo-a foo-inst) 1)
(check-equal? ($foo-b foo-inst) 2)
(check-equal? ($foo-c foo-inst) 3)
(define-message $scope (v))
(test-case "Scope messages"
(in-message-scope ($scope 1)
(in-message-scope ($scope 2)
(check-equal? (get-message-scope)
(list ($scope 2)
($scope 1)))
(check-equal? (scope-message foo-inst)
($regarding ($scope 1)
($regarding ($scope 2)
foo-inst)))))))