syndicate-rkt/syndicate/syntax.rkt

272 lines
9.5 KiB
Racket
Raw Normal View History

2021-06-04 13:56:03 +00:00
;;; SPDX-License-Identifier: LGPL-3.0-or-later
2021-06-04 14:20:14 +00:00
;;; SPDX-FileCopyrightText: Copyright © 2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
2021-06-01 08:04:10 +00:00
#lang racket/base
(provide this-turn
this-facet
this-actor
entity
actor-system
ref
react
define-field
stop-facet
stop-current-facet
on-start
on-stop
sync!
send!
spawn
begin/dataflow
define/dataflow
stop-when-true
2021-06-10 11:29:19 +00:00
entity/stop-on-retract
2021-06-01 08:04:10 +00:00
this-target
at
assert
stop-when
2021-06-01 08:04:10 +00:00
(rename-out [event:when when])
2021-06-03 15:02:14 +00:00
during
during/spawn
2021-06-03 15:02:14 +00:00
during*)
2021-06-01 08:04:10 +00:00
(require racket/match)
(require racket/stxparam)
(require (for-syntax racket/base))
(require (for-syntax racket/syntax))
2021-06-09 21:05:51 +00:00
(require (for-syntax syntax/parse))
(require preserves-schema)
2021-06-01 08:04:10 +00:00
(require "actor.rkt")
(require (prefix-in actor: "actor.rkt"))
2021-06-10 09:42:07 +00:00
(require "entity-ref.rkt")
2021-06-01 08:04:10 +00:00
(require "event-expander.rkt")
(require "pattern.rkt")
2021-06-09 21:05:51 +00:00
(require "syntax-classes.rkt")
2021-06-01 08:04:10 +00:00
2021-06-10 09:42:07 +00:00
(define-syntax this-turn
(make-set!-transformer
(lambda (stx)
(syntax-case stx ()
[id
(identifier? #'id)
#'(or (current-turn) (error 'this-turn "Illegal use outside an Actor turn"))]))))
2021-06-01 08:04:10 +00:00
2021-06-10 09:42:07 +00:00
(define-syntax-rule (with-this-turn turn-expr expr ...)
(parameterize ([current-turn turn-expr])
2021-06-01 08:04:10 +00:00
expr ...))
(define-syntax this-facet
(syntax-id-rules ()
[_ (turn-active-facet this-turn)]))
(define-syntax this-actor
(syntax-id-rules ()
[_ (facet-actor this-facet)]))
2021-06-09 21:05:51 +00:00
(define-syntax (actor-system stx)
(syntax-parse stx
[(_ name:<name> expr ...)
2021-06-10 09:42:07 +00:00
#'(actor:actor-system #:name name.N (lambda () expr ...))]))
2021-06-01 08:04:10 +00:00
2021-06-10 09:42:07 +00:00
(define (ref entity)
(entity-ref this-facet entity '()))
2021-06-01 08:04:10 +00:00
(define-syntax-rule (react setup-expr ...)
2021-06-10 09:42:07 +00:00
(turn-facet! this-turn (lambda () setup-expr ...)))
2021-06-01 08:04:10 +00:00
(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)]
2021-06-10 09:42:07 +00:00
[(_ f expr ...) (turn-stop! this-turn f (lambda () expr ...))]))
2021-06-01 08:04:10 +00:00
(define-syntax-rule (stop-current-facet expr ...)
(stop-facet this-facet expr ...))
(define-syntax-rule (on-start expr ...)
2021-06-10 09:42:07 +00:00
(facet-on-end-of-turn! this-facet (lambda () expr ...)))
2021-06-01 08:04:10 +00:00
(define-syntax-rule (on-stop expr ...)
2021-06-10 09:42:07 +00:00
(facet-on-stop! this-facet (lambda () expr ...)))
2021-06-01 08:04:10 +00:00
(define-syntax-rule (sync! peer expr ...)
2021-06-10 09:42:07 +00:00
(turn-sync! this-turn peer (lambda (_reply) expr ...)))
2021-06-01 08:04:10 +00:00
(define-syntax-rule (send! peer assertion)
(turn-message! this-turn peer (->preserve assertion)))
2021-06-01 08:04:10 +00:00
2021-06-09 21:05:51 +00:00
(define-syntax (spawn stx)
(syntax-parse stx
2021-06-10 11:33:34 +00:00
[(_ name:<name> daemon:<daemon?>)
(raise-syntax-error #f "Need body in spawn")]
2021-06-09 21:05:51 +00:00
[(_ name:<name> daemon:<daemon?> setup-expr ...)
#'(turn-spawn! #:name name.N
#:daemon? daemon.D
this-turn
2021-06-10 09:42:07 +00:00
(lambda () setup-expr ...))]))
2021-06-01 08:04:10 +00:00
(define-syntax-rule (begin/dataflow expr ...)
2021-06-10 09:42:07 +00:00
(turn-dataflow! this-turn (lambda () expr ...)))
2021-06-01 08:04:10 +00:00
(define-syntax-rule (define/dataflow id expr)
(begin (define-field id #f)
(begin/dataflow (id expr))))
(define-syntax-rule (stop-when-true test expr ...)
(begin/dataflow
(when test
(stop-current-facet expr ...))))
2021-06-10 11:29:19 +00:00
(define (entity/stop-on-retract #:name [name 'stop-on-retract] [k void])
(entity #:name name #:retract (lambda (_handle) (stop-current-facet (k)))))
2021-06-01 08:04:10 +00:00
;;---------------------------------------------------------------------------
(define-for-syntax orig-insp
(variable-reference->module-declaration-inspector (#%variable-reference)))
(define-syntax-parameter this-target
(lambda (stx)
2021-06-10 09:42:07 +00:00
(raise-syntax-error #f "Illegal use outside an `at` expression" stx)))
2021-06-01 08:04:10 +00:00
(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
2021-06-10 08:00:22 +00:00
(lambda (stx)
(syntax-parse stx
[(_ condition:<when> expr)
#`(turn-assert/dataflow! this-turn
this-target
2021-06-10 09:42:07 +00:00
(lambda ()
2021-06-10 08:00:22 +00:00
(if condition.E
(->preserve expr)
(void))))])))
2021-06-01 08:04:10 +00:00
(define-event-expander stop-when
(syntax-rules ()
[(_ event expr ...)
(event:when event (stop-current-facet expr ...))]))
2021-06-01 08:04:10 +00:00
(require "schemas/gen/dataspace.rkt")
(define-event-expander event:when
(lambda (stx)
(syntax-case stx (message asserted retracted)
[(_ (message pat) expr ...)
#`(assert (Observe (:pattern pat)
(ref (entity #:message
2021-06-10 09:42:07 +00:00
(lambda (bindings)
(match-define (list #,@(analyse-pattern-bindings #'pat)) bindings)
expr ...)))))]
[(_ (asserted pat) expr ...)
#`(assert (Observe (:pattern pat)
(ref (entity #:assert
2021-06-10 09:42:07 +00:00
(lambda (bindings _handle)
(match-define (list #,@(analyse-pattern-bindings #'pat)) bindings)
expr ...)))))]
[(_ (retracted pat) expr ...)
#`(assert (Observe (:pattern pat)
(let ((assertion-map (make-hash)))
(ref (entity #:assert
2021-06-10 09:42:07 +00:00
(lambda (bindings handle)
(hash-set! assertion-map handle bindings))
#:retract
2021-06-10 09:42:07 +00:00
(lambda (handle)
(match-define (list #,@(analyse-pattern-bindings #'pat))
(hash-ref assertion-map handle))
(hash-remove! assertion-map handle)
expr ...))))))]))
2021-06-01 08:04:10 +00:00
(syntax-rules ()
[(_ test expr ...)
(when test expr ...)]))
(define-event-expander during
(lambda (stx)
(syntax-case stx ()
[(_ pat expr ...)
#`(assert (Observe (:pattern pat)
2021-06-10 09:42:07 +00:00
(ref (during* (lambda (bindings)
2021-06-03 15:02:14 +00:00
(match-define (list #,@(analyse-pattern-bindings #'pat)) bindings)
expr ...)))))])))
(define-event-expander during/spawn
(lambda (stx)
(syntax-parse stx
[(_ pat name-stx:<name> daemon:<daemon?> expr ...)
#`(assert
(Observe (:pattern pat)
(ref (during*
2021-06-10 09:42:07 +00:00
(lambda (bindings)
(match-define (list #,@(analyse-pattern-bindings #'pat)) bindings)
(define name name-stx.N)
(define monitor
2021-06-10 11:29:19 +00:00
(ref (entity/stop-on-retract #:name (list name 'monitor-in-parent))))
(define monitor-handle (turn-assert! this-turn monitor 'alive))
(turn-spawn! this-turn
#:name name
#:daemon? daemon.D
#:link
2021-06-10 11:29:19 +00:00
(entity/stop-on-retract #:name
(list name 'monitor-in-child))
2021-06-10 09:42:07 +00:00
(lambda () expr ...)
(hasheq monitor-handle #t)))))))])))
2021-06-08 07:31:28 +00:00
(define (during* f #:name [name '?])
2021-06-03 15:02:14 +00:00
(define assertion-map (make-hash))
2021-06-08 07:31:28 +00:00
(entity #:name name
#:assert
2021-06-10 09:42:07 +00:00
(lambda (value handle)
2021-06-03 15:02:14 +00:00
(let ((facet (react (facet-prevent-inert-check! this-facet)
2021-06-10 09:42:07 +00:00
(f value))))
2021-06-03 15:02:14 +00:00
(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
2021-06-10 09:42:07 +00:00
(lambda (handle)
2021-06-03 15:02:14 +00:00
(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)]))))
2021-06-01 08:04:10 +00:00
;;---------------------------------------------------------------------------
;;; Local Variables:
2021-06-08 07:31:52 +00:00
;;; eval: (put 'actor-system/dataspace 'racket-indent-function 1)
2021-06-03 20:44:47 +00:00
;;; eval: (put 'at 'racket-indent-function 1)
2021-06-08 07:31:52 +00:00
;;; eval: (put 'react 'racket-indent-function 0)
;;; eval: (put 'spawn 'racket-indent-function 0)
2021-06-03 20:44:47 +00:00
;;; eval: (put 'stop-when 'racket-indent-function 1)
;;; eval: (put 'stop-when-true 'racket-indent-function 1)
2021-06-01 08:04:10 +00:00
;;; End: