Compare commits

..

7 Commits
main ... pr/42

Author SHA1 Message Date
Michael Ballantyne 512783ec0f fix the serializer 2020-09-24 22:07:49 -06:00
Sam Caldwell 8a74f7ffee try out the syntax serializer 2020-09-24 13:18:55 -04:00
Sam Caldwell 721fb1c30f debug state 2020-09-24 11:07:30 -04:00
Sam Caldwell 4e97151cc5 Fix issue keep debugging 2020-09-24 11:05:55 -04:00
Sam Caldwell 0a8e400f63 work towards using typedefs, debugging 2020-09-17 15:11:54 -04:00
Sam Caldwell 8d6a037841 workaround: combine big and little lambda 2020-08-18 17:02:05 -04:00
Sam Caldwell 23616488ce wip on typedefs 2020-08-18 16:58:21 -04:00
114 changed files with 2806 additions and 5957 deletions

View File

@ -36,8 +36,3 @@
"scribble-lib"
"sha"
))
(define test-omit-paths
;; There's some shared library related build issue with the syndicate-gl things
'("syndicate-gl/"
"syndicate-ide/"))

View File

@ -409,7 +409,6 @@
[(_ [id:id init maybe-contract ...] ...)
(quasisyntax/loc stx
(begin
(ensure-in-endpoint-context! 'field)
(when (and (in-script?) (pair? (current-facet-id)))
(error 'field
"~a: Cannot declare fields in a script; are you missing a (react ...)?"
@ -488,17 +487,13 @@
(syntax-parse stx
[(_ script ...)
(quasisyntax/loc stx
(begin
(ensure-in-endpoint-context! 'on-start)
(schedule-script! (lambda () (begin/void-default script ...)))))]))
(schedule-script! (lambda () (begin/void-default script ...))))]))
(define-syntax (on-stop stx)
(syntax-parse stx
[(_ script ...)
(quasisyntax/loc stx
(begin
(ensure-in-endpoint-context! 'on-stop)
(add-stop-script! (lambda () (begin/void-default script ...)))))]))
(add-stop-script! (lambda () (begin/void-default script ...))))]))
(define-syntax (on-event stx)
(syntax-parse stx
@ -803,7 +798,7 @@
#:macro-definer-name define-event-expander
#:introducer-parameter-name current-event-expander-introducer
#:local-introduce-name syntax-local-event-expander-introduce
#:expander-form-predicate-name event-expander-form?
#:expander-id-predicate-name event-expander-id?
#:expander-transform-name event-expander-transform)
(provide (for-syntax
@ -811,7 +806,7 @@
event-expander?
event-expander-proc
syntax-local-event-expander-introduce
event-expander-form?
event-expander-id?
event-expander-transform)
define-event-expander)
@ -949,8 +944,8 @@
(define event-stx (syntax-disarm armed-event-stx orig-insp))
(syntax-parse event-stx
#:literals [core:message asserted retracted rising-edge know forget realize]
[expander
#:when (event-expander-form? #'expander)
[(expander args ...)
#:when (event-expander-id? #'expander)
(event-expander-transform
event-stx
(lambda (result)
@ -1121,12 +1116,11 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Endpoint Creation
(define (ensure-in-endpoint-context! who)
(when (or (in-script?) (null? (current-facet-id)))
(error who "Attempt to add endpoint out of installation context; are you missing a (react ...)?")))
(define (add-endpoint! where internal? patch-fn handler-fn)
(ensure-in-endpoint-context! 'add-endpoint!)
(when (in-script?)
(error 'add-endpoint!
"~a: Cannot add endpoint in script; are you missing a (react ...)?"
where))
(define-values (new-eid delta-aggregate)
(let ()
(define a (current-actor-state))

View File

@ -8,7 +8,6 @@
(require "main.rkt")
(require (submod "actor.rkt" for-module-begin))
(require "store.rkt")
(require (only-in "core.rkt" clean-actions))
(provide (rename-out [module-begin #%module-begin])
activate
@ -72,13 +71,6 @@
#%declare
begin-for-declarations))))
(define (ensure-spawn-actions! acts)
(define cleaned-acts (clean-actions acts))
(for ([act (in-list cleaned-acts)]
#:unless (actor? act))
(raise-argument-error 'syndicate-module "top-level actor creation action" act))
cleaned-acts)
(define-syntax (syndicate-module stx)
(syntax-parse stx
[(_ (action-ids ...) (form forms ...))
@ -97,9 +89,8 @@
#`(begin
(define-values (tmp ...) (values #,@(make-list (length (syntax->list #'(x ...))) #'#f)))
(define action-id
(ensure-spawn-actions!
(capture-actor-actions
(lambda () (set!-values (tmp ...) e)))))
(lambda () (set!-values (tmp ...) e))))
(define-values (x ...) (values tmp ...))
(syndicate-module (action-ids ... action-id) (forms ...)))]
[(head rest ...)
@ -108,8 +99,7 @@
#`(begin #,expanded (syndicate-module (action-ids ...) (forms ...)))]
[else
(with-syntax ([action-id (car (generate-temporaries (list #'form)))])
#`(begin
(define action-id (ensure-spawn-actions! (capture-actor-actions (lambda () #,expanded))))
#`(begin (define action-id (capture-actor-actions (lambda () #,expanded)))
(syndicate-module (action-ids ... action-id) (forms ...))))])]
[non-pair-syntax
#'(begin form (syndicate-module (action-ids ...) (forms ...)))])]

View File

@ -60,10 +60,7 @@
(quit))]
[_ #f]))
(actor (lambda (e s) (quit))
#f
(message (set-timer 'tick 1000 'relative)))
(message (set-timer 'tick 1000 'relative))
(actor ticker
1
(patch-seq (sub (observe (set-timer ? ? ?)))

View File

@ -7,7 +7,4 @@
'(;; Sam: example-plain is interactive, I think
"examples/example-plain.rkt"
;; Sam: for whatever reason I get a failure to load libcrypto for f-to-c
"examples/actor/f-to-c.rkt"
;; Sam: this test displays to stderr which the package server does not like
"tests/nested-spawn-exceptions.rkt"
))
"examples/actor/f-to-c.rkt"))

View File

@ -13,7 +13,6 @@
(require (for-syntax syntax/parse))
(require rackunit)
(require racket/engine)
(require racket/exn)
(define mt-scn (scn trie-empty))
@ -290,7 +289,7 @@
;; leaf behavior function
(define (actor-behavior e s)
(when e
(with-handlers ([exn:fail? (lambda (e) (printf "exception: ~v\n" (exn->string e)) (quit #:exception e (list)))])
(with-handlers ([exn:fail? (lambda (e) (eprintf "exception: ~v\n" e) (quit #:exception e (list)))])
(match-define (actor-state π-old fts) s)
(define-values (actions next-fts)
(for/fold ([as '()]
@ -546,7 +545,7 @@
;; boot-actor : actor Γ -> Action
(define (boot-actor a Γ)
(with-handlers ([exn:fail? (lambda (e)
(printf "booting actor died with: ~a\n" (exn->string e))
(eprintf "booting actor died with: ~v\n" e)
#f)])
(match a
[`(spawn ,O ...)

View File

@ -28,7 +28,7 @@
#:macro-definer-name define-assertion-expander
#:introducer-parameter-name current-assertion-expander-introducer
#:local-introduce-name syntax-local-assertion-expander-introduce
#:expander-form-predicate-name assertion-expander-form?
#:expander-id-predicate-name assertion-expander-id?
#:expander-transform-name assertion-expander-transform)
(provide (for-syntax
@ -36,7 +36,7 @@
assertion-expander?
assertion-expander-proc
syntax-local-assertion-expander-introduce
assertion-expander-form?
assertion-expander-id?
assertion-expander-transform)
define-assertion-expander)
@ -153,8 +153,8 @@
bs
ins))]
[expander
(assertion-expander-form? #'expander)
[(expander args ...)
(assertion-expander-id? #'expander)
(assertion-expander-transform pat-stx (lambda (r) (walk (syntax-rearm r pat-stx))))]
[(ctor p ...)

View File

@ -1,7 +1,5 @@
#lang racket/base
(provide start-tracing!)
(require racket/match)
(require racket/set)
(require racket/string)
@ -14,7 +12,7 @@
(define-logger syndicate/trace/msd)
(define (start-tracing! output-filename)
(let ((output-filename (getenv "SYNDICATE_MSD")))
(when output-filename
(define names (make-hash (list (cons '() "'ground"))))
(define (open-output cause)
@ -106,5 +104,3 @@
(loop)))))
(channel-get ch)
(current-trace-procedures (cons msd-trace (current-trace-procedures))))))
(start-tracing! (getenv "SYNDICATE_MSD"))

View File

@ -1,4 +0,0 @@
*.pml
*.trail
*.rktd
*.tmp

View File

@ -6,6 +6,5 @@ pan.c : leader-and-seller.pml
# -a to analyze, -f for (weak) fairness
# -n to elide report of unreached states
# -N spec-name to verify a particular specification
check: pan
./pan -a -f -n
./pan -a -f

View File

@ -0,0 +1,635 @@
#lang racket
;; TODO - syntax for LTL
(require "proto.rkt")
(require "ltl.rkt")
(module+ test
(require rackunit)
(require "test-utils.rkt"))
;; a SpinProgram is a
;; (sprog Assignment [Listof SpinProcess] [LTL SName])
(struct sprog [assignment procs spec] #:transparent)
;; a SpinProcess is a
;; (sproc SName [Setof SName] Assignment [Listof SName] [Setof SpinState])
(struct sproc [name state-names init initial-assertions states] #:transparent)
;; an Assignment is a [Hashof SVar SValue]
;; a SName is a Symbol that is a legal variable name in Spin
;; a SVar is a
;; (svar SName SType)
(struct svar [name ty] #:transparent)
;; a SValue is one of
;; - Int
;; - Bool
;; - SName
;; and must be a valid Spin literal
;; a SType is one of
;; - 'SInt
;; - 'SBool
;; - 'mtype
(define SInt 'SInt)
(define SBool 'SBool)
(define mtype 'mtype)
;; a SpinState is a
;; (sstate SName [Sequenceof SBranch])
(struct sstate [name branches] #:transparent)
;; a SBranch is a
;; (sbranch D+ SName [Listof SAction])
(struct sbranch [event dest actions] #:transparent)
;; a SAction is one of
;; - (assert ?)
;; - (retract ?)
;; - (send ?)
;; - (incorporate D+)
;; - (transition-to SName)
(struct assert [ty] #:transparent)
(struct retract [ty] #:transparent)
;; send defined in proto.rkt
(struct incorporate [evt] #:transparent)
(struct transition-to [dest] #:transparent)
;; each process has a local variable that determines its current state
(define CURRENT-STATE (svar 'current mtype))
;; a NameEnvironment is a [Hashof τ SName]
;; [Sequenceof RoleGraph] [LTL τ] -> SpinProgram
(define (program->spin rgs [spec #t])
(define assertion-tys (all-assertions rgs))
(define event-tys (all-events rgs))
(define event-subty# (make-event-map assertion-tys event-tys))
(define all-mentioned-tys (set-union assertion-tys event-tys))
(define name-env (make-name-env all-mentioned-tys))
(define globals (initial-assertion-vars-for all-mentioned-tys name-env))
(define procs (for/list ([rg rgs]) (rg->spin rg event-subty# name-env)))
(define spec-spin (rename-ltl spec name-env))
(sprog globals procs spec-spin))
;; RoleGraph [Hashof τ [Setof τ]] NameEnvironment -> SpinProcess
(define (rg->spin rg event-subty# name-env #:name [name (gensym 'proc)])
(match-define (role-graph st0 states) rg)
(define all-events (all-event-types (in-hash-values states)))
(define state-renaming (make-state-rename (hash-keys states)))
(define states- (for/list ([st (in-hash-values states)])
(state->spin st states event-subty# name-env state-renaming)))
(define st0- (hash-ref state-renaming st0))
;; ergh the invariant for when I tack on _assertions to a name is getting tricksy
(define st0-assertions (rename-all name-env (super-type-closure (state-assertions (hash-ref states st0)) event-subty#)))
(define assignment (local-variables-for st0- all-events name-env))
(sproc name (hash-values-set state-renaming) assignment st0-assertions (list->set states-)))
;; State [Sequenceof State] [Hashof τ [Setof τ]] NameEnvironment [Hashof StateName SName] -> SpinState
(define (state->spin st states event-subty# name-env state-env)
(match-define (state name transitions assertions) st)
(define name- (hash-ref state-env name))
(define branches (for*/list ([(D+ txns) (in-hash transitions)]
[txn (in-set txns)])
(match-define (transition effs dest) txn)
(match-define (state _ _ dest-assertions) (hash-ref states dest))
(define dest- (hash-ref state-env dest))
(branch-on D+ assertions dest- dest-assertions effs event-subty# name-env)))
(sstate name- branches))
;; [Setof τ] -> NameEnvironment
(define (make-name-env tys)
(let loop ([name-depth 3])
(when (> name-depth 10)
(raise-argument-error 'make-name-env "types able to be named" tys))
(define renaming
(for/hash ([ty (in-set tys)])
(values ty
(type->id ty #:depth name-depth))))
(define names (hash-values-set renaming))
(cond
[(equal? (set-count names) (set-count tys))
renaming]
[else
(loop (add1 name-depth))])))
;; SName -> SName
(define (assertions-var-name s)
(string->symbol (format "~a_assertions" s)))
;; SName -> SName
(define (active-var-name s)
(string->symbol (format "know_~a" s)))
;; [Setof τ] [Setof τ] -> [Hashof τ [Setof τ]]
(define (make-event-map assertion-tys event-tys)
;; TODO - potentially use non-empty intersection
(for/hash ([a (in-set assertion-tys)])
(values a
(all-supertypes-of a event-tys))))
;; τ [Setof τ] -> [Setof τ]
(define (all-supertypes-of τ tys)
(for*/set ([ty (in-set tys)]
#:when (<:? τ ty))
ty))
;; [Setof τ] [Hashof τ [Setof τ]]
(define (super-type-closure asserts event-subty#)
(for*/set ([a (in-set asserts)]
[supers (in-value (hash-ref event-subty# a))]
[τ (in-set (set-add supers a))])
τ))
;; [Setof τ] NameEnvironment -> Assignment
(define (initial-assertion-vars-for assertion-tys name-env)
(for/hash ([τ (in-set assertion-tys)])
(values (svar (assertions-var-name (hash-ref name-env τ)) SInt)
0)))
;; NameEnvironment [Setof τ] -> [Sequenceof SName]
(define (rename-all name-env asserts)
(for/set ([a (in-set asserts)])
(hash-ref name-env a)))
;; [Sequenceof RoleGraph] -> [Setof τ]
(define (all-assertions rgs)
;; RoleGraph -> (Setof τ)
(define (all-assertions-of rg)
(for*/set ([st (in-hash-values (role-graph-states rg))]
[τ (in-set (state-assertions st))])
τ))
(for/fold ([as (set)])
([rg rgs])
(set-union as (all-assertions-of rg))))
;; [Sequenceof RoleGraph] -> [Setof τ]
(define (all-events rgs)
;; RoleGraph -> (Setof τ)
(define (all-events-of rg)
(all-event-types (hash-values (role-graph-states rg))))
(for/fold ([as (set)])
([rg rgs])
(set-union as (all-events-of rg)))
)
;; [Sequenceof State] -> ?
(define (all-event-types states)
(for*/set ([st states]
[D+ (in-hash-keys (state-transitions st))])
(match D+
[(or (Asserted τ) (Retracted τ))
τ]
[(Message τ)
(raise-argument-error 'all-event-types "messages not supported yet" D+)]
[_
(raise-argument-error 'all-event-types "internal events not allowed" D+)])))
;; SName [Setof τ] NameEnvironment -> Assignment
(define (local-variables-for st0 all-events name-env)
(define assign
(for/hash ([evt (in-set all-events)])
(values (svar (active-var-name (hash-ref name-env evt))
SBool)
#f)))
(hash-set assign CURRENT-STATE st0))
;; D+ [Setof τ] SName [Setof τ] [Listof TransitionEffect] [Hashof τ [Setof τ]] NameEnvironment -> SBranch
(define (branch-on D+ curr-assertions dest dest-assertions effs event-subty# name-env)
(define new-assertions (super-type-closure (set-subtract dest-assertions curr-assertions) event-subty#))
(define retractions (super-type-closure (set-subtract curr-assertions dest-assertions) event-subty#))
(define (lookup ty) (hash-ref name-env ty))
(define asserts (set-map new-assertions (compose assert lookup)))
(define retracts (set-map retractions (compose retract lookup)))
(unless (empty? effs)
(raise-argument-error 'branch-on "messages not supported" effs))
(define renamed-evt (rename-event D+ name-env))
(sbranch renamed-evt dest (list* (transition-to dest)
(incorporate renamed-evt)
(append asserts retracts effs))))
;; D+ NameEnvironment -> D+
(define (rename-event D+ name-env)
(match D+
[(Asserted τ)
(Asserted (hash-ref name-env τ))]
[(Retracted τ)
(Retracted (hash-ref name-env τ))]
[(Message τ)
(raise-argument-error 'rename-event "messages not implemented yet" D+)]))
;; [LTL τ] -> [LTL SName]
(define (rename-ltl ltl name-env)
(define (lookup τ) (hash-ref name-env τ))
(map-atomic ltl lookup))
(module+ test
(test-case
"sanity: compile book seller type"
(define/timeout seller-rg (compile seller-actual))
(define name-env (hash
(Observe (Observe (Struct 'BookQuoteT (list (Base 'String) (Mk⋆)))))
'Obs_Obs_BookQuoteT
(Observe (Struct 'BookQuoteT (list (Base 'String) (Mk⋆))))
'Obs_BookQuoteT_String_star
(Struct 'BookQuoteT (list (Base 'String) (U (list (Base 'Int) (Base 'Int)))))
'BookQuoteT_String_U_Int_Int))
(define event# (hash
(Observe (Observe (Struct 'BookQuoteT (list (Base 'String) (Mk⋆)))))
(set)
(Struct 'BookQuoteT (list (Base 'String) (U (list (Base 'Int) (Base 'Int)))))
(set)))
(define/timeout seller-spin (rg->spin seller-rg event# name-env))
(check-true (sproc? seller-spin))))
(define tab-level (make-parameter 0))
(define TAB-WIDTH 2)
(define (indent)
(display (make-string (* TAB-WIDTH (tab-level)) #\space)))
(define-syntax-rule (with-indent bdy ...)
(parameterize ([tab-level (add1 (tab-level))])
bdy ...))
(define SPIN_ID_RX #rx"[a-zA-Z][a-zA-Z0-9_]*")
(define SPIN_ID_TRAILING_CHAR #rx"[a-zA-Z0-9_]+")
;; (U Symbol String) -> Bool
(define (spin-id? s)
(when (symbol? s)
(set! s (symbol->string s)))
(regexp-match? SPIN_ID_RX s))
(define SPIN-KEYWORDS
'(active assert atomic bit bool break byte chan d_step D_proctype do
else empty enabled fi full goto hidden if init int len mtype nempty
never nfull od of pc_value printf priority proctype provided run
short skip timeout typedef unless unsigned xr xs))
;; Symbol -> Symbol
(define (unkeyword s)
(if (member s SPIN-KEYWORDS)
(gensym s)
s))
;; (U Symbol String) -> SName
(define (make-spin-id s)
(when (symbol? s)
(set! s (symbol->string s)))
(define with_legal_prefix (string-append "ty_" s))
(match (regexp-match* SPIN_ID_TRAILING_CHAR with_legal_prefix)
['("ty_")
(raise-argument-error 'make-spin-id "unable to make spin id" s)]
[(cons fst rst)
(define match-str (apply string-append fst rst))
(define without-added-prefix (substring match-str 3))
(if (spin-id? without-added-prefix)
(unkeyword (string->symbol without-added-prefix))
(unkeyword (string->symbol match-str)))]))
;; τ -> SName
(define (type->id ty #:depth [depth 3])
(define ctors (type-constructors ty depth))
(define rough-name (string-join (map symbol->string ctors) "_"))
(make-spin-id rough-name))
;; [Listof StateName] -> [Hashof StateName SName]
(define (make-state-rename state-names)
(let loop ([prefix 3])
(define renaming (for/hash ([nm (in-list state-names)])
(values nm
(state-name->spin-id nm #:prefix prefix))))
(define distinct-names (hash-values-set renaming))
(cond
[(equal? (set-count distinct-names) (set-count state-names))
renaming]
[(> prefix 20)
(raise-argument-error 'make-state-rename "able to make renaming" state-names)]
[else
(loop (add1 prefix))])))
;; StateName -> SName
(define (state-name->spin-id nm #:prefix [prefix 3])
(cond
[(set-empty? nm)
(gensym 'inert)]
[else
(define (take-prefix s) (substring s 0 (min prefix (string-length s))))
(define rough-name (string-join (set-map nm (compose take-prefix symbol->string)) "_"))
(make-spin-id rough-name)]))
;; τ -> [Listof Symbol]
(define (type-constructors ty depth)
(cond
[(zero? depth) '()]
[else
(match ty
[(Struct name tys)
;; TODO - consider camel-casing struct name
(cons name (append-map (λ (ty) (type-constructors ty (sub1 depth))) tys))]
[(Observe ty)
(cons 'Obs (type-constructors ty (sub1 depth)))]
[(U tys)
(cons 'U (append-map (λ (ty) (type-constructors ty (sub1 depth))) tys))]
[(== )
(list 'star)]
[(Base name)
(list name)]
[(List _)
(list 'List)]
[(Set _)
(list 'Set)]
[(Hash _ _)
(list 'Hash)]
[(internal-label _ _)
(raise-argument-error 'type-constructors "internal events not supported" ty)])]))
(module+ test
(test-case
"type-constructors basics"
(define bi (Struct 'BookInterestT (list (Base 'String) (Base 'String) (Base 'Bool))))
(check-equal? (type-constructors bi 1)
'(BookInterestT))
(check-equal? (type-constructors bi 2)
'(BookInterestT String String Bool))
(check-equal? (type-constructors bi 3)
'(BookInterestT String String Bool))
(check-equal? (type-constructors (Observe bi) 3)
'(Obs BookInterestT String String Bool)))
(test-case
"type->id basics"
(define bi (Struct 'BookInterestT (list (Base 'String) (Base 'String) (Base 'Bool))))
(check-equal? (type->id bi)
'BookInterestT_String_String_Bool)
(check-equal? (type->id (Observe bi))
'Obs_BookInterestT_String_String_Bool)
(check-equal? (type->id (Struct 'hi-mom '()))
'himom)
(check-equal? (type->id bi #:depth 1)
'BookInterestT)
(check-exn exn:fail?
(lambda () (type->id (Struct '--- '())))
"unable to make spin id")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Code Generation
(define SPIN-PRELUDE (file->string "spin-prelude.pml"))
;; SpinThang FilePath -> Void
(define (gen-spin/to-file spin name)
(with-output-to-file name
(lambda () (gen-spin spin))
#:mode 'text
#:exists 'replace))
;; SpinThang -> Void
(define (gen-spin spin)
(match spin
[(sprog assignment procs spec)
(display SPIN-PRELUDE)
(gen-assignment assignment)
(newline)
(for ([p procs])
(gen-spin p)
(newline))
(gen-spec "spec" (lambda () (gen-ltl spec)))
(newline)
(gen-sanity-ltl assignment)]
[(sproc name state-names init asserts states)
(indent) (declare-mtype state-names)
(indent) (printf "active proctype ~a() {\n" name)
(with-indent
(gen-assignment init)
(for ([a asserts])
(gen-spin (assert a)))
(indent) (displayln "end: do")
(with-indent
(for ([st states])
(gen-spin st)))
(indent) (displayln "od;")
)
(indent) (displayln "}")]
[(sstate name branches)
(indent) (printf ":: ~a == ~a ->\n" (svar-name CURRENT-STATE) name)
(with-indent
(indent) (displayln "if")
(with-indent
(cond
[(empty? branches)
(indent) (displayln ":: true -> skip;")]
[else
(for ([branch branches])
(gen-spin branch))]))
(indent) (displayln "fi;"))]
[(sbranch event dest actions)
(indent) (printf ":: ~a ->\n" (predicate-for event))
;; TODO - make the body atomic
(with-indent
(indent) (displayln "atomic {")
(with-indent
(for ([act actions])
(gen-spin act)))
(indent) (displayln "}"))]
[(assert x)
(indent) (printf "ASSERT(~a);\n" x)]
[(retract x)
(indent) (printf "RETRACT(~a);\n" x)]
[(send x)
(raise-argument-error 'gen-spin "message sending not supported yet" spin)]
[(incorporate evt)
(indent) (update-for evt)]
[(transition-to dest)
(indent) (printf "~a = ~a;\n" (svar-name CURRENT-STATE) dest)]))
;; [Setof SName] -> Void
(define (declare-mtype state-names)
(display "mtype = {")
(display (string-join (set-map state-names symbol->string) ", "))
(displayln "}"))
;; Assignment -> Void
(define (gen-assignment assign)
(for ([(var val) (in-hash assign)])
(indent) (printf "~a = ~a;\n"
(declare-var var)
(spin-val->string val))))
;; SVar -> Void
(define (declare-var var)
(match-define (svar name ty) var)
(format "~a ~a" (spin-type->string ty) name))
;; SValue -> String
(define (spin-val->string v)
(cond
[(boolean? v)
(if v "true" "false")]
[(exact-integer? v)
(~a v)]
[(symbol? v)
(~a v)]))
;; SType -> String
(define (spin-type->string ty)
(match ty
[(== SInt) "int"]
[(== SBool) "bool"]
[(== mtype) "mtype"]))
;; D+ -> String
(define (predicate-for event)
(match event
[(Asserted nm)
(define assertion-var nm)
(define active-var (active-var-name nm))
(format "ASSERTED(~a) && !~a" assertion-var active-var)]
[(Retracted nm)
(define assertion-var nm)
(define active-var (active-var-name nm))
(format "RETRACTED(~a) && ~a" assertion-var active-var)]
[(Message nm)
(raise-argument-error 'predicate-for "message sending not supported yet" event)]))
;; D+ -> Void
(define (update-for event)
(match event
[(Asserted nm)
(define active-var (active-var-name nm))
(printf "~a = ~a;\n" active-var (spin-val->string #t))]
[(Retracted nm)
(define active-var (active-var-name nm))
(printf "~a = ~a;\n" active-var (spin-val->string #f))]
[(Message nm)
(raise-argument-error 'predicate-for "message sending not supported yet" event)]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; LTL
;; String {-> Void} -> Void
(define (gen-spec name mk-body)
(indent) (printf "ltl ~a {\n" name)
(with-indent
(mk-body))
(newline)
(indent) (displayln "}"))
;; [LTL SName] -> Void
(define (gen-ltl ltl)
(match ltl
[(always p)
(indent) (displayln "[](")
(with-indent
(gen-ltl p))
(indent) (displayln ")")]
[(eventually p)
(indent) (displayln "<>(")
(with-indent
(gen-ltl p))
(indent) (displayln ")")]
[(weak-until p q)
(gen-ltl-bin-op "W" p q)]
[(strong-until p q)
(gen-ltl-bin-op "U" p q)]
[(ltl-implies p q)
(gen-ltl-bin-op "->" p q)]
[(ltl-and p q)
(gen-ltl-bin-op "&&" p q)]
[(ltl-or p q)
(gen-ltl-bin-op "||" p q)]
[(ltl-not p)
(indent) (display "!(")
(gen-ltl p)
(displayln ")")]
[(atomic nm)
(printf "ASSERTED(~a)\n" nm)]
[#t
(display "true")]
[#f
(display "false")]))
;; String [LTL SName] [LTL SName] -> Void
(define (gen-ltl-bin-op name p q)
(indent) (display "(") (gen-ltl p) (display ") ")
(displayln name)
(newline)
(indent) (display "(") (gen-ltl q) (displayln ")"))
;; Assignment -> Void
(define (gen-sanity-ltl assignment)
(gen-spec "sanity"
(lambda ()
(indent) (displayln "[](")
(with-indent
(for ([assertion-var (in-hash-keys assignment)])
(indent) (printf "~a >= 0 &&\n" (svar-name assertion-var)))
(indent) (displayln "true"))
(indent) (displayln ")"))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Misc Utils
;; [Hashof K V] -> [Setof V]
(define (hash-values-set h)
(for/set ([x (in-hash-values h)])
x))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Test Case
(module+ leader-and-seller
(define leader-rg (compile (parse-T
'(Role ; = react
(get-quotes)
(Reacts ; = on
(Asserted (BookQuoteT String (Bind Int)))
(Branch
(Effs (Branch (Effs (Stop get-quotes)) (Effs)))
(Effs
(Role
(poll-members)
(Reacts
(Asserted (BookInterestT String (Bind String) Discard))
(Branch
(Effs (Stop poll-members (Branch (Effs (Stop get-quotes)) (Effs))))
(Effs))
(Branch
(Effs
(Stop get-quotes (Role (announce) (Shares (BookOfTheMonthT String)))))
(Effs)))
(Reacts (Retracted (BookInterestT String (Bind String) Bool)))
(Reacts (Asserted (BookInterestT String (Bind String) Bool)))
(Reacts (Retracted (BookInterestT String (Bind String) Bool)))
(Reacts (Asserted (BookInterestT String (Bind String) Bool)))))))
(Reacts (Retracted (ClubMemberT (Bind String))))
(Reacts (Asserted (ClubMemberT (Bind String))))))))
(define seller-rg (compile seller-actual))
(define member-rg (compile member-actual))
(define bq (book-quote String ))
(define bi (book-interest String ))
(define book-club-spec
(&& (eventually (atomic bq))
(always (ltl-implies (atomic (Observe bq))
(eventually (atomic bq))))
(always (ltl-implies (atomic (Observe bi))
(eventually (atomic bi))))))
(define book-club-spin (program->spin (list leader-rg seller-rg member-rg)
book-club-spec))
(gen-spin/to-file book-club-spin "gen-book-club.pml"))
(module+ flink
(define (import r)
(define r+ (parse-T r))
(compile/internal-events (compile r+) #f))
(define jm-rg (import job-manager-actual))
(define tm-rg (import task-manager-ty))
(define tr-rg (import task-runner-ty))
(define flink-spin (program->spin (list tr-rg tm-rg jm-rg)))
(gen-spin/to-file flink-spin "gen-flink.pml"))

View File

@ -17,8 +17,6 @@
error
define-tuple
match-define
mk-tuple
tuple-select
(for-syntax (all-defined-out)))
(require "core-types.rkt")
@ -44,30 +42,39 @@
;; copied from stlc
(define-typed-syntax (ann e (~optional (~datum :)) τ:type)
[ e e- ( : τ.norm) ( ν (~effs eff ...))]
[ e e- ( : τ.norm)]
#:fail-unless (pure? #'e-) "expression must be pure"
------------------------------------------------
[ e- ( : τ.norm) ( ν (eff ...))])
[ e- ( : τ.norm) ])
;; copied from ext-stlc
(define-typed-syntax if
[(_ e_tst e1 e2) τ-expected
[ e_tst e_tst- _] ; Any non-false value is truthy.
#:fail-unless (pure? #'e_tst-) "expression must be pure"
[ e1 e1- ( : τ-expected) ( ν (~effs eff1 ...))]
[ e2 e2- ( : τ-expected) ( ν (~effs eff2 ...))]
[ e1 e1- ( : τ-expected)
( ν-ep (~effs eps1 ...)) ( ν-f (~effs fs1 ...)) ( ν-s (~effs ss1 ...))]
[ e2 e2- ( : τ-expected)
( ν-ep (~effs eps2 ...)) ( ν-f (~effs fs2 ...)) ( ν-s (~effs ss2 ...))]
--------
[ (if- e_tst- e1- e2-)
( : τ-expected)
( ν #,(make-Branch #'((eff1 ...) (eff2 ...))))]]
( ν-ep (eps1 ... eps2 ...))
( ν-f #,(make-Branch #'((fs1 ...) (fs2 ...))))
( ν-s (ss1 ... ss2 ...))]]
[(_ e_tst e1 e2)
[ e_tst e_tst- _] ; Any non-false value is truthy.
#:fail-unless (pure? #'e_tst-) "expression must be pure"
[ e1 e1- ( : τ1) ( ν (~effs eff1 ...))]
[ e2 e2- ( : τ2) ( ν (~effs eff2 ...))]
[ e1 e1- ( : τ1)
( ν-ep (~effs eps1 ...)) ( ν-f (~effs fs1 ...)) ( ν-s (~effs ss1 ...))]
[ e2 e2- ( : τ2)
( ν-ep (~effs eps2 ...)) ( ν-f (~effs fs2 ...)) ( ν-s (~effs ss2 ...))]
#:with τ (mk-U- #'(τ1 τ2))
--------
[ (if- e_tst- e1- e2-) ( : τ)
( ν #,(make-Branch #'((eff1 ...) (eff2 ...))))]])
( ν-ep (eps1 ... eps2 ...))
( ν-f #,(make-Branch #'((fs1 ...) (fs2 ...))))
( ν-s (ss1 ... ss2 ...))]])
(define-typed-syntax (when e s ...+)
------------------------------------
@ -84,18 +91,26 @@
[ e e- : τ_x] ...
#:fail-unless (stx-andmap pure? #'(e- ...)) "expressions must be pure"
[[x x- : τ_x] ... (block e_body ...) e_body- ( : τ_expected)
( ν (~effs eff ...))]
( ν-ep (~effs eps ...))
( ν-f (~effs fs ...))
( ν-s (~effs ss ...))]
----------------------------------------------------------
[ (let- ([x- e-] ...) e_body-) ( : τ_expected)
( ν (eff ...))]]
( ν-ep (eps ...))
( ν-f (fs ...))
( ν-s (ss ...))]]
[(_ ([x e] ...) e_body ...)
[ e e- : τ_x] ...
#:fail-unless (stx-andmap pure? #'(e- ...)) "expressions must be pure"
[[x x- : τ_x] ... (block e_body ...) e_body- ( : τ_body)
( ν (~effs eff ...))]
( ν-ep (~effs eps ...))
( ν-f (~effs fs ...))
( ν-s (~effs ss ...))]
----------------------------------------------------------
[ (let- ([x- e-] ...) e_body-) ( : τ_body)
( ν (eff ...))]])
( ν-ep (eps ...))
( ν-f (fs ...))
( ν-s (ss ...))]])
;; copied from ext-stlc
(define-typed-syntax let*
@ -110,10 +125,14 @@
[ pred pred- ( : Bool)] ...
#:fail-unless (stx-andmap pure? #'(pred- ...)) "predicates must be pure"
[ (block s ...) s- ( : τ-s)
( ν (~effs eff ...))] ...
( ν-ep (~effs eps ...))
( ν-f (~effs fs ...))
( ν-s (~effs ss ...))] ...
------------------------------------------------
[ (cond- [pred- s-] ...) ( : (U τ-s ...))
( ν #,(make-Branch #'((eff ...) ...)))])
( ν-ep (eps ... ...))
( ν-f #,(make-Branch #'((fs ...) ...)))
( ν-s (ss ... ...))])
(define else #t)
@ -124,7 +143,9 @@
(elaborate-pattern/with-type pat #'τ-e))
#:with (([x τ:type] ...) ...) (stx-map pat-bindings #'(p/e ...))
[[x x- : τ.norm] ... (block s ...) s- ( : τ-s)
( ν (~effs eff ...))] ...
( ν-ep (~effs eps ...))
( ν-f (~effs fs ...))
( ν-s (~effs ss ...))] ...
;; REALLY not sure how to handle p/p-/p.match-pattern,
;; particularly w.r.t. typed terms that appear in p.match-pattern
[ p/e p-- τ-p] ...
@ -138,29 +159,28 @@
[ (match- e- [p- s-] ...
[_ (#%app- error- "incomplete pattern match")])
( : (U τ-s ...))
( ν #,(make-Branch #'((eff ...) ...)))])
( ν-ep #,(make-Branch #'((eps ...) ...)))
( ν-f #,(make-Branch #'((fs ...) ...)))
( ν-s #,(make-Branch #'((ss ...) ...)))])
;; (Listof Value) -> Value
(define- (mk-tuple es)
(#%app- cons- 'tuple es))
(define-typed-syntax (tuple e:expr ...)
[ e e- ( : τ) ( ν (~effs F ...))] ...
[ e e- ( : τ)] ...
#:fail-unless (stx-andmap pure? #'(e- ...)) "expressions not allowed to have effects"
-----------------------
[ (#%app- mk-tuple (#%app- list- e- ...))
( : (Tuple τ ...))
( ν (F ... ...))])
[ (#%app- list- 'tuple e- ...) ( : (Tuple τ ...))])
(define unit : Unit (tuple))
(define-typed-syntax (select n:nat e:expr)
[ e e- ( : (~Tuple τ ...)) ( ν (~effs F ...))]
[ e e- ( : (~Tuple τ ...))]
#:fail-unless (pure? #'e-) "expression not allowed to have effects"
#:do [(define i (syntax->datum #'n))]
#:fail-unless (< i (stx-length #'(τ ...))) "index out of range"
#:with τr (list-ref (stx->list #'(τ ...)) i)
--------------------------------------------------------------
[ (#%app- tuple-select n e-) ( : τr) ( ν (F ...))])
[ (#%app- tuple-select n e-) ( : τr)])
(define- (tuple-select n t)
(#%app- list-ref- t (#%app- add1- n)))
@ -185,6 +205,8 @@
[(tuple p ...)
#:with (([x:id τ:type] ...) ...) (stx-map pat-bindings #'(p ...))
#'([x τ] ... ...)]
#;[(k:kons1 p)
(pat-bindings #'p)]
[(~constructor-exp cons p ...)
#:with (([x:id τ:type] ...) ...) (stx-map pat-bindings #'(p ...))
#'([x τ] ... ...)]
@ -238,16 +260,12 @@
[(tuple p ...)
(quasisyntax/loc pat
(tuple #,@(stx-map elaborate-pattern #'(p ...))))]
[(~constructor-exp ctor p ...)
(define field-tys (ctor-field-tys #'ctor))
(define sub-pats
(for/list ([field-pat (in-syntax #'(p ...))]
[field-ty? (in-list field-tys)])
(if field-ty?
(elaborate-pattern/with-type field-pat field-ty?)
(elaborate-pattern field-pat))))
[(k:kons1 p)
(quasisyntax/loc pat
(ctor #,@sub-pats))]
(k #,(elaborate-pattern #'p)))]
[(~constructor-exp ctor p ...)
(quasisyntax/loc pat
(ctor #,@(stx-map elaborate-pattern #'(p ...))))]
[e:expr
#'e]))
@ -259,14 +277,10 @@
[x:dollar-ann-id
(syntax/loc pat (bind x.id x.ty))]
[x:dollar-id
(when (bot? ty)
(raise-syntax-error #f "unable to instantiate pattern with matching part of type" pat))
(quasisyntax/loc pat (bind x.id #,ty))]
[($ x:id ty)
(syntax/loc pat (bind x ty))]
[($ x:id)
(when (bot? ty)
(raise-syntax-error #f "unable to instantiate pattern with matching part of type" pat))
(quasisyntax/loc pat (bind x #,ty))]
[(tuple p ...)
(define (matching? t)
@ -305,7 +319,6 @@
(define (proj t i)
(syntax-parse t
[(~constructor-type _ tt ...)
#:when (matching? t)
(if (= i -1)
t
(stx-list-ref #'(tt ...) i))]
@ -332,6 +345,8 @@
#:datum-literals (tuple discard bind)
[(tuple p ...)
#`(#,list-binding 'tuple #,@(stx-map loop #'(p ...)))]
#;[(k:kons1 p)
#`(#,(kons1->constructor #'k) #,(loop #'p))]
[(bind x:id τ:type)
(bind-id-transformer #'x)]
[discard
@ -358,6 +373,7 @@
[ e e- ( (~Tuple τ ...))]
#:fail-unless (stx-length=? #'(x ...) #'(τ ...))
"mismatched size"
#:fail-unless (pure? #'e-) "expr must be pure"
#:with (sel ...) (for/list ([y (in-syntax #'(x ...))]
[t (in-syntax #'(τ ...))]
[i (in-naturals)])

View File

@ -62,7 +62,7 @@
(U (Observe (Observe (TcpConnection ★/t (TcpListener ★/t))))
(Observe (TcpConnection ★/t (TcpListener Int)))
(Observe (TcpConnection ★/t (TcpListener Int)))
(Advertise (Observe (TcpChannel ★/t (TcpListener (TcpHandle (Seal ★/t))) ★/t)))
(Advertise (Observe (TcpChannel ★/t (TcpListener (TcpHandle (Seal ★/t)) ★/t))))
(Observe (Advertise (TcpChannel (TcpAddress String Int) (TcpHandle (Seal ★/t)) ★/t)))
(TcpAccepted ★/t)
(Advertise (TcpChannel (TcpHandle (Seal ★/t)) (TcpAddress String Int) ★/t))
@ -102,7 +102,7 @@
(require/typed syndicate/drivers/tcp2)
(require/typed (submod syndicate/drivers/tcp2 syndicate-main)
[activate! : (proc (U) #:effects ((Actor Tcp2Driver))) #;( (Computation (Value (U))
[activate! : ( (Computation (Value (U))
(Endpoints)
(Roles)
(Spawns (Actor Tcp2Driver))))])

View File

@ -19,17 +19,21 @@
(U (Left A)
(Right B)))
(define ( (X) (f [x : X] -> X))
x)
(define ( (X Y Z) (partition/either [xs : (List X)]
[pred : (→fn X (Either Y Z))]
[pred : (→fn X (U (Left Y)
(Right Z)) #;(Either Y Z))]
-> (Tuple (List Y) (List Z))))
(for/fold ([lefts (List Y) (list)]
[rights (List Z) (list)])
(for/fold ([acc (Tuple (List Y) (List Z)) (tuple (list) (list))])
([x xs])
(define y-or-z (pred x))
(match y-or-z
[(left (bind y Y))
(tuple (cons y lefts)
rights)]
(tuple (cons y (select 0 acc))
(select 1 acc))]
[(right (bind z Z))
(tuple lefts
(cons z rights))])))
(tuple (select 0 acc)
(cons z (select 1 acc)))])))

27
racket/typed/example.rkt Normal file
View File

@ -0,0 +1,27 @@
#lang typed/syndicate
(define-type-alias ds-type
(U (Observe (Tuple String )) (Tuple String Int)))
(dataspace ds-type
(spawn ds-type
(facet _
(fields [the-thing Int 0])
(assert (tuple "the thing" (ref the-thing)))
(on (asserted (tuple "set thing" (bind new-v Int)))
(set! the-thing new-v))))
(spawn ds-type
(let [k (λ [10 (begin)]
[(bind x Int)
(facet _ (fields)
(assert (tuple "set thing" (+ x 1))))])]
(facet _ (fields)
(on (asserted (tuple "the thing" (bind x Int)))
(k x)))))
(spawn ds-type
(facet _ (fields)
(on (asserted (tuple "the thing" (bind t Int)))
(displayln t)))))

View File

@ -1,19 +1,14 @@
#lang typed/syndicate
;; Expected Output
;; 0
;; 70
;; #f
(define-constructor (account balance)
#:type-constructor AccountT
#:with Account (AccountT Int)
#:with AccountRequest (AccountT /t))
#:with AccountRequest (AccountT ))
(define-constructor (deposit amount)
#:type-constructor DepositT
#:with Deposit (DepositT Int)
#:with DepositRequest (DepositT /t))
#:with DepositRequest (DepositT ))
(define-type-alias ds-type
(U Account
@ -23,43 +18,45 @@
(Observe DepositRequest)
(Observe (Observe DepositRequest))))
(define-type-alias account-manager-role
(Role (account-manager)
(Shares Account)
(Reacts (Asserted Deposit))))
(define-type-alias client-role
(Role (client)
(Reacts (Asserted Account))))
(run-ground-dataspace ds-type
(dataspace ds-type
(spawn ds-type
(lift+define-role acct-mngr-role
(start-facet account-manager
(field [balance Int 0])
(facet _
(fields [balance Int 0])
(assert (account (ref balance)))
(on (asserted (deposit (bind amount Int)))
(set! balance (+ (ref balance) amount))))))
(set! balance (+ (ref balance) amount)))))
(spawn ds-type
(lift+define-role obs-role
(start-facet observer
(facet _
(fields)
(on (asserted (account (bind amount Int)))
(displayln amount)))))
(displayln amount))))
(spawn ds-type
(lift+define-role buyer-role
(start-facet buyer
(facet _
(fields)
(on (asserted (observe (deposit discard)))
(start-facet deposits
(facet _
(fields)
(assert (deposit 100))
(assert (deposit -30))))))))
(assert (deposit -30)))))))
(module+ test
(check-simulates acct-mngr-role account-manager-role)
(check-simulates obs-role client-role)
;; Tried to write this, then it failed, I looked and buyer doesn't actually implement that spec
#;(check-simulates buyer-role client-role)
)
#|
;; Hello-worldish "bank account" example.
(struct account (balance) #:prefab)
(struct deposit (amount) #:prefab)
(spawn (field [balance 0])
(assert (account (balance)))
(on (message (deposit $amount))
(balance (+ (balance) amount))))
(spawn (on (asserted (account $balance))
(printf "Balance changed to ~a\n" balance)))
(spawn* (until (asserted (observe (deposit _))))
(send! (deposit +100))
(send! (deposit -30)))
|#

View File

@ -1,21 +0,0 @@
#lang typed/syndicate
;; Expected Output:
;; got: new
(define-constructor* (something : SomethingT new blue)
#:with Something (SomethingT String Int))
(define-type-alias τc
(U Something
(Observe★ SomethingT)))
(run-ground-dataspace
τc
(spawn
(start-facet _
(assert (something "new" 42))))
(spawn
(start-facet _
(on (asserted (something $x 42))
(printf "got: ~a\n" x))))
)

View File

@ -1,36 +0,0 @@
#lang typed/syndicate
;; Expected Output
;; pong: 8339
(message-struct ping : Ping (v))
(message-struct pong : Pong (v))
(define-type-alias ds-type
(U (Message (Ping Int))
(Message (Pong Int))
(Observe (Ping ★/t))
(Observe (Pong ★/t))
(Observe (Observe (Ping ★/t)))))
(run-ground-dataspace ds-type
(spawn ds-type
(lift+define-role ponger
(start-facet echo
(on (message (ping $v))
(send! (pong v))))))
(spawn ds-type
(lift+define-role pinger
(start-facet serve
(on (asserted (observe (ping _)))
(send! (ping 8339)))
(on (message (pong $x))
(printf "pong: ~v\n" x))))))
(module+ test
(verify-actors (And (Eventually (M (Ping Int)))
(Eventually (M (Pong Int)))
(Always (Implies (M (Ping Int))
(Eventually (M (Pong Int))))))
pinger
ponger))

View File

@ -1,17 +0,0 @@
#lang typed/syndicate
;; using different syntax than "client.rkt"
(require/typed "driver.rkt" [#:struct msg])
(define m : (MsgT Int String) (msg 1 "hi"))
(msg-in m)
(msg-out m)
(match m
[(msg (bind x Int) discard)
(displayln x)])
;; error: msg/checked: arity mismatch
#;(msg 1 2 3)

View File

@ -1,12 +0,0 @@
#lang racket
(struct egg (size day) #:transparent)
(provide (except-out (struct-out egg)
egg-size
egg-day))
(struct chicken (eggs) #:transparent)
(provide chicken)

View File

@ -1,18 +0,0 @@
#lang typed/syndicate/roles
(require-struct egg #:as Egg #:from "lib.rkt" #:omit-accs)
(define e (egg 5 "Sun"))
(match e
[(egg $sz $d)
(displayln sz)
(displayln d)])
(require-struct chicken #:as Chicken #:from "lib.rkt" #:omit-accs)
(define c (chicken (list e e e)))
(match c
[(chicken $eggs)
(displayln eggs)])

View File

@ -1,5 +0,0 @@
#lang typed/syndicate
(require/typed "lib.rkt" [x : Int])
(displayln (+ x 1))

View File

@ -1,8 +0,0 @@
#lang typed/syndicate
(require/typed "lib.rkt"
[#:opaque Vec #:arity = 3]
[ones : (Vec Int Int Int)]
[vec+ : (→fn (Vec Int Int Int) (Vec Int Int Int) (Vec Int Int Int))])
(vec+ ones ones)

View File

@ -1,8 +0,0 @@
#lang typed/syndicate
(require/typed "lib.rkt"
[#:opaque Vec]
[ones : Vec]
[vec+ : (→fn Vec Vec Vec)])
(vec+ ones ones)

View File

@ -1,13 +0,0 @@
#lang racket
(provide ones
vec+)
(struct vec (x y z) #:transparent)
(define ones (vec 1 1 1))
(define (vec+ v1 v2)
(vec (+ (vec-x v1) (vec-x v2))
(+ (vec-y v1) (vec-y v2))
(+ (vec-z v1) (vec-z v2))))

View File

@ -1,5 +0,0 @@
#lang typed/syndicate
(require "provides.rkt")
(a-fun 5)

View File

@ -0,0 +1,57 @@
#lang typed/syndicate/roles
;; Expected Output
;; 0
;; 70
;; #f
(define-constructor (account balance)
#:type-constructor AccountT
#:with Account (AccountT Int)
#:with AccountRequest (AccountT ★/t))
(define-constructor (deposit amount)
#:type-constructor DepositT
#:with Deposit (DepositT Int)
#:with DepositRequest (DepositT ★/t))
(define-type-alias ds-type
(U Account
(Observe AccountRequest)
(Observe (Observe AccountRequest))
Deposit
(Observe DepositRequest)
(Observe (Observe DepositRequest))))
(define-type-alias account-manager-role
(Role (account-manager)
(Shares Account)
(Reacts (Know (Deposit Int)))))
(define-type-alias client-role
(Role (client)
(Reacts (Know Account))))
(run-ground-dataspace ds-type
(spawn ds-type
(print-role
(start-facet account-manager
(field [balance Int 0])
(assert (account (ref balance)))
(on (asserted (deposit (bind amount Int)))
(set! balance (+ (ref balance) amount))))))
(spawn ds-type
(print-role
(start-facet observer
(on (asserted (account (bind amount Int)))
(displayln amount)))))
(spawn ds-type
(print-role
(start-facet buyer
(on (asserted (observe (deposit discard)))
(start-facet deposits
(assert (deposit 100))
(assert (deposit -30))))))))

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
;; Expected Output
;; leader learns that there are 5 copies of The Wind in the Willows
@ -34,14 +34,14 @@
(define-type-alias τc
(U BookQuote
(Observe (BookQuoteT String ★/t))
(Observe (Observe BookQuoteT))
(Observe (Observe (BookQuoteT ★/t ★/t)))
ClubMember
(Observe ClubMemberT)
(Observe (ClubMemberT ★/t))
BookInterest
(Observe (BookInterestT String ★/t ★/t))
(Observe (Observe BookInterestT))
(Observe (Observe (BookInterestT ★/t ★/t ★/t)))
BookOfTheMonth
(Observe BookOfTheMonthT)))
(Observe (BookOfTheMonthT ★/t))))
(define-type-alias Inventory (List (Tuple String Int)))
@ -59,19 +59,17 @@
(Role (_)
;; nb no mention of retracting this assertion
(Shares (BookQuoteT String Int))))))
(export-type "seller-role.rktd" seller-role)
(define (spawn-seller [inventory : Inventory])
(spawn τc
(export-roles "seller-impl.rktd"
(lift+define-role seller-impl
(begin
(start-facet seller
(field [books Inventory inventory])
;; Give quotes to interested parties.
(during (observe (book-quote $title _))
;; TODO - lookup
(assert (book-quote title (lookup title (! books))))))))))
(assert (book-quote title (lookup title (ref books)))))))))
(define-type-alias leader-role
(Role (leader)
@ -79,16 +77,16 @@
(Role (poll)
(Reacts (Asserted (BookInterestT String String Bool))
;; this is actually implemented indirectly through dataflow
(Branch (Stop leader
(U (Stop leader
(Role (_)
(Shares (BookOfTheMonthT String))))
(Stop poll)))))))
(define-type-alias leader-actual
(Role (get-quotes)
(Role (get-quotes31)
(Reacts (Asserted (BookQuoteT String (Bind Int)))
(Stop get-quotes)
(Role (poll-members)
(Role (poll-members36)
(Reacts OnDataflow
(Stop poll-members
(Stop get-quotes))
@ -104,60 +102,59 @@
(define (spawn-leader [titles : (List String)])
(spawn τc
(export-roles "leader-impl.rktd"
(lift+define-role leader-impl
(print-role
(start-facet get-quotes
(field [book-list (List String) (rest titles)]
[title String (first titles)])
(define (next-book)
(cond
[(empty? (! book-list))
[(empty? (ref book-list))
(printf "leader fails to find a suitable book\n")
(stop get-quotes)]
[#t
(:= title (first (! book-list)))
(:= book-list (rest (! book-list)))]))
(set! title (first (ref book-list)))
(set! book-list (rest (ref book-list)))]))
;; keep track of book club members
(define/query-set members (club-member $name) name
#;#:on-add #;(printf "leader acknowledges member ~a\n" name))
(on (asserted (book-quote (! title) $quantity))
(printf "leader learns that there are ~a copies of ~a\n" quantity (! title))
(on (asserted (book-quote (ref title) $quantity))
(printf "leader learns that there are ~a copies of ~a\n" quantity (ref title))
(cond
[(< quantity (+ 1 (set-count (! members))))
[(< quantity (+ 1 (set-count (ref members))))
;; not enough in stock for each member
(next-book)]
[#t
;; find out if at least half of the members want to read the book
(start-facet poll-members
(define/query-set yays (book-interest (! title) $name #t) name)
(define/query-set nays (book-interest (! title) $name #f) name)
(on (asserted (book-interest (! title) $name _))
(define/query-set yays (book-interest (ref title) $name #t) name)
(define/query-set nays (book-interest (ref title) $name #f) name)
(on (asserted (book-interest (ref title) $name _))
;; count the leader as a 'yay'
(when (>= (set-count (! yays))
(/ (set-count (! members)) 2))
(printf "leader finds enough affirmation for ~a\n" (! title))
(when (>= (set-count (ref yays))
(/ (set-count (ref members)) 2))
(printf "leader finds enough affirmation for ~a\n" (ref title))
(stop get-quotes
(start-facet announce
(assert (book-of-the-month (! title))))))
(when (> (set-count (! nays))
(/ (set-count (! members)) 2))
(printf "leader finds enough negative nancys for ~a\n" (! title))
(assert (book-of-the-month (ref title))))))
(when (> (set-count (ref nays))
(/ (set-count (ref members)) 2))
(printf "leader finds enough negative nancys for ~a\n" (ref title))
(stop poll-members (next-book))))
;; begin/dataflow is a problem for simulation checking
#;(begin/dataflow
;; count the leader as a 'yay'
(when (>= (set-count (! yays))
(/ (set-count (! members)) 2))
(printf "leader finds enough affirmation for ~a\n" (! title))
(when (>= (set-count (ref yays))
(/ (set-count (ref members)) 2))
(printf "leader finds enough affirmation for ~a\n" (ref title))
(stop get-quotes
(start-facet announce
(assert (book-of-the-month (! title))))))
(when (> (set-count (! nays))
(/ (set-count (! members)) 2))
(printf "leader finds enough negative nancys for ~a\n" (! title))
(stop poll-members (next-book)))))])))))))
(assert (book-of-the-month (ref title))))))
(when (> (set-count (ref nays))
(/ (set-count (ref members)) 2))
(printf "leader finds enough negative nancys for ~a\n" (ref title))
(stop poll-members (next-book)))))]))))))
(define-type-alias member-role
(Role (member)
@ -170,8 +167,7 @@
(define (spawn-club-member [name : String]
[titles : (List String)])
(spawn τc
(export-roles "member-impl.rktd"
(lift+define-role member-impl
(print-role
(start-facet member
;; assert our presence
(assert (club-member name))
@ -179,7 +175,7 @@
(during (observe (book-interest $title _ _))
(define answer (member? title titles))
(printf "~a responds to suggested book ~a: ~a\n" name title answer)
(assert (book-interest title name answer))))))))
(assert (book-interest title name answer)))))))
(run-ground-dataspace τc
(spawn-seller (list (tuple "The Wind in the Willows" 5)
@ -191,19 +187,3 @@
"Encyclopaedia Brittannica"))
(spawn-club-member "tony" (list "Candide"))
(spawn-club-member "sam" (list "Encyclopaedia Brittannica" "Candide")))
(module+ test
(verify-actors (And (Eventually (A BookQuote))
(Always (Implies (A (Observe (BookQuoteT String ★/t)))
(Eventually (A BookQuote))))
(Always (Implies (A (Observe (BookInterestT String ★/t ★/t)))
(Eventually (A BookInterest)))))
leader-impl
seller-impl
member-impl))
(module+ test
(check-simulates leader-impl leader-impl)
(check-has-simulating-subgraph leader-impl leader-role)
(check-simulates seller-impl seller-impl)
(check-has-simulating-subgraph seller-impl seller-role))

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
;; adapted from section 8.3 of Tony's dissertation
@ -22,11 +22,11 @@
(Role (cell-factory)
(Reacts (Message (CreateCellT ID Value))
;; want to say that what it spawns is a Cell
(ActorWithRole ★/t Cell))))
(Spawn ★/t))))
(define-type-alias Reader
(Role (reader)
(Shares (Observe (CellT ID ★/t)))))
(Shares (Observe (Cell ID ★/t)))))
(define-type-alias Writer
(Role (writer)

View File

@ -1,6 +1,6 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(require typed/syndicate/drivers/tcp)
(require "../../drivers/tcp.rkt")
;; message
(define-constructor (speak who what)
@ -26,7 +26,8 @@
(spawn chat-ds
(start-facet chat-server
(during/spawn (tcp-connection (bind id Symbol) (tcp-listener 5999))
;; TODO - should be during/spawn
(during (tcp-connection (bind id Symbol) (tcp-listener 5999))
(assert (tcp-accepted id))
(let ([me (gensym 'user)])
(assert (present me))

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(define-constructor (file name content)
#:type-constructor FileT

View File

@ -1,8 +1,9 @@
#lang typed/syndicate
#lang typed/syndicate/roles
;; ---------------------------------------------------------------------------------------------------
;; Protocol
#|
#|
Conversations in the flink dataspace primarily concern two topics: presence and
@ -115,8 +116,7 @@ JobManager and the TaskManager, and one between the TaskManager and its
TaskRunners.
|#
;; I think this is wrong by explicitly requiring that the facet stop in response
(define-type-alias TaskAssigner-v1
(define-type-alias TaskAssigner
(Role (assign)
(Shares (Observe (TaskPerformance ID ConcreteTask ★/t)))
;; would be nice to say how the TaskIDs relate to each other
@ -124,14 +124,6 @@ TaskRunners.
(Branch (Stop assign)
(Effs)))))
(define-type-alias TaskAssigner
(Role (assign)
;; would be nice to say how the TaskIDs relate to each other
(Reacts (Asserted (TaskPerformance ID ConcreteTask TaskStateDesc))
)))
(export-type "task-assigner.rktd" TaskAssigner)
(define-type-alias TaskPerformer
(Role (listen)
(During (Observe (TaskPerformance ID ConcreteTask ★/t))
@ -161,12 +153,12 @@ The JobManager then performs the job and, when finished, asserts
(Observe (Observe (TaskPerformance ID ★/t ★/t)))
(JobManagerAlive)
(Observe (JobManagerAlive))
(Observe TaskRunner)
(Observe (TaskRunner ★/t))
(TaskManager ID Int)
(Observe TaskManager)
(Observe (TaskManager ★/t ★/t))
(JobCompletion ID (List InputTask) TaskResult)
(Observe (JobCompletion ID (List InputTask) ★/t))
(Observe (Observe JobCompletion))))
(Observe (Observe (JobCompletion ★/t ★/t ★/t)))))
;; ---------------------------------------------------------------------------------------------------
;; Util Macros
@ -178,11 +170,13 @@ The JobManager then performs the job and, when finished, asserts
(printf fmt . args)
(printf "\n")))
|#
;; ---------------------------------------------------------------------------------------------------
;; TaskRunner
#|
(define (word-count-increment [h : WordCount]
[word : String]
@ -204,9 +198,8 @@ The JobManager then performs the job and, when finished, asserts
(define (spawn-task-runner [id : ID] [tm-id : ID])
(spawn τc
(export-roles "task-runner-impl.rktd"
(lift+define-role task-runner-impl
(start-facet runner ;; #:includes-behavior TaskPerformer
(begin
(start-facet runner
(assert (task-runner id))
(on (retracted (task-manager tm-id _))
(stop runner))
@ -223,7 +216,7 @@ The JobManager then performs the job and, when finished, asserts
(set! state (finished wc))]
[(reduce-work $left $right)
(define wc (hash-union/combine left right +))
(set! state (finished wc))])))))))
(set! state (finished wc))]))))))
;; ---------------------------------------------------------------------------------------------------
;; TaskManager
@ -232,9 +225,8 @@ The JobManager then performs the job and, when finished, asserts
(define (spawn-task-manager [num-task-runners : Int])
(define id (gensym 'task-manager))
(spawn τc
(export-roles "task-manager-impl.rktd"
(#;begin lift+define-role task-manager-impl
(start-facet tm ;; #:includes-behavior TaskAssigner
(begin
(start-facet tm
(log "Task Manager (TM) ~a is running" id)
(during (job-manager-alive)
(log "TM ~a learns about JM" id)
@ -295,7 +287,7 @@ The JobManager then performs the job and, when finished, asserts
[OVERLOAD/ts
(set! status OVERLOAD/ts)]
[(finished discard)
(set! status st)]))))))))))
(set! status st)])))))))))
;; ---------------------------------------------------------------------------------------------------
;; JobManager
@ -322,10 +314,11 @@ The JobManager then performs the job and, when finished, asserts
-> (Tuple (List X) (List X))))
(define l (split-at/lenient- xs n))
(tuple (first l) (second l)))
|#
;; Task -> Bool
;; Test if the task is ready to run
(define (task-ready? [t : PendingTask] -> (Maybe ConcreteTask))
#;(define (task-ready? [t : PendingTask] -> (Maybe ConcreteTask))
(match t
[(task $tid (map-work $s))
;; having to re-produce this is directly bc of no occurrence typing
@ -337,7 +330,7 @@ The JobManager then performs the job and, when finished, asserts
none]))
(define (partition-ready-tasks [tasks : (List PendingTask)]
#;(define (partition-ready-tasks [tasks : (List PendingTask)]
-> (Tuple (List PendingTask)
(List ConcreteTask)))
(define part (inst partition/either PendingTask PendingTask ConcreteTask))
@ -350,6 +343,27 @@ The JobManager then performs the job and, when finished, asserts
(left t)]))))
(define (partition-ready-tasks [tasks : (List Int)]
-> (Tuple (List Int)
(List Int)))
(define part (inst partition/either Int Int Int))
(part tasks
(lambda ([t : Int])
(right 0)
#;(match (some 5)
[(some $ct)
(right ct)]
[none
(left 0)]))))
#;(define (debug [tasks : (List Int)] -> (Tuple (List String) (List Int)))
(define part (inst partition/either Int String Int))
(tuple (list) (list))
(part tasks
(lambda ([t : Int])
(left "hi"))))
#|
(define (input->pending-task [t : InputTask] -> PendingTask)
(match t
[(task $id (map-work $s))
@ -371,8 +385,8 @@ The JobManager then performs the job and, when finished, asserts
(define (spawn-job-manager)
(spawn τc
(lift+define-role job-manager-impl ;; export-roles "job-manager-impl.rktd"
(start-facet jm ;; #:includes-behavior TaskAssigner
(begin
(start-facet jm
(assert (job-manager-alive))
(log "Job Manager Up")
@ -471,7 +485,7 @@ The JobManager then performs the job and, when finished, asserts
;; Requires (task-ready? t)
(define ( (ρ) (perform-task [t : ConcreteTask]
[k : (proc TaskID TaskResult -> ★/t
#:effects (ρ))]))
#:roles (ρ))]))
(start-facet perform
(on start (set! tasks-in-progress (add1 (ref tasks-in-progress))))
(on stop (set! tasks-in-progress (sub1 (ref tasks-in-progress))))
@ -479,8 +493,8 @@ The JobManager then performs the job and, when finished, asserts
(log "JM begins on task ~a" this-id)
;; ID -> ...
(define ((ρ) (assign-task [mngr : ID]
[request-again! : (proc -> ★/t #:effects (ρ))]))
(define (assign-task [mngr : ID]
[request-again! : (→fn ★/t)])
(start-facet assign
(on (retracted (task-manager mngr _))
;; our task manager has crashed
@ -513,7 +527,7 @@ The JobManager then performs the job and, when finished, asserts
(on (realize (tasks-finished job-id $data:TaskResult))
(stop delegate-tasks
(start-facet done (assert (job-completion job-id tasks data)))))
(on (realize (task-is-ready job-id $t:ConcreteTask))
(on (realize (task-is-ready job-id $t))
(perform-task t push-results)))
(for ([t (in-list ready)])
(add-ready-task! t))))))))
@ -524,12 +538,10 @@ The JobManager then performs the job and, when finished, asserts
;; Job -> Void
(define (spawn-client [j : JobDesc])
(spawn τc
(export-roles "client-impl.rktd"
(lift+define-role client-impl
(start-facet _
(match-define (job $id $tasks) j)
(on (asserted (job-completion id tasks $data))
(printf "job done!\n~a\n" data)))))))
(printf "job done!\n~a\n" data)))))
;; ---------------------------------------------------------------------------------------------------
;; Main
@ -548,29 +560,4 @@ The JobManager then performs the job and, when finished, asserts
(spawn-task-manager 3)
(spawn-client (file->job "lorem.txt"))
(spawn-client (string->job INPUT)))
(module+ test
#;(verify-actors #;(Eventually (A (JobCompletion ID (List InputTask) TaskResult)))
(Always (Implies (A (Observe (JobCompletion ID (List InputTask) ★/t)))
(Eventually (A (JobCompletion ID (List InputTask) TaskResult)))))
job-manager-impl
task-manager-impl
client-impl)
(verify-actors (And (Always (Implies (A (Observe (TaskPerformance ID ConcreteTask ★/t)))
(Eventually (A (TaskPerformance ID ConcreteTask TaskStateDesc)))))
(Eventually (A (TaskPerformance ID ConcreteTask TaskStateDesc))))
TaskAssigner
TaskPerformer))
(module+ test
(check-simulates task-runner-impl task-runner-impl)
(check-has-simulating-subgraph task-runner-impl TaskPerformer)
(check-simulates task-manager-impl task-manager-impl)
(check-has-simulating-subgraph task-manager-impl TaskPerformer)
(check-has-simulating-subgraph task-manager-impl TaskAssigner)
(check-has-simulating-subgraph job-manager-impl TaskAssigner))
;; infinite loop?
#;(module+ test
(check-simulates job-manager-impl job-manager-impl))
|#

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
;; Expected Output:
#|

View File

@ -0,0 +1,20 @@
#lang typed/syndicate/roles
;; Expected Output
;; pong: 8339
(define-type-alias ds-type
(U (Message (Tuple String Int))
(Observe (Tuple String ★/t))))
(run-ground-dataspace ds-type
(spawn ds-type
(start-facet echo
(on (message (tuple "ping" (bind x Int)))
(send! (tuple "pong" x)))))
(spawn ds-type
(start-facet serve
(on start
(send! (tuple "ping" 8339)))
(on (message (tuple "pong" (bind x Int)))
(printf "pong: ~v\n" x)))))

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(provide a-fun)

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
;; Expected Output:
#|

View File

@ -1,13 +1,10 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(require-struct msg #:as Msg
#:from "driver.rkt")
(define m (msg 1 "hi"))
(msg-in m)
(msg-out m)
(match m
[(msg (bind x Int) discard)
(displayln x)])

View File

@ -0,0 +1,5 @@
#lang typed/syndicate/roles
(require/typed "lib.rkt" [x : Int])
(displayln (+ x 1))

View File

@ -0,0 +1,5 @@
#lang typed/syndicate/roles
(require "provides.rkt")
(a-fun 5)

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
;; Expected Output
;; f: 0

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(run-ground-dataspace Int
(spawn Int

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
;; Expected Output
;; +GO

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
;; Expected Output
;; adding key2 -> 88

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
;; Expected Output
;; size: 0

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
;; Expected Output
;; query: 0

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
;; Expected Output:
;; +42

View File

@ -0,0 +1,150 @@
#lang typed/syndicate/roles
;; Expected Output
;; Completed Order:
;; Catch 22
;; 10001483
;; March 9th
(define-constructor (price v)
#:type-constructor PriceT
#:with Price (PriceT Int))
(define-constructor (out-of-stock)
#:type-constructor OutOfStockT
#:with OutOfStock (OutOfStockT))
(define-type-alias QuoteAnswer
(U Price OutOfStock))
(define-constructor (quote title answer)
#:type-constructor QuoteT
#:with Quote (QuoteT String QuoteAnswer)
#:with QuoteRequest (Observe (QuoteT String ★/t))
#:with QuoteInterest (Observe (QuoteT ★/t ★/t)))
(define-constructor (split-proposal title price contribution accepted)
#:type-constructor SplitProposalT
#:with SplitProposal (SplitProposalT String Int Int Bool)
#:with SplitRequest (Observe (SplitProposalT String Int Int ★/t))
#:with SplitInterest (Observe (SplitProposalT ★/t ★/t ★/t ★/t)))
(define-constructor (order-id id)
#:type-constructor OrderIdT
#:with OrderId (OrderIdT Int))
(define-constructor (delivery-date date)
#:type-constructor DeliveryDateT
#:with DeliveryDate (DeliveryDateT String))
(define-type-alias (Maybe t)
(U t Bool))
(define-constructor (order title price id delivery-date)
#:type-constructor OrderT
#:with Order (OrderT String Int (Maybe OrderId) (Maybe DeliveryDate))
#:with OrderRequest (Observe (OrderT String Int ★/t ★/t))
#:with OrderInterest (Observe (OrderT ★/t ★/t ★/t ★/t)))
(define-type-alias ds-type
(U ;; quotes
Quote
QuoteRequest
(Observe QuoteInterest)
;; splits
SplitProposal
SplitRequest
(Observe SplitInterest)
;; orders
Order
OrderRequest
(Observe OrderInterest)))
(define-type-alias seller-role
(Role (seller)
(Reacts (Asserted (Observe (QuoteT String ★/t)))
(Role (_)
(Shares (QuoteT String Int))))))
(run-ground-dataspace ds-type
;; seller
(spawn ds-type
(start-facet _
(field [book (Tuple String Int) (tuple "Catch 22" 22)]
[next-order-id Int 10001483])
(on (asserted (observe (quote (bind title String) discard)))
(start-facet x
(on (retracted (observe (quote title discard)))
(stop x))
(define answer
(match title
["Catch 22"
(price 22)]
[_
(out-of-stock)]))
(assert (quote title answer))))
(on (asserted (observe (order (bind title String) (bind offer Int) discard discard)))
(start-facet x
(on (retracted (observe (order title offer discard discard)))
(stop x))
(let ([asking-price 22])
(if (and (equal? title "Catch 22") (>= offer asking-price))
(let ([id (ref next-order-id)])
(set! next-order-id (+ 1 id))
(assert (order title offer (order-id id) (delivery-date "March 9th"))))
(assert (order title offer #f #f))))))))
;; buyer A
(spawn ds-type
(start-facet buyer
(field [title String "Catch 22"]
[budget Int 1000])
(on (asserted (quote (ref title) (bind answer QuoteAnswer)))
(match answer
[(out-of-stock)
(stop buyer)]
[(price (bind amount Int))
(start-facet negotiation
(field [contribution Int (/ amount 2)])
(on (asserted (split-proposal (ref title) amount (ref contribution) (bind accept? Bool)))
(if accept?
(stop buyer)
(if (> (ref contribution) (- amount 5))
(stop negotiation (displayln "negotiation failed"))
(set! contribution
(+ (ref contribution) (/ (- amount (ref contribution)) 2)))))))]))))
;; buyer B
(spawn ds-type
(start-facet buyer-b
(field [funds Int 5])
(on (asserted (observe (split-proposal (bind title String) (bind price Int) (bind their-contribution Int) discard)))
(let ([my-contribution (- price their-contribution)])
(cond
[(> my-contribution (ref funds))
(start-facet decline
(assert (split-proposal title price their-contribution #f))
(on (retracted (observe (split-proposal title price their-contribution discard)))
(stop decline)))]
[#t
(start-facet accept
(assert (split-proposal title price their-contribution #t))
(on (retracted (observe (split-proposal title price their-contribution discard)))
(stop accept))
(on start
(spawn ds-type
(start-facet purchase
(on (asserted (order title price (bind order-id? (Maybe OrderId)) (bind delivery-date? (Maybe DeliveryDate))))
(match (tuple order-id? delivery-date?)
[(tuple (order-id (bind id Int)) (delivery-date (bind date String)))
;; complete!
(begin (displayln "Completed Order:")
(displayln title)
(displayln id)
(displayln date)
(stop purchase))]
[discard
(begin (displayln "Order Rejected")
(stop purchase))]))))))])))))
)

View File

@ -1,33 +0,0 @@
#lang typed/syndicate
;; Expected Output
;; +parent
;; +GO
;; +ready
;; -parent
;; -GO
;; -ready
(define-type-alias ds-type
(U (Tuple String) (Observe (Tuple ★/t))))
(run-ground-dataspace ds-type
(spawn ds-type
(start-facet parent
(assert (tuple "parent"))
(during/spawn (tuple "GO")
(assert (tuple "ready")))
(on (asserted (tuple "ready"))
(stop parent))))
(spawn ds-type
(start-facet flag
(assert (tuple "GO"))
(on (retracted (tuple "parent"))
(stop flag))))
(spawn ds-type
(start-facet obs
(during (tuple (bind s String))
(on start
(printf "+~a\n" s))
(on stop
(printf "-~a\n" s))))))

View File

@ -1,7 +0,0 @@
#lang typed/syndicate/roles
(require "typed-out.rkt")
(define c : (Cow Int) (cow 5))
(cow-moos c)

View File

@ -1,7 +0,0 @@
#lang typed/syndicate/roles
(require "struct-out.rkt")
(happy-days (happy 5))
(define classic : (Happy Int) (happy 100))

View File

@ -1,5 +0,0 @@
#lang typed/syndicate/roles
(provide (struct-out happy))
(define-constructor* (happy : Happy days))

View File

@ -1,5 +0,0 @@
#lang typed/syndicate/roles
(require-struct cow #:as Cow #:from "untyped.rkt")
(provide (struct-out cow))

View File

@ -1,5 +0,0 @@
#lang racket
(provide (struct-out cow))
(struct cow (moos) #:transparent)

View File

@ -20,14 +20,14 @@
(define-constructor (quote title answer)
#:type-constructor QuoteT
#:with Quote (QuoteT String QuoteAnswer)
#:with QuoteRequest (Observe (QuoteT String /t))
#:with QuoteInterest (Observe (QuoteT /t /t)))
#:with QuoteRequest (Observe (QuoteT String ))
#:with QuoteInterest (Observe (QuoteT )))
(define-constructor (split-proposal title price contribution accepted)
#:type-constructor SplitProposalT
#:with SplitProposal (SplitProposalT String Int Int Bool)
#:with SplitRequest (Observe (SplitProposalT String Int Int /t))
#:with SplitInterest (Observe (SplitProposalT /t /t /t /t)))
#:with SplitRequest (Observe (SplitProposalT String Int Int ))
#:with SplitInterest (Observe (SplitProposalT )))
(define-constructor (order-id id)
#:type-constructor OrderIdT
@ -40,11 +40,11 @@
(define-type-alias (Maybe t)
(U t Bool))
(define-constructor (order title price oid delivery-date)
(define-constructor (order title price id delivery-date)
#:type-constructor OrderT
#:with Order (OrderT String Int (Maybe OrderId) (Maybe DeliveryDate))
#:with OrderRequest (Observe (OrderT String Int /t /t))
#:with OrderInterest (Observe (OrderT /t /t /t /t)))
#:with OrderRequest (Observe (OrderT String Int ))
#:with OrderInterest (Observe (OrderT )))
(define-type-alias ds-type
(U ;; quotes
@ -60,87 +60,78 @@
OrderRequest
(Observe OrderInterest)))
(define-type-alias seller-role
(Role (seller)
(During (Observe (QuoteT String ★/t))
(Shares (QuoteT String QuoteAnswer)))
#;(Reacts (Asserted (Observe (QuoteT String ★/t)))
(Role (_)
;; QuoteAnswer was originally, erroneously, Int
(Shares (QuoteT String QuoteAnswer))))))
(run-ground-dataspace ds-type
(dataspace ds-type
;; seller
(spawn ds-type
(lift+define-role seller-impl
(start-facet _ ;; #:implements seller-role
(field [book (Tuple String Int) (tuple "Catch 22" 22)]
(facet _
(fields [book (Tuple String Int) (tuple "Catch 22" 22)]
[next-order-id Int 10001483])
(on (asserted (observe (quote (bind title String) discard)))
(start-facet x
(facet x
(fields)
(on (retracted (observe (quote title discard)))
(stop x))
(define answer
(stop x (begin)))
(match title
["Catch 22"
(price 22)]
[_
(out-of-stock)]))
(assert (quote title answer))))
(assert (quote title (price 22)))]
[discard
(assert (quote title (out-of-stock)))])))
(on (asserted (observe (order (bind title String) (bind offer Int) discard discard)))
(start-facet x
(facet x
(fields)
(on (retracted (observe (order title offer discard discard)))
(stop x))
(let ([asking-price 22])
(stop x (begin)))
(let [asking-price 22]
(if (and (equal? title "Catch 22") (>= offer asking-price))
(let ([id (ref next-order-id)])
(set! next-order-id (+ 1 id))
(assert (order title offer (order-id id) (delivery-date "March 9th"))))
(assert (order title offer #f #f)))))))))
(let [id (ref next-order-id)]
(begin (set! next-order-id (+ 1 id))
(assert (order title offer (order-id id) (delivery-date "March 9th")))))
(assert (order title offer #f #f))))))))
;; buyer A
(spawn ds-type
(lift+define-role buyer-a-impl
(start-facet buyer
(field [title String "Catch 22"]
(facet buyer
(fields [title String "Catch 22"]
[budget Int 1000])
(on (asserted (quote (ref title) (bind answer QuoteAnswer)))
(match answer
[(out-of-stock)
(stop buyer)]
(stop buyer (begin))]
[(price (bind amount Int))
(start-facet negotiation
(field [contribution Int (/ amount 2)])
(facet negotiation
(fields [contribution Int (/ amount 2)])
(on (asserted (split-proposal (ref title) amount (ref contribution) (bind accept? Bool)))
(if accept?
(stop buyer)
(stop buyer (begin))
(if (> (ref contribution) (- amount 5))
(stop negotiation (displayln "negotiation failed"))
(set! contribution
(+ (ref contribution) (/ (- amount (ref contribution)) 2)))))))])))))
(+ (ref contribution) (/ (- amount (ref contribution)) 2)))))))]))))
;; buyer B
(spawn ds-type
(lift+define-role buyer-b-impl
(start-facet buyer-b
(field [funds Int 5])
(facet buyer-b
(fields [funds Int 5])
(on (asserted (observe (split-proposal (bind title String) (bind price Int) (bind their-contribution Int) discard)))
(let ([my-contribution (- price their-contribution)])
(let [my-contribution (- price their-contribution)]
(cond
[(> my-contribution (ref funds))
(start-facet decline
(facet decline
(fields)
(assert (split-proposal title price their-contribution #f))
(on (retracted (observe (split-proposal title price their-contribution discard)))
(stop decline)))]
(stop decline (begin))))]
[#t
(start-facet accept
(facet accept
(fields)
(assert (split-proposal title price their-contribution #t))
(on (retracted (observe (split-proposal title price their-contribution discard)))
(stop accept))
(stop accept (begin)))
(on start
(spawn ds-type
(start-facet purchase
(facet purchase
(fields)
(on (asserted (order title price (bind order-id? (Maybe OrderId)) (bind delivery-date? (Maybe DeliveryDate))))
(match (tuple order-id? delivery-date?)
[(tuple (order-id (bind id Int)) (delivery-date (bind date String)))
@ -149,15 +140,8 @@
(displayln title)
(displayln id)
(displayln date)
(stop purchase))]
(stop purchase (begin)))]
[discard
(begin (displayln "Order Rejected")
(stop purchase))]))))))]))))))
(stop purchase (begin)))]))))))])))))
)
(module+ test
(check-simulates seller-impl seller-impl)
;; found a bug in spec, see seller-role above
(check-simulates seller-impl seller-role)
(check-simulates buyer-a-impl buyer-a-impl)
(check-simulates buyer-b-impl buyer-b-impl))

View File

@ -1,22 +0,0 @@
#lang typed/syndicate
(define (wf1)
(spawn
(with-facets
([onn (facet (assert (tuple 'on))
(on start (printf "on\n")))]
[off (facet (on (asserted (tuple 'go))
(stop off
(start onn)))
(on start (printf "off\n")))])
off)))
(run-ground-dataspace
(wf1)
(spawn (start-facet _ (assert (tuple 'go)))))
;; BAD
#;(spawn
(with-facets
[on (facet (on start (start on)))]
on))

View File

@ -12,8 +12,8 @@
(require (only-in "list.rkt" List ~List))
(require (only-in "set.rkt" Set ~Set))
(require (only-in "hash.rkt" Hash ~Hash))
(require (only-in "prim.rkt" Int Bool + #%datum))
(require (only-in "core-expressions.rkt" let unit tuple-select mk-tuple))
(require (only-in "prim.rkt" Bool + #%datum))
(require (only-in "core-expressions.rkt" let unit))
(require "maybe.rkt")
(require (postfix-in - (only-in racket/set
@ -125,64 +125,36 @@
#,body))]))
(define-typed-syntax for/fold
[(for/fold ([acc:id (~optional (~datum :)) τ-acc init] ...+)
[(for/fold ([acc:id (~optional (~datum :)) τ-acc init])
(clause:iter-clause
...)
e-body ...+)
[ init init- ( : τ-acc)] ...
#:fail-unless (all-pure? #'(init- ...)) "expression must be pure"
[ init init- ( : τ-acc)]
#:fail-unless (pure? #'init-) "expression must be pure"
#:with (clauses- ([x x- τ] ...)) (analyze-for-clauses #'(clause.parend ...))
#:do [(define num-accs (length (syntax->list #'(τ-acc ...))))]
#:with body-ty (if (= 1 num-accs)
(first (syntax->list #'(τ-acc ...)))
(type-eval #'(Tuple (~@ τ-acc ...))))
[[[x x-- : τ] ...]
[[acc acc- : τ-acc] ...] (block e-body ...) e-body-
( : body-ty)
( ν (~effs F ...))]
[[x x-- : τ] ...
[acc acc- : τ-acc] (block e-body ...) e-body-
( : τ-acc)
( ν-ep (~effs τ-ep ...))
( ν-s (~effs τ-s ...))
( ν-f (~effs τ-f ...))]
-------------------------------------------------------
[ (values->tuple #,num-accs
(for/fold- ([acc- init-] ...)
[ (for/fold- ([acc- init-])
clauses-
#,(bind-renames #'([x-- x-] ...) #`(tuple->values #,num-accs e-body-))))
( : body-ty)
( ν (F ...))]]
[(for/fold (accs ... [acc:id init] more-accs ...)
#,(bind-renames #'([x-- x-] ...) #'e-body-))
( : τ-acc)
( ν-ep (τ-ep ...))
( ν-s (τ-s ...))
( ν-f (τ-f ...))]]
[(for/fold ([acc:id init])
clauses
e-body ...+)
[ init _ ( : τ-acc)]
---------------------------------------------------
[ (for/fold (accs ... [acc τ-acc init] more-accs ...)
[ (for/fold ([acc τ-acc init])
clauses
e-body ...)]])
(define-syntax-parser tuple->values
[(_ n:nat e:expr)
(define arity (syntax-e #'n))
(cond
[(= 1 arity)
#'e]
[else
(define/with-syntax tmp (generate-temporary 'tup))
(define projections
(for/list ([i (in-range arity)])
#`(#%app- tuple-select #,i tmp)))
#`(let- ([tmp e])
(#%app- values- #,@projections))])])
#;(tuple->values 1 (tuple 0))
(define-syntax-parser values->tuple
[(_ n:nat e:expr)
(define arity (syntax-e #'n))
(cond
[(= 1 arity)
#'e]
[else
(define/with-syntax (tmp ...) (generate-temporaries (make-list arity 'values->tuple)))
#`(let-values- ([(tmp ...) e])
(#%app- mk-tuple (#%app- list- tmp ...)))])])
(define-typed-syntax (for/list (clause:iter-clause ...)
e-body ...+)
#:with (clauses- ([x x- τ] ...)) (analyze-for-clauses #'(clause.parend ...))
@ -204,17 +176,21 @@
#:with (clauses- ([x x- τ] ...)) (analyze-for-clauses #'(clause.parend ...))
[[x x-- : τ] ... (block e-body ...) e-body-
( : τ-body)
( ν (~effs F ...))]
( ν-ep (~effs τ-ep ...))
( ν-s (~effs τ-s ...))
( ν-f (~effs τ-f ...))]
----------------------------------------------------------------------
[ (for/set- clauses-
#,(bind-renames #'([x-- x-] ...) #'e-body-))
( : (Set τ-body))
( ν (F ...))])
( ν-ep (τ-ep ...))
( ν-s (τ-s ...))
( ν-f (τ-f ...))])
(define-typed-syntax (for/sum (clause ...)
e-body ...+)
----------------------------------------------------------------------
[ (for/fold ([acc Int 0])
[ (for/fold ([acc 0])
(clause ...)
(+ acc (let () e-body ...)))])
@ -231,7 +207,9 @@
#:with (clauses- ([x x- τ] ...)) (analyze-for-clauses #'(clause.parend ...))
[[x x-- : τ] ... (block e-body ...) e-body-
( : τ-body)
( ν (~effs F ...))]
( ν-ep (~effs τ-ep ...))
( ν-s (~effs τ-s ...))
( ν-f (~effs τ-f ...))]
[[res _ : τ-body] res res- ( : _)]
----------------------------------------------------------------------
[ (let- ()
@ -242,4 +220,6 @@
(some res-)
none))
( : (Maybe τ-body))
( ν (F ...))])
( ν-ep (τ-ep ...))
( ν-s (τ-s ...))
( ν-f (τ-f ...))])

View File

@ -33,20 +33,32 @@
(define-container-type Hash #:arity = 2)
(define-typed-syntax (hash (~seq key:expr val:expr) ...)
(begin-for-syntax
(define-splicing-syntax-class key-val-list
#:attributes (items)
(pattern (~seq k1 v1 rest:key-val-list)
#:attr items #`((k1 v1) #,@#'rest.items))
(pattern (~seq)
#:attr items #'())))
(define-typed-syntax (hash keys&vals:key-val-list)
#:with ((key val) ...) #'keys&vals.items
[ key key- ( : τ-k)] ...
[ val val- ( : τ-val)] ...
#:fail-unless (all-pure? #'(key- ... val- ...)) "gotta be pure"
#:with together-again (stx-flatten #'((key- val-) ...))
--------------------------------------------------
[ (#%app- hash- (~@ key val) ...) ( : (Hash (U τ-k ...) (U τ-val ...)))])
[ (#%app- hash- #,@#'together-again) ( : (Hash (U τ-k ...) (U τ-val ...)))])
(require/typed racket/base
;; don't have a type for ConsPair
#;[make-hash : ( (K V) (→fn (List (ConsPair K V)) (Hash K V)))]
[hash-set : ( (K V) (→fn (Hash K V) K V (Hash K V)))]
[hash-ref : ( (K V) (→fn (Hash K V) K V))]
;; TODO hash-ref/failure
[hash-has-key? : ( (K V) (→fn (Hash K V) K Bool))]
[hash-update : ( (K V) (→fn (Hash K V) K (→fn V V) (Hash K V)))]
;; TODO hash-update/failure
[hash-remove : ( (K V) (→fn (Hash K V) K (Hash K V)))]
[hash-map : ( (K V R) (→fn (Hash K V) (→fn K V R) (List R)))]
[hash-keys : ( (K V) (→fn (Hash K V) (List K)))]
@ -59,6 +71,7 @@
(require/typed racket/hash
[hash-union : ( (K1 V1 K2 V2) (→fn (Hash K1 V1) (Hash K2 V2) (Hash (U K1 K2) (U V1 V2))))]
;; TODO - hash-union with #:combine
)
(define- (hash-ref/failure- h k err)

View File

@ -1,13 +1,8 @@
#lang info
(define scribblings '(("scribblings/typed-syndicate.scrbl" ())))
(define compile-omit-paths
'("examples"
"tests"))
(define test-omit-paths
;; a number of the examples use SPIN for model checking which I need
;; to figure out how to get working on the package server
'("examples/"
"tests/spin/"))
'("examples/roles/chat-tcp2.rkt"))

View File

@ -3,24 +3,18 @@
(provide List
(for-syntax ~List)
list
(typed-out [[empty- : (List )] empty]
[[empty?- : ( (X) (→fn (List X) Bool))] empty?]
[[cons- : ( (X) (→fn X (List X) (List X)))] cons]
[[cons?- : ( (X) (→fn X (List X) Bool))] cons?]
(typed-out [[cons- : ( (X) (→fn X (List X) (List X)))] cons]
[[first- : ( (X) (→fn (List X) X))] first]
[[second- : ( (X) (→fn (List X) X))] second]
[[rest- : ( (X) (→fn (List X) (List X)))] rest]
[[member?- ( (X) (→fn X (List X) Bool))] member?]
[[empty?- ( (X) (→fn (List X) Bool))] empty?]
[[reverse- ( (X) (→fn (List X) (List X)))] reverse]
[[partition- ( (X) (→fn (List X) (→fn X Bool) (List X)))] partition]
[[map- ( (X Y) (→fn (→fn X Y) (List X) (List Y)))] map]
[[argmax- : ( (X) (→fn (→fn X Int) (List X) X))] argmax]
[[argmin- : ( (X) (→fn (→fn X Int) (List X) X))] argmin]
[[remove- : ( (X) (→fn X (List X) (List X)))] remove]
[[length- : ( (X) (→fn (List X) Int))] length]))
[[map- ( (X Y) (→fn (→fn X Y) (List X) (List Y)))] map]))
(require "core-types.rkt")
(require (only-in "prim.rkt" Bool Int))
(require (only-in "prim.rkt" Bool))
(require (postfix-in - racket/list))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -7,25 +7,23 @@
;; - (eventually [LTL X])
;; - (weak-until [LTL X] [LTL X])
;; - (strong-until [LTL X] [LTL X])
;; - (release [LTL X] [LTL X])
;; - (ltl-implies [LTL X] [LTL X])
;; - (ltl-and [LTL X] [LTL X])
;; - (ltl-or [LTL X] [LTL X])
;; - (ltl-and [Listof [LTL X]])
;; - (ltl-or [Listof [LTL X]])
;; - (ltl-not [LTL X])
;; - (atomic X)
;; - Bool
;; where X represents the type of atomic propositions
(struct always [p] #:prefab)
(struct eventually [p] #:prefab)
(struct atomic [p] #:prefab)
(struct weak-until [p q] #:prefab)
(struct strong-until [p q] #:prefab)
(struct release [p q] #:prefab)
(struct ltl-implies [p q] #:prefab)
(struct ltl-and [p q] #:prefab)
(struct ltl-or [p q] #:prefab)
(struct ltl-not [p] #:prefab)
(struct always [p] #:transparent)
(struct eventually [p] #:transparent)
(struct atomic [p] #:transparent)
(struct weak-until [p q] #:transparent)
(struct strong-until [p q] #:transparent)
(struct ltl-implies [p q] #:transparent)
(struct ltl-and [p q] #:transparent)
(struct ltl-or [p q] #:transparent)
(struct ltl-not [p] #:transparent)
;; [LTL X] {X -> Y} -> [LTL Y]
(define (map-atomic ltl op)
@ -39,8 +37,6 @@
(weak-until (loop p) (loop q))]
[(strong-until p q)
(strong-until (loop p) (loop q))]
[(release p q)
(release (loop p) (loop q))]
[(ltl-implies p q)
(ltl-implies (loop p) (loop q))]
[(ltl-and p q)

View File

@ -5,12 +5,9 @@
None*
Some
some
none
has?)
none)
(require "core-types.rkt")
(require "prim.rkt")
(require "core-expressions.rkt")
(define-constructor* (none* : None*))
@ -38,10 +35,3 @@
(error "some")]
[none
(error "none")]))
(define ( (X) (has? [v : (Maybe X)] [p : (→fn X Bool)] -> Bool))
(match v
[none
#f]
[(some $x)
(p x)]))

View File

@ -1,31 +1,28 @@
#lang turnstile
(provide (all-defined-out)
True False Bool
(for-syntax (all-defined-out)))
(require "core-types.rkt")
(require (rename-in racket/math [exact-truncate exact-truncate-]))
(require (postfix-in - (only-in racket/format ~a ~v)))
(require (postfix-in - (only-in racket/format ~a)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Primitives
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-base-types Zero NonZero String ByteString Symbol)
(define-type-alias Int (U Zero NonZero))
(define-base-types Int Bool String ByteString Symbol)
;; hmmm
(define-primop + (fn Int Int Int))
(define-primop - (fn Int Int Int))
(define-primop * (fn Int Int Int))
(define-primop not (fn Bool Bool))
(define-primop < (fn Int Int Bool))
(define-primop > (fn Int Int Bool))
(define-primop <= (fn Int Int Bool))
(define-primop >= (fn Int Int Bool))
(define-primop = (fn Int Int Bool))
(define-primop + ( Int Int (Computation (Value Int) (Endpoints) (Roles) (Spawns))))
(define-primop - ( Int Int (Computation (Value Int) (Endpoints) (Roles) (Spawns))))
(define-primop * ( Int Int (Computation (Value Int) (Endpoints) (Roles) (Spawns))))
(define-primop not ( Bool (Computation (Value Bool) (Endpoints) (Roles) (Spawns))))
(define-primop < ( Int Int (Computation (Value Bool) (Endpoints) (Roles) (Spawns))))
(define-primop > ( Int Int (Computation (Value Bool) (Endpoints) (Roles) (Spawns))))
(define-primop <= ( Int Int (Computation (Value Bool) (Endpoints) (Roles) (Spawns))))
(define-primop >= ( Int Int (Computation (Value Bool) (Endpoints) (Roles) (Spawns))))
(define-primop = ( Int Int (Computation (Value Bool) (Endpoints) (Roles) (Spawns))))
(define-primop even? (→fn Int Bool))
(define-primop odd? (→fn Int Bool))
(define-primop add1 (→fn Int Int))
@ -35,14 +32,12 @@
(define-primop zero? (→fn Int Bool))
(define-primop positive? (→fn Int Bool))
(define-primop negative? (→fn Int Bool))
(define-primop current-inexact-milliseconds (→fn Int))
(define-primop string=? (→fn String String Bool))
(define-primop bytes->string/utf-8 (fn ByteString String))
(define-primop string->bytes/utf-8 (fn String ByteString))
(define-primop gensym (fn Symbol Symbol))
(define-primop symbol->string (fn Symbol String))
(define-primop string->symbol (fn String Symbol))
(define-primop bytes->string/utf-8 ( ByteString (Computation (Value String) (Endpoints) (Roles) (Spawns))))
(define-primop string->bytes/utf-8 ( String (Computation (Value ByteString) (Endpoints) (Roles) (Spawns))))
(define-primop gensym ( Symbol (Computation (Value Symbol) (Endpoints) (Roles) (Spawns))))
(define-primop symbol->string ( Symbol (Computation (Value String) (Endpoints) (Roles) (Spawns))))
(define-primop string->symbol ( String (Computation (Value Symbol) (Endpoints) (Roles) (Spawns))))
(define-typed-syntax (/ e1 e2)
[ e1 e1- ( : Int)]
@ -99,35 +94,17 @@
--------------------------------------------------
[ (#%app- ~a- e- ...) ( : String)])
(define-typed-syntax (~v e ...)
[ e e- ( : τ)] ...
#:fail-unless (stx-andmap flat-type? #'(τ ...))
"expressions must be string-able"
--------------------------------------------------
[ (#%app- ~v- e- ...) ( : String)])
(define-typed-syntax (format s e ...)
[ s s- ( : String)]
[ e e- ( : τ)] ...
#:fail-unless (stx-andmap flat-type? #'(τ ...))
"expressions must be string-able"
--------------------------------------------------
[ (#%app- format- s- e- ...) ( : String)])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Basic Values
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-typed-syntax #%datum
[(_ . n:integer)
#:with T (if (zero? (syntax-e #'n)) #'Zero #'NonZero)
----------------
[ (#%datum- . n) ( : T)]]
[(_ . b:boolean)
#:with T (if (syntax-e #'b) #'True #'False)
[ (#%datum- . n) ( : Int)]]
[(_ . b:boolean)
----------------
[ (#%datum- . b) ( : T)]]
[ (#%datum- . b) ( : Bool)]]
[(_ . s:string)
----------------
[ (#%datum- . s) ( : String)]])

View File

@ -13,7 +13,6 @@
;; Role Type Data Definitions
;; a FacetName is a symbol
;; a Name is a Symbol
;; a T is one of
;; - (Role FacetName (Listof EP)), also abbreviated as just Role
@ -21,31 +20,26 @@
;; - (Sends τ)
;; - (Realizes τ)
;; - (Stop FacetName Body)
;; - (WriteField Name τ)
(struct Role (nm eps) #:prefab)
(struct Spawn (ty) #:prefab)
(struct Sends (ty) #:prefab)
(struct Realizes (ty) #:prefab)
(struct Stop (nm body) #:prefab)
(struct WriteField (nm ty) #:prefab)
(struct ReadField (nm) #:prefab)
(struct Role (nm eps) #:transparent)
(struct Spawn (ty) #:transparent)
(struct Sends (ty) #:transparent)
(struct Realizes (ty) #:transparent)
(struct Stop (nm body) #:transparent)
;; a EP is one of
;; - (Reacts D Body), describing an event handler
;; - (Shares τ), describing an assertion
;; - (Know τ), describing an internal assertion
;; - (Field Name τ), describing a field declaration
(struct Reacts (evt body) #:prefab)
(struct Shares (ty) #:prefab)
(struct Know (ty) #:prefab)
(struct Field (nm ty) #:prefab)
(struct Reacts (evt body) #:transparent)
(struct Shares (ty) #:transparent)
(struct Know (ty) #:transparent)
;; a Body describes actions carried out in response to some event, and
;; is one of
;; - T
;; - (Listof Body)
;; - (Branch (Listof Body))
(struct Branch (arms) #:prefab)
(struct Branch (arms) #:transparent)
;; a D is one of
;; - (Asserted τ), reaction to assertion
@ -57,11 +51,11 @@
;; - StartEvt, reaction to facet startup
;; - StopEvt, reaction to facet shutdown
;; - DataflowEvt, reaction to field updates
(struct Asserted (ty) #:prefab)
(struct Retracted (ty) #:prefab)
(struct Message (ty) #:prefab)
(struct Forget (ty) #:prefab)
(struct Realize (ty) #:prefab)
(struct Asserted (ty) #:transparent)
(struct Retracted (ty) #:transparent)
(struct Message (ty) #:transparent)
(struct Forget (ty) #:transparent)
(struct Realize (ty) #:transparent)
(define StartEvt 'Start)
(define StopEvt 'Stop)
(define DataflowEvt 'Dataflow)
@ -74,8 +68,8 @@
;; specified facet,
;; - (StartOf FacetName)
;; - (StopOf FacetName)
(struct StartOf (fn) #:prefab)
(struct StopOf (fn) #:prefab)
(struct StartOf (fn) #:transparent)
(struct StopOf (fn) #:transparent)
;; NOTE: because I'm adding D+ after writing a bunch of code using only D,
;; expect inconsistencies in signatures and names
@ -90,20 +84,17 @@
;; - ⋆
;; - (Base Symbol)
;; - (internal-label Symbol τ)
;; - (VarTy Name (NEListof (List τ τ))), describing an assertion endpoint
;; whose type varies depending on the type of the named field
(struct U (tys) #:prefab)
(struct Struct (nm tys) #:prefab)
(struct Observe (ty) #:prefab)
(struct List (ty) #:prefab)
(struct Set (ty) #:prefab)
(struct Hash (ty-k ty-v) #:prefab)
(struct Mk⋆ () #:prefab)
(struct internal-label (actor-id ty) #:prefab)
(struct VarTy (nm tys) #:prefab)
(struct U (tys) #:transparent)
(struct Struct (nm tys) #:transparent)
(struct Observe (ty) #:transparent)
(struct List (ty) #:transparent)
(struct Set (ty) #:transparent)
(struct Hash (ty-k ty-v) #:transparent)
(struct Mk⋆ () #:transparent)
(struct internal-label (actor-id ty) #:transparent)
;; TODO this might be a problem when used as a match pattern
(define (Mk⋆))
(struct Base (name) #:prefab)
(struct Base (name) #:transparent)
(define Int (Base 'Int))
(define String (Base 'String))
(define Bool (Base 'Bool))
@ -142,8 +133,8 @@
;; a TransitionEffect is one of
;; - (send τ)
;; - (realize τ)
(struct send (ty) #:prefab)
(struct realize (ty) #:prefab)
(struct send (ty) #:transparent)
(struct realize (ty) #:transparent)
;; a TransitionDesc is a (Hashof D+ (Setof (Listof RoleEffect)), describing the
;; possible ways an event (+/- of an assertion) can alter the facet tree.
@ -213,14 +204,13 @@
(values D txns)))
(define assertions (assertions-in-state current assertion#))
(define new-work
(for*/set ([txns (in-hash-values transitions)]
(for*/list ([txns (in-hash-values transitions)]
[txn (in-set txns)]
[st (in-value (transition-dest txn))]
#:unless (or (equal? st current)
(hash-has-key? states st)
(member st more)))
#:unless (equal? st current)
#:unless (hash-has-key? states st))
st))
(loop (append more (set->list new-work))
(loop (append more new-work)
(hash-set states current (state current transitions assertions)))]
['()
(role-graph (set (Role-nm role)) states)])))
@ -247,25 +237,24 @@
(match-define (role-graph st0 st#) rg)
(check-true (hash-has-key? st# (set 'x 'y)))))
;; a DetectedCylce is a (detected-cycle StateName (Listof TraversalStep)), as in
;; (detected-cycle start steps)
;; where path represents the sequences of states containing a cycle,
(struct detected-cycle (start steps) #:transparent)
;; a TraversalStep is a (traversal-step D StateName)
;; representing a state transition along an edge matching D to a destination state
(struct traversal-step (evt dest) #:transparent)
;; a DetectedCylce is a (List (Listof StateName) D D D), as in
;; (list path init evt D)
;; where
;; - path represents the sequences of states containing a cycle,
;; - init is the external event that initiated this activity
;; - evt is the last-taken internal event
;; - D is the edge in the graph that matched evt
;; RoleGraph Role -> (U RoleGraph DetectedCycle)
;; "Optimize" the given role graph with respect to internal events.
;; The resulting graph will have transitions of only external events.
(define (compile/internal-events rg)
(define (compile/internal-events rg role)
(match-define (role-graph st0 orig-st#) rg)
;; doing funny business with state (set) here
(define orig-st#+ (hash-set orig-st# (set) (state (set) (hash) (set))))
;; a WorkItem is a
;; (work-item TraversalStep (Listof TraversalStep) D+ (Listof D+) (Listof TransitionEffect))
;; (work-item StateName (Listof StateName) D+ (Listof D+) (Listof TransitionEffect))
;; such as (work-item from path/r to by with effs), where
;; - from is the origin state for this chain of events
;; - path/r is the list of states in the path to this point, *after* from, in reverse
@ -275,7 +264,6 @@
;; - with is a list of pending events to be processed
;; - effs are the external effects emitted on this path
(struct work-item (from path/r to by with effs) #:transparent)
(let/ec fail
(define (walk work visited st#)
(match work
@ -302,21 +290,20 @@
(set! states (hash-set states (set) (state (set) (hash) (set)))))
(role-graph new-st0 states)]
[(cons (work-item from path/r to by with effs) more-work)
(match-define (traversal-step last-evt cur-st) to)
(define prev (if (empty? path/r) from (traversal-step-dest (first path/r))))
(define prev (if (empty? path/r) from (first path/r)))
(define prev-assertions (state-assertions (hash-ref orig-st#+ prev)))
(match-define (state _ txn# cur-assertions) (hash-ref orig-st#+ cur-st))
(match-define (state _ txn# cur-assertions) (hash-ref orig-st#+ to))
(define new-state-changes (route-internal prev-assertions
cur-assertions))
(define state-changes* (for/list ([D (in-set new-state-changes)]
#:when (for/or ([D/actual (in-hash-keys txn#)])
(D<:? D D/actual)))
D))
(define started (for*/list ([fn (in-set (set-subtract cur-st prev))]
(define started (for*/list ([fn (in-set (set-subtract to prev))]
[D (in-value (StartOf fn))]
#:when (hash-has-key? txn# D))
D))
(define stopped (for*/list ([fn (in-set (set-subtract prev cur-st))]
(define stopped (for*/list ([fn (in-set (set-subtract prev to))]
[D (in-value (StopOf fn))]
#:when (hash-has-key? txn# D))
D))
@ -345,12 +332,18 @@
#:when (implies (DataflowEvt? D) (DataflowEvt? evt))
[t (in-set ts)])
(match-define (transition more-effs dest) t)
(check-for-cycle! from path/r+ evt dest fail)
(when (and (member dest path/r+)
;; TODO - cycles involving Start/Stop are tricky. Punt for now
(not (start/stop-evt? evt)))
(fail (list (cons from (reverse (cons dest path/r+)))
by
evt
D)))
(define-values (internal-effs external-effs)
(partition-transition-effects more-effs))
(work-item from
path/r+
(traversal-step evt dest)
dest
by
(append more-pending internal-effs)
(append effs external-effs)))]))
@ -368,9 +361,9 @@
(cond
[(ormap empty? induced-work)
;; this is the end of some path
(define visited+ (set-add visited cur-st))
(define visited+ (set-add visited to))
(define new-paths-work
(for*/list (#:unless (set-member? visited cur-st)
(for*/list (#:unless (set-member? visited to)
[(D txns) (in-hash txn#)]
#:when (external-evt? D)
#:unless (equal? D DataflowEvt)
@ -378,52 +371,21 @@
(match-define (transition es dst) t)
(define-values (internal-effs external-effs)
(partition-transition-effects es))
(work-item cur-st '() (traversal-step D dst) D internal-effs external-effs)))
(define new-st# (update-path st# from cur-st by effs))
(work-item to '() dst D internal-effs external-effs)))
(define new-st# (update-path st# from to by effs))
(walk (append more-work induced-work* new-paths-work) visited+ new-st#)]
[else
(walk (append more-work induced-work*) visited st#)])]))
(walk (list (work-item (set) '() (traversal-step StartEvt st0) StartEvt '() '()))
(walk (list (work-item (set) '() st0 StartEvt '() '()))
(set)
(hash))))
#|
(define input (file->value "va2.rktd"))
(define rg (compile input))
(render-to-file rg "va2.dot")
(define rgi (compile/internal-events rg))
(render-to-file rgi "va2i.dot")
|#
;; (Listof TraceStep) D StateName (DetectedCycle -> X) -> (U X Void)
;; the path is in reverse, and the final step is the pair evt/dest;
;; so their is a cycle if the sequence from the first occurrence of
;; dest in the path matches the sequence from the second occurrence to
;; the first.
(define (check-for-cycle! from path/r evt dest fail)
;; TraceStep -> Bool
(define (same-state? step) (equal? dest (traversal-step-dest step)))
;; (Listof TraceStep) -> (Values (Listof TraceStep) (Listof TraceStep))
(define (split-at-same-state steps) (splitf-at steps (compose not same-state?)))
(define-values (loop1 trail) (split-at-same-state path/r))
(when (cons? trail)
(match-define (cons prior-last trail2) trail)
(define-values (loop2 trail3) (split-at-same-state trail2))
(define last-step (traversal-step evt dest))
(when (and (cons? trail3)
(equal? (cons last-step loop1)
(cons prior-last loop2)))
(fail (detected-cycle from (reverse (cons last-step path/r)))))))
(module+ test
(test-case
"most minimal functionality for removing internal events"
;; manager role has basically nothing to it
(define m (compile manager))
(define i (compile/internal-events m))
(define i (compile/internal-events m manager))
(check-true (role-graph? i))
(check-true (simulates?/rg i m))
(check-true (simulates?/rg m i))
@ -434,7 +396,7 @@
;; because it doesn't use any internal events, it should be unaffected
(define tmr (parse-T task-runner-ty))
(define tm (compile tmr))
(define tmi (compile/internal-events tm))
(define tmi (compile/internal-events tm tmr))
(check-true (role-graph? tmi))
;; I'm not exactly sure how the two should be related via simulation :S
(check-true (simulates?/rg tmi tm)))
@ -448,15 +410,15 @@
(Realizes Int))))
(define r (parse-T cyclic))
(define rg (compile r))
(define i (run/timeout (thunk (compile/internal-events rg))))
(check-true (detected-cycle? i))
(check-match i
(detected-cycle
(== (set))
(list (traversal-step 'Start (== (set 'x)))
(traversal-step (StartOf 'x) (== (set 'x)))
(traversal-step (Realize (internal-label _ (== Int))) (== (set 'x)))
(traversal-step (Realize (internal-label _ (== Int))) (== (set 'x)))))))
(define i (run/timeout (thunk (compile/internal-events rg r))))
(check-true (list? i))
(check-equal? (length i) 4)
(match-define (list path kick-off evt edge) i)
;; the first 'x -> 'x cycle is ignored because it's a Start event
(check-equal? path (list (set) (set 'x) (set 'x) (set 'x)))
(check-equal? kick-off StartEvt)
(check-match evt (Realize (internal-label _ (== Int))))
(check-match edge (Realize (internal-label _ (== Int)))))
(test-case
"interesting internal start event"
(test-case
@ -471,7 +433,7 @@
(define r (parse-T strt))
(define rg (run/timeout (thunk (compile r))))
(check-true (role-graph? rg))
(define rgi (run/timeout (thunk (compile/internal-events rg))))
(define rgi (run/timeout (thunk (compile/internal-events rg r))))
(check-true (role-graph? rgi))
(match-define (role-graph st0 st#) rgi)
(check-equal? st0 (set 'x 'y))
@ -492,7 +454,7 @@
(Role 'y (list)))))))
(define rg (run/timeout (thunk (compile role))))
(check-true (role-graph? rg))
(define rgi (run/timeout (thunk (compile/internal-events rg))))
(define rgi (run/timeout (thunk (compile/internal-events rg role))))
(check-true (role-graph? rgi))
(define state# (role-graph-states rgi))
(check-true (hash-has-key? state# (set 'x)))
@ -509,7 +471,7 @@
(define role (run/timeout (thunk (parse-T desc))))
(define rg (run/timeout (thunk (compile role))))
(check-true (role-graph? rg))
(define rgi (run/timeout (thunk (compile/internal-events rg))))
(define rgi (run/timeout (thunk (compile/internal-events rg role))))
(check-true (role-graph? rgi))
(check-match rgi
(role-graph (== (set 'x 'y))
@ -684,8 +646,8 @@
(check-equal? sn0 (set 'seller))
(check-true (hash-has-key? seller# (set 'seller)))
(check-true (hash-has-key? seller# (set 'seller 'fulfill)))
(check-equal? (list->set (hash-keys seller#))
(set (set 'seller 'fulfill)
(check-equal? (hash-keys seller#)
(list (set 'seller 'fulfill)
(set 'seller)))
(define st0 (hash-ref seller# (set 'seller)))
(define transitions (state-transitions st0))
@ -840,12 +802,12 @@
(define seller+spawn (Role 'start (list (Reacts StartEvt (Spawn seller)))))
(define rg (run/timeout (thunk (compile seller+spawn))))
(check-true (role-graph? rg))
(define rgi (compile/internal-events rg))
(define rgi (compile/internal-events rg seller+spawn))
(check-true (role-graph? rgi))
(define srg (compile seller))
(check-true (run/timeout (thunk (simulates?/rg rg rg))))
(check-false (run/timeout (thunk (simulates?/rg rg srg))))
(check-true (run/timeout (thunk (simulates?/rg srg rg))))
(check-false (run/timeout (thunk (simulates?/rg srg rg))))
(check-true (run/timeout (thunk (simulates?/rg rgi srg))))
(check-true (run/timeout (thunk (simulates?/rg srg rgi)))))
(test-case
@ -860,7 +822,7 @@
(Role 'know (list))))))))))
(define rg (run/timeout (thunk (compile role))))
(check-true (role-graph? rg))
(define rgi (run/timeout (thunk (compile/internal-events rg))))
(define rgi (run/timeout (thunk (compile/internal-events rg role))))
(check-true (role-graph? rgi))
(define state-names (hash-keys (role-graph-states rgi)))
(for ([sn (in-list state-names)])
@ -1017,24 +979,19 @@
(for/fold ([st st])
([c (in-list children)])
(set-remove st c)))
(define-values (final-txns _)
(for/fold ([txns (set (transition '() st-))]
[pending-effs rest])
(for/fold ([txns (set (transition '() st-))])
([f-name (in-list children)])
(define stop-effs (hash-ref (hash-ref txn# f-name) (StopOf f-name)))
(define stop-effs+ (if (set-empty? stop-effs)
(set '())
stop-effs))
(define new-txns
(for*/set ([txn (in-set txns)]
[st (in-value (transition-dest txn))]
[effs* (in-set stop-effs+)]
[next-txn (in-set (loop st (append pending-effs effs*)))])
[next-txn (in-set (loop st (append effs* rest)))])
(transition (append (transition-effs txn)
(transition-effs next-txn))
(transition-dest next-txn))))
(values new-txns '())))
final-txns])])))
(transition-dest next-txn))))])])))
(module+ test
(test-case
@ -1044,61 +1001,7 @@
(set)
(facet-tree (hash) (hash))
(hash)))
(check-equal? txns (set (transition (list (realize Int) (realize String)) (set)))))
(test-case
"another bug in apply-effects"
;; was duplicating some effects
(define r #s(Role
run-a-round342
(#s(Shares
#s(Struct
RoundT
(#s(Base Symbol) #s(Base String) #s(List #s(Base String)))))
#s(Reacts
Start
#s(Role
wait364
(#s(Reacts
#s(Asserted #s(Struct LaterThanT (#s(Base Int))))
#s(Branch
((#s(Branch
((#s(Stop
run-a-round342
(#s(Role
over356
(#s(Shares
#s(Struct
ElectedT
(#s(Base String)
#s(Base String)))))))))
(#s(Stop
run-a-round342
(#s(Realizes
#s(Struct
StartRoundT
(#s(Set #s(Base String))
#s(Set #s(Base String)))))))))))
())))))))))
(define labeled-role (label-internal-events r))
(define roles# (describe-roles labeled-role))
(define ft (make-facet-tree r))
(define current (set 'wait364 'run-a-round342))
(define eff* (list
(stop 'run-a-round342)
(realize
'#s(internal-label
initial31336
#s(Struct
StartRoundT
(#s(Set #s(Base String)) #s(Set #s(Base String))))))))
(check-equal? (apply-effects eff* current ft roles#)
(set (transition
(list
(realize
'#s(internal-label
initial31336
#s(Struct StartRoundT (#s(Set #s(Base String)) #s(Set #s(Base String)))))))
(set))))))
(check-equal? txns (set (transition (list (realize Int) (realize String)) (set))))))
;; FacetTree FacetName (Setof FacetName) -> (List FacetName)
;; return the facets in names that are children of the given facet nm, ordered
@ -1615,7 +1518,6 @@
(verify g (set-add assumptions goal)))
(unless (same-on-specified-events? transitions1
transitions2
sn1
verify/with-current-assumed)
(return #f))
(return (same-on-extra-events? transitions1
@ -1642,178 +1544,6 @@
))])))
(verify (equiv st0-1 st0-2) (set)))
;; Role Role -> Bool
(define (simulates?/report-error impl spec)
(define impl-rg (compile/internal-events (compile impl)))
(define spec-rg (compile/internal-events (compile spec)))
(cond
[(detected-cycle? impl-rg)
(printf "Detected Cycle in Implementation!\n")
(describe-detected-cycle impl-rg)
#f]
[(detected-cycle? spec-rg)
(printf "Detected Cycle in Specification!\n")
(describe-detected-cycle spec-rg)
#f]
[(simulates?/rg impl-rg spec-rg)
#t]
[else
(define trace (find-simulation-counterexample impl-rg spec-rg))
(print-failing-trace trace impl-rg spec-rg)
#f]))
;; DetectedCycle -> Void
(define (describe-detected-cycle dc)
(printf "Initial State: ~a\n" (detected-cycle-start dc))
(for ([step (in-list (detected-cycle-steps dc))])
(printf " :: ~a ==> ~a\n" (D->label (traversal-step-evt step)) (traversal-step-dest step))))
;; a FailingTrace is a (failing-trace (Listof Transition) (Listof Transition) (Listof TraceStep))
(struct failing-trace (impl-path spec-path steps) #:transparent)
;; a TraceStep is one of
;; - (both-step D)
;; - (impl-step D)
;; - (spec-step D)
;; describing either both the spec and the implementation responding to an
;; event, only the implementation, or only the spec
(struct both-step (evt) #:transparent)
(struct impl-step (evt) #:transparent)
(struct spec-step (evt) #:transparent)
;; FailingTrace RoleGraph RoleGraph -> Void
(define (print-failing-trace trace impl-rg spec-rg)
(match-define (role-graph _ impl-st#) impl-rg)
(match-define (role-graph _ spec-st#) spec-rg)
(match-define (failing-trace impl-path spec-path steps) trace)
(define SEP (make-string 40 #\;))
(define (print-sep)
(newline)
(displayln SEP)
(newline))
(let loop ([steps steps]
[impl-path impl-path]
[spec-path spec-path]
;; because the path might end with an impl-step or spec-step, remember the last
;; states we've seen so we can print its assertions at the right time
[last-spec-state (transition-dest (car spec-path))]
[last-impl-state (transition-dest (car impl-path))])
(define (get-spec-dest)
(transition-dest (car spec-path)))
(define (get-impl-dest)
(transition-dest (car impl-path)))
(match steps
[(cons step more-steps)
(print-sep)
(printf "In response to event:\n")
(match step
[(or (both-step D)
(impl-step D)
(spec-step D))
(pretty-print D)])
(when (or (both-step? step) (impl-step? step))
(define impl-effs (transition-effs (car impl-path)))
(printf "Implementation steps to state:\n")
(pretty-print (get-impl-dest))
(unless (empty? impl-effs)
(printf "With Effects:\n")
(pretty-print impl-effs)))
(when (empty? more-steps)
(define impl-final (if (spec-step? step) last-impl-state (get-impl-dest)))
(printf "Implementation Assertions:\n")
(pretty-print (state-assertions (hash-ref impl-st# impl-final))))
(when (or (both-step? step) (spec-step? step))
(define spec-effs (transition-effs (car spec-path)))
(printf "Specification steps to state:\n")
(pretty-print (get-spec-dest))
(unless (empty? spec-effs)
(printf "With Effects:\n")
(pretty-print spec-effs)))
(when (empty? more-steps)
(define spec-final (if (impl-step? step) last-spec-state (get-spec-dest)))
(printf "Specification Assertions:\n")
(pretty-print (state-assertions (hash-ref spec-st# spec-final))))
(loop more-steps
(if (spec-step? step) impl-path (cdr impl-path))
(if (impl-step? step) spec-path (cdr spec-path))
(if (impl-step? step) last-spec-state (get-spec-dest))
(if (spec-step? step) last-impl-state (get-impl-dest)))]
[_
(newline)
(void)])))
;; RoleGraph RoleGraph -> Trace
;; assuming impl-rg does not simulate spec-rg, find a trace of transitions
;; (event + effects + destination assertions) demonstrating different behaviors
(define (find-simulation-counterexample impl-rg spec-rg)
(match-define (role-graph impl-st0 impl-st#) impl-rg)
(match-define (role-graph spec-st0 spec-st#) spec-rg)
;; inside loop, the each trace field is in reverse
(let loop ([work (list (failing-trace (list (transition '() impl-st0))
(list (transition '() spec-st0))
(list (both-step StartEvt))))]
#;[visited (set)])
(match work
[(cons (failing-trace impl-path/rev spec-path/rev steps/rev) more-work)
(match-define (transition impl-effs impl-dest) (car impl-path/rev))
(match-define (transition spec-effs spec-dest) (car spec-path/rev))
(define last-step (car steps/rev))
(cond
[(or (impl-step? last-step)
;; when only the implementation steps, no need to compare effects on transitions
(and (spec-step? last-step) (empty? spec-effs))
(effects-subsequence? spec-effs impl-effs))
;; cascading conds will help with development and isolating where things go wrong
(match-define (state _ impl-transition# impl-assertions) (hash-ref impl-st# impl-dest))
(match-define (state _ spec-transition# spec-assertions) (hash-ref spec-st# spec-dest))
(cond
;; n.b. internal events should be compiled away by now or this wouldn't work
[(assertion-superset? impl-assertions spec-assertions)
;; same effects and same assertions, compare transitions
;; TODO: similarity to `same-on-specified-events?`
(define spec-matching-txns
(for*/list ([(spec-D spec-txns) (in-hash spec-transition#)]
[(impl-D impl-txns) (in-hash impl-transition#)]
#:when (D<:? spec-D impl-D)
[spec-txn (in-set spec-txns)]
[impl-txn (in-set impl-txns)])
(failing-trace (cons impl-txn impl-path/rev)
(cons spec-txn spec-path/rev)
(cons (both-step spec-D) steps/rev))))
;; transitions that the spec has but the implementation doesn't respond to
;; TODO: similarity to `same-on-extra-events?`
(define impl-evts (hash-keys impl-transition#))
(define spec-extra-txns
(for*/list ([(spec-D spec-txns) (in-hash spec-transition#)]
;; TODO - this more or less assumes that *any* event matching impl-D also matches spec-evt, which I'm not sure is quite right
#:unless (for/or ([impl-evt (in-list impl-evts)])
(D<:? impl-evt spec-D))
[spec-txn (in-set spec-txns)])
(failing-trace impl-path/rev
(cons spec-txn spec-path/rev)
(cons (spec-step spec-D) steps/rev))))
;; TODO: similarity to above code
;; transitions that the implementation has that the spec doesn't respond to
(define spec-evts (hash-keys spec-transition#))
(define impl-extra-txns
(for*/list ([(impl-D impl-txns) (in-hash impl-transition#)]
;; TODO - this more or less assumes that *any* event matching impl-D also matches spec-evt, which I'm not sure is quite right
#:unless (for/or ([spec-evt (in-list spec-evts)])
(D<:? spec-evt impl-D))
[impl-txn (in-set impl-txns)])
(failing-trace (cons impl-txn impl-path/rev)
spec-path/rev
(cons (impl-step impl-D) steps/rev))))
(loop (append more-work spec-matching-txns spec-extra-txns impl-extra-txns))]
[else
;; states have different assertions
(failing-trace (reverse impl-path/rev) (reverse spec-path/rev) (reverse steps/rev))])]
[else
;; transitions have different effects
(failing-trace (reverse impl-path/rev) (reverse spec-path/rev) (reverse steps/rev))])]
[_
(error "ran out of work")])))
;; (List Role) -> (Hashof RoleName (Setof τ))
;; map each role's name to the assertions it contributes
(define (all-roles-assertions roles)
@ -1841,11 +1571,7 @@
;; as determined by the verify procedure
;; and the effects on the edge going to Y are a supersequence of the effects
;; on the edge to Y
;; and:
;; Determine if the events in transitions2 that don't have any match in transitions1, are:
;; - all effect free
;; - verify with sn1 matched to each destination
(define (same-on-specified-events? transitions1 transitions2 sn1 verify)
(define (same-on-specified-events? transitions1 transitions2 verify)
(for/and ([(D2 edges2) (in-hash transitions2)])
(define edges1
(for/fold ([agg (set)])
@ -1859,11 +1585,7 @@
(set-union agg txns1)))
(cond
[(set-empty? edges1)
;; - I think this is right, as long as the current state of the implementation
;; matches all states the spec steps to --- unless there are effects on the transition
(for/and ([txn (in-set edges2)])
(and (empty? (transition-effs txn))
(verify (equiv sn1 (transition-dest txn)))))]
#f]
[else
(define combos (make-combinations edges1 edges2))
(verify (one-of combos))])))
@ -1972,69 +1694,19 @@
(define (simulating-subgraphs impl spec)
;; assume spec doesn't have any internal events
(define spec-rg (compile spec))
(define impl-rg (compile/internal-events (compile impl)))
(define impl-rg (compile/internal-events (compile impl) impl))
(define evts (relevant-events spec-rg))
(for/list ([srg (subgraphs impl-rg evts)]
#:when (simulates?/rg srg spec-rg))
srg))
;; Role Role -> (Maybe RoleGraph)
;; try to find any subgraph of the implementation simulating the spec
;; TODO: would be nice to find the largest
(define (find-simulating-subgraph impl spec)
(define spec-rg (compile spec))
(define impl-rg (compile/internal-events (compile impl)))
(find-simulating-subgraph/rg impl-rg spec-rg))
;; RoleGraph RoleGraph -> (Maybe RoleGraph)
(define (find-simulating-subgraph/rg impl-rg spec-rg)
(define evts (relevant-events spec-rg))
(for/first ([srg (subgraphs impl-rg evts)]
#:when (simulates?/rg srg spec-rg))
srg))
;; Role Role -> Bool
(define (find-simulating-subgraph/report-error impl spec)
(define spec-rg (compile spec))
(define impl-rg (compile/internal-events (compile impl)))
(define ans (find-simulating-subgraph/rg impl-rg spec-rg))
(cond
[ans
#t]
[else
(define-values (ft sg) (find-largest-simulating-subgraph-counterexample impl-rg spec-rg))
(print-failing-trace ft impl-rg spec-rg)
#f]))
;; RoleGraph RoleGraph -> (Values FailingTrace RoleGraph)
;; assuming impl does not have any simulating subgraphs of spec
;; largest *trace*, not largest subgraph
(define (find-largest-simulating-subgraph-counterexample impl-rg spec-rg)
(define evts (relevant-events spec-rg))
(define-values (trace len rg)
(for/fold ([best-trace #f]
[best-length 0]
[best-subgraph #f])
([srg (subgraphs impl-rg evts)])
(define ft (find-simulation-counterexample srg spec-rg))
(define len (failing-trace-length ft))
;; thing >= will prefer larger graphs
(if (>= len best-length)
(values ft len srg)
(values best-trace best-length best-subgraph))))
(values trace rg))
;; FailingTrace -> Int
(define (failing-trace-length ft)
(length (failing-trace-steps ft)))
(module+ test
(test-case
"task manager has task performer subgraphs"
(define tpr (parse-T task-performer-spec))
(define tmr (parse-T task-manager-ty))
(define ans (simulating-subgraphs tmr tpr))
(check-equal? (length ans) 340)
(check-equal? (length ans) 68)
(define tprg (compile tpr))
(check-true (simulates?/rg (first ans) tprg))
(check-true (simulates?/rg (second ans) tprg))))
@ -2074,16 +1746,15 @@
(define st#
(for/hash ([st (in-list states*)])
(match-define (state _ orig-txn# assertions) (hash-ref state# st))
(define (enabled-txns D)
(define txn#
(for/hash ([D (in-hash-keys orig-txn#)]
#:when (event-enabled? D))
(define orig-txns (hash-ref orig-txn# D))
(define new-txns
(for/set ([txn (in-set orig-txns)]
#:when (set-member? states (transition-dest txn)))
txn))
(define txn#
(for*/hash ([D (in-hash-keys orig-txn#)]
#:when (event-enabled? D)
[new-txns (in-value (enabled-txns D))]
#:unless (set-empty? new-txns))
;; TODO - what if new-txns is empty?
(values D new-txns)))
(values st (state st txn# assertions))))
(for ([st0 (in-list states*)])
@ -2906,12 +2577,10 @@
"job manager reads and compiles"
(define jmr (run/timeout (thunk (parse-T job-manager-actual))))
(check-true (Role? jmr))
(define jm (run/timeout (thunk (compile jmr)) 5000))
(define jm (run/timeout (thunk (compile jmr))))
(check-true (role-graph? jm))
(define jmi (run/timeout (thunk (compile/internal-events jm)) 5000))
(check-true (role-graph? jmi))
;; TODO : times out, probably due to infinite loop
#;(check-true (run/timeout (thunk (simulates?/rg jmi jmi)) 100000))))
(define jmi (run/timeout (thunk (compile/internal-events jm jmr))))
(check-true (run/timeout (thunk (simulates?/rg jmi jmi))))))
(define task-runner-ty
'(Role
@ -3046,12 +2715,12 @@
(check-false (simulates? tm (parse-T task-performer-spec)))))
#;(module+ test
(module+ test
(test-case
"job manager subgraph(s) implement task assigner"
(define jmr (run/timeout (thunk (parse-T job-manager-actual))))
(define tar (parse-T task-assigner-spec))
(define ans (run/timeout (thunk (simulating-subgraphs jmr tar)) 4000))
(define ans (run/timeout (thunk (simulating-subgraphs jmr tar)) 1800))
(check-true (list? ans))
(check-false (empty? ans))))
@ -3321,40 +2990,7 @@
(Stop y))))))
(define r (parse-T ty))
(define rg (compile r))
(define rgi (compile/internal-events rg))
(define rgi (compile/internal-events rg r))
(render-to-file rg "before.dot")
(render-to-file rgi "after.dot")
)
(module+ test
(test-case
"regression: ok for implementation not to have edges if the current state matches"
(define a (role-graph
(set 'seller341 'during-inner343)
(hash
(set 'seller341 'during-inner343)
(state
(set 'seller341 'during-inner343)
'#hash()
(set
'#s(Observe #s(Observe #s(Struct BookQuoteT (#s(Base String) #s(Mk⋆)))))
'#s(Struct BookQuoteT (#s(Base String) #s(Base Int))))))))
(define b (role-graph
(set 'seller)
(hash
(set 'seller)
(state
(set 'seller)
(hash
'#s(Asserted #s(Observe #s(Struct BookQuoteT (#s(Base String) #s(Mk⋆)))))
(set (transition '() (set '_ 'seller))))
(set
'#s(Observe #s(Observe #s(Struct BookQuoteT (#s(Base String) #s(Mk⋆)))))))
(set '_ 'seller)
(state
(set '_ 'seller)
'#hash()
(set
'#s(Observe #s(Observe #s(Struct BookQuoteT (#s(Base String) #s(Mk⋆)))))
'#s(Struct BookQuoteT (#s(Base String) #s(Base Int))))))))
(check-true (run/timeout (thunk (simulates?/rg a b))))))

657
racket/typed/roles.rkt Normal file
View File

@ -0,0 +1,657 @@
#lang turnstile
(provide #%module-begin
#%app
(rename-out [typed-quote quote])
#%top-interaction
require only-in
;; Start dataspace programs
run-ground-dataspace
;; Types
Tuple Bind Discard
Role Reacts Shares Asserted Retracted Message OnDataflow Stop OnStart OnStop
Know Forget Realize
Branch Effs
FacetName Field ★/t
Observe Inbound Outbound Actor U
Computation Value Endpoints Roles Spawns Sends
→fn proc
;; Statements
let let* if spawn dataspace start-facet set! begin stop begin/dataflow #;unsafe-do
when unless send! realize! define
;; Derived Forms
during During
define/query-value
define/query-set
define/query-hash
define/dataflow
on-start on-stop
;; endpoints
assert know on field
;; expressions
tuple select lambda ref observe inbound outbound
Λ inst call/inst
;; making types
define-type-alias
assertion-struct
message-struct
define-constructor define-constructor*
;; values
#%datum
;; patterns
bind discard
;; primitives
(all-from-out "prim.rkt")
;; expressions
(all-from-out "core-expressions.rkt")
;; lists
(all-from-out "list.rkt")
;; sets
(all-from-out "set.rkt")
;; sequences
(all-from-out "sequence.rkt")
;; hash tables
(all-from-out "hash.rkt")
;; for loops
(all-from-out "for-loops.rkt")
;; utility datatypes
(all-from-out "maybe.rkt")
(all-from-out "either.rkt")
;; DEBUG and utilities
print-type print-role role-strings
;; Extensions
match cond
;; require & provides
require provide
submod for-syntax for-meta only-in except-in
require/typed
require-struct
)
(require "core-types.rkt")
(require "core-expressions.rkt")
(require "list.rkt")
(require "set.rkt")
(require "prim.rkt")
(require "sequence.rkt")
(require "hash.rkt")
(require "for-loops.rkt")
(require "maybe.rkt")
(require "either.rkt")
(require (prefix-in syndicate: syndicate/actor-lang))
(require (submod syndicate/actor priorities))
(require (for-meta 2 macrotypes/stx-utils racket/list syntax/stx syntax/parse racket/base))
(require macrotypes/postfix-in)
(require (for-syntax turnstile/mode))
(require turnstile/typedefs)
(require (postfix-in - racket/list))
(require (postfix-in - racket/set))
(module+ test
(require rackunit)
(require rackunit/turnstile))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Creating Communication Types
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-simple-macro (assertion-struct name:id (~datum :) Name:id (slot:id ...))
(define-constructor* (name : Name slot ...)))
(define-simple-macro (message-struct name:id (~datum :) Name:id (slot:id ...))
(define-constructor* (name : Name slot ...)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Compile-time State
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(begin-for-syntax
(define current-communication-type (make-parameter #f))
;; Type -> Mode
(define (communication-type-mode ty)
(make-param-mode current-communication-type ty))
(define (elaborate-pattern/with-com-ty pat)
(define τ? (current-communication-type))
(if τ?
(elaborate-pattern/with-type pat τ?)
(elaborate-pattern pat))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Core forms
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-typed-syntax (start-facet name:id ep ...+)
#:with name- (syntax-local-identifier-as-binding (syntax-local-introduce (generate-temporary #'name)))
#:with name+ (syntax-local-identifier-as-binding #'name)
#:with facet-name-ty (type-eval #'FacetName)
#:do [(define ctx (syntax-local-make-definition-context))
(define unique (gensym 'start-facet))
(define name-- (add-orig (internal-definition-context-introduce ctx #'name- 'add)
#'name))
(int-def-ctx-bind-type-rename #'name+ #'name- #'facet-name-ty ctx)
(define-values (ep-... τ... ep-effects facet-effects spawn-effects)
(walk/bind #'(ep ...) ctx unique))
(unless (and (stx-null? facet-effects) (stx-null? spawn-effects))
(type-error #:src #'(ep ...) #:msg "only endpoint effects allowed"))]
#:with ((~or (~and τ-a (~Shares _))
(~and τ-k (~Know _))
;; untyped syndicate might allow this - TODO
#;(~and τ-m (~Sends _))
(~and τ-r (~Reacts _ _ ...))
~MakesField)
...)
ep-effects
#:with τ (type-eval #`(Role (#,name--)
τ-a ...
τ-k ...
;; τ-m ...
τ-r ...))
--------------------------------------------------------------
[ (syndicate:react (let- ([#,name-- (#%app- syndicate:current-facet-id)])
#,@ep-...))
( : ★/t)
( ν-f (τ))])
(define-typed-syntax (field [x:id τ-f:type e:expr] ...)
#:fail-unless (stx-andmap flat-type? #'(τ-f ...)) "keep your uppity data outta my fields"
[ e e- ( : τ-f)] ...
#:fail-unless (stx-andmap pure? #'(e- ...)) "field initializers not allowed to have effects"
#:with (x- ...) (generate-temporaries #'(x ...))
#:with (τ ...) (stx-map type-eval #'((Field τ-f.norm) ...))
#:with MF (type-eval #'MakesField)
----------------------------------------------------------------------
[ (erased (field/intermediate [x x- τ e-] ...))
( : ★/t)
( ν-ep (MF))])
(define-typed-syntax (assert e:expr)
[ e e- ( : τ)]
#:fail-unless (pure? #'e-) "expression not allowed to have effects"
#:with τs (mk-Shares- #'(τ))
-------------------------------------
[ (syndicate:assert e-) ( : ★/t)
( ν-ep (τs))])
(define-typed-syntax (know e:expr)
[ e e- ( : τ)]
#:fail-unless (pure? #'e-) "expression not allowed to have effects"
#:with τs (mk-Know- #'(τ))
-------------------------------------
[ (syndicate:know e-) ( : ★/t)
( ν-ep (τs))])
(define-typed-syntax (send! e:expr)
[ e e- ( : τ)]
#:fail-unless (pure? #'e-) "expression not allowed to have effects"
#:with τm (mk-Sends- #'(τ))
--------------------------------------
[ (#%app- syndicate:send! e-) ( : ★/t)
( ν-f (τm))])
(define-typed-syntax (realize! e:expr)
[ e e- ( : τ)]
#:fail-unless (pure? #'e-) "expression not allowed to have effects"
#:with τm (mk-Realizes- #'(τ))
--------------------------------------
[ (#%app- syndicate:realize! e-) ( : ★/t)
( ν-f (τm))])
(define-typed-syntax (stop facet-name:id cont ...)
[ facet-name facet-name- ( : FacetName)]
[ (block #f cont ...) cont-
( ν-ep (~effs))
( ν-s (~effs))
( ν-f (~effs τ-f ...))]
#:with τ #'(Stop facet-name- τ-f ...)
---------------------------------------------------------------------------------
[ (syndicate:stop-facet facet-name- cont-) ( : ★/t)
( ν-f (τ))])
(begin-for-syntax
(define-syntax-class event-cons
#:attributes (syndicate-kw ty-cons)
#:datum-literals (asserted retracted message know forget realize)
(pattern (~or (~and asserted
(~bind [syndicate-kw #'syndicate:asserted]
[ty-cons #'Asserted]))
(~and retracted
(~bind [syndicate-kw #'syndicate:retracted]
[ty-cons #'Retracted]))
(~and message
(~bind [syndicate-kw #'syndicate:message]
[ty-cons #'Message]))
(~and know
(~bind [syndicate-kw #'syndicate:know]
[ty-cons #'Know]))
(~and forget
(~bind [syndicate-kw #'syndicate:forget]
[ty-cons #'Forget]))
(~and realize
(~bind [syndicate-kw #'syndicate:realize]
[ty-cons #'Realize])))))
(define-syntax-class priority-level
#:literals (*query-priority-high*
*query-priority*
*query-handler-priority*
*normal-priority*
*gc-priority*
*idle-priority*)
(pattern (~and level
(~or *query-priority-high*
*query-priority*
*query-handler-priority*
*normal-priority*
*gc-priority*
*idle-priority*))))
(define-splicing-syntax-class priority
#:attributes (level)
(pattern (~seq #:priority l:priority-level)
#:attr level #'l.level)
(pattern (~seq)
#:attr level #'*normal-priority*))
)
(define-typed-syntax on
#:datum-literals (start stop)
[(on start s ...)
[ (block s ...) s- ( ν-ep (~effs))
( ν-f (~effs τ-f ...))
( ν-s (~effs τ-s ...))]
#:with τ-r (type-eval #'(Reacts OnStart τ-f ... τ-s ...))
-----------------------------------
[ (syndicate:on-start s-) ( : ★/t)
( ν-ep (τ-r))]]
[(on stop s ...)
[ (block s ...) s- ( ν-ep (~effs))
( ν-f (~effs τ-f ...))
( ν-s (~effs τ-s ...))]
#:with τ-r (type-eval #'(Reacts OnStop τ-f ... τ-s ...))
-----------------------------------
[ (syndicate:on-stop s-) ( : ★/t)
( ν-ep (τ-r))]]
[(on (evt:event-cons p)
priority:priority
s ...)
#:do [(define msg? (free-identifier=? #'syndicate:message (attribute evt.syndicate-kw)))
(define elab
(elaborate-pattern/with-com-ty (if msg? #'(message p) #'p)))]
#:with p/e (if msg? (stx-cadr elab) elab)
[ p/e p-- ( : τp)]
#:fail-unless (pure? #'p--) "pattern not allowed to have effects"
#:with ([x:id τ:type] ...) (pat-bindings #'p/e)
[[x x- : τ] ... (block s ...) s-
( ν-ep (~effs))
( ν-f (~effs τ-f ...))
( ν-s (~effs τ-s ...))]
#:with p- (substs #'(x- ...) #'(x ...) (compile-syndicate-pattern #'p/e))
#:with τ-r (type-eval #'(Reacts (evt.ty-cons τp) τ-f ... τ-s ...))
-----------------------------------
[ (syndicate:on (evt.syndicate-kw p-)
#:priority priority.level
s-)
( : ★/t)
( ν-ep (τ-r))]])
(define-typed-syntax (begin/dataflow s ...+)
[ (block s ...) s-
( : _)
( ν-ep (~effs))
( ν-f (~effs τ-f ...))
( ν-s (~effs τ-s ...))]
#:with τ-r (type-eval #'(Reacts OnDataflow τ-f ... τ-s ...))
--------------------------------------------------
[ (syndicate:begin/dataflow s-)
( : ★/t)
( ν-ep (τ-r))])
(define-for-syntax (compile-syndicate-pattern pat)
(compile-pattern pat
#'list-
(lambda (id) #`($ #,id))
identity))
(define-typed-syntax spawn
;; TODO - do the lack of #:cut-s cause bad error messages here?
[(spawn τ-c:type s)
#:fail-unless (flat-type? #'τ-c.norm) "Communication type must be first-order"
;; TODO: check that each τ-f is a Role
#:mode (communication-type-mode #'τ-c.norm)
[
[ (block s) s- ( ν-ep (~effs)) ( ν-s (~effs)) ( ν-f (~effs τ-f ...))]
]
;; TODO: s shouldn't refer to facets or fields!
#:with (τ-i τ-o τ-i/i τ-o/i τ-a) (analyze-roles #'(τ-f ...))
#:fail-unless (<: #'τ-o #'τ-c.norm)
(format "Output ~a not valid in dataspace ~a" (type->str #'τ-o) (type->str #'τ-c.norm))
#:with τ-final (mk-Actor- #'(τ-c.norm))
#:fail-unless (<: #'τ-a #'τ-final)
"Spawned actors not valid in dataspace"
#:fail-unless (project-safe? ( (strip-? #'τ-o) #'τ-c.norm)
#'τ-i)
(string-append "Not prepared to handle inputs:\n" (make-actor-error-message #'τ-i #'τ-o #'τ-c.norm))
#:fail-unless (project-safe? ( (strip-? #'τ-o/i) #'τ-o/i) #'τ-i/i)
(string-append "Not prepared to handle internal events:\n" (make-actor-error-message #'τ-i/i #'τ-o/i #'τ-o/i))
--------------------------------------------------------------------------------------------
[ (syndicate:spawn (syndicate:on-start s-)) ( : ★/t)
( ν-s (τ-final))]]
[(spawn s)
#:do [(define τc (current-communication-type))]
#:when τc
----------------------------------------
[ (spawn #,τc s)]])
;; Type Type Type -> String
(define-for-syntax (make-actor-error-message τ-i τ-o τ-c)
(define mismatches (find-surprising-inputs τ-i τ-o τ-c))
(string-join (map type->str mismatches) ",\n"))
;; Type Type Type -> (Listof Type)
(define-for-syntax (find-surprising-inputs τ-i τ-o τ-c)
(define incoming ( (strip-? τ-o) τ-c))
;; Type -> (Listof Type)
(let loop ([ty incoming])
(syntax-parse ty
[(~U* τ ...)
(apply append (map loop (syntax->list #'(τ ...))))]
[_
(cond
[(project-safe? ty τ-i)
'()]
[else
(list ty)])])))
(define-typed-syntax (dataspace τ-c:type s ...)
#:fail-unless (flat-type? #'τ-c.norm) "Communication type must be first-order"
#:mode (communication-type-mode #'τ-c.norm)
[
[ s s- ( ν-ep (~effs)) ( ν-s (~effs τ-s ...)) ( ν-f (~effs))] ...
]
#:with τ-actor (mk-Actor- #'(τ-c.norm))
#:fail-unless (stx-andmap (lambda (t) (<: t #'τ-actor)) #'(τ-s ... ...))
"Not all actors conform to communication type"
#:with τ-ds-i (strip-inbound #'τ-c.norm)
#:with τ-ds-o (strip-outbound #'τ-c.norm)
#:with τ-relay (relay-interests #'τ-c.norm)
-----------------------------------------------------------------------------------
[ (syndicate:dataspace s- ...) ( : ★/t)
( ν-s ((Actor (U τ-ds-i τ-ds-o τ-relay))))])
(define-typed-syntax (set! x:id e:expr)
[ e e- ( : τ)]
#:fail-unless (pure? #'e-) "expression not allowed to have effects"
[ x x- ( : (~Field τ-x:type))]
#:fail-unless (<: #'τ #'τ-x) "Ill-typed field write"
----------------------------------------------------
[ (#%app- x- e-) ( : ★/t)])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Derived Forms
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-typed-syntax during
#:literals (know)
[(_ (~or (~and k (know p)) p) s ...)
#:with p+ (elaborate-pattern/with-com-ty #'p)
#:with inst-p (instantiate-pattern #'p+)
#:with start-e (if (attribute k) #'know #'asserted)
#:with stop-e (if (attribute k) #'forget #'retracted)
#:with res #'(on (start-e p+)
(start-facet during-inner
(on (stop-e inst-p)
(stop during-inner))
s ...))
----------------------------------------
[ (on (start-e p+)
(start-facet during-inner
(on (stop-e inst-p)
(stop during-inner))
s ...))]])
(define-simple-macro (During (~or (~and K ((~literal Know) τ:type)) τ:type)
EP ...)
#:with τ/inst (instantiate-pattern-type #'τ.norm)
#:with start-e (if (attribute K) #'Know #'Asserted)
#:with stop-e (if (attribute K) #'Forget #'Retracted)
(Reacts (start-e τ)
(Role (during-inner)
(Reacts (stop-e τ/inst)
(Stop during-inner))
EP ...)))
;; TODO - reconcile this with `compile-pattern`
(define-for-syntax (instantiate-pattern pat)
(let loop ([pat pat])
(syntax-parse pat
#:datum-literals (tuple discard bind)
[(tuple p ...)
#`(tuple #,@(stx-map loop #'(p ...)))]
[(k:kons1 p)
#`(k #,(loop #'p))]
[(bind x:id τ)
#'x]
;; not sure about this
[discard
#'discard]
[(~constructor-exp ctor p ...)
(define/with-syntax uctor (untyped-ctor #'ctor))
#`(ctor #,@(stx-map loop #'(p ...)))]
[_
pat])))
;; Type -> Type
;; replace occurrences of (Bind τ) with τ in a type, in much the same way
;; instantiate-pattern does for patterns
;; TODO - this is almost exactly the same as replace-bind-and-discard-with-★
(define-for-syntax (instantiate-pattern-type ty)
(syntax-parse ty
[(~Bind τ)
#'τ]
[(~U* τ ...)
(mk-U- (stx-map instantiate-pattern-type #'(τ ...)))]
[(~Any/new τ-cons τ ...)
#:when (reassemblable? #'τ-cons)
(define subitems (for/list ([t (in-syntax #'(τ ...))])
(instantiate-pattern-type t)))
(reassemble-type #'τ-cons subitems)]
[_ ty]))
(begin-for-syntax
(define-splicing-syntax-class on-add
#:attributes (expr)
(pattern (~seq #:on-add add-e)
#:attr expr #'add-e)
(pattern (~seq)
#:attr expr #'#f))
(define-splicing-syntax-class on-remove
#:attributes (expr)
(pattern (~seq #:on-remove remove-e)
#:attr expr #'remove-e)
(pattern (~seq)
#:attr expr #'#f)))
(define-typed-syntax (define/query-value x:id e0 p e
(~optional add:on-add)
(~optional remove:on-remove))
[ e0 e0- ( : τ)]
#:fail-unless (pure? #'e0-) "expression must be pure"
----------------------------------------
[ (begin (field [x τ e0-])
(on (asserted p)
#:priority *query-priority*
(set! x e)
add.expr)
(on (retracted p)
#:priority *query-priority-high*
(set! x e0-)
remove.expr))])
(define-typed-syntax (define/query-set x:id p e
(~optional add:on-add)
(~optional remove:on-remove))
#:with p+ (elaborate-pattern/with-com-ty #'p)
#:with ([y τ] ...) (pat-bindings #'p+)
;; e will be re-expanded :/
[[y y- : τ] ... e e- τ-e]
----------------------------------------
[ (begin (field [x (Set τ-e) (set)])
(on (asserted p+)
#:priority *query-priority*
(set! x (set-add (ref x) e))
add.expr)
(on (retracted p+)
#:priority *query-priority-high*
(set! x (set-remove (ref x) e))
remove.expr))])
(define-typed-syntax (define/query-hash x:id p e-key e-value
(~optional add:on-add)
(~optional remove:on-remove))
#:with p+ (elaborate-pattern/with-com-ty #'p)
#:with ([y τ] ...) (pat-bindings #'p+)
;; e-key and e-value will be re-expanded :/
;; but it's the most straightforward way to keep bindings in sync with
;; pattern
[[y y- : τ] ... e-key e-key- τ-key]
[[y y-- : τ] ... e-value e-value- τ-value]
;; TODO - this is gross, is there a better way to do this?
;; #:with e-value-- (substs #'(y- ...) #'(y-- ...) #'e-value- free-identifier=?)
;; I thought I could put e-key- and e-value-(-) in the output below, but that
;; gets their references to pattern variables out of sync with `p`
----------------------------------------
[ (begin (field [x (Hash τ-key τ-value) (hash)])
(on (asserted p+)
#:priority *query-priority*
(set! x (hash-set (ref x) e-key e-value))
add.expr)
(on (retracted p+)
#:priority *query-priority-high*
(set! x (hash-remove (ref x) e-key))
remove.expr))])
(define-simple-macro (on-start e ...)
(on start e ...))
(define-simple-macro (on-stop e ...)
(on stop e ...))
(define-typed-syntax define/dataflow
[(define/dataflow x:id τ:type e)
[ e e- ( : τ)]
#:fail-unless (pure? #'e-) "expression must be pure"
;; because the begin/dataflow body is scheduled to run at some later point,
;; the initial value is visible e.g. immediately after the define/dataflow
;; #:with place-holder (attach #'(#%datum- #f) ': #'τ.norm)
----------------------------------------
[ (begin (field [x τ e-])
(begin/dataflow (set! x e-)))]]
[(define/dataflow x:id e)
[ e e- ( : τ)]
#:fail-unless (pure? #'e-) "expression must be pure"
----------------------------------------
[ (define/dataflow x τ e-)]])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Expressions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-typed-syntax (ref x:id)
[ x x- (~Field τ)]
------------------------
[ (#%app- x-) ( : τ)])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Ground Dataspace
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; n.b. this is a blocking operation, so an actor that uses this internally
;; won't necessarily terminate.
(define-typed-syntax (run-ground-dataspace τ-c:type s ...)
;;#:fail-unless (flat-type? #'τ-c.norm) "Communication type must be first-order"
#:mode (communication-type-mode #'τ-c.norm)
[
[ s s- ( : t1)] ...
[ (dataspace τ-c.norm s- ...) _ ( : t2)]
]
-----------------------------------------------------------------------------------
[ (#%app- syndicate:run-ground s- ...) ( : (AssertionSet τ-c))])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Utilities
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-typed-syntax (print-type e)
[ e e- ( : τ) ( ν-ep (~effs eps ...)) ( ν-f (~effs fs ...)) ( ν-s (~effs ss ...))]
#:do [(pretty-display (type->strX #'τ))]
----------------------------------
[ e- ( : τ) ( ν-ep (eps ...)) ( ν-f (fs ...)) ( ν-s (ss ...))])
(define-typed-syntax (print-role e)
[ e e- ( : τ) ( ν-ep (~effs eps ...)) ( ν-f (~effs fs ...)) ( ν-s (~effs ss ...))]
#:do [(for ([r (in-syntax #'(fs ...))])
(pretty-display (type->strX r)))]
----------------------------------
[ e- ( : τ) ( ν-ep (eps ...)) ( ν-f (fs ...)) ( ν-s (ss ...))])
;; this is mainly for testing
(define-typed-syntax (role-strings e)
[ e e- ( : τ) ( ν-f (~effs fs ...))]
#:with (s ...) (for/list ([r (in-syntax #'(fs ...))])
(type->strX r))
----------------------------------------
[ (#%app- list- (#%datum- . s) ...) ( : (List String))])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Tests
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module+ test
(check-type
(spawn (U (Observe (Tuple Int ★/t)))
(start-facet echo
(on (message (tuple 1 $x))
#f)))
: ★/t)
(check-type (spawn (U (Message (Tuple String Int))
(Observe (Tuple String ★/t)))
(start-facet echo
(on (message (tuple "ping" $x))
(send! (tuple "pong" x)))))
: ★/t)
(typecheck-fail (spawn (U (Message (Tuple String Int))
(Message (Tuple String String))
(Observe (Tuple String ★/t)))
(start-facet echo
(on (message (tuple "ping" (bind x Int)))
(send! (tuple "pong" x)))))))
;; local definitions
#;(module+ test
;; these cause an error in rackunit-typechecking, don't know why :/
#;(check-type (let ()
(begin
(define id : Int 1234)
id))
: Int
-> 1234)
#;(check-type (let ()
(define (spawn-cell [initial-value : Int])
(define id 1234)
id)
(typed-app spawn-cell 42))
: Int
-> 1234)
(check-equal? (let ()
(define id : Int 1234)
id)
1234)
#;(check-equal? (let ()
(define (spawn-cell [initial-value : Int])
(define id 1234)
id)
(typed-app spawn-cell 42))
1234))

View File

@ -1,778 +0,0 @@
#lang scribble/manual
@(require (for-label (only-in racket struct)
typed/syndicate/roles)
(prefix-in racket: (for-label racket))
(prefix-in untyped: (for-label syndicate/actor)))
@title{Typed Syndicate}
@defmodule[typed/syndicate/roles]
@section{Overview}
@section{Types}
@deftogether[(@defidform[Int]
@defidform[Bool]
@defidform[String]
@defidform[ByteString]
@defidform[Symbol])]{
Base types.
}
@defform[(U type ...)]{
The type representing the union of @racket[type ...].
}
@defidform[⊥]{
An alias for @racket[(U)].
}
@defidform[★/t]{
The type representing any possible assertion, and, in an @racket[AssertionSet],
the possibility for an infinite set of assertions.
}
@defidform[Discard]{
The type of @racket[_] patterns.
}
@defform[(Bind type)]{
The type of @racket[$] patterns.
}
@defidform[FacetName]{
The type associated with identifiers bound by @racket[start-facet].
}
@defform[(Role (x) type ...)]{
The type of a facet named @racket[x] and endpoints described by @racket[type
...].
}
@defform[(Stop X type ...)]{
The type of a @racket[stop] action.
}
@defform[(Field type)]{
The type of a field containing values of @racket[type].
}
@defform[(Shares type)]{
The type of an @racket[assert] endpoint.
}
@defform[#:literals (OnStart OnStop Asserted Retracted)
(Reacts EventDesc type ...)
#:grammar
[(EventDesc (code:line OnStart)
(code:line OnStart)
(code:line (Asserted event-type))
(code:line (Retracted event-type)))]]{
The type of a @racket[on] endpoint that reacts to events described by
@racket[EventDesc] with the behavior given by @racket[type ...].
}
@deftogether[(@defidform[OnStart]
@defidform[OnStop]
@defform[(Asserted type)]
@defform[(Retracted type)])]{
See @racket[Reacts].
}
@defform[(Actor type)]{
The type of an actor that operates in a dataspace with a certain communication
@racket[type].
}
@defform[(ActorWithRole comm-type behavior-type)]{
An @racket[Actor] type with the additional @racket[behavior-type] describing the
actor's behavior in terms of a @racket[Role].
}
@defform[(Sends type)]{
The type of a @racket[send!] action.
}
@defform[(Realize type)]{
The type of a @racket[realize!] action.
}
@deftogether[(@defform[(Branch type ...)]
@defform[(Effs type ...)])]{
Types that may arise in descriptions in @racket[Role] types due to branching and
sequencing.
}
@defform[(Tuple type ...)]{
The type of @racket[tuple] expressions.
}
@defidform[Unit]{
An alias for @racket[(Tuple)].
}
@defform[(AssertionSet type)]{
The type for a set of assertions of a certain @racket[type]. Note that these are
not interoperable with the general purpose @racket[set] data structures.
}
@defform[(∀ (X ...) type)]{
Universal quantification over types.
}
@defform[#:literals (Computation Value Endpoints Roles Spawns)
(→ type ... (Computation (Value result-type)
(Endpoints ep-type ...)
(Roles role-type ...)
(Spawns spawn-type ...)))]{
The type of a function with parameters @racket[type ...] that returns @racket[result-type]. The type includes the effects of any actions performed by the function:
@itemlist[
@item{@racket[Endpoints]: includes any endpoint installation effects, such as from @racket[assert] and @racket[on].}
@item{@racket[Roles]: includes any script action effects, such as from @racket[start-facet], @racket[stop], and @racket[send!].}
@item{@racket[Spawns]: includes descriptions of any @racket[spawn] actions.}
]
}
@defform[(→fn type-in ... type-out)]{
Shorthand for a @racket[→] type with no effects.
}
@defform[(proc maybe-quantifiers type-in ... maybe-arrow type-out
maybe-endpoints
maybe-roles
maybe-spawns)
#:grammar
[(maybe-quantifiers (code:line)
(code:line #:forall (X ...)))
(maybe-arrow (code:line)
(code:line →)
(code:line ->))
(maybe-endpoints (code:line)
(code:line #:endpoints (e ...)))
(maybe-roles (code:line)
(code:line #:roles (r ...)))
(maybe-spawns (code:line)
(code:line #:spawns (s ...)))]]{
A more convenient notation for writing (potentially polymorphic) function types
with effects. Shorthand for @racket[(∀ (X ...) (→ type-in ... (Computation
(Value type-out) (Endpoints e ...) (Roles r ...) (Spawns s ...))))].
}
@deftogether[(@defform[(Computation type ...)]
@defform[(Value type)]
@defform[(Endpoints type)]
@defform[(Roles type)]
@defform[(Spawns type)])]{
See @racket[→].
}
@section{User Defined Types}
@defform*[[(define-type-alias id type)
(define-type-alias (ty-cons-id arg-id ...) type)]]{
Define @racket[id] to be the same as @racket[type], or create a type constructor
@racket[(ty-cons-id ty ...)] whose meaning is @racket[type] with references to
@racket[arg-id ...] replaced by @racket[ty ...].
}
@defform[(define-constructor (ctor-id slot-id ...)
maybe-type-ctor
maybe-alias ...)
#:grammar
[(maybe-type-ctor (code:line)
(code:line #:type-constructor type-ctor-id))
(maybe-alias (code:line)
(code:line #:with alias alias-body))]]{
Defines a container analagous to a prefab @racket[struct]. Includes accessor
functions for each @racket[slot-id]. (But not, presently, a predicate function).
When a @racket[type-ctor-id] is provided, the type of such structures is
@racket[(type-ctor-id type ...)], where each @racket[type] describes the value
of the corresponding slot. When not provided, the type constructor is named by
appending @racket["/t"] to @racket[ctor-id].
Each @racket[alias] and @racket[alias-body] creates an instance of
@racket[define-type-alias].
}
@defform[#:literals (:)
(define-constructor* (ctor-id : type-ctor-id slot-id ...)
maybe-alias ...)]{
An abbreviated form of @racket[define-constructor].
}
@defform[#:literals (:)
(assertion-struct ctor-id : type-ctor-id (slot-id ...))]{
An abbreviated form of @racket[define-constructor].
}
@defform[#:literals (:)
(message-struct ctor-id : type-ctor-id (slot-id ...))]{
An abbreviated form of @racket[define-constructor].
}
@section{Actor Forms}
@defform[(run-ground-dataspace type expr ...)]{
Starts a ground, i.e. main, dataspace of the program, with the given
communication @racket[type] and initial actors spawned by @racket[expr ...].
}
@defform[(spawn maybe-type s)
#:grammar
[(maybe-type (code:line)
(code:line type))]]{
Spawns an actor with behavior given by @racket[s]. The @racket[type] gives the
communication type of the enclosing dataspace. When absent, @racket[type] is
supplied by the nearest lexically enclosing @racket[spawn] or @racket[dataspace]
form, if any exist.
}
@defform[(dataspace type expr ...)]{
Spawns a dataspace with communication type @racket[type] as a child of the
dataspace enclosing the executing actor. The script @racket[expr ...] spawns the
initial actors of the new dataspace.
}
@defform[(start-facet id maybe-spec expr ...+)
#:grammar
[(maybe-spec (code:line)
(code:line #:implements type)
(code:line #:includes-behavior type))]]{
Start a facet with name @racket[id] and endpoints installed through the
evaluation of @racket[expr ...].
}
@defform[(stop id expr ...)]{
Terminate the facet @racket[id] with continuation script @racket[expr ...]. Any
facets started by the continuation script survive the termination of facet
@racket[id].
}
@defform[#:literals (start stop message asserted retracted _ $)
(on event-description body ...+)
#:grammar
[(event-description (code:line start)
(code:line stop)
(code:line (message pattern))
(code:line (asserted pattern))
(code:line (retracted pattern)))
(pattern (code:line _)
(code:line ($ id type))
(code:line ($ id))
(code:line $id)
(code:line $id:type)
(code:line (ctor pattern ...))
(code:line expr))]]{
Creates an event handler endpoint that responds to the event specified by
@racket[event-description]. Executes the @racket[body ...] for each matching
event, with any pattern variables bound to their matched value.
Patterns have the following meanings:
@itemlist[
@item{@racket[_] matches anything.}
@item{@racket[($ id type)] matches any value and binds it to @racket[id] with
assumed type @racket[type].}
@item{@racket[($ id)] is like @racket[($ id type)], but attempts to use the
current communication type to fill in the @racket[type] of potential matches.
May raise an error if no suitable communication type is in scope.}
@item{@racket[(? pred pattern)] matches values where @racket[(pred val)] is not
@racket[#f] and that match @racket[pattern].}
@item{@racket[$id:type] is shorthand for @racket[($ id type)].}
@item{@racket[$id] is shorthand for @racket[($ id)].}
@item{@racket[(ctor pat ...)] matches values built by applying the constructor
@racket[ctor] to values matching @racket[pat ...]. @racket[ctor] is usually
a @racket[struct] name.}
@item{@racket[expr] patterns match values that are @racket[equal?] to
@racket[expr].}
]
}
@defform[(on-start expr ...+)]{
Shorthand for @racket[(on start expr ...)].
}
@defform[(on-stop expr ...+)]{
Shorthand for @racket[(on stop expr ...)].
}
@defform[(assert expr)]{
Creates an assertion endpoint with the value of @racket[expr].
}
@defform[(know expr)]{
Creates an internal assertion endpoint with the value of @racket[expr].
}
@defform[(send! expr)]{
Broadcast a dataspace message with the value of @racket[expr].
}
@defform[(realize! expr)]{
Broadcast an actor-internal message with the value of @racket[expr].
}
@defform[#:literals (:)
(field [id maybe-type expr] ...)
#:grammar
[(maybe-type (code:line)
(code:line type)
(code:line : type))]]{
Defines fields of type @racket[type] with names @racket[id] and initial values
@racket[expr]. If @racket[type] is not provided, the type of the initial
expression is used as the type of the field.
}
@defform[(ref id)]{
Reference the @racket[field] named @racket[id].
}
@defform[(set! id expr)]{
Update the value the @racket[field] named @racket[id].
}
@defform[(begin/dataflow expr ...+)]{
Evaluate and perform the script @racket[expr ...], and then again each time a
field referenced by the script updates.
}
@defform[(during pattern expr ...+)]{
Engage in behavior for the duration of a matching assertion. The syntax of
@racket[pattern] is the same as described by @racket[on].
}
@defform[(during/spawn pattern expr ...+)]{
Like @racket[during], but spawns an actor for the behavior @racket[expr ...].
}
@defform[(define/query-value name absent-expr pattern expr
maybe-on-add
maybe-on-remove)
#:grammar
[(maybe-on-add (code:line)
(code:line #:on-add on-add-expr))
(maybe-on-remove (code:line)
(code:line #:on-remove on-remove-expr))]]{
Equivalent to the untyped @racket[untyped:define/query-value]. The
@racket[on-add-expr] and @racket[on-remove-expr], when given, execute after
@racket[name] has been updated.
}
@defform[(define/query-set name pattern expr
maybe-on-add
maybe-on-remove)
#:grammar
[(maybe-on-add (code:line)
(code:line #:on-add on-add-expr))
(maybe-on-remove (code:line)
(code:line #:on-remove on-remove-expr))]]{
Equivalent to the untyped @racket[untyped:define/query-set].
}
@defform[(define/query-hash name pattern key-expr value-expr
maybe-on-add
maybe-on-remove)
#:grammar
[(maybe-on-add (code:line)
(code:line #:on-add on-add-expr))
(maybe-on-remove (code:line)
(code:line #:on-remove on-remove-expr))]]{
Equivalent to the untyped @racket[untyped:define/query-hash].
}
@defform[(define/dataflow name maybe-type expr)
#:grammar
[(maybe-type (code:line)
(code:line type))]]{
Define a @racket[field] named @racket[name], whose value is reevaluated to the
result of @racket[expr] each time any referenced field changes. When
@racket[type] is not supplied, the field has the type of the given
@racket[expr].
}
@section{Expressions}
@defform*[#:literals (:)
[(ann expr : type)
(ann expr type)]]{
Ensure that @racket[expr] has the given @racket[type].
}
@defform[(if test-expr then-expr else-expr)]{
The same as Racket's @racket[racket:if].
}
@deftogether[(@defform[(cond [test-expr body-expr ...+] ...+)]
@defthing[else Bool #:value #t])]{
Like Racket's @racket[racket:cond].
}
@defform[(when test-expr expr)]{
Like Racket's @racket[racket:when], but results in @racket[#f] when
@racket[test-expr] is @racket[#f].
}
@defform[(unless test-expr expr)]{
Like Racket's @racket[racket:unless], but results in @racket[#f] when
@racket[test-expr] is @racket[#f].
}
@defform[(let ([id expr] ...) body ...+)]{
The same as Racket's @racket[racket:let].
}
@defform[(let* ([id expr] ...) body ...+)]{
The same as Racket's @racket[racket:let*].
}
@defform[#:literals (:)
(lambda ([x opt-: type] ...) expr ...+)
#:grammar
[(opt-: (code:line)
(code:line :))]]{
Constructsa an anonymous function.
}
@defidform[λ]{Synonym for @racket[lambda].}
@defform[(Λ (X ...) expr)]{
Parametric abstraction over type variables @racket[X ...].
}
@defform[(inst expr type ...)]{
Instantiates the type variables @racket[X ...] with @racket[type ...], where
@racket[expr] has type @racket[(∀ (X ...) t)].
}
@defform*[#:literals (: → -> ∀)
[(define id : type expr)
(define id expr)
(define (id [arg-id opt-: arg-type] ... opt-res-ty) expr ...+)
(define (∀ (X ...) (id [arg-id opt-: arg-type] ... opt-res-ty)) expr ...+)]
#:grammar
[(opt-: (code:line) (code:line :))
(opt-res-ty (code:line)
(code:line arr res-type))
(arr (code:line →) (code:line ->))]]{
Define a constant or a (potentially polymorphic) function. Note that the
function name @racket[id] is @emph{not} bound in the body.
}
@defform[(define-tuple (id ...) expr)]{
Define @racket[id ...] to each of the slots of the tuple produced by
@racket[expr].
}
@defform[(match-define pattern expr)]{
Define the binders of @racket[pattern] to the matching values of @racket[expr].
}
@defform[(begin expr ...+)]{
Sequencing form whose value and type is that of the final @racket[expr].
}
@defform[(block expr ...+)]{
Like @racket[begin], but also introduces a definition context for its body.
}
@defform[(match expr [pattern body-expr ...+] ...+)]{
Like Racket's @racket[racket:match] but with the pattern syntax described by
@racket[on].
}
@defform[(tuple expr ...)]{
Constructs a tuple of arbitrary arity.
}
@defform[(select i expr)]{
Extract the @racket[i]th element of a @racket[tuple].
}
@defthing[unit Unit #:value (tuple)]
@defform[(error format-expr arg-expr ...)]{
Raises an exception using @racket[format-expr] as a format string together with
@racket[arg-expr ...].
}
@deftogether[(
@defthing[+ (→fn Int Int Int)]
@defthing[- (→fn Int Int Int)]
@defthing[* (→fn Int Int Int)]
@defthing[< (→fn Int Int Bool)]
@defthing[> (→fn Int Int Bool)]
@defthing[<= (→fn Int Int Bool)]
@defthing[>= (→fn Int Int Bool)]
@defthing[= (→fn Int Int Bool)]
@defthing[even? (→fn Int Bool)]
@defthing[odd? (→fn Int Bool)]
@defthing[add1 (→fn Int Int)]
@defthing[sub1 (→fn Int Int)]
@defthing[max (→fn Int Int Int)]
@defthing[min (→fn Int Int Int)]
@defthing[zero? (→fn Int Bool)]
@defthing[positive? (→fn Int Bool)]
@defthing[negative? (→fn Int Bool)]
@defthing[current-inexact-milleseconds? (→fn Int)]
@defthing[string=? (→fn String String Bool)]
@defthing[bytes->string/utf-8 (→fn ByteString String)]
@defthing[string->bytes/utf-8 (→fn String ByteString)]
@defthing[gensym (→fn Symbol Symbol)]
@defthing[symbol->string (→fn Symbol String)]
@defthing[string->symbol (→fn String Symbol)]
@defthing[not (→fn Bool Bool)]
@defform[(/ e1 e2)]
@defform[(and e ...)]
@defform[(or e ...)]
@defform[(equal? e1 e2)]
@defform[(displayln e)]
@defform[(printf fmt-expr val-expr ...)]
@defform[(~a e ...)]
)]{
Primitive operations imported from Racket.
}
@defform[#:literals (:)
(for/fold ([acc-id maybe-:ty acc-expr] ...+)
(for-clause ...)
body-expr ...+)
#:grammar
[(maybe-:ty (code:line)
(code:line : acc-type))
(for-clause (code:line [id seq-expr])
(code:line [id : type seq-expr])
(code:line [(k-id v-id) hash-expr])
(code:line #:when test-expr)
(code:line #:unless test-expr)
(code:line #:break test-expr))]]{
Similar to Racket's @racket[racket:for/fold].
When more than one @racket[acc-id] is used, the body of the loop must evaluate
to a @racket[tuple] with one value for each accumulator, with the final tuple
also being the result of the entire expression.
Each @racket[seq-expr] should be of type @racket[Sequence], though expressions
of type @racket[List] and @racket[Set] are automatically converted.
}
@deftogether[(
@defform[(for/list (for-clause ...) body ...+)]
@defform[(for/set (for-clause ...) body ...+)]
@defform[(for/sum (for-clause ...) body ...+)]
@defform[(for (for-clause ...) body ...+)]
@defform[(for/first (for-clause ...) body ...+)]
)]{
Like their Racket counterparts. See @racket[for/fold] for the description of
@racket[for-clause].
Unlike @racket[racket:for/first], @racket[for/first] returns a @racket[Maybe]
value to indicate success/failure.
}
@section{Require & Provide}
@defform[(struct-out ctor-id)]{
}
@subsection{Requiring From Outside Typed Syndicate}
@defform[#:literals (:)
(require/typed lib clause ...)
#:grammar
[(clause (code:line [id : type])
(code:line opaque))
(opaque (code:line [#:opaque type-name])
(code:line [#:opaque type-name #:arity op arity-nat]))
(opaque (code:line =) (code:line >) (code:line >=))]]{
Import and assign types to bindings from outside Typed Syndicate.
Note that @emph{unlike} Typed Racket, Typed Syndicate does not attach contracts
to imported bindings.
An @racket[#:opaque] declaration defines a type @racket[type-name] (or, in the
@racket[#:arity] case, a type constructor) that may be used to describe imports
but otherwise has no other operations.
}
@defform[(require-struct ctor-id #:as ty-ctor-id #:from lib maybe-omit-accs)
#:grammar
[(maybe-omit-accs (code:line)
(code:line #:omit-accs))]]{
Import a Racket @racket[struct] named @racket[ctor-id] and create a type
constructor @racket[ty-ctor-id] for its instances.
Unless @racket[#:omit-accs] is specified, defines the accessor functions for the
struct.
}
@section{Builtin Data Structures}
@deftogether[(@defstruct[observe ([claim any?]) #:omit-constructor]
@defform[(Observe type)])]{
Constructs an assertion of interest.
}
@deftogether[(@defstruct[inbound ([assertion any?]) #:omit-constructor]
@defform[(Inbound type)])]{
Constructor for an assertion inbound from an outer dataspace.
}
@deftogether[(@defstruct[outbound ([assertion any?]) #:omit-constructor]
@defform[(Outbound type)])]{
Constructor for an assertion outbound to an outer dataspace.
}
@deftogether[(@defstruct[message ([body any?]) #:omit-constructor]
@defform[(Message type)])]{
Constructor for a broadcast message.
}
@subsection{Lists}
@defform[(List type)]{
The type for @racket[cons] lists whose elements are of type @racket[type].
}
@deftogether[(
@defthing[empty (List ⊥)]
@defthing[empty? (∀ (X) (→fn (List X) Bool))]
@defthing[cons (∀ (X) (→fn X (List X) (List X)))]
@defthing[cons? (∀ (X) (→fn X (List X) Bool))]
@defthing[first (∀ (X) (→fn (List X) X))]
@defthing[second (∀ (X) (→fn (List X) X))]
@defthing[rest (∀ (X) (→fn (List X) (List X)))]
@defthing[member? (∀ (X) (→fn X (List X) Bool))]
@defthing[reverse (∀ (X) (→fn (List X) (List X)))]
@defthing[partition (∀ (X) (→fn (List X) (→fn X Bool) (List X)))]
@defthing[map (∀ (X Y) (→fn (→fn X Y) (List X) (List Y)))]
@defthing[argmax (∀ (X) (→fn (→fn X Int) (List X) X))]
@defthing[argmin (∀ (X) (→fn (→fn X Int) (List X) X))]
@defthing[remove (∀ (X) (→fn X (List X) (List X)))]
@defthing[length (∀ (X) (→fn (List X) Int))]
@defform[(list e ...)]
)]{
Like their Racket counterparts.
}
@subsection{Sets}
@defform[(Set type)]{
The type for sets whose elements are of type @racket[type].
}
@deftogether[(
@defform[(set e ...)]
@defform[(set-union st ...+)]
@defform[(set-intersect st ...+)]
@defform[(set-subtract st ...+)]
@defthing[set-first (∀ (X) (→fn (Set X) X))]
@defthing[set-empty? (∀ (X) (→fn (Set X) Bool))]
@defthing[set-count (∀ (X) (→fn (Set X) Int))]
@defthing[set-add (∀ (X) (→fn (Set X) X (Set X)))]
@defthing[set-remove (∀ (X) (→fn (Set X) X (Set X)))]
@defthing[set-member? (∀ (X) (→fn (Set X) X Bool))]
@defthing[list->set (∀ (X) (→fn (List X) (Set X)))]
@defthing[set->list (∀ (X) (→fn (Set X) (List X)))]
)]{
Like their Racket counterparts.
}
@subsection{Hashes}
@defform[(Hash key-type value-type)]{
The type for key/value hash tables.
}
@deftogether[(
@defform[(hash key val ... ...)]
@defthing[hash-set (∀ (K V) (→fn (Hash K V) K V (Hash K V)))]
@defthing[hash-ref (∀ (K V) (→fn (Hash K V) K V))]
@defthing[hash-ref/failure (∀ (K V) (→fn (Hash K V) K V V))]
@defthing[hash-empty? (∀ (K V) (→fn (Hash K V) Bool))]
@defthing[hash-has-key? (∀ (K V) (→fn (Hash K V) K Bool))]
@defthing[hash-count (∀ (K V) (→fn (Hash K V) Int))]
@defthing[hash-update (∀ (K V) (→fn (Hash K V) K (→fn V V) (Hash K V)))]
@defthing[hash-update/failure (∀ (K V) (→fn (Hash K V) K (→fn V V) V (Hash K V)))]
@defthing[hash-remove (∀ (K V) (→fn (Hash K V) K (Hash K V)))]
@defthing[hash-map (∀ (K V R) (→fn (Hash K V) (→fn K V R) (List R)))]
@defthing[hash-keys (∀ (K V) (→fn (Hash K V) (List K)))]
@defthing[hash-values (∀ (K V) (→fn (Hash K V) (List V)))]
@defthing[hash-union (∀ (K1 V1 K2 V2) (→fn (Hash K1 V1) (Hash K2 V2) (Hash (U K1 K2) (U V1 V2))))]
@defthing[hash-union/combine (∀ (K V) (→fn (Hash K V) (Hash K V) (→fn V V V) (Hash K V)))]
@defthing[hash-keys-subset? (∀ (K1 V1 K2 V2) (→fn (Hash K1 V1) (Hash K2 V2) Bool))]
)]{
Like their Racket counterparts. The /failure and /combine suffixes are in place
of keyword arguments, which Typed Syndicate does not presently support.
}
@subsection{Sequences}
@defform[(Sequence type)]{
The type for a sequence of @racket[type] values.
}
@deftogether[(
@defthing[empty-sequence (Sequence ⊥)]
@defthing[sequence->list (∀ (X) (→fn (Sequence X) (List X)))]
@defthing[sequence-length (∀ (X) (→fn (Sequence X) Int))]
@defthing[sequence-ref (∀ (X) (→fn (Sequence X) Int Int))]
@defthing[sequence-tail (∀ (X) (→fn (Sequence X) Int (Sequence X)))]
@defthing[sequence-append (∀ (X) (→fn (Sequence X) (Sequence X) (Sequence X)))]
@defthing[sequence-map (∀ (A B) (→fn (→fn A B) (Sequence A) (Sequence B)))]
@defthing[sequence-andmap (∀ (X) (→fn (→fn X Bool) (Sequence X) Bool))]
@defthing[sequence-ormap (∀ (X) (→fn (→fn X Bool) (Sequence X) Bool))]
@defthing[sequence-fold (∀ (A B) (→fn (→fn A B A) (Sequence B) A))]
@defthing[sequence-count (∀ (X) (→fn (→fn X Bool) (Sequence X) Int))]
@defthing[sequence-filter (∀ (X) (→fn (→fn X Bool) (Sequence X) (Sequence X)))]
@defthing[sequence-add-between (∀ (X) (→fn (Sequence X) X (Sequence X)))]
@defthing[in-list (∀ (X) (→fn (List X) (Sequence X)))]
@defthing[in-hash-keys (∀ (K V) (→fn (Hash K V) (Sequence K)))]
@defthing[in-hash-values (∀ (K V) (→fn (Hash K V) (Sequence V)))]
@defthing[in-range (→fn Int (Sequence Int))]
@defthing[in-set (∀ (X) (→fn (Set X) (Sequence X)))]
)]{
Like their Racket counterparts.
}
@subsection{Maybe}
@deftogether[(
@defidform[None]
@defthing[none None]
@defstruct[some ([v any?]) #:omit-constructor]
@defform[(Some type)]
@defform[(Maybe type)]
)]{
@racket[(Maybe type)] is an alias for @racket[(U None (Some type))].
}
@subsection{Either}
@deftogether[(
@defstruct[left ([v any?]) #:omit-constructor]
@defform[(Left type)]
@defstruct[right ([v any?]) #:omit-constructor]
@defform[(Right type)]
@defform[(Either left-type right-type)]
)]{
@racket[(Either left-type right-type)] is an alias for @racket[(U (Left
left-type) (Right right-type))].
}
@defthing[partition/either (∀ (X Y Z) (→fn (List X) (→fn X (Either Y Z)) (Tuple (List Y) (List Z))))]{
Partition a list based on a function that returns an @racket[Either] value.
}
@section{Behavioral Checking}

View File

@ -17,15 +17,12 @@
sequence-add-between
in-list
in-set
in-hash-keys
in-hash-values
in-range
)
(require "core-types.rkt")
(require (only-in "list.rkt" List))
(require (only-in "set.rkt" Set))
(require (only-in "hash.rkt" Hash))
(require (only-in "prim.rkt" Int Bool))
#;(require (postfix-in - racket/sequence))
@ -53,8 +50,25 @@
(require/typed racket/base
[in-list : ( (X) (→fn (List X) (Sequence X)))]
[in-hash-keys : ( (K V) (→fn (Hash K V) (Sequence K)))]
[in-hash-values : ( (K V) (→fn (Hash K V) (Sequence V)))]
[in-range : (→fn Int (Sequence Int))])
(require/typed racket/set
[in-set : ( (X) (→fn (Set X) (Sequence X)))])
#;(define-typed-syntax empty-sequence
[_
--------------------
[ empty-sequence- ( : (Sequence (U)))]])
;; er, this is making everything a macro, as opposed to a procedure...
;; think I ought to add polymorphous first :\
#;(define-typed-syntax (sequence->list s)
[ s s- ( : (~Sequence τ))]
#:fail-unless (pure? #'s-)
------------------------------
[ (sequence->list- s-) ( : (List τ))])
#;(define-typed-syntax (sequence-length s)
[ s s- ( : (~Sequence τ))]
#:fail-unless (pure? #'s-)
------------------------------
[ (sequence-length- s-) ( : Int)])

View File

@ -3,28 +3,23 @@
(provide Set
(for-syntax ~Set)
set
;; set-member?
;; set-add
;; set-remove
;; set-count
set-member?
set-add
set-remove
set-count
set-union
set-subtract
set-intersect
;; list->set
;; set->list
(typed-out [[set-first- : ( (X) (→fn (Set X) X))] set-first]
[[set-empty?- : ( (X) (→fn (Set X) Bool))] set-empty?]
[[set-count- : ( (X) (→fn (Set X) Int))] set-count]
[[set-add- : ( (X) (→fn (Set X) X (Set X)))] set-add]
[[set-remove- : ( (X) (→fn (Set X) X (Set X)))] set-remove]
[[set-member?- : ( (X) (→fn (Set X) X Bool))] set-member?]
[[list->set- : ( (X) (→fn (List X) (Set X)))] list->set]
[[set->list- : ( (X) (→fn (Set X) (List X)))] set->list]
))
list->set
set->list
(typed-out [[set-first- : ( (X) (→fn (Set X) X))]
set-first]
[[set-empty?- : ( (X) (→fn (Set X) Bool))]
set-empty?]))
(require "core-types.rkt")
(require (only-in "prim.rkt" Int Bool))
(require (only-in "list.rkt" ~List List))
(require (only-in "list.rkt" ~List))
(require (postfix-in - racket/set))
@ -40,6 +35,38 @@
---------------
[ (#%app- set- e- ...) (Set (U τ ...))])
(define-typed-syntax (set-count e)
[ e e- (~Set _)]
#:fail-unless (pure? #'e-) "expression must be pure"
----------------------
[ (#%app- set-count- e-) Int])
(define-typed-syntax (set-add st v)
[ st st- (~Set τs)]
#:fail-unless (pure? #'st-) "expression must be pure"
[ v v- τv]
#:fail-unless (pure? #'v-) "expression must be pure"
-------------------------
[ (#%app- set-add- st- v-) (Set (U τs τv))])
(define-typed-syntax (set-remove st v)
[ st st- (~Set τs)]
#:fail-unless (pure? #'st-) "expression must be pure"
[ v v- τs]
#:fail-unless (pure? #'v-) "expression must be pure"
-------------------------
[ (#%app- set-remove- st- v-) (Set τs)])
(define-typed-syntax (set-member? st v)
[ st st- (~Set τs)]
#:fail-unless (pure? #'st-) "expression must be pure"
[ v v- τv]
#:fail-unless (pure? #'v-) "expression must be pure"
#:fail-unless (<: #'τv #'τs)
"type mismatch"
-------------------------------------
[ (#%app- set-member?- st- v-) Bool])
(define-typed-syntax (set-union st0 st ...)
[ st0 st0- (~Set τ-st0)]
#:fail-unless (pure? #'st0-) "expression must be pure"
@ -64,3 +91,15 @@
#:fail-unless (all-pure? #'(st- ...)) "expressions must be pure"
-------------------------------------
[ (#%app- set-subtract- st0- st- ...) (Set τ-st0)])
(define-typed-syntax (list->set l)
[ l l- (~List τ)]
#:fail-unless (pure? #'l-) "expression must be pure"
-----------------------
[ (#%app- list->set- l-) (Set τ)])
(define-typed-syntax (set->list s)
[ s s- (~Set τ)]
#:fail-unless (pure? #'s-) "expression must be pure"
-----------------------
[ (#%app- set->list- s-) (List τ)])

View File

@ -0,0 +1,9 @@
/* Useful macros */
#define ASSERTED(x) (x##_assertions > 0)
#define RETRACTED(x) (x##_assertions == 0)
#define ASSERT(x) x##_assertions = x##_assertions + 1
#define RETRACT(x) x##_assertions = x##_assertions - 1
/* Rest of Program */

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +0,0 @@
#lang typed/syndicate/roles
(provide activate!
later-than
LaterThanT
LaterThan
TimeStateDriver)
(require-struct later-than
#:as LaterThanT
#:from syndicate/drivers/timestate)
(define-type-alias LaterThan (LaterThanT Int))
(define-type-alias TimeStateDriver
(U LaterThan
(Observe (LaterThanT ★/t))))
;; TODO ignoring other driver underneath it
(require/typed (submod syndicate/drivers/timestate syndicate-main)
[activate! : (proc #:spawns ((Actor TimeStateDriver)))])

View File

@ -1,2 +1,2 @@
#lang s-exp syntax/module-reader
typed/syndicate/roles
typed/main

View File

@ -1,3 +0,0 @@
#!/bin/sh
spin -p -t $1

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +1,2 @@
#lang s-exp syntax/module-reader
typed/syndicate/roles
typed/roles

View File

@ -1,21 +0,0 @@
#!/bin/sh
pushd ${1%/*}/ > /dev/null
EXE="$1-verifier.o"
spin -a $1
if [[ $? -ne 0 ]]; then
popd > /dev/null
exit 1
fi
gcc -o $EXE -D NFAIR=3 pan.c
# -a to analyze, -f for (weak) fairness
# -n to elide report of unreached states
# -N spec-name to verify a particular specification
$EXE -a -f -n -N $2
rm $EXE pan.*
popd > /dev/null

View File

@ -1,10 +0,0 @@
/* Useful macros */
#define ASSERTED(x) (x##_assertions > 0)
#define RETRACTED(x) (x##_assertions == 0)
#define ASSERT(x) x##_update = x##_update + 1
#define RETRACT(x) x##_update = x##_update - 1
#define SEND(x) x##_messages = x##_messages + 1
/* Rest of Program */

View File

@ -1,56 +0,0 @@
#lang turnstile
(provide Observe★
RoleNTimes
(for-syntax RoleNTimes*))
(require "core-types.rkt")
(require turnstile/typedefs)
(define-syntax (Observe★ stx)
(define star (type-eval #'★/t))
(syntax-parse stx
[(_ TyCons:id)
#:do [(define arity? (get-type-arity #'TyCons))]
#:when arity?
(mk-Observe- (list (reassemble-type #'TyCons (make-list (arity-min arity?) star))))]
[(_ t)
#:with (~Any/new TyCons τ ...) (type-eval #'t)
#:when (reassemblable? #'TyCons)
(mk-Observe- (list (reassemble-type #'TyCons (stx-map (lambda (_) star) #'(τ ...)))))]
[_
(raise-syntax-error #f "Not a type that can automatically be subscribed to" stx)]))
(begin-for-syntax
;; Arity -> Nat
(define (arity-min a)
(match a
[(arity-eq n) n]
[(arity-ge n) n])))
(define-for-syntax (RoleNTimes* n Step behav)
(let loop ([i 1])
(define nm (format-id behav "step~a" i))
(quasisyntax/loc behav
(Role (#,nm)
#,@(if (= i 1)
(list #'(Shares Unit))
(list))
(Reacts #,(if (= i 1)
#'(Asserted Unit)
#`(Message #,Step))
#,@(if (= i n)
(list)
(list #`(Sends #,Step))))
(Reacts (Message #,Step)
(Effs #,behav
(Stop #,nm
#,@(if (< i n)
(if (= i 1)
(list #`(Sends #,Step) (loop (add1 i)))
(list (loop (add1 i))))
(list)))))))))
(define-syntax-parser RoleNTimes
[(_ ~! n:nat Step:type behav:type)
(RoleNTimes* (syntax-e #'n) #'Step.norm #'behav.norm)])

View File

@ -15,13 +15,6 @@
(define (serialize-syntax stx)
(define unique-tag (gensym))
(define table (hasheq))
(define dedup-table (hasheq))
(define (dedup k f)
(if (hash-has-key? dedup-table k)
(hash-ref dedup-table k)
(let ([res (f)])
(set! dedup-table (hash-set dedup-table k res))
res)))
(define (lift! el)
(define tag-sym (gensym))
@ -41,43 +34,29 @@
(cons k serialized-val))))
(define (serialize-element! el #:always-lift? [always-lift? #f])
(dedup
el
(lambda ()
(syntax-map
el
(lambda (tail? d) d)
(lambda (orig-s d)
;(when (and always-lift? (not (ref? (hash-ref dedup-table orig-s)))) ; TODO
;(error 'dedup "lift error"))
(dedup
orig-s
(lambda ()
(if (or always-lift?
(ormap (lambda (p) (syntax-property-preserved? orig-s p))
(syntax-property-symbol-keys orig-s)))
(lift! (build-props! orig-s d))
(datum->syntax orig-s d orig-s #f)))))
syntax-e))))
(datum->syntax orig-s d orig-s #f)))
syntax-e))
(define top-s (serialize-element! stx))
(define res (datum->syntax #f (serialized-syntax unique-tag table top-s)))
res)
(datum->syntax #f (serialized-syntax unique-tag table top-s)))
(define (deserialize-syntax ser)
;(displayln 'deserialize-in)
;(print-syntax-width +inf.0)
;(println ser)
;(pretty-print (syntax->datum ser))
(match (syntax-e ser)
[(serialized-syntax unique-tag-stx table-stx contents)
(define unique-tag (syntax-e unique-tag-stx))
(define table (syntax-e table-stx))
(define dedup-table (hasheq))
(define (dedup k f)
(if (hash-has-key? dedup-table k)
(hash-ref dedup-table k)
(let ([res (f)])
(set! dedup-table (hash-set dedup-table k res))
res)))
(define (maybe-syntax-e v)
(if (syntax? v) (syntax-e v) v))
@ -99,26 +78,21 @@
(syntax-property stx k prop-val #t)))
(define (deserialize-element el)
(dedup
el
(lambda ()
(syntax-map
el
(lambda (tail? d)
(match d
[(ref tag sym)
#:when (equal? (maybe-syntax-e tag) unique-tag)
(dedup
sym
(lambda () (deserialize-stx-with-props (maybe-syntax-e sym))))]
(deserialize-stx-with-props (maybe-syntax-e sym))]
[_ d]))
(lambda (orig-s d)
(dedup
orig-s
(lambda () (datum->syntax orig-s d orig-s #f))))
syntax-e))))
(lambda (orig-s d) (datum->syntax orig-s d orig-s #f))
syntax-e))
(define res (deserialize-element contents))
;(displayln 'deserialize-out)
;(println res)
;(pretty-print (syntax->datum res))
res]))
(module+ test

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(require rackunit/turnstile)

View File

@ -1,26 +0,0 @@
#lang typed/syndicate
(assertion-struct ping : Ping (v))
(assertion-struct pong : Pong (v))
(assertion-struct flip : Flip (v))
(assertion-struct flop : Flop (v))
(define-type-alias Pinger (Ping Int))
(define-type-alias Ponger (U (Ping Int)
(Pong Int)
(Observe (Ping ★/t))))
(define-type-alias PingPong (U Pinger Ponger))
(define-type-alias Flipper (Flip Int))
(define-type-alias Flopper (U (Flip Int)
(Flop Int)
(Observe (Flip ★/t))))
(define-type-alias FlipFlop (U Flipper Flopper))
(run-ground-dataspace (U PingPong FlipFlop)
(spawn Pinger (start-facet _ (assert (ping 5))))
(spawn Ponger (start-facet _ (during (ping $v) (assert (pong v)))))
(spawn Flipper (start-facet _ (assert (flip 8))))
(spawn Flopper (start-facet _ (during (flip $v) (assert (flop v))))))

View File

@ -1,22 +0,0 @@
#lang typed/syndicate
(require rackunit/turnstile)
(define-constructor* (trust lvl))
(check-type (trust 5) : (TrustT Int))
(define-constructor* (hungry-hippos count appetite)
#:with HungryHippos (HungryHipposT Int String))
(check-type (hungry-hippos 12 "massive") : HungryHippos)
(define-constructor* (doggy [color : String] [weight : Int]))
(check-type (doggy "black" 60) : (DoggyT String Int))
(check-type (doggy "brown" 45) : Doggy)
(define-constructor* (leaf))
(check-type (leaf) : (LeafT))
(check-type (leaf) : Leaf)

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(run-ground-dataspace (U)
(spawn (U)

View File

@ -1,22 +1,17 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(require rackunit/turnstile)
(define ( (ρ) (assert-something! [p : (proc ★/t #:effects (ρ))]))
(define ( (ρ) (assert-something! [p : (proc ★/t #:endpoints (ρ))]))
(p))
(define (test-fun)
(call/inst assert-something! (lambda () (assert 5))))
(check-type test-fun : (proc ★/t #:effects ((Shares NonZero))))
(check-type test-fun : (proc ★/t #:endpoints ((Shares Int))))
(define (test-call/inst-insertion)
(assert-something! (lambda () (assert 5))))
(check-type test-call/inst-insertion : (proc ★/t #:effects ((Shares NonZero))))
(define ( (ρ) (start-something! [p : (proc ★/t #:effects (ρ))]))
(p))
(define (test-call-start-something)
(start-something! (lambda () (start-facet x (assert 5)))))
(check-type test-call/inst-insertion : (proc ★/t #:endpoints ((Shares Int))))

View File

@ -1,7 +0,0 @@
#lang typed/syndicate
(lambda ()
(start-facet x
(if #f
(assert (tuple 0))
(assert (tuple 1)))))

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(require rackunit/turnstile)

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(require rackunit/turnstile)

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(require rackunit/turnstile)

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(require rackunit/turnstile)
@ -9,7 +9,7 @@
: Int
0)
(check-type (for/fold ([x : Int 0])
(check-type (for/fold ([x 0])
([y (list 1 2 3)])
y)
: Int
@ -20,13 +20,13 @@
(define inventory0 (list (tuple "The Wind in the Willows" 5)
(tuple "Catch 22" 2)
(tuple "Candide" 33)))
(check-type (for/fold ([stock : Int 0])
(check-type (for/fold ([stock 0])
([item inventory0])
(select 1 item))
: Int
33)
(check-type (for/fold ([stock : Int 0])
(check-type (for/fold ([stock 0])
([item inventory0])
(if (equal? "Catch 22" (select 0 item))
(select 1 item)
@ -36,7 +36,7 @@
(define (lookup [title : String]
[inv : Inventory] -> Int)
(for/fold ([stock : Int 0])
(for/fold ([stock 0])
([item inv])
(if (equal? title (select 0 item))
(select 1 item)

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(require rackunit/turnstile)

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(require rackunit/turnstile)

View File

@ -1,22 +0,0 @@
#lang typed/syndicate
(require rackunit/turnstile)
(typecheck-fail (spawn
(start-facet x
(on (asserted $x:Int)
#f)))
#:with-msg "overly broad interest")
(typecheck-fail (spawn
(start-facet x
(on (asserted (observe $x:Int))
#f)))
#:with-msg "overly broad interest")
;; TODO - but this one seems fine?
(typecheck-fail (spawn
(start-facet x
(on (asserted _)
#f)))
#:with-msg "overly broad interest")

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(require rackunit/turnstile)

View File

@ -1,4 +1,4 @@
#lang typed/syndicate
#lang typed/syndicate/roles
(require rackunit/turnstile)
@ -18,4 +18,4 @@
(on start (call/inst perform-task push-results))))
: (List String)
-> (list
"(Role (x) (Reacts OnStart (Role (perform) (Reacts OnStart (Stop perform (Branch (Effs (Role (done) (Shares True))) (Effs)))))))"))
"(Role (x) (Reacts OnStart (Role (perform) (Reacts OnStart (Stop perform (Branch (Effs (Role (done) (Shares Bool))) (Effs)))))))"))

Some files were not shown because too many files have changed in this diff Show More