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 15:19:24 +00:00
|
|
|
|
2021-06-01 08:04:10 +00:00
|
|
|
#lang racket/base
|
|
|
|
|
|
|
|
(provide this-turn
|
|
|
|
this-facet
|
|
|
|
this-actor
|
|
|
|
|
|
|
|
entity
|
|
|
|
actor-system
|
2021-06-13 05:55:50 +00:00
|
|
|
actor-group
|
2021-06-10 14:21:30 +00:00
|
|
|
object
|
2021-06-01 08:04:10 +00:00
|
|
|
|
|
|
|
ref
|
|
|
|
react
|
2021-06-11 12:18:53 +00:00
|
|
|
let-event
|
2021-06-01 08:04:10 +00:00
|
|
|
define-field
|
|
|
|
stop-facet
|
|
|
|
stop-current-facet
|
|
|
|
on-start
|
|
|
|
on-stop
|
|
|
|
sync!
|
|
|
|
send!
|
|
|
|
spawn
|
2021-06-10 14:21:30 +00:00
|
|
|
spawn/link
|
2021-06-01 08:04:10 +00:00
|
|
|
|
|
|
|
begin/dataflow
|
|
|
|
define/dataflow
|
2021-06-03 20:44:39 +00:00
|
|
|
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
|
2021-06-03 20:44:39 +00:00
|
|
|
stop-when
|
2021-06-01 08:04:10 +00:00
|
|
|
(rename-out [event:when when])
|
2021-06-03 15:02:14 +00:00
|
|
|
during
|
2021-06-09 21:06:40 +00:00
|
|
|
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))
|
2021-06-08 14:20:58 +00:00
|
|
|
(require preserves-schema)
|
2021-06-01 08:04:10 +00:00
|
|
|
|
|
|
|
(require "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")
|
2021-06-02 11:11:26 +00:00
|
|
|
(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-11 12:18:53 +00:00
|
|
|
(define-logger syndicate/object) ;; used by the (object) macro
|
|
|
|
|
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-13 05:55:50 +00:00
|
|
|
#'(make-actor-system #:name name.N (lambda () expr ...))]))
|
|
|
|
|
|
|
|
(define-syntax (actor-group stx)
|
|
|
|
(syntax-parse stx
|
2021-06-15 10:43:27 +00:00
|
|
|
[(_ name:<name> link:<link?> group-boot-expr ...)
|
2021-06-13 05:55:50 +00:00
|
|
|
#'(make-actor-group #:name name.N
|
2021-06-15 10:43:27 +00:00
|
|
|
#:link? link.L
|
2021-06-13 05:55:50 +00:00
|
|
|
(lambda () group-boot-expr ...))]))
|
2021-06-01 08:04:10 +00:00
|
|
|
|
2021-06-10 14:21:30 +00:00
|
|
|
(define-syntax (object stx)
|
|
|
|
(syntax-parse stx
|
2021-06-11 12:18:53 +00:00
|
|
|
[(_ name-stx:<name> handler ...)
|
2021-06-10 14:21:30 +00:00
|
|
|
#`(let ((state (make-hash)))
|
2021-06-11 12:18:53 +00:00
|
|
|
(define name name-stx.N)
|
2021-06-15 10:41:46 +00:00
|
|
|
(define (handler-function assertion is-message?)
|
|
|
|
(-object-clauses name assertion is-message? [] [handler ...]))
|
2021-06-11 12:18:53 +00:00
|
|
|
(ref (entity #:name name
|
2021-06-10 14:21:30 +00:00
|
|
|
#:assert (lambda (m h) (-object-assert state handler-function m h))
|
|
|
|
#:retract (lambda (h) (-object-retract state h))
|
|
|
|
#:message (lambda (m) (-object-message handler-function m)))))]))
|
|
|
|
|
|
|
|
(define (-object-assert state handler-function assertion handle)
|
2021-06-15 10:41:46 +00:00
|
|
|
(define k (handler-function assertion #f))
|
2021-06-10 14:21:30 +00:00
|
|
|
(when k (hash-set! state handle k)))
|
|
|
|
|
|
|
|
(define (-object-retract state handle)
|
|
|
|
(define k (hash-ref state handle #f))
|
|
|
|
(when k
|
|
|
|
(hash-remove! state handle)
|
|
|
|
(k)))
|
|
|
|
|
|
|
|
(define (-object-message handler-function message)
|
2021-06-15 10:41:46 +00:00
|
|
|
(define k (handler-function message #t))
|
2021-06-10 14:21:30 +00:00
|
|
|
(when k
|
|
|
|
(k)))
|
|
|
|
|
|
|
|
(define-syntax (-object-clauses stx)
|
|
|
|
(syntax-parse stx
|
2021-06-15 10:41:46 +00:00
|
|
|
[(_ name input is-message? [completed ...]
|
|
|
|
[])
|
2021-06-10 14:21:30 +00:00
|
|
|
#'(match input
|
|
|
|
completed ...
|
2021-06-11 12:18:53 +00:00
|
|
|
[_
|
2021-06-15 10:41:46 +00:00
|
|
|
(log-syndicate/object-debug "Unhandled ~a ~v in ~v"
|
|
|
|
(if is-message? "message" "assertion")
|
|
|
|
input name)
|
2021-06-11 12:18:53 +00:00
|
|
|
#f])]
|
2021-06-10 14:21:30 +00:00
|
|
|
|
2021-06-15 10:41:46 +00:00
|
|
|
[(_ name input is-message? [completed ...]
|
|
|
|
[ [#:message pat body+ ...] more ... ])
|
2021-06-11 12:18:53 +00:00
|
|
|
#'(-object-clauses name
|
|
|
|
input
|
2021-06-15 10:41:46 +00:00
|
|
|
is-message?
|
|
|
|
[ completed ... [(-object-pattern pat) #:when is-message?
|
|
|
|
body+ ... #f] ]
|
|
|
|
[more ...])]
|
2021-06-10 14:21:30 +00:00
|
|
|
|
2021-06-15 10:41:46 +00:00
|
|
|
[(_ name input is-message? [completed ...]
|
|
|
|
[ [#:asserted pat body+ ... #:retracted body- ...] more ... ])
|
2021-06-11 12:18:53 +00:00
|
|
|
#`(-object-clauses name
|
|
|
|
input
|
2021-06-15 10:41:46 +00:00
|
|
|
is-message?
|
|
|
|
[ completed ... [(-object-pattern pat) #:when (not is-message?)
|
2021-06-10 14:21:30 +00:00
|
|
|
body+ ...
|
|
|
|
#,(if (null? (syntax->list #'(body- ...)))
|
|
|
|
#`#f
|
|
|
|
#`(lambda () body- ...))] ]
|
|
|
|
[more ...])]
|
|
|
|
|
2021-06-15 10:41:46 +00:00
|
|
|
[(_ name input is-message? [completed ...]
|
|
|
|
[ [#:asserted pat body+ ...] more ... ])
|
2021-06-11 12:18:53 +00:00
|
|
|
#'(-object-clauses name
|
|
|
|
input
|
2021-06-15 10:41:46 +00:00
|
|
|
is-message?
|
2021-06-10 14:21:30 +00:00
|
|
|
[completed ...]
|
|
|
|
[ [#:asserted pat body+ ... #:retracted] more ... ])]
|
|
|
|
|
2021-06-15 10:41:46 +00:00
|
|
|
[(_ name input is-message? [completed ...]
|
|
|
|
[ [pat body ...] more ... ])
|
2021-06-11 12:18:53 +00:00
|
|
|
#'(-object-clauses name
|
|
|
|
input
|
2021-06-15 10:41:46 +00:00
|
|
|
is-message?
|
2021-06-10 14:21:30 +00:00
|
|
|
[completed ...]
|
|
|
|
[ [#:asserted pat
|
|
|
|
(define f (react (facet-prevent-inert-check! this-facet) body ...))
|
|
|
|
#:retracted
|
|
|
|
(stop-facet f)]
|
|
|
|
more ... ])]))
|
|
|
|
|
|
|
|
(define-match-expander -object-pattern
|
|
|
|
(lambda (stx)
|
|
|
|
(syntax-case stx ()
|
|
|
|
[(_ pat-stx)
|
|
|
|
(analyse-match-pattern #'pat-stx)])))
|
|
|
|
|
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-13 05:55:50 +00:00
|
|
|
(turn-facet! (lambda () setup-expr ...)))
|
2021-06-01 08:04:10 +00:00
|
|
|
|
2021-06-11 12:18:53 +00:00
|
|
|
(define-syntax (let-event stx)
|
|
|
|
(syntax-parse stx
|
|
|
|
[(_ [] body ...)
|
|
|
|
#'(begin body ...)]
|
|
|
|
[(_ [#:do expr e ...] body ...)
|
|
|
|
#'(begin expr (let-event [e ...] body ...))]
|
|
|
|
[(_ [e0 e ...] body ...)
|
|
|
|
#'(react (stop-when e0 (let-event [e ...] body ...)))]))
|
|
|
|
|
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 ()
|
2021-06-13 05:55:50 +00:00
|
|
|
[(_ f) (turn-stop! f)]
|
|
|
|
[(_ f expr ...) (turn-stop! 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)
|
2021-06-08 14:20:58 +00:00
|
|
|
(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
|
|
|
|
2021-06-10 14:21:30 +00:00
|
|
|
(define-syntax (spawn/link stx)
|
|
|
|
(syntax-parse stx
|
|
|
|
[(_ name-stx:<name> daemon:<daemon?> setup-expr ...)
|
|
|
|
#`(begin
|
|
|
|
(define name name-stx.N)
|
|
|
|
(define monitor (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
|
|
|
|
(entity/stop-on-retract #:name (list name 'monitor-in-child))
|
|
|
|
(lambda () setup-expr ...)
|
|
|
|
(hasheq monitor-handle #t)))]))
|
|
|
|
|
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))))
|
|
|
|
|
2021-06-03 20:44:39 +00:00
|
|
|
(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
|
|
|
|
2021-06-03 20:44:39 +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)
|
2021-06-13 05:55:50 +00:00
|
|
|
(syntax-parse stx
|
|
|
|
[(_ ((~datum message) pat) expr ...)
|
2021-06-02 11:11:26 +00:00
|
|
|
#`(assert (Observe (:pattern pat)
|
|
|
|
(ref (entity #:message
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda (bindings)
|
2021-06-02 11:11:26 +00:00
|
|
|
(match-define (list #,@(analyse-pattern-bindings #'pat)) bindings)
|
|
|
|
expr ...)))))]
|
2021-06-13 05:55:50 +00:00
|
|
|
[(_ ((~datum asserted) pat) expr ...)
|
2021-06-02 11:11:26 +00:00
|
|
|
#`(assert (Observe (:pattern pat)
|
|
|
|
(ref (entity #:assert
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda (bindings _handle)
|
2021-06-02 11:11:26 +00:00
|
|
|
(match-define (list #,@(analyse-pattern-bindings #'pat)) bindings)
|
2021-06-03 20:44:39 +00:00
|
|
|
expr ...)))))]
|
2021-06-13 05:55:50 +00:00
|
|
|
[(_ ((~datum retracted) pat) expr ...)
|
2021-06-03 20:44:39 +00:00
|
|
|
#`(assert (Observe (:pattern pat)
|
|
|
|
(let ((assertion-map (make-hash)))
|
|
|
|
(ref (entity #:assert
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda (bindings handle)
|
2021-06-03 20:44:39 +00:00
|
|
|
(hash-set! assertion-map handle bindings))
|
|
|
|
#:retract
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda (handle)
|
2021-06-03 20:44:39 +00:00
|
|
|
(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 ()
|
2021-06-02 11:11:26 +00:00
|
|
|
[(_ 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 ...)))))])))
|
|
|
|
|
2021-06-09 21:06:40 +00:00
|
|
|
(define-event-expander during/spawn
|
|
|
|
(lambda (stx)
|
|
|
|
(syntax-parse stx
|
|
|
|
[(_ pat name-stx:<name> daemon:<daemon?> expr ...)
|
2021-06-10 14:21:30 +00:00
|
|
|
#`(assert (Observe (:pattern pat)
|
|
|
|
(ref (during* (lambda (bindings)
|
|
|
|
(match-define (list #,@(analyse-pattern-bindings #'pat)) bindings)
|
|
|
|
(spawn/link #:name name-stx.N #:daemon? daemon.D expr ...))))))])))
|
2021-06-09 21:06:40 +00:00
|
|
|
|
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-10 12:41:57 +00:00
|
|
|
(hash-set! assertion-map
|
|
|
|
handle
|
|
|
|
(react (facet-prevent-inert-check! this-facet)
|
|
|
|
(f value))))
|
2021-06-03 15:02:14 +00:00
|
|
|
#: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)
|
2021-06-10 12:41:57 +00:00
|
|
|
[#f (void)]
|
2021-06-03 15:02:14 +00:00
|
|
|
[facet
|
|
|
|
(hash-remove! assertion-map handle)
|
|
|
|
(stop-facet facet)]))))
|
2021-06-01 08:04:10 +00:00
|
|
|
|
|
|
|
;;---------------------------------------------------------------------------
|
|
|
|
;;; Local Variables:
|
2021-06-15 10:43:27 +00:00
|
|
|
;;; eval: (put 'actor-group 'racket-indent-function 0)
|
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-10 14:21:30 +00:00
|
|
|
;;; eval: (put 'object 'racket-indent-function 0)
|
2021-06-08 07:31:52 +00:00
|
|
|
;;; eval: (put 'react 'racket-indent-function 0)
|
2021-06-14 17:23:12 +00:00
|
|
|
;;; eval: (put 'send! 'racket-indent-function 1)
|
|
|
|
;;; eval: (put 'sync! 'racket-indent-function 1)
|
2021-06-08 07:31:52 +00:00
|
|
|
;;; 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:
|