syndicate-rkt/syndicate/syntax.rkt

197 lines
6.8 KiB
Racket

#lang racket/base
(provide this-turn
this-facet
this-actor
action
entity
actor-system
with-fresh-turn
ref
react
define-field
stop-facet
stop-current-facet
on-start
on-stop
sync!
send!
spawn
begin/dataflow
define/dataflow
this-target
at
assert
(rename-out [event:when when])
during)
(require racket/match)
(require racket/stxparam)
(require (for-syntax racket/base))
(require (for-syntax racket/syntax))
(require "actor.rkt")
(require (prefix-in actor: "actor.rkt"))
(require "event-expander.rkt")
(require "pattern.rkt")
(define-syntax-parameter this-turn
(lambda (stx)
(raise-syntax-error #f "Illegal use outside an Actor turn" stx)))
(define-syntax-rule (with-this-turn id expr ...)
(syntax-parameterize ([this-turn (make-rename-transformer #'id)])
expr ...))
(define-syntax this-facet
(syntax-id-rules ()
[_ (turn-active-facet this-turn)]))
(define-syntax this-actor
(syntax-id-rules ()
[_ (facet-actor this-facet)]))
(define-syntax-rule (action formals expr ...)
(lambda (turn . formals)
(with-this-turn turn expr ...)))
(define-syntax-rule (actor-system expr ...)
(actor:actor-system (action () expr ...)))
(define-syntax-rule (with-fresh-turn expr ...)
(turn-freshen this-turn (action () expr ...)))
(define-syntax-rule (ref e)
(turn-ref this-turn e))
(define-syntax-rule (react setup-expr ...)
(turn-facet! this-turn (action () setup-expr ...)))
(define-syntax-rule (define-field id initial-value)
(define id (turn-field! this-turn 'id initial-value)))
(define-syntax stop-facet
(syntax-rules ()
[(_ f) (turn-stop! this-turn f)]
[(_ f expr ...) (turn-stop! this-turn f (action () expr ...))]))
(define-syntax-rule (stop-current-facet expr ...)
(stop-facet this-facet expr ...))
(define-syntax-rule (on-start expr ...)
;; TODO: delay to end of turn (?)
(begin expr ...))
(define-syntax-rule (on-stop expr ...)
(facet-on-stop! this-facet (action () expr ...)))
(define-syntax-rule (sync! peer expr ...)
(turn-sync! this-turn peer (action (_reply) expr ...)))
(define-syntax-rule (send! peer assertion)
(turn-message! this-turn peer assertion))
(define-syntax-rule (spawn setup-expr ...)
(turn-spawn! this-turn (action () setup-expr ...)))
(define-syntax-rule (begin/dataflow expr ...)
(turn-dataflow! this-turn (action () expr ...)))
(define-syntax-rule (define/dataflow id expr)
(begin (define-field id #f)
(begin/dataflow (id expr))))
;;---------------------------------------------------------------------------
(define-for-syntax orig-insp
(variable-reference->module-declaration-inspector (#%variable-reference)))
(define-syntax-parameter this-target
(lambda (stx)
(raise-syntax-error #f "Illegal use outside an Actor turn" stx)))
(define-syntax (at stx)
(syntax-case stx ()
[(_ target-expr items ...)
#`(let ((target target-expr))
(syntax-parameterize ([this-target (make-rename-transformer #'target)])
#,@(for/list [(item-stx (in-list (syntax->list #'(items ...))))]
(let loop ((item-stx item-stx))
(define disarmed-item-stx (syntax-disarm item-stx orig-insp))
(syntax-case disarmed-item-stx ()
[(expander args ...)
(event-expander-id? #'expander)
(event-expander-transform disarmed-item-stx
(lambda (r) (loop (syntax-rearm r item-stx))))]
[_
item-stx])))))]))
(define-event-expander assert
(syntax-rules ()
[(_ expr)
(turn-assert/dataflow! this-turn this-target (action () (:template expr)))]))
(require "schemas/gen/dataspace.rkt")
(define-event-expander event:when
(lambda (stx)
(syntax-case stx (message asserted)
[(_ (message pat) expr ...)
#`(assert (Observe (:pattern pat)
(ref (entity #:message
(action (bindings)
(match-define (list #,@(analyse-pattern-bindings #'pat)) bindings)
expr ...)))))]
[(_ (asserted pat) expr ...)
#`(assert (Observe (:pattern pat)
(ref (entity #:assert
(action (bindings _handle)
(match-define (list #,@(analyse-pattern-bindings #'pat)) bindings)
expr ...)))))]))
(syntax-rules ()
[(_ test expr ...)
(when test expr ...)]))
(define-event-expander during
(lambda (stx)
(syntax-case stx ()
[(_ pat expr ...)
#`(assert (Observe (:pattern pat)
(ref (let ((assertion-map (make-hash)))
(entity #:assert
(action (bindings handle)
(match-define (list #,(analyse-pattern-bindings #'pat)) bindings)
(let ((facet (react
(facet-prevent-inert-check! this-facet)
expr ...)))
(match (hash-ref assertion-map handle #f)
[#f
(hash-set! assertion-map handle facet)]
['dead
(hash-remove! assertion-map handle)
(stop-facet facet)]
[_
(error 'during "Duplicate assertion handle ~a" handle)])))
#:retract
(action (handle)
(match (hash-ref assertion-map handle #f)
[#f
(hash-set! assertion-map handle 'dead)]
['dead
(error 'during "Duplicate retraction handle ~a" handle)]
[facet
(hash-remove! assertion-map handle)
(stop-facet facet)])))))))])))
;;---------------------------------------------------------------------------
;;; Local Variables:
;;; eval: (put 'action 'scheme-indent-function 1)
;;; eval: (put 'action 'racket-indent-function 1)
;;; End: