syndicate-2017/racket/typed/roles.rkt

699 lines
25 KiB
Racket
Raw Normal View History

2018-07-25 21:26:47 +00:00
#lang turnstile
(provide (rename-out [syndicate:#%module-begin #%module-begin])
(rename-out [typed-app #%app])
#%top-interaction
require only-in
;; Types
Int Bool String Tuple Bind Discard List
Role Reacts Reaction Shares Know ¬Know Message
FacetName Field ★/t
Observe Inbound Outbound Actor U
;; Statements
#;let spawn #;dataspace start-facet set! #;begin #;stop #;unsafe-do
;; endpoints
assert on
;; expressions
tuple #;λ ref observe inbound outbound
;; values
#%datum
;; patterns
bind discard
;; primitives
+ - * / and or not > < >= <= = equal? displayln
;; making types
define-type-alias
define-constructor
;; DEBUG and utilities
print-type print-role
(rename-out [printf- printf])
;; Extensions
;; match if cond
)
(require (prefix-in syndicate: syndicate/actor-lang))
(require (for-meta 2 macrotypes/stx-utils racket/list syntax/stx))
(require (for-syntax turnstile/examples/util/filter-maximal))
(require macrotypes/postfix-in)
(require (rename-in racket/math [exact-truncate exact-truncate-]))
(require (postfix-in - racket/list))
(require (postfix-in - racket/set))
(module+ test
(require rackunit)
(require turnstile/rackunit-typechecking))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Type Checking Conventions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; : describes the immediate result of evaluation
;; a key aggregates `assert` endpoints
;; r key aggregates each `on` endpoint as a `Reaction`
2018-07-27 14:24:46 +00:00
;; f key aggregates facet effects (starting a facet)
;; s key aggregates spawned actors
2018-07-25 21:26:47 +00:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Types
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-binding-type Role #:arity >= 2 #:bvs = 1)
(define-type-constructor Shares #:arity = 1)
(define-type-constructor Reacts #:arity >= 0)
(define-type-constructor Reaction #:arity >= 2)
(define-type-constructor Know #:arity = 1)
(define-type-constructor ¬Know #:arity = 1)
(define-type-constructor Message #:arity = 1)
(define-type-constructor Field #:arity = 1)
(define-type-constructor Bind #:arity = 1)
(define-type-constructor #:arity > 0)
(define-type-constructor Tuple #:arity >= 0)
(define-type-constructor Observe #:arity = 1)
(define-type-constructor Inbound #:arity = 1)
(define-type-constructor Outbound #:arity = 1)
(define-type-constructor Actor #:arity = 1)
(define-type-constructor AssertionSet #:arity = 1)
(define-type-constructor Patch #:arity = 2)
(define-type-constructor List #:arity = 1)
(define-type-constructor Set #:arity = 1)
(define-base-types Int Bool String Discard ★/t FacetName)
(define-for-syntax (type-eval t)
((current-type-eval) t))
(define-type-constructor U* #:arity >= 0)
(define-for-syntax (prune+sort tys)
(stx-sort
(filter-maximal
(stx->list tys)
typecheck?)))
(define-syntax (U stx)
(syntax-parse stx
[(_ . tys)
;; canonicalize by expanding to U*, with only (sorted and pruned) leaf tys
#:with ((~or (~U* ty1- ...) ty2-) ...) (stx-map (current-type-eval) #'tys)
#:with tys- (prune+sort #'(ty1- ... ... ty2- ...))
(if (= 1 (stx-length #'tys-))
(stx-car #'tys-)
(syntax/loc stx (U* . tys-)))]))
2018-07-26 21:16:06 +00:00
;; for looking at the "effects"
(begin-for-syntax
(define-syntax ~effs
(pattern-expander
(syntax-parser
[(_ eff:id ...)
#:with tmp (generate-temporary 'effss)
#'(~and tmp
(~parse (eff ...) (stx-or #'tmp #'())))])))
(define (stx-truth? a)
(and a (not (and (syntax? a) (false? (syntax-e a))))))
(define (stx-or a b)
(cond [(stx-truth? a) a]
[else b])))
2018-07-25 21:26:47 +00:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; User Defined Types, aka Constructors
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; τ.norm in 1st case causes "not valid type" error when referring to ⊥ in another file.
;; however, this version expands the type at every reference, incurring a potentially large
;; overhead---2x in the case of book-club.rkt
;; (copied from ext-stlc example)
(define-syntax define-type-alias
(syntax-parser
[(_ alias:id τ)
#'(define-syntax- alias
(make-variable-like-transformer #'τ))]
[(_ (f:id x:id ...) ty)
#'(define-syntax- (f stx)
(syntax-parse stx
[(_ x ...)
#:with τ:any-type #'ty
#'τ.norm]))]))
(begin-for-syntax
(define-splicing-syntax-class type-constructor-decl
(pattern (~seq #:type-constructor TypeCons:id))
(pattern (~seq) #:attr TypeCons #f))
(struct user-ctor (typed-ctor untyped-ctor)
#:property prop:procedure
(lambda (v stx)
(define transformer (user-ctor-typed-ctor v))
(syntax-parse stx
[(_ e ...)
#`(#,transformer e ...)]))))
(define-syntax (define-constructor stx)
(syntax-parse stx
[(_ (Cons:id slot:id ...)
ty-cons:type-constructor-decl
(~seq #:with
Alias AliasBody) ...)
#:with TypeCons (or (attribute ty-cons.TypeCons) (format-id stx "~a/t" (syntax-e #'Cons)))
#:with MakeTypeCons (format-id #'TypeCons "make-~a" #'TypeCons)
#:with GetTypeParams (format-id #'TypeCons "get-~a-type-params" #'TypeCons)
#:with TypeConsExpander (format-id #'TypeCons "~~~a" #'TypeCons)
#:with TypeConsExtraInfo (format-id #'TypeCons "~a-extra-info" #'TypeCons)
#:with (StructName Cons- type-tag) (generate-temporaries #'(Cons Cons Cons))
(define arity (stx-length #'(slot ...)))
#`(begin-
(struct- StructName (slot ...) #:reflection-name 'Cons #:transparent)
(define-syntax (TypeConsExtraInfo stx)
(syntax-parse stx
[(_ X (... ...)) #'('type-tag 'MakeTypeCons 'GetTypeParams)]))
(define-type-constructor TypeCons
#:arity = #,arity
#:extra-info 'TypeConsExtraInfo)
(define-syntax (MakeTypeCons stx)
(syntax-parse stx
[(_ t (... ...))
#:fail-unless (= #,arity (stx-length #'(t (... ...)))) "arity mismatch"
#'(TypeCons t (... ...))]))
(define-syntax (GetTypeParams stx)
(syntax-parse stx
[(_ (TypeConsExpander t (... ...)))
#'(t (... ...))]))
(define-syntax Cons
(user-ctor #'Cons- #'StructName))
(define-typed-syntax (Cons- e (... ...))
#:fail-unless (= #,arity (stx-length #'(e (... ...)))) "arity mismatch"
[ e e- ( : τ)] (... ...)
2018-07-25 21:26:47 +00:00
----------------------
[ (#%app- StructName e- (... ...)) ( : (TypeCons τ (... ...)))])
2018-07-25 21:26:47 +00:00
(define-type-alias Alias AliasBody) ...)]))
(begin-for-syntax
(define-syntax ~constructor-extra-info
(pattern-expander
(syntax-parser
[(_ tag mk get)
#'(_ (_ tag) (_ mk) (_ get))])))
(define-syntax ~constructor-type
(pattern-expander
(syntax-parser
[(_ tag . rst)
#'(~and it
(~fail #:unless (user-defined-type? #'it))
(~parse tag (get-type-tag #'it))
(~Any _ . rst))])))
(define-syntax ~constructor-exp
(pattern-expander
(syntax-parser
[(_ cons . rst)
#'(~and (cons . rst)
(~fail #:unless (ctor-id? #'cons)))])))
(define (inspect t)
(syntax-parse t
[(~constructor-type tag t ...)
(list (syntax-e #'tag) (stx-map type->str #'(t ...)))]))
(define (tags-equal? t1 t2)
(equal? (syntax-e t1) (syntax-e t2)))
(define (user-defined-type? t)
(get-extra-info (type-eval t)))
(define (get-type-tag t)
(syntax-parse (get-extra-info t)
[(~constructor-extra-info tag _ _)
(syntax-e #'tag)]))
(define (get-type-args t)
(syntax-parse (get-extra-info t)
[(~constructor-extra-info _ _ get)
(define f (syntax-local-value #'get))
(syntax->list (f #`(get #,t)))]))
(define (make-cons-type t args)
(syntax-parse (get-extra-info t)
[(~constructor-extra-info _ mk _)
(define f (syntax-local-value #'mk))
(type-eval (f #`(mk #,@args)))]))
(define (ctor-id? stx)
(and (identifier? stx)
(user-ctor? (syntax-local-value stx (const #f)))))
(define (untyped-ctor stx)
(user-ctor-untyped-ctor (syntax-local-value stx (const #f)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Conveniences
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Syntax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(begin-for-syntax
;; constructors with arity one
(define-syntax-class kons1
(pattern (~or (~datum observe)
(~datum inbound)
(~datum outbound))))
(define (kons1->constructor stx)
(syntax-parse stx
#:datum-literals (observe inbound outbound)
[observe #'syndicate:observe]
[inbound #'syndicate:inbound]
[outbound #'syndicate:outbound]))
(define-syntax-class basic-val
(pattern (~or boolean
integer
string)))
(define-syntax-class prim-op
(pattern (~or (~literal +)
(~literal -)
(~literal displayln)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Utilities Over Types
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-for-syntax (bot? t)
(<: t (type-eval #'(U*))))
(define-for-syntax (flat-type? τ)
(syntax-parse τ
[(~→ τ ...) #f]
[(~Actor τ) #f]
[_ #t]))
(define-for-syntax (strip-? t)
(type-eval
(syntax-parse t
[(~U* τ ...) #`(U #,@(stx-map strip-? #'(τ ...)))]
[~★/t #'★/t]
[(~Observe τ) #'τ]
[_ #'(U*)])))
(define-for-syntax (strip-inbound t)
(type-eval
(syntax-parse t
[(~U* τ ...) #`(U #,@(stx-map strip-? #'(τ ...)))]
[~★/t #'★/t]
[(~Inbound τ) #'τ]
[_ #'(U*)])))
(define-for-syntax (strip-outbound t)
(type-eval
(syntax-parse t
[(~U* τ ...) #`(U #,@(stx-map strip-? #'(τ ...)))]
[~★/t #'★/t]
[(~Outbound τ) #'τ]
[_ #'(U*)])))
(define-for-syntax (relay-interests t)
(type-eval
(syntax-parse t
;; TODO: probably need to `normalize` the result
[(~U* τ ...) #`(U #,@(stx-map strip-? #'(τ ...)))]
[~★/t #'★/t]
[(~Observe (~Inbound τ)) #'(Observe τ)]
[_ #'(U*)])))
2018-07-27 14:24:46 +00:00
(define-for-syntax (analyze-role-input/output t)
(syntax-parse t
[(~Role (name:id) (~Shares τ-s) (~Reacts τ-r ...) sub-role ...)
(type-eval #'(U*))]))
2018-07-25 21:26:47 +00:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Subtyping
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Type Type -> Bool
(define-for-syntax (<: t1 t2)
(syntax-parse #`(#,t1 #,t2)
[((~U* τ1 ...) _)
(stx-andmap (lambda (t) (<: t t2)) #'(τ1 ...))]
[(_ (~U* τ2:type ...))
(stx-ormap (lambda (t) (<: t1 t)) #'(τ2 ...))]
;; TODO
#;[((~Actor τ1:type) (~Actor τ2:type))
;; should these be .norm? Is the invariant that inputs are always fully
;; evalutated/expanded?
(and (<: #'τ1 #'τ2)
(<: ( (strip-? #'τ1) #'τ2) #'τ1))]
[((~AssertionSet τ1) (~AssertionSet τ2))
(<: #'τ1 #'τ2)]
[((~Set τ1) (~Set τ2))
(<: #'τ1 #'τ2)]
[((~Patch τ11 τ12) (~Patch τ21 τ22))
(and (<: #'τ11 #'τ21)
(<: #'τ12 #'τ22))]
[((~Tuple τ1:type ...) (~Tuple τ2:type ...))
#:when (stx-length=? #'(τ1 ...) #'(τ2 ...))
(stx-andmap <: #'(τ1 ...) #'(τ2 ...))]
[(_ ~★/t)
(flat-type? t1)]
[((~Observe τ1:type) (~Observe τ2:type))
(<: #'τ1 #'τ2)]
[((~Inbound τ1:type) (~Inbound τ2:type))
(<: #'τ1 #'τ2)]
[((~Outbound τ1:type) (~Outbound τ2:type))
(<: #'τ1 #'τ2)]
[((~constructor-type t1 τ1:type ...) (~constructor-type t2 τ2:type ...))
#:when (tags-equal? #'t1 #'t2)
(and (stx-length=? #'(τ1 ...) #'(τ2 ...))
(stx-andmap <: #'(τ1 ...) #'(τ2 ...)))]
[((~→ τ-in1 ... τ-out1) (~→ τ-in2 ... τ-out2))
#:when (stx-length=? #'(τ-in1 ...) #'(τ-in2 ...))
(and (stx-andmap <: #'(τ-in2 ...) #'(τ-in1 ...))
(<: #'τ-out1 #'τ-out2))]
[(~Discard _)
#t]
;; TODO: clauses for Roles, and so on
;; should probably put this first.
[_ (type=? t1 t2)]))
;; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;; MODIFYING GLOBAL TYPECHECKING STATE!!!!!
;; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
(begin-for-syntax
(current-typecheck-relation <:))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Core forms
(define-typed-syntax (start-facet name:id ((~datum fields) [x:id τ-f:type e:expr] ...) ep ...+)
#:fail-unless (stx-andmap flat-type? #'(τ-f ...)) "keep your uppity data outta my fields"
;; TODO - probably don't want these expressions to have any effects
[ e e- ( : τ-f)] ...
[[name name- : FacetName] [x x- : (Field τ-f.norm)] ...
[ep ep- ( r (τ-r ...))
( a (τ-a ...))
2018-07-27 14:24:46 +00:00
( f (τ-fs ...))] ...]
2018-07-25 21:26:47 +00:00
#:with as (type-eval #'(U τ-a ... ...))
#:with τ (type-eval #'(Role (name-)
(Shares as)
(Reacts τ-r ... ...)
;; actually these should be empty
τ-fs ... ...))
2018-07-25 21:26:47 +00:00
--------------------------------------------------------------
[ (syndicate:react (let- ([name- (syndicate:current-facet-id)])
#,(make-fields #'(x- ...) #'(e- ...))
ep- ...))
( : ★/t)
( r ())
( a ())
2018-07-27 14:24:46 +00:00
( f (τ))])
2018-07-25 21:26:47 +00:00
(define-for-syntax (make-fields names inits)
(syntax-parse #`(#,names #,inits)
[((x:id ...) (e ...))
#'(syndicate:field [x e] ...)]))
(define-typed-syntax (assert e:expr)
[ e e- ( : τ) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
-------------------------------------
[ (syndicate:assert e-) ( : ★/t)
( a (τ))
( r ())
2018-07-27 14:24:46 +00:00
( f ())])
2018-07-25 21:26:47 +00:00
(begin-for-syntax
(define-syntax-class asserted-or-retracted
#:datum-literals (asserted retracted)
(pattern (~or (~and asserted
(~bind [syndicate-kw #'syndicate:asserted]
[react-con #'Know]))
(~and retracted
(~bind [syndicate-kw #'syndicate:retracted]
[react-con #'¬Know]))))))
(define-typed-syntax on
;; TODO - on start/stop
#;[(on (~literal start) s)
[ s s- ( :i τi) ( :o τ-o) ( :a τ-a)]
-----------------------------------
[ (syndicate:on-start s-) ( : (U)) ( :i τi) ( :o τ-o) ( :a τ-a)]]
#;[(on (~literal stop) s)
[ s s- ( :i τi) ( :o τ-o) ( :a τ-a)]
-----------------------------------
[ (syndicate:on-stop s-) ( : (U)) ( :i τi) ( :o τ-o) ( :a τ-a)]]
[(on (a/r:asserted-or-retracted p) s)
[ p _ ( : τp) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
#:with p- (compile-syndicate-pattern #'p)
#:with ([x:id τ:type] ...) (pat-bindings #'p)
[[x x- : τ] ... s s- ( a (~effs))
( r (~effs))
( f (~effs τ-f ...))]
2018-07-27 14:24:46 +00:00
#:with (rhs ...) (if (stx-null? #'(τ-f ...)) #'((U*)) #'(τ-f ...))
2018-07-25 21:26:47 +00:00
#:with τ-r #'(Reaction (a/r.react-con τp) rhs ...)
-----------------------------------
[ (syndicate:on (a/r.syndicate-kw p-)
(let- ([x- x] ...) s-))
( : ★/t)
( r (τ-r))
2018-07-27 14:24:46 +00:00
( f ())
2018-07-25 21:26:47 +00:00
( a ())]])
;; pat -> ([Id Type] ...)
(define-for-syntax (pat-bindings stx)
(syntax-parse stx
#:datum-literals (bind tuple)
[(bind x:id τ:type)
#'([x τ])]
[(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 τ] ... ...)]
[_
#'()]))
(define-for-syntax (compile-pattern pat bind-id-transformer exp-transformer)
(let loop ([pat pat])
(syntax-parse pat
#:datum-literals (tuple discard bind)
[(tuple p ...)
#`(list 'tuple #,@(stx-map loop #'(p ...)))]
[(k:kons1 p)
#`(#,(kons1->constructor #'k) #,(loop #'p))]
[(bind x:id τ:type)
(bind-id-transformer #'x)]
[discard
#'_]
[(~constructor-exp ctor p ...)
(define/with-syntax uctor (untyped-ctor #'ctor))
#`(uctor #,@(stx-map loop #'(p ...)))]
[_
(exp-transformer pat)])))
(define-for-syntax (compile-syndicate-pattern pat)
(compile-pattern pat
(lambda (id) #`($ #,id))
identity))
(define-typed-syntax (spawn τ-c:type s)
#:fail-unless (flat-type? #'τ-c.norm) "Communication type must be first-order"
[ s s- ( a (~effs)) ( r (~effs)) ( f (~effs τ-f ...))]
2018-07-25 21:26:47 +00:00
;; TODO: s shouldn't refer to facets or fields!
;; TODO - check the role against the type of the dataspace
#:do [(define ins-and-outs (stx-map analyze-role-input/output #'(τ-f ...)))]
2018-07-25 21:26:47 +00:00
#|
#:fail-unless (<: #'τ-o.norm #'τ-c.norm)
(format "Output ~a not valid in dataspace ~a" (type->str #'τ-o.norm) (type->str #'τ-c.norm))
#:fail-unless (<: (type-eval #'(Actor τ-a.norm))
(type-eval #'(Actor τ-c.norm))) "Spawned actors not valid in dataspace"
#:fail-unless (project-safe? ( (strip-? #'τ-o.norm) #'τ-c.norm)
#'τ-i.norm) "Not prepared to handle all inputs"
|#
--------------------------------------------------------------------------------------------
;; TODO - need a key for spawning actors, I guess
2018-07-27 14:24:46 +00:00
[ (syndicate:spawn (syndicate:on-start s-)) ( : ★/t) ( a ()) ( r ()) ( f ())])
2018-07-25 21:26:47 +00:00
(define-typed-syntax (set! x:id e:expr)
[ e e- ( : τ) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
[ x x- ( : (~Field τ-x:type))]
#:fail-unless (<: #'τ #'τ-x) "Ill-typed field write"
----------------------------------------------------
[ (x- e-) ( : ★/t)])
2018-07-25 21:26:47 +00:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Expressions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-typed-syntax (ref x:id)
[ x x- (~Field τ)]
------------------------
[ (x-) ( : τ)])
2018-07-25 21:26:47 +00:00
(define-typed-syntax (typed-app e_fn e_arg ...)
;; TODO : other keys
[ e_fn e_fn- ( : (~→ τ_in ... τ_out)) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
#:fail-unless (stx-length=? #'[τ_in ...] #'[e_arg ...])
(num-args-fail-msg #'e_fn #'[τ_in ...] #'[e_arg ...])
[ e_arg e_arg- ( : τ_in) ( a (~effs)) ( r (~effs)) ( f (~effs))] ...
2018-07-25 21:26:47 +00:00
------------------------------------------------------------------------
[ (#%app- e_fn- e_arg- ...) ( : τ_out)])
2018-07-25 21:26:47 +00:00
(define-typed-syntax (tuple e:expr ...)
[ e e- ( : τ) ( a (~effs)) ( r (~effs)) ( f (~effs))] ...
2018-07-25 21:26:47 +00:00
-----------------------
[ (list- 'tuple e- ...) ( : (Tuple τ ...))])
2018-07-25 21:26:47 +00:00
(define-typed-syntax (select n:nat e:expr)
[ e e- ( : (~Tuple τ ...)) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
#:do [(define i (syntax->datum #'n))]
#:fail-unless (< i (stx-length #'(τ ...))) "index out of range"
#:with τr (list-ref (stx->list #'(τ ...)) i)
--------------------------------------------------------------
[ (tuple-select n e-) ( : τr)])
2018-07-25 21:26:47 +00:00
(define- (tuple-select n t)
(list-ref- t (add1 n)))
;; it would be nice to abstract over these three
(define-typed-syntax (observe e:expr)
[ e e- ( : τ) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
---------------------------------------------------------------------------
[ (syndicate:observe e-) ( : (Observe τ))])
2018-07-25 21:26:47 +00:00
(define-typed-syntax (inbound e:expr)
[ e e- ( : τ) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
---------------------------------------------------------------------------
[ (syndicate:inbound e-) ( : (Inbound τ))])
2018-07-25 21:26:47 +00:00
(define-typed-syntax (outbound e:expr)
[ e e- ( : τ) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
---------------------------------------------------------------------------
[ (syndicate:outbound e-) ( : (Outbound τ))])
2018-07-25 21:26:47 +00:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Patterns
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-typed-syntax (bind x:id τ:type)
----------------------------------------
[ (error- 'bind "escaped") ( : (Bind τ))])
2018-07-25 21:26:47 +00:00
(define-typed-syntax discard
[_
--------------------
;; TODO: change void to _
[ (error- 'discard "escaped") ( : Discard)]])
2018-07-25 21:26:47 +00:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Core-ish forms
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Primitives
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; hmmm
(define-primop + ( Int Int Int))
(define-primop - ( Int Int Int))
(define-primop * ( Int Int Int))
#;(define-primop and ( Bool Bool Bool))
(define-primop or ( Bool Bool Bool))
(define-primop not ( Bool Bool))
(define-primop < ( Int Int Bool))
(define-primop > ( Int Int Bool))
(define-primop <= ( Int Int Bool))
(define-primop >= ( Int Int Bool))
(define-primop = ( Int Int Bool))
(define-typed-syntax (/ e1 e2)
[ e1 e1- ( : Int) ( a (~effs)) ( r (~effs)) ( f (~effs))]
[ e2 e2- ( : Int) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
------------------------
[ (exact-truncate- (/- e1- e2-)) ( : Int)])
2018-07-25 21:26:47 +00:00
;; for some reason defining `and` as a prim op doesn't work
(define-typed-syntax (and e ...)
[ e e- ( : Bool) ( a (~effs)) ( r (~effs)) ( f (~effs))] ...
2018-07-25 21:26:47 +00:00
------------------------
[ (and- e- ...) ( : Bool)])
2018-07-25 21:26:47 +00:00
(define-typed-syntax (equal? e1:expr e2:expr)
[ e1 e1- ( : τ1:type) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
#:fail-unless (flat-type? #'τ1.norm)
(format "equality only available on flat data; got ~a" (type->str #'τ1))
[ e2 e2- ( : τ1) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
---------------------------------------------------------------------------
[ (equal?- e1- e2-) ( : Bool) ( a (~effs)) ( r (~effs)) ( f (~effs))])
2018-07-25 21:26:47 +00:00
(define-typed-syntax (empty? e)
[ e e- ( : (~List _)) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
-----------------------
[ (empty?- e-) ( : Bool)])
2018-07-25 21:26:47 +00:00
(define-typed-syntax (first e)
[ e e- ( : (~List τ)) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
-----------------------
[ (first- e-) ( : τ)])
2018-07-25 21:26:47 +00:00
(define-typed-syntax (rest e)
[ e e- ( : (~List τ)) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
-----------------------
[ (rest- e-) ( : (List τ))])
2018-07-25 21:26:47 +00:00
(define-typed-syntax (member? e l)
[ e e- ( : τe:type) ( a (~effs)) ( r (~effs)) ( f (~effs))]
[ l l- ( : (~List τl:type)) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
#:fail-unless (<: #'τe.norm #'τl.norm) "incompatible list"
----------------------------------------
[ (member?- e- l-) ( : Bool)])
2018-07-25 21:26:47 +00:00
(define- (member?- v l)
(and- (member- v l) #t))
(define-typed-syntax (displayln e:expr)
[ e e- ( : τ) ( a (~effs)) ( r (~effs)) ( f (~effs))]
2018-07-25 21:26:47 +00:00
---------------
[ (displayln- e-) ( : ★/t)])
2018-07-25 21:26:47 +00:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Basic Values
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-typed-syntax #%datum
[(_ . n:integer)
----------------
[ (#%datum- . n) ( : Int)]]
2018-07-25 21:26:47 +00:00
[(_ . b:boolean)
----------------
[ (#%datum- . b) ( : Bool)]]
2018-07-25 21:26:47 +00:00
[(_ . s:string)
----------------
[ (#%datum- . s) ( : String)]])
2018-07-25 21:26:47 +00:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Utilities
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-typed-syntax (print-type e)
2018-07-27 14:24:46 +00:00
[ e e- ( : τ) ( a as) ( r rs) ( f es)]
2018-07-25 21:26:47 +00:00
#:do [(displayln (type->str #'τ))]
----------------------------------
2018-07-27 14:24:46 +00:00
[ e- ( : τ) ( a as) ( r rs) ( f es)])
2018-07-25 21:26:47 +00:00
(define-typed-syntax (print-role e)
2018-07-27 14:24:46 +00:00
[ e e- ( : τ) ( a as) ( r rs) ( f es)]
2018-07-25 21:26:47 +00:00
#:do [(for ([r (in-syntax #'es)])
(displayln (type->str r)))]
----------------------------------
2018-07-27 14:24:46 +00:00
[ e- ( : τ) ( a as) ( r rs) ( f es)])