racket/collects/macro-debugger/view/stepper.ss
2008-05-23 05:11:26 +00:00

428 lines
14 KiB
Scheme

#lang scheme/base
(require scheme/class
scheme/unit
scheme/list
scheme/match
scheme/gui
framework/framework
syntax/boundmap
"interfaces.ss"
"prefs.ss"
"extensions.ss"
"warning.ss"
"hiding-panel.ss"
"term-record.ss"
(prefix-in s: "../syntax-browser/widget.ss")
(prefix-in s: "../syntax-browser/params.ss")
"../model/deriv.ss"
"../model/deriv-util.ss"
"../model/deriv-find.ss"
"../model/trace.ss"
"../model/reductions.ss"
"../model/steps.ss"
"cursor.ss"
"../util/notify.ss")
(provide macro-stepper-widget%
macro-stepper-widget/process-mixin)
;; Macro Stepper
;; macro-stepper-widget%
(define macro-stepper-widget%
(class* object% ()
(init-field parent)
(init-field config)
;; Terms
;; all-terms : (list-of TermRecord)
;; (Reversed)
(define all-terms null)
;; terms : (Cursor-of TermRecord)
;; Contains visible terms of all-terms
(define terms (cursor:new null))
;; focused-term : -> TermRecord or #f
(define (focused-term)
(cursor:next terms))
;; add-deriv : Deriv -> void
(define/public (add-deriv d)
(let ([trec (new term-record% (stepper this) (raw-deriv d))])
(add trec)))
;; add-trace : (list-of event) -> void
(define/public (add-trace events)
(let ([trec (new term-record% (stepper this) (events events))])
(add trec)))
;; add : TermRecord -> void
(define/public (add trec)
(set! all-terms (cons trec all-terms))
(let ([display-new-term? (cursor:at-end? terms)]
[invisible? (send trec get-deriv-hidden?)])
(unless invisible?
(cursor:add-to-end! terms (list trec))
(trim-navigator)
(if display-new-term?
(refresh)
(update)))))
;; remove-current-term : -> void
(define/public (remove-current-term)
(cursor:remove-current! terms)
(trim-navigator)
(refresh))
(define/public (get-config) config)
(define/public (get-controller) sbc)
(define/public (get-view) sbview)
(define/public (get-warnings-area) warnings-area)
(define/public (get-macro-hiding-prefs) macro-hiding-prefs)
(define/public (reset-primary-partition)
(send sbc reset-primary-partition)
(update/preserve-view))
(define area (new vertical-panel% (parent parent)))
(define supernavigator
(new horizontal-panel%
(parent area)
(stretchable-height #f)
(alignment '(center center))))
(define navigator
(new horizontal-panel%
(parent supernavigator)
(stretchable-width #f)
(stretchable-height #f)
(alignment '(left center))))
(define extra-navigator
(new horizontal-panel%
(parent supernavigator)
(stretchable-width #f)
(stretchable-height #f)
(alignment '(left center))
(style '(deleted))))
(define warnings-area (new stepper-warnings% (parent area)))
(define sbview (new stepper-syntax-widget%
(parent area)
(macro-stepper this)))
(define sbc (send sbview get-controller))
(define control-pane
(new vertical-panel% (parent area) (stretchable-height #f)))
(define macro-hiding-prefs
(new macro-hiding-prefs-widget%
(parent control-pane)
(stepper this)
(config config)))
(send config listen-show-syntax-properties?
(lambda (show?) (send sbview show-props show?)))
(send config listen-show-hiding-panel?
(lambda (show?) (show-macro-hiding-prefs show?)))
(send sbc listen-selected-syntax
(lambda (stx) (send macro-hiding-prefs set-syntax stx)))
(send config listen-highlight-foci?
(lambda (_) (update/preserve-view)))
(send config listen-highlight-frontier?
(lambda (_) (update/preserve-view)))
(send config listen-show-rename-steps?
(lambda (_) (refresh/re-reduce)))
(send config listen-one-by-one?
(lambda (_) (refresh/re-reduce)))
(send config listen-force-letrec-transformation?
(lambda (_) (refresh/resynth)))
(send config listen-extra-navigation?
(lambda (show?) (show-extra-navigation show?)))
(define nav:up
(new button% (label "Previous term") (parent navigator)
(callback (lambda (b e) (navigate-up)))))
(define nav:start
(new button% (label "<-- Start") (parent navigator)
(callback (lambda (b e) (navigate-to-start)))))
(define nav:previous
(new button% (label "<- Step") (parent navigator)
(callback (lambda (b e) (navigate-previous)))))
(define nav:next
(new button% (label "Step ->") (parent navigator)
(callback (lambda (b e) (navigate-next)))))
(define nav:end
(new button% (label "End -->") (parent navigator)
(callback (lambda (b e) (navigate-to-end)))))
(define nav:down
(new button% (label "Next term") (parent navigator)
(callback (lambda (b e) (navigate-down)))))
(define/private (trim-navigator)
(if (> (length (cursor->list terms)) 1)
(send navigator change-children
(lambda _
(list nav:up
nav:start
nav:previous
nav:next
nav:end
nav:down)))
(send navigator change-children
(lambda _
(list nav:start
nav:previous
nav:next
nav:end)))))
(define/public (show-macro-hiding-prefs show?)
(send area change-children
(lambda (children)
(if show?
(append (remq control-pane children) (list control-pane))
(remq control-pane children)))))
(define/private (show-extra-navigation show?)
(send supernavigator change-children
(lambda (children)
(if show?
(list navigator extra-navigator)
(list navigator)))))
;; Navigation
(define/public-final (at-start?)
(send (focused-term) at-start?))
(define/public-final (at-end?)
(send (focused-term) at-end?))
(define/public-final (navigate-to-start)
(send (focused-term) navigate-to-start)
(update/save-position))
(define/public-final (navigate-to-end)
(send (focused-term) navigate-to-end)
(update/save-position))
(define/public-final (navigate-previous)
(send (focused-term) navigate-previous)
(update/save-position))
(define/public-final (navigate-next)
(send (focused-term) navigate-next)
(update/save-position))
(define/public-final (navigate-up)
(when (focused-term)
(send (focused-term) on-lose-focus))
(cursor:move-prev terms)
(refresh/move))
(define/public-final (navigate-down)
(when (focused-term)
(send (focused-term) on-lose-focus))
(cursor:move-next terms)
(refresh/move))
;; Update
;; update/save-position : -> void
(define/private (update/save-position)
(update/preserve-lines-view))
;; update/preserve-lines-view : -> void
(define/public (update/preserve-lines-view)
(define text (send sbview get-text))
(define start-box (box 0))
(define end-box (box 0))
(send text get-visible-line-range start-box end-box)
(update)
(send text scroll-to-position
(send text line-start-position (unbox start-box))
#f
(send text line-start-position (unbox end-box))
'start))
;; update/preserve-view : -> void
(define/public (update/preserve-view)
(define text (send sbview get-text))
(define start-box (box 0))
(define end-box (box 0))
(send text get-visible-position-range start-box end-box)
(update)
(send text scroll-to-position (unbox start-box) #f (unbox end-box) 'start))
;; update : -> void
;; Updates the terms in the syntax browser to the current step
(define/private (update)
(define text (send sbview get-text))
(define position-of-interest 0)
(define multiple-terms? (> (length (cursor->list terms)) 1))
(send text begin-edit-sequence)
(send sbview erase-all)
(update:show-prefix)
(when multiple-terms? (send sbview add-separator))
(set! position-of-interest (send text last-position))
(update:show-current-step)
(when multiple-terms? (send sbview add-separator))
(update:show-suffix)
(send text end-edit-sequence)
(send text scroll-to-position
position-of-interest
#f
(send text last-position)
'start)
(enable/disable-buttons))
;; update:show-prefix : -> void
(define/private (update:show-prefix)
;; Show the final terms from the cached synth'd derivs
(for-each (lambda (trec) (send trec display-final-term))
(cursor:prefix->list terms)))
;; update:show-current-step : -> void
(define/private (update:show-current-step)
(when (focused-term)
(send (focused-term) display-step)))
;; update:show-suffix : -> void
(define/private (update:show-suffix)
(let ([suffix0 (cursor:suffix->list terms)])
(when (pair? suffix0)
(for-each (lambda (trec)
(send trec display-initial-term))
(cdr suffix0)))))
;; enable/disable-buttons : -> void
(define/private (enable/disable-buttons)
(define term (focused-term))
(send nav:start enable (and term (send term has-prev?)))
(send nav:previous enable (and term (send term has-prev?)))
(send nav:next enable (and term (send term has-next?)))
(send nav:end enable (and term (send term has-next?)))
(send nav:up enable (cursor:has-prev? terms))
(send nav:down enable (cursor:has-next? terms)))
;; --
;; refresh/resynth : -> void
;; Macro hiding policy has changed; invalidate cached parts of trec
(define/public (refresh/resynth)
(for-each (lambda (trec) (send trec invalidate-synth!))
(cursor->list terms))
(refresh))
;; refresh/re-reduce : -> void
;; Reduction config has changed; invalidate cached parts of trec
(define/private (refresh/re-reduce)
(for-each (lambda (trec) (send trec invalidate-steps!))
(cursor->list terms))
(refresh))
;; refresh/move : -> void
;; Moving between terms; clear the saved position
(define/private (refresh/move)
(refresh))
;; refresh : -> void
(define/public (refresh)
(send warnings-area clear)
(when (focused-term)
(send (focused-term) on-get-focus))
(update))
;; delayed-recache-errors : (list-of (cons exn string))
(define delayed-recache-errors null)
;; handle-recache-error : exception string -> void
(define/private (handle-recache-error exn part)
(if (send config get-debug-catch-errors?)
(begin
(set! delayed-recache-errors
(cons (cons exn part) delayed-recache-errors))
(queue-callback
(lambda ()
(when (pair? delayed-recache-errors)
(message-box
"Error"
(string-append
"Internal errors in macro stepper:\n"
(if (memq 'macro-hiding (map cdr delayed-recache-errors))
(string-append
"Macro hiding failed on one or more terms. "
"The macro stepper is showing the terms "
"with macro hiding disabled.\n")
"")
(if (memq 'reductions (map cdr delayed-recache-errors))
(string-append
"The macro stepper failed to compute the reduction sequence "
"for one or more terms.\n")
"")))
(set! delayed-recache-errors null)))))
(raise exn)))
(define/private (foci x) (if (list? x) x (list x)))
;; Hiding policy
(define/public (get-show-macro?)
(send macro-hiding-prefs get-policy))
;; Derivation pre-processing
(define/public (get-preprocess-deriv) (lambda (d) d))
;; Initialization
(super-new)
(send sbview show-props (send config get-show-syntax-properties?))
(show-macro-hiding-prefs (send config get-show-hiding-panel?))
(show-extra-navigation (send config get-extra-navigation?))
(refresh/move)
))
(define (macro-stepper-widget/process-mixin %)
(class %
(super-new)
(define/override (get-preprocess-deriv)
(lambda (d) (get-original-part d)))
;; get-original-part : Deriv -> Deriv/#f
;; Strip off mzscheme's #%top-interaction
;; Careful: the #%top-interaction node may be inside of a lift-deriv
(define/private (get-original-part deriv)
(let ([deriv* (adjust-deriv/lift deriv)])
deriv*))
;; adjust-deriv/lift : Derivation -> (list-of Derivation)
(define/private (adjust-deriv/lift deriv)
(match deriv
[(Wrap lift-deriv (e1 e2 first lifted-stx second))
(let ([first (adjust-deriv/top first)])
(and first
(let ([e1 (wderiv-e1 first)])
(make-lift-deriv e1 e2 first lifted-stx second))))]
[else (adjust-deriv/top deriv)]))
;; adjust-deriv/top : Derivation -> Derivation
(define/private (adjust-deriv/top deriv)
(if (or (syntax-source (wderiv-e1 deriv))
(p:module? deriv))
deriv
;; It's not original...
;; Strip out mzscheme's top-interactions
;; Keep anything that is a non-mzscheme top-interaction
;; Drop everything else (not original program)
(cond [(not (mrule? deriv)) #f]
[(for/or ([x (base-resolves deriv)]) (top-interaction-kw? x))
;; Just mzscheme's top-interaction; strip it out
(adjust-deriv/top (mrule-next deriv))]
[(equal? (map syntax-e (base-resolves deriv)) '(#%top-interaction))
;; A *different* top interaction; keep it
deriv]
[else
;; Not original and not tagged with top-interaction
#f])))
(define/public (top-interaction-kw? x)
(free-identifier=? x #'#%top-interaction))
))