2018-04-06 10:37:59 +00:00
|
|
|
#lang racket/base
|
|
|
|
;; "Skeletons" describe the indexed structure of a dataspace.
|
|
|
|
;; In particular, they efficiently connect assertions to matching interests.
|
|
|
|
|
|
|
|
(provide (struct-out skeleton-interest)
|
2018-05-04 14:55:53 +00:00
|
|
|
(struct-out visibility-restriction)
|
2018-04-06 10:37:59 +00:00
|
|
|
make-empty-skeleton
|
|
|
|
add-interest!
|
|
|
|
remove-interest!
|
|
|
|
add-assertion!
|
|
|
|
remove-assertion!
|
2018-05-04 14:55:53 +00:00
|
|
|
send-assertion!)
|
2018-04-06 10:37:59 +00:00
|
|
|
|
|
|
|
(require syndicate/support/struct)
|
|
|
|
(require racket/match)
|
|
|
|
(require racket/hash)
|
|
|
|
(require racket/list)
|
|
|
|
|
2018-04-19 16:55:52 +00:00
|
|
|
(require "bag.rkt")
|
2018-05-03 15:14:30 +00:00
|
|
|
(require "pattern.rkt")
|
|
|
|
(require "assertions.rkt")
|
2018-04-19 16:55:52 +00:00
|
|
|
|
2018-04-06 10:37:59 +00:00
|
|
|
(module+ test (require rackunit))
|
|
|
|
|
2018-05-04 14:55:53 +00:00
|
|
|
;; A VisibilityRestriction describes ... TODO
|
|
|
|
;; (visibility-restriction SkProj Assertion)
|
|
|
|
(struct visibility-restriction (path term) #:transparent)
|
|
|
|
|
|
|
|
;; A ScopedAssertion is a VisibilityRestriction or an Assertion.
|
|
|
|
;; (Corollary: Instances of `visibility-restriction` can never be assertions.)
|
|
|
|
|
2018-04-06 10:37:59 +00:00
|
|
|
;; A `Skeleton` is a structural guard on an assertion: essentially,
|
|
|
|
;; specification of (the outline of) its shape; its silhouette.
|
|
|
|
;; Following a skeleton's structure leads to zero or more `SkCont`s.
|
|
|
|
;;
|
|
|
|
;; Skeleton = (skeleton-node SkCont (AListof SkSelector (MutableHash SkClass SkNode)))
|
|
|
|
;; SkSelector = (skeleton-selector Nat Nat)
|
2018-05-01 19:57:22 +00:00
|
|
|
;; SkClass = StructType | (list-type Nat) | (vector-type Nat)
|
2018-04-06 10:37:59 +00:00
|
|
|
;;
|
|
|
|
(struct skeleton-node (continuation [edges #:mutable]) #:transparent)
|
|
|
|
(struct skeleton-selector (pop-count index) #:transparent)
|
|
|
|
(struct list-type (arity) #:transparent)
|
2018-05-01 19:57:22 +00:00
|
|
|
(struct vector-type (arity) #:transparent)
|
2018-04-06 10:37:59 +00:00
|
|
|
;;
|
|
|
|
;; A `SkDesc` is a single assertion silhouette, usually the
|
|
|
|
;; evaluation-result of `desc->skeleton-stx` from `pattern.rkt`.
|
|
|
|
;;
|
|
|
|
;; A `SkCont` is a *skeleton continuation*, a collection of "next
|
|
|
|
;; steps" after a `Skeleton` has matched the general outline of an
|
|
|
|
;; assertion.
|
|
|
|
;;
|
|
|
|
;; INVARIANT: At each level, the caches correspond to the
|
|
|
|
;; appropriately filtered and projected contents of the dataspace
|
|
|
|
;; containing the structures.
|
|
|
|
;;
|
|
|
|
;; SkCont = (skeleton-continuation
|
2018-05-04 14:55:53 +00:00
|
|
|
;; (MutableSet ScopedAssertion)
|
2018-04-06 10:37:59 +00:00
|
|
|
;; (MutableHash SkProj (MutableHash SkKey SkConst)))
|
|
|
|
;; SkConst = (skeleton-matched-constant
|
2018-05-04 14:55:53 +00:00
|
|
|
;; (MutableSet ScopedAssertion)
|
2018-04-06 10:37:59 +00:00
|
|
|
;; (MutableHash SkProj SkAcc))
|
|
|
|
;; SkAcc = (skeleton-accumulator
|
2018-04-19 16:55:52 +00:00
|
|
|
;; (MutableBag SkKey)
|
2018-04-08 06:01:39 +00:00
|
|
|
;; (MutableSeteq (... -> Any)))
|
2018-04-06 10:37:59 +00:00
|
|
|
;;
|
|
|
|
(struct skeleton-continuation (cache table) #:transparent)
|
|
|
|
(struct skeleton-matched-constant (cache table) #:transparent)
|
2018-04-19 16:55:52 +00:00
|
|
|
(struct skeleton-accumulator (cache handlers) #:transparent)
|
2018-04-06 10:37:59 +00:00
|
|
|
;;
|
|
|
|
;; A `SkProj` is a *skeleton projection*, a specification of loci
|
|
|
|
;; within a tree-shaped assertion to collect into a flat list.
|
|
|
|
;;
|
|
|
|
;; SkProj = (Listof (Listof Nat))
|
|
|
|
;;
|
|
|
|
;; The outer list specifies elements of the flat list; the inner lists
|
|
|
|
;; specify paths via zero-indexed links to child nodes in the
|
|
|
|
;; tree-shaped assertion being examined. A precondition for use of a
|
|
|
|
;; `SkProj` is that the assertion being examined has been checked for
|
|
|
|
;; conformance to the skeleton being projected.
|
|
|
|
;;
|
|
|
|
;; A `SkKey` is the result of running a `SkProj` over a term,
|
|
|
|
;; extracting the values at the denoted locations.
|
|
|
|
;;
|
|
|
|
;; SkKey = (Listof Any)
|
|
|
|
;;
|
|
|
|
;; Each `SkProj` in `SkCont` selects *constant* portions of the term
|
|
|
|
;; for more matching against the `SkKey`s in the table associated with
|
|
|
|
;; the `SkProj`. Each `SkProj` in `SkConst`, if any, selects
|
|
|
|
;; *variable* portions of the term to be given to the handler
|
|
|
|
;; functions in the associated `SkAcc`.
|
|
|
|
|
|
|
|
;; A `SkInterest` is a specification for an addition to or removal
|
|
|
|
;; from an existing `Skeleton`.
|
|
|
|
;;
|
2018-04-29 13:54:14 +00:00
|
|
|
;; SkInterest = (skeleton-interest SkDesc
|
|
|
|
;; SkProj
|
|
|
|
;; SkKey
|
|
|
|
;; SkProj
|
|
|
|
;; (... -> Any)
|
|
|
|
;; (Option ((MutableBag SkKey) -> Any)))
|
2018-04-06 10:37:59 +00:00
|
|
|
;;
|
|
|
|
;; The `SkDesc` gives the silhouette. The first `SkProj` is the
|
|
|
|
;; constant-portion selector, to be matched against the `SkKey`. The
|
|
|
|
;; second `SkProj` is used on matching assertions to extract the
|
|
|
|
;; variable portions, to be passed to the handler function.
|
|
|
|
;;
|
2018-04-29 13:54:14 +00:00
|
|
|
(struct skeleton-interest (desc
|
|
|
|
const-selector
|
|
|
|
const-value
|
|
|
|
var-selector
|
|
|
|
handler
|
|
|
|
cleanup
|
|
|
|
) #:transparent)
|
2018-04-06 10:37:59 +00:00
|
|
|
|
|
|
|
;;---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
(define (make-empty-skeleton/cache cache)
|
|
|
|
(skeleton-node (skeleton-continuation cache
|
|
|
|
(make-hash))
|
|
|
|
'()))
|
|
|
|
|
|
|
|
(define (make-empty-skeleton)
|
2018-04-30 08:32:08 +00:00
|
|
|
(make-empty-skeleton/cache (make-hash)))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
2018-04-29 13:54:14 +00:00
|
|
|
(define (skcont-add! c i)
|
|
|
|
(match-define (skeleton-interest _desc cs cv vs h _cleanup) i)
|
2018-04-06 10:37:59 +00:00
|
|
|
(define (make-matched-constant)
|
2018-04-30 08:32:08 +00:00
|
|
|
(define assertions (make-hash))
|
2018-04-30 09:04:33 +00:00
|
|
|
(hash-for-each (skeleton-continuation-cache c)
|
|
|
|
(lambda (a _)
|
2018-05-04 14:55:53 +00:00
|
|
|
(when (equal? (apply-projection (unscope-assertion a) cs) cv)
|
2018-04-30 09:04:33 +00:00
|
|
|
(hash-set! assertions a #t))))
|
2018-04-30 08:32:08 +00:00
|
|
|
(skeleton-matched-constant assertions (make-hash)))
|
2018-04-06 10:37:59 +00:00
|
|
|
(define cvt (hash-ref! (skeleton-continuation-table c) cs make-hash))
|
|
|
|
(define sc (hash-ref! cvt cv make-matched-constant))
|
|
|
|
(define (make-accumulator)
|
2018-04-19 16:55:52 +00:00
|
|
|
(define cache (make-bag))
|
2018-04-30 09:04:33 +00:00
|
|
|
(hash-for-each (skeleton-matched-constant-cache sc)
|
|
|
|
(lambda (a _)
|
2018-05-04 14:55:53 +00:00
|
|
|
(unpack-scoped-assertion [restriction-path term] a)
|
|
|
|
(when (or (not restriction-path) (equal? restriction-path vs))
|
|
|
|
(bag-change! cache (apply-projection term vs) 1))))
|
2018-04-30 08:32:08 +00:00
|
|
|
(skeleton-accumulator cache (make-hasheq)))
|
2018-04-06 10:37:59 +00:00
|
|
|
(define acc (hash-ref! (skeleton-matched-constant-table sc) vs make-accumulator))
|
2018-04-30 08:32:08 +00:00
|
|
|
(hash-set! (skeleton-accumulator-handlers acc) h #t)
|
2018-04-29 13:54:14 +00:00
|
|
|
(for [(vars (in-bag (skeleton-accumulator-cache acc)))] (apply h '+ vars)))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
2018-04-22 20:04:22 +00:00
|
|
|
(define (skcont-remove! c i)
|
2018-04-29 13:54:14 +00:00
|
|
|
(match-define (skeleton-interest _desc cs cv vs h cleanup) i)
|
2018-04-06 10:37:59 +00:00
|
|
|
(define cvt (hash-ref (skeleton-continuation-table c) cs #f))
|
|
|
|
(when cvt
|
|
|
|
(define sc (hash-ref cvt cv #f))
|
|
|
|
(when sc
|
|
|
|
(define acc (hash-ref (skeleton-matched-constant-table sc) vs #f))
|
|
|
|
(when acc
|
2018-04-30 08:32:08 +00:00
|
|
|
(when (and cleanup (hash-has-key? (skeleton-accumulator-handlers acc) h))
|
2018-04-29 13:54:14 +00:00
|
|
|
(cleanup (skeleton-accumulator-cache acc)))
|
2018-04-30 08:32:08 +00:00
|
|
|
(hash-remove! (skeleton-accumulator-handlers acc) h)
|
|
|
|
(when (hash-empty? (skeleton-accumulator-handlers acc))
|
2018-04-06 10:37:59 +00:00
|
|
|
(hash-remove! (skeleton-matched-constant-table sc) vs)))
|
|
|
|
(when (hash-empty? (skeleton-matched-constant-table sc))
|
|
|
|
(hash-remove! cvt cv)))
|
|
|
|
(when (hash-empty? cvt)
|
|
|
|
(hash-remove! (skeleton-continuation-table c) cs))))
|
|
|
|
|
|
|
|
(define (term-matches-class? term class)
|
|
|
|
(cond
|
|
|
|
[(list-type? class) (and (list? term) (= (length term) (list-type-arity class)))]
|
2018-05-01 19:57:22 +00:00
|
|
|
[(vector-type? class) (and (vector? term) (= (vector-length term) (vector-type-arity class)))]
|
2018-04-06 10:37:59 +00:00
|
|
|
[(struct-type? class) (and (non-object-struct? term) (eq? (struct->struct-type term) class))]
|
|
|
|
[else (error 'term-matches-class? "Invalid class: ~v" class)]))
|
|
|
|
|
|
|
|
(define (subterm-matches-class? term path class)
|
2018-05-04 14:55:53 +00:00
|
|
|
(term-matches-class? (apply-projection-path (unscope-assertion term) path) class))
|
|
|
|
|
|
|
|
(define (unscope-assertion scoped-assertion)
|
|
|
|
(match scoped-assertion
|
|
|
|
[(visibility-restriction _ term) term]
|
|
|
|
[term term]))
|
|
|
|
|
|
|
|
(define-syntax-rule (unpack-scoped-assertion [path term] expr)
|
|
|
|
(define-values (path term)
|
|
|
|
(match expr
|
|
|
|
[(visibility-restriction p t) (values p t)]
|
|
|
|
[other (values #f other)])))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
|
|
|
(define (extend-skeleton! sk desc)
|
2018-10-20 23:58:40 +00:00
|
|
|
(define (walk-node! rev-path sk pop-count index desc)
|
2018-04-06 10:37:59 +00:00
|
|
|
(match desc
|
|
|
|
[(list class-desc pieces ...)
|
|
|
|
(define class
|
2018-05-01 19:57:22 +00:00
|
|
|
(cond [(struct-type? class-desc) class-desc]
|
|
|
|
[(eq? class-desc 'list) (list-type (length pieces))]
|
|
|
|
[(eq? class-desc 'vector) (vector-type (length pieces))]
|
2018-04-06 10:37:59 +00:00
|
|
|
[else (error 'extend-skeleton! "Invalid class-desc: ~v" class-desc)]))
|
|
|
|
(define selector (skeleton-selector pop-count index))
|
|
|
|
(define table
|
|
|
|
(match (assoc selector (skeleton-node-edges sk))
|
|
|
|
[#f (let ((table (make-hash)))
|
|
|
|
(set-skeleton-node-edges! sk (cons (cons selector table) (skeleton-node-edges sk)))
|
|
|
|
table)]
|
|
|
|
[(cons _selector table) table]))
|
|
|
|
(define (make-skeleton-node-with-cache)
|
|
|
|
(define unfiltered (skeleton-continuation-cache (skeleton-node-continuation sk)))
|
2018-04-30 08:32:08 +00:00
|
|
|
(define filtered (make-hash))
|
2018-10-20 23:58:40 +00:00
|
|
|
(define path (reverse rev-path))
|
2018-04-30 09:04:33 +00:00
|
|
|
(hash-for-each unfiltered
|
|
|
|
(lambda (a _)
|
|
|
|
(when (subterm-matches-class? a path class)
|
|
|
|
(hash-set! filtered a #t))))
|
2018-04-30 08:32:08 +00:00
|
|
|
(make-empty-skeleton/cache filtered))
|
2018-04-06 10:37:59 +00:00
|
|
|
(define next (hash-ref! table class make-skeleton-node-with-cache))
|
2018-10-20 23:58:40 +00:00
|
|
|
(walk-edge! (cons 0 rev-path) next 0 0 pieces)]
|
2018-04-06 10:37:59 +00:00
|
|
|
[_
|
|
|
|
(values pop-count sk)]))
|
2018-10-20 23:58:40 +00:00
|
|
|
(define (walk-edge! rev-path sk pop-count index pieces)
|
2018-04-06 10:37:59 +00:00
|
|
|
(match pieces
|
|
|
|
['()
|
|
|
|
(values (+ pop-count 1) sk)]
|
|
|
|
[(cons p pieces)
|
2018-10-20 23:58:40 +00:00
|
|
|
(let-values (((pop-count sk) (walk-node! rev-path sk pop-count index p)))
|
|
|
|
(walk-edge! (cons (+ index 1) (cdr rev-path)) sk pop-count (+ index 1) pieces))]))
|
2018-10-20 17:27:15 +00:00
|
|
|
(let-values (((_pop-count sk) (walk-node! '() sk 0 0 desc)))
|
2018-04-06 10:37:59 +00:00
|
|
|
sk))
|
|
|
|
|
|
|
|
(define (add-interest! sk i)
|
|
|
|
(let ((sk (extend-skeleton! sk (skeleton-interest-desc i))))
|
2018-04-29 13:54:14 +00:00
|
|
|
(skcont-add! (skeleton-node-continuation sk) i)))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
|
|
|
(define (remove-interest! sk i)
|
|
|
|
(let ((sk (extend-skeleton! sk (skeleton-interest-desc i))))
|
2018-04-22 20:04:22 +00:00
|
|
|
(skcont-remove! (skeleton-node-continuation sk) i)))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
2018-05-04 14:55:53 +00:00
|
|
|
(define (skeleton-modify! sk term0 modify-skcont! modify-skconst! modify-skacc!)
|
|
|
|
(unpack-scoped-assertion [restriction-path term0-term] term0)
|
|
|
|
|
2018-04-06 10:37:59 +00:00
|
|
|
(define (walk-node! sk term-stack)
|
|
|
|
(match-define (skeleton-node continuation edges) sk)
|
|
|
|
|
|
|
|
(modify-skcont! continuation term0)
|
2018-04-30 09:04:33 +00:00
|
|
|
(hash-for-each (skeleton-continuation-table continuation)
|
|
|
|
(lambda (constant-proj key-proj-handler)
|
2018-05-04 14:55:53 +00:00
|
|
|
(define constants (apply-projection term0-term constant-proj))
|
2018-04-30 09:04:33 +00:00
|
|
|
(define proj-handler (hash-ref key-proj-handler constants #f))
|
|
|
|
(when proj-handler
|
|
|
|
(modify-skconst! proj-handler term0)
|
2018-04-30 13:46:43 +00:00
|
|
|
(hash-for-each (skeleton-matched-constant-table proj-handler)
|
|
|
|
(lambda (variable-proj acc)
|
2018-05-04 15:04:42 +00:00
|
|
|
;; (when restriction-path
|
|
|
|
;; (log-info "Restriction path ~v in effect; variable-proj is ~v, and term is ~v"
|
|
|
|
;; restriction-path
|
|
|
|
;; variable-proj
|
|
|
|
;; term0))
|
2018-05-03 21:09:33 +00:00
|
|
|
(when (or (not restriction-path)
|
|
|
|
(equal? restriction-path variable-proj))
|
2018-05-04 14:55:53 +00:00
|
|
|
(define variables (apply-projection term0-term variable-proj))
|
2018-05-03 21:09:33 +00:00
|
|
|
(modify-skacc! acc variables term0)))))))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
2018-04-30 08:14:00 +00:00
|
|
|
(for [(edge (in-list edges))]
|
2018-04-06 10:37:59 +00:00
|
|
|
(match-define (cons (skeleton-selector pop-count index) table) edge)
|
|
|
|
(define popped-stack (drop term-stack pop-count))
|
2018-10-20 20:42:38 +00:00
|
|
|
(define old-top (car popped-stack))
|
|
|
|
(define new-top
|
|
|
|
(cond [(non-object-struct? old-top) (vector-ref (struct->vector old-top) (+ index 1))]
|
|
|
|
[(list? old-top) (list-ref old-top index)]
|
|
|
|
[(vector? old-top) (vector-ref old-top index)]))
|
2018-04-06 10:37:59 +00:00
|
|
|
(define entry (hash-ref table
|
2018-10-20 20:42:38 +00:00
|
|
|
(cond [(non-object-struct? new-top) (struct->struct-type new-top)]
|
|
|
|
[(list? new-top) (list-type (length new-top))]
|
|
|
|
[(vector? new-top) (vector-type (vector-length new-top))]
|
2018-04-06 10:37:59 +00:00
|
|
|
[else #f])
|
|
|
|
#f))
|
2018-10-20 20:42:38 +00:00
|
|
|
(when entry (walk-node! entry (cons new-top popped-stack)))))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
2018-10-20 20:42:38 +00:00
|
|
|
(walk-node! sk (list (list term0-term))))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
|
|
|
(define (add-term-to-skcont! skcont term)
|
2018-04-30 08:32:08 +00:00
|
|
|
(hash-set! (skeleton-continuation-cache skcont) term #t))
|
2018-04-06 10:37:59 +00:00
|
|
|
(define (add-term-to-skconst! skconst term)
|
2018-04-30 08:32:08 +00:00
|
|
|
(hash-set! (skeleton-matched-constant-cache skconst) term #t))
|
2018-05-04 14:55:53 +00:00
|
|
|
(define (add-term-to-skacc! skacc vars _term)
|
2018-05-04 15:04:42 +00:00
|
|
|
;; (log-info ">>>>>> At addition time for ~v, cache has ~v"
|
|
|
|
;; _term
|
|
|
|
;; (hash-ref (skeleton-accumulator-cache skacc) vars 0))
|
2018-04-19 16:55:52 +00:00
|
|
|
(match (bag-change! (skeleton-accumulator-cache skacc) vars 1)
|
|
|
|
['absent->present
|
2018-04-30 09:04:33 +00:00
|
|
|
(hash-for-each (skeleton-accumulator-handlers skacc)
|
|
|
|
(lambda (handler _) (apply handler '+ vars)))]
|
2018-04-19 16:55:52 +00:00
|
|
|
;; 'present->absent and 'absent->absent absurd
|
|
|
|
['present->present
|
|
|
|
(void)]))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
2018-05-04 14:55:53 +00:00
|
|
|
(define (add-assertion! sk term)
|
2018-04-06 10:37:59 +00:00
|
|
|
(skeleton-modify! sk
|
|
|
|
term
|
|
|
|
add-term-to-skcont!
|
|
|
|
add-term-to-skconst!
|
|
|
|
add-term-to-skacc!))
|
|
|
|
|
|
|
|
(define (remove-term-from-skcont! skcont term)
|
2018-04-30 08:32:08 +00:00
|
|
|
(hash-remove! (skeleton-continuation-cache skcont) term))
|
2018-04-06 10:37:59 +00:00
|
|
|
(define (remove-term-from-skconst! skconst term)
|
2018-04-30 08:32:08 +00:00
|
|
|
(hash-remove! (skeleton-matched-constant-cache skconst) term))
|
2018-04-06 10:37:59 +00:00
|
|
|
(define (remove-term-from-skacc! skacc vars _term)
|
2018-04-19 16:55:52 +00:00
|
|
|
(define cache (skeleton-accumulator-cache skacc))
|
2018-05-04 15:04:42 +00:00
|
|
|
;; (log-info ">>>>>> At removal time for ~v, cache has ~v" _term (hash-ref cache vars 0))
|
2018-04-19 16:55:52 +00:00
|
|
|
(if (bag-member? cache vars)
|
|
|
|
(match (bag-change! cache vars -1)
|
|
|
|
['present->absent
|
2018-04-30 09:04:33 +00:00
|
|
|
(hash-for-each (skeleton-accumulator-handlers skacc)
|
|
|
|
(lambda (handler _) (apply handler '- vars)))]
|
2018-04-19 16:55:52 +00:00
|
|
|
;; 'absent->absent and 'absent->present absurd
|
|
|
|
['present->present
|
|
|
|
(void)])
|
|
|
|
(log-warning "Removing assertion not previously added: ~v" _term)))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
2018-05-04 14:55:53 +00:00
|
|
|
(define (remove-assertion! sk term)
|
2018-04-06 10:37:59 +00:00
|
|
|
(skeleton-modify! sk
|
|
|
|
term
|
|
|
|
remove-term-from-skcont!
|
|
|
|
remove-term-from-skconst!
|
|
|
|
remove-term-from-skacc!))
|
|
|
|
|
2018-05-04 14:55:53 +00:00
|
|
|
(define (send-assertion! sk term)
|
2018-04-06 10:37:59 +00:00
|
|
|
(skeleton-modify! sk
|
|
|
|
term
|
|
|
|
void
|
|
|
|
void
|
|
|
|
(lambda (skacc vars _term)
|
2018-04-30 09:04:33 +00:00
|
|
|
(hash-for-each (skeleton-accumulator-handlers skacc)
|
|
|
|
(lambda (handler _) (apply handler '! vars))))))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
|
|
|
;; TODO: avoid repeated descent into `term` by factoring out prefixes of paths in `proj`
|
|
|
|
(define (apply-projection term proj)
|
2018-04-30 08:14:00 +00:00
|
|
|
(for/list [(path (in-list proj))]
|
2018-04-06 10:37:59 +00:00
|
|
|
(apply-projection-path term path)))
|
|
|
|
|
|
|
|
(define (apply-projection-path term path)
|
2018-10-20 17:27:15 +00:00
|
|
|
(for/fold [(term term)] [(index (in-list path))]
|
2018-05-01 19:57:22 +00:00
|
|
|
(cond [(non-object-struct? term) (vector-ref (struct->vector term) (+ index 1))]
|
|
|
|
[(list? term) (list-ref term index)]
|
|
|
|
[(vector? term) (vector-ref term index)]
|
2018-04-06 10:37:59 +00:00
|
|
|
[else (error 'apply-projection "Term representation not supported: ~v" term)])))
|
|
|
|
|
|
|
|
;;---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
(module+ test
|
|
|
|
(struct a (x y) #:transparent)
|
|
|
|
(struct b (v) #:transparent)
|
|
|
|
(struct c (v) #:transparent)
|
|
|
|
(struct d (x y z) #:transparent)
|
|
|
|
|
|
|
|
(define sk
|
2018-04-30 08:32:08 +00:00
|
|
|
(make-empty-skeleton/cache
|
|
|
|
(make-hash (for/list [(x (list (a (b 'bee) (b 'cat))
|
|
|
|
(a (b 'foo) (c 'bar))
|
|
|
|
(a (b 'foo) (c 'BAR))
|
|
|
|
(a (c 'bar) (b 'foo))
|
|
|
|
(a (c 'dog) (c 'fox))
|
|
|
|
(d (b 'DBX) (b 'DBY) (b 'DBZ))
|
|
|
|
(d (c 'DCX) (c 'DCY) (c 'DCZ))
|
|
|
|
(b 'zot)
|
|
|
|
123))]
|
|
|
|
(cons x #t)))))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
2018-04-29 13:54:14 +00:00
|
|
|
(define i1
|
|
|
|
(skeleton-interest (list struct:a (list struct:b #f) #f)
|
2018-10-20 17:27:15 +00:00
|
|
|
'((0 0))
|
2018-04-29 13:54:14 +00:00
|
|
|
'(foo)
|
2018-10-20 17:27:15 +00:00
|
|
|
'((1))
|
2018-04-29 13:54:14 +00:00
|
|
|
(lambda (op . bindings)
|
|
|
|
(printf "xAB HANDLER: ~v ~v\n" op bindings))
|
|
|
|
(lambda (vars)
|
|
|
|
(printf "xAB CLEANUP: ~v\n" vars))))
|
|
|
|
|
|
|
|
(add-interest! sk i1)
|
2018-04-06 10:37:59 +00:00
|
|
|
|
|
|
|
(void (extend-skeleton! sk (list struct:a (list struct:b #f) #f)))
|
|
|
|
(void (extend-skeleton! sk (list struct:a #f (list struct:c #f))))
|
|
|
|
(void (extend-skeleton! sk (list struct:a #f (list struct:c (list struct:b #f)))))
|
|
|
|
(void (extend-skeleton! sk (list struct:a #f #f)))
|
|
|
|
(void (extend-skeleton! sk (list struct:c #f)))
|
|
|
|
(void (extend-skeleton! sk (list struct:b #f)))
|
|
|
|
(void (extend-skeleton! sk (list struct:d (list struct:b #f) #f (list struct:b #f))))
|
|
|
|
(void (extend-skeleton! sk (list struct:d (list struct:b #f) #f (list struct:c #f))))
|
|
|
|
(void (extend-skeleton! sk (list struct:d (list struct:c #f) #f (list struct:b #f))))
|
|
|
|
(void (extend-skeleton! sk (list struct:d (list struct:c #f) #f (list struct:c #f))))
|
|
|
|
(check-eq? sk (extend-skeleton! sk #f))
|
|
|
|
|
|
|
|
(add-interest! sk
|
|
|
|
(skeleton-interest (list struct:d (list struct:b #f) #f (list struct:c #f))
|
2018-10-20 17:27:15 +00:00
|
|
|
'((2 0))
|
2018-04-06 10:37:59 +00:00
|
|
|
'(DCZ)
|
2018-10-20 17:27:15 +00:00
|
|
|
'(() (0) (0 0) (1))
|
2018-04-06 10:37:59 +00:00
|
|
|
(lambda (op . bindings)
|
2018-04-29 13:54:14 +00:00
|
|
|
(printf "DBC HANDLER: ~v ~v\n" op bindings))
|
|
|
|
(lambda (vars)
|
|
|
|
(printf "DBC CLEANUP: ~v\n" vars))))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
|
|
|
(remove-assertion! sk (a (b 'foo) (c 'bar)))
|
|
|
|
(remove-assertion! sk (d (b 'B1) (b 'DBY) (c 'DCZ)))
|
|
|
|
(add-assertion! sk (d (b 'B1) (b 'DBY) (c 'DCZ)))
|
|
|
|
(add-assertion! sk (d (b 'BX) (b 'DBY) (c 'DCZ)))
|
|
|
|
(add-assertion! sk (d (b 'B1) (b 'DBY) (c 'CX)))
|
|
|
|
(add-assertion! sk (d (b 'B1) (b 'DBY) (c 'DCZ)))
|
|
|
|
(add-assertion! sk (d (b 'BX) (b 'DBY) (c 'DCZ)))
|
|
|
|
(add-assertion! sk (d (b 'B1) (b 'DBY) (c 'CX)))
|
|
|
|
|
|
|
|
(add-interest! sk
|
|
|
|
(skeleton-interest (list struct:d #f (list struct:b #f) #f)
|
2018-10-20 17:27:15 +00:00
|
|
|
'((1 0))
|
2018-04-06 10:37:59 +00:00
|
|
|
'(DBY)
|
2018-10-20 17:27:15 +00:00
|
|
|
'((0) (2))
|
2018-04-06 10:37:59 +00:00
|
|
|
(lambda (op . bindings)
|
2018-04-29 13:54:14 +00:00
|
|
|
(printf "xDB HANDLER: ~v ~v\n" op bindings))
|
|
|
|
(lambda (vars)
|
|
|
|
(printf "xDB CLEANUP: ~v\n" vars))))
|
2018-04-06 10:37:59 +00:00
|
|
|
|
|
|
|
(send-assertion! sk (d (b 'BX) (b 'DBY) (c 'DCZ)))
|
|
|
|
(send-assertion! sk (d (b 'BX) (b 'DBY) (c 'DCZ)))
|
|
|
|
|
|
|
|
(remove-assertion! sk (d (b 'B1) (b 'DBY) (c 'DCZ)))
|
|
|
|
(remove-assertion! sk (d (b 'BX) (b 'DBY) (c 'DCZ)))
|
|
|
|
(remove-assertion! sk (d (b 'B1) (b 'DBY) (c 'CX)))
|
|
|
|
(remove-assertion! sk (d (b 'B1) (b 'DBY) (c 'DCZ)))
|
|
|
|
(remove-assertion! sk (d (b 'BX) (b 'DBY) (c 'DCZ)))
|
|
|
|
(remove-assertion! sk (d (b 'B1) (b 'DBY) (c 'CX)))
|
|
|
|
;; sk
|
2018-04-29 13:54:14 +00:00
|
|
|
|
|
|
|
(remove-interest! sk i1)
|
2018-04-06 10:37:59 +00:00
|
|
|
)
|