#lang racket
(require "../proof/proof.rkt"
"../acl2/acl2.rkt"
"../acl2/rep.rkt"
"../private/hash.rkt"
"proof-state.rkt")
(define-struct dracula-state (action table) #:prefab)
(define-struct action (desc) #:prefab)
(define-struct (error-action action) () #:prefab)
(define-struct (normal-action action) () #:prefab)
(define-struct (interrupt-action action) () #:prefab)
(define-struct proof-table (names current hash) #:prefab)
(define (dracula-state-active? state)
(and (dracula-state? state)
(action? (dracula-state-action state))))
(define (dracula-state-busy? state)
(and (dracula-state? state)
(normal-action? (dracula-state-action state))))
(define (dracula-state-error? state)
(and (dracula-state? state)
(error-action? (dracula-state-action state))))
(define (dracula-state-interrupt? state)
(and (dracula-state? state)
(interrupt-action? (dracula-state-action state))))
(define (dracula-state-proof-chosen? state)
(and (dracula-state? state)
(symbol? (proof-table-current (dracula-state-table state)))))
(define (dracula-state-acl2-open? state)
(and (dracula-state-proof-chosen? state)
(proof-state-acl2-open? (dracula-state-current-proof state))))
(define initial-proof-table
(make-proof-table null #f (make-immutable-hasheq null)))
(define initial-dracula-state
(make-dracula-state #f initial-proof-table))
(define (dracula-state-populate state proof)
(make-dracula-state
(dracula-state-action state)
(proof-table-populate (dracula-state-table state) proof)))
(define (proof-table-populate table proof)
(match table
[(struct proof-table (old-names old-name old-hash))
(let* ([new-names (proof-parts proof)]
[new-name
(cond [(memq old-name new-names) old-name]
[else #f])]
[new-hash (proof-hash-populate old-hash proof)])
(make-proof-table new-names new-name new-hash))]))
(define (proof-hash-populate old-hash proof)
(for/fold
([hash old-hash])
([name (proof-parts proof)])
(let* ([part (proof-part proof name)]
[old-pstate (hash-ref/default hash name #f)]
[new-pstate (if old-pstate
(proof-state-populate old-pstate part)
(initial-proof-state part))])
(hash-set hash name new-pstate))))
(define (dracula-state-pending state desc)
(make-dracula-state (make-normal-action desc) (dracula-state-table state)))
(define (dracula-state-interrupt state)
(make-dracula-state
(interrupt (dracula-state-action state))
(dracula-state-table state)))
(define (interrupt action)
(make-interrupt-action (action-desc action)))
(define (dracula-state-error state)
(make-dracula-state
(if (dracula-state-action state)
(err (dracula-state-action state))
(make-error-action "internal failure"))
(dracula-state-table state)))
(define (err action)
(make-error-action (action-desc action)))
(define (dracula-state-done state)
(make-dracula-state #f (dracula-state-table state)))
(define (dracula-state-choose state name)
(make-dracula-state
(dracula-state-action state)
(proof-table-choose (dracula-state-table state) name)))
(define (proof-table-choose table name)
(make-proof-table (proof-table-names table) name (proof-table-hash table)))
(define (dracula-state-start-acl2 state acl2-state)
(dracula-state-update-current state proof-state-start-acl2 acl2-state))
(define (dracula-state-update-acl2 state acl2-state)
(dracula-state-update-current state proof-state-update-acl2 acl2-state))
(define (dracula-state-advance state acl2-state saved)
(dracula-state-update-current state proof-state-advance acl2-state saved))
(define (dracula-state-rewind state)
(dracula-state-update-current state proof-state-rewind))
(define (dracula-state-edit state)
(dracula-state-update-current state proof-state-edit))
(define (dracula-state-stop-acl2 state)
(dracula-state-update-current
(dracula-state-done state)
proof-state-stop-acl2))
(define (dracula-state-names state)
(proof-table-names (dracula-state-table state)))
(define (dracula-state-activity state)
(action-desc (dracula-state-action state)))
(define (dracula-state-current-name state)
(proof-table-current (dracula-state-table state)))
(define (dracula-state-proof-tree state)
(proof-state-proof-tree (dracula-state-current-proof state)))
(define (dracula-state-initial-prompt state)
(proof-state-initial-prompt (dracula-state-current-proof state)))
(define (dracula-state-acl2-input state)
(proof-state-acl2-input (dracula-state-current-proof state)))
(define (dracula-state-acl2-output state)
(proof-state-acl2-output (dracula-state-current-proof state)))
(define (dracula-state-final-prompt state)
(proof-state-final-prompt (dracula-state-current-proof state)))
(define (dracula-state-total-output state)
(proof-state-total-output (dracula-state-current-proof state)))
(define (dracula-state-start-of-proof? state)
(proof-state-start-of-proof? (dracula-state-current-proof state)))
(define (dracula-state-end-of-proof? state)
(proof-state-end-of-proof? (dracula-state-current-proof state)))
(define (dracula-state-at-first-term? state)
(proof-state-at-first-term? (dracula-state-current-proof state)))
(define (dracula-state-at-last-term? state)
(proof-state-at-last-term? (dracula-state-current-proof state)))
(define (dracula-state-finished? state)
(proof-state-finished? (dracula-state-current-proof state)))
(define (dracula-state-admitted? state)
(proof-state-admitted? (dracula-state-current-proof state)))
(define (dracula-state-edited? state)
(proof-state-edited? (dracula-state-current-proof state)))
(define (dracula-state-next-sexp state)
(proof-state-next-sexp (dracula-state-current-proof state)))
(define (dracula-state-save-before-next-sexp state)
(proof-state-save-before-next-sexp (dracula-state-current-proof state)))
(define (dracula-state-restore-saved-sexp state)
(proof-state-restore-saved-sexp (dracula-state-current-proof state)))
(define (dracula-state-first-admitted-position state)
(proof-state-first-admitted-position (dracula-state-current-proof state)))
(define (dracula-state-last-admitted-position state)
(proof-state-last-admitted-position (dracula-state-current-proof state)))
(define (dracula-state-last-attempted-position state)
(proof-state-last-attempted-position (dracula-state-current-proof state)))
(define (dracula-state-term-index state)
(proof-state-term-index (dracula-state-current-proof state)))
(define (dracula-state-proof-size state)
(proof-state-size (dracula-state-current-proof state)))
(define (dracula-state-index-before-pos state pos)
(proof-state-index-before-pos (dracula-state-current-proof state) pos))
(define (dracula-state-index-after-pos state pos)
(proof-state-index-after-pos (dracula-state-current-proof state) pos))
(define (dracula-state-update-current state update . args)
(make-dracula-state
(dracula-state-action state)
(apply proof-table-update-current (dracula-state-table state) update args)))
(define (proof-table-update-current table update . args)
(make-proof-table
(proof-table-names table)
(proof-table-current table)
(hash-update (proof-table-hash table)
(proof-table-current table)
(lambda (pstate) (apply update pstate args)))))
(define (dracula-state-current-proof state)
(let* ([table (dracula-state-table state)]
[hash (proof-table-hash table)]
[current (proof-table-current table)])
(hash-ref/check hash current)))
(provide/contract
[dracula-state? (-> any/c boolean?)]
[dracula-state-active? (-> any/c boolean?)] [dracula-state-busy? (-> any/c boolean?)] [dracula-state-error? (-> any/c boolean?)] [dracula-state-interrupt? (-> any/c boolean?)]
[dracula-state-proof-chosen? (-> any/c boolean?)]
[dracula-state-acl2-open? (-> any/c boolean?)]
[initial-dracula-state dracula-state?]
[dracula-state-populate (-> dracula-state? proof? dracula-state?)]
[dracula-state-pending
(-> (and/c dracula-state?
(not/c dracula-state-interrupt?)
(not/c dracula-state-error?))
string?
dracula-state-busy?)]
[dracula-state-error
(-> dracula-state-acl2-open? dracula-state-error?)]
[dracula-state-interrupt
(-> (and/c dracula-state? (not/c dracula-state-error?))
dracula-state-interrupt?)]
[dracula-state-done
(-> (and/c dracula-state-active? (not/c dracula-state-error?))
(and/c dracula-state? (not/c dracula-state-active?)))]
[dracula-state-choose
(-> dracula-state? symbol? dracula-state-proof-chosen?)]
[dracula-state-start-acl2
(-> (and/c dracula-state-proof-chosen? (not/c dracula-state-acl2-open?)) acl2?
dracula-state-acl2-open?)]
[dracula-state-update-acl2
(-> dracula-state-acl2-open? acl2? dracula-state-acl2-open?)]
[dracula-state-advance
(-> (and/c dracula-state-acl2-open?
dracula-state-admitted?
(not/c dracula-state-at-last-term?))
acl2?
(or/c sexp/c #f)
dracula-state-acl2-open?)]
[dracula-state-rewind
(-> (and/c dracula-state-acl2-open? (not/c dracula-state-at-first-term?))
dracula-state-acl2-open?)]
[dracula-state-edit (-> dracula-state-acl2-open? dracula-state-acl2-open?)]
[dracula-state-stop-acl2
(-> dracula-state-acl2-open?
(and/c dracula-state-proof-chosen?
(not/c dracula-state-acl2-open?)
(not/c dracula-state-active?)))]
[dracula-state-names (-> dracula-state? (listof symbol?))]
[dracula-state-activity (-> dracula-state-active? string?)]
[dracula-state-at-first-term? (-> dracula-state-acl2-open? boolean?)]
[dracula-state-at-last-term? (-> dracula-state-acl2-open? boolean?)]
[dracula-state-current-name (-> dracula-state-proof-chosen? symbol?)]
[dracula-state-next-sexp
(-> (and/c dracula-state-acl2-open? (not/c dracula-state-at-last-term?))
sexp/c)]
[dracula-state-save-before-next-sexp
(-> (and/c dracula-state-acl2-open? (not/c dracula-state-at-last-term?))
sexp/c)]
[dracula-state-restore-saved-sexp
(-> (and/c dracula-state-admitted? (not/c dracula-state-at-first-term?))
sexp/c)]
[dracula-state-start-of-proof? (-> dracula-state-acl2-open? boolean?)]
[dracula-state-end-of-proof? (-> dracula-state-acl2-open? boolean?)]
[dracula-state-finished? (-> dracula-state-acl2-open? boolean?)]
[dracula-state-admitted? (-> dracula-state-acl2-open? boolean?)]
[dracula-state-edited? (-> dracula-state-acl2-open? boolean?)]
[dracula-state-proof-tree (-> dracula-state-acl2-open? string?)]
[dracula-state-initial-prompt (-> dracula-state-acl2-open? string?)]
[dracula-state-acl2-input (-> dracula-state-acl2-open? string?)]
[dracula-state-acl2-output (-> dracula-state-acl2-open? string?)]
[dracula-state-final-prompt (-> dracula-state-acl2-open? string?)]
[dracula-state-total-output (-> dracula-state-acl2-open? string?)]
[dracula-state-proof-size
(-> dracula-state-proof-chosen? exact-nonnegative-integer?)]
[dracula-state-term-index
(-> dracula-state-acl2-open? exact-nonnegative-integer?)]
[dracula-state-first-admitted-position
(-> dracula-state-acl2-open? exact-nonnegative-integer?)]
[dracula-state-last-admitted-position
(-> dracula-state-acl2-open? exact-nonnegative-integer?)]
[dracula-state-last-attempted-position
(-> dracula-state-acl2-open? exact-nonnegative-integer?)]
[dracula-state-index-before-pos
(-> dracula-state-acl2-open? exact-nonnegative-integer?
exact-nonnegative-integer?)]
[dracula-state-index-after-pos
(-> dracula-state-acl2-open? exact-nonnegative-integer?
exact-nonnegative-integer?)]
)